Blog Archives

November 8th, 2011
8:02 pm
iMedia Linux– configuration/application install issues

Posted under Linux
Tags , , , , , , ,

This post brings together a number of past issues which I have not posted previously, discovered while setting up and using iMedia embedded Linux on my diskless LinITX Jupiter test box.

A zip of all the customised scripts and various config files (such as the infamous xorg.conf) are in the repository.

Shell Script Usage

1/ The startup scripts for applications and drivers etc. are in /etc/rcS.d/. You just add scripts to that and they are automatically run. They are all run by /etc/rcS in alpha order. They are grouped by a prefix of M05, M10, M20, M30 etc. – this seems just to be an arbitrary grouping that determines the order for dependencies etc. Note that all of rcS.d/ is run at run level 3 as set in /etc/inittab

The general order of startup is therefore (see /etc/inittab):-

  • /etc/rc.init runs, and calls rc.sysinit directly
  • /etc/rc.sysinit iterates init.d and runs everything in it. The order is partly determined by an initial grouping number – note the first to run is 00createvar which creates the /var tree on startup (see later)
  • /etc/rcS runs as above, iterating /etc/rcS.d/

2/ /usr/local/bin/ has the extra shared shell scripts – rlog, rlog-leafpad, sx (start X), sxr (start X as root), plus start/stop scripts for Tomcat and Glassfish.

In Thunar, you can add file associations for scripts by right clicking in the file and selecting open with other application – for each app you can add a custom launch command below. (I added rlog and rlog-leafpad). If you add an incorrect one (I added beaver by mistake) Thunar may not let you remove it from the list. Just edit ~/.local/share/applications/defaults.list and remove it from there. Note that /usr/local/bin/ is already on the path so all the script in it are visible – good place to put other global scripts.

Note that you can add scripts to e.g. a program launcher on the top panel bar – right click and create a program launcher, then add items to it – useful for scripts which run without parameters (unlike the rlog and rlog-leafpad above which act on files and therefore are Thunar’s context menu for the files they operate on). When adding a script as an item to a program launcher, the ‘startup notification’ just gives a wait cursor while the script is running (useful). Running in an explicit terminal window is WEIRD – for example for glassfish I set the middle icon on the RHS pane to “terminal”, and set the command to be “aterm -e start-glassfish”. I did not tick “Run in Terminal” as this did not work however!

Logging under iMedia Linux

1/ Logs are stored under the /var tree which is recreated at startup each time see above, so log files are purged as we are running on a small flash based distro. Therefore, Tomcat and Glassfish for example are set to use sym links to link their log directories from their normal install directories to be under /var/log/. There is some trickery to this – for Glassfish I make sure that the *normal* log folder is not present (renaming it with a date/time stamp if required) else the sym link is set up wrongly.

2/ Some logs (but by no means all) in /var/logs/ are circular buffers handled by emlog  – see here for details. They show in Thunar as ‘character type devices’ and  need copying to be visible – /usr/local/bin/rlog does this using nbcat as per the emlog site. I also added /usr/local/bin/rlog-leafpad which does the copy and fires up leafpad on the result. Note that as the emlog site states, you cannot list such a log when active using cat as a non blocking read is required – hence the need for nbcat as used by rlog and rlog-leafpad.

Installing new Applications

1/ Installing new apps is a pain, as rpm installs don’t appear to be supported etc. I tried installing various zipped tarballs of VNC/RDP alternatives for remote desktop but they all needed dependant libraries I did not have, so I had to give up. I think you can build from source to add things but did not go that far! The apps I did install successfully – java 1.6.0_29, tomcat 6.0.29 and Glassfish 3.0.1 – was all installed in folders under /opt as this appeared to be the correct place. Note that for Tomcat, I placed the config files under /etc/apache-tomcat-6.0.20/conf/ and sym-linked them from the ‘expected’ place, /opt/apache-tomcat-6.0.20/opt/, as this appeared to be correct protocol – other apps placed their config under /etc/ and linked to it from their install directory under /opt/. However I did not go to the trouble of doing this for Glassfish – it would be possible (I did do it for the log directory) but the directory structure is more complex.

2/ I did have success with Java – I just ran the .bin install kit of the latest Linux version of the sun Java SE (jdk6u29), and it all unzipped properly and ran fine. Thankfully there were no library problems – probably because there had already been an earlier working jdk6 already installed by default. I added a shell script /etc/profile.d/java-jdk1.6.0_29.sh which created the JAVA_HOME and added the bin directory to the path, but note that this did not work for init time shell scripts for either Tomcat or Glassfish, so their startup scripts had to add their own definitions to work.

3/ I successfully installed Glassfish 3.0.1 (from the zip kit download). To get it to work I had to upgrade Java as above as I got errors otherwise, and the old jdk was below the minimum certified version. However, it worked fine after upgrading java. Note that to stop it checking for updates on startup I just renamed /opt/glassfish-3.0.1-web/glassfish/modules/console-updatecenter-plugin.jar by adding “.disabled” on the end. You can achieve the same thing using the updatetool, but this failed to install properly due to a python error/dependency. I also removed the default jsf-api.jar and jsf-impl.jar from the same folder as above, and added the Mojarra 2.0.4 FCS jars to the folder instead, as my apps needed this version. Note that this also speeds up the startup of the Glassfish admin tool. See my notes here about clearing the osgi cache if you do this.

4/ For Tomcat and Glassfish I separated out the log directory creation from the actual startup, using separate scripts. The log creation is always run, and so sits under /etc/rcS.d/, and the auto startup is optional and may sit under /etc/rcS.disabled/ as a placeholder if it is not autostarted. However, as the log directories under /var/ are always setup, you can then manually start them if desired and they will still work. This is done with the scripts in /usr/local/bin/start-glassfish/stop-glassfish/start-tomcat/stop-tomcat. As this directory is on the path, the scripts can be directly run from a terminal window OR from a remote SSH window BUT you would need to be logged in as root to do it.

Graphical Remote Desktop

Re remote desktop, it is in theory possible to use a windows based X server and connect in that way. To do this, you need to run an X display manager on the Linux box to handle the xdmcp protocol etc. imedia linux does have /usr/bin/xdm which is an old display manager. I did manage to run it from the initial login prompt before typing startx, just by typing xdm, and it popped a login screen. However it would not connect to xfce. It recognised a valid login and tried to do something, failed, and redisplayed itself. An invalid login gave a login failure. I also managed to run the launcher from XMING under windows, and got as far as connecting to xdm. to do this I edited /etc/X11/xdm/Xaccess to enable the “*” entry to allow all comers. I also experimented with editing /etc/X11/xdm/xdm-config and set DisplayManager*authorize to false, and tried commenting out the last line as follows :-

! SECURITY: do not listen for XDMCP or Chooser requests
! Comment out this line if you want to manage X terminals with xdm
!DisplayManager.requestPort:    0

I managed to get XMING to display the same xdm login screen that I got locally, which was a good start – I knew I had a connection working. However, I realised in the end that xfce does not appear to be using a display manager – it simplifies things and bypasses it, and to set up xdm to link properly to xfce and to work remotely looked like loads of setting up with no instructions on how to do it properly.

I therefore sadly gave up on this and admitted defeat on installing any kind of graphical remote desktop!

Samba

I got the samba server to share folders successfully – I added the shares in /etc/samba/smb.conf. Security was set to user (security = user). I tried setting “valid users=” to a list of users, to allow restriction of users e.g. to glassfish/tomcat log folders, but could not get this to work, so I left it out.

Note that I did need to use “smbpasswd -a username” to add an existing linux user to the samba user list, and give it a password. You need to run as root to do this, or it merely allows you to change your own password. smbusers allows you to map external users (used by windows clients) to linux users – see here. Note that you don’t need to do this – you can just use the linux names. Note also that when adding/setting passwords with smbpasswd, you *always* use the Linux name, not the samba alias. Some other useful links for Samba follow:-

Ftp, Telnet and SSH

1/ ftp is enabled by default via vsftp. The config file is in /etc/vsftpd/vsftpd.conf. The default settings are pretty sensible in opening it up for use in a secur local lan. ftp works via all the local linux accounts including root. The log is in /vat/log/vsftpd.log.

2/ Telnet works but does not allow root access (presumably as too insecure). utelnetd is the daemon but there is no documentation for it on the net I could find. SSH works fine via the sshd and allows root access, but could not find any config files or logging for it, although it is documented on the net – the man pages are here, however the config files mentioned for the daemon do not appear to be present under imedia Linux. No problem, it is set up fine for LAN use and works well from putty in ssh mode.

No Comments »

September 23rd, 2011
3:17 pm
Preventing Overflow with long strings in table cells

Posted under JSF
Tags , , , , , , ,

I hit this issue when displaying email addresses in a p:dataTable.

The problem is that for long strings without spaces, the browser tries to enlarge the table cell width, causing the table to stretch beyond the correct bounds and messing up the layout. A column will wrap and enlarge vertically, but this will only be done when it can break on a space. Setting the widths for the columns is technically just advisory on the browser and may be overriden if needed.

There are various solutions to this, and this post here in Stack Overflow discusses them.

My chosen solution in this case was the following:-

  • Place the text in the cells in <spans>, to allow them to be styled with CSS. You could also style the column <td> cells by applying style/styleClass attributes to the p:column tag, but this will limit your flexibility – for example if you do this p:column does not expose the title attribute on the <td> (see below)
  • Style the <spans>  with display:inline-block;overflow:hidden. This allows a width to be set for the span (I used the same width as set for the column), and hides any overflow (which would otherwise bleed into the next column).
  • Text will still wrap on spaces if they are present, but long strings without spaces, such as email addresses or file paths, do not cause a problem, but they will truncate and so will not be fully visible by default.
  • I include a title attribute on the span to include the full text. This allows the full text to be displayed on hover for any long strings that are truncated in the cell.

This neatly solves the problem, and prevents the table layout messing up.

No Comments »

September 23rd, 2011
1:21 pm
JPA – Using a mapped superclass to hold Ids and Version Numbers for all Entities

Posted under JPA
Tags , , , ,

All my entities have a numeric ID as a primary key, except in very exceptional cases. In particular, I never used business data as part of the primary key, nor do I ever use a primary key for any business purposes (such as an invoice number). I consider that primary and foreign keys are only used to define relationships, i.e. they are metadata as far as the domain model is concerned.

The problem of using business data in primary keys is that if the business data format for a primary key changes in any way, all the foreign keys referring to this primary key column must also be changed. This can result in massive changes throughout the data model for what started as a simple business change. Taking the above invoice number for example, the business may decide to add an alphanumeric branch prefix to the invoice number.

If instead all primary keys are kept as separate numeric IDs, changes to the format of business data should typically only require changes to one table.

With that rant out of the way, the main point of this post is that, given the above, plus the need to hold version numbers on all entities to support optimistic locking, it is desirable to hold all the primary keys and version numbers in a mapped abstract superclass. This has the following benefits:-

  • the entities are simplified and the key/version number implementation is encapsulated and centralised, which is a good design principle
  • the mechanism allows for a standard mechanism to get the primary key/version of any entity polymorphically via the mapped superclass. This is especially useful when you need to do comparisons between entities and you do not want to override equals on the entities. It is also useful for other polymorphic situations – in my case I also have a polymorphic tree implementation which makes use of this

Note the following points about the implementation:-

  • As I have discussed here, I always annotate getters rather than fields, to permit inheritance. In this case, I provide fields plus polymorphic getters/setters in the mapped superclass for getEntityId and setEntityId which are marked transient and are not annotated. They are purely to allow polymorphic access to the primary key.
  • Each entity defines its own getters/setters with a mnemonic name for the primary key. These getters/setters call the base polymorphic ones. The reason for this is that as well as improving the key naming,  it allows each entity to annotate its primary key differently, for example to use a specific generator for sequences etc.
  • As the primary keys are annotated in the subclasses, this permits the base superclass IDs to be generic. In my case, this caters for both Long and Integer primary keys using a generic base superclass. Note that it would not be possible to annotate in the superclass if the ID is a parameterised type – JPA spits this out and will not allow it.
  • Due to the above generic issue, the type for the version number must be fixed, as this is annotated in the superclass. In my case I settled for an int for version numbers.
  • Note that as the primary key is generic, it must therefore be a reference type rather than a primitive type (e.g. Long rather than long). In my case, primary keys are normally Long
  • In some cases, I have other mapped superclasses, such as Tree and TreeNode classes. In this case, Tree and TreeNode extend the EntityBase class, and Tree and TreeNode subclasses then just extend Tree and TreeNode respectively.

The following code illustrates a simple example of the superclass and an entity subclass:-

 

EntityBase

/**
* Entity implementation class for Entity: EntityBase
* This mapped superclass defines the primary key and locking version number for all entities.
* The getters/setters are marked transient so they are not mapped here. This allows polymorphic access to primary key (and version),
* but still allows the subclass to define its own (mapped) getter/setter names for the primary key, and to annotate for specific generators etc.
* This allows meaningful names for primary keys, normally <tableName>Id
*/
@MappedSuperclass
@Access(AccessType.PROPERTY)
public abstract class EntityBase<C> implements Serializable {
    private static final long serialVersionUID = 8075127067609241095L;

    private C entityId;
    private int version;
   
    @Transient public C getEntityId() {
        return entityId;
    }
    @Transient public void setEntityId(C entityId) {
        this.entityId = entityId;
    }
    /*
     * The version cannot be generic as it is annotated here (unlike the primary key)
     * If you do, Eclipselink throws a tantrum. In practice, an int is plenty –
     * it would allow continuous version changes once a second for over 68 years for example.
     */
    @Version
    public int getVersion() {
        return version;
    }
    public void setVersion(int version) {
        this.version = version;
    }
}

 

Address

@Entity
@Access(AccessType.PROPERTY)
public class Address extends EntityBase<Long> implements Serializable {
    private static final long serialVersionUID = 3206799789679218177L;
   
    private int latitude;
    private int longitude;   
    private String streetAddress1;
    private String streetAddress2;
    private String locality;
    private String postTown;
    private String county;
    private String postCode;
       
    public Address(){}

    @Id
    @GeneratedValue(generator="AddressId")   
    public Long getAddressId() {return super.getEntityId();}
    public void setAddressId(Long addressId) {super.setEntityId(addressId);}
   
    public int getLatitude() {return latitude;}
    public void setLatitude(int latitude) {this.latitude = latitude;}
    public int getLongitude() {return longitude;}
    public void setLongitude(int longitude) {this.longitude = longitude;}
   
    public String getStreetAddress1() {return streetAddress1;}
    public void setStreetAddress1(String streetAddress1) {this.streetAddress1 = streetAddress1;}
    public String getStreetAddress2() {return streetAddress2;}
    public void setStreetAddress2(String streetAddress2) {this.streetAddress2 = streetAddress2;}
    public String getLocality() {return locality;}
    public void setLocality(String locality) {this.locality = locality;}
    public String getPostTown() {return postTown;}
    public void setPostTown(String postTown) {this.postTown = postTown;}
    public String getCounty() {return county;}
    public void setCounty(String county) {this.county = county;}
    public String getPostCode() {return postCode;}
    public void setPostCode(String postCode) {this.postCode = postCode;}   
}

No Comments »

September 23rd, 2011
12:18 pm
Re-queuing JSF Events

Posted under JSF
Tags , , , ,

This is a very simple and powerful technique which can provide an easy solution to a number of event issues.

The case in point was where I wanted a value change event on an input component (a check box) to behave like an action event.

The value change event will normally fire after validation (after the Process validations phase). In my case, I wanted the event to be fired at the Invoke Application phase, as would happen with a button click. In other words, I wanted my checkbox to behave more like a button.

Whilst there are other ways around this  kind of issue, they often involve messing with the JSF life cycle by using immediate components/calling render response early etc. and typically have other side effects. For example, in a Value change event you will not see the results of the bean setters being called as this has not happened yet, so you end up having to make JSF calls to manually update values early etc.

Instead, a value change event can easily be re-queued to occur in the Invoke Application phase. The beauty of this is that you are relocating the event rather than messing with the JSF lifecycle, which means that the event happens in the context you want it to, and everything is set up correctly.

To requeue an event, you must detect when it fires the first time, and then requeue it. When it fires the second time, you detect this again and perform the action that you desire.

Here is a code sample which does this:-

    public void showInheritedListener(ValueChangeEvent event) {

        /*
         * Requeue this event to the Invoke Application phase so it behaves like an action
         * This ensures that all the model values have been updated.
         */
        if (event.getPhaseId() == PhaseId.INVOKE_APPLICATION) {
               log.fine(this+":showInheritedListener: oldValue="+event.getOldValue()+", newvalue="+event.getNewValue());       
            boolean newValue = (Boolean)event.getNewValue();
            changeInherited(newValue);
        }
        else {
            event.setPhaseId(PhaseId.INVOKE_APPLICATION);
            event.queue();
        }       
    }   

An important point to note is the use of event.getPhaseId() to detect which phase the event is currently being called in. In particular, when it is first called after the Process Validations phase, it is important to note that event.getPhaseId() will return PhaseId.ANY_PHASE, which is not expected or intuitive. You will see from the above code that by handling the first call to the event in the else clause of the if, we only have to test for the second call, when event.getPhaseId() will return PhaseId.INVOKE_APPLICATION as you would expect.

This technique is clean and simple to use, and does not suffer from unwanted side effects that other solutions have. It is well worth taking note of.

No Comments »

July 26th, 2011
10:31 am
Extra unwanted margin around an HTML textarea in Google Chrome

Posted under CSS
Tags , , , , , ,

Chrome places an unwanted 4px bottom margin on a textarea, which is impossible to elminate purely by the margin settings.

In addition, the other browsers sometimes have related issues.

This post on StackOverflow discusses the issue, and the Chrome bug issue may be found here.

Issues like this can be caused in inline and inline-block elements, due to side effects of the line height/vertical alignment of textual elements. They can be hard issues to diagnose as the cause of the extra margin is not readily visible in tools like Firebug or Chrome’s developer tools/debugger. In order to see it, I added an extra div with a border around the element, and the margin was then clearly visible, but of course it was still not reported as a margin on the textarea element, which steadfastly maintained its story that no margin was present!

As per the StackOverflow article, there are 2 ways around this issue:-

  • If the textarea is set to have vertical-align:top then this eliminates the problem. It also has the advantage of maintaining the element as inline-block – in Chrome’s case this is the default, and with other browsers this will often be used in order to allow margins etc. which an inline element will not allow.
  • Another fix for the problem is to set the textarea to display:block, i.e. to make it a block element. This is fine, but it should be noted that as the element is not natively a block type element, IE7 and earlier IE versions will not handle this. IE8 and IE9 will allow an inline element to be redesignated as a block one. Therefore, the first method has better browser compatibility.

No Comments »

July 26th, 2011
10:05 am
Controlling textarea resizing in HTML

Posted under CSS
Tags , , ,

A number of web browsers (notably Firefox, Google Chrome and Apple Safari) have a feature whereby a textarea element in an HTML form can be dynamically resized after rendering, by allowing the user to drag the corner of the element. At the time of writing , IE and Opera do not have this feature.

This is often a desirable feature, but in order to preserve layout it is also desirable to restrict and control it as desired. The following facilities are available to do this:-

  • It can be disabled completely using the css property resize:none. Note that this is a CSS3 property, which limits its scope of use.
  • Another means to do this is by using the min-width, max-width, min-height, and max-height properties, which have the advantage that they are CSS2 properties and therefore more widely supported. They are also more flexible in that they allow precise control of the amount of resizing allowed on the element. Resizing can be disabled completely by setting the minimum and maximum width/height to the actual width/height values.

No Comments »

July 25th, 2011
11:35 am
Using the Primefaces p:panel component

Posted under JSF
Tags , , , ,

This post details some tips discovered whilst experimenting with p:panel.

1/ The toggle button on the right hand side of the panel is rendered with ui-state-default. This does not look attractive with some themes – it often looks like a bit of a zit due to the background on the thick plus sign icon. I noticed that the dialog component p:dialog does not render its close icon in the header with ui-state-default,  and this looks much more attractive as the surrounding highlight on the icon only shows on hover.

This can be applied to p:panel by removing the ui-state-default class from the anchor tags around the icons on the panel header. The following example jQuery performs this (in my case, the panelDivId argument is the ID of an h:paneGroup/div surrounding the panel:-

function ss_PanelFixIcons(panelDivId) {
    var escapedPanelDivId = panelDivId.replace(/:/g, ‘\\3A ‘);
    var panelIcons = jQuery(‘div#’ + escapedPanelDivId + ‘ div.ui-panel-titlebar > a.ui-panel-titlebar-icon’);
    panelIcons.removeClass(‘ui-state-default’);
}

 

2/ It would be nice to be able to explicitly expand and collapse the panel as well as to just toggle it. In fact the panel widget does expose its current state via its cfg property, although this is not publicly documented. The following example functions use this to provide explict expand, collapse, and set to passed boolean state functions. In addition a function is provided to get the current panel state:-

function ss_PanelExpand(widgetVar) {
    if (widgetVar.cfg.collapsed) {
        widgetVar.toggle();
    }
}

function ss_PanelCollapse(widgetVar) {
    if (!widgetVar.cfg.collapsed) {
        widgetVar.toggle();
    }
}

function ss_PanelSetCollapsed(widgetVar, state) {
    if (!widgetVar.cfg.collapsed == state) {
        widgetVar.toggle();
    }   
}

function ss_PanelGetCollapsed(widgetVar) {
    return widgetVar.cfg.collapsed;
}

 

3/ A query came up on the Primefaces forum on how to lazy load the panel, as it eagerly loads and the expand/collapse is all done client side. The post is available here. the solution is straightforward:-

  • Use a toggleListener to update a renderPanel property to true if the panel state from the event was visible, and false if it was hidden.
  • Then conditionally render a content h:panelGroup inside the panel, using the above property as the rendered property.
  • One issue with this is that the actual panel toggle occurs before the ajax update of the panel not after, so with the slide toggle effect on (say with toggleSpeed=”1000”), you see an empty sliding toggle first, then a non sliding ajax update. In this case it is best to turn off the slide effect with toggleSpeed=”0”. If you use another button to toggle the panel you can get around this, as the onComplete event for the button can toggle the panel (via its widget/ as per the above JavaScript), and this happens after the Ajax to render the panel. In practice you would have to somehow overlay the standard toggle button with another one of your own, or manually disable the standard one via CSS, as if you set toggleable=”false” for the panel this completely disables toggling via the widget as well as removing the toggle button.
  • It is probably not worth the trouble of trying to get sliding to work if you are lazy loading. Note that when I tried some older/slow machines the slide effect rendered poorly anyway, so this should also be born in mind.

No Comments »

July 21st, 2011
10:58 am
More useful Posts about inline-block and alignment

Posted under CSS
Tags , , , , ,

Update 18/1/2012

I was having trouble getting cross theme and cross browser consistency in aligning text adjacent to an icon in a series of IconTextButtons of mine, inside a toolbar.

Both the icon and the text were in spans set to display:inline-block and the spans were inside a div. I found the following useful in solving the issue :-

  1. The key issue turned out to be that the line-height was very different across Primefaces themes. The font size was constant at about (effectively) 11.5px, but the effective line-height varied with the them between 12px and 16px. This was the main cause of the issue in getting good alignment.
  2. I just set a fixed line-height of 14px for all the buttons in the toolbar, and this solved the cross theme (and cross browser) issues.
  3. The text was to the right of the icon, and found that tweaking the top margin for the icon set the position of both it and the text vertically, due to the adjacency-relative way in which vertical-align works.
  4. In order to adjust the vertical alignment of the text slightly relative to the icon, I found that setting a small bottom margin on the text achieved this, so one to bear in mind when experimenting.
  5. I had also tried padding changes as well as margin, but the effects (or lack of them) were similar to tweaking the margins.

 

Original Post

This post gives a good description of the effect on margins and padding for inline vs. block elements elements.

This StackOverflow post point out the effect of adjacent inline elements on the vertical alignment of an element – in this case an element was pushed down a few pixels due to the prescence of adjacent inline elements.

I was trying to align text and buttons in a narrow vertical toolbar, and as I have found previously, different browsers render differently.

The best consistency across browsers was obtained as follows :-

  1. Use display:inline-block to allow vertical margins to be obeyed on the elements. They can then be precisely adjusted (but may still behave differently depending on the adjacent elements). inline-block has decent cross browser support. IE6 and IE7 only support it on elements with a native type of ‘inline’ – see this post for cross browser support details.
  2. Using vertical-align:bottom seems to give the best cross browser consistency.
  3. Top and/or bottom margins generally need to be tweaked for each individual case depending on element adjacency. (Depending on the case you may need to set a top or a bottom margin to have the desired effect consistently across browsers.) For example, I had to treat a text only span differently to a text span adjacent to a couple of buttons on the bar.

No Comments »

July 19th, 2011
10:14 pm
Accessing JSF Resource Bundles from Java Code

Posted under JSF
Tags , , ,

This is useful to be able to do. Typically you will want to declare a resource bundle in faces-config.xml to load it once for the application. You then refer to it from any JSF page that needs it.

However, you often want to also load messages from code. An example might be the generation of custom faces messages or other error messages generated by the code.

It is clearly therefore desirable to access the same message bundle that JSF has loaded, so that it is specified centrally, loaded once for the application, and reused by both JSF and Java.

This post here by Andy Gibson details how to do this. The code fragments are shown below, in case the link ever becomes broken:-

 

Resource File

firstName=First Name
lastName=Last Name
forgotPassword=Forgot Password?
usernameTaken={0} is already taken

 

faces-config.xml

<application>
    <resource-bundle>
        <base-name>org.fluttercode.resourcedemo.MessageResources</base-name>
        <var>msgs</var>
    </resource-bundle>
</application>

 

Class MessageProvider

public class MessageProvider {

    private ResourceBundle bundle;

    public ResourceBundle getBundle() {
        if (bundle == null) {
            FacesContext context = FacesContext.getCurrentInstance();
            bundle = context.getApplication().getResourceBundle(context, “msgs”);
        }
        return bundle;
    }

    public String getValue(String key) {

        String result = null;
        try {
            result = getBundle().getString(key);
        } catch (MissingResourceException e) {
            result = “???” + key + “??? not found”;
        }
        return result;
    }

}

Backing Bean

@Named
@RequestScoped
public class SomeBean {

    public String getMessage() {
        String msg = new MessageProvider().getValue(“someMessage”);
        return MessageFormat.format(msg, “SomeValue”);
    }
}

Example Code to generate a custom FacesMessage (from CoreJSF Edition 3, Page 332)

public void validateDate(ComponentSystemEvent event) {
    UIComponent source = event.getComponent();
    UIInput dayInput = (UIInput) source.findComponent(“day”);
    UIInput monthInput = (UIInput) source.findComponent(“month”);
    UIInput yearInput = (UIInput) source.findComponent(“year”);
    int d = ((Integer) dayInput.getLocalValue()).intValue();
    int m = ((Integer) monthInput.getLocalValue()).intValue();
    int y = ((Integer) yearInput.getLocalValue()).intValue();

    if (!isValidDate(d, m, y)) {
       FacesMessage message = com.corejsf.util.Messages.getMessage(
            “com.corejsf.messages”, “invalidDate”, null);
        message.setSeverity(FacesMessage.SEVERITY_ERROR);
        FacesContext context = FacesContext.getCurrentInstance();
        context.addMessage(source.getClientId(), message);
       context.renderResponse();
    }

}

No Comments »

July 19th, 2011
8:54 pm
JPA – Accessing the primary key ID allocated during a persist operation on a new entity

Posted under JPA
Tags , , , ,

I wanted to do this in order to use the ID as part of the creation of a Base64 encoded tree path in another column in the same row, as I was using path enumeration as my tree algorithm (see here on slideshare.net for an excellent article on database tree algorithms).

The simple answer is – you can’t do this reliably, unless you allocate IDs yourself in some way.

  1. The ID is not available before a persist. I could call flush and then read it back, create the TreePath and then persist again – this is safe. This is discussed here on Stack Overflow.
  2. The JPA Lifecycle callback @PrePersist does not guarantee that the ID is visible. The net is rather quiet on this but this post here about hibernate says it cannot be relied upon  (@PostPersist would of course be different). There are strong limits on what you can do in such a callback or entity listener. For example, you can’t do entity manager operations, persist entities, or refer to other entities etc.
  3. Triggers would be another way to avoid the double update. I could set the rest of my TreePath prior to the first persist, and then retrieve the actual ID in a before insert trigger using the new.TreePathID syntax (MySQL and Oracle use similar syntax in this respect). I could then encode it in Base64 using a stored procedure, and append it to the treepath. Oracle has a built in package with Base64 encoding and decoding available (the utl_encode package). For MySql there is an open source example on the internet here. From posts on the net, e.g. here, triggers do work in MySQL via JPA.

The best solution looks like using triggers on the database server, as this avoids the double update. I have yet to investigate/try this.

No Comments »