1 2 3 Previous Next

felipegaucho

142 posts

I just updated the Cejug-Classifieds Project to support Maven 2 builds and I added some new features, including a Shell Script able to configure the resources and also to deploy the the application in the Glassfish V3. The script creates all Java EE resources required by the application, like the DataSource, the JavaMail connection and the JMS Queues. In the next sections I will describe how to create each of this resources using the "Glassfish's Administration CLI tool" (the asadmin command line).

                                               
           

The Glassfish's Administration CLI tool

           

The CLI tool is available when you install Glassfish in your           machine and include the %AS_HOME\bin in the PATH           environment variable. In order to test if your configuration is ok,           just open a terminal and type:

           
     asadmin version
     Version = GlassFish v3 (build 74.2)
     Command version executed successfully.
           

You should see the Glassfish version on the screen, otherwise,           please review the installation           of Glassfish before to proceed reading the rest of this blog.

           

Important: I will assume you know what Java EE           resources are and specially that you know what is a DataSource,           a JMS Queue and a JavaMail           resource.

           

Environment configuration

           

The following details should be configured in your machine in           order to execute the sample commands of this blog:

           
                   
  •                

    Install Glassfish                V3 with the default configuration values.

                   
  •                
  •                

    Install MySQL with user=root and password=adminadmin.                If you use different values, please adapt the commands in the scripts                below.

                   
  •                
  •                

    Be sure to have the MySQL driver                installed in the Glassfish lib folder. If you didn't installed the                driver yet, just copy the MySQL                Connector/J 5.1.12 jar file to the AS_HOME\domains\domain1\lib                folder.

                   
  •                
  •                

    Be sure to create the classifieds database before to proceed,                ust open a terminal (or DOS window) and type:

                   
    mysql -uroot -padminadmin
    mysql> create database classifieds;
    mysql> Query OK, 1 row affected (0.00 sec)
    mysql> exit;
          
                   
  •            
           

The resources of Cejug-Classifieds

           

The goal of this entry is not to replace the           excellent Glassfish documentation, it is just a shortcut for the ones           interested in collaborate in the CEJUG open-source projects. I will           use the           Cejug-Classifieds Shell Script as example of asadmin           usage, and if you are using Windows there are just few details you           should change in order to obtain the same results. The resources to be           created are the ones highlighted in the right image of the Glassfish           Administrative console. These resources are:

           
                   
  1.                

    jdbc/classifiedsPool - a MySQL JDBC Connection                Pool

                   
  2.                
  3.                

    jdbc/classifieds - a MySQL Data Source

                   
  4.                
  5.                

    NotificationQueueConnectionfactory - a JMS                connection factory used by the notification features.

                   
  6.                
  7.                

    RegistrationQueueConnectionfactory - a JMS                connection factory used by the pedantic                registration use case.

                   
  8.                
  9.                

    NotificationQueueConnectionfactory - the                notification JMS Queue.

                   
  10.                
  11.                

    RegistrationQueueConnectionfactory - the                registration JMS Queue.

                   
  12.                
  13.                

    mail/classifieds - the JavaMail resource, used to                messages through the GMail                SMTP server.

                   
  14.            
           
           

res.png

           

After executing the instructions below you should check the resources of your Glassfish accessing http://localhost:4848 and then navigate in the left pane to find each resource. You can also use the impressive Admin GUI of Glassfish to modify the resources you created through the line commands or even create the resources directly in the Admin GUI. The reason I prefer the asadmin line commands is due to the higher productivity and - specially - due to the chance to integrate the resources creation in the continuous integration of the project. Nevertheless it is a personal choice and it is up to you to find your best way of doing that.

Creating a DataSource resource with asadmin

Data Sources are the resource you need to connect your Java EE Application to a database. It depends on two configurations: a connection pool and the JDBC resource itself. Your application will connect to the JDBC resource and the container will manage the connections pool - so you don't need to add boiler plate code to your application just to manage the life cycle of the JDBC connections.

       
  1.    

    Create the connection pool:

       
    asadmin create-jdbc-connection-pool --datasourceclassname com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource --restype javax.sql.ConnectionPoolDataSource --property "User=$MYSQL_USER:Password=$MYSQL_PASSWORD:URL=$DB_URL" jdbc/classifiedsPool
       

    Where:

       
             
    •        

      $MYSQL_USER is the database user

             
    •        
    •        

      $MYSQL_PASSWORD is the database user's           password

             
    •        
    •        

      $DB_URL is the database connection URL.           Unfortunatelly the database connection is slightly different for each           operational system due to the slashes '/' differences.

             
    •    
       

    Example with the real values for Cejug-Classifieds:

       
             
    •        

      Linux:

             
      asadmin create-jdbc-connection-pool --datasourceclassname com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource --restype javax.sql.ConnectionPoolDataSource --property "User=root:Password=adminadmin:URL=jdbc\\:mysql\\://localhost\\:3306/classifieds" jdbc/classifiedsPool
             
    •        
    •        

      Windows:

             
      asadmin create-jdbc-connection-pool --datasourceclassname com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource --restype javax.sql.ConnectionPoolDataSource --property "User=root:Password=adminadmin:URL=jdbc\:mysql\://localhost\:3306/classifieds" jdbc/classifiedsPool
             
    •    
       

    Test the connection pool:

       
    asadmin ping-connection-pool jdbc/classifiedsPool
    Command ping-connection-pool executed successfully.
    
       
  2.    
  3.    

    Create the JDBC resource:

       
    asadmin --user=$ASADMIN_USER create-jdbc-resource --connectionpoolid jdbc/classifiedsPool jdbc/classifieds
       

    Where:

       
             
    •        

      $ASADMIN_USER is the Glassfish administrator           username

             
    •    
       

    Example with the real values for Cejug-Classifieds:

       
             
    •        

      The same command for both Linux and windows:

             
      asadmin --user=admin create-jdbc-resource --connectionpoolid jdbc/classifiedsPool jdbc/classifieds
             
    •    
       
  4.    
  5.    

    Test the JDBC resource:

       
    asadmin --user admin list-jdbc-resources
    jdbc/__TimerPool
    jdbc/__default
    jdbc/arena
    jdbc/classifieds
    
    Command list-jdbc-resources executed successfully.
       

You can find here an example of JPA 2.0 persistence.xml file using this resource.

Creating JMS resources with asadmin

Messaging is one of the most powerful resource of Java EE applications, because it enable asynchronous tasks in your application and also provides a mechanism to Queue processes when your application is busy. Several use cases can respond much faster to the client request if the some tasks are processed in background, and that is the way Cejug-Classifieds uses the Glassfish JMS: for customers notifications and for the registration use case. The registration case is the easier example: a new customer register an account in the classifieds system, and then the system sends an email to confirm the customer request. SMTP is always a complicated resource because it is not guaranteed to deliver the messages and also because the SMTP can be down in the moment the customer tries to register. To not block the application or to force the customer to wait for the SMTP server response, every new registration is stored in a Queue and then the application immediately respond to the customer application saying "please check your email for the confirmation message". After that, the server releases the resources used by the registration use case and other process will handle the email sending to the new customer - faster and more reliable than trying to handle the whole use case in memory.

       
  1.    

    Create the JMS connection factories:

       
    asadmin create-jms-resource --restype=javax.jms.QueueConnectionFactory --description="Cejug-Classifieds Registration Connection Factory." RegistrationQueueConnectionFactory
       
    asadmin create-jms-resource --restype=javax.jms.QueueConnectionFactory --description="Cejug-Classifieds Notification Connection Factory." NotificationQueueConnectionFactory
       

    Notice that JMS is a bit simpler than DataSource, you don't need      to specify users and passwords since the Open JMS is part of the Glassfish      itself (instead of accessing an external database)

       

    Test the JMS connection pool (yes, the test is the same since      all connections pools are the same type resource in Glassfish):

       
    asadmin ping-connection-pool RegistrationQueueConnectionFactory
    Command ping-connection-pool executed successfully.
    
       
  2.    
  3.    

    Create the JMS Queues:

       
    asadmin create-jms-resource --restype=javax.jms.Queue --description="Queue used to register Cejug-Classifieds users." RegistrationQueue
       
    asadmin create-jms-resource --restype=javax.jms.Queue --description="Queue used to notify Cejug-Classifieds users." NotificationQueue
       

    The same command is valid for both Linux and windows.

       
  4.    
  5.    

    Test the JMS resource:

       
    asadmin --user admin list-jms-resources
    RegistrationQueue
    NotificationQueue
    
    Command list-jms-resources executed successfully.
       

Here you can find a sample code using the notification queue and here you find another MessageDrivenBean consuming the registration queue.

Creating a JavaMail resource with asadmin

At this point I hope you already identified a pattern on creating resources in the Glassfish server, the commands are similar and the most important details are the parameter values. To create a connection with an SMTP server you need only one command, since there is no pooling for SMTP connections.

       
  1.    

    Create the JavaMail resource:

       
    asadmin --interactive=false create-javamail-resource --mailhost=$MAIL_HOST --mailuser=$MAIL_USER --fromaddress=$MAIL_FROM --enabled=true --description="e-Mail account used to confirm the registration of the Arena PUJ users" --storeprotocol=imap --storeprotocolclass=com.sun.mail.imap.IMAPStore --transprotocol smtp --transprotocolclass com.sun.mail.smtp.SMTPSSLTransport --property mail-smtp.user=$MAIL_SMTP_USER:mail-smtp.port=465:mail-smtp.password=$MAIL_SMTP_PASSWORD:mail-smtp.auth=true:mail-smtp.socketFactory.fallback=false:mail-smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory:mail-smtp.socketFactory.port=$MAIL_SMTP_PORT:mail-smtp.starttls.enable=true mail/classifieds
       

    Example with the fake password for Cejug-Classifieds:

       
             
    •        

      The same command for both Linux and windows:

             
      
      asadmin --interactive=false create-javamail-resource --mailhost=smtp.gmail.com --mailuser=cejug.classifieds --fromaddress=cejug.classifieds@gmail.com --enabled=true --description="e-Mail account used to confirm the registration of the Cejug-Classifieds users" --storeprotocol=imap --storeprotocolclass=com.sun.mail.imap.IMAPStore --transprotocol smtp --transprotocolclass com.sun.mail.smtp.SMTPSSLTransport --property mail-smtp.user=cejug.classifieds@gmail.com:mail-smtp.port=465:mail-smtp.password=fake:mail-smtp.auth=true:mail-smtp.socketFactory.fallback=false:mail-smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory:mail-smtp.socketFactory.port=465:mail-smtp.starttls.enable=true mail/classifieds
             
    •    
       
  2.    
  3.    

    Test the JavaMail resource:

       
    asadmin --user admin list-javamail-resources
    mail/classfieds
    
    Command list-javamail-resources executed successfully.
       

Here you find an example of code using the JavaMail resource.

Using Shell Script or BAT files to trigger asadmin commands

Now you are exposed to a sert of examples of useful asadmin commands, it is time to think about an efficient way of executing them - and the best way I can imagine is the authomatization of resources creation through script files. If you are working in a unix-like operational system you will use a Shell Script, and if you are using Windows you need to create a batch file (*.bat). The asadmin commands are the same, but we have three distinct points to care between linux and windows:

       
  1.    

    Semi-colon X Colon: Windows uses semi-colon; while Linux uses colon: as parameters separator. And there      is another hidden trap in our asadmin commands: when you pass quoted      parameters to the asadmin like "User=$MYSQL_USER:Password=$MYSQL_PASSWORD:URL=$DB_URL"      you always need to use colon since the String will be interpreted by a      Java code and not by the operational system.

       
  2.    
  3.    

    Inverted Slashes: The wndows uses inverted      slashes\ while Linux uses slashes/      as paths separator. This is important in the JDBC resources, because      the JDBC URL depends on the OS - for example:

       
             
    •        

      Linux: URL=jdbc\\:mysql\\://localhost\\:3306/classifieds

             
    •        
    •        

      Windows: DB_URL=jdbc\:mysql\://localhost\:3306/classifieds

             
    •    
       
  4.    
  5.    

    Use CALL for executing the asadmin      commands on Windows, otherwise the batch file will exit after the first      command. Example:

       
    CALL asadmin --user=%ASADMIN_USER% create-jdbc-resource --connectionpoolid jdbc/classifiedsPool jdbc/classifieds
       
  6.    
  7.    

    You can also delete the Glassfish resources with the asadmin      commands, that's useful to cleanup the Glassfish and also to be sure      that a previous or misconfigured resource won't be used. For example:

       
    asadmin --passwordfile=$PASS_FILE delete-jms-resource RegistrationQueueConnectionFactory
    asadmin create-jms-resource --restype=javax.jms.QueueConnectionFactory --description="Cejug-Classifieds Registration Connection Factory." RegistrationQueueConnectionFactory
       

    The first command will throw some error messages if the resource      is not present, but the second command will run anyway.

       

As example you can download the scripts of Cejug-Classifieds here:

Summary

asadmin is a powerful tool, specially if added to a continuous integration environment like Hudson. With scripts it is quite simple to do that, and it will push your project to a next quality level. I just can't imagine to run a project in Glassfish without such scripts, but it is up to you to evaluate this option. Also keep in mind that the above scripts are just a glimpse on the features of the asadmin, you can do much more like deploy and undeploy the Java EE applications or check if they are working fine. There are also a chance to extend the asadmin tool like demonstrated by Sreenivas Munnangi and by Nachiappan. I see a portability issue on this approach but eventually you need that so you know where to look for.

Any issue or question, please be my guest to contribute with my open-source projects.

One of the most controversial but yet powerful techniques for integrating distributed systems is the JSONP format, a javascript function that bypasses the same origin policy of the browser. Jersey provides built-in support for JSONP and this blog demonstrates how to benefit from this feature.

When JSONP is a good option?

                                               
           

The controversial around JSONP is the fact that using JSONP     your application bypasses the Same     Origin Policy, facilitating the fearful cross-site     scripting (XSS) [1, 2]. Despite that obvious     risk, there are certain scenarios where JSONP makes sense and solves     a lot of problems which would require a more expensive solution     without the usage of cross site scripts.

           

Consider you need to integrate some data between two web     applications hosted by third party companies. Suppose those     companies have no previous agreement so in order to share data     between the companies you have two choices:

           
                   
  1. To establish a secure channel between the servers (think       about the business costs here).
  2.                
  3. To expose the application data using JSONP, and then one       application can consume the data of the other without any change       in the network (the technical effort to support the JSONP format is  minimum).
  4.            
           

The other aspect to consider in using the traditional is the     problem of bottlenecking the web. So, if a server is the     only data source of its web-application, does it really inspect the     third party servers data before to dispatch to the clients? If not,     it is just an unnecessary bottleneck, making the web slower without     any benefit (it is nor more neither less secure if the server just     forward third party data) - take a couple of minutes to think about     that.

           
xss.png

This topic is much more controversial [1, 2, 3] and detailed than my simple analogies, but I hope you can see the benefits of using JSONP in controllable environments. Otherwise, just consider that Google Adsense wouldn't be feasible without JSONP - a good example on how JSONP unleashes the web. In summary:

 

"JSONP is a prime choice when you trust or when you can control the servers consumed by your web-applications."

 

 

JSONP in practice with Jersey & Glassfish V3

As example of how to enable JSONP in your web-services, I will demonstrate some features of the Arena PUJ project. One of the Arena project goals is to facilitate the consume of its public information about competitions and competitors. So the quest is how to allow the developers to quickly build a client of the Arena server?. The goal is to make Arena HTTP Server as friendly as the Twitter server for example. Fortunately the Jersey framework treats JSONP as first class technology and makes it extremely easy to expose HTTP resources in such format.

JSONP support in Jersey

In order to enable JSONP in a web-application based on the Jersey Framework, you need to care about three basic steps:

       
  1. To change code on the server-side to return the data wrapped   as GenericEntity attributes of the type JSONWithPadding.
  2.    
  3. To configure Jersey to use the JSON natural notation instead   of the default JAXB format.
  4.    
  5. To change the clients code to understand your data structure   formatted as JSONP.

The first two steps are pure Jersey code, and are actually pretty simple steps. The third step can be done with plain javascript but to facilitate my life I will use the JSONP features of the jQuery Library. So, let's start with the server side.

Loading the homeworks of the PUJCE-09 Competition.

PUJ is an academic competition where undergraduate students submit their homeworks for the evaluation by senior Java professionals. A basic use case of web-applications exposing the PUJ data is to offer the downloading of the homeworks of the competitors. You can see such a feature in action in one of the following PUJ Clients:

The above web-applications consume the information from the same server, the Arena PUJ Web-Service. The image of the competitors links to their Java code, just click on it to download the homework. Despite all of them are hosted in the same domain, the DWR and the HTML5 applications use JSONP and are ready to be deployed in other server if necessary. The JSF 2.0 application connects directly in the persistence layer, a set of @Stateless EJBs injected in the JSF ManagedBeans. So we have from the same server two distinct types of data access: regular HTTP Requests with the client deployed in the same domain as the server and JSONP HTTP Request done from applications deployable anywhere (more freedom, more cloud oriented).

First of all let's consume the data in the safe traditional way, using a pure HTTP Request. When you access the URL http://fgaucho.dyndns.org:8080/arena-http/homework?competition=PUJCE-09, you are accessing the below Server code fragment (you can check the complete code here). Notice that the supported response types are XML and JSON, so your data is only accessible from a client launched from the server where this code is running.

  @GET
  @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
  public Collection<PujHomeworkEntity> readAll(
      @QueryParam(EntityFacadeConstants.PARAM_START) @DefaultValue(EntityFacadeConstants.PARAM_START_DEFAULT_VALUE) int start,
      @QueryParam(EntityFacadeConstants.PARAM_MAX) @DefaultValue(EntityFacadeConstants.PARAM_MAX_DEFAULT_VALUE) int max,
      @QueryParam("acronym") String acronym,
      @QueryParam("title") String title,
      @QueryParam("competition") String competition) {
    Map<String , Serializable> parameters = new ConcurrentHashMap<String, Serializable>();
    if (acronym != null) { parameters.put("acronym", acronym); }
    if (title != null) { parameters.put("title", title); }
    if (competition != null) {
      try {
        parameters.put("competition", competitionFacade.read(
            PujCompetitionEntity.class, competition));
      } catch (Exception error) {
        return new ArrayList<PujHomeworkEntity>();
      }
    }
    
    return facade.findByCriteria(parameters, start, max); // using JPA2 criteria API
  }

Step #1 - using JSONWithPadding

Now you want to expose the same data using JSONP, allowing any HTTP client to access your server data. The only change you need to do in your code is to wrap the collection as a javax.ws.rs.core.GenericEntity and then to return a com.sun.jersey.api.json.JSONWithPadding instead of the collection itself. Notice also the response MIME type, defined as application/x-javascript and also as XML and JSON. This is a special hint about Jersey: you can have only one method returning several different MIME types. I've chosen to have a separated method for JSONP because it is experimental but I believe soon I will review that decision and unify all methods around the same code - keep that in mind if you are designing your own API.

  @GET
  @Path("jsonp")
  @Produces( { "application/x-javascript", MediaType.APPLICATION_JSON,
      MediaType.APPLICATION_XML })
  public JSONWithPadding readAllP(
      @QueryParam("jsoncallback") @DefaultValue("fn") String callback,
      @QueryParam(EntityFacadeConstants.PARAM_START) @DefaultValue(EntityFacadeConstants.PARAM_START_DEFAULT_VALUE) int start,
      @QueryParam(EntityFacadeConstants.PARAM_MAX) @DefaultValue(EntityFacadeConstants.PARAM_MAX_DEFAULT_VALUE) int max,
      @QueryParam("acronym") String acronym,
      @QueryParam("title") String title,
      @QueryParam("competition") String competition) {
    Collection<PujHomeworkEntity> competitions = readAll(start, max,
        acronym, title, institution, competition);
    return new JSONWithPadding(
        new GenericEntity<Collection<PujHomeworkEntity>>(competitions) {
        }, callback);
  }

You can test this method using CURL:

curl -XGET http://fgaucho.dyndns.org:8080/arena-http/homework/jsonp\?competition=PUJCE-09

Step #2 - using JSON natural notation with Jersey

Jersey is one of most friendly API in the Glassfish portfolio, but there is a tweak that bothers me since the first day I tried to serialize JAXB annotated objects in JSON format. If you use attributes in your JAXB objects, the JSON notation will receive an @ symbol in front of it, a non-standard javascript notation that will brake libraries like jQuery. The workaround is provided by the Jersey itself, in format of a ContextResolver class. So, in order to have natural JSON notation in your web-service you need to create a class like the one below. You can find the real code used in the Arena here, and you can also check more information about ContextResolver and JSON natural notation in Jersey here.

import javax.ws.rs.ext.*;
import javax.xml.bind.JAXBContext;
import com.kenai.puj.arena.model.*;
 import com.sun.jersey.api.json.JSONConfiguration; import com.sun.jersey.api.json.JSONJAXBContext;

@Provider
public class MyJAXBContextResolver implements ContextResolver<JAXBContext> {

  private JAXBContext context;
  private Class<?>[] types = { PujAdvertisementEntity.class,
      PujCompetitionEntity.class, PujLinkEntity.class,
      PujHomeworkEntity.class };

  public MyJAXBContextResolver() throws Exception {
    this.context = new JSONJAXBContext(JSONConfiguration.natural().build(),
        types);
  }

  public JAXBContext getContext(Class<?> objectType) {
    for (Class<?> c : types) {
      if (c.equals(objectType)) {
        return context;
      }
    }
    return null;
  }
}

You just need to have a ContextResolver class in the same package of your Jersey resources, and the container will load that. The server side is done, now you need a smart client to consume that.

Step #1 - consuming JSONP with jQuery

                                               
           

The special feature that motivated me to use jQuery for     loading the JSONP data of Arena was a function called jQuery.getJSON.     It basically returns for your javascript code the content of any   JSONP enabled server, and jQuery does that using asynchronous calls (AJAX).

           

<div id="homeworks"></div>

<script type="text/javascript"
  src="http://code.jquery.com/jquery-latest.js"></script>
<script>
  jQuery.noConflict();
  jQuery.ajaxSetup ({ cache: true });
    jQuery(document).ready(function(){
        loadHomeworks("PUJCE-09"); /* loading three different competitions */
        loadHomeworks("PUJCE-08");
        loadHomeworks("PUJCE-07");
        function loadHomeworks(competition) {
          var div = document.createElement('div');
          div.className="history";
          div.id = competition;
          var url = "http://fgaucho.dyndns.org:8080/arena-http/homework/jsonp?competition="+competition+"&jsoncallback=?";
          jQuery.getJSON(url,
          function(data){
              var oUL = document.createElement('ul');
              oUL.className="history2";
              div.appendChild(oUL);
              
            jQuery.each(data, function(i, fn) {
                  var avatar = document.createElement('img');
                  for ( var a in fn.author )
                  {
                      var author = fn.author[a];
                      for ( var r in author.role )
                      {
                       if(author.role[r].name == 'STUDENT') {
                        avatar.src = author.avatar + '?s=48&r=r';
                        avatar.title = author.name;
                        break;
                       }
                      }
                      if(avatar.src) {
                          break;
                      }
                  } 
                  var anchor = document.createElement('a');
                  anchor.href = fn.url;
                  anchor.appendChild(avatar);
                  var p = document.createElement('p');
                  p.appendChild(anchor);
                  var item = document.createElement('li');
                  item.appendChild(p);
                  oUL.insertBefore(item, oUL.firstChild);
                  
              }); 
          });
          var outterDiv = document.getElementById("homeworks");
          outterDiv.appendChild(div);
        }
        
    });
</script>
           
           

           

The result of the above script is demonstrated in the below image, a set of images for each of the PUJCE competitions.

competitors.png

Summary

The script presented here can be embedded in any web-application and I suggest you to try that in your local machine as a cloud computing experiment. Just create a webapp containning an HTML page with the above script and deploy it to your preferred web-server, a Tomcat or a Glassfish for example. Access it and notice that it will load the data from my server without any problem. Isn't it cool? You can consume the data of CEJUG PUJ competitions without any integration effort, without the need of any extra code, you don't need to ask permission for me to load such data or even make a formal agreement to interchange data between the two servers.

JSONP is a silver bullet?

Not at all, JSONP is just an alternative for scenarios where you can have diverse HTTP clients consuming diverse data from diverse HTTP servers in a free way - no need of contracts or web bottlenecks. The clients consume the data from where it is generated, and the servers expose just part of the data required for the clients to complete the information required by the end users. It is cloud computing oriented and it explores the best of the Internet capabilities.

How to control the security and the dynamic of the data? For security there is only one feature: trust, when you code the client software you should consume data from server you know or from servers you trust. And about the changes in data models, you need just one more special feature from the REST style of architecture: HATEOAS. I will talk about that in another blog, for now I believe we already have a good topic to discuss - I am just waiting your feedback.

                                               
           

CDI           is one of the best features of Java EE 6, it gives you - for example -           a chance to include a beans.xml file in the WEB-INF           folder in           order to optimize the beans discovering during the application startup.           An empty file is a fair price to pay for the cool features of the CDI but as soon you           import the project in your preferred IDE you will see warnings about           the impossibility of validating such file. The IDE is doing its job           mitigating the risk of work without a chance to validate an XML file,           now it is your time to fix this broken window.

           

The beans descriptor schema: beans_1_0.xsd

           

If you mess with the beans.xml file and try to deploy your           application, Glassfish V3 will identify the problem because it           contains the schema document describing the format of the bean.xml           file. You can find this schema in the folder $AS_HOME/glassfish/lib/schemas/beans_1_0.xsd,           where $AS_HOME stands for the Glassfish V3 installation folder.

           
           

broken windows

           

Including the proper header in your beans.xml file

The only step you need to proceed in order to calm down your IDE is to include the schema declaration in the header of the beans.xml file:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

Done, just rebuild and refresh the project to see all that boring warnings going away. IMHO it is much more elegant than disabling the XML validation - what is commonly suggested by people that like to brake windows and/or software :)

IMPORTANT: it only works with a recent version of the Glassfish plugin for Eclipse (>= 1.0.52), so if your Eclipse installation is older than February 2010 it is a good moment to download the latest Eclipse IDE and install the Glassfish Plugin again, isn't it? This issue will disappear naturally with time, but it is an important detail since the plugin is too new.

* Thanks Ludo for all hints about this little issue.

* Thanks Dominik Dorn for calling my attention to a file I believed only available in the Glassfish distribution :)

Here it is the PDF version of my slides @Jfokus 2010, the great Java conference in Sweden.

You feedback is always welcome.

And if you missed that, here you find my conference wrap-up.

 

 

felipegaucho

Jfokus 2010 Wrap-Up Blog

Posted by felipegaucho Jan 30, 2010

My mailbox aggregates several Java User Groups and other specialized sources of information about the Java universe, with special guests like CEJUG and the Java EE community. Many of these Java sources are used by consultant companies to hire smart people, and since last year I am reading a desperate growing interest about skilled Java developers. More: few days ago I was having a coffee with some colleagues and a manager confessed he is worried where to hire all resources he needs to allocate in the signed contracts for 2010.

Listening such conversation and watching the raising offerings in the mailing lists I have only one conclusion: Java market is dry, skilled Java developers are becoming scarce. Reasons for that? No idea, but there are some obvious observations about our times:

       
  •    

    Hype languages and technologies didn't conquered the market as   we expected, languages like Scala, Ruby, Grails, etc. Android? You   know, perhaps next year. These languages advertised revolutions during   the last two or three year, sold out a lot of books and conference   speeches but nowadays it is not easy to find good jobs (salaries) for   such technologies. Certainly there are good jobs somewhere, but it is   nothing compared to the Java is dead speech of three years   ago. Simple fact is: Java is still ranking   high in the IT market, while all that hype revolutions are still hype   promises. And the young developers that followed the hype? Well, they will need to accept that Java job now, frustrated people mostly unable to delivery a quality service anyway.

       
  •    
  •    

    People are becoming lazy and dumb, everyday a bit more. Watch idiocracy and you   will get the point. If not convinced, watch MTV for half an hour and   you get a live demo :). The iPhone users cannot handle more than one   button in any GUI and unsafe-typed languages say that "anything that   requires a type declaration is just too complicated to be useful".   Nice speech, but what to do with developers convinced that math and   domain models are obsolete technologies?

       
  •    
  •    

    What about the salaries and Java carriers? Java platform   produces a large chunk of all software running in the Global IT   market, supporting business at a scale of billions of dollars every   year. Nothing more natural than expect the guys behind this technology   monster to have a good life - or at least a profitable life. Well, the   reality is a boring overestimation of the management models, leaving   to the developers just the extra hours, tendinitis and   more learning curves.

       
                                               
           

How to hire good Java developers?

           

Just in case you are seriously looking for good Java developers, some hints:

           
                   
  1. Raise the salary (no excuses).
  2.                
  3. Offer learning as part of the job benefits (conferences,   books, courses, etc).
  4.                
  5. Allow your developers to take project decisions.
  6.                
  7. Use modern Java technologies (Still using Java 1.4?)
  8.                
  9. Give the developers some stability and carrier perspective,   and don't try that in a bureaucratic way.
  10.                
  11. Flexible working time and remote office should be available.
  12.                
  13. Give the developers more than water and coffee.. how about   fruits? cokes and other beverages? How much it costs for you to buy 1   coke per developer a day? If you think it is too much, please leave   the market :)
  14.                
  15. Don't try poor copies of Google and IBM ideas, these   companies are just richer than yours. Be creative and honest with your   developers.
  16.            
           

Good luck :) Java market is dry, good developers are scarce.. it is time for smart managers to raise the salaries and catch the good ones, the rest can be shared by people reading Scrum and Kanban manuals.

           
           

           
                                               
           

After configuring Hudson to run in a Glassfish with security manager enabled I started to have problems in other applications, specially web applications using reflection to access private fields in Java classes. Over the web I noticed a lot of people struggling with the same issue (Seam, GWT, Vaadin, etc). The problem is caused because most of the modern frameworks tries to access Java private fields directly - perhaps motivated by the popularity of type-unsafe languages or just designed for better performance. The frameworks designer expect to have this freedom but the Security Manager imposes strict rules against that. Applications based on these frameworks running on a secure Glassfish will eventually throw an exception like:

           
           

           
java.security.AccessControlException: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
    at java.security.AccessController.checkPermission(AccessController.java:546)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
    ..
    ..
    [#|2010-01-02T11:28:34.681+0100|WARNING|glassfishv3.0|org.directwebremoting.dwrp.BaseCallMarshaller|_ThreadID=30;_ThreadName=Thread-1;|--Erroring: batchId[1]
     message[java.lang.IllegalAccessError: Class com.sun.xml.bind.v2.runtime.reflect.Accessor$FieldReflection
     can not access a member of class com.kenai.puj.arena.model.entity.PujInstitutionEntity with modifiers "private"]|#]

Here are some alternatives to workaround the problem:

       
  1. Change the accessibility of classes from fields to methods.      You can do that annotating the methods instead of fields, specially for      JPA and EJB annotations. In the new book Pro JPA 2, they      demonstrate a good practice using methods annotation to facilitate unit      testing as well, but this is another topic.    
             
    • Pros: solves the problem without additional           container configurations.
    •        
    • Cons: goodbye IDE refactorings and           auto-completion. I am a fan of auto-completion and usually I have the           getters&setters methods generated by the IDE. I can't imagine myself           handling getters and setters manually.
    •    
       
  2.    
  3.    

    Suppress access checks in the security policy of Glassfish. I      would say that is the canonical solution, described in the "Issues      Related to Security" section of the Glassfish manual.

       
             
    • Pros: it follows the Glassfish recommendation           and keeps your code and project structure as you want, without alien           constraints.
    •        
    • Cons: you need to change the Glassfish           configuration files what means a risk when you upgrade the server - if           you forget to reconfigure the new server, all applications will start           to fail (at least it is not a silent killer).
    •    
       

    How to do that?

       
             
    1. open the security policy file: glassfishv3/glassfish/domains/domain1/config/server.policy
    2.        
    3. include the following entry:
    4.        
      grant codeBase "file:${com.sun.aas.installRoot}/domains/domain1/applications/arena-dwr/-" {
          permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
      };
         
       

    Don't forget to replace the arena-dwr by the name of      your application, and also to check project path if you are not using      the default container instance domain1.

       

More I work with Glassfish more this kind of issue becomes trivial to solve, but perhaps it is hard for new Glassfish adopters to quick fix such problems. A surprising point is the need of hand crafted configurations in local server files. Eventually we could deploy the security policy with the application itself or to include some configuration hints in the sun-web.xml file or other standard configuration file. Perhaps a good suggestion for Glassfish v4.

* I am not suggesting to open the doors allowing web applications to reconfigure the container, but certain flexibility is a desirable feature. Or perhaps a new set of options in the admin GUI for quick fixing the most common configuration problems. And yes, if all framework designers change their mind set, all this problems will never happen, but then you are talking about a brand new world - too much for hope even in the beginning of a new decade :)

I got some difficulties following the tutorial about creating components with JSF 2.0, mainly due to some obsolete instructions and Maven dependencies of the more than 1 year old original articles of Ed Burns. I wrote down upgrades instructions in a hope to help other newbies to create composite UI with JSF 2.0. Nevertheless, you should read the original text because I won't explain the concepts behind creating Composite User Interfaces and neither rephrase Ed Burns. I will just give you en updated version of the same project, with the same xhtml code. I am using Eclipse on the Karmic Koala Ubuntu 9.10 but the below instructions should work everywhere :)

The original articles from Ed Burns:

There are tons of related material on the web, but after reading several blogs and tutorials I've choosen the Mr. Burns' ones due to the simplicity of the example. If you know other good material to start learning UI composite elements with JSF 2.0, please write the URL in the bottom of this page. The original text is based on Netbeans and depends on a local copy of javaee and jsf libs. I replaced that for Maven dependencies and I also adapted the example to Eclipse but there is no dependency to any Eclipse feature, you are free to choose your IDE since the code is a pure Maven project. I also added an external css file instead of the original inline style tag.

       
  1.    

    Install Glassfish      v3 and Maven 2.x

       
  2.    
  3.    

    Download the sample project and unzip it      somewhere

       
  4.    
  5.    

    Go to the folder you unziped the sample project and type the      following commands:

       

    mvn -Dwtpversion=2.0 compile package      eclipse:eclipse

       

    asadmin start-domain

       

    asadmin deploy target/jsf-example01.war

       
  6.    
  7.    

    Open the project URL with your browser: http://localhost:8080/jsf-example01/index.jsf

       

    You should see something like the below image:

       

       

You should be able to import the project in Eclipse and also to use the Glassfish Eclipse Plugin to run and/or debug the project directly inside the IDE. Be my guest to ask about this example, I am also learning here but eventually I am one step further :). And if you need advanced hints about JSF, please join the Mojarra mailing list, the quality and the velocity of the responses are impressive.

Web applications created by the Eclipse IDE contains an annoying folder WebContent to host the web resources and deployment descriptors. Quite natural for Eclipse users, this feature ignores the Maven convention and force the developers to hack the pom files in order to get the project up and running in Eclipse. In this aspect, Eclipse if far behind the other IDEs regarding Maven support, even if you consider the very good M2Eclipse plugin. So, for you lazy Christmas hackers, here it is a solution for the Maven integration problems in Eclipse based on the maven-war-plugin.

ERRATA: please use the WTP plugin instead of changing the project structure.  I figured out the wtp plugin after writting this blog, so I suggest you to check just the 1st and the 3th steps of the below instructions. I kept the original blog information in case you really need or want to change the project structure.

       
  1.    

    Create a Web Project in Eclipse: right-click on the Project Explorer > New > Project > Web \ Dynamic Web Project

       
  2.    
  3. Create a pom.xml file in the project root folder, with the following content:
  4.    
  5.    
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
         <modelVersion>4.0.0</modelVersion>
         <groupId>org.cejug</groupId>
         <artifactId>webapp-test</artifactId>
         <packaging>war</packaging>
         <version>1.0-SNAPSHOT</version>
         <name>webapp-test Maven Webapp</name>
         <url>http://maven.apache.org</url>
         <repositories>
              <repository>
                   <id>maven2-repository.dev.java.net</id>
                   <name>Java.net Repository for Maven</name>
                   <url>http://download.java.net/maven/2</url>
              </repository>
         </repositories>
    
         <build>
              <finalName>${project.name}</finalName>
              <plugins>
                   <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-war-plugin</artifactId>
                        <version>2.0.2</version>
                        <configuration>
                             <webResources>
                                  <resource>
                                       <directory>${basedir}/WebContent</directory>
                                  </resource>
                             </webResources>
                             <warSourceDirectory>WebContent</warSourceDirectory>
                             <warSourceExcludes>WebContent/WEB-INF/lib/*.jar</warSourceExcludes>
                             <archiveClasses>false</archiveClasses>
                             <archive>
                                  <manifest>
                                       <addClasspath>true</addClasspath>
                                       <classpathPrefix />
                                  </manifest>
                                  <manifestEntries>
                                       <url>${pom.url}</url>
                                       <Implementation-Build>${buildNumber}</Implementation-Build>
                                       <Implementation-Title>${project.name}</Implementation-Title>
                                       <Implementation-Vendor>CEJUG</Implementation-Vendor>
                                       <Implementation-Version>${project.version}</Implementation-Version>
                                       <Built-By>${user.name}</Built-By>
                                       <Built-OS>${os.name}</Built-OS>
                                       <Build-Date>${timestamp}</Build-Date>
                                       <SCM>${buildNumber}</SCM>
                                  </manifestEntries>
                             </archive>
                        </configuration>
                   </plugin>
              </plugins>
         </build>
    </project>
         
       
  6.    
  7.    

    Compile and prepare the project for eclipse:

       
    mvn -Dwtpversion=2.0 compile eclipse:eclipse
    
       

Notice the usage of the plugin -Dwtpversion to enable Maven to add Eclipse WTP Support to the project. That simple flag do the trick :). Actually just using that flag will work, but not all plugins of Eclipse will work out of the box without the WebContent folder - it is up to you to decide if it is worthy to modify your project structure or just go straight ahead with the plain Maven folder.

Done, now you can refresh the project in Eclipse and continue to work. Remember that jjust the resources folder is hard coded in Eclipse, the src/main/java continues as Maven expects. Perhaps some day we can have the confluence between the conventions of Maven and Eclipse and then we will finally becomes free of this daily basis hacks.

http://rlv.zcache.com/happy_new_year_2010_card-p137042075152258748q6k5_400.jpg

* Thanks Ruddi for the tips about Eclipse :)

Jazoon 2010 is calling for papers, with a renewed website and some surprises reserved for the ones accepted in the conference. Jazoon is an international Java conference in the heart of Europe, for the ones looking for the quality of the technical content and a comfortable venue. You find better info in the conference website, but below you have the important shortcuts if you are a prospective Jazoon speaker.

Jazoon'10 - Jazoon'10 Call for Papers opened

JAZOON
Starting immediately the clock is running towards the submission deadline for the Jazoon'10 Call for Papers. You are invited to actively participate in the steering of the program of Jazoon'10.

Proposals for Short and Long Talks can be submitted within the scope of the technical sessions until 3 February 2010.

Submit a Short Talk (20 minutes)

Submit a Long Talk (50 minutes)

Proposals for Jazoon Rookie (20 minutes) can be submitted until 4 April 2010. Participating criteria and benefits can be found here.

Submit a Rookie Talk
(Speaker must be aged 26 or younger on 1 June 2010)

http://jazoon.com/Portals/0/Content/Logos/jazoon-logos/v3_jazoon_subt_black_web.jpg

A small JAXB puzzle: how to define a custom element to serialize Date objects with the TimeZone information? Piece of cake, isn't it? Try it yourself and you will be surprised with the tricky details.

A friend of mine gave me a JAXB challenge this week: his company already uses a customization of the xsd:date type in a legacy code - mapped to a proprietary type instead of the default Calendar type. Now they also need to represent Calendar objects in their application schema, so they need to model the date objects as a custom type. My first thought was about a five minutes hack, just defining an element based on the xsd:date and use the JAXB customization to map the new type to the Java Calendar type. After my five minutes I got few issues:

         
  1.      

    The default customization of Calendar in JAXB doesn't serialize      the Time information of a date. Ok, let's create a custom binder class      and hack the way we want to write and read our data.

         
  2.      
  3.      

    If you use xsd:dateTime instead of a simple xsd:date,      the default adapter of JAXB doesn't work anymore.

         
  4.      
  5.      

    Other surprise: you can't use the java.text.SimpleDateFormat      to serialize Date objects because the String representation of the      TimeZone provided by Java is not compatible with the XML specification.

                                                                                                                           
    - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") produces2009-12-06T15:59:34+0100
    - the expected format for the Schema xsd:dateTime type is2009-12-06T15:59:34+01:00
         

    You got the difference? Yes, the stupid missed      colon in the time zone representation makes the output of the      SimpleDateFormat incompatible with the XSD Schema specification. Yes,      unbelievable but you need to handle that detail programatically.

         

You can try by yourself but instead of proving you the details I wrote down my hack solution. If you know a more elegant solution, please give me your feedback. Remember the original problem: to not use the xsd:dateTime directly since it is already in use by other customization. Also: your customization should support a date and time representation, including the time zone.

Below you find a transcription of the sample project I created to illustrate the solution, to facilitate the copy paste and also to allow you to check the solution in case you don't want or you can't compile and run the project. Otherwise, just download the complete project. To compile and run the project, open a terminal and type the following line commands in the folder you unzipped the project:

mvn clean compile test eclipse:eclipse

The sample Maven project

         
  1.      

    First step, to create the maven project and configure the JAXB      plugin in the pom.xml. To create the project I used the Maven default      J2SE archetype:

         
    mvn archetype:create -DgroupId=cejug.org -DartifactId=jaxb-example
    mvn compile eclipse:eclipse
    
  2.      
  3.      

    Then you can import the project in your preferred IDE and      configure the JAXB plugin in the pom.xml:

         
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>cejug.org</groupId>
        <artifactId>jaxb-example</artifactId>
        <packaging>jar</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>jaxb-example</name>
        <url>http://maven.apache.org</url>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
        <pluginRepositories>
            <pluginRepository>
                <id>maven2-repository.dev.java.net</id>
                <name>Java.net Maven 2 Repository</name>
                <url>http://download.java.net/maven/2
                </url>
            </pluginRepository>
        </pluginRepositories>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.0.2</version>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                    </configuration>
                </plugin>
                <plugin>
                    <!-- https://jaxb.dev.java.net/jaxb-maven2-plugin/ -->
                    <groupId>org.jvnet.jaxb2.maven2</groupId>
                    <artifactId>maven-jaxb2-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>generate</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <schemaDirectory>${basedir}/src/main/resources/schema</schemaDirectory>
                        <!-- generateDirectory>${basedir}/src/main/java</generateDirectory-->
                        <includeSchemas>
                            <includeSchema>**/*.xsd</includeSchema>
                        </includeSchemas>
                        <strict>true</strict>
                        <verbose>false</verbose>
                        <extension>true</extension>
                        <readOnly>yes</readOnly>
                        <removeOldOutput>true</removeOldOutput>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    
  4.      
  5.      

    After that, I created the sample schema /jaxb-example/src/main/resources/schema/sample-binding.xsd:

         
    
    <?xml version="1.0" encoding="UTF-8"?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.w3.org/2001/XMLSchema http://www.w3.org/2001/XMLSchema.xsd"
         targetNamespace="http://cejug.org/sample"
         xmlns:sample="http://cejug.org/sample" elementFormDefault="qualified"
         xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
         xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
         jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.1">
        <xsd:annotation>
            <xsd:appinfo>
                <jaxb:globalBindings>
                    <xjc:serializable uid="-6026937020915831338" />
                    <jaxb:javaType name="java.util.Date"
                             xmlType="sample:sample.date"
                             parseMethod="org.cejug.binder.XSDateTimeCustomBinder.parseDateTime"
                             printMethod="org.cejug.binder.XSDateTimeCustomBinder.printDateTime" />
                </jaxb:globalBindings>
            </xsd:appinfo>
        </xsd:annotation>
    
        <xsd:element name="element" type="sample:element.type" />
    
        <xsd:complexType name="element.type">
            <xsd:sequence minOccurs="1">
                <xsd:element name="jdate" type="sample:sample.date" />
            </xsd:sequence>
        </xsd:complexType>
    
        <xsd:simpleType name="sample.date">
            <xsd:restriction base="xsd:dateTime" />
        </xsd:simpleType>
    </xsd:schema>
    
  6.      
  7.      

    Inspired by this      blog I created the custom binder org.cejug.binder.XSDateTimeCustomBinder:

         
    package org.cejug.binder;
    
    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class XSDateTimeCustomBinder {
        public static Date parseDateTime(String s) {
            DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
            try {
                return formatter.parse(s);
            } catch (ParseException e) {
                return null;
            }
        }
    
        // crazy hack because the 'Z' formatter produces an output incompatible with the xsd:dateTime
        public static String printDateTime(Date dt) {
            DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
            DateFormat tzFormatter = new SimpleDateFormat("Z");
            String timezone = tzFormatter.format(dt);
            return formatter.format(dt) + timezone.substring(0, 3) + ":"
                    + timezone.substring(3);
        }
    }
         
  8.      
  9. Then I created a JUnit class with the following test method:
    package cejug.org;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.Date;
    import java.util.GregorianCalendar;
    import java.util.TimeZone;
    
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.JAXBElement;
    import javax.xml.bind.JAXBException;
    import javax.xml.bind.Marshaller;
    import javax.xml.bind.Unmarshaller;
    import javax.xml.validation.Schema;
    import javax.xml.validation.SchemaFactory;
    
    import junit.framework.Test;
    import junit.framework.TestCase;
    import junit.framework.TestSuite;
    
    import org.cejug.sample.ElementType;
    import org.cejug.sample.ObjectFactory;
    import org.xml.sax.SAXException;
    
    public class JaxbSampleTest extends TestCase {
        private static final String UTF_8 = "UTF-8";
        private static final File TEST_FILE = new File("target/test.xml");
    
        public JaxbSampleTest(String testName) {
            super(testName);
        }
    
        public static Test suite() {
            return new TestSuite(JaxbSampleTest.class);
        }
    
        @Override
        protected void setUp() throws Exception {
            super.setUp();
            if (TEST_FILE.exists()) {
                if (!TEST_FILE.delete()) {
                    fail("impossible to delete the test file, please release it and run the test again");
                }
            }
        }
    
        public void testApp() {
            ObjectFactory xmlFactory = new ObjectFactory();
            ElementType type = new ElementType();
            Date calendar = GregorianCalendar.getInstance(TimeZone.getDefault())
                    .getTime();
            type.setJdate(calendar);
    
            JAXBElement<ElementType> element = xmlFactory.createElement(type);
    
            try {
                writeXml(element, TEST_FILE);
                JAXBElement<ElementType> result = read(TEST_FILE);
                assertEquals(calendar.toString(), result.getValue().getJdate().toString());
            } catch (Exception e) {
                fail(e.getMessage());
            }
        }
    
        private void writeXml(JAXBElement<ElementType> sample, File file)
                throws JAXBException, IOException {
            FileWriter writer = new FileWriter(file);
            try {
                JAXBContext jc = JAXBContext.newInstance(ElementType.class
                        .getPackage().getName(), Thread.currentThread()
                        .getContextClassLoader());
                Marshaller m = jc.createMarshaller();
                m.setProperty(Marshaller.JAXB_ENCODING, UTF_8);
                m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                m.marshal(sample, writer);
            } finally {
                writer.close();
            }
        }
    
        @SuppressWarnings("unchecked")
        public JAXBElement<ElementType> read(File file) throws JAXBException,
                SAXException, IOException {
            InputStreamReader reader = new InputStreamReader(new FileInputStream(
                    file));
            try {
                JAXBContext jc = JAXBContext.newInstance(ElementType.class
                        .getPackage().getName(), Thread.currentThread()
                        .getContextClassLoader());
    
                Unmarshaller unmarshaller = jc.createUnmarshaller();
                SchemaFactory sf = SchemaFactory
                        .newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
                Schema schema = sf.newSchema(Thread.currentThread()
                        .getContextClassLoader().getResource(
                                "../classes/schema/sample-binding.xsd"));
                unmarshaller.setSchema(schema);
    
                JAXBElement<ElementType> element = (JAXBElement<ElementType>) unmarshaller
                        .unmarshal(reader);
                return element;
            } finally {
                reader.close();
            }
        }
    }

That's it, I hope it can save your next five minutes of hack :)

When I comment in mailing lists that I am implementing a registration module for my application, hundreds of other developers comment they are coding exactly the same functionality in their projects - an indicator that something is missing in the Java EE Universe.

Registration is just an example, there are many others like notification, content repository management, etc. If you look for solutions to such problems you will find a lot of frameworks and products supplying solutions for separated parts of a common enterprise application. The point is, you can't can adopt one of this features without adopting the whole framework surrounding the feature and usually you can't or you dont'n want to do that. It is senseless to expect such specialized features included in the container specification, but at same time we should recognize that today it takes too long from the concept of a feature to production in a standard Java EE Server, and it is not a problem of the server, it is something else, something missing.

The game of the monolith

In my opinion, what is missed is a set of standardized components on top of which the frameworks will assemble its complete solutions. For example, think about the popular JBoss Seam, a beautiful framework isn't it? But now think on how to use just the authentication feature of JBoss in other framework, or the REST support or even the AJAX component of Seam. Is it possible to get advantage of such implementations in other frameworks like JSF without a painful migration path? I don't think so. That's the point: while JSF, Seam and other frameworks are doing a great job in offering complete solutions based on Java EE containers, each of these products has an independent set of features, and that features are non-compatible with the features of other products. More: the vendors behind these products need to code, test and guarantee somehow that each small feature is robust and good for your problem, resulting in a non-standardized market, full of sales speeches and religious arguments - a mess. A profitable mess I would say, but much less profitable than it would be. As far I see today, we have a Java EE container and in front of it we have a collection of frameworks incompatible whithin each other - a collection of monoliths.

                                 
          

A good analogy is perhaps the car industry,           where the engine of your car is built with sharable components. There           is no such thing like a motor full of pieces incompatible with any           other motors in the world. When the companies design cars, they check           the market to see what components are available and then design the           car (the solution) based on that components. The standardization of           such components is very complex but at least it provides the           guarantees we need to risk our lives inside the cars. And if you need           or want to change a some part of the motor of your car, you will get           surprised with how many options you have in a good car parts supplier           - all compatible with the components specification of your car.

          
http://blog.antiquetrader.com/blog/content/binary/eBay%20Monolith.jpg

Application level components

If you try to implement a basic Java EE feature by yourself, let's say the registration use case, it will cost you a lot of effort. Just try that: open your IDE and build a registration system without using any framework. It is easy to do, specially after Java EE 6, but write down the time you need to get it available on the screen. And include the amount of time you need to configure and deploy the solution - a simple login/logout/registration use case. Now, make another experiment: install Hudson and then install some plugins. How long it takes since you downloaded Hudson and get your plugins available for testing? Minutes, right? Where is the diference?

Obviously Hudson is a web application and not a generic server, but the key point is: Hudson provides more than just the infra-structure and an extensible API, it provides application level components. So, the Hudson application is running on your browser and if you want something else you just click a few buttons and that features will become fully integrated with the web application. That's what I dream for the next generations of Java EE containers, not only a robust and efficient solutions platform with standard connectors and interfaces, but mainly a set of components I can quickly add to any application - independent from the brand of the framework my application is based on.

* Everytime I think about it, I recall that such feature should be provided by independent vendors and should be away from any java EE specification. And after few minutes I also recall that such abstraction and simplicity leads the today market to a lack of alternatives other than monoliths. It is an open tought, I hope that one day I don't need to rethink about this anymore.. the day where my Glassfish will have a pane full of fancy features, like Twitter notification, registration use case out of the box, GMail integration and many others plugins. I am pretty convinced that a server offering such goodies will dominate the market as quick as Hudson did few years ago.

With the newcomer Vaadin module I updated the Arena Project script to support builds on Windows platform. Not a big deal in terms of configuration but it is worthy a notification in case you had tried to build the project before and got frustrated with the Platform Classifier restricted to the UNIX-family.

Why to use Platform Classifiers? The lack of a good Maven support for the Glassfish Command Line Utility for Administration (a.k.a. asadmin) forced me to adopt a shell script to execute some complementary steps to my Maven build - then I added some MySql commands as well. After testing the script on Linux,  I translated the script to Windows.

Please help in testing the portable build script

Arena PUJ is open-source and you can checkout and build all its artifacts in few minutes, so if you have ten minutes to donate to my project, please follow this instruction and send me your feedback .

It is still a work under progress but I plan to have a stable script for Linux and Windows before my presentation at JFokus.

http://www.thedigitalaviator.com/blog//wp-content/uploads/i-stress-test1.jpg

Now available in two flavors!

Filter Blog

By date: