tag:blogger.com,1999:blog-65321466231440590522024-03-05T06:52:29.303-08:00John AmentJohn Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.comBlogger25125tag:blogger.com,1999:blog-6532146623144059052.post-33662427795112952962017-10-22T19:58:00.000-07:002017-10-22T19:58:08.189-07:00How to deal with Java EE ModulesI recently spent some time trying to figure out why <a href="https://hammock-project.github.io/" target="_blank">Hammock</a> wasn't working on Java 9. It was a very weird error, but something people run into quite often.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBException</span><br />
<br />
Errr ok. I've been using JAX-B for a long time. I never realized that it was part of Java EE. It made sense though, given the javax namespace. Apparently the fix was to add some configuration when running Maven to include JAX-B's module from the JDK (which I guess I always was using?)<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">mvn clean install -DargLine="--add-modules java.xml.bind"</span><br />
<br />
The <span style="font-family: "courier new" , "courier" , monospace;">-DargLine</span> passes additional options to the forked surefire JVM, --add-modules (plural!) adds a single module (plus its dependencies) to the classpath, otherwise it's not visible. All of these are runtime issues, visible when the CDI runtime attempts to start. So after making this change, I figured things would work.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">Caused by: java.lang.ClassNotFoundException: javax.xml.ws.WebServiceFeature</span><br />
<br />
Yay. Now I remembered why I liked OSGi so much. Apparently the fix for this one is to add the module java.xml.ws to the build. So I went ahead and ran<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">mvn clean install -DargLine="--add-modules java.xml.bind --add-modules java.xml.ws"</span><br />
<br />
Fair enough, another module. Not too bad. So after running that I was expecting more modules to be added, and got this output<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">Caused by: java.lang.ClassNotFoundException: javax.annotation.Priority</span><br />
<br />
Ok, that's a weird one. Why's it weird? The <span style="font-family: "courier new" , "courier" , monospace;">@Priority</span> annotation comes from <span style="font-family: "courier new" , "courier" , monospace;">javax.annotation-api</span> JAR. It's not provided by the system. CDI runtimes will bring in this JAR (Weld uses the RI, OWB brings in the geronimo spec). I spent about 10 hours over three days trying to dissect this one. I tried all sorts of things to enable the javax.annotation module, even though it was on the classpath. Before I reveal the solution, it's best to understand why the modules I explicitly enabled above are hidden.<br />
<br />
These modules come from Java EE, yet the RI for them was in the JDK itself. By placing the RI in the JDK, we open up external usage for these internal feature set. We also set a precedent that all Java implementations will include these dependencies. That can't be done if these modules are expected to be there but aren't. We lose the build once, run anywhere mantra Java has followed for so long. The good news though, each of the modules are available are standalone dependencies, distributed via Maven Central.<br />
<br />
Anyways, back to how to fix this problem. It turns out, when you enable the <span style="font-family: "courier new" , "courier" , monospace;">java.xml.ws</span> module, it includes a large number of internal dependencies, including the internal JDK <span style="font-family: "courier new" , "courier" , monospace;">javax.annotation</span> package. One of the modular changes in the JDK is that a package name can only exist in one module. Since javax.annotation was coming from the JDK and a JAR on the classpath, the JDK version was being used. So how to deal with this? Well, it turns out for this use case you cannot rely on JDK provided modules. By bringing in the actual maven dependencies for these JARs, you can deal with this consistently - not depending on any JDK internals but by publically available JARs. This is all I had to bring in to make an application compile and run on Java 9:<br />
<br />
<pre style="background-color: white; font-family: Menlo; font-size: 9pt;"><span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">dependency</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">groupId</span><span style="background-color: #efefef;">></span>javax.annotation<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">groupId</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">artifactId</span><span style="background-color: #efefef;">></span>javax.annotation-api<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">artifactId</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">version</span><span style="background-color: #efefef;">></span>1.3.1<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">version</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">dependency</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">dependency</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">groupId</span><span style="background-color: #efefef;">></span>javax.xml.ws<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">groupId</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">artifactId</span><span style="background-color: #efefef;">></span>jaxws-api<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">artifactId</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">version</span><span style="background-color: #efefef;">></span>2.3.0<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">version</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">dependency</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">dependency</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">groupId</span><span style="background-color: #efefef;">></span>javax.activation<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">groupId</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">artifactId</span><span style="background-color: #efefef;">></span>activation<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">artifactId</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"><</span><span style="background-color: #efefef; color: navy; font-weight: bold;">version</span><span style="background-color: #efefef;">></span>1.1.1<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">version</span><span style="background-color: #efefef;">></span>
<span style="background-color: #efefef;"></</span><span style="background-color: #efefef; color: navy; font-weight: bold;">dependency</span><span style="background-color: #efefef;">></span></pre>
<pre style="background-color: white; font-family: Menlo; font-size: 9pt;"><span style="background-color: #efefef;">
</span></pre>
<br />
<br />
The great thing, because of the transitive dependencies all needed JARs will work.
John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com2tag:blogger.com,1999:blog-6532146623144059052.post-78787311820870756202017-10-01T12:26:00.003-07:002017-10-01T12:26:41.858-07:00Moving Java EE away from the JCP - an important first stepIf you haven't already, sign up for the new <a href="https://dev.eclipse.org/mailman/listinfo/ee4j-community" target="_blank">EE4J mailing list</a><br />
<br />
I was surprised as others to see this in one of the <a href="https://dev.eclipse.org/mhonarc/lists/ee4j-community/msg00020.html" target="_blank">first few messages on list</a><br />
<blockquote class="tr_bq">
<span style="font-family: monospace;">It is my understanding that the new specification process will not be using the JCP.</span></blockquote>
However, I believe it's an extremely important thing to realize how critical of a step this is. When Oracle purchased Sun, they brought along everything that was there. Included in this was the very Sun heavy JCP, which while being open was a pain if you weren't a Sun employee. Much of this has remained the case with Oracle in the lead. The JCP is run independently, but by seemingly Oracle staff.<br />
<br />
While we've been able to get some JSRs through that are not lead by Oracle, it hasn't been many. The intention to move EE4J away from the JCP is purely a positive sign that Oracle wants to let the community drive the initiatives. It allows those who want a say and have a say to drive the direction of this new technology. If I look at who is on the <a href="https://jcp.org/en/participation/committee" target="_blank">JCP EC</a>, not all of them are involved in Java EE today. So why should the future and effectively the vote on whether a Java EE specification is ready to be shipped put forth to a group who may not be interested in Java EE?<br />
<br />
To me at least, this is a great sign, an important step, and really a clear indication that we need to look at things differently with EE4J than we ever did with Java EE. I welcome the future and the innovation that this project is going to create.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-31610819909867762962016-06-21T16:14:00.004-07:002016-06-22T03:20:54.012-07:00Hibernate OGM + Apache DeltaSpike Data = Pure Love for NoSQLIf you haven't looked at it before, <a href="http://hibernate.org/ogm/" target="_blank">Hibernate OGM</a> is a JPA implementation designed around NoSQL databases. Since its a JPA implementation, it plugs in perfectly to Apache DeltaSpike's Data module. The added support for NoSQL databases really is a strong suitor for cross platform support.<br />
<br />
To start, we'll create a persistence.xml to represent our connection.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><persistence font=""></persistence></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><persistence</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> version="2.1"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> xmlns="http://xmlns.jcp.org/xml/ns/persistence"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <persistence-unit name="MyPU" transaction-type="RESOURCE_LOCAL"></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <!-- Use the Hibernate OGM provider: configuration will be transparent --></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <properties></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <property name="hibernate.ogm.datastore.provider" value="mongodb"/></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <property name="hibernate.ogm.datastore.database" value="swarmic"/></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <property name="hibernate.ogm.datastore.create_database" value="true"/></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </properties></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </persistence-unit></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></persistence></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "times" , "times new roman" , serif;">This is copied pretty much verbatim from the user guide. I'm using MongoDB. Not for any particular reason other than I've used it before and it was already installed on my machine. Next we'll create a repository and an entity:</span><br />
<span style="font-family: "times" , "times new roman" , serif;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Entity</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">public class Employee {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @Id</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @GeneratedValue(generator = "uuid")</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @GenericGenerator(name="uuid", strategy="uuid2")</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private String id;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @Column(length = 40)</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private String name;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Repository(forEntity = Employee.class)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">public interface EmployeeRepository extends EntityPersistenceRepository<employee string="">{</employee></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @Query("select e from Employee e order by e.name")</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Stream<employee> list();</employee></span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span><br />
<span style="font-family: "times" , "times new roman" , serif;"><br /></span>
<span style="font-family: "times" , "times new roman" , serif;">Now we have a database layer that can save and retrieve entities. Last thing we need is a REST endpoint to expose this. To do that, we want to make sure its transactional since we're using resource local as well as providing some sane operations (create, list). That endpoint probably looks like this</span><br />
<span style="font-family: "times" , "times new roman" , serif;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Path("/")</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@RequestScoped</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Produces("application/json")</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">@Transactional</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">public class EmployeeRest {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @Inject</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private EmployeeRepository repository;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @GET</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public Response list(@QueryParam("name") String name) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> return Response.ok(repository.list().collect(toList())).build();</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @GET</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @Path("/{id}")</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public Employee get(@PathParam("id") String id) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> return repository.findBy(id);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @POST</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> @Consumes("text/plain")</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public Response create(String name) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Employee employee = new Employee(name);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Employee result = repository.save(employee);</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> return Response.ok(result.getId()).build();</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span><br />
<span style="font-family: "times" , "times new roman" , serif;"><br /></span>
<span style="font-family: "times" , "times new roman" , serif;">So just like that, with in the ball park of 75 lines of code, we have a CDI based application that uses Hibernate OGM and Apache DeltaSpike that can list, get and create entities end to end. That was super simple!</span>John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com4tag:blogger.com,1999:blog-6532146623144059052.post-8037344980517291872016-05-29T06:48:00.001-07:002016-05-29T06:48:02.605-07:00Hammock 0.0.3 is Out!Hammock 0.0.3 is out!<br />
<br />
After more than 2 years, the next version of Hammock is finally out. Some of the key changes here:<br />
<br />
- Upgraded to the latest libraries of pretty much everything.<br />
- Use a more modular build structure<br />
- Introduction of a new security component<br />
- Serving file system assets<br />
<br />
If you're not familiar with Hammock, its a lightweight integration, using CDI, based on RestEasy, Undertow. It's a quick and easy to use development framework to spin up small applications.<br />
<br />
<br />
Full details on how to get started with Hammock can be found in the <a href="https://github.com/johnament/hammock/blob/hammock-0.0.3/README.md" target="_blank">README</a><br />
<br />
So what's next? Well a few integrations are still in the works.<br />
<br />
- JPA support, probably via Hibernate, likely to also provide migration support via Flyway<br />
- Camel support based on the <a href="http://camel.apache.org/cdi.html" target="_blank">Camel CDI project</a><br />
- Metrics support on the <a href="https://github.com/astefanutti/metrics-cdi" target="_blank">Metrics CDI project</a>John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-83117397758196362462015-12-20T15:05:00.000-08:002015-12-20T15:05:25.648-08:00Picking the right Scope for your CDI BeansI sometimes find people struggling with how to choose the right scope for your beans. While it can be confusing, I hope that this article will help with your decision making to figure out which scope best applies to your beans.<br />
<br />
<h3>
What's available?</h3>
<br />
As of Java EE 7, your normal scopes are RequestScoped, SessionScoped, ApplicationScoped, ConversationScoped and TransactionScoped. The first two are closely tied to the HTTP life cycle, typically when an HttpSession is started, you get the beginning of a Session Context available for use. When a session is destroyed that Session Context ends. Sessions are meant to be passivated and potentially serializable, so any SessionScoped objects you have must be serialization friendly, including their dependencies. A Request Context exists in many places, but the most straight forward use case is around the duration of a single HTTP Request. The various specs define a few other places where a Request Context is active - PostConstruct methods of Singleton EJBs, MDB invocations, etc.<br />
<br />
A Conversation Context is started manually by a developer and is usually bounded within a shorter period than a containing context. For example, you could create a conversation as a child to a request, and close it before the request is done. The typical use case is around a single session, a set of requests that are all meant to be done together in a coordinated fashion.<br />
<br />
ApplicationScoped beans are created once, the first time the application calls upon them, and are not created again. Note that the scope of an application is somewhat ambiguous. If you have just a WAR, even if it has some libraries without EJBs, it will share a context. Anytime a JAR provides its own entry point (e.g. a JAX-RS endpoint, SOAP endpoint), that may be considered a separate application. EARs are known for introducing this kind of problem, as multiple WARs and EJB JARs will likely create their own unique contexts, resulting in multiple Application Contexts being available. When in doubt, if you can run a single WAR without EAR do it.<br />
<br />
Transaction Scope was introduced in Java EE 7 as a part of JTA 1.2. This context is activated within the bounds of a single transaction. <br />
<br />
There are two other scopes, pseudo scopes you could say, Dependent and Singleton. When working with CDI, Singleton is basically the same as ApplicationScoped, except that Singleton beans aren't eligible for interceptors, decorators. Dependent has similar restrictions, but has an interesting caveat. The injected bean shares its context with its injection point. If you inject it in a RequestScoped bean, then the injected Dependent bean shares the Request Context.<br />
<br />
<h3>
State & Data vs Services and Operations</h3>
<br />
As an application is doing work, it needs to maintain some amount of state. This could represent a user's session, entities being manipulated, a local cache of static resources. This is different than a service that may be performing operations.<br />
<br />
<h4>
Domain-Driven Design considerations</h4>
<br />
Suppose that you are designing a shopping cart, one of the timeless classics in software development. How would you model the ShoppingCart based on scopes, as well as building a rich model that supports the operations relevant to its use. Consider these interfaces<br />
<br />
<blockquote class="tr_bq">
public interface ShoppingCart {<br /> ShoppingCartItem addItem(Item item);<br /> Order checkout(BillingInformation billingInformation);<br />}</blockquote>
<br />
At a very high level, consider these behaviors as well:<br />
- A shopping cart is persistent. If I change it, and then leave the site, what I added should be available to me at a later point.<br />
- Adding an item to my shopping cart is an atomic, synchronized, idempotent and request based transaction. I'm only able to add one item at a time in a single request but I could open multiple browser tabs and make changes in tandem.<br />
- Since these operations are atomic and state is persistent, the changes I make should be automatically written to a data store as a part of these operations.<br />
<br />
Based on this information, as well as the tips above, how would you scope these domain objects?<br />
<br />
Here's one approach.<br />
<br />
- Your ShoppingCart is session scoped. It's associated to a user, persistent but generally tied to a single user session. <br />
- Your ShoppingCart is dependent on some kind of ShoppingCartService that is responsible for the persistence of the state of a shopping cart, and likely other services as needed (e.g. an OrderService for handling checkout w/ credit card information). These services are ApplicationScoped and operate on these classes.<br />
- Item is a RequestScoped bean that represents what you're trying to add to your cart. It is built up in a single request and pushed into your cart.<br />
- BillingInformation is a ConversationScoped bean, the data is built up in a few requests, and then calls checkout when all of the information is present.<br />
- Neither Order nor ShoppingCartItem are managed beans. They are created within the scope of their respective methods.<br />
<br />
These domain classes together represent the state of your application, specifically how things are changing over time. So how do you interact with them?<br />
<br />
<h4>
Controllers</h4>
<br />
If a controller is aware of the view and the backing model, what scope does it get? If you're dealing with JAX-RS, the answer is pretty easy - RequestScoped resource classes are mandated in a JAX-RS/CDI environment. You have a bit more leway with frameworks like JSF, but realistically a request scoped controller makes the most sense.<br />
- It's bound to the HTTP lifecycle (assuming you're using HTTP)<br />
- It represents the start of a request.<br />
- It's the user's action of interacting with the system on a per request basis.<br />
<br />
This doesn't mean you can't use a SessionScoped or TransactionScoped controller, but semantically it makes things clearer that it is request scoped. Another thing to point out, your request scoped controller can still interact with your session scoped model. Typically requests are made within a session, and thus give you access to the sessions contents as well as requet's contents. That means this controller is valid<br />
<br />
<blockquote class="tr_bq">
@RequestScoped<br />public class ShoppingCartController {<br /> @Inject<br /> private ShoppingCart shoppingCart;<br />}</blockquote>
<br />
This is a perfectly valid thing to do. <br />
<br />
Consider this alternate approach. What do you think is going to happen?<br />
<blockquote class="tr_bq">
<br />@RequestScoped<br />public class Item {<br />}<br />@SessionScoped<br />public class ShoppingCartController{<br /> @Inject<br /> private Item item;<br />}</blockquote>
<br />
In here, as mentioned above, Item is bound to a request, it represents the item that is being selected by the user. I marked my controller as session scoped since the lifecycle of the shopping cart is tied to a session. This is a legal injection and is threadsafe. What happens is that the context is bound to the HTTP request, the same controller (session scoped) will operate on two different requests. Obviously be careful for things like mutating the controller (since its a controller, shouldn't be an issue).<br />
<br />
<h4>
Services</h4>
<br />
Services, from my point of view have two valid scopes. First, they can be application scoped (or singleton, if you don't care about proxies/AOP) since they maintain no state. Second, they can be dependent since they also maintain no state, and can be reused in a wider variety of cases. I'm generally warry of recommending dependent scoped beans, just because of some ways they can be misused (e.g. not cleaning up, lookup/non-injection cases). As long as a service isn't maintaining any state, it can be used over and over again. <br />
<br />
<h4>
Conclusion</h4>
<br />
There you have it. I hope you found this article useful. Please feel free to add comments below.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-75622885254495968812014-03-23T18:13:00.000-07:002014-03-23T18:13:41.979-07:00Review of Java EE and HTML5 Enterprise Application DevelopmentI recently had the pleasure of reading through the book <i>Java EE and HTML5 Enterprise Application Development</i> by John Brock, Arun Gupta and Geertjan Wielenga.<br />
<br />
First, a comment on file formats. I use Linux at home. I had the most trouble trying to get setup to actually read the book. The format used is only compatible with Adobe Digital Editions, which only works on Mac and Windows. I ended up getting a VM to do the reading on. Little bit of a pain if you're like me and use a tablet for a decent amount of reading. <br />
<br />
The book takes the approach of wanting to build HTML5 applications, leveraging the Java server side as an API type server, with both REST APIs and WebSockets in use, and a front end based on <a href="http://knockoutjs.com/" rel="nofollow" target="_blank">Knockout</a> and low level jQuery to process API calls. The backend is using your stereotypical Java EE stack of JPA, EJB and JAX-RS, plus WebSocket support. The way used in this book serves as an entry point for someone new to a lot of the technology and how to use them; it doesn't focus on changes over time in these specs or some of the new features. It's a bottom up approach for being able to expose your database over an API.<br />
<br />
Probably the most confusing part of the book, and it may be because of different authors, is the crossing of example types. In the JPA and JAX-RS chapters, we use a book and author example. In the WebSocket chapter the authors use a board and tic tac toe example. I believe the consistent use of a fluid example is the best thing to do in a technical book. A good example of that is <i><a href="http://shop.oreilly.com/product/0636920025368.do" target="_blank">Continuous Enterprise Development</a> </i>by <a href="https://twitter.com/alrubinger" target="_blank">Andrew Lee Rubinger</a> and <a href="https://twitter.com/aslakknutsen" target="_blank">Aslak Knutsen</a>.<br />
<br />
The chapter on application security is probably the best of the book, in my opinion. It goes through what you need to do not just server side but also client side to secure your web applications. For those new to this programming paradigm, it's some good information on some of the key differences versus traditional server side rendered web applications (JSF, Struts, etc).<br />
<br />
The content of the book is brought about in an introductory manner. If you're new to these technologies, it's a good read to get up to speed on how they work. The JPA spec has only changed a little bit in 2.0 and 2.1, so if you're already familiar with how things worked previously, it's not a huge change. JAX-RS is a newer spec, in its 2.0 release already and shows how declarative it can be. Hidden in the REST chapter you'll find some interesting pieces on CDI, Transactions and Bean Validation. These other technologies really help build the bridge across all of the technology.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-45383844353929230282014-02-26T19:27:00.001-08:002014-02-26T19:27:17.625-08:00Announcing HammockI'd like to introduce the world to Hammock<br />
<br />
Hammock is based on my last blog post, creating a light weight service to run JAX-RS resources over a minimalistic configuration.<br />
<br />
Binaries are currently up on Sonatype OSS (I hope they sync to MVN central shortly): https://oss.sonatype.org/index.html#nexus-search;quick~ws.ament.hammock<br />
<br />
Github: https://github.com/johnament/hammock<br />
<br />
What is Hammock?<br />
<br />
Hammock is a light weight integration between JBoss RestEasy, Undertow and Weld. Leveraging Weld SE, it provides automatic resource scanning and minimal binding code to launch a web container (Undertow) running the basic services to launch a full JAX-RS application. <br />
<br />
Getting Started<br />
<br />
Getting started with Hammock is simple. Add a reference to the project in your pom.xml:<br />
<br />
<dependency></dependency><br />
<groupid>ws.ament.hammock</groupid><br />
<artifactid>hammock-core</artifactid><br />
<version>0.0.1</version><br />
<br />
<br />
Add your REST Resource class:<br />
<br />
@Path("/echo")<br />
@RequestScoped<br />
public class EchoResource {<br />
@GET<br />
@Produces("text/plain")<br />
public String greet() {<br />
return "hello";<br />
}<br />
}<br />
<div>
<br /></div>
<div>
Implement the configuration, for application (via @ApplicationConfig)</div>
<div>
<br /></div>
<div>
<div>
@ApplicationConfig</div>
<div>
@ApplicationScoped</div>
<div>
public class ApplicationConfigBean implements WebServerConfiguration {</div>
<div>
@Override</div>
<div>
public int getPort() {</div>
<div>
return 8080;</div>
<div>
}</div>
<div>
@Override</div>
<div>
public String getContextRoot() {</div>
<div>
return "/api";</div>
<div>
}</div>
<div>
@Override</div>
<div>
public Collection<class> getProviderClasses() {</class></div>
<div>
return Collections.EMPTY_LIST;</div>
<div>
}</div>
<div>
@Override</div>
<div>
public Collection<class> getResourceClasses() {</class></div>
<div>
return Collections.singleton(EchoResource.class);</div>
<div>
}</div>
<div>
@Override</div>
<div>
public String getBindAddress() {</div>
<div>
return "0.0.0.0";</div>
<div>
}</div>
<div>
}</div>
</div>
<div>
<br /></div>
<div>
You can optionally also do this for a management interface as well (via @ManagementConfig). The resources tied to each of these configurations would then be launched when you start your application.</div>
<div>
<br /></div>
<div>
Starting your app can be done manually via Weld SE, or by using their built in class, org.jboss.weld.environment.se.StartMain .</div>
John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com5tag:blogger.com,1999:blog-6532146623144059052.post-27705044220289738612014-01-19T06:48:00.000-08:002014-01-19T06:48:01.125-08:00Bridging Netty, RestEasy and WeldAs you likely know, RestEasy already supports an embedded container for <a href="http://docs.jboss.org/resteasy/docs/3.0.6.Final/userguide/html/RESTEasy_Embedded_Container.html#d4e1408" target="_blank">Netty</a>. RestEasy also supports CDI injection, but only for enterprise use cases (e.g. part of the Java EE spec or using Weld Servlet). In the case of Netty, it's almost possible, except that the lack of a ServletContext seems to throw it off.<br />
<br />
In addition, in many use cases you may want to translate each incoming request into a CDI RequestScope. This requires some custom handling of each request, before passing it down to RestEasy for processing. This allows you to properly scope all of your objects, though you cannot use a session scoped object (since there would be no active session).<br />
<br />
The code is pretty simple to do this. You can find details on my github repository: https://github.com/johnament/resteasy-netty-cdi<br />
<br />
First, define your endpoint. In my test case, I added a very simple one:<br />
<br />
<pre style="box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px;"><div class="line" id="LC34" style="box-sizing: border-box; padding-left: 10px;">
<span class="nd" style="box-sizing: border-box;">@Path</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="s" style="box-sizing: border-box; color: #dd1144;">"/"</span><span class="o" style="box-sizing: border-box; font-weight: bold;">)</span></div>
<div class="line" id="LC34" style="box-sizing: border-box; padding-left: 10px;">
@RequestScoped</div>
<div class="line" id="LC35" style="box-sizing: border-box; padding-left: 10px;">
<span class="kd" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="kd" style="box-sizing: border-box; font-weight: bold;">class</span> <span class="nc" style="box-sizing: border-box; color: #445588; font-weight: bold;">TestEndpoint</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC36" style="box-sizing: border-box; padding-left: 10px;">
<span class="nd" style="box-sizing: border-box;">@GET</span></div>
<div class="line" id="LC37" style="box-sizing: border-box; padding-left: 10px;">
<span class="kd" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="n" style="box-sizing: border-box;">String</span> <span class="nf" style="box-sizing: border-box; color: #990000; font-weight: bold;">echo</span><span class="o" style="box-sizing: border-box; font-weight: bold;">()</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC38" style="box-sizing: border-box; padding-left: 10px;">
<span class="k" style="box-sizing: border-box; font-weight: bold;">return</span> <span class="s" style="box-sizing: border-box; color: #dd1144;">"pong"</span><span class="o" style="box-sizing: border-box; font-weight: bold;">;</span></div>
<div class="line" id="LC39" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">}</span></div>
<div class="line" id="LC40" style="box-sizing: border-box; padding-left: 10px;">
<span style="font-weight: bold;">}</span></div>
</pre>
<br />
Next, we need some code to initialize the server. I added this directly in my test, but I would imagine most people would want to initialize it elsewhere.<br />
<br />
<pre style="box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px;"><div class="line" id="LC54" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;"> CDINettyJaxrsServer</span> <span class="n" style="box-sizing: border-box;">netty</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="k" style="box-sizing: border-box; font-weight: bold;">new</span> <span class="n" style="box-sizing: border-box;">CDINettyJaxrsServer</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC55" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">ResteasyDeployment</span> <span class="n" style="box-sizing: border-box;">rd</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="k" style="box-sizing: border-box; font-weight: bold;">new</span> <span class="n" style="box-sizing: border-box;">ResteasyDeployment</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC56" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">rd</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">setActualResourceClasses</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">paths</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">getResources</span><span class="o" style="box-sizing: border-box; font-weight: bold;">());</span></div>
<div class="line" id="LC57" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">rd</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">setInjectorFactoryClass</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">CdiInjectorFactory</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">class</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">getName</span><span class="o" style="box-sizing: border-box; font-weight: bold;">());</span></div>
<div class="line" id="LC58" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">netty</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">setDeployment</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">rd</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC59" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">netty</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">setPort</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="mi" style="box-sizing: border-box; color: #009999;">8087</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC60" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">netty</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">setRootResourcePath</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="s" style="box-sizing: border-box; color: #dd1144;">""</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC61" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">netty</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">setSecurityDomain</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="kc" style="box-sizing: border-box; font-weight: bold;">null</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC62" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">netty</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">start</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
</pre>
<br />
As you can see in the test, I am using a custom CdiNettyJaxrsServer, which is what enables me for CDI integration. The only thing different about mine versus the normal one is what RequestDispatcher I use. The RequestDispatcher is what RestEasy provides to handle the incoming requests and what the response looks like. It's very low level. I decided this was the exact point I wanted to start the CDI RequestScope. So my RequestDispatcher looks like this<br />
<br />
<pre style="box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px;"><div class="line" id="LC41" style="box-sizing: border-box; padding-left: 10px;">
<span class="kd" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="kd" style="box-sizing: border-box; font-weight: bold;">class</span> <span class="nc" style="box-sizing: border-box; color: #445588; font-weight: bold;">CDIRequestDispatcher</span> <span class="kd" style="box-sizing: border-box; font-weight: bold;">extends</span> <span class="n" style="box-sizing: border-box;">RequestDispatcher</span></div>
<div class="line" id="LC42" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC43" style="box-sizing: border-box; padding-left: 10px;">
</div>
<div class="line" id="LC44" style="box-sizing: border-box; padding-left: 10px;">
<span class="kd" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="nf" style="box-sizing: border-box; color: #990000; font-weight: bold;">CDIRequestDispatcher</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">SynchronousDispatcher</span> <span class="n" style="box-sizing: border-box;">dispatcher</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span> <span class="n" style="box-sizing: border-box;">ResteasyProviderFactory</span> <span class="n" style="box-sizing: border-box;">providerFactory</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span></div>
<div class="line" id="LC45" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">SecurityDomain</span> <span class="n" style="box-sizing: border-box;">domain</span><span class="o" style="box-sizing: border-box; font-weight: bold;">)</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC46" style="box-sizing: border-box; padding-left: 10px;">
<span class="kd" style="box-sizing: border-box; font-weight: bold;">super</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">dispatcher</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span><span class="n" style="box-sizing: border-box;">providerFactory</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span><span class="n" style="box-sizing: border-box;">domain</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC47" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">}</span></div>
<div class="line" id="LC48" style="box-sizing: border-box; padding-left: 10px;">
</div>
<div class="line" id="LC49" style="box-sizing: border-box; padding-left: 10px;">
<span class="kd" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="kt" style="box-sizing: border-box; color: #445588; font-weight: bold;">void</span> <span class="nf" style="box-sizing: border-box; color: #990000; font-weight: bold;">service</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">HttpRequest</span> <span class="n" style="box-sizing: border-box;">request</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span> <span class="n" style="box-sizing: border-box;">HttpResponse</span> <span class="n" style="box-sizing: border-box;">response</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span> <span class="kt" style="box-sizing: border-box; color: #445588; font-weight: bold;">boolean</span> <span class="n" style="box-sizing: border-box;">handleNotFound</span><span class="o" style="box-sizing: border-box; font-weight: bold;">)</span> <span class="kd" style="box-sizing: border-box; font-weight: bold;">throws</span> <span class="n" style="box-sizing: border-box;">IOException</span></div>
<div class="line" id="LC50" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC51" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">BoundRequestContext</span> <span class="n" style="box-sizing: border-box;">requestContext</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="n" style="box-sizing: border-box;">CDI</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">current</span><span class="o" style="box-sizing: border-box; font-weight: bold;">().</span><span class="na" style="box-sizing: border-box; color: teal;">select</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">BoundRequestContext</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">class</span><span class="o" style="box-sizing: border-box; font-weight: bold;">).</span><span class="na" style="box-sizing: border-box; color: teal;">get</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC52" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">Map</span><span class="o" style="box-sizing: border-box; font-weight: bold;"><</span><span class="n" style="box-sizing: border-box;">String</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span><span class="n" style="box-sizing: border-box;">Object</span><span class="o" style="box-sizing: border-box; font-weight: bold;">></span> <span class="n" style="box-sizing: border-box;">requestMap</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="k" style="box-sizing: border-box; font-weight: bold;">new</span> <span class="n" style="box-sizing: border-box;">HashMap</span><span class="o" style="box-sizing: border-box; font-weight: bold;"><</span><span class="n" style="box-sizing: border-box;">String</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span><span class="n" style="box-sizing: border-box;">Object</span><span class="o" style="box-sizing: border-box; font-weight: bold;">>();</span></div>
<div class="line" id="LC53" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">requestContext</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">associate</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">requestMap</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC54" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">requestContext</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">activate</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC55" style="box-sizing: border-box; padding-left: 10px;">
<span class="k" style="box-sizing: border-box; font-weight: bold;">try</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC56" style="box-sizing: border-box; padding-left: 10px;">
<span class="kd" style="box-sizing: border-box; font-weight: bold;">super</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">service</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">request</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span><span class="n" style="box-sizing: border-box;">response</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span><span class="n" style="box-sizing: border-box;">handleNotFound</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC57" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">}</span></div>
<div class="line" id="LC58" style="box-sizing: border-box; padding-left: 10px;">
<span class="k" style="box-sizing: border-box; font-weight: bold;">finally</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC59" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">requestContext</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">invalidate</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC60" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">requestContext</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">deactivate</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC61" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">requestContext</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">dissociate</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">requestMap</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC62" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">}</span></div>
<div class="line" id="LC63" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">}</span></div>
<div class="line" id="LC64" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">}</span></div>
</pre>
<br />
So whenever a request comes in, I start the context (using Weld's BoundRequestContext) and on completion I end it. I also created a custom CdiInjectorFactory for Netty. This alleviates a bug in the base one that depends on a ServletContext being available (throughs a NullPointerException). It's just a simplified version of the injector factory<br />
<br />
<pre style="box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px;"><div class="line" id="LC144" style="box-sizing: border-box; padding-left: 10px;">
<span class="kd" style="box-sizing: border-box; font-weight: bold;">protected</span> <span class="n" style="box-sizing: border-box;">BeanManager</span> <span class="nf" style="box-sizing: border-box; color: #990000; font-weight: bold;">lookupBeanManager</span><span class="o" style="box-sizing: border-box; font-weight: bold;">()</span></div>
<div class="line" id="LC145" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC146" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">BeanManager</span> <span class="n" style="box-sizing: border-box;">beanManager</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="kc" style="box-sizing: border-box; font-weight: bold;">null</span><span class="o" style="box-sizing: border-box; font-weight: bold;">;</span></div>
<div class="line" id="LC147" style="box-sizing: border-box; padding-left: 10px;">
</div>
<div class="line" id="LC148" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">beanManager</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="n" style="box-sizing: border-box;">lookupBeanManagerCDIUtil</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC149" style="box-sizing: border-box; padding-left: 10px;">
<span class="k" style="box-sizing: border-box; font-weight: bold;">if</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">beanManager</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">!=</span> <span class="kc" style="box-sizing: border-box; font-weight: bold;">null</span><span class="o" style="box-sizing: border-box; font-weight: bold;">)</span></div>
<div class="line" id="LC150" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC151" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">log</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">debug</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="s" style="box-sizing: border-box; color: #dd1144;">"Found BeanManager via CDI Util"</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC152" style="box-sizing: border-box; padding-left: 10px;">
<span class="k" style="box-sizing: border-box; font-weight: bold;">return</span> <span class="n" style="box-sizing: border-box;">beanManager</span><span class="o" style="box-sizing: border-box; font-weight: bold;">;</span></div>
<div class="line" id="LC153" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">}</span></div>
<div class="line" id="LC154" style="box-sizing: border-box; padding-left: 10px;">
</div>
<div class="line" id="LC155" style="box-sizing: border-box; padding-left: 10px;">
<span class="k" style="box-sizing: border-box; font-weight: bold;">throw</span> <span class="k" style="box-sizing: border-box; font-weight: bold;">new</span> <span class="nf" style="box-sizing: border-box; color: #990000; font-weight: bold;">RuntimeException</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="s" style="box-sizing: border-box; color: #dd1144;">"Unable to lookup BeanManager."</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC156" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">}</span></div>
</pre>
<br />
You'll also notice in my test code I'm using a CDI Extension - LoadPathsExtension. This simply sits on the classpath and listens as Weld initializes. <br />
<br />
<span class="n" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;">LoadPathsExtension</span><span style="background-color: white; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;"> </span><span class="n" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;">paths</span><span style="background-color: white; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;"> </span><span class="o" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; font-weight: bold; line-height: 18px; white-space: pre;">=</span><span style="background-color: white; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;"> </span><span class="n" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;">CDI</span><span class="o" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; font-weight: bold; line-height: 18px; white-space: pre;">.</span><span class="na" style="background-color: white; box-sizing: border-box; color: teal; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;">current</span><span class="o" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; font-weight: bold; line-height: 18px; white-space: pre;">().</span><span class="na" style="background-color: white; box-sizing: border-box; color: teal; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;">select</span><span class="o" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; font-weight: bold; line-height: 18px; white-space: pre;">(</span><span class="n" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;">LoadPathsExtension</span><span class="o" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; font-weight: bold; line-height: 18px; white-space: pre;">.</span><span class="na" style="background-color: white; box-sizing: border-box; color: teal; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;">class</span><span class="o" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; font-weight: bold; line-height: 18px; white-space: pre;">).</span><span class="na" style="background-color: white; box-sizing: border-box; color: teal; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px; white-space: pre;">get</span><span class="o" style="background-color: white; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; font-weight: bold; line-height: 18px; white-space: pre;">();</span><br />
<br />
For each ProcessAnnotatedType it observes, it checks if Path is present. If Path is present, it adds it to a local list of all resources. <br />
<br />
<pre style="box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px;"><div class="line" id="LC40" style="box-sizing: border-box; padding-left: 10px;">
<span class="kd" style="box-sizing: border-box; font-weight: bold;"> public</span> <span class="kt" style="box-sizing: border-box; color: #445588; font-weight: bold;">void</span> <span class="nf" style="box-sizing: border-box; color: #990000; font-weight: bold;">checkForPath</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="nd" style="box-sizing: border-box;">@Observes</span> <span class="n" style="box-sizing: border-box;">ProcessAnnotatedType</span><span class="o" style="box-sizing: border-box; font-weight: bold;"></span> <span class="n" style="box-sizing: border-box;">pat</span><span class="o" style="box-sizing: border-box; font-weight: bold;">)</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC41" style="box-sizing: border-box; padding-left: 10px;">
<span class="k" style="box-sizing: border-box; font-weight: bold;">if</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">pat</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">getAnnotatedType</span><span class="o" style="box-sizing: border-box; font-weight: bold;">().</span><span class="na" style="box-sizing: border-box; color: teal;">isAnnotationPresent</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">Path</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">class</span><span class="o" style="box-sizing: border-box; font-weight: bold;">))</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">{</span></div>
<div class="line" id="LC42" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">logger</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">info</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="s" style="box-sizing: border-box; color: #dd1144;">"Discovered resource "</span><span class="o" style="box-sizing: border-box; font-weight: bold;">+</span><span class="n" style="box-sizing: border-box;">pat</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">getAnnotatedType</span><span class="o" style="box-sizing: border-box; font-weight: bold;">().</span><span class="na" style="box-sizing: border-box; color: teal;">getJavaClass</span><span class="o" style="box-sizing: border-box; font-weight: bold;">());</span></div>
<div class="line" id="LC43" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">resources</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">add</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">pat</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">getAnnotatedType</span><span class="o" style="box-sizing: border-box; font-weight: bold;">().</span><span class="na" style="box-sizing: border-box; color: teal;">getJavaClass</span><span class="o" style="box-sizing: border-box; font-weight: bold;">());</span></div>
<div class="line" id="LC44" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">}</span></div>
<div class="line" id="LC45" style="box-sizing: border-box; padding-left: 10px;">
<span class="o" style="box-sizing: border-box; font-weight: bold;">}</span></div>
</pre>
<br />
This makes scanning for Paths possible, which is done by the container for RestEasy. In the Netty deployment, you need to always maintain your list of resources.<br />
<br />
<pre style="box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px;"><div class="line" id="LC53" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;"> LoadPathsExtension</span> <span class="n" style="box-sizing: border-box;">paths</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="n" style="box-sizing: border-box;">CDI</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">current</span><span class="o" style="box-sizing: border-box; font-weight: bold;">().</span><span class="na" style="box-sizing: border-box; color: teal;">select</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">LoadPathsExtension</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">class</span><span class="o" style="box-sizing: border-box; font-weight: bold;">).</span><span class="na" style="box-sizing: border-box; color: teal;">get</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC54" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">CDINettyJaxrsServer</span> <span class="n" style="box-sizing: border-box;">netty</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="k" style="box-sizing: border-box; font-weight: bold;">new</span> <span class="n" style="box-sizing: border-box;">CDINettyJaxrsServer</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC55" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">ResteasyDeployment</span> <span class="n" style="box-sizing: border-box;">rd</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="k" style="box-sizing: border-box; font-weight: bold;">new</span> <span class="n" style="box-sizing: border-box;">ResteasyDeployment</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC56" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">rd</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">setActualResourceClasses</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">paths</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">getResources</span><span class="o" style="box-sizing: border-box; font-weight: bold;">());</span></div>
</pre>
<br />
Finally, we start the actual test which uses the JAX-RS client API to make a request to a specific resource. <br />
<br />
<pre style="box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 18px;"><div class="line" id="LC63" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">Client</span> <span class="n" style="box-sizing: border-box;">c</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="n" style="box-sizing: border-box;">ClientBuilder</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">newClient</span><span class="o" style="box-sizing: border-box; font-weight: bold;">();</span></div>
<div class="line" id="LC64" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">String</span> <span class="n" style="box-sizing: border-box;">result</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="n" style="box-sizing: border-box;">c</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">target</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="s" style="box-sizing: border-box; color: #dd1144;">"http://localhost:8087"</span><span class="o" style="box-sizing: border-box; font-weight: bold;">).</span><span class="na" style="box-sizing: border-box; color: teal;">path</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="s" style="box-sizing: border-box; color: #dd1144;">"/"</span><span class="o" style="box-sizing: border-box; font-weight: bold;">).</span><span class="na" style="box-sizing: border-box; color: teal;">request</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="s" style="box-sizing: border-box; color: #dd1144;">"text/plain"</span><span class="o" style="box-sizing: border-box; font-weight: bold;">).</span><span class="na" style="box-sizing: border-box; color: teal;">accept</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="s" style="box-sizing: border-box; color: #dd1144;">"text/plain"</span><span class="o" style="box-sizing: border-box; font-weight: bold;">).</span><span class="na" style="box-sizing: border-box; color: teal;">get</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="n" style="box-sizing: border-box;">String</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">class</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
<div class="line" id="LC65" style="box-sizing: border-box; padding-left: 10px;">
<span class="n" style="box-sizing: border-box;">Assert</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="na" style="box-sizing: border-box; color: teal;">assertEquals</span><span class="o" style="box-sizing: border-box; font-weight: bold;">(</span><span class="s" style="box-sizing: border-box; color: #dd1144;">"pong"</span><span class="o" style="box-sizing: border-box; font-weight: bold;">,</span> <span class="n" style="box-sizing: border-box;">result</span><span class="o" style="box-sizing: border-box; font-weight: bold;">);</span></div>
</pre>
<br />John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com1tag:blogger.com,1999:blog-6532146623144059052.post-55992698679366558142013-10-26T09:32:00.001-07:002013-10-26T09:32:04.805-07:00Announcing injectahvent - a lightweight integration between CDI Events & Apache Camel exchanges<h3>
Howdy all!</h3>
<br />
I am proud to announce a new open source library I am working on, injectahvent. Injectahvent is meant to be a light weight integration between Camel Messages and CDI Events. It allows you to define a processor that will fire CDI events on Camel exchanges, and in turn will also allow you to register new ObserverMethods in CDI that listen for events and move them over to Apache Camel exchanges.<br />
<br />
<h3>
So what does it do so far?</h3>
<br />
Well, it's a little generic right now, but essentially you can register a new CDIEventProcessor in to your RouteBuilder and let CDI fire an Event with the body and exchange objects.<br />
<br />
The second part it does is is to allow an application developer to create a simple CDI extension that registers new ObserverMethods for CDI events to look for and use a Camel ProducerTemplate to fire that message.<br />
<br />
Conceptually, this is a carry on project from the JBoss SeamJMS module. While the new fluent API for sending messages was inspired by some of the builder pattern used in Seam JMS and is now incorporated in JMS 2.0, the firing of events was not carried over. Firing the events is more of an EIP/EAI type of tool. As a result, I decided to leverage Apache Camel to make it more generic.<br />
<br />
The library leverages <a href="http://www.deltaspike.org/" target="_blank">Apache DeltaSpike,</a> with its CDI Container Control API to start a new RequestContext for a fired message. It's currently assumed that the basic bootstrap of a CDI container is done outside of this context.<br />
<br />
Source Code: <a href="https://github.com/johnament/injectahvent">https://github.com/johnament/injectahvent</a><br />
Issues: <a href="https://github.com/johnament/injectahvent/issues">https://github.com/johnament/injectahvent/issues</a><br />
<br />
I hope to start putting together a wiki for it soon. As well as doing some nice code clean up.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-19878386248488123852013-09-29T16:19:00.002-07:002013-09-29T16:21:52.543-07:00Testing JAAS based authentication using Arquillian + Apache DeltaSpike Servlet ModuleHey all. Long time no post.<br />
<br />
In today's discussion, I'm talking about testing enterprise applications again. I recently was faced with a dilemma. I needed to test my application in an authenticated way, where the user was logged in vs logged out to ensure that things were going right with an authenticated principal.<br />
<br />
Of course, this assumes a few things. First, that we've executed something to ensure our database is populated with a user that could log in. In my case, I did this by calling internal APIs that do registration and registration completion. You could do other things, such as using the <a href="https://docs.jboss.org/author/display/ARQ/Persistence" target="_blank">Arquillian Persistence Extension</a> to insert records. My application is using the <a href="http://arquillian.org/guides/getting_started_rinse_and_repeat/#write_a_test" target="_blank">@InSequence</a> annotation with Arquillian and JUnit to give methods an ordering.<br />
<br />
Now that we have a little bit of setup, we're going to leverage a few newer technologies. In Servlet 3, methods were added to the HTTPServletRequest interface that can <a href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String, java.lang.String)" target="_blank">login</a> and <a href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()" target="_blank">logout</a>. These give us an easy interface to be able to authenticate an end user in to the configured JAAS realm. The problem though is how can we access these objects from an Arquillian test?<br />
<br />
Of course, this approach is assuming you're using the Servlet 3 protocol (or better) to execute your tests. This ensures that you have a an active HTTP request on every test. This request is what we'll use to login the user to the application, and logout afterwards. You can follow the instructions <a href="http://www.deltaspike.org/servlet.html" target="_blank">here</a> to setup the Servlet module in your application. You'll likely also want to use the Maven resolver from ShrinkWrap to bring in the Servlet Module to your deployment WAR file. That resolver config is as easy as:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">File[] impl = Maven.resolver().resolve("org.apache.deltaspike.modules:deltaspike-servlet-module-impl").withTransitivity().asFile();</span><br />
<br />
which can then be added to your WAR as library JARs.<br />
<br />
Now, in your test case you just need to inject the request. Then in your Before/After methods login and logout.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">@Inject</span><br />
<span style="font-family: Courier New, Courier, monospace;">@Web</span><br />
<span style="font-family: Courier New, Courier, monospace;">private HttpServletRequest request;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">@Before</span><br />
<span style="font-family: Courier New, Courier, monospace;">public void loginBeforeTest() throws ServletException { // throws simply in case there is a configuration issue, bad account info, already logged in etc.</span><br />
<span style="font-family: Courier New, Courier, monospace;"> request.login(username,password);</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">@After</span><br />
<span style="font-family: Courier New, Courier, monospace;">public void logoutWhenDone() throws ServletException {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> request.logout();</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
Now, when your test executes, any injection point for Principal will be filled in with the account that was logged in. This will correctly propogate to any security context as well, EJBContext, MessageDrivenContext, etc. This of course assumes that your username and password are instance variables within the class, or static references that can be found (I have found that the static reference approach works best for handling client and server tests in arquillian).John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-23986817714980000162013-07-16T10:15:00.002-07:002013-07-16T10:16:57.188-07:00Just an idea - programmatic registration of MDBsJust an idea - programmatic registration of MDBs<br />
<br />
So, I'm throwing an idea out there, soliciting feedback. Why can't MDBs be programmatically registered in the container?<br />
<br />
My idea is that an MDB can be a CDI object (rather than an EJB object),<br />
<br />
I have a simple GitHub project around this idea here, if you want to check it out (still need to maven-ize it): <a href="https://github.com/johnament/jms-mdb-config">https://github.com/johnament/jms-mdb-config</a><br />
<br />
The first thing to point out is that MDBs are the main way to support message processing in JMS in a Java EE application server. It's not possible to setup a message listener due to the container restriction around unmanaged threads.<br />
<br />
The idea is to generally provide MDB support programmatically. This is something very useful from both a framework standpoint and an application developer standpoint. This allows cleaner support for lambda expressions, as well as give a way to dynamically bind MDBs based on runtime settings. It allows you to on the fly change your bindings (of course, this is assuming that support can be added for it).<br />
<br />
In the late days of Java EE 7, a change to MDBs was introduced to allow an MDB to be bound at a method level of an object. While this is a great feature, it still doesn't tackle what I think most people need from an MDB - dynamic support. I'm using a PaaS example in my setup - where we need to dynamically create a queue per tenant to do work (to physically separate their data) and then register that queue when ready to a new MDB instance. <br />
<br />
There are a few things this doesn't seem to support as well. The first is pooling. No way to create many instances in the one case and the other case uses CDI rules for instantiation. I think both are OK, since we're not talking about super heavyweight objects. Though we may run into an issue if too many messages come on the thread. Realistically, I haven't handled an implementation that wasn't singleton in nature, so I think this isn't a huge loss. The second is that this doesn't give an option of doing the configuration from annotations. I think this could be solved by introducing annotations @JMSConfigurationProvider and @JMSListenerMethod, so that the container scanned these automatically on start up.<br />
<br />
Of course, these are all JMS specific annotations and interfaces. I would imagine a revised MDB spec like this would indicate that a configuration object may be polled and return a typed configuration based on what it's handling, so JMSConfiguration would be that for JMS (and if we did support other types of MDBs, they would each have their own configuration). <br />
<br />
Another thing that this helps with is in the SE world. We now have a standard interface to program against for binding of listeners. While this would be an MDB in SE, it could apply to a remote JMS connection. This could remove the need for binding MessageListeners.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-68149867401305307012013-06-15T05:46:00.000-07:002013-06-15T05:46:48.931-07:00What's new in JMS 2 - Part 2 - An Event based Message SenderOne of the pipe dreams we had in Seam3 was to be able to create a variable JMS event router that could send and receive messages as if they were simple CDI events. Why did we want this? For one, it was rather difficult to build a JMS sender. lots of objects and exception handling, not much to do with these errors. It was beneficial to support this as this gave an easy way to handle asynchronous event processing with CDI, leveraging JMS. It should be simple, but there were some stumbling blocks we ran across.<br/><br/>
<ol>
<li>CDI events used a global firing process, not a first match or best match algorithm. If you had an observer method that was as generic as:
<br/><br/>
public void handleObj(@Observes Object obj) { ... }
<br/><br/>
Then every event fired would make it to this method.
<br/><br/></li>
<li>Creating specific bindings breaks dynamic event processing.
<br/><br/>
In CDI, there are two ways to fire an event. The first is to use the Event interface, the other is to use a BeanManager.
<br/><br/>
We got close. With a fairly convoluted way we could support static binding of events to JMS messages. However, we had no way to support the additional qualifiers that may accompany a message. Let's say we had the following qualifiers on our event:
<br/><br/>
@SendTo("someQueue") @From(customer=1) @ReplyTo("someOtherQueue")
<br/><br/>
We could use the SendTo to map the message to a Destination, however the extra annotations were not able to come along for the ride. This is because CDI didn't give access to these qualifiers, so any observer method was blind to its input.
<br/><br/></li>
<li>In bound message processing breaks Java EE specification requirements. Technically, you cannot start a message listener in Java EE; you instead need to setup an MDB. You could create a message listener implementation and allow developers to extend it for custom processing, or have it mapped in ejb-jar.xml but it doesn't allow this solution to be turn key.</li>
</ol>
<br/><br/><br/><br/>
To help fix the problems introduced in 1 and 2, along came the EventMetadata object, which helps out our observer methods. This class acts like an InjectionPoint but is specific to event observers.
<br/><br/>
Issue 3 remains an issue. Thankfully, one of the late additions in Java EE 7 was support for a Resource Adapter that was more dynamic in nature. We'll have to see if something can be
<br/><br/>
Now, with CDI 1.1 and JMS 2 we can easily build this outbound message sender with just about 25 lines of code. Behold
<br/><br/>
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSzWAwqjPHTtnUYkQ4ptltMBmRF4P8QrEDhR7WFgOdG1O_14ekYVnmXKHlQzC6zYIC_8yY0NRQxMUN6HUBsB3WVNvQ1ZhcjtET5IkZJ2rNaQP0nP9YdQk3mUJiXX5wa6nmzUh88pdzfcLt/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;"> public class SendToObserver {
@Inject
private JMSContext jmsContext;
@Resource
private Context context;
public void sendViaJms(@Observes @SendTo("") Serializable obj, EventMetadata metadata) {
SendTo st = getSendTo(metadata);
try {
Destination d = (Destination) context.lookup(st.value());
jmsContext.createProducer().setProperty("qualifiers", metadata.getQualifiers()).send(d, obj);
} catch (NamingException e) {
// TODO log something here please
}
}
public SendTo getSendTo(EventMetadata metadata) {
Set<Annotation> qualifiers = metadata.getQualifiers();
for (Annotation a : qualifiers) {
if (a instanceof SendTo) {
return (SendTo) a;
}
}
return null;
}
}
</code></pre>
<br/><br/>
Assuming that we have a SendTo qualifier defined as
<br/><br/>
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSzWAwqjPHTtnUYkQ4ptltMBmRF4P8QrEDhR7WFgOdG1O_14ekYVnmXKHlQzC6zYIC_8yY0NRQxMUN6HUBsB3WVNvQ1ZhcjtET5IkZJ2rNaQP0nP9YdQk3mUJiXX5wa6nmzUh88pdzfcLt/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;"> @Qualifier
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
public @interface SendTo {
@Nonbinding String value();
}
</code></pre>
<br/><br/>
So what happens in this observer? Simple. First, we're observing any Serializable object. So an injection point for this observer could be
<br/><br/>
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSzWAwqjPHTtnUYkQ4ptltMBmRF4P8QrEDhR7WFgOdG1O_14ekYVnmXKHlQzC6zYIC_8yY0NRQxMUN6HUBsB3WVNvQ1ZhcjtET5IkZJ2rNaQP0nP9YdQk3mUJiXX5wa6nmzUh88pdzfcLt/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;"> @Inject
@SendTo("someQueue")
@Important
private Event<Serializable> serializableEvent;
</code></pre>
<br/><br/>
Now, in CDI 1.1 the qualifiers (@SendTo("someQueue") and @Important) will be forwarded and found in the annotation set, returned in getQualifiers(). We can iterate through them to find the SendTo to identify where to send the message to. We can also take all of these qualifiers and send them as an attribute of the message; making them available for use on the receiver side. getSendTo processes the values to read in this destination.
<br/><br/>
Next, we use JMS2's JMSContext to simplify sending. Behind the scenes, this is using a JMSProducer via a builder pattern to set properties on the message and then send it to the destination. We don't need to create a message, it happens within the sender for us. The injection here can be Request scoped or Transaction scoped, whichever is appropriate here will be activated.
<br/><br/>
What was easily 1000 lines + in Seam JMS is now just about 25 lines (30 lines if you count the qualifier). This is a huge amount of code improvement. And now, sending JMS messages is really as easy as firing a CDI event.
<br/><br/>John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com2tag:blogger.com,1999:blog-6532146623144059052.post-17497730646233363002013-03-10T18:25:00.003-07:002013-03-23T07:00:18.465-07:00What's New in JMS 2 (Part 1)This post is the first of many parts around the new features of JMS 2. <br />
<br />
In this post we talk about some of the new features in the original APIs. The biggest changes here are around the AutoCloseable interface and RuntimeExceptions.<br />
<br />
Let's say we want to read some messages from a Queue, but maybe can't use an MDB or MessageListener to do the work.<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>public List<string> readMessageContent() {</string></span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>List<string> messageBodies = new ArrayList<>();</string></span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>try (Connection conn = connFactory.createConnection();</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>Session sess = conn.createSession();</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>MessageConsumer cons = sess.createConsumer(queue)) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>Message m = null;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>while ((m = cons.receiveNoWait()) != null) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if (m instanceof TextMessage) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>TextMessage tm = (TextMessage) m;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>messageBodies.add(tm.getText());</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>m.acknowledge();</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>} catch (JMSException | JMSRuntimeException e) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return messageBodies;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<br />
In our try area we can create a Connection, Session and Message Consumer in an AutoCloseable fashion. We only want TextMessages so use an if to check the type. We don't have to deal with any of the closing methods in the code and handle only the exception. We also have a new JMSRuntimeException that can be caught, or you can let it throw further into the stack.<br />
<br />
Digging through the JMS 2.0 javadocs, you'll notice a lot of use in AutoCloseable. All of the Session interfaces have it now, all of the Connection interfaces as well. All of the MessageConsumer equivalents (TopicSubscriber, QueueReceiver) and the MessageProducers (TopicPublisher, QueueSender) have it as well. The new APIs (JMSContext and related) all have it too. Whenever you create these objects in a try with resources statement they will automatically close for you when done. This is a pretty powerful feature that matches standard use cases from today.<br />
<br />
At this point, all you have to do is finish out your REST resource, and you can easily read all given messages in a single request. Here's what it looks like:<br />
<br />
<br />
@Path("/jms")<br />
@Stateless<br />
public class WhatsNewReader {<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>@Resource(mappedName = "jms/__defaultConnectionFactory")<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>private ConnectionFactory connFactory;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>@Resource(mappedName = "jms/SomeQueue")<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>private Queue queue;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>private Logger logger = Logger.getLogger(WhatsNewReader.class<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.getCanonicalName());<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>public List<string> readMessageContent() {</string><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>List<string> messageBodies = new ArrayList<>();</string><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>logger.info("Reading.");<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>try (Connection conn = connFactory.createConnection();<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>Session sess = conn.createSession();<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>MessageConsumer cons = sess.createConsumer(queue)) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>logger.info("In the try.");<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>Message m = null;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>while ((m = cons.receiveNoWait()) != null) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>logger.info("In the while.");<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (m instanceof TextMessage) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>TextMessage tm = (TextMessage) m;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>messageBodies.add(tm.getText());<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>m.acknowledge();<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>logger.info("leaving iteration.");<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>} catch (JMSException | JMSRuntimeException e) {<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return messageBodies;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>@GET<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>@Produces("text/plain")<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>public String getMessages() {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>List<string> msgs = readMessageContent();</string><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>StringBuilder sb = new StringBuilder("Hello,");<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>for (String m : msgs) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>sb.append(m).append("\n");<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return sb.toString();<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
}<br />
<br />
Note that I have to use mappedName in my resources. As far as I can remember, mappedName is supposed to be the product specific JNDI, however I was not able to use name to look these up. Hopefully this gets corrected in a latest GF4 Build.<br />
<br />
<br />
<br />
You can pull the code from this example, and the next few, from here on my github account: <a href="https://github.com/johnament/whats-new-jms2">https://github.com/johnament/whats-new-jms2</a><br />
<br />
Edit:<br />
<br />
- Fixed JNDI look up issue/at least it's working in b80/b81<br />
- Fixed my typo of receive vs receiveNoWait.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com1tag:blogger.com,1999:blog-6532146623144059052.post-26146283933600180362013-01-20T17:10:00.000-08:002013-01-20T17:10:07.745-08:00The book has a cover imageGood news everyone!<br />
<br />
I now have a cover image selected for the book, Arquillian Testing Guide. It's going to be the 1964 World's Fair, home of the climactic battle from Men In Black.<br />
<br />
Going with the photographer next weekend to take the pictures. One step closer to getting a pre-order up.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-9878816741210992152013-01-13T07:01:00.001-08:002013-04-26T04:34:50.647-07:00And then I wrote a bookI started writing a similar blog post to this around New Year's but after reading it a few times it didn't quite convey what I was hoping for.<br />
<br />
If you've been living under a rock, I wrote a book. Yes, I can finally say I <b>wrote</b> it. First draft is completely in the publisher's hands and reviews going on. So far I've done one chapter's final draft but have plenty more to do over the next six weeks or so. Hopefully nothing major comes up.<br />
<br />
The book's subject is <a href="http://www.arquillian.org/" target="_blank">Arquillian</a>, the leading deployment automation and extension framework for java testing. It pushed me to learn more about the tools and even question what I knew about how they worked. Overall, I think readers who are new to Arquillian or even automated testing will find it very useful. It's being published by Packt, and it fits into their "Getting Started" area of books so it's not meant for more advanced users, but generally novices.<br />
<br />
One thing I should point out is that I am being paid to write the book. If you're not aware, I lost my mother about seven years ago to pancreatic cancer. The <a href="http://www.path.jhu.edu/pancreas/" target="_blank">Pancreas Multidisciplinary Cancer Team at Johns Hopkins</a> takes donations so I've decided to donate a portion of the proceeds in my mother's name to the team.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-31624040580738350422012-11-20T19:44:00.000-08:002012-11-20T19:44:00.489-08:00LinkedIn UpdatesWell, if it's not already known, I recently left Burlington Coat Factory and joined the team at Sparta Systems. The most curious thing to note is the influx of LinkedIn views, connection requests and overall traffic. I'm used recruiters pinging me occasionally on LinkedIn saying, roughly, "OMG I have the greatest job for you ever email me for details." Then you email them and receive back jobs all over the state/rough conditions. Worst yet, you do end up interviewing with these people and they can be completely disorganized to the point where the job is clearly too painful.<br />
<br />
I will say I found LinkedIn to be a very useful tool during my job search. I was able to research the people I was interviewing with before hand, what companies they came from and how they were related previously. Also gave me a good idea about what they may be looking for in a new recruit. Made a world of difference.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-23886186641566112352012-08-26T07:43:00.002-07:002012-08-26T07:43:35.824-07:00Arquillian, WebLogic with a HIbernate Enabled WebAppFor some upcoming work related applications, I decided to give a try to Arquillian and WebLogic. Our constraint though was to ensure that we're using Hibernate, since we get very odd results when using EclipseLink in our WebLogic apps.<br />
<br />
We're targetting WebLogic 12c for new applications, which ships with tools like SLF4J, Weld in our app server. Lots of libraries are already loaded in your application as a result:<br />
<br />
- SLF4J<br />
- Javassist<br />
- Jersey<br />
- Jackson/Jettison<br />
<br />
As a result of all of these libraries being available, you can get some very unexpected results trying to drop Hibernate in to your application. In my case I was using it as a JPA implementation. This is what my persistence.xml looks like as a result:<br />
<br />
<table cellpadding="0" cellspacing="0" class="lines" style="border-collapse: collapse; border-spacing: 0px; border: 0px; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font: inherit; line-height: 1.4; margin: 0px; padding: 0px; text-align: start;"><tbody style="border: 0px; margin: 0px; padding: 0px;">
<tr style="border: 0px; margin: 0px; padding: 0px;"><td style="border: 0px; margin: 0px; padding: 0px;"><pre class="line_numbers" style="background-color: #ececec; border-right-color: rgb(221, 221, 221); border-right-style: solid; border-width: 0px 1px 0px 0px; color: #aaaaaa; cursor: pointer; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; padding: 10px 6px; text-align: right;"><span id="L1" rel="#L1" style="border: 0px; margin: 0px; padding: 0px;">1</span>
<span id="L2" rel="#L2" style="border: 0px; margin: 0px; padding: 0px;">2</span>
<span id="L3" rel="#L3" style="border: 0px; margin: 0px; padding: 0px;">3</span>
<span id="L4" rel="#L4" style="border: 0px; margin: 0px; padding: 0px;">4</span>
<span id="L5" rel="#L5" style="border: 0px; margin: 0px; padding: 0px;">5</span>
<span id="L6" rel="#L6" style="border: 0px; margin: 0px; padding: 0px;">6</span>
<span id="L7" rel="#L7" style="border: 0px; margin: 0px; padding: 0px;">7</span>
<span id="L8" rel="#L8" style="border: 0px; margin: 0px; padding: 0px;">8</span>
<span id="L9" rel="#L9" style="border: 0px; margin: 0px; padding: 0px;">9</span>
<span id="L10" rel="#L10" style="border: 0px; margin: 0px; padding: 0px;">10</span>
<span id="L11" rel="#L11" style="border: 0px; margin: 0px; padding: 0px;">11</span>
<span id="L12" rel="#L12" style="border: 0px; margin: 0px; padding: 0px;">12</span>
<span id="L13" rel="#L13" style="border: 0px; margin: 0px; padding: 0px;">13</span>
<span id="L14" rel="#L14" style="border: 0px; margin: 0px; padding: 0px;">14</span>
</pre>
</td><td style="border: 0px; margin: 0px; padding: 0px;" width="100%"><div class="highlight" style="background-color: white; background-position: initial initial; background-repeat: initial initial; border: none; margin: 0px; padding: 0px;">
<pre style="border: 0px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; padding: 0px;"><div class="line" id="LC1" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><persistence span="span"> <span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">xmlns=</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"http://java.sun.com/xml/ns/persistence"</span></persistence></span></div>
<div class="line" id="LC2" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">xmlns:xsi=</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"http://www.w3.org/2001/XMLSchema-instance"</span></div>
<div class="line" id="LC3" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">xsi:schemaLocation=</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"</span></div>
<div class="line" id="LC4" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">version=</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"2.0"</span><span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;">></span></div>
<div class="line" id="LC5" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><persistence -unit="-unit" span="span"> <span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">name=</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"LOCALAPPS"</span><span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;">></span></persistence></span></div>
<div class="line" id="LC6" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><provider></provider></span>org.hibernate.ejb.HibernatePersistence<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
</pre>
</div>
</td></tr>
</tbody></table>
<br />
<div class="line" id="LC7" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><jta -data-source="-data-source"></jta></span>jdbc/LocalApps<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC8" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><properties></properties></span></div>
<div class="line" id="LC9" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><property span="span"> <span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">name=</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"hibernate.hbm2ddl.auto"</span> <span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">value=</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"update"</span><span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;">/></span></property></span></div>
<div class="line" id="LC10" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><property span="span"> <span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">name=</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"hibernate.transaction.jta.platform"</span></property></span></div>
<div class="line" id="LC11" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">value=</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"org.hibernate.service.jta.platform.internal.WeblogicJtaPlatform"</span> <span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;">/></span></div>
<div class="line" id="LC12" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC13" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC14" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<br />
In this scenario, I was using a MySQL database, where the connection was available as jdbc/LocalApps. You can see on line 6 that I have set my JPA provider to Hibernate. I ensured that Hibernate was in my project using the following dependency:<br />
<br />
<br />
<pre style="border: 0px; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 16px; padding: 0px;"><div class="line" id="LC42" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><dependency></dependency></span></div>
<div class="line" id="LC43" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><groupid></groupid></span>org.hibernate<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
</pre>
<div class="line" id="LC44" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><artifactid></artifactid></span>hibernate-entitymanager<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC45" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><version></version></span>4.1.5.SP1<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC46" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><exclusions></exclusions></span></div>
<div class="line" id="LC47" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><exclusion></exclusion></span></div>
<div class="line" id="LC48" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><artifactid></artifactid></span>javassist<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC49" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><groupid></groupid></span>org.javassist<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC50" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC51" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC52" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC52" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><br /></span></div>
<div class="line" id="LC52" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><br /></span></div>
<br />
<br />
I had to remove javassist from Hibernate's dependency since it will conflict with Weld. If you don't, you will receive deployment failures. The javassist version deployed with WebLogic is binary compatible with Hibernate 4.1.5.SP1. If you do not make this change, CDI injection will not work with your application.<br />
<br />
Next up, we have to deal with an AST/ANTLR issue. Hibernate uses AST for query object reading. When you create a query "select p from Person p" it uses AST to read these tokens. WebLogic's version is not binary compatible, so you cannot simply exclude the library. You have to include it in your application. In order to allow WebLogic core and your application to operate, you'll need the following weblogic.xml in your WAR file<br />
<br />
<table cellpadding="0" cellspacing="0" class="lines" style="border-collapse: collapse; border-spacing: 0px; border: 0px; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font: inherit; line-height: 1.4; margin: 0px; padding: 0px; text-align: start;"><tbody style="border: 0px; margin: 0px; padding: 0px;">
<tr style="border: 0px; margin: 0px; padding: 0px;"><td style="border: 0px; margin: 0px; padding: 0px;"><pre class="line_numbers" style="background-color: #ececec; border-right-color: rgb(221, 221, 221); border-right-style: solid; border-width: 0px 1px 0px 0px; color: #aaaaaa; cursor: pointer; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; padding: 10px 6px; text-align: right;"><span id="L1" rel="#L1" style="border: 0px; margin: 0px; padding: 0px;">1</span>
<span id="L2" rel="#L2" style="border: 0px; margin: 0px; padding: 0px;">2</span>
<span id="L3" rel="#L3" style="border: 0px; margin: 0px; padding: 0px;">3</span>
<span id="L4" rel="#L4" style="border: 0px; margin: 0px; padding: 0px;">4</span>
<span id="L5" rel="#L5" style="border: 0px; margin: 0px; padding: 0px;">5</span>
</pre>
</td><td style="border: 0px; margin: 0px; padding: 0px;" width="100%"><div class="highlight" style="background-color: white; background-position: initial initial; background-repeat: initial initial; border: none; margin: 0px; padding: 0px;">
<pre style="border: 0px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; padding: 0px;"><div class="line" id="LC1" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><weblogic -web-app="-web-app"></weblogic></span></div>
<div class="line" id="LC2" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><container -descriptor="-descriptor"></container></span></div>
<div class="line" id="LC3" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><prefer -web-inf-classes="-web-inf-classes"></prefer></span>true<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
</pre>
</div>
</td></tr>
</tbody></table>
<div class="line" id="LC4" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC5" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<br />
Now you should be able to deploy your Hibernate Web App on WebLogic 12c. Now if you're like me, you want to start testing this application. You'll want to define the following Deployment method in yoru arquillian test case<br />
<br />
<br />
<pre style="border: 0px; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 16px; padding: 0px;"><div class="line" id="LC26" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="n" style="border: 0px; margin: 0px; padding: 0px;">File</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">[]</span> <span class="n" style="border: 0px; margin: 0px; padding: 0px;">libs</span> <span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">=</span> <span class="n" style="border: 0px; margin: 0px; padding: 0px;">DependencyResolvers</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">use</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">(</span><span class="n" style="border: 0px; margin: 0px; padding: 0px;">MavenDependencyResolver</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">class</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">)</span></div>
<div class="line" id="LC27" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">loadEffectivePom</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">(</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"pom.xml"</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">)</span></div>
<div class="line" id="LC28" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">importAllDependencies</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">()</span></div>
<div class="line" id="LC29" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">resolveAsFiles</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">();</span></div>
<div class="line" id="LC30" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="n" style="border: 0px; margin: 0px; padding: 0px;">WebArchive</span> <span class="n" style="border: 0px; margin: 0px; padding: 0px;">wa</span> <span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">=</span> <span class="n" style="border: 0px; margin: 0px; padding: 0px;">ShrinkWrap</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">create</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">(</span><span class="n" style="border: 0px; margin: 0px; padding: 0px;">WebArchive</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">class</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">,</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"foo.war"</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">)</span></div>
<div class="line" id="LC31" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">addClasses</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">(</span><span class="n" style="border: 0px; margin: 0px; padding: 0px;">BasicEntity</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">class</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">,</span><span class="n" style="border: 0px; margin: 0px; padding: 0px;">BasicEntityDAO</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">class</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">)</span></div>
<div class="line" id="LC32" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">addAsLibraries</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">(</span><span class="n" style="border: 0px; margin: 0px; padding: 0px;">libs</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">)</span></div>
<div class="line" id="LC33" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">addAsWebInfResource</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">(</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"web/weblogic.xml"</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">,</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"weblogic.xml"</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">)</span></div>
<div class="line" id="LC34" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">addAsWebInfResource</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">(</span><span class="n" style="border: 0px; margin: 0px; padding: 0px;">EmptyAsset</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">INSTANCE</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">,</span> <span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"beans.xml"</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">)</span></div>
<div class="line" id="LC35" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">.</span><span class="na" style="border: 0px; color: teal; margin: 0px; padding: 0px;">addAsResource</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">(</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"META-INF/persistence.xml"</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">,</span><span class="s" style="border: 0px; color: #dd1144; margin: 0px; padding: 0px;">"META-INF/persistence.xml"</span><span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">)</span></div>
<div class="line" id="LC36" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="o" style="border: 0px; font-weight: bold; margin: 0px; padding: 0px;">;</span></div>
</pre>
<br />
<br />
The first four lines tell ShrinkWrap to gather all dependencies in the pom file - this will include hibernate as well. Similar to what we have to do to build the real deployment, we need to add a few extra items. We'll need the weblogic.xml used to deploy the application, as well as the persistence.xml. Note that you must use addAsResource and include the file location. In order to ease my testing, I added the following to my build section of the pom file:<br />
<br />
<br />
<pre style="border: 0px; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 16px; padding: 0px;"><div class="line" id="LC76" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><build></build></span></div>
<div class="line" id="LC77" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><testresources></testresources></span></div>
<div class="line" id="LC78" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><testresource></testresource></span></div>
<div class="line" id="LC79" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><directory></directory></span>src/test/resources<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
</pre>
<div class="line" id="LC80" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC81" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><testresource></testresource></span></div>
<div class="line" id="LC82" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><directory></directory></span>src/main/resources<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC83" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC84" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><testresource></testresource></span></div>
<div class="line" id="LC85" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><directory></directory></span>src/main/webapp/WEB-INF<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC86" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"><targetpath></targetpath></span>web<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC87" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC88" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<span class="nt" style="border: 0px; color: navy; margin: 0px; padding: 0px;"></span></div>
<div class="line" id="LC88" style="border: 0px; margin: 0px; padding: 0px 0px 0px 10px;">
<br /></div>
<br />
This will add these locations to your test classpath. This should simplify gathering files. This could also be used if you are working with ArquillianDrone to test your web app. Hopefully with these tips, you can simplify any pains when using Arquillian and WebLogic.<br />
<br />
The source code for this tutorial can be found here: <a href="https://github.com/johnament/tad-arquillian-weblogic-hibernate">https://github.com/johnament/tad-arquillian-weblogic-hibernate</a><br />
<br />
Happy Testing!John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-7207017043159461792011-06-04T06:29:00.000-07:002011-06-04T06:52:56.753-07:00Seam JMS 3.0.0.Beta2 is now out!Finally, Beta2 of the Seam JMS project is now available. This is mostly a minor improvement release:<br /><br />1. Support for TopicBuilders and QueueBuilders, simple interfaces for sending and receiving messages with JMS. To use one, just inject a reference:<br /><br />@Inject QueueBuilder queueBuilder;<br /><br />Then, choose destinations and send messages:<br /><br />queueBuilder.destination("jms/SomeQueue").send("This is my text");<br /><br />No need for complicated objects or anything. In addition, the TopicBuilder supports Subtopics. Subtopics are based around message selectors, using a String property sm_jms_subtopic.<br /><br />2. Changes in the mapping APIs. Instead of using @Routing(RouteType.INGRESS) or @Routing(RouteType.EGRESS) you can simply use @Inbound and @Outbound. I figure this will be easier to read and remember.<br /><br />3. Some big documentation clean ups occurred, and I'm still working on some more.<br /><br />Visit the module homepage here: http://sfwk.org/Seam3/JMSModule<br />Grab the download here: http://sourceforge.net/projects/jboss/files/Seam/JMS<br /><br />Visit the Seam Community Forums with any questions, comments or issues!John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-29663814376833738502011-04-17T05:20:00.000-07:002011-04-17T05:44:10.564-07:00Running CDI Source on JBoss AS 6For those unaware, last month an initiative called <a href="http://rick-hightower.blogspot.com/2011/03/announcing-cdi-source.html">CDI Source</a> was announced by Rick Hightower. It looks like their goals are pretty similar to <a href="http://www.sfwk.org">Seam</a>, a tool I've been using for a few years now; and most recently started actually contributing to!<br /><br />I was curious yesterday (mostly because it was pouring here all day) to see what had come of it, and happened to notice they were first tackling CDI & Spring interoperability. Not a bad move I thought, Spring already has all of the add-ons you would be looking for (arguably too many), so being able to bring that in to a CDI enabled application makes a lot of sense. I would still argue that Spring really needs to be able to delegate down to an underlying CDI implementation in these cases, mostly for performance reasons.<br /><br />I decided to clone their repositories. They have two currently, one is their underlying beancontainer and another for examples (they also host a resin plugin for maven, but out of scope..). When I cloned and started digging in to it, I found some things that were cool (tests worked out of the box) and some things I didn't like (platform dependence). I built the main project, no issue. I built the example spring app, had an issue there - tests didn't run. So I rebuilt without tests, generated a WAR file. I then tried to deploy it to JBoss AS 6. No luck, talk about nearly killing a VM. I deployed to a stopped JBoss instance, and attempted to start up, received a lot of classloader based errors (missing XAManager, base classloader setup wrong, etc). Never fun, though reminded me of the issues I have in Seam JMS :-)<br /><br />When I dug into the code, I found a few problems. The biggest I saw was due to all of the extra dependencies that Spring pulls in, deployment to a full application server (as it always used to be) was going to be a challenge. I tried marking dependencies as provided, but no luck. Still were being pulled in for some reason. So I decided to pull out the pre-maven rule book and ripping out libraries under WEB-INF/lib. I was able to string the list down to these:<br /><br /><ul><li>aopalliance-1.0.jar</li><li>aspectjrt-1.6.11.M2.jar</li><li>aspectjweaver-1.6.11.M2.jar</li><li>beancontainer-api-1.0-SNAPSHOT.jar</li><li>commons-beanutils-1.8.0.jar</li><li>commons-collections-3.1.jar</li><li>commons-dbcp-1.3.jar</li><li>commons-digester-2.0.jar</li><li>commons-fileupload-1.2.1.jar</li><li>commons-pool-1.5.4.jar</li><li>dom4j-1.6.1.jar</li><li>flexjson-2.1.jar</li><li>jcl-over-slf4j-1.6.1.jar</li><li>joda-time-1.6.jar</li><li>slf4j-api-1.6.1.jar</li><li>slf4j-log4j12-1.6.1.jar</li><li>spring-aop-3.0.5.RELEASE.jar</li><li>spring-asm-3.0.5.RELEASE.jar</li><li>spring-aspects-3.0.5.RELEASE.jar</li><li>spring-beans-3.0.5.RELEASE.jar</li><li>springbridge-1.0-SNAPSHOT.jar</li><li>spring-context-3.0.5.RELEASE.jar</li><li>spring-context-support-3.0.5.RELEASE.jar</li><li>spring-core-3.0.5.RELEASE.jar</li><li>spring-expression-3.0.5.RELEASE.jar</li><li>spring-jdbc-3.0.5.RELEASE.jar</li><li>spring-js-resources-2.2.1.RELEASE.jar</li><li>spring-orm-3.0.5.RELEASE.jar</li><li>spring-tx-3.0.5.RELEASE.jar</li><li>spring-web-3.0.5.RELEASE.jar</li><li>spring-webmvc-3.0.5.RELEASE.jar</li><li>tiles-api-2.2.1.jar</li><li>tiles-core-2.2.1.jar</li><li>tiles-jsp-2.2.1.jar</li><li>tiles-servlet-2.2.1.jar</li><li>tiles-template-2.2.1.jar</li></ul>Yep, had to shrink it down to 36 libraries. Still a lot of libraries in place. Attempting to deploy this resulted in some Weld errors, resolving around injection targets. I figured they were incorrectly creating injection targets in the code, and confirmed that in their SpringIntegrationExtention class, they were making beans that were also injection targets, for some reason. When I removed this code, the application deployed fine. I still can't run the application correctly due to a tiles error (<a href="http://pastebin.com/2cew9QfL">see here</a>) but at least it deploys fine now.<br /><br />As of this morning, I saw that Rick had also been working on it, and made essentially the same change I did to the code to make it work with Weld.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com2tag:blogger.com,1999:blog-6532146623144059052.post-67341943444555031132011-04-05T17:44:00.000-07:002011-04-05T17:46:37.307-07:00Seam JMS 3.0.0.Beta1 is now availableI am ecstatic to announce the release of Seam JMS 3.0.0.Beta1 to the wild. This is the first release of the module intended for deployment on JBoss AS 6. With this release we have added support for both egress (outbound to a JMS Queue/Topic) and ingress (inbound from a JMS Queue/Topic) event routes. We also provide a simplified messaging API for use within applications.<br /><br />Downloads<br /><br />The Seam JMS 3.0.0.Beta1 package can be downloaded at <a href="http://sourceforge.net/projects/jboss/files/Seam/JMS">http://sourceforge.net/projects/jboss/files/Seam/JMS</a><br /><br />Documentation<br /><br />You can find our <a href="http://docs.jboss.org/seam/3/jms/3.0.0.Beta1/reference/en-US/html_single/">Reference Guide</a> as well as <a href="http://docs.jboss.org/seam/3/jms/3.0.0.Beta1/api/">API Docs</a><br /><br />Maven Users<br /><br />The easiest way to get started in a maven project is to include the following dependency in your project. You'll need to make sure you have a repository reference to the <a href="http://repository.jboss.org/nexus/content/groups/public">JBoss Community Repository</a>.<br /><br /><code><br /><dependency><br /> <groupid>org.jboss.seam.jms</groupid><br /> <artifactid>seam-jms</artifactid><br /> <version>3.0.0.Beta1</version><br /></dependency><br /></code><br /><br />APIs<br /><br />The core API for the module is around the <a href="http://docs.jboss.org/seam/3/jms/3.0.0.Beta1/api/index.html?org/jboss/seam/jms/MessageManager.html">MessageManager</a> interface. This provides a series of convenient methods<br /><br />Deployment Capabilities<br /><br />You can also statically define routes within your application, both ingress and egress. You can define interfaces defining routes. Further details can be read <a href="http://docs.jboss.org/seam/3/jms/latest/reference/en-US/html/routing.html#routing.bridge">in the Reference Guide</a>.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-41259751626560013932010-07-18T05:08:00.001-07:002010-07-18T05:17:26.183-07:00Outsource Source ControlIt's been a while blog, but I have something on my mind that I need to get out there.<br /><br />As some may know, my company still uses SCCS for source control. More over, they included a home grown wrapper around it to make source control SOX compliant. What? Why is source control a SOX compliance issue? For binary files, you don't even want to know (and we're big on discoverer reports).<br /><br />Anyways, my group is allowed to use CVS, as SCCS cannot control Java (I swear this is what I was told). I hate it. I come from ClearCase and Subversion in my background. ClearCase had a lot of awesome features, but probably overkill for small shops. Subversion, to me it had very few features, but it worked.<br /><br />Personally, I love the distributed model. The problem we have at work is that everyone can get on to test machines, and they will only host source code on test machines. I want a central server where no one else can get to the code. I've thought about outsourcing the source control, but I'm worried about externals getting the code. Anyone know if the hosters provide NDAs and private/secure repositories?John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0tag:blogger.com,1999:blog-6532146623144059052.post-28815975497446500442010-03-20T08:41:00.000-07:002010-03-20T09:14:06.198-07:00Dyanmic ResourceBundles in CDISo I consider this blog post more of a"Part 2" from my last blog post.<br /><br />If you're anything like me, you like using ResourceBundles but find them to be an annoyance when it comes to using the same bundle in both your view and actions. I'm attempting to, with this blog post, make that a lot simpler for you.<br /><br />What are resource bundles? java.util.ResourceBundle is an abstract class in Java SE that is Locale aware. It's an easy way to add i18n support in your application. You can use it to load "bundles" either programatically or from a properties file. In this example, I will provide you with some code that loads the bundle from a properties file, have an optional annotation that can specify what bundle and what locale, as well as code that dynamically looks up Locales.<br /><br />Just like last time, we'll need to have a Producer method. In this example, the annotation is optional (as we assume that this code can handle the injection of any instance of java.util.ResourceBundle) and there will be an optional secondary producer for the Locale itself.<br /><br />So first, the first draft of the Producer method:<br /><br /><br /><code><pre><br /> @Produces<br /> public ResourceBundle produceResourceBundle(InjectionPoint ip) {<br /> Class container = ip.getMember().getDeclaringClass();<br /> String baseName = container.getCanonicalName().replace(".","/");<br /> Locale locale = Locale.getDefault();<br /> return ResourceBundle.getBundle(baseName, locale);<br /> }<br /></pre></code><br /><br />Now, clearly this producer doesn't work that well, but it's a start. Using this, you can use <code>@Inject ResourceBundle bundle</code>; which if it is placed inside of a class com.tad.cdi.comps.Bundler, will look for a bundle with the same name; com/tad/cdi/comps/Bundler. Good so far, right?<br /><br />Now I'm going to introduce the optional qualifier, @Bundle. Using @Bundle, you can specify a runtime dependency on either a different ResourceBundle (then the one being injected into) or a different locale.<br /><br />Bundle.java:<br /><pre><code><br />@Retention(RUNTIME)<br />@Target({METHOD, FIELD, PARAMETER, TYPE})<br />public @interface Bundle {<br /> public String baseName() default "";<br /> public String locale() default "";<br />}<br /></code></pre><br /><br />The Producer method to support this grows a bit, as we now support @Bundle, @Bundle(baseName="") @Bundle(locale="") and @Bundle(baseName="",locale="") so we have to add this logic to the producer.<br /><br /><em>A note for those not familiar with them</em>: Locales, in string format, take the shape of language_Country_qualifier, so you can write something as simple as "en", "sp_US", or even "fr_CA_with.napoleon.dialect" as your Bundle.<br /><br />An appropriate producer method would look something like this:<br /><br /><pre><code><br /> @Produces<br /> public ResourceBundle produceResourceBundle(InjectionPoint ip) {<br /> Bundle b = null;<br /> if (ip.getAnnotated().isAnnotationPresent(Bundle.class)) {<br /> b = ip.getAnnotated().getAnnotation(Bundle.class);<br /> }<br /> Class container = ip.getMember().getDeclaringClass();<br /> String baseName = (b == null || b.baseName().equals("")) ? container.getCanonicalName() : b.baseName();<br /> Locale locale = null;<br /> if (b == null) {<br /> locale = Locale.getDefault();<br /> } else if (b.locale().equals("") || b.locale().equals("default")) {<br /> locale = Locale.getDefault();<br /> } else {<br /> String[] lpieces = b.locale().split("_", 3);<br /> switch (lpieces.length) {<br /> case 0:<br /> locale = Locale.getDefault();<br /> break;<br /> case 1:<br /> locale = new Locale(lpieces[0]);<br /> break;<br /> case 2:<br /> locale = new Locale(lpieces[0], lpieces[1]);<br /> break;<br /> case 3:<br /> locale = new Locale(lpieces[0], lpieces[1], lpieces[2]);<br /> break;<br /> default:<br /> locale = Locale.getDefault();<br /> break;<br /> }<br /> }<br /> baseName = baseName.replace(".", "/");<br /> return ResourceBundle.getBundle(baseName, locale);<br /> }<br /></code></pre><br /><br />What we're doing with this code, we allow a a baseName to be specified in the @Bundle, this can take the form of "some.dotted.expression" or even "some/path/expression," meaning the bundle can be anywhere - doesn't need to be one dedicated to this class. Note that the behavior of @Bundle if no baseName is found is to use the enclosing class. Locale works similarly as well, you can specify locale="some_locale_expression" to load the locale, or leave it blank to load the default locale.<br /><br />Still, this may not do everything that you need. If you're like me, you have some object that contains the locale of the current HTTP Session/User. And it may look something like this:<br /><br /><pre><code><br />@SessionScoped<br />public class User {<br /> ...<br /> public Locale getUsersLocale() { return myLocale; }<br /> ...<br />}<br /></code></pre><br /><br />Well, if you've already gotten that part, then you're almost done. Using the BeanManager interface in CDI, you can actually dynamically load this Locale using BeanManager.getReference. First thing you need to do is add a Producer equivalent to the above method. Preferably, since User is already a SessionScoped CDI ManagedBean, the producer will go into the same method. Now, you do need to remember to handle the rules of CDI Producers - can't return null. So here's how to add the necessary logic to produce the Locale:<br /><br /><pre><code><br />@SessionScoped<br />public class User {<br /> ...<br /> public Locale getUsersLocale() { return myLocale; }<br /> @Produces public Locale produceSessionUsersLocale() { return myLocale; }<br /> ...<br />}<br /></code></pre><br /><br />What this now does is produce a Dependent Locale into your context. You can then modify your ResourceBundle producer in the following way; note that I have added logic that works even if this producer is absent, based on the previous steps.<br /><br /><pre><code><br /> @Inject<br /> BeanManager beanManager;<br /><br /> @Produces<br /> public ResourceBundle produceResourceBundle(InjectionPoint ip) {<br /> Bundle b = null;<br /> if (ip.getAnnotated().isAnnotationPresent(Bundle.class)) {<br /> b = ip.getAnnotated().getAnnotation(Bundle.class);<br /> }<br /> Class container = ip.getMember().getDeclaringClass();<br /> String baseName = (b == null || b.baseName().equals("")) ? container.getCanonicalName() : b.baseName();<br /> Locale locale = null;<br /> try {<br /> Bean localeBean = (Bean) beanManager.getBeans(Locale.class).iterator().next();<br /> CreationalContext cc = beanManager.createCreationalContext(localeBean);<br /> Locale producedLocale = (Locale) beanManager.getReference(localeBean, Locale.class, cc);<br /> locale = producedLocale;<br /> } catch (Exception e) {<br /> //not sure what to do here yet.<br /> System.out.println("Caught an exception trying to load a ResourceBundle");<br /> if (b == null) {<br /> locale = Locale.getDefault();<br /> } else if (b.locale().equals("") || b.locale().equals("default")) {<br /> locale = Locale.getDefault();<br /> } else {<br /> String[] lpieces = b.locale().split("_", 3);<br /> switch (lpieces.length) {<br /> case 0:<br /> locale = Locale.getDefault();<br /> break;<br /> case 1:<br /> locale = new Locale(lpieces[0]);<br /> break;<br /> case 2:<br /> locale = new Locale(lpieces[0], lpieces[1]);<br /> break;<br /> case 3:<br /> locale = new Locale(lpieces[0], lpieces[1], lpieces[2]);<br /> break;<br /> default:<br /> locale = Locale.getDefault();<br /> break;<br /> }<br /> }<br /> }<br /> baseName = baseName.replace(".", "/");<br /> return ResourceBundle.getBundle(baseName, locale);<br /> }<br /></code></pre><br /><br />So as you can see, we are attempting to lookup the Locale in the current context. If we find one, we always use that Locale; otherwise we use the original logic.<br /><br />Now obviously, this guide wouldn't be too useful unless we had some Arquillian test cases.<br /><br />The code is located in the same project as the previous post, but here are the essentials.<br /><br />A test producer object, this can produce Locale as needed:<br /><br /><code><pre><br />public class LocaleProducer {<br /> @Produces<br /> public Locale produceSomeLocale() {<br /> System.out.println("Have a request for Locale English...");<br /> return Locale.ENGLISH;<br /> }<br />}<br /></pre></code><br /><br />I also wrote two tests, one that uses the Locales with and without @Bundle, another that uses the producer style.<br /><br />To verify the logic without Producing Locales:<br /><br /><code><pre><br /> @Deployment<br /> public static JavaArchive createDeployment() {<br /> return Archives.create("test.jar", JavaArchive.class)<br /> .addClass(BundleProducer.class)<br /> .addClass(Bundle.class)<br /> .addResource("com/tad/cdi/mods/properties/ResourceBundleInjectTest.properties")<br /> .addResource("com/tad/cdi/mods/properties/Special_sp.properties")<br /> .addManifestResource("META-INF/beans.xml",<br /> ArchivePaths.create("beans.xml"));<br /> }<br /><br /> @Inject ResourceBundle bundle;<br /><br /> @Inject @Bundle(baseName="com/tad/cdi/mods/properties/Special",locale="sp")<br /> ResourceBundle bundleSpecialSP;<br /><br /> @Test<br /> public void testBundleContents() {<br /> assertEquals("world",bundle.getString("hello"));<br /> }<br /><br /> @Test<br /> public void testBundleSpecified() {<br /> assertEquals("bottom",bundleSpecialSP.getString("bob"));<br /> }<br /></pre></code><br /><br />And to test including the ability to produce locales:<br /><br /><code><pre><br /> @Deployment<br /> public static JavaArchive createDeployment() {<br /> return Archives.create("test.jar", JavaArchive.class)<br /> .addClass(BundleProducer.class)<br /> .addClass(Bundle.class)<br /> .addClass(LocaleProducer.class)<br /> .addResource("com/tad/cdi/mods/properties/ProducedLocaleTest_en.properties")<br /> .addManifestResource("META-INF/beans.xml",<br /> ArchivePaths.create("beans.xml"));<br /> }<br /><br /> @Inject ResourceBundle bundle;<br /><br /> @Test<br /> public void testBundleContents() {<br /> assertEquals("world",bundle.getString("hello"));<br /> }<br /></pre></code><br /><br />So there you have it, enjoy your ResourceBundles!John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com1tag:blogger.com,1999:blog-6532146623144059052.post-81329317164406150082010-03-14T11:01:00.000-07:002010-03-14T11:37:35.341-07:00Writing a Property Loader in Java EE 6 and Testing it using ArquillianSo, like most people, I'm interested in Java EE 6, and the new CDI framework that comes with it. I see it as a huge time saver and seems to fit in well with the whole ecosystem of Java EE (not to mention, it also knocks Spring down a little, a plus in my book).<br /><br />We're beginning to adopt Java EE 6 at work. A big application has been running for a few weeks already and now we have a couple of smaller applications that are likely to run with our live site (one being a search engine). I'm not aiming this article to be an intro to Weld, CDI or Java EE 6; I would expect anyone reading this to be at least familiar with the concepts.<br /><br />Something that's big for us is testing, and allowing the application to be configurable. We definitely push the separation between development and administration and I have been ensuring that all applications match that mindset. As a result, loading property files is a typical use case for us. I was looking at how we've been doing it, and decided that it should be much simpler if we had a producer method to produce property files. Some of our files reside in the deployment archives, most on the file system; and we usually like to make it a system property to configure where to read the files from. Below is some sample code explaining how to implement a Property Loader in CDI<br /><br />First, the qualifier; it only takes one argument the value.<br /><br /><pre>@Qualifier<br />@Retention(RUNTIME)<br />@Target({METHOD, FIELD, PARAMETER, TYPE})<br />public @interface ConfiguredBy {<br />@Nonbinding public String value();<br />}</pre><br /><br />We use Nonbinding on the value so that there's only one producer necessary; since the value is essentially an argument to what we want to produce, and what it gets attached to is the Produced object. For the sake of my code, I only support producing instances of java.util.Properties.<br /><br />Here's what the Producer method looks like (and yell if you don't like my code; note that the real version would be cleaner assuming you had an injectable SLF4J Logger).<br /><br /><pre> @Produces @ConfiguredBy("")<br />/**<br />* Produces a java.util.Properties object based on the qualifier ConfiguredBy<br />* and the injection point.<br />*<br />* Behavior is as follows:<br />* - the value can be a System property or a path.<br />* - If it's a system property, we convert it to the value of that property first<br />*<br />* - Then we check to see if the value now is an absolute path or a classpath entry<br />* - We try both.<br />*/<br />public Properties produceProperties(InjectionPoint ip) {<br /> Properties p = new Properties();<br /> String value = ip.getAnnotated().getAnnotation(ConfiguredBy.class).value();<br /> System.out.println("Producing properties with value.... "+value);<br /> if(value == null || value.equals("")) {<br /> //if the given file is empty, we can't load it too well.<br /> return p;<br /> }<br /> String propValue = System.getProperty(value);<br /> if(propValue != null) {<br /> value = propValue;<br /> }<br /><br /> File f = new File(value);<br /> if(f.exists() && !f.isDirectory()) {<br /> //so it's on the file system, let's load it.<br /> try{<br /> FileInputStream fis = new FileInputStream(f);<br /> p.load(fis);<br /> } catch (IOException e) {<br /> System.out.println("Problem reading the file, ignoring.");<br /> }<br /> }<br /> //now we try to get it from the classpath, as a resource.<br /> try{<br /> InputStream is = this.getClass().getClassLoader().getResourceAsStream(value);<br /> p.load(is);<br /> } catch (Exception e) {<br /> System.out.println("Problem reading the file, ignoring.");<br /> }<br /> return p;<br />}</pre>So what this code allows us to do is attempt to load a file based on a System property, and it can exist on the file system or as a resource in the class loader.<br /><br />Now here's the fun part, how to test this using Arquillian. For those that don't know, Arquillian is a new tool from JBoss designed to help testing software in a container. As of this post, they support Glassfish V3, Weld SE, JBoss AS 5.1 and JBoss AS 6.0. It looks like they also support OpenEJB; but I'm not sure what version. I was able to run my tests on this class using the Weld SE container using JUnit. They also support TestNG; but I've historically always leaned towards JUnit.<br /><br />Here's an example of a testing class, in this case I use a System property to find the location of a file in the classpath.<br /><br />First, the maven dependencies.<br /><br /><pre><br /> <dependency><br /> <groupId>junit</groupId><br /> <artifactId>junit</artifactId><br /> <version>4.7</version><br /> <scope>test</scope><br /> </dependency><br /><br /> <dependency><br /> <groupId>org.jboss.weld</groupId><br /> <artifactId>weld-se</artifactId><br /> <version>1.0.1-Final</version><br /> </dependency><br /><br /> <dependency><br /> <groupId>org.jboss.arquillian.container</groupId><br /> <artifactId>arquillian-weld-embedded</artifactId><br /> <version>1.0.0-SNAPSHOT</version><br /> <scope>test</scope><br /> </dependency><br /><br /> <dependency><br /> <groupId>org.jboss.arquillian</groupId><br /> <artifactId>arquillian-junit</artifactId><br /> <version>1.0.0-SNAPSHOT</version><br /> <scope>test</scope><br /> </dependency><br /> </pre><br /><br />In order to test a system property, I needed to add it explicitly in the surefire plugin in maven:<br /><br /><pre><br /> <plugin><br /> <groupId>org.apache.maven.plugins</groupId><br /> <artifactId>maven-surefire-plugin</artifactId><br /> <version>2.5</version><br /> <configuration><br /> <systemPropertyVariables><br /> <propertyProducerTestSystemProperty.file>META-INF/test1.properties</propertyProducerTestSystemProperty.file><br /> </systemPropertyVariables><br /> </configuration><br /> </plugin><br /></pre><br /><br />My test1.properties file, located in src/test/resources/META-INF/, was simply:<br /><br /><pre><br />key1=value2<br />key2=value2<br />key3=something<br />key4=key4<br /></pre><br />My test case class was then very simple to write. This is all I had to do to test my producer method, create an injection point!<br /><br /><pre><br />@RunWith(Arquillian.class)<br />public class PropertyProducerTestSystemProperty {<br /><br /> @Deployment<br /> public static JavaArchive createDeployment() {<br /> return Archives.create("test.jar", JavaArchive.class)<br /> .addClass(PropertyProducer.class)<br /> .addClass(ConfiguredBy.class)<br /> .addManifestResource("META-INF/test1.properties",<br /> ArchivePaths.create("test1.properties"))<br /> .addManifestResource(<br /> "META-INF/beans.xml",<br /> ArchivePaths.create("beans.xml"));<br /> }<br /><br /> @Inject @ConfiguredBy("propertyProducerTestSystemProperty.file")<br /> Properties properties;<br /><br /> @Test<br /> public void testPropertySize() {<br /> Assert.assertEquals(4,properties.size());<br /> }<br /> @Test<br /> public void testPropertyContains() {<br /> Assert.assertFalse(properties.containsKey("search.url.base"));<br /> <br /> }<br /> @Test<br /> public void testPropertyValue() {<br /> Assert.assertEquals("something", properties.getProperty("key3"));<br /> }<br /><br />}<br /></pre><br />The createDeployment method, since it's annotated @Deployment signifies the files that will be included in the test - what the container will need to deploy. Note that there's no code in my code that has a direct dependency on how it's tested - switching from Weld SE to Glassfish is simply done in maven. Also note that they have more robush ways of testing in the examples, but it's beyond the scope of this topic.<br /><br />For each test case, the injection point will get processed and injected; and you can verify that the tests pass.<br /><br />If you want to give this a try, you can clone the source from my google code site, <a href="http://code.google.com/p/tadcdicomps/">tadcdicomps</a> and then click on the Source tab. this is the properties project under hg. To run the tests, I have a Test Suite that has multiple test classes in it, the command I ran after building was<br /><br /><blockquote>mvn test -Dtest=PropertiesTestSuite</blockquote><br />Enjoy!John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com1tag:blogger.com,1999:blog-6532146623144059052.post-90041719144460631972010-01-29T05:24:00.000-08:002010-01-29T05:30:54.463-08:00A feature that JSF needsI've noticed for some time now that there are just some things that are hokey in JSF.<br /><br />If you're like me, you almost always have your forms setup like this:<br /><br /><code> <h:outputLabel for="pvalue" value="Value"/><br /> <h:inputText value="#{propertyAction.propValue}" id="pvalue"/></code><br /><br />Now if there's a validation on this input, you need to mark the label (otherwise users get a really bizarre error message that they won't understand)<br /><br /><code> <h:outputLabel for="pvalue" value="Value"/><br /> <h:inputText value="#{propertyAction.propValue}" id="pvalue" label="Value"/></code><br /><br />And if you're using a bundle, it'll look something like this:<br /><br /><code> <h:outputLabel for="pvalue" value="${msgs['value']}"/><br /> <h:inputText value="#{propertyAction.propValue}" id="pvalue" label="${msgs['value']}"/></code><br /><br />So why can't JSF be smart enough to realize "Ok, I have an outputLabel for this input type, it has a validation error, let me use that label instead." and make the label attribute optional and can override the outputLabel in this case.John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com1tag:blogger.com,1999:blog-6532146623144059052.post-18224005583277894472010-01-03T09:52:00.001-08:002010-01-03T10:08:45.246-08:00Why does IT get ignored?So I work in the IT field, to me that means more than just programming or support, it's about building a solution with the business.<div><br /></div><div>Is it me or is the later part not happening anymore? With the adoption of SaaS or the businesses leaning towards more off the shelf products, it seems like the result is that IT not involved in a lot of the decision making and it's simply handed off and said "here, do this." There's no business analyst involved, there's no research on how to implement it or how to integrate it with existing systems. </div><div><br /></div><div>I can whole heartedly understand the business wanting to be able to do it themselves, but I'm not sure it's a good idea. We're IT because we're good at computering (computering, able to work with and understand elements in the computer realm). The business side doesn't always understand the ramifications of their needs. In the world of distributed computing, the idea that a system is standalone is nonexistent. From the basic automatic uploading of a file via FTP to web service communication, it's all related.</div><div><br /></div><div>Sometimes it seems like IT is okay with the idea that the business just goes on and operates. I think it's in part to how expenditures work. What happened to the days of IT sitting down with the business, finding what they want then plan out do we build it, outsource it, or buy it?</div>John Amenthttp://www.blogger.com/profile/11775194521384049642noreply@blogger.com0