Showing posts with label Glassfish. Show all posts
Showing posts with label Glassfish. Show all posts

Thursday, 17 January 2013

JUnit testing EJBs in embedded Glassfish in Netbeans (the hard way)

Back to basics: Testing


On the face of things it was worth going back basic testing because my frustration turned to joy!

I am by nature very inquisitive and have sometimes been known to spend "far too much time not being productive" at work trying to solve problems that my employer might not consider worthy of my time.

A bit of background is needed here: for the last few years I have been employed as a software developer by a company that until recently didn't really know what this meant. Not a criticism of my employer just a statement of fact that the discipline of Software Engineering and Development was not relevant to them.

Now I find myself being "allowed" to think about things like Unit testing.. oh the joy!

So, time scrape the rust off my Unit testing skills. First stop a Netbeans tutorial which demonstrates using JUnit to test EJBs in an embedded Glassfish. As "middleware" is what I do* I quickly knocked the example together as per the instructions... damn and blast Murphy and his law!!
Yeap, everything except the testing worked.
Here is the Message of Doom

Invalid ejb jar [WebAppJUnit.jar]: it contains zero ejb. 
Note: 
1. A valid ejb jar requires at least one session, entity (1.x/2.x style), or message-driven bean. 
2. EJB3+ entity beans (@Entity) are POJOs and please package them as library jar. 
3. If the jar file contains valid EJBs which are annotated with EJB component level annotations (@Stateless, @Stateful, @MessageDriven, @Singleton), please check server.log to see whether the annotations were processed properly.

Apparently my EJBs are not being found. After spending several fruitless hours looking for a solution and not finding anything that helped me at all my curiosity took over.

What I found out

The Message of Doom had a clue: it was trying to load an EJB jar called WebAppJUnit.jar. Well the tutorial doesn't say create an Enterprise Application with associated EJB Module so an EJB jar ain't being built!

The tutorial gets you to create a POJO Stateless Session Bean which sits in your WAR file.
This WAR file has to be loaded by the EJB Container in order to have @Annotations processed. This wasn't happening.

The tutorial mentions adding properties to further setup the EJBContainer but doesn't explain what the properties mean. Here it uses EJBContainer.MODULES with a file object. This property allows you to extend the Classpath of the EJB Container, something I found out during my fruitless googling.

In order to get the tutorial working you simply add the following lines of code

        Map properties = new HashMap();
        properties.put(EJBContainer.MODULES, new File("dist/WebAppJUnit.war"));
// Make sure you use the properties when creating the EJB Container!
        EJBContainer container = javax.ejb.embeddable.EJBContainer.createEJBContainer(properties);
// Change /classes/ to /WebAppJUnit/
        MyBean instance = (MyBean)container.getContext().lookup("java:global/WebAppJUnit/MyBean");


Et voila!! (Caveat, unless you build the web app the WAR file is not created and Message of Doom appears again).

* Actually I also bind the middleware I develop to a database and to a web UI using PrimeFaces because I am the only web applications developer currently working here.

So now I can, finally, officially perform tests on the software I develop because it is considered essential.

Wednesday, 14 November 2012

PrimeFaces PUSH

On Monday this week I was going through my blogs round when I spotted this from Geertjan Wielenga,
some of you may know Geertjan as a Principal Product Manager for Oracle and NetBeans guru whose regular blog posts are well worth reading if you are a Java Dev and/or NetBeans user.

In essence what Geertjan is looking for is a way of publishing information to browsers where this information may come from hardware devices perhaps based on TinkerForge.

If you read his post you can see more about what exactly he wants to do.

I decided I would see if I could slap something together which could be used for something like this.

Requirements

  • Data to be supplied asynchronously to the web app and browsers
  • Wide browser support
  • As a Proof of Concept simulation is allowed.
My Technology Choices

I use PrimeFaces for most if not all of my JSF based WebApps and this has some very handy support for PUSH (WebSockets) which uses Atmosphere. I have never used this before so this is the perfect opportunity to try it out.

Because I wanted to do a little more than simply push the current vehicle direction and update a few p tags I also added a page which uses Raphael to provide SVG support. Basically my vehicle is a simple triangle that gets transformed into a direction supplied by data pushed to the client.

I had already suggested using a Singleton Session Bean using Timers as a way of supplying data and decided this would be the easiest way to simulate hardware being spun around and reporting its current direction to any interested clients.

I have created a Project for this on GitHub should you wish to try the code out for yourself.
Edit:

  • I have since found that Glassfish and WebSockets don't mix very well (at least with PrimeFaces).
    I created a version of the same project which runs well under Tomcat 7 where WebSocket support seems to work off the bat!
  • The AsynchDirectionChangeSimulator bean is no longer active but the same function is provided by a Servlet.

Here is the code for the Session Timer Bean that simulates the "hardware".

package org.andy.pf.tfsim.simulator;

import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import org.primefaces.push.PushContext;
import org.primefaces.push.PushContextFactory;

/**
 *
 * @author a.bailey
 */
@Singleton
@Startup
public class AsynchDirectionChangeSimulator {

    final static String[] DIRS = {
        "North",
        "Northeast",
        "East",
        "Southeast",
        "South",
        "Southwest",
        "West",
        "Northwest"
    };
    
    
    @Schedule(minute = "*", second = "*/1", hour = "*")
    public void pushDirection() {
        String nextDirection = DIRS[(int)(Math.random()*DIRS.length)];
        PushContext ctx = PushContextFactory.getDefault().getPushContext();
        if( ctx != null ) {
            ctx.push("/tfSim", nextDirection);
        }
    }
}


Please note that this looks breathlessly simple and it is because all the magic is wrapped up in the libraries being used.

Here is the page used to display my little triangle animated on push.
The code is meant to be readable by the way not perfect.


<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:p="http://primefaces.org/ui">
    <f:view contentType="text/html" encoding="utf-8">
        <h:head>
            <title>TinkerForge RT Sim with SVG</title>
            <h:outputScript library="js" name="raphael-min.js"/>
            <f:facet name="last">
                <script type="text/javascript">
                    var dirTransforms = {
                       'North':"R0",
                       'Northeast':"R45",
                       'East':"R90",
                       'Southeast':"R135",
                       'South':"R180",
                       'Southwest':"R225",
                       'West':"R270",
                       'Northwest':"R315"
                    };
                    var canvas = null;
                    var tf = null;
                    $(document).ready(function() {
                       canvas = Raphael(document.getElementById("raphaelPanel"), 300, 300);
                       // tf = canvas.rect(50, 20, 40, 100);
                       tf = canvas.path("M120 180H180L150 40L120 180");
                       tf.attr("stroke", "#000");
                    });
                    function setDirection(data) {
                        tf.transform(dirTransforms[data]);
                    }
                </script>
            </f:facet>
        </h:head>
        <h:body>
            <p:panel id="raphaelPanel">
            </p:panel>
            <p:socket onMessage="setDirection" channel="/tfSim"/>
        </h:body>
    </f:view>
</html>