Arquillian with NetBeans, GlassFish embedded, JPA and a MySQL Datasource

Markus Eisele
8
This is an, let's call it accidental post. I was looking into transactional CDI observers and playing around with GlassFish embedded to run some integration tests against it. But surprisingly this did not work too well and I am still figuring out, where exactly the problems are while using the plain embedded GlassFish for that. In the meantime I switched to Arquillian. After I looked at the Arquillian 1.0.0.Alpha4 a bit more detailed last year, it was time to see, what the guys prepared for 1.0.0 final. Some stuff changed a bit and I was surprised to only find some basic examples on the net. That was the main reason I started writing this post. To have a more complete example of all the three technologies working together.

Getting Started
First of all, get yourself a fresh copy of latest NetBeans 7.1. It's out since a few weeks and it really looks good. If you like, you can download a copy of the Java EE version, which comes with latest GlassFish OSS Edition 3.1.1 pre bundled. Install it and fire it up. Also grep a copy of MySQL Community Edition and install it. Back in NetBeans, setup a new Maven Webapplication via the new Project Wizard. Let's call it "simpleweb" and we tell it to run on GF 3.1.1 (if you haven't done so, you should create a Services>Server>GlassFish instance before or do it during the project setup).

Implement your Application
Even if this isn't test-driven, I like to use this approach because I still believe, that this is the most common case you find out there in your projects. You have a lot of stuff ready to run and you are looking for some kind of automated integration tests. So, let's assume you have a very basic entity, we call it "com.mycompany.simpleweb.entities.AuditLog". You can create it with the NetBeans new Entity wizard. The third step during the Entity creation is the provider and database setup. Define a new Datasource and name it "jdbc/auditlog". As a connection specification use MySQL J driver and I assume you have a database up and running (let's assume this is called auditlog). Test the connection and finish the wizard.


If you are using the wizard, you get some free gifts. Beside the fact, that you now have your AuditLog entity in the source tree, you also find a META-INF/persistence.xml file in your src/main/resources and a glassfish-resources.xml in src/main/setup. This is needed later on, keep it in mind. Add some additional properties to your entity. For now I add "String account". And don't forget to define a Version field "Timestamp timestamp". And it's also nice to have a little named query to get a list of all AuditLogs
@NamedQuery(name = "findAllAuditLogs",
query = "SELECT OBJECT (e) FROM AuditLog e")

@Version
private Timestamp timestamp;

If you are using the wizard, make sure to check your pom.xml. The wizard is adding some eclipselink dependencies in scope provided, so this shouldn't make a big difference here. Next is to add a com.mycompany.simpleweb.service.AuditRepositoryService EJB. This should be responsible for all CRUD operations on the AuditLog entity.
Add some code to it to insert an AuditLog:
@PersistenceContext
private EntityManager em;

  public void writeLog(String account) {
        AuditLog log = new AuditLog();
        log.setAccount(account);
        em.persist(log);
    }
And some more code to find out the total number of entries in your table:
public int findAll() {
        TypedQuery<AuditLog> query = em.createNamedQuery("AuditLog.findAllAuditLogs", AuditLog.class);
        return query.getResultList().size();

    }
That's all for now.

Adding Basic Test Dependencies
Next we are going to add some very basic test dependencies. Open your projects pom.xml file and add the following sections for Arquillian to your project:
        
         
        <repository>
            <id>JBoss</id>
            <name>JBoss Repository</name>
            <url>https://repository.jboss.org/nexus/content/groups/public/</url>
        </repository>
    <dependencymanagement>     
         
        <dependencies>
            <dependency>
                <groupid>org.jboss.arquillian</groupid>
                <artifactid>arquillian-bom</artifactid>
                <version>1.0.0.Final-SNAPSHOT</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencymanagement>
    <dependencies>
        
        <dependency>
            <groupid>org.jboss.arquillian.container</groupid>
            <artifactid>arquillian-glassfish-embedded-3.1</artifactid>
            <version>1.0.0.Final-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
        <dependency>
        
            <groupid>org.jboss.arquillian.junit</groupid>
            <artifactid>arquillian-junit-container</artifactid>
            <scope>test</scope>
        </dependency>
    </dependencies>
Beside that, you also need the embedded Glassfish dependency.
        
        <dependency>
            <groupid>org.glassfish.extras</groupid>
            <artifactid>glassfish-embedded-all</artifactid>
            <version>3.1</version>
            <scope>test</scope>
        </dependency>
We also need the MySQL J driver:
        <dependency>
            <groupid>mysql</groupid>
            <artifactid>mysql-connector-java</artifactid>
            <version>5.1.18</version>
            <scope>test</scope>
        </dependency>

Configuring Arquillian
After we have all the needed dependencies in place, we need to further configure Arquillian. This is done via the arquillian.xml which has to be placed in the src/test/resources folder (you might need to create it outside NetBeans before) and should look like this:
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian-1.0.xsd">
    <engine>
        <property name="deploymentExportPath">target/arquillian</property>
    </engine>

    <container default="true" qualifier="glassfish">
        <configuration>
            <property name="sunResourcesXml">src/main/setup/glassfish-resources.xml</property> 
        </configuration>
    </container>
</arquillian>
The engine parameter tells Arquillian to place a packaged version of your test archive to a target/arquillian folder. This is quite useful for hunting down problems. The container qualifier points the testrunner to the glassfish-resources.xml which was created by the entity creation wizard. All done. One single thing I would like to suggest is to make a copy of your persistence.xml and place it to the test/resources folder renamed to something like test-persistence.xml. I consider it a best practice to have an option to configure your test JPA a bit different than the productive one. To make a simple example, we would like to see some more logging output during the tests, so the copied version should additionally contain the needed parameters. I also like to change the table generation strategy for testing to drop-and-create-tables:
 
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.logging.level.sql" value="FINEST" />
<property name="eclipselink.logging.parameters" value="true" />
Let's take a look at the the tests.

Add a Testcase
Lets add a test. This is easy with NetBeans: Right click on your EJB and select "Tools>Create JUnit Tests". Select JUnit 4.x and accept the name proposal "com.mycompany.simpleweb.service.AuditRepositoryServiceTest". Now your project has a new "Test Packages" folder. As you can see, the test is in error. NetBeans assumes, that you want to do a test based on embedded EJBContainer. Nice guess, but we would like to add some Arquillian here. Remove the EJBContainer import and strip the class down to this:
@RunWith(Arquillian.class)
public class AuditRepositoryServiceTest {
}
Now it's time to define the deployment archive for the test using ShrinkWrap. The deployment archive for the test is defined using a static method annotated with Arquillian's @Deployment annotation.
@Deployment
    public static JavaArchive createTestArchive() {
        return ShrinkWrap.create(JavaArchive.class, "test.jar").addPackage(AuditLog.class.getPackage()).addPackage(AuditRepositoryService.class.getPackage()).addAsManifestResource(
                new ByteArrayAsset("<beans>".getBytes()),
                ArchivePaths.create("beans.xml")).addAsManifestResource(
                "test-persistence.xml",
                ArchivePaths.create("persistence.xml"));
    }
After the packages which should be contained are added, an empty beans.xml (which should be enough for now) is added and the test-persistence.xml is added as a manifest resource named persistence.xml. Great. One last thing is to define the test itself.
@EJB 
AuditRepositoryService repository;

 @Test
    public void insertLog() throws Exception {
        repository.writeLog("Markus");
        int numberOfLogs = repository.findAll();
        Assert.assertEquals(1, numberOfLogs);

    }

We are inserting a simple test entity and are getting the count back from the database which is checked via assertEquals. That's all. Fire up your tests. (Right click on the AuditRepositoryServiceTest class and select "Test File (Strg+F6).

Examining what's happening
The output window shows the Std.out of a starting GlassFish. If you examine the output further you see, that the JDBC connection pool and the JDBC resource are created:
INFO: command add-resources result: PlainTextActionReporterSUCCESSDescription: add-resources AdminCommandnull
    JDBC connection pool mysql_auditlog_rootPool created successfully.
    JDBC resource jdbc/auditlog created successfully.
and the "test" application was deployed:
INFO: WEB0671: Loading application [test] at [/test]
17.01.2012 10:12:39 org.glassfish.deployment.admin.DeployCommand execute
INFO: test was successfully deployed in 6.461 milliseconds.
Scanning through the output does point you to some EclipseLink stuff, but the additional sql logging doesn't seem to be in effect. This is because EclipseLink needs to know to which logger to point the output to. Normally the log output is redirected to the server logger which is auto-discovered. We didn't do any logging configuration until now and simply rely on what is default for Java Logging. So, let's add a little logging configuration. Put an empty logging.properties file to src/test/resources and add some simple lines to it:
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.level=FINEST
add the maven sure-fire plugin to the build section of your pom.xml:
 
<plugin>
                <groupid>org.apache.maven.plugins</groupid>
                <artifactid>maven-surefire-plugin</artifactid>
                <version>2.11</version>
                <configuration>
                    <includes>
                        <include>com/mycompany/simpleweb/service/*</include>
                    </includes>
                    <systempropertyvariables>
                        <java.util.logging.config.file>${basedir}/src/test/resources/logging.properties</java.util.logging.config.file>
                    </systempropertyvariables>
                </configuration>
            </plugin>
If you now issue a clean and build, you see, that the desired log output is shown in the NetBeans build output.
FEIN: INSERT INTO AUDITLOG (ID, ACCOUNT, TIMESTAMP) VALUES (?, ?, ?)
 bind => [1, Markus, 2012-01-17 11:02:54.0]
In fact, if you use Strg+F6 you still only see INFO level messages. To fix this, you need to change your NetBeans run action settings. Right click your project and select "Properties". Select "Actions" and "Test file". Add the following as a new line within "Set Properties" area:
java.util.logging.config.file=src/test/resources/logging.properties


Now you also see the desired log-level output with a single test-run. That was it. You can download the complete sample maven project (as ZIP-File) with the mentioned classes and play around a bit. Have fun!

[UPDATE: 18.01.2012]
Static weaving problem explained in another post.

Post a Comment

8Comments

  1. Great post.
    Thanks for the sample project!

    ReplyDelete
  2. Unfortunately the sample project cannot be loaded because the JBoss repository is missing from its pom.xml. Add it and the sample project loads.

    ReplyDelete
  3. Some problems that I encounter that might help someone:
    - It's groupId and artifactId, both with capital "I".
    - When you edit and save pom.xml, you need to Download Dependencies. Right-click the project and click "Show and Rosolve Problems ..."
    - If you already have the jars, instead of "Dowloading Dependencies", you can install them manually.
    - The user creates a NamedQuery findAllAuditLogs but calls AuditLog.findAllAuditLogs!

    by ばか

    ReplyDelete
  4. Thanks animeworld,

    Things got messed up during html conversion.
    Shouldn't happen to the sample-project :)

    Thanks,
    M

    ReplyDelete
  5. I appreciate your post
    Unfortunately I have absolutely no clue where to get all
    the jar files from.
    Would you mind adding a valid maven repository?
    Currently I cannot retrieve any package
    from

    https://repository.jboss.org/nexus/content/groups/public/


    Thanks.

    Ola



    ReplyDelete
    Replies
    1. Hi Ola,

      the repository is still valid! I try to find the time to upload a complete sample to github during the next weeks!

      - M

      Delete
Post a Comment