Posts

Showing posts from 2009

Friendly paths to access dynamic JSF content

JSF 1 is HTTP POST based and, as such, makes it hard to generate friendly/RESTful URLs that are meaningful to the user. Try to serve something like a content management system (CMS) using JSF and you immediately run into problems. However if you write a custom ViewHandler , you can translate the virtual url, such as /page/about/contactUs , into a physical page (view), e.g. /dynamicContent.xhtml . All cases where the ViewHandler references the viewId (which is just the full filename of the page its executing/referencing), need to be mapped correctly so that JSF opens the page that exists, while the user sees the content specified by the URL that maps to a database for example. Below is the view handler that wraps around the Facelets view handler to provide the described functionality.: /** * View Handler that wraps around first Facelets then the default handler, to translate the virtual address of the content page to the physical xhtml * page that will serve it. * * @author Ch...

Undeploying Google Guice jar file locked

When trying to undeploy an webapp that uses Google Guice from an webapp server like Tomcat, you may notice that it doesn't undeploy properly. The problem seems to be related to com.google.inject.internal.Finalizer , which is a Thread created to clean up after Guice is finished. However the thread doesn't stop properly. My solution is to modify this class (by just adding that individual source file to the project as I don't want to rebuild the whole project) adding a stop method that can be call from a ServletContextListener.contextDestroyed() . My modified Finializer: private boolean stop = false; /** * Loops continuously, pulling references off the queue and cleaning them up. */ // @SuppressWarnings("InfiniteLoopStatement") @Override public void run() { try { while (!stop) { try { cleanUp(queue.remove()); } catch (InterruptedException e) { /* ignore */ } } } catch (ShutDown shutDown) { /* ignore */ } } public void stopThr...

Actions not being called when using 2 view tags

I had a problem where a command button's action was not being called on the managed bean. When using tiles inside JSF, you may have it set up so that you have a template.jsp and a body.jsp. The template.jsp, using tiles inserts body.jsp. template.jsp defines a <f:view> tag as per normal. Inside body.jsp, whilst you don't technically need a <f:view> tag, you may get some component (namely f:phaseListener ) complaining about not having a view root, so you does it asks and defines the <f:view> at the start of the file. You load up the page, everything renders correctly and you click a submit button. The form validation errors appear as normal, so you fill in some values and click submit again. This time, NOTHING. So you try turning on all the logging and still nothing seems wrong. This happened to me. I wasted quiet a few hours on this one: working out how to log things correctly using eclipse/tomcat and get Java Util Logging working etc. After a ton of breakp...

Calling JSF actions by URL

In JSF 1, there is no provided functionality to invoke an action (by this I mean a java function, not a JSF action invoked by a component). JSF 2 adds functionality to support this, through f:viewParam / f:event and the PreRenderViewEvent . However in JSF 1, you can bind a phase listener to a specific page using the f:phaseListener tag to call the code before the Render Phase. To make sure that the code is only called when the page is access via the url and not from a postback caused by a component you can use the function added in JSF 1.2:  ResponseStateManager.isPostback(FacesContext context) . First off we configure the phase listener in the page (action.xhtml): <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core"> <f:phaselistener binding="#{urlActionBean.listener}" /> Next is the phase listener and action code: public class UrlActionBean { /*...

Eclipse Plugins

After having my elcipse install crashing several times, I thought it a good idea to compile a easily accessible list of plugins I use. Log4E Allows loggers to be added to classes, replaces System.out and printStackTrace etc Website: http://log4e.jayefem.de/content/view/3/2/ Update site: http://log4e.jayefem.de/update Log4Eclipse Log4j socket appender host - allows log4j to send log messages directly to eclipse (no need to inspect log files). I have rebuilt it using log4j 1.2.15 see below. Website: http://www.nitwit.de/log4eclipse/ My build: log4eclipse_0.4.0.jar Subclipse Subversion client Website: http://subclipse.tigris.org/ v1.6 Update site: http://subclipse.tigris.org/update_1.6. x v1.8 Update site: http://subclipse.tigris.org/update_1.8.x JBoss Tools Tools for JBoss server and JSF/Richfaces/Facelets editors. Plus a lot of others (I just use the richfaces plugin). Website: http://www.jboss.org/tools Update site: http://download.jboss.org/jbosstool...

Multiple Log4J instances in a WebApp

Many times I've come across the classic problem of different logging instances in an web app server. Most of them involve classloader conflicts: The webapp has log4j.jar but the webapp has bundled log4j.jar as well and you get errors. OR you have the log4j.jar in the application server's shared library directory and you have 2 webapps but the configuration conflict - or even just a configuration for the application server itself and one for the webapp. I've finally come across a solution for log4j. It involves using a repository selector based on a context, this is fully described here - Supporting the log4j RepositorySelector in Servlet Containers . So the solution to stop conflicts and independently configure each application is this. First put ALL logging jars in the shared library directory including ( log4j.jar, slf4j-api.jar, slf4j-log4j.jar, commons-logging.jar, etc). This ensures that if they one of the libraries is loaded in the main classloader it can access the ...

Access Control in JSF using a PhaseListener

After doing a quick search of the web, I did not find any nice solutions to implementing access control in JSF. Using a servlet filter mapping seemed inadequate, and there wasn't any obvious place to start. I initially tried using a custom NavigationHandler, however that is only used after an action is performed (e.g. #{someBean.action} ), and not for directly accessing a URL (e.g. typing in /test.faces). Some more searching revealed that a PhaseListener was the place to do it. After checking the JSF lifecycles I determined that RESTORE_VIEW was the correct place to do it - ALL pages go through at least the RESTORE_VIEW and RENDER_VIEW phases. You can check the viewId in the afterPhase (as the view has been loaded in this phase, hence can't check in beforePhase) and redirect using the navigation handler as nesecary. Below is my implementation of it. I used a flexible inclusion/exclusion filter so I can make the rules as complex as I want. This implementation determines ...

JSF - Injecting Managed Beans into Managed Beans

Using Google Guice and JSF with something like GuiceSF to inject the JSF managed beans (backing beans) gives you a lot of power over the injection. However, by doing so JSF no longer resolves the EL expressions from faces-config.xml and injects them into the managed beans. An easy way around this, and somewhat cleaner, is to create an annotation that is 'bound' to an EL expression. To do so requires the use of GuiceyFruit's extensions to Guice. First create the annotation: import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; import com.google.inject.BindingAnnotation; /** * Injection by expression language. * @see com.google.inject.name.Named */ @BindingAnnotation @Target( { FIELD, PARAMETER, METHOD }) @Retention(RUNT...

EJB3 Stateful Session Beans with ejbCreate

I had trouble obtaining a stateful session bean using the EJB3 pattern when trying to pass initial data to it. You can use injection to create instances of stateful beans by simply declaring an instance variable in a bean, for example: @EJB MyStatefulLocal mylocal; . But this doesn't allow you to pass any data on creation. The answer is to use a EJBLocalHome interface like in EJB2 but it's a bit complicated with all the annotations. The ejbCreate method from EJB2.1 is called create in the local home interface and called whatever you want in the bean itself (as long as it is annotated with @Init Below is an example. You can download the source here: download source . /** Local Interface. Dummy interface to enable us to return the Business interface. */ public interface MyStatefulLocalEjb2 extends EJBLocalObject, MyStatefulLocal {} /** Local Business Interface. Put business method definitions here */ public interface MyStatefulLocal {} /** Define method(s) which create the E...

Reacquiring a Stateful Session Bean on NoSuchEJBException

In the current project I'm working on I'm using a Tomcat server connecting to a remote JBoss instance. We're using a Stateful Session Bean (SFSB) to hold the session information for the current user for authentication/access control purposes. The bean is stored in tomcat within the session (within a session-scoped managed bean actually) and generally it works fine. However, if the bean is destroyed on the server then, as per the EJB specification, an NoSuchEJBException is thrown. This could be handled individually by catching the exception, printing a user friendly message and getting a new instance of the session bean. However, it you've got several method calls across multiple classes, having this try/catch code throughout all the classes bloats the code and just plain looks ugly. I wanted a solution where I didn't need to touch the module variable that stored the EJB given to me by jboss - I wanted it to obtain a new instance itself. The reason being, if I hav...

Tomcat - load & bind an external naming context

In my previous post Injecting JBoss EJB3 beans into Tomcat6 , I used Tomcat's ability to bind EJB's to the local JNDI context by specifying JBoss' NamingContextFactory and the URL to the EJB. However in the process of using it, I discovered a problem with Stateful Session Beans . I was getting NoSuchEJBException - either after a redeploy to JBoss, or calling the @Remove annotated method on the session bean. A lot of debugging later, I discovered that the cause was that Tomcat was initially storing a ejb ref ( org.apache.EjbRef ) in the context and when first accessed it looks up the EJB using the factory and then replaces the reference in the context with the instance of the EJB. Every subsequent lookup in the context returns the same instance. This however breaks the JEE5 contract: FROM JSR 220: NOTE: When a stateful session bean is looked up or otherwise obtained through the explicit JNDI lookup mechanisms, the container must provide a new stateful session bean ins...

Injecting JBoss EJB3 beans into Tomcat6

Injecting EJB's into a managed bean (a bean spawned by appserver, of a JSF managed bean) inside an application server is simple: public class AppManagedBean { @EJB(mappedName="ejb/myBean") private MyBeanRemote session; The container looks up the mapped bean and injects it. Easy. However in tomcat it gets a little messy. Tomcat doesn't document how to inject them. It assumes something annotated with @EJB is in the context somewhere and tries to look it up. It has documented how to lookup ejb's by defining entries in your context.xml or server.xml. But there isn't anything documented for defining EJB's. Looking at the soure it has support for <Ejb/> references but no real clue on how to configure it. So after stepping through the code I came up with the following soloution: My environment is JBoss 5 running remotely (on localhost). A seperate instance of Tomcat 6. In it I have defined a session bean: @Stateful(mappedName="userSessi...

Change user name in eclipse

The code comment templates are handy for inserting the author of a class, which is handy in rather large projects. For example, here is my template for types(classes): /** * @author ${user} * * ${tags} */ However under windows (and probably *nix as well) it just inserts the current user name. But I want it always to display my real name - which is more meaningful when employees come and go. You can change it by passing this argument on the comment line: You need to put it at the end of your command line. eclipse.exe -vmargs -Duser.name="You real name"

A few good Guice Tutorials

I came across these rather good Guice tutorials in trying to find a way to integrate Google Guice in an application server (EJB3). Part 1: a quick intro . Part 2: method interceptors . This was the tricky one, how to inject EJB's which are created by the container without having to have every class extend a base class with a @PostConstruct annotated method to do the injecting. The solution was to use the new interceptors introduced into JEE 5. Part 3 – Integrating Guice with EJB If you want a little background, see EJB Interceptors .

CommandButton not calling action when using immediate and rendered

I came across a problem with using a custom command component, that when using immediate it wasn't calling the action I had bound to it. I started resolving the issue and discovered my decode code wasn't being called. I had create a custom button, cannibalising and extending the original CommandButton component. Due to my lack of understanding of setting up renderkits, I gave up and hacked in a renderer: public class ImageButton extends HtmlCommandButton { private ImageButtonRenderer render = new ImageButtonRenderer(); @Override public void decode(FacesContext context) { render.decode(context, this); } @Override public void encodeBegin(FacesContext context) throws IOException { render.encodeBegin(context, this); } This resulted in decode not always working. I came across this nice summary of how to write a custom component and altered my code accordingly. Decode worked but the action was still not called. Thought the cause was j...

ClassCastException with PortableRemoteObject.narrow() EJB2/EJB3

After switching to JBoss 5 and recreating my EAR project inside eclipse, I started getting ClassCastException: java.lang.ClassCastException at com.sun.corba.se.impl.javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:229) at javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:137) Object obj = initialContext.lookup(ejbReferenceComponent); MyEJBRemoteHome home = javax.rmi.PortableRemoteObject.narrow(obj, MyEJBRemoteHome.class); After looking around, the cause of it is how the app server determines whether to give you a EJBHome instance which you have to use .narrow() then .create() to get a reference to the bean for EJB2 vs returning a proxy to the bean itself for EJB3. JBoss has some information on referencing EJB3 from EJB2 environments and vice-versa. The summary generally is if the application.xml has the EJB2 header then it gives you an EJBHome interface. If the ear's ejb-jar has the EJB3 header then it gives you a proxy to the bean itself (no need ...

Simple transactional unit testing database

Last week I wrote a post about using Google Guice to perform transaction handling using interceptors . When it came time to write some database level unit tests, I wanted to have the same kind of simple transaction handling so that every unit test is rolled back on completion. Rolling back the changes each test makes is necessary for the tests to be repeatable and consistent . TestNG provides convenient way to do processing before and after each method is called using @BeforeMethod and @AfterMethod . All you need to do is annotate methods that you want automatically rolled back with @Transactional then check for it and act accordingly. The same could be done with JUnit using a RunListener . Below is my implementation. I use just one connection per unit test, it can easily be adapted across multiple connections. public abstract class BaseUtilTest { private static final Logger log = Logger.getLogger(BaseUtilTest.class); protected Connection con; @BeforeClass public void init()...

Lightweight transaction handling in Tomcat

With Enterprise Java Beans (EJB) used with Container-Managed Transactions (CMT), transactions are transparently handled by the application server. When a method is marked with @TransactionAttribute(REQUIRED) then it starts a transaction (if one is not already started) and on competition of the method commits it (if it created the transaction). If an exception occurs, then the container rolls back the transaction. The beauty of it, is that it requires no extra code, just a single annotation. However, if running outside an application server, e.g. in a Tomcat only environment, then container managed transactions cannot be used. The common approach would be to use Spring. Spring provides the same functionality as EJB's but with a few drawbacks. It requires a large number of libraries to be included in your classpath plus a cumbersome to maintain configuration file just to set up some basic transaction handling. Spring does have its advantages but is overkill in a lot of cases. E...

Logging Tomcat 6 startup via log4j

For a recent task I had the need to log the tomcat startup process via log4j (so I could view it in eclipse using the log4eclipse plugin). The simple copying log4j.properties and log4j.jar into TOMCAT/lib didn't work as it had for previous versions. After some quick digging around I finally read the right section of the documentation . The steps are pretty easy to follow. The jar of juli (their logger) that comes with the standard build doesn't allow for commons-logging. To get it to work you need to download the source and compile the extras commons-logging. Which is a simple: ant download ant build-only ant -f extras.xml commons-logging Next: Replace $CATALINA_HOME/bin/tomcat-juli.jar with output/extras/tomcat-juli.jar . Place output/extras/tomcat-juli-adapters.jar in $CATALINA_HOME/lib. For apache-tomcat-6.0.14-src you'll need to change build.properties.default line 45: jdt.loc=http://archive.eclipse.org/eclipse/downloads/drops/R-3.2.2-200702121330/ecl...