Kohei Nozaki's blog 

An example of Maven EAR project consists of an EJB interface, an EJB implementation and a WAR


Posted on Friday Mar 06, 2015 at 10:43PM in Maven


The project consists of following principal modules:

  • eartest-ejb-api: holds an EJB local interface named Hello. packaging=jar. no dependency.

  • eartest-ejb-impl: holds an EJB implementation named HelloImpl which implements Hello. packaging=ejb. depends on eartest-ejb-api.

  • eartest-war: holds an Servlet which has an injection point of Hello interface. depends on eartest-ejb-api.

  • eartest-ear: holds above 3 modules in the EAR.

Whole project is can be obtained from https://github.com/lbtc-xxx/eartest .

Structure of eartest-ear module

$ tree eartest-ear/target/eartest-ear
eartest-ear/target/eartest-ear
|-- META-INF
|   `-- application.xml
|-- eartest-ejb-impl-1.0-SNAPSHOT.jar
|-- eartest-war-1.0-SNAPSHOT.war
`-- lib
    `-- eartest-ejb-api-1.0-SNAPSHOT.jar

2 directories, 4 files

Structure of eartest-war module

$ tree eartest-war/target/eartest-war
eartest-war/target/eartest-war
|-- META-INF
`-- WEB-INF
    `-- classes
        `-- eartest
            `-- war
                `-- MyServlet.class

5 directories, 1 file

MyServlet can reference eartest-ejb-api-1.0-SNAPSHOT.jar because it’s placed under lib directory in the parent EAR. this packaging style is called as Skinny WAR.

Structure of eartest-ejb-api

$ tree eartest-ejb-api/target/classes
eartest-ejb-api/target/classes
`-- eartest
    `-- ejb
        `-- api
            `-- Hello.class

3 directories, 1 file

Structure of eartest-ejb-impl

$ tree eartest-ejb-impl/target/classes
eartest-ejb-impl/target/classes
|-- META-INF
|   `-- ejb-jar.xml
`-- eartest
    `-- ejb
        `-- impl
            `-- HelloImpl.class

4 directories, 2 files

A problem with IntelliJ IDEA

IntelliJ has an annoying issue: Maven support cannot handle skinny wars for EAR deployments : IDEA-97324. this brings unnecessary eartest-ejb-api into WEB-INF/lib inside the WAR and brings following exception. to avoid this, I need to put <scope>provided</scope> in dependency declaration for eartest-ejb-api in pom.xml of eartest-war.

Caused by: java.lang.IllegalStateException: JBAS011048: Failed to construct component instance
	at org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:162)
	at org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:133)
	at org.jboss.as.ee.component.BasicComponent.createInstance(BasicComponent.java:89)
	at org.jboss.as.ee.component.ComponentRegistry$ComponentManagedReferenceFactory.getReference(ComponentRegistry.java:149)
	at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$5.createInstance(UndertowDeploymentInfoService.java:1233)
	at io.undertow.servlet.core.ManagedServlet$DefaultInstanceStrategy.start(ManagedServlet.java:215) [undertow-servlet-1.1.0.Final.jar:1.1.0.Final]
	... 27 more
Caused by: java.lang.IllegalArgumentException: Can not set eartest.ejb.api.Hello field eartest.war.MyServlet.hello to eartest.ejb.api.Hello$$$view17
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167) [rt.jar:1.8.0_20]
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171) [rt.jar:1.8.0_20]
	at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81) [rt.jar:1.8.0_20]
	at java.lang.reflect.Field.set(Field.java:758) [rt.jar:1.8.0_20]
	at org.jboss.as.ee.component.ManagedReferenceFieldInjectionInterceptorFactory$ManagedReferenceFieldInjectionInterceptor.processInvocation(ManagedReferenceFieldInjectionInterceptorFactory.java:108)
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.invocation.WeavedInterceptor.processInvocation(WeavedInterceptor.java:53)
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.as.ee.component.AroundConstructInterceptorFactory$1.processInvocation(AroundConstructInterceptorFactory.java:28)
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45) [wildfly-ee-8.2.0.Final.jar:8.2.0.Final]
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64)
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:326)
	at org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80)
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
	at org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:160)
	... 32 more


Testing a JBatch job using Arquillian on remote WildFly


Posted on Thursday Mar 05, 2015 at 05:14PM in JBatch


I pushed entire project to https://github.com/lbtc-xxx/arquillian-jbatch .

While I prefer remote EJB way like my previous posting for JBatch testing, it works well for simple project. but little slower than remote EJB on my environment.


Using Apache BatchEE's server API with JBeret


Posted on Wednesday Mar 04, 2015 at 06:11PM in JBatch


Apache BatchEE is a fork of the JSR352 reference implementation with many additional features. it has useful REST APIs built on JAX-RS so we can manipulate (start, stop, restart, and so on) batches through REST API. fortunately, it is well modularized so we can use its REST API implementation with other JSR352 implementation such as JBeret.

curl -H 'Content-Type: application/json' \
     -d '{"entries": [ {"key": "myKey1", "value": "myValue1"}, {"key": "myKey2", "value": "myValue2"} ]}' \
     http://localhost:8080/batcheetest/jbatch/batchee/execution/start/myjob

Then you’ll see following output in WildFly console:

17:57:18,608 INFO  [stdout] (Batch Thread - 9) Hello world!
17:57:18,609 INFO  [stdout] (Batch Thread - 9) Job Parameters: {myKey2=myValue2, myKey1=myValue1}

It’s much better than create a servlet which kicks the batch.

And I haven’t tested yet, it also have useful client API for that REST API. we can use JobOperator transparently thanks to its proxy. for details of REST API and BatchEE, see following URLs:

UPDATE:

I added a test case which uses client API of BatchEE, but it doesn’t work with released version. you need to apply a patch by hand. for details refer https://issues.apache.org/jira/browse/BATCHEE-59

Also I created an example of a test class which uses Arquillian. this won’t work with 0.2-incubating but will work with future versions.

@RunWith(Arquillian.class)
public class MyJobArquillianIT {
    @ArquillianResource
    private URL url;
    private JobOperator jobOperator;

    @Deployment(testable = false)
    public static Archive<?> war() {
        final File[] files = Maven.configureResolver()
                .loadPomFromFile("pom.xml")
                .resolve("org.apache.batchee:batchee-jaxrs-server")
                .withTransitivity()
                .asFile();
        return ShrinkWrap.create(WebArchive.class)
                .addClass(HelloBatchlet.class)
                .addAsResource("META-INF/batch-jobs/myjob.xml")
                .addAsLibraries(files);
    }

    @Before
    public void before() {
        jobOperator = BatchEEJAXRSClientFactory.newClient(url.toExternalForm() + "jbatch");
    }

    @Test
    public void test() {
        Properties jobParameters = new Properties();
        jobParameters.setProperty("someKey", "someValue");
        final JobExecution jobExecution = waitForFinish(jobOperator.start("myjob", jobParameters));
        Assert.assertEquals(BatchStatus.COMPLETED, jobExecution.getBatchStatus());
    }

    private static final Collection<BatchStatus> BATCH_END_STATUSES
            = EnumSet.of(BatchStatus.COMPLETED, BatchStatus.FAILED, BatchStatus.STOPPED, BatchStatus.ABANDONED);

    private JobExecution waitForFinish(long executionId) {
        JobExecution jobExecution;
        while (!BATCH_END_STATUSES.contains((jobExecution = jobOperator.getJobExecution(executionId)).getBatchStatus())) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        return jobExecution;
    }
}

Web frontend

Its web-frontend GUI (batchee-servlet-embedded) works even against JBeret runtime as follows. you can view executions, jobs and its definition, and can start jobs with custom parameters.

42afff86 2c07 4c4f 8a93 9b90f4910b43

It also exposes simple-rest API which is more useful when issue the command by hand or some cases (e.g. cron job). in case of this example, you can start a job as follows:

$ curl 'http://localhost:8080/batcheetest/jbatch-gui/rest/start/myjob?param1=x&param2=y'
5
OK

You can read its help as follows:

$ curl 'http://localhost:8080/batcheetest/jbatch-gui/rest/'
-1
FAILURE
Unknown command:
The returned response if of MIME type text/plain and contains the following information
  {jobExecutionId} (or -1 if no executionId was detected)\n
  OK (or FAILURE)\n
  followed by command specific information

Known commands are:

* start/ - start a new batch job
  Sample: http://localhost:8080/myapp/jbatch/rest/start/myjobname?param1=x&param2=y
  BatchEE will start the job and immediately return

* status/ - query the current status
  Sample: http://localhost:8080/myapp/jbatch/rest/status/23
  will return the state of executionId 23

* stop/ - stop the job with the given executionId
  Sample: http://localhost:8080/myapp/jbatch/rest/stop/23
  will stop the job with executionId 23

* restart/ - restart the job with the given executionId
  Sample: http://localhost:8080/myapp/jbatch/rest/restart/23
  will restart the job with executionId 23


Deploying an application to WildFly with Ant + Cargo


Posted on Wednesday Mar 04, 2015 at 04:49PM in WildFly


I created an Ant script which deploys an application to WildFly through ssh tunnel. it creates ssh tunnel using Ant’s sshtunnel target. the script works well with a Jenkins job.


Configuring automatic push by successfully build


Posted on Sunday Mar 01, 2015 at 11:19PM in Jenkins


Making Jenkins to push to an another remote repository if build finishes successfully.

Recipe

  1. Create a bare repository

    $ mkdir trader-stable.git
    $ cd trader-stable.git
    $ git init --bare
    Initialized empty Git repository in /Users/Shared/trader-stable.git/
    $
  2. Click Add Repository

    4a49f571 4135 43a8 915f e96db6eb902b
  3. Enter Repository URL

    e33f505c a52b 4752 83f9 44bf45b9db47
  4. Click Advanced…​

    507dc8b1 d86b 4cde b24c b59da15e84ed
  5. Enter stable to Name

    0f54d0a9 5317 40f5 9c60 ee13804a9904
  6. Click Add post-build actionGit Publisher

    44eeab12 4cf2 4c4a 81a9 785b99514659
  7. Check Push Only If Build Succeeds

  8. Click Add Tag

    60946cca e837 4245 a2c8 8e74c98c1f23
  9. Enter $BUILD_NUMBER to Tag to push

  10. Check Create new tag

  11. Enter stable to Target remote name

  12. Click Save

    2a9e7146 7663 414f 9499 91b65e028a43

Test

$ pwd
/Users/kyle/tmp/trader
$ echo 'push if succeeds test' >> hi.txt
$ git commit -am 'push if succeeds test'
$ git push origin master

Jenkins said Pushing tag 8 to repo stable

3e1e0e9a 2732 4054 8a20 82da0f67a7ab
$ git remote add stable /Users/Shared/trader-stable.git
$ git fetch stable
remote: Counting objects: 1, done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (1/1), done.
From /Users/Shared/trader-stable
 * [new tag]         8          -> 8
$