Since we've come back from the USA, we made the decision not to have a TV in the house. We feel it causes too many behavioural issues with our kids so it's better just not to have one so obviously present and demanding attention. (That's not to say that they never watch the "TV", we just use a tablet instead, which gives us much more control over what exactly they watch and when. You can put the tablet or laptop in the cupboard, something that's more inconvenient to do with a TV.)
Laura and I have amassed a small DVD collection in multiple regions. Since we don't have a TV, there's no way for us to play our DVD collection, except on the laptop. I was looking for a (cheap) way to view our DVDs on our various other devices (phones, tablets, etc) and hit on using a vortexbox as a media-streaming solution using an old Dell PC we had lying around. Vortexbox is a Fedora linux-based automated CD/DVD ripping and media library solution. It supports Logitech Squeezeboxes, DLNA and Samba out-of-the-box, and you can install Plex media server to round out the solution. The current Vortexbox version is 2.2 and based on Fedora 16. There is also a new 3.4 beta version out on Fedora 20.
As usual, the project turned out to be a little more expensive than expected - the PC didn't have enough RAM, big enough HD or a wireless network connection! So after a RAM upgrade, new 2TB HD and powerline network adaptors, I got it running.
The Vortexbox software more-or-less automates the CD/DVD ripping process. It takes about 30 minutes to rip a DVD to disk for later viewing, at a cost of around 4-7GB for each feature. Add the Plex media server and you've got a very nice solution that even does transcoding on the fly (although the CPU on this box only has enough grunt to handle transcoding of one stream at a time)
Now, if I feel like it, I can watch a DVD on the tablet or phone anywhere in the house. We can both watch different things on different devices at the same time, which is good for "marital harmony" :-)
Monday, January 20, 2014
Wednesday, January 15, 2014
It's been a while...
Who can believe that it's been over 4 years since I last posted???
Lets see, what happened during that time...
I'm also going to try to add notes on my side projects as well. Hopefully it'll make for more interesting reading.
Cheers to whoever is watching (probably nobody!)
Lets see, what happened during that time...
- Had 3 children (wow!)
- Moved to the USA to work for Microsoft
- Moved back to Australia
- Started work for Boeing
I'm also going to try to add notes on my side projects as well. Hopefully it'll make for more interesting reading.
Cheers to whoever is watching (probably nobody!)
Thursday, November 13, 2008
JSF and field validation
JSF provides some useful tools for field-level validation (<f:validate .../> and cousins). However, what if you have some externally-implemented validation whose errors you want to associate with specific fields? The "JSF way" would be to register the errors with the specific fields in question, for example:
The above is not ideal, since the field IDs are hard-coded into the backing bean. An alternative is to add a binding to the backing bean so that the correct component ID can be fetched.
While this works, your backing bean will need to have a whole bunch of UIComponent objects bound to it, which is a little messy.
A further problem arises when you try to integrate some other field-level validation framework into JSF, for example, the Spring validator. Suppose you had the following:
There is no out-of-the-box way to associate the errors generated by the Spring validation framework with actual JSF field IDs.
The spring "field id" for an error is really the JavaBean property path to access that property (e.g. dataObject.property1.property2). JSF field IDs follow allowable HTML ID syntax, so the spring "field id" can't be used directly as a JSF field ID.
It would also be nice to associate one error message with multiple fields. For example, suppose your validator lodged an object-level (i.e. not global) message such as Assigned date must be after lodged date. Clearly this error involves two fields and can be remedied by changing either of the fields. In this case, you'd want to display an interesting marker next to each field (e.g. using <rich:message .../> or some similar tag) and display the overall error associated to the general section of the form (or as a global error).
JSF purists would say that as error message display is a UI function, then you should code all mappings at the backing bean level. However, we live in the real world here!!! If you have heaps of fields for a simple domain object and an existing, tested validator for this domain object, then you're not going to re-write the validations in JSF, nor are you going to add a whole bunch of code to each backing bean solely to deal with the Spring-to-JSF error translation. Instead, you want a simple re-usable way to associate the existing error messages with the appropriate JSF field IDs.
To acheive this, we need to solve several problems. These are:
So we might end up with markup like this:
We want to perform this enhancement without having to write custom JSF components. This means that we need to modify the list of faces messages returned by FacesContext.getMessages(...) to include any messages for those IDs given in the otherMessageIds attribute.
One possibility is to use a PhaseListener before the render phase to map the messages. The disadvantages of this method are:
For these reasons, we use an alternative method which is to override the FacesContext object with our own.
To do this, you need:
The FacesContextWrapper is a simple adaptor implementation for a FacesContext class. It is an abstract class that wraps a FacesContext and delegates all requests to the wrapped class.
The MessageMappingFacesContextFactory factory implementation creates instances of the MessageMappingFacesContext.
The key part of the implementation is the MessageMappingFacesContext which overrides the getMessages(...) function. The override method:
I've implemented this technique and it works fine. When I get a chance, I'll post a code example.
public String someAction() {
String outcome = "success";
boolean result = someExternalValidation(...);
if (!result) {
FacesContext.getCurrentInstance().addMessage(
"formId:subviewId:fieldId",
new FacesMessage(FacesMessage.SEVERITY_ERROR, "This field is wrong");
);
outcome = null;
}
return outcome;
}
The above is not ideal, since the field IDs are hard-coded into the backing bean. An alternative is to add a binding to the backing bean so that the correct component ID can be fetched.
private UIComponent fieldComponent;
...
public setFieldComponent(UIComponent pFieldComponent) {
this.fieldComponent = pComponent;
}
...
public String someAction() {
String outcome = "success";
boolean result = someExternalValidation(...);
if (!result) {
FacesContext.getCurrentInstance().addMessage(
this.fieldComponent.getClientId(),
new FacesMessage(FacesMessage.SEVERITY_ERROR, "This field is wrong");
);
outcome = null;
}
return outcome;
}
While this works, your backing bean will need to have a whole bunch of UIComponent objects bound to it, which is a little messy.
A further problem arises when you try to integrate some other field-level validation framework into JSF, for example, the Spring validator. Suppose you had the following:
private Object dataObject;
private Validator dataObjectValidator;
...
public String someAction() {
String outcome = "success";
Errors errors = new BeanPropertyBindingResult(this.dataObject, "dataObject");
ValidationUtils.invokeValidator(this.dataObjectValidator, this.dataObject, errors);
if (errors.hasErrors()) {
// ?!? How to associate these errors with field IDs ?!?
outcome = null;
}
return outcome;
}
There is no out-of-the-box way to associate the errors generated by the Spring validation framework with actual JSF field IDs.
The spring "field id" for an error is really the JavaBean property path to access that property (e.g. dataObject.property1.property2). JSF field IDs follow allowable HTML ID syntax, so the spring "field id" can't be used directly as a JSF field ID.
It would also be nice to associate one error message with multiple fields. For example, suppose your validator lodged an object-level (i.e. not global) message such as Assigned date must be after lodged date. Clearly this error involves two fields and can be remedied by changing either of the fields. In this case, you'd want to display an interesting marker next to each field (e.g. using <rich:message .../> or some similar tag) and display the overall error associated to the general section of the form (or as a global error).
JSF purists would say that as error message display is a UI function, then you should code all mappings at the backing bean level. However, we live in the real world here!!! If you have heaps of fields for a simple domain object and an existing, tested validator for this domain object, then you're not going to re-write the validations in JSF, nor are you going to add a whole bunch of code to each backing bean solely to deal with the Spring-to-JSF error translation. Instead, you want a simple re-usable way to associate the existing error messages with the appropriate JSF field IDs.
To acheive this, we need to solve several problems. These are:
- Translating the Spring field/object "field id" paths into valid JSF IDs. (but see below)
- Adding the Spring field/object error messages as JSF error messages.
- Associating those error messages with an actual JSF field.
So we might end up with markup like this:
<h:panelgrid cellspacing="2" columns="2">
...
<h:outputlabel value="Field 1" for="field1"/>
<h:panelgroup>
<h:inputtext id="field1" value="#{bean.field1}">
<f:attribute name="otherMessageIds" value="dataObject.field1"/>
</h:inputtext>
<h:message for="field1"/>
</h:panelgroup>
...
<h:panelgrid>
We want to perform this enhancement without having to write custom JSF components. This means that we need to modify the list of faces messages returned by FacesContext.getMessages(...) to include any messages for those IDs given in the otherMessageIds attribute.
One possibility is to use a PhaseListener before the render phase to map the messages. The disadvantages of this method are:
- You need to remove the old message, otherwise you will get multiple messages for the same error.
- You can't associate the same error with multiple fields.
For these reasons, we use an alternative method which is to override the FacesContext object with our own.
To do this, you need:
- A FacesContextWrapper implementation which implements the adaptor pattern for a FacesContext. This is so we don't have to implement all the faces context methods ourselves!
- A MessageMappingFacesContext implementation, which is a subclass of the wrapper.
- A FacesContextFactory implementation which creates your special MessageMappingFacesContext instances.
The FacesContextWrapper is a simple adaptor implementation for a FacesContext class. It is an abstract class that wraps a FacesContext and delegates all requests to the wrapped class.
The MessageMappingFacesContextFactory factory implementation creates instances of the MessageMappingFacesContext.
The key part of the implementation is the MessageMappingFacesContext which overrides the getMessages(...) function. The override method:
- Invokes the superclass to fetch the actual normal messages.
- Adds all these messages to an internal list
- Locates the associated component for the client ID, and if this component exists and has the "otherMessageIds" attribute, invokes the superclass to fetch all messages for each message ID and adds them to the internal list
- Returns an iterator for the internal list
I've implemented this technique and it works fine. When I get a chance, I'll post a code example.
I've Moved!!
Well, it's been a long time since the last post and a lot has happened.
- I got married to my lovely Laura;
- We moved to Brisbane, Australia; and so...
- I now work at Workcover Queensland (it does Worker's Compensation for all of Queensland).
I'm still doing webapps using Java technologies, just the specific technologies have changed. Now I'm using JSF and Spring, rather than TIBCO products.
Tuesday, June 27, 2006
Load-balancing with the TIBCO Portal
The TIBCO Portal (and perhaps other TIBCO web-based products) does not support load-balancing within the product itself. It is the responsibility of the servlet container to implement load balancing.
A brief explanation of the TIBCO system is necessary. TIBCO uses a product called the TIBCO Administrator (I'll call it the Administrator for short) to maintain an "administrative domain". This administrative domain consists of machines, servlet containers and software. Machines and servlet containers are registered with the Administrator. The TIBCO portal is packaged as an EAR which is deployed by the Administrator on the domain. The EAR contains several services (WAR files) which are deployed by the Administrator to one or more servlet containers registered with the domain.
You would think that you'd be able to deploy the portal services to more than one host and then place those hosts in the load-balanced cluster.
Unfortunately, you can't deploy most portal services to more than one servlet container in a domain. So, you can't do load-balancing this way.
As I said earlier, it is the responsibility of the servlet container to implement load balancing. The Administrator expects that the cluster behaves like a single servlet container, and that you register the cluster with the Administrator, not the constituent servlet container instances.
I wanted to do a load-balanced install of TIBCO Portal Builder under SunONE 6.1 SP4. This version of SunONE doesn't support clustering natively, and as I mentioned above, the Portal won't allow us to deploy services across multiple servlet containers. To work around this, TIBCO suggested that we install the portal on one machine, then copy (manually) the configured and deployed web applications to a servlet container on the other machine.
There is a snag with this approach, however. Some Portal services cannot be installed in this way. The BPS_PB, and CPS services must not be deployed onto more than one servlet container. So, to work around this, you have to place these services in yet another servlet container.
There is one final point with this approach. The Administrator appears to store the file system path of each registered servlet container in the Administration database. Each Portal service uses this information to find the file name of the servlet container configuration file (e.g. server.xml in SunONE) and parses this file on servlet initialisation. Precisely why this is necessary, I don't know, but the upshot is that:
If you don't, you won't be able to start the second server instance successfully.
A brief explanation of the TIBCO system is necessary. TIBCO uses a product called the TIBCO Administrator (I'll call it the Administrator for short) to maintain an "administrative domain". This administrative domain consists of machines, servlet containers and software. Machines and servlet containers are registered with the Administrator. The TIBCO portal is packaged as an EAR which is deployed by the Administrator on the domain. The EAR contains several services (WAR files) which are deployed by the Administrator to one or more servlet containers registered with the domain.
You would think that you'd be able to deploy the portal services to more than one host and then place those hosts in the load-balanced cluster.
Unfortunately, you can't deploy most portal services to more than one servlet container in a domain. So, you can't do load-balancing this way.
As I said earlier, it is the responsibility of the servlet container to implement load balancing. The Administrator expects that the cluster behaves like a single servlet container, and that you register the cluster with the Administrator, not the constituent servlet container instances.
I wanted to do a load-balanced install of TIBCO Portal Builder under SunONE 6.1 SP4. This version of SunONE doesn't support clustering natively, and as I mentioned above, the Portal won't allow us to deploy services across multiple servlet containers. To work around this, TIBCO suggested that we install the portal on one machine, then copy (manually) the configured and deployed web applications to a servlet container on the other machine.
There is a snag with this approach, however. Some Portal services cannot be installed in this way. The BPS_PB, and CPS services must not be deployed onto more than one servlet container. So, to work around this, you have to place these services in yet another servlet container.
There is one final point with this approach. The Administrator appears to store the file system path of each registered servlet container in the Administration database. Each Portal service uses this information to find the file name of the servlet container configuration file (e.g. server.xml in SunONE) and parses this file on servlet initialisation. Precisely why this is necessary, I don't know, but the upshot is that:
- You have to install the servlet container in exactly the same location on both load-balanced machines, and
- You have to set the server name of servlet container on both the load-balanced machines to the same name.
If you don't, you won't be able to start the second server instance successfully.
Saturday, June 24, 2006
My and my "Canguro"
Friday, June 23, 2006
Code Formatting for Blogs
It has been annoying me for some time that I didn't have properly formatted code in this blog. I could get it to either indent correctly but expand and ruin the page formatting (using <pre>), or line-wrap inappropriately (using <tt>).
Today I did a bit of web searching and found this excellent blog article on how to format ruby code for blogs. While the whole solution is a bit more than I need, inserting the following snippet of CSS into my blog style was just the ticket.
There's still a little bit that's not prefect (small <pre>...</pre> sections still look a bit funny), it's almost exactly what I was looking for!
Isn't the web wonderful :-)
Today I did a bit of web searching and found this excellent blog article on how to format ruby code for blogs. While the whole solution is a bit more than I need, inserting the following snippet of CSS into my blog style was just the ticket.
pre {
background-color: #f1f1f3;
color: #112;
padding: 10px;
font-size: 1.1em;
overflow: auto;
margin: 4px 0px;
width: 95%;
}
There's still a little bit that's not prefect (small <pre>...</pre> sections still look a bit funny), it's almost exactly what I was looking for!
Isn't the web wonderful :-)
Friday, May 12, 2006
Proxy me baby
We have pretty much decided to use the mod_proxy_html module for apache with SunONE as our platform. This means that the apache module will parse and rewrite the HTML generated by the portal, fixing up the URLs as appropriate.
Why? Well the production environment is using Novell iChain, and it does basically the same thing. Thus, developing and testing with this parsing overhead is a reasonable way to proceed.
Hopefully this will work properly!
Why? Well the production environment is using Novell iChain, and it does basically the same thing. Thus, developing and testing with this parsing overhead is a reasonable way to proceed.
Hopefully this will work properly!
Subscribe to:
Posts (Atom)
