Friday, February 24, 2012

Container Configuration - JBoss 7.1.0

Well, when I started this blog and promised to configure multiple containers, I didn't realize I was on the bleeding edge.  That is what you get for assuming everything is going to work.  In this post, we'll discuss some of the issues with JBoss 7, demonstrate how to configure it, and deploy an application with Eclipse and Netbeans.

First, JBoss 7.0.2 does not include support for the JSF EL call for a parameterized method.  i.e. #{bean.method()}.  Because we use this in a couple places, our app will not run on JBoss 7.0.2.  The good news is JBoss 7.1.0 does support it, was released a week ago, and is certified JEE 6.  So, there is no reason to continue to use JBoss 7.0.2 since it wasn't certified in the first place and who knows all the issues you'll run into trying to run JEE 6 in it.  In any case, the configuration is the same.

You will need to download the mysql-connector-java-5.x.x-bin.jar located at: http://dev.mysql.com/downloads/connector/j/

Create the needed directories, and unzip this file into: C:\jboss-as-7.1.0.Final\modules\com\mysql\main where C:\jboss-as-7.1.0.Final is your JBoss installation directory.

In that same directory, you will need to put in an xml file called: module.xml
In module.xml, you will have the contents of:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="com.mysql">
        <resources>
                <resource-root path="mysql-connector-java-5.1.18-bin.jar"/>
        </resources>
        <dependencies>
                <module name="javax.api"/>
                <module name="javax.transaction.api"/>
        </dependencies>
</module>

This of course means the the directory will contain 2 files. module.xml and mysql-connector-5.x.x-bin.jar.  Once you start JBoss, if everything is configured correctly with the module, you will get a third file added to the directory called mysql-connetor-5.x.x-bin.jar.index.  Note: in the module.xml above, it has the specific version I downloaded.  Be sure to keep all the x.x changed to whatever version you are using.

This will register your connector for use in the datasource.  Remember, there are several ways to get this job done, this is just one of them, but it works.  Once you have a complete working system, you can then decide how best to deploy it.

Next you need to modify the xml file of the type of JBoss server you are going to run.  i.e. Domain or Standalone.  Since I am doing development, I modified standalone.xml.  The modifications are the same for any of the configurations.

The standalone.xml file is located at: C:\jboss-as-7.1.0.Final\standalone\configuration\standalone.xml
Now, I'd show you the whole file, but JBoss has put the entire configuration into this one file.  So, I will only post the snipets that I modified.  First in one of the subsystems, you will find datasources.  It comes with the H2 datasource defined.  I left the H2 datasource in and added the MySQL datasource as follows:

            <datasources>
                <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
                    <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
                    <driver>h2</driver>
                    <security>
                        <user-name>sa</user-name>
                        <password>sa</password>
                    </security>
                </datasource>
                <datasource jta="true" jndi-name="java:/JSFDemoJNDI" pool-name="my_pool" enabled="true" use-java-context="true" use-ccm="true">
                    <connection-url>jdbc:mysql://localhost:3306/jsfdemodb</connection-url>
                    <driver>mysql</driver>
                    <pool>
                        <min-pool-size>5</min-pool-size>
                        <max-pool-size>20</max-pool-size>
                        <prefill>false</prefill>
                        <use-strict-min>false</use-strict-min>
                        <flush-strategy>FailingConnectionOnly</flush-strategy>
                    </pool>
                    <security>
                        <user-name>JSFDemoUser</user-name>
                        <password>ItWorks!</password>
                    </security>
                    <timeout>
                        <idle-timeout-minutes>5</idle-timeout-minutes>
                        <query-timeout>600</query-timeout>
                    </timeout>
                </datasource>
                <drivers>
                    <driver name="h2" module="com.h2database.h2">
                        <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
                    </driver>
                    <driver name="mysql" module="com.mysql"/>
                </drivers>
            </datasources>

Notice, I did not use an xa datasource.  If you are in an xa environment, you will have to change the driver and the datasource to reflect xa, but in a development environment, this is sufficient.  Also, remember you can delete the H2 stuff, I left it in to demonstrate the difference between what we added, and what is already there.

JBoss is a little pickier with the JNDI name then Glassfish was and I had to follow the java:/ convention.  So you will see in the code, that the persistence unit reflects the updated JNDI name.

Also note: we included the driver name to be used in the JNDI and it references the module we created previously.

A side note:  since I am running both the Glassfish Appserver and JBoss on the same box, I had to move one of them to a different port.  In the JBoss standalone.xml file, I changed the port 8080 to port 80 making JBoss respond to your typical web port.  Both app servers can run simultaneously on the same box.  

Eclipse supports JBoss 7 and will deploy directly to it.  But, once you have deployed, it does not always redeploy depending on.... well, seems like random events, but failure, success, etc. all play a part.  If you want to redeploy, just create a file, or change the app.status file to app.dodeploy.  i.e. You deploy JSFDemoApp.war, a file is created JSFDemoApp.war.deployed.  You want to refresh the deployment, and it didn't do it automatically for you.  Save your files in eclipse, they should automatically goto: C:\jboss-as-7.1.0.Final\standalone\deployments\JSFDemoApp.war and create a file C:\jboss-as-7.1.0.Final\standalone\deployments\JSFDemoApp.war.dodeploy.

Another note:  JBoss doesn't like persistence units it can't handle.  Meaning, your application won't run if the persistence.xml file is not completely to JBoss' liking.  So, in our first project, we had a persistence.xml file that contained a local persistence unit for testing.  Don't include that in our deployment to JBoss.

Lastly, Netbeans.  Netbeans 7.0.1 does not contain support for JBoss 7 servers.  You cannot directly deploy to a JBoss 7 server.  Let me tell you the quick and dirty trick I used and from there you can see how you would support it.  First, a war, jar, ear, etc. file is basically a zip file.  I could have used the directory structure in the build directory from netbeans and copied that over, but since my Glassfish server was using those, I just renamed the war file in the dist directory to be zip.  Used winzip to open it up and deleted the hibernate files, since I had a newer version of hibernate in my JBoss server, and I replaced the persistence.xml file with the JBoss persistence file.  Because I didn't want web services running on the JBoss server at that time, I deleted that as well.  Then I copied the war file to the C:\jboss-as-7.1.0.Final\standalone\deployments directory, and away it went.  So, although Netbeans doesn't support it, you can accomplish the support by setting up a maven project, an ant build script, or simply by doing what I did to get your war to be JBoss compliant.  Here is the persistence.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="JSFDemoPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/JSFDemoJNDI</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
      <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
    </properties>
  </persistence-unit>
</persistence>

Hopefully, I didn't leave out a step, but the same JSFDemoApp that we used in project-1 runs on both Glassfish 3.x and JBoss 7.1.0.  The manual said to ignore the Transaction Manager Lookup, but I didn't try it without it, I was having enough problems with the Transaction Manager already.  If you get one thing wrong, generally speaking, nothing will work.

Saturday, February 18, 2012

Primefaces

JSF comes with some basic components, but to get the most out of JSF, you will need to create your own custom components, or use a component library.  Primefaces is one such library that has many great components and they have AJAX built in.  In this application, we used menus, dialog boxes, command buttons, data tables, a tree, input boxes, output boxes, and display panels.  We presented icons on our menu items and buttons.  And we used AJAX throughout the application.  There are many other components in the primefaces showcase.  We also used one of their custom skins for a different look and feel (outcast.jar) which was configured in the web.xml.

The lables Primefaces use don't always match what you may expect, i.e. you use update= instead of render= for an ajax update of a component.  But, once you know it, it is quite simple to map the information, and much of that can be gotten directly from their showcase samples.

Review StartPage.xhtml in JSF Continued for samples of how each component was implemented.

Note:  do not update the dialog box, it stops working if you do.  Instead update the component (i.e. panel) or form in the dialog box to refresh the display.

Friday, February 17, 2012

AOP - Aspect Oriented Programming

Okay, what is AOP or Aspect Oriented Programming and how does it fit with JSF?  Well, we have already been using a form of AOP - Transactions.  Transactions are a typical use case of AOP.  AOP addresses cross cutting concerns and applys that to our objects.  Let us look for a moment how AOP affected our use of transactions.

If we were not using declarative transactions, we would have had to manage the transactions ourselves.  i.e.
public void save(Entity entity) {
    try {
            em.getTransaction().begin();
            em.persist(entity);
            em.getTransaction().commit();
     } catch (TransactionException e) {
            logger.log(Level.SEVERE, "Fatal error in persistence environment: ", e);
     }

}
And that doesn't even get into the JNDI lookup, etc.  But, with AOP we created a standard way of wrapping the transaction such that we can rewrite the above method as:
@TransactionAttribute( TransactionAttributeType.REQUIRED)
public void save(Entity entity) {
       em.persist(entity);
}
And that transaction already includes the JNDI lookup.  Now if we implement a new transaction manager, method, etc.  What do we change?  All we have to change is the AOP method.  AOP is implemented on our beans, just as we saw with our transactions.  Although there is no limit on what AOP can be applied to, some real world applications are: logging, security, auditing, read/write locks, exception handling, performance monitoring, caching, and of course transaction management.

Let us take a simple example.  Logging.  Suppose we normally have a class that looks something like:
public class MyClass {
    private  Logger logger = Logger.getLogger("MyClass");
    public void doSomething(Object someObject) {
        logger.log(Level.FINE, "doSomething ", someObject);
        try {
           ...
        } catch (SomeException e) {
             logger.log(Level.SEVER, "doSomething", e);
        }
        ...
    }
    ...
}


Now we can re-write that as:
@Trace
public class MyClass {
   @LogException
   public void doSomething(Object someObject) {
       ...
   }
   ...
}
And to change the logging all we have to change is the implementation of the @Trace, or @LogException and all the classes annotated by the above will change.

Let us look at a complete example.  This first example has a non binding parameter attached to it so that it will have to be interpreted at run time.  There are 4 files we have to deal with when implementing the AOP.  We need the actual interceptor, we need the annotation for the interceptor, we need to register the interceptor in beans.xml, and of course, we need to annotate our class with the annotation.

The interceptor: com/sample/interceptors/TracerInterceptor.java

package com.sample.interceptors;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
/**
 * @author Thomas Dias
 */
@Traceable
@Interceptor

package com.sample.interceptors;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
/**
 * @author Thomas Dias
 */
@Traceable
@Interceptor
public class TracerInterceptor {
    @AroundInvoke
    public Object log(InvocationContext ctx) throws Exception {
        Logger logger = Logger.getLogger(ctx.getTarget().getClass().getName());
        logger.setUseParentHandlers(true); // log to the container logs
        logger.setLevel(Level.ALL); // set this based on some configuration file
        Level curLevel = getTraceableAnnotation(ctx.getMethod()).logLevel().getLevel();
        if (logger.isLoggable(curLevel)) {
            StringBuilder msg = new StringBuilder();
            msg.append("Entering: ");
            msg.append(ctx.getMethod());
            msg.append(" Parameters: ");
            msg.append(Arrays.toString(ctx.getParameters()));
            logger.log(curLevel, msg.toString());
            Object returnMe = ctx.proceed();
            msg.setLength(0);
            msg.append("Exited: ");
            msg.append(ctx.getMethod());
            msg.append(" Returned : ");
            if (returnMe != null) {
                msg.append(returnMe.toString());
            }
            logger.log(curLevel, msg.toString());
            return returnMe;
        } else {
            return ctx.proceed();
        }
    }
    public Traceable getTraceableAnnotation(Method method) {
        for (Annotation a : method.getAnnotations()) {
            if (a instanceof Traceable) {
                return (Traceable) a;
            }
        }
        for (Annotation a : method.getDeclaringClass().getAnnotations()) {
            if (a instanceof Traceable) {
                return (Traceable) a;
            }
        }
        return null;
    }
}
Notice we have an "extra" method here to find out which annotation was used to call the interceptor.  This method then returns the parameter we put in our annotation.  i.e. @Traceable(logLevel=Traceable.LogLevelType.FINE) will return the FINE LogLevelType for the method Traceable.logLevel();

Otherwise we see that this interceptor will find the class name we are calling, get a Logger for that classname, log to its parents logger, set the log level to all (although this should come from a configuration), get the desired log level from the annotation being used, and if the annotation level for logging is less then the ALL loglevel, it will log a record before and after the method call.  We use this interceptor by putting @Traceable on the class in which case all methods will be logged, or we can put the @Traceable at the method which will then only log calls to that method.

The annotaion: com/sample/interceptors/Traceable.java

package com.sample.interceptors;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.logging.Level;
import javax.enterprise.util.Nonbinding;
import javax.interceptor.InterceptorBinding;
/**
 * @author Thomas Dias
 */
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Traceable {
    public enum LogLevelType {
        FINE(Level.FINE), WARN(Level.WARNING), SEVERE(Level.SEVERE);
        private Level level;
        LogLevelType(Level level) {
            this.level = level;
        }
        public Level getLevel() {
            return level;
        }
    }
    @Nonbinding
    public LogLevelType logLevel() default LogLevelType.FINE;
}
Notice here, we included an enum to support the different types the logLevel could be bound to.

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    <interceptors>
        <class>com.sample.interceptors.TracerInterceptor</class>
    </interceptors>
</beans>
Just keep adding <class>...</class> for each interceptor you want to use.

And a bean using the annotation: com/sample/beans/TreeBean.java

package com.sample.beans;
import com.sample.entities.OrderEntity;
import com.sample.entities.OrderPartsEntity;
import com.sample.interceptors.Traceable;
import java.io.Serializable;
import javax.enterprise.context.Dependent;
import javax.inject.Named;
import org.primefaces.event.NodeSelectEvent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;
/**
 * @author Thomas Dias
 */
@Named("treeBean")
@Dependent
@Traceable(logLevel=Traceable.LogLevelType.FINE)
public class TreeBean implements Serializable {
    MainSampleViewBean mainSampleViewBean;
    /** Creates a new instance of TreeBean */
    public TreeBean() {
    }
    private TreeNode selectedNode;
    private TreeNode treeRoot;
    private void addNode(OrderPartsEntity part, TreeNode parent) {
        TreeNode newNode = new DefaultTreeNode(part, parent);
        for (OrderPartsEntity subPart : part.getSubOrderParts()) {
            addNode(subPart, newNode);
        }
    }
    public TreeNode getOrderTree() {
        return treeRoot;
    }
    public void buildTree(OrderEntity orderEntity) {
        treeRoot = new DefaultTreeNode(null, null);
        if (orderEntity == null) {
            selectedNode = null;
            return;
        }
        TreeNode node = new DefaultTreeNode(orderEntity, treeRoot);
        for (OrderPartsEntity part : orderEntity.getOrderedParts()) {
            if (part.getParent() == null) {
                addNode(part, node);
            }
        }
        setSelectedNode(node);
        onNodeSelect(null);
    }
    public TreeNode getSelectedNode() {
        return selectedNode;
    }
    public void setSelectedNode(TreeNode selectedNode) {
        this.selectedNode = selectedNode;
    }
    public void onNodeSelect(NodeSelectEvent event) {
        if (selectedNode != null) {
            selectedNode.setSelected(true);
            selectedNode.setExpanded(true);
            Object nodeData = selectedNode.getData();
            StringBuilder msg = new StringBuilder("Selected Node: ");
            msg.append(nodeData);
            msg.append(", Parts Id: ");
            Long id = null;
            if (nodeData instanceof OrderPartsEntity) {
                id = ((OrderPartsEntity) nodeData).getPart().getId();
                msg.append(id);
                msg.append(", Order Entity Id: ");
                msg.append(((OrderPartsEntity) nodeData).getOrderEntity().getId());
            } else {
                msg.append("null, Order Entity Id: ");
                msg.append(((OrderEntity) nodeData).getId());
            }
        }
        mainSampleViewBean.partSelected();
    }
    @Traceable(logLevel=Traceable.LogLevelType.WARN)
    public MainSampleViewBean getMainSampleViewBean() {
        return mainSampleViewBean;
    }
    @Traceable(logLevel=Traceable.LogLevelType.WARN)
    public void setMainSampleViewBean(MainSampleViewBean mainSampleViewBean) {
        this.mainSampleViewBean = mainSampleViewBean;
    }
    public TreeNode getTreeRoot() {
        return treeRoot;
    }
    public void setTreeRoot(TreeNode treeRoot) {
        this.treeRoot = treeRoot;
    }
}

We have seen this bean before.  The only addition is the @Traceable line.  Notice here we overroad the log level at the method for get and set MainSampleViewBean.  This was actually overridden because when we did our annotation lookup in our interceptor, the getTraceableAnnotation looked first at the method annotations, then at the class annotations.

Our second complete example demonstrates if we bind the parameter to the interceptor.  Unlike the first one where we had to go find the annotation and figure out what value the developer set, here we know what the value is, but we have to make a separate interceptor for each possible value.  Now we have to deal with beans.xml, the bean we are going to annotate with the interceptor, the interceptors for each value, the annotation, and I included a utility class so I didn't have to duplicate the code.

The new beans.xml

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    <interceptors>
        <class>com.sample.interceptors.TracerInterceptor</class>
        <class>com.sample.interceptors.LogFineInterceptor</class>
        <class>com.sample.interceptors.LogWarnInterceptor</class>
    </interceptors>
</beans>

We are still using the first interceptor for the other bean, so we did not remove it from the beans.xml.  If we do remove it from there, the interceptor will be disabled.  We don't have to recompile to disable or enable interceptors.

The interceptor for the fine value: LogFineInterceptor.java

package com.sample.interceptors;
import java.util.logging.Level;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
/**
 * @author Thomas Dias
 */
@Loggable("FINE")
@Interceptor
public class LogFineInterceptor {
    @AroundInvoke
    public Object log(InvocationContext ctx) throws Exception {
        LogIt.enter(Level.FINE, ctx);
        Object returnMe = ctx.proceed();
        LogIt.exit(Level.FINE, ctx, returnMe);
        return returnMe;
    }
}

The interceptor for the warn value: LogWarnInterceptor.java

package com.sample.interceptors;
import java.util.logging.Level;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
/**
 * @author Thomas Dias
 */
@Loggable("WARN")
@Interceptor
public class LogWarnInterceptor {
    @AroundInvoke
    public Object log(InvocationContext ctx) throws Exception {
        LogIt.enter(Level.WARNING, ctx);
        Object returnMe = ctx.proceed();
        LogIt.exit(Level.WARNING, ctx, returnMe);
        return returnMe;
    }
}

The annotation: Loggable.java

package com.sample.interceptors;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;
/**
 * @author Thomas Dias
 */
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Loggable {
    public String value() default "FINE";
}

The utility class: LogIt.java

import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.interceptor.InvocationContext;
/**
 * @author Thomas Dias
 */
public class LogIt {
    private static Logger logger = null;
    public static void init(InvocationContext ctx) {
        logger = Logger.getLogger(ctx.getTarget().getClass().getName());
        logger.setUseParentHandlers(true); // log to the container logs
        logger.setLevel(Level.ALL); // set this based on some configuration file
    }
    public static void enter(Level level, InvocationContext ctx) {
        if(logger==null) init(ctx);
        if (logger.isLoggable(Level.FINE)) {
            StringBuilder msg = new StringBuilder();
            msg.append("Entering: ");
            msg.append(ctx.getMethod());
            msg.append(" Parameters: ");
            msg.append(Arrays.toString(ctx.getParameters()));
            logger.log(Level.FINE, msg.toString());
        }
    }
    public static void exit(Level level, InvocationContext ctx, Object returned) {
        if (logger.isLoggable(level)) {
            StringBuilder msg = new StringBuilder("Exited: ");
            msg.append(ctx.getMethod());
            msg.append(" Returned : ");
            if (returned != null) {
                msg.append(returned.toString());
            }
            logger.log(level, msg.toString());
        }
    }
}

and the bean we are annotating: RestBean.java

package com.sample.beans;
import com.sample.interceptors.Loggable;
import com.sample.webservice.client.PartEntityRESTClient;
import com.sample.webservice.other.Part;
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.faces.event.ActionEvent;
import javax.inject.Named;
/**
 * JSF Named bean for interacting with a RESTful web service via REST client
 * Request Scope
 * @author Thomas Dias
 */
@Named(value = "restBean")
@RequestScoped
@Loggable("FINE")
public class RestBean implements Serializable {
    private String name = "", parentName = "", msg = "";
    /** Default constructor */
    public RestBean() {
    }
    /**
     * Listener method to create a part via an http GET - gets part with name of name
     * @param event
     */
    @Loggable("WARN")
    public void createByGet(ActionEvent event) {
        createByGet();
    }
    /**
     * Action method to create a part via an http GET - gets part with name of name
     * @return empty string
     */
    public String createByGet() {
        Part part = new PartEntityRESTClient().createByGet(parentName, name);
        msg = "Created " + part.getId() + " " + part.getName();
        return "";
    }
    /**
     * Listener method to create a part via an http POST - creates part whose name is name, and parent is parentname
     * @param event
     */
    public void createByPost(ActionEvent event) {
        createByPost();
    }
    /**
     * Action method to create a part via an http POST - creates part whose name is name, and parent is parentname
     * @return empty string
     */
    public String createByPost() {
        new PartEntityRESTClient().create_XML(new Part(name, parentName));
        msg = "Created by post";
        return "";
    }
    /**
     * Listener method for deleting a part - deletes part whose id = name
     * @param event
     */
    public void delete(ActionEvent event) {
        delete();
    }
    /**
     * Action method for deleting a part - deletes part whose id = name
     * @return empty string
     */
    public String delete() {
        PartEntityRESTClient client = new PartEntityRESTClient();
        Part part = client.findByName(name);
        if (part.getId() == 0l) {
            msg = "No Part Found";
        } else {
            client.remove(part.getId().toString());
            msg = "Deleted " + name;
        }
        return "";
    }
    /**
     * Listener method for retrieving a part whose name is name
     * @param event
     */
    public void find(ActionEvent event) {
        find();
    }
    /**
     * Action method for retrieving a part whose name is name
     * @return empty string
     */
    public String find() {
        Part part = new PartEntityRESTClient().findByName(name);
        msg = part.toString();
        return "";
    }
    // *** Standard getters and setters below this line
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getParentName() {
        return parentName;
    }
    public void setParentName(String parentName) {
        this.parentName = parentName;
    }
}


Tuesday, February 14, 2012

Project 2 - REST WebService with Spring

Before I begin, I just had to mention, I was reading a review of web frameworks where the author rated JSF 2 as a zero for REST support.  The author is mistaken, there is nothing simpler then adding REST support to JSF.  First JSF is the view or client side, so there would be no need for REST as a serivce in JSF, and adding a REST client through JSF is trivial - as demonstrated.  In addition, although I put the REST support in an EJB in our first project and here we put it in a Component Bean for Spring, there is nothing stopping you from putting it directly into the backing bean (except, of course, proper coding style).

As mentioned we are going to implement a Jersey client with Spring in our container.

To do that, we have to modify our web.xml and add a servlet to handle the REST services:

    <servlet>
        <servlet-name>Jersey Spring</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Spring</servlet-name>
        <url-pattern>/resources/*</url-pattern>
    </servlet-mapping>

Next, we have our web service: com/sample/webservice/PartEntityFacadeRest

package com.sample.webservice;
import com.sample.entities.PartEntity;
import com.sample.services.PartService;
import com.sample.webservice.other.Part;
import javax.ejb.EJBTransactionRolledbackException;
import javax.inject.Inject;
import javax.persistence.EntityExistsException;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
 * RESTful service for doing CRUD operations on the Parts table
 * This service allows vendors to create parts and subparts.
 * The vendor can remove parts, and the subparts. 
 * Or they can find a part.
 * There is no method for updating.
 * We provide two methods for creating, one via a POST, and one via a GET
 * 
 * @author Thomas Dias
 */
@Component
@Scope("request")
// This is the sub path from the root of rest resources path.  So the full URL would be http://[hostname]/JSFDemoSpringRich/resources/Part
@Path("/Part")
// @Path("com.sample.partentity") - you may want to designate the url similarly to your package definitions
public class PartEntityFacadeREST {
    /** Managed bean for interacting with the database */
    @Inject
    private PartService partService;
    /** Default constructor - explicitly coded to remind us they are required */
    public PartEntityFacadeREST() {
    }
    /**
     * create method, called via a post.
     * Since no path is stated, will use the root path.  http://[host]/JSFDemoSpringRich/resources/Part 
     * @param part to be created.  Note: the part may be sent in xml or json format.
     * @throws exception if part cannot be created, i.e. name not unique
     */
    @POST
    @Consumes({"application/xml", "application/json"})
    public void create(Part part) {
        PartEntity parent = partService.findByName(part.getParent());
        PartEntity entity = new PartEntity(part.getName(), parent);
        partService.create(entity);
    }
    /**
     * creates a part via the GET method.  URL is http://[host]/JSFDemoSpringRich/resources/Part/createByGet/{parentName}/{name}
     * @param parentName name of part to assign as the parent of this part
     * @param name of new part
     * @return part created in xml format.  Id of part will be 0l if there was an error creating the requested part.
     */
    @GET
    @Path("createByGet/{parent}/{name}")
    @Produces({"application/xml"})
    public Part createByGet(@PathParam("parent") String parentName, @PathParam("name") String name) {
        Part result = null;
        PartEntity parent = partService.findByName(parentName);
        PartEntity newPart = new PartEntity(name, parent);  
        // in case there is an error persisting the new part, set the newPart to null
        try {
           partService.create(newPart);
        } catch (EntityExistsException e) {
           newPart = null;         
        } catch (EJBTransactionRolledbackException e) {
           newPart = null;
        }
        // We are returning a Part, not a PartEntity - convert the PartEntity to a part.
        result = new Part(newPart);
        return result;
    }
    /**
     * remove the part id from the database via the DELETE method.  
     * URL: http://[host]/JSFDemoSpringRich/resources/Part
     * This will also remove all the children.
     * Although this is useful for example, what happens to the orders that reference this part?
     * What happens if we get an error?
     * @param id 
     * @throws exception if there is a database constraint violation
     */
    @DELETE
    @Path("{id}")
    public void remove(@PathParam("id") Long id) {
        partService.remove(id);
    }
    /**
     * retrieves a part via the GET method.  URL is http://[host]/JSFDemoSpringRich/resources/Part/findByName/{name}
     * @param name is the name of the part.
     * @return part, or an empty part if no part is found.
     */
    @GET
    @Path("findByName/{id}")
    @Produces({"application/xml"})
    public Part find(@PathParam("id") String name) {
        return new Part(partService.findByName(name));
    }
    public PartService getPartService() {
        return partService;
    }
    public void setPartService(PartService partService) {
        this.partService = partService;
    }
}

Although I used the same name as our last REST service, there are a couple changes that were made.  Since we did not implement a facade in this project, we changed the facade to a service.  And the annotations at the top went to Spring annotations instead of CDI.  Also, we do not need an ApplicationConfig.java file since we did that with the servlets in the web.xml.  Otherwise, the implementation is the same.  Please, see the first discussion at: http://jsf-tying-it-all-together.blogspot.com/2011/12/rest-service.html

And lastly our client: com/sample/webservice/client/

package com.sample.webservice.client;
import com.sample.webservice.other.Part;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
/**
 * RESTClient for accessing the RESTful web service at http://localhost:8080/JSFDemoApp/resources/Part
 *  USAGE:<pre>
 *        PartEntityRESTClient client = new PartEntityRESTClient();
 *        Object response = client.XXX(...);
 *        // do whatever with response
 *        client.close();
 *  </pre>
 * @author Thomas Dias
 */
public class PartEntityRESTClient {
    private WebResource webResource;
    private Client client;
    private static final String BASE_URI = "http://localhost:8080/JSFDemoSpringRich/resources";
    /**
     * Default constructor - initializes client to reference appropriate web service.
     */
    public PartEntityRESTClient() {
        com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig();
        client = Client.create(config);
        webResource = client.resource(BASE_URI).path("Part");
    }
    /**
     * CRUD operation to delete a record from the database
     * @param id of part to be removed
     * @throws UniformInterfaceException if web service throws an exception. i.e. remove failed.
     */
    public void remove(String id) throws UniformInterfaceException {
        webResource.path(java.text.MessageFormat.format("{0}", new Object[]{id})).delete();
    }
    /**
     * Operation to retrieve a record by supplying its name.
     * @param name of part to find.
     * @return the part found.  Part will have an id of 0l if no part was found.
     * @throws UniformInterfaceException if web service throws an exception
     */
    public Part findByName(String name) throws UniformInterfaceException {
        WebResource resource = webResource;
        resource = resource.path(java.text.MessageFormat.format("findByName/{0}", new Object[]{name}));
        return resource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(Part.class);
    }
    /**
     * creates a part and persists it in the customers database via an http POST method.
     * creates an xml file from the part to be supplied with the POST method
     * @param part to be created
     * @throws UniformInterfaceException if web service throws an exception. i.e. part is not unique.
     */
    public void create_XML(Part part) throws UniformInterfaceException {
        webResource.type(javax.ws.rs.core.MediaType.APPLICATION_XML).post(part);
    }
    /**
     * creates a part and persists it in the customers database via an http GET method.
     * supplies the pertinent parts of the part to be created in the URL
     * @param parent name of the part that is the parent of this part.  Supply an empty string if their is no parent.
     * @param name of the part to be created.
     * @return the part created by the web service.
     * @throws UniformInterfaceException if web service throws and exception.  
     */
    public Part createByGet(String parent, String name) throws UniformInterfaceException {
        WebResource resource = webResource;
        resource = resource.path(java.text.MessageFormat.format("createByGet/{0}/{1}", new Object[]{parent, name}));
        return resource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(Part.class);
    }
    /**
     * release resources associated with this client.
     */
    public void close() {
        client.destroy();
    }
}

Here the only change was the path so it went to the new application instead of the services referenced in the first.  See: http://jsf-tying-it-all-together.blogspot.com/2011/12/rest-client.html

To see the discussion regarding testing, see: http://jsf-tying-it-all-together.blogspot.com/2011/12/testing-rest-service.html

And the backing bean only had its annotations changed to Spring.  So, besides modifying the code to handle the Spring annotations instead of CDI (which we could have done through xml if we weren't using annotations), all we did was add Jersey Spring servlet to the web-xml and it all worked.

Project 2 - Web Services

As discussed in project 1, your requirements are going to have to determine if you go the REST or SOAP route.    The arguments for complexity on the SOAP side are "valid" but somewhat irrelevant with the tools available.  The robustness of SOAP is "valid" with REST having either an alternative, workaround, or is simply maturing.  The reality is that many shops are going the RESTful route.  The same seems to be true for REST implementations.  Spring has its RestTemplate, and Oracle has Jersey, but the difference between the two do not seem to have a compelling reason to use one over the other.

Since we already have a Jersey service / client, we'll use those and note the minor differences needed to implement them.


Friday, February 10, 2012

Project 2 - Bean Testing with JUnit

There is a difference between Unit testing, Integration testing, Functional testing, Acceptance testing, etc.  Here we will demonstrate unit testing, and 2 forms of integration testing.  In our AjaxBean, we have a method validation that returns if the name is unique and valid.  Let us test this method in 3 different ways and we can see how we would write the rest of our tests.

AjaxBeanWithoutSpringTest.java

package com.sample.beans;
import com.sample.dao.BasicDao;
import com.sample.dao.OrderDaoImp;
import com.sample.dao.PartDao;
import com.sample.entities.OrderEntity;
import com.sample.entities.PartEntity;
import com.sample.services.OrderService;
import com.sample.services.OrderServiceImp;
import java.util.List;
import javax.faces.validator.ValidatorException;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import org.springframework.orm.jpa.JpaTemplate;
/**
 * @author Thomas Dias
 */
public class AjaxBeanWithoutSpringTest {
    class TestOrderService implements OrderService {
        public List<PartEntity> getAvailableParts(Long id) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public PartDao getPartDao() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public void setPartDao(PartDao partDao) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public BasicDao getDao() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public void setDao(BasicDao dao) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public int count() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public void create(OrderEntity entity) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public void delete(OrderEntity entity) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public void edit(OrderEntity entity) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public OrderEntity find(Long id) {
            return null;
        }
        public List<OrderEntity> findAll() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public JpaTemplate getJpaTemplate() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public void remove(Long id) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        public OrderEntity findByName(String name) {
            OrderEntity result = null;
            if (name.equals("Sample Order1")) {
                result = new OrderEntity();
                result.setName(name);
            }
            return result;
        }
        public OrderEntity getOrderEntity(OrderEntity orderEntity) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    };
    public AjaxBeanWithoutSpringTest() {
    }
    @BeforeClass
    public static void setUpClass() throws Exception {
    }
    @AfterClass
    public static void tearDownClass() throws Exception {
    }
    @Before
    public void setUp() {
    }
    @After
    public void tearDown() {
    }
    /**
     * Test of validate method, of class AjaxBean.
     */
    @Test
    public void unitTestValidate() {
        AjaxBean instance = new AjaxBean();
        instance.setOrderService(new TestOrderService());
        String value = "Sample Order1";
        try {
            instance.validate(null, null, null);
            fail("Validation failed to catch error");
        } catch (ValidatorException e) {
        }
        try {
            instance.validate(null, null, "");
            fail("Validation failed to catch error");
        } catch (ValidatorException e) {
        }
        try {
            instance.validate(null, null, value);
            fail("Validation failed to catch error");
        } catch (ValidatorException e) {
        }
        instance.validate(null, null, "no error");
    }
    @Test
    public void integrationTestValidate() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("localTestingPU");
        AjaxBean instance = new AjaxBean();
        OrderServiceImp orderService = new OrderServiceImp();
        OrderDaoImp orderDao = new OrderDaoImp();
        orderDao.setEntityManagerFactory(emf);
        orderService.setDao(orderDao);
        instance.setOrderService(orderService);
        String value = "Sample Order1";
        try {
            instance.validate(null, null, value);
            fail("Validation failed to catch error");
        } catch (ValidatorException e) {
        }
        instance.validate(null, null, "no error");
        emf.close();
    }
}

The first test we have is: unitTestValidate().  What is a unit test?  It is the testing of the smallest piece of an application that can be tested.  So, in our unit test, we call our validate method, but the validate method relies on an OrderService to retrieve the record from the database.  So, using our setter method, we inject a OrderServiceTest class that implements OrderService with methods that return predictable results.  Then we test what happens when we pass a null value, when we pass an empty value, when we pass a value that is supposed to exist, and when we pass a value that is valid.  Because the validation throws an exception, we have to put our checks in try catch blocks.

The second test is an integration test.  It tests the integration of the bean with the database.  We create an EntityManagerFactory and inject it into an OrderServiceImp class that we inject into our bean.  Then we test the a value that should be in the database, and a value that shouldn't.  (I already had it in the database, but it is just as easy to call a method to put the record in the database)  Notice the last line in the test; we have to close the EntityManagerFactory and clean up.

The third test demonstrates an integration test with Spring.
AjaxBeanWithSpringTest.java

package com.sample.beans;
import com.sample.services.OrderService;
import javax.faces.validator.ValidatorException;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import org.springframework.beans.factory.annotation.Autowired;
/**
 * @author Thomas Dias
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="/AjaxBeanWithSpringTest.xml")
public class AjaxBeanWithSpringTest {
    @Autowired
    OrderService orderService;
    public OrderService getOrderService() {
        return orderService;
    }
    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }
    public AjaxBeanWithSpringTest() {
    }
    @BeforeClass
    public static void setUpClass() throws Exception {
    }
    @AfterClass
    public static void tearDownClass() throws Exception {
    }
    @Before
    public void setUp() {
    }
    @After
    public void tearDown() {
    }
    @Test
    public void integrationTestValidate() {
        AjaxBean instance = new AjaxBean();
        instance.setOrderService(orderService);
        String value = "Sample Order1";
        try {
            instance.validate(null, null, value);
            fail("Validation failed to catch error");
        } catch (ValidatorException e) {
        }
        instance.validate(null, null, "no error");
    }
}
We start this with JUnit, but we annotate it with:
   @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="/AjaxBeanWithSpringTest.xml")
The first annotation runs the test with Spring engaged, the second defines the context.xml that we will run with.  Note:  the path of the xml will be the context path of the test classes.  For me, it was:
/build/test/classes/AjaxBeanWithSpringTest.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="localTestingPU"/>
    </bean>
    <bean id="orderDao" class="com.sample.dao.OrderDaoImp">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <bean id="partDao" class="com.sample.dao.PartDaoImp">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <bean id="orderService" class="com.sample.services.OrderServiceImp">
        <property name="dao" ref="orderDao" />
        <property name="partDao" ref="partDao" />
    </bean>
</beans>

Notice, this creates all the dependencies and injects them into the orderService field via the @Autowire in AjaxBeanWithSpringTest.  We then perform the same tests we did in the last integration test.

From here we can see how we would test the rest.  Injecting mock classes into our beans for unit testing, creating instances of our implementation classes via Spring or JUnit without Spring to inject the beans into our integration tests, and then we could use an embedded container to create the beans and test it in the container.

Note: I only tested one method to demonstrate testing for corner cases, and testing against the database.  Of course, we would need to write tests for all the other methods, etc.