views:

1801

answers:

1

For tests of some small JBoss enterprise apps I would like to use JUnit, and the Maven Cargo plugin. (I know that there is also JSFUnit but first I would like to take a closer look at Cargo.)

Is there a simple example available online which I could use as a reference for running a JUnit test which invokes a EJB operation using JBoss (4.2 or 5.1) using the Maven Cargo plugin? I have found some good introductions to the configuration, but I get error messages in the EJB lookup so it would be helpful to see how it should be used.

Here is the test code using InitialContext:

public void testEcho() {
   assertEquals("Echo Echo", lookupEchoBeanRemote().Echo("Echo"));
}

private EchoBeanRemote lookupEchoBeanRemote() {
    try {
        Context c = new InitialContext();
        return (EchoBeanRemote) c.lookup("EchoBean/remote");
    } catch (NamingException ne) {
        Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", ne);
        throw new RuntimeException(ne);
    }
}

Which gives this error:

testEcho(de.betabeans.Echo2Test)  Time elapsed: 0.885 sec  <<< ERROR!
java.lang.reflect.UndeclaredThrowableException
    at $Proxy3.Echo(Unknown Source)
    at de.betabeans.Echo2Test.testEcho(Echo2Test.java:17)
Caused by: java.security.PrivilegedActionException: java.lang.reflect.InvocationTargetException
    at java.security.AccessController.doPrivileged(Native Method)
    at org.jboss.ejb3.security.client.SecurityActions.createSecurityContext(SecurityActions.java:657)
    at org.jboss.ejb3.security.client.SecurityClientInterceptor.invoke(SecurityClientInterceptor.java:59)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
    at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:74)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
    at org.jboss.aspects.remoting.PojiProxy.invoke(PojiProxy.java:62)
    at $Proxy4.invoke(Unknown Source)
    at org.jboss.ejb3.proxy.impl.handler.session.SessionProxyInvocationHandlerBase.invoke(SessionProxyInvocationHandlerBase.java:207)
    at org.jboss.ejb3.proxy.impl.handler.session.SessionProxyInvocationHandlerBase.invoke(SessionProxyInvocationHandlerBase.java:164)
    ... 28 more
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at org.jboss.security.SecurityContextFactory.createSecurityContext(SecurityContextFactory.java:117)
    at org.jboss.security.SecurityContextFactory.createSecurityContext(SecurityContextFactory.java:76)
    at org.jboss.ejb3.security.client.SecurityActions$1.run(SecurityActions.java:662)
    ... 38 more
Caused by: java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/security/jacc/PolicyContextException
    at java.lang.ClassLoader.defineClass1(Native Method)

If I use the EJB annotation

@EJB(beanInterface=EchoBeanRemote.class,mappedName="EchoBean/remote")
private EchoBeanRemote newSessionBean;

public Echo3Test(String testName) {
    super(testName);
}

public void testEcho() {
   assertEquals("Echo Echo", newSessionBean.Echo("Echo"));
}

The test result is

testEcho(de.betabeans.Echo3Test)  Time elapsed: 0.001 sec  <<< ERROR!
java.lang.NullPointerException
    at de.betabeans.Echo3Test.testEcho(Echo3Test.java:20)

jndi.properties is located in the EJB jar root folder and contains these lines:

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=jnp://localhost:1099
### The TimedSocketFactory connection timeout in milliseconds (0 == blocking) 
jnp.timeout=0
### The TimedSocketFactory read timeout in milliseconds (0 == blocking) 
jnp.sotimeout=0

The bean source code is

package de.betabeans;

import javax.ejb.Remote;

@Remote
public interface EchoBeanRemote {
    String Echo(final String in);
}
package de.betabeans;

import javax.ejb.Stateless;

@Stateless
public class EchoBean implements EchoBeanRemote {
    public String Echo(final String in) {
        return in + " " + in;
    }
}

I have also tested a web application which can call the EJB without problems - in both ways, with InitialContext or an annotation. A warning which I received in the deployment of the web application was

WARN [MappedReferenceMetaDataResolverDeployer] Unresolved references exist in JBossWebMetaData:[#web-app:AnnotatedEJBReferenceMetaData{name=de.betabeans.Echo3Servlet/echoBean,ejb-ref-type=null,link=null,ignore-dependecy=false,mapped/jndi-name=EchoBean/remote,resolved-jndi-name=null,beanInterface=interface de.betabeans.EchoBeanRemote}, #web-app:AnnotatedEJBReferenceMetaData{name=NewServlet/newSessionBean,ejb-ref-type=null,link=null,ignore-dependecy=false,mapped/jndi-name=NewSessionBean/remote,resolved-jndi-name=null,beanInterface=interface de.betabeans.NewSessionBeanRemote}] 12:26:11,770 INFO

All tests performed with JBoss 5.1.0.GA on two different build systems.

I have uploaded the complete Maven project now to http://www.mikejustin.com/download/JBossSimpleEJBApp-ejb-test.zip

+1  A: 

EDIT: after added sources

First of all - my example works on JBoss 4.2.3.GA and Cargo 1.0 I did some refactoring of your code:

pom.xml file

    <groupId>de.betabeans</groupId>
 <artifactId>JBossSimpleEJBApp-ejb-test</artifactId>
 <packaging>ejb</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>JBossSimpleEJBApp-ejb JEE5 EJB Test</name>
 <url>http://maven.apache.org&lt;/url&gt;
 <dependencies>
  <dependency>
     <groupId>javax.ejb</groupId>
     <artifactId>ejb-api</artifactId>
     <version>3.0</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>jboss</groupId>
   <artifactId>jboss-ejb3</artifactId>
   <version>4.2.3.GA</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.jboss.client</groupId>
   <artifactId>jbossall-client</artifactId>
   <version>4.2.3.GA</version>
   <scope>test</scope>
  </dependency>
 </dependencies>
 <repositories>
   <repository>
    <releases>
     <enabled>true</enabled>
    </releases>
    <snapshots>
       <enabled>true</enabled>
     <updatePolicy>always</updatePolicy>
    </snapshots>
    <id>repository.jboss.com</id>
    <name>Jboss Repository for Maven</name>
    <url>http://repository.jboss.com/maven2/&lt;/url&gt;
    <layout>default</layout>
   </repository>
 </repositories>
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.0.2</version>
    <configuration>
     <source>1.5</source>
     <target>1.5</target>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-ejb-plugin</artifactId>
    <version>2.1</version>
    <configuration>
     <ejbVersion>3.0</ejbVersion>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.codehaus.cargo</groupId>
    <artifactId>cargo-maven2-plugin</artifactId>
    <version>1.0</version>
    <configuration>
     <container>
      <containerId>jboss42x</containerId>
      <home>${jboss.home}</home>
      <append>false</append>
     </container>
     <configuration>
      <type>existing</type>
      <home>${jboss.home}/server/default</home>
      <properties>
       <cargo.jboss.configuration>default</cargo.jboss.configuration>
       <cargo.rmi.port>1099</cargo.rmi.port>
       <cargo.logging>high</cargo.logging>
      </properties>
     </configuration>
     <wait>false</wait>
    </configuration>
    <executions>
     <execution>
      <id>start-container</id>
      <phase>pre-integration-test</phase>
      <goals>
       <goal>start</goal>
      </goals>
     </execution>
     <execution>
      <id>stop-container</id>
      <phase>post-integration-test</phase>
      <goals>
       <goal>stop</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
     <skip>true</skip>
    </configuration>
    <executions>
     <execution>
      <id>surefire-it</id>
      <phase>integration-test</phase>
      <goals>
       <goal>test</goal>
      </goals>
      <configuration>
       <skip>false</skip>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
  <finalName>JBossSimpleEJBApp-ejb-test</finalName>
 </build>

I've changed your pom in following sections:

  • dependecies (you use ejb-api from glasfish)
  • repositories (I recomend to use JBoss Maven2 in layout default)
  • version and containerId of cargo-maven2-plugin

I've moved resources folder to test folder

jndi.properties file must be use by test (not beans) and can be as follows or that you have:

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost

The orher configuration files (jboss.xml, MANIFEST.MF) aren't necessary.

Configuration of server
The biggest problem with jboss 4.2.3.GA server and ejb.jar file is that it doesn't work by default! Description of the problem and workaround you can find here. (That was the hardest thing. In Jboss 5.0 server this problem doesn't exist but in maven-cargo-plugin this container is as experimental one)

That's all
Below I paste some links to references, If you'll have still problems I will send you my entire fixed project.


My original answer
There are several problems with Cargo and JBoss. Main reason is that datasource configuration in pom doesn't work, so you need to deploy separate datasource file. From JBoss perspective it has to be a file placed in main deploy directory (for Tomcat is located in META-INF folder). Second task is copy jdbc library before cargo run.

Great resource for you is this post from Carlos Sanchez blog. Maybe you can use Selenium instead JSFUnit too :)

To copy datasource file I use following configuration:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-ds-context</id>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <phase>pre-integration-test</phase>
                    <configuration>
                        <outputDirectory>${jboss.deploy-ds.dir}</outputDirectory>
                        <resources>
                            <resource>
                                <directory>${basedir}/src/main/webresources/META-INF</directory>
                                <filtering>true</filtering>
                                <includes>
                                    <include>context-ds.xml</include>
                                </includes>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>
cetnar
Many thanks for your answer which might be helpful in the future - in my current very basic example project there are no datasources involved.
mjustin
Works great - your help is very appreciated!
mjustin