<< April 2010 | Home | June 2010 >>

Taking Advantage of Parallelism

A while ago some colleagues attended a lecture where the presenter introduced the idea that applications may not take full advantage of the multi-core servers which are available today. The idea was that if you have two cores but a process which is running on a single thread, then all the work is done on one single core. Application servers help in this respect, because they handle multiple incoming requests simultaneously, by starting a new thread for each request. So if the server has two cores it can really handle two requests simultaneously, or if it has 6 cores, it can handle 6 requests simultanously.

So multi-core CPUs can help the performance of your server if you have multiple simultaneous requests, which is often the case when your server is running near its limit. But it's not often the case that you want your servers running close to the limit, so you typically scale out, by adding more nodes to your server cluster, which has a similar effect to adding cores to the CPU (you can continue to handle multiple requests simultaneously).

So once you have scaled up by adding more cores, and scaled out by adding more servers, how can you improve performance?

Some processes can be designed to be non-serial, especially in enterprise scenarios. The Wikipedia article on multi-core processors talks about this. Imagine a process which gathers data from multiple systems while preparing the data which it responds with. An example would be a pricing system. Imagine your local zoo offered a web service for purchasing individual tickets, say an entrance ticket, a voucher for some tasty elephant snacks for feeding time, a voucher for their shop for getting gifts before you leave, etc. Now imagine, you as an entrepreneur wanted to open a re-selling business offering packages for such products, so that you could offer a discount (greater sales volume, lower per-item profit).

A perfect way to do this would be to partner with the Zoo and offer a website which integrates with the zoo's web service and sells such packages. You implement your website, but then while doing performance tests, you notice that regardless of load, an average sales is taking 3 seconds to complete. You analyse the system and determine that its the zoo's web service which is the problem - each product quote is taking a full second to get. You talk to the zoo's IT department, and they confirm that this is known, but there is little they can do about it because in the back end they are using complex reservation systems which work out a dynamic market price which is based on supply and demand.

So, you go away and have a think, and remember that your data center has just just installed some servers with flashy new multi-core processors, which are costing you a fortune. Then it hits you! Getting a product quote is an independent task. So while getting quotes for the items in your package, you might as well do it in parallel, at the same time! Hang on now. You implemented your system in Java and the business logic is in EJBs, so there's no chance of spawning new threads, the container won't let you! Except... you implemented it on a shiny new Java EE 6 server! Hooray! Why? Because of the javax.ejb.Asynchronous annotation.

The Javadocs for this annotation state:

Used to mark a method as an asynchronous method or to designate all business methods of a class or interface as asynchronous.

So, what you do, is add this annotation to a business method of your EJB and the container runs it on a new thread. Brilliant! The only minor issue is how to get the result from your asynchronous calls, but that's relatively easy, using the Future<T> class. Consider the following method declaration:

/**
 * note that async methods implicitly start new transactions!
 * see ejb 3.1 spec, chapter 4.5.3.
 */
@Override
@Asynchronous
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public Future getOffer(Product product, UUID purchaseId) {
    .
    .

This EJB business method takes a product and purchase ID (effectively a session ID). It gets called by the container on a new thread, which implicitly means that it cannot re-use any existing transactions and must hence be run using a new transaction (see EJB specification, chapter 4.5.3). This method then calls the zoo's web service and when it gets a response, returns the response:

    return new AsyncResult(o);

where "o" is an offer - the response from the web service call. The javax.ejb.AsyncResult<T> class is the standard implentation of a Future<T>, and simply wraps the actual object you want to return.

The EJB which started the async calls knows when they have all returned, because it can check the results isDone() method. As soon as the new thread completes, the container sets this method to return true.

So, the net effect is that instead of taking three seconds to get an offer for your package of three items, it only takes one second! A whopping 300% improvement!

The async annotation in the EJB spec is a welcome extension. If also offers the ability to cancel tasks as well as handle exceptions from the async calls (via ExecutionExceptions which wrap the problem). With it however, there are some dangers, as suggested in the Wikipedia article on multi-core processors. The fact that such async methods are forced to start a new transaction can cause problems. However, this is actually an advantage, because we are calling web services! Web services are inherently non-transactional. That means they are committed as soon as you get their response, not as soon as your transaction is committed. So in order to make web services XA (two phase commit) compatible, one normally adds a "commit" method to the web service which the caller must call when all their business logic is complete, or one adds a mechanism for cancelling such transactions.

I have used the new "inner" transaction which the container starts to track the state of these offers / sales. As soon as the web service returns, I write the result to a table in the database with its status "OFFERED", so that I know I have not actually purchased it. Regardless of errors in other calls to the web service, I am guaranteed to have such an entry for each successful web service result, due to the inner transaction. After I get the three offers, the orchestration EJB which called the async bean (which calls the web services), purchases the three offers. After each purchase, I update the status in the database to "BOUGHT", also using an inner transaction (REQUIRES_NEW), so that regardless of any failures in subsequent purchases, the state of individual purchases is known. Why go to this effort? Well, I have a business rule: my packages are sold as complete packages, or not at all! So if any single purchase fails, I need to cancel my other purchases. If I don't, I still owe the zoo for what I have purchased, and I didn't get any money from my customer, because the package failed!

The solution is to use the timer service from the EJB container. I schedule a method in an EJB to analyse my offers/purchases and for any incomplete session (purchase ID), I cancel all three offers and update my records to mark the purchases as "CANCELLED".

I've put this together as a sample app which includes EJB 3.1, Servlet 3.0, Inteceptors, JPA 2.0, the EJB Timer Service, Validation (JSR-303), JMS and JAX-WS, all based on the GlassFish 3 configuration which was blogged at GlassFish 3 In 30 Minutes. The source for this mega sample app can be downloaded here.

Some final quick notes:

1) A web service, and its client cannot be deployed in the same EAR! That makes sense in normal conditions, but for a sample app, where you want your server to call a test WS, it can cause trouble. So the zoo web service is deployed as a simple web project.

2) The Javadocs for the OrchestrationBean provide some more details of the business process.

© 2010 Ant Kutschera

Social Bookmarks :  Add this post to Slashdot    Add this post to Digg    Add this post to Reddit    Add this post to Delicious    Add this post to Stumble it    Add this post to Google    Add this post to Technorati    Add this post to Bloglines    Add this post to Facebook    Add this post to Furl    Add this post to Windows Live    Add this post to Yahoo!

GlassFish v3, JSF and Virtual Servers

Anyone wanting to run a JSF app on GlassFish may run into problems when migrating to production, if they are hosting multiple domains on their servers by using virtual hosts!

The default deployment, deploys your app to all virtual servers (except _asadmin).  If you do that, you get lots of errors, and the app doesn't run.

The solution is easy, simply add the --virtualservers argument to the "deploy" command in the "asadmin" console, and supply the relevant virtual server (just the one).

Hopefully this will get fixed in GFv3.1!

Tags :
Social Bookmarks :  Add this post to Slashdot    Add this post to Digg    Add this post to Reddit    Add this post to Delicious    Add this post to Stumble it    Add this post to Google    Add this post to Technorati    Add this post to Bloglines    Add this post to Facebook    Add this post to Furl    Add this post to Windows Live    Add this post to Yahoo!

Oracles Sun Forums Are Crap

Rant Time:

I've run in with the forum moderators before, but this really winds me up. I searched on Google for "java open browser", to remind myself which API to call to open the default browser, and the number one search result was this:

    http://forums.sun.com/thread.jspa?threadID=679673

The answer is at the bottom of the page. Perfect. But then Darryl Burke comes along and locks the thread, because he reckons this latest posting is useless. Sorry, but Sun Forum Moderators don't get the concept of how forums are searched and used! They once told me they lock the threads because they want you to post new threads.  I don't have the time to make a new thread asking a question every time I can't solve something, and then wait and hope someone with the answer comes along over the next few days - I want to search for it ,and find the answer immediately. If they keep locking threads, you end up with hundereds of old locked threads which don't help anyone. What their vision is doing, is simply destroying the internet!

Idiots! And that is one reason I don't post to their forums anymore - they are the losers, not me.

Tags :
Social Bookmarks :  Add this post to Slashdot    Add this post to Digg    Add this post to Reddit    Add this post to Delicious    Add this post to Stumble it    Add this post to Google    Add this post to Technorati    Add this post to Bloglines    Add this post to Facebook    Add this post to Furl    Add this post to Windows Live    Add this post to Yahoo!

GlassFish 3 In 30 Minutes

The aim: Set up a simple Java EE 6 project on GlassFish v3 in no time at all. The project must include: email, JMS, JPA, web and EJB (session bean, message driven bean and a timer bean). It must also include security and transactions.

Sounds like a lot, but thanks to Java Enterprise Edition version 6, setting up a project like this and configuring all the resources in the Application Server are really easy! I chose GlassFish because its open source, has a useful little Admin Console and I've never developed with it before.

Before I started I downloaded Java SE 6 (update 20), Mysql Server, the Mysql JDBC Driver and the GlassFish Tools Bundle for Eclipse, which is a WTP Version of Eclipse 3.5.1 with some specific bundles for developing and deploying on GlassFish.

The process I wanted to implement was simple: a user goes to a website, clicks a link to a secure page and logs in, after which a message is persisted to the database and an asynchronous email gets sent. The user is shown a confirmation. In the background theres also a task which reads new messages from the database and updates them so they are not processed a second time.

The design was to use a servlet for calling a stateless session EJB, which persists a message using JPA and sends a JMS message to a message driven bean for asynchronous processing. The MDB sends an email. A timer EJB processes and updates any messages it finds in the database. Additionally I set a requirement to use only the newest technologies in Java EE 6, my servlet and beans were configured using annotations. The following sequence diagram shows the rough design:

click to zoom

The first challenge was to configure my resources in GlassFish. I started the preinstalled server instance which is shipped with this special Eclipse and opened the admin console at localhost (got the port number from the log console).

Without deploying any apps, I configured the following:

1) JDBC Connection Pools, which contain the connection details to the database - one for data, one for a security realm. When creating them, I used default settings apart from:

Pool for Data:

  <jdbc-connection-pool datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" res-type="javax.sql.XADataSource" name="testPool" ping="true">

    <property name="URL" value="jdbc:mysql://localhost:3306/test" />
    <property name="Url" value="jdbc:mysql://localhost:3306/test" />
    <property name="User" value="root" />
    <property name="Password" value="password" />
    .
    .
  <jdbc-connection-pool>


Pool for Security Realm:

  <jdbc-connection-pool driver-classname="com.mysql.jdbc.Driver" res-type="java.sql.Driver" name="realmPool" ping="true">
    <property name="URL" value="jdbc:mysql://localhost:3306/test?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=UTF-8" />
    <property name="password" value="password" />
    <property name="user" value="root" />
  </jdbc-connection-pool>

2) JDBC Resources, which is where you set the JNDI names for your JDBC Connection Pools.

  <jdbc-resource pool-name="testPool" jndi-name="jdbc/test" />   <jdbc-resource pool-name="realmPool" jndi-name="jdbc/realm" />

3) JMS Resource - one connection factory for sending messages, and one destination which is the queue which references a physical destination in the jms service (which gets automatically added further down in the admin console under the JMS Service).

  <admin-object-resource res-adapter="jmsra" res-type="javax.jms.Queue" description="a test queue" jndi-name="jms/destinationResource">     <property name="Name" value="test_destination" />   </admin-object-resource>   <connector-resource pool-name="jmsConnectionPool" jndi-name="jmsConnectionPool" />   <connector-connection-pool name="jmsConnectionPool" resource-adapter-name="jmsra" is-connection-validation-required="true" connection-definition-name="javax.jms.ConnectionFactory" transaction-support="XATransaction" />

4) A Javamail Session, so that my app could send email over POP3.

  <mail-resource host="localhost" store-protocol="POP3" store-protocol-class="com.sun.mail.pop3.POP3Store" jndi-name="mail/Session" from="boss@maxant.co.uk" user="boss">     <property name="mail-password" value="boss" />   </mail-resource>

5) Under Configuration / Security, I set up a JDBC realm which used the realm database connection pool which was configured above.

  <auth-realm name="database-realm" classname="com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm">     <property name="jaas-context" value="jdbcRealm" />     <property name="datasource-jndi" value="jdbc/realm" />     <property name="user-table" value="party" />     <property name="user-name-column" value="login" />     <property name="password-column" value="password" />     <property name="group-table" value="role" />     <property name="group-name-column" value="role" />     <property name="db-user" value="root" />     <property name="db-password" value="password" />     <property name="digest-algorithm" value="none" />   </auth-realm>

Here is the domain.xml file (GlassFish's main configuration file, located under either %glassfishv3_install%/glassfish/domains/domain1/config if you installed the server, or under %GlassFish-Tools-Bundle-For-Eclipse-1.2-Install&/workspace/.metadata/.plugins/com.sun.enterprise.jst.server.sunappsrv92/domain1/config if you installed the GlassFish Tools Bundle for Eclipse).

Put the Mysql J/Connector JAR into %GlassFish-Tools-Bundle-For-Eclipse-1.2-Install%/glassfishv3/glassfish/lib or %glassfishv3_install%\glassfish\lib. GlassFish already contains Mail, Activation and JMS JARs on its classpath, so there is nothing else to do here.

Using Eclipse, create a new EAR project, as well as a new web module. Once created, right click on the running server and click "add / remove". Add the new EAR so that its deployed, and once deployed, return to the admin console.

You can now set up a virtual server (host) so that you can run multiple domains using the same server (something you might realistically want to do with a prodution server). To do this, you either need to modify a DNS server so that multiple domains resolve to your IP address, or you can modify the hosts file (on windows its c:\windows\system32\drivers\etc\hosts) and add a domain. In the admin console, set up a new virtual server by refering to that domain, and setting its default application to the one you just deployed. That way, any HTTP request which comes in for that domain is sent to your web application. To enable a request like "http://testwsmaxantcouk:8084/" to be redirected to "index.jsp" in your app, you need to set the context root of the webapp to "/", in application.xml or the EAR:

  <application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd" id="Application_ID" version="5">
    <display-name>Seven
    <module>
      <web>
        <web-uri>SevenWeb.war</web-uri>
        <context-root>/</context-root>
      </web>
    </module>
  </application>

In order for this configuration to work, you need to create a database and relevant schema, which you can do using the three SQL files inside the download at the bottom of this article, to create the database, create tables for the realm and application, and insert some initial data into them.

The next step is to add your servlet. I used the eclipse wizard to add a new servlet, which generates a class into your web project with Java EE 6 annotations:

  @WebServlet(name = "SevenServlet", urlPatterns = { "/SevenServlet" })
  public class SevenServlet extends HttpServlet {
  .
  .

The servlet delegates its work to a stateless session EJB, which ensures that a transaction is started. The EJB can also be used to check security, although the servlet needs to be deployed within a security context in order to get the web container to automatically reply with a redirection to the login page, in the case where the user is not logged in. In Java EE 6, you do this also using annotations:

  @Resource(name="java:app/SevenEJB/EJBSeven")
  private EJBSevenLocal ejbLocal;

When the container finds this annotation in an servlet, it injects the EJB automatically.

The EJB is declared with some annotations and resources too:

  @DeclareRoles({Roles.REGISTERED})
  @Stateless
  @TransactionManagement(TransactionManagementType.CONTAINER)
  public class EJBSeven implements EJBSevenLocal {
  .
  .

This tells the EJB container that the EJB is stateless, uses container managed transactions and may be used by users with roles "registered". The following resources are declared:

  @Resource(mappedName = "jms/destinationResource")
  private Queue q;

  @Resource(mappedName = "jmsConnectionPool")
  private QueueConnectionFactory qcf;

  @Resource
  private SessionContext sessionContext;

  @PersistenceContext(unitName="MessageManagement")
  private EntityManager em;

These resources are a JMS connection factory, and a queue, for sending the asynchronous message. The session context is the EJBs session context which allows the EJB to query users roles and rollback transactions, amongst other things. A JPA Entity Manager is also declared allowing the EJB to use the database. Finally, the business method declared in the EJB interface is implemented:

  @Override
  @RolesAllowed({Roles.REGISTERED})
  @TransactionAttribute(TransactionAttributeType.REQUIRED)
  public String execute(String command) {
  .
  .

The annotations above tell the container that the user must be in the given role in order to call this method, and that a transaction is required.

Next, the message driven bean is implemented:

  @MessageDriven(
    activationConfig = { @ActivationConfigProperty(
      propertyName = "destinationType", propertyValue = "javax.jms.Queue"
    ) },
    mappedName = "jms/destinationResource")
  public class MDBean implements MessageListener {
  .
  .

The annotations above tell the container which messages should be sent to the onMessage(Message) method of the bean. This bean too has resources, namely a mail session, for sending email:

  @Resource(name="mail/Session")
  private Session mailSession;

The timer EJB is also implemented:

  @Stateless
  @TransactionManagement(TransactionManagementType.CONTAINER)
  public class EJBTimerSeven {

    @PersistenceContext(unitName="MessageManagement")
    private EntityManager em;
  .
  .

In order for the timer bean to use the entity manager within a transactional context (so that it can for example update or insert data), it too needs a declaration that it uses container managed transactions. The method which is scheduled is defined next:

  @Schedule(second="0", minute="*/1", hour="6-23", dayOfWeek="Mon-Fri", dayOfMonth="*", month="*", year="*", info="MyTimer")
  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
  private void scheduledTimeout(final Timer t) {
.
.

Note that there is nothing in this beans definition that makes it a timer bean. Rather the method which is to be called when the schedule fires, is simply annotated. I could have just as easily added this method to the main EJB in my project. The schedule pattern is similar to scheduling a cron job in unix, and the second part to ensuring that this methods actions on the entity manager are committed is to add the TransactionAttribute annotation, in this case ensuring that a new transaction is started.

The last thing I needed was a class for JPA, to represent the table I want to write to:

  @Entity
  public class Message {

    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Id
    private int uid;

    @Column(name="sender")
    private String sender;

    @Column(name="when_sent")
    private Timestamp whenSent;
    .
    .

This classes annotations show that its a persistable entity using JPA (the @Entity annotation), that the "uid" attribute is the primary key and is generated by the database and that the other attributes map to given columns in the database. Using these very simple annotations and configuring the entity manager using the follwing simple XML, JPA is enabled and it becomes very simple to use indeed.

  <persistence>
    <persistence-unit name="MessageManagement">
      <jta-data-source>jdbc/test</jta-data-source>
      <class>uk.co.maxant.test.Message</class>
    </persistence-unit>
  </persistence>

This XML file is saved as "persistence.xml" and dropped into the META-INF folder of the EJB project.

So, setting up a Java EE 6 enterprise application is really simple! Here are some comments...

Remember that when calling services (EJBs) from your web layer (servlets or in JSF backing beans), that you should always call a façade whose job is to ensure that a transaction is started. In fact, you may have noticed that the realm JDBC resource was configured as a simple SQL Driver, whereas the JDBC resource for the application was set up as an XA Data Source. What's the difference? Well within the application we used JMS and the application database in the same business method of our EJB, which was run within a transaction. To ensure that either both resources were committed together, or neither, you MUST use XA. The JMS connection factory has a flag on it to say that it should be XA-enabled. The application which you can download at the end of this article contains a hyperlink for starting the process described at the top of the article, as well as another hyperlink for starting it with an error. Any errors that occur in your business logic, before the container attempts to commit resources, are not affected by XA. Rather, XA helps if one of the resources cannot commit, say due to a data constaint defined in the database. That means that if the container had sent the JMS message and then attempted to write data to the database and discovered the data was not valid, it would not commit the sending of the JMS message, so neither resource gets commited! It is important to understand the subtle differences in where the errors occur, in order to see the benefits of XA. For more information see Wikipedia

If you get the following error after deploying the EAR, don't worry, it's quite normal: "WEB9051: Error trying to scan the classes at .../eclipseApps/Seven/SevenEJB.jar for annotations in which a ServletContainerInitializer has expressed interest". See here.

GlassFish's log files can be found at either %glassfishv3_install%/glassfish/domains/domain1/logs if you installed the server, or under %GlassFish-Tools-Bundle-For-Eclipse-1.2-Install&/workspace/.metadata/.plugins/com.sun.enterprise.jst.server.sunappsrv92/domain1/logs if you installed the GlassFish Tools Bundle for Eclipse).

If you experience problems with the security realm, the logs don't give much information. The easiest solution is to set a breakpoint for exception com.sun.enterprise.security.auth.login.common.LoginException and when it comes up, you can debug the JDBCRealm class. You need to download the source which you can find under https://svn.dev.java.net/svn/glassfish-svn/trunk/v3/security/core (login with user "guest" and no password). More information for the JDBC realm can be found here. One other noteworthy point about realms and GlassFish is that unlike with Tomcat, you must state which realm to use for your web app. You can either do this in the sun-application.xml file, or by adding the realm-name element to your login-config element of web.xml. Both are shown in the download for this article (see bottom).

Until now, I have never used Java EE 6. I had got into the routine of using simple Spring for simple projects. But Java EE 6 is practically the same as Spring in terms of configuring services (EJBs) and adding security and transaction annotations. So I've started to ask myself what the advantage of Spring now is. Well Spring still offers simple database handling in terms of not having to worry about exceptions and being able to call Hibernate or other frameworks in a standard way, but JPA offers the same advantages. Spring also offers simplified sending of email, which Java EE 6 does not have, but this is no huge deal. One nice feature of Spring is that it includes AOP, which I have used mostly for improving on Spring Security (by simplifying it, search on this blog for more details). While Java EE 6 doesn't offer AOP out of the box, you can add it quite simply (see http://www.eclipse.org/aspectj). What's more, the security offered by Java EE is much more standard than that offered by Spring. To so summarise, it's getting hard to justify wanting or needing to use Spring. While it is sold as being light weight, modern Java EE app servers are themselves quite light weight, and thanks to "profiles" you can obtain even lighter weight versions of them. See the java.sun.com for more information.

You will notice that the JNDI names used in the resource annotations in my EJBs were added against "mappedName" attributes in the annotations, rather than "name". What that means is that the standard indirection mappings that one should use when deploying EJBs, has not been used, namely the resource "jms/destinationResource" MUST be present in the JNDI tree, rather than the container looking for this name in a mapping in the deployment descriptor. This is fine when deploying your own EJBs to your own app server, but the original idea of creating EJBs was that you would write them, and the deployer would decide how the resources are named, which hence requires a mapping. If you do provice a mapping in the deployment descriptors, then you should use the "name" attribute in the annotations. See here for more information.

The full source code can be downloaded here.


© 2010 Ant Kutschera

Social Bookmarks :  Add this post to Slashdot    Add this post to Digg    Add this post to Reddit    Add this post to Delicious    Add this post to Stumble it    Add this post to Google    Add this post to Technorati    Add this post to Bloglines    Add this post to Facebook    Add this post to Furl    Add this post to Windows Live    Add this post to Yahoo!