Skip navigation
1 2 3 Previous Next

felipegaucho

142 posts

Felipe Viera Silva (aka Felipe Gaúcho) passed away on 5 March 2010.

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 asadmincommand 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 thePATH 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 JavaMailresource.

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 andpassword=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\libfolder.

  • 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 ofasadmin 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. jdbc/classifieds - a MySQL Data Source

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

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

  5. NotificationQueueConnectionfactory - the notification JMS Queue.

  6. RegistrationQueueConnectionfactory - the registration JMS Queue.

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

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 theasadmin 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. 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
      
  3. 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 fileusing this resource.

Creating JMS resources with asadmin

Messagingis 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. 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.

  3. 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. 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 asadmincommands

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. 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

  3. Use CALL for executing the asadmincommands 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
    
  4. You can also delete the Glassfish resources with theasadmin 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 byNachiappan. 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. 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).

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. To configure Jersey to use the JSON natural notation instead of the default JAXB format.
  3. 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 safetraditional way, using a pure HTTP Request. When you access the URLhttp://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.

CDIis 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 Ludofor all hints about this little issue.

* Thanks Dominik Dornfor calling my attention to a file I believed onlyavailable 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

Quickies

  • Jfokus team: fantastic people! Mattias, Helena and all the conference team, thank you!
  • Jfokus conference: excellent!
  • Graph DB is buzz word, Emil Eifrem an unique character.
  • Ed Burns, Toni Epple and Laforge, we missed you guys.
  • Scrum loosing value due to the excessive number os Scrum masters out there. Dan North and other famous Scrum evangelists were demonstrating frustration on the way Scrum is being adopted in the market - as just another certification that can mean anything. The most of presentation was not about how to adopt Scrum but why it is not enough. I guess it is becoming difficult for the consultants to earn the easy money of two years ago, and they are joking themselves while creating another models. I heard words like scruminist and waterscrum but it still hype. Kanban was promoted, Pomodoro technique as well - the endless cycle of the new management recipes.
  • Oracle will discontinue Kenai.
  • Agile languages desperate trying to prove its superior qualities but all questions are answered with planned features or features that will come some day. Incomplete tools trying to catch adoption with future promises.
  • Emily and the usefulness of test driven development.
  • Security, security and security - how to save yourself from the JSONP on the cloud?
  • Java EE 6 - hype !
  • Groovy - hype !
  • Re-focus on programming quality - hype !
  • NoSql - hype

It seems nowadays everyone wants to get rid off Java and relational databases, but there is nothing yet done to replace such profitable technologies. From the other side, Java counter attack with Java EE 6 and the JPA 2.0 makes OO-RDBMS easier than ever. I am not sure if or when the agile movment will be able to replace Java in the market, but I know their attempt is making our preferred technology everyday better - thank you for that.

My conference tourism report

Stockholm is a charming city forged with the Viking spirit, money and the best education I've ever observed in my life. People are friendly and the city offers a lot of interesting spots for the tourists - everyone speaks English and I didn't have any communication problems over there. I skipped half of the tutorial day to walk in the small streets of the old town and it was worthy every step. The Vasa museum is a remarkable spot and the small streets full of shops, bistros and historical references brought me joyful moments - I sent some SMS to my wife planning our vacation trip to Sweden asap (perhaps matching the next year's Jfokus). For a traveler and old surfer like me, definitely a place I will recommend for friends and family.

Hotel and venue

I were hosted in the Rica Hotel, just 100 meters from the Filmstaden Sergel, the conference venue. Everything worked as planned both in the hotel and in the venue, and the proximity of the conference and the free wireless Internet in the hotel made my three days in Stockholm very comfortable, and the breakfast buffet was another remarkable feature of the hotel :). In the second day of the conference the film city proved to be too small for supporting almost a thousand people and the Wi-Fi stopped to work - but nevertheless the rooms were quite comfortable and everyone had a great time. The conference food and beverage were excellent as well. The Jfokus team was outstanding in offering a great experience for the conference attendees - more impressive when you realize they are developers and JUG members and not professional conference organizers.

The conference tutorials

The first day was dedicated to three hours tutorials, and I've chosen the speech of Kevlin Henney about GOOD: Good Object-Oriented Development. It was excellent, the speaker is an English native speaker and he used his language skills to entertain us during a guided tour through the Object Orientation concepts. Even for an experienced developer it was really worthy to recall all important aspects on how to treat software design with care and quality. I recommend that presentation if you have the privilege to meet Mr. Henney in a next conference. I was also surprised to know that the British gentleman has Brazilian roots as well - and much more surprised to see a slide in Brazilian Portuguese during his presentation ("povo" - plain old value object).

After the excellent presentation I had a short talk with Alexis Moussine-Pouchkine from Sun Microsystems. Our lunch was all about Glassfish and I also demonstrated to him my Arena project and we talked about the java EE future, Oracle acquisition and other topics. I know Alexis for a long time, it was nice to have some minutes to talk freely about Java and software trends in general. At the end we agreed the new money injection from Oracle can bring a wonderful future to Glassfish - a lot of opportunities for the developers. After the lunch I decided to skip the afternoon of tutorials to visit Stockholm, my very first visit to Sweden. I walked for three hours throughout the amazing downtown, and then I got back to the hotel very satisfied, freezing by the scandinavian wind with some gifts to my family. In the evening the Jfokus invited me to the speakers' dinner.

The speakers' dinner: Mattias Karlson and his team treated us as VIPs during all the conference and the speakers' dinner deserves a bold remark. The moments at the Fredsgatan 12 were splendid, great food, great conversations and everyone treated like a king. Mattias himself was the image of a happy man, going from table to table to celebrate the Java moment with all speakers - enhanced with the biggest smile of the Sweden after the SMS from Joshua Bloch :). Jfokus gave us the best hospitality we could imagine and I am sure that atmosphere motivated great speeches in the next day. It was the first time I tasted duck, for the surprise of my French colleagues saying "yes, it is duck and it is very good, why?". I just explained that duck is not a common dish in Brazil and that superb first experience will certainly include duck in my preferred menu. The champagne, the wines (including the surprising cinnamon wine) and the friendship will remain in my memory forever.

Second day

The second day of the conference included my speech, but I planned to attend other sessions to relax and to restore my English accent. Cameron Purdy from Oracle had the privilege of the Keynote, talking to us about JRockit and some new trends of Java, specially the optimizations on the JRE class loader and the JDK byte code compiler. A good speech, interrupted five minutes before the end due to a technical issue. At that moment I got the impression that Jfokus team deserved a better support from the venue managers. J-man appeared in the middle of the crowd, proving that sometimes the picture is a bit different from the real character :), but he did a great job making people to talk about Java and about the conference. The venue was fulfilled of booths, including local companies and some traditional big vendors like Oracle, Microsoft and Google. There was some surprises like bwin, a popular beat site here in Europe. I asked the booth girl about a cassino-like company in a Java conference and she confessed their site is done with Java - good to know that my bets are being processed in the proper way. They also promoted a poker tournament after the event, but I am just too bad playing poker to risk that one.

Gertjan was there making another corridor film from a conference and my old friend Roman Strobl was there with the JetBrains team, nice to hear about them again. And I also had the privilege to talk with the Vaadin developers I met before through their mailing lists. We discussed aspect of security and I collected my second Book of Vaadin, a blue covered pocket book about the 6.2 edition of the Vaadin Framework. Still in the Vaadin topic, I attended the session of Joonas Lehtinen talking about RIA Security - Broken By Design. Nice hints, including some live demo of hacking RIA applications using firebug. I did some networking during a good lunch and my afternoon started with the Dan North speaking about Why Your Agile Roll-Out is Failing. Good speech, good humor and nice hints from an experienced Agile Methodologies consultant. After that it was my time to concentrate, I went back to the hotel for a last minute relaxation and presentation review. Four o'clock I was in the Salong 14 for my presentation but just before my schedule Mr. Ellnestam talked 15 minutes in Swedish about leadership. I couldn't understand a word of the Viking-Avatar language they use in Sweden, but during the speakers' dinner Ola Ellnestam explained briefly his topic and judging from the public reaction I would say he did a great job.

My presentation

My presentation host was Mr. Staffan Nöteberg and this time everything worked, the notebook connected the beamer without any problem, the presentation finished just in time and my connection with the public was very friendly and natural. I have two polemic topics in the design I demonstrated on the stage: Anemic Domain Model andREST with JAX-RS. I am working around several issues raised from these technologies using the relational database as flexible structure, and it is sometimes controversial. Nevertheless, I presented all sections of my work and the public was quite receptive. I asked how many of them are familiar with some technologies:

  • JPA: almost all of them.

  • JAXB: ~80%

  • HATEOAS: ~20%

I introduced the Arena Project and then I explained how to use the JPA and JAXB together to expose the database on the HTTP layer. I concluded the session explaining the HATEOAS concept and how I plan to solve the issue of having dynamic interfaces in Java. I finished three minutes before my deadline, time enough to collect some feedback.

Feedback: I received a friendly feedback just after the presentation, and more good vibes later on twitter. On the stage I also listened Rickard Öberg from Jayway explaining how they are solving HATEOAS with Java using annotations and DSL to produce a rules based framework. Later during the conference party, he talked with me and also commented he didn't like the idea of using an anemic domain model. Excellent feedback, but unfortunately the framework is proprietary and we cannot check its details online. I hope they publish at least their solution outline in a blog to allow us to think better about it. I loved to speak in Sweden for sure I will submit a paper next year as well.

After dark party and Oracle announcement

After the conference everyone went to a pub few blocks from the venue, and the beer did the job. I was officially waiting for theIndigo show and for the Oracle announcement. The band was really good, the conversation with a lot of smart people is always a joy, and then we had the Oracle moment. I joke with Henrik Kniberg (the kanban speaker) about geeks playing guitars in a java conference, but I should confess their cover band performed really well. The Oracle announcement brought us a good perspective for the future of Java, but this is a topic for another blog.

Thank you Jfokus

The conference was great, there are a lot of smart people I would quote here, but I prefer just to extend my best impressions for all people from Sweden. An amazing country you have out there, please keep it like that - and see you next year during the next year Jfokus.

http://lh4.ggpht.com/_vYDxU6jxckI/S2QZS-mwCDI/AAAAAAAAApM/0Vhsbh_yuHc/s912/dsc02245.jpg
Me and Mattias Karlsson, the Chief of the Conference during the speakers dinner.

http://lh4.ggpht.com/_vYDxU6jxckI/S2QZVeEORxI/AAAAAAAAApg/wfQexMzH3x4/s128/dsc02211.jpg
http://lh6.ggpht.com/_vYDxU6jxckI/S2QZFpz7B9I/AAAAAAAAAns/ShpREE2gMSs/s128/dsc02206.jpg
http://lh6.ggpht.com/_vYDxU6jxckI/S2QZIecYciI/AAAAAAAAAoE/5ZSqq043i-k/s128/dsc02248.jpg
http://lh4.ggpht.com/_vYDxU6jxckI/S2QZMFErTTI/AAAAAAAAAoc/AywbKuyBofo/s128/dsc02219.jpg
http://lh3.ggpht.com/_vYDxU6jxckI/S2QZWO5GBAI/AAAAAAAAApk/nu8wTHHk6PY/s128/dsc02234.jpg
http://lh6.ggpht.com/_vYDxU6jxckI/S2QZcg5vY3I/AAAAAAAAAqM/fortk3gl4bk/s128/dsc02209.jpg
http://lh4.ggpht.com/_vYDxU6jxckI/S2QZsMMzJxI/AAAAAAAAAr8/UwjZuYV5Su0/s128/dsc02286.jpg
http://lh4.ggpht.com/_vYDxU6jxckI/S2QaDzy0LiI/AAAAAAAAAuc/9Z9cu3fIKRY/s128/dsc02395.jpg
http://lh5.ggpht.com/_vYDxU6jxckI/S2QaUlDeIOI/AAAAAAAAAwE/DtvriHv7xFY/s128/dsc02368.jpg
http://lh6.ggpht.com/_vYDxU6jxckI/S2Qa727yzLI/AAAAAAAAA0A/s6oN5GlClTM/s128/dsc02278.jpg
http://lh5.ggpht.com/_vYDxU6jxckI/S2Qa2Hn4a2I/AAAAAAAAAzc/0Ab4hVdtwzA/s128/dsc02280.jpg
http://lh6.ggpht.com/_vYDxU6jxckI/S2QakKqJz6I/AAAAAAAAAxo/MJJMrnuQjNY/s128/dsc02311.jpg
http://lh4.ggpht.com/_vYDxU6jxckI/S2QZ-C63EDI/AAAAAAAAAt0/mkUA_PfjHyM/s128/dsc02296.jpg
http://lh6.ggpht.com/_vYDxU6jxckI/S2QZRPjp96I/AAAAAAAAAo8/dL-KyyplKE4/s128/dsc02216.jpg
http://lh5.ggpht.com/_vYDxU6jxckI/S2QZ1g1eovI/AAAAAAAAAs4/Rl9vnyOb93M/s128/dsc02264.jpg
http://lh4.ggpht.com/_vYDxU6jxckI/S2Qa7fViBJI/AAAAAAAAAz8/yIwLRl2HJSg/s128/dsc02261.jpg
http://lh3.ggpht.com/_vYDxU6jxckI/S2QZKRlFesI/AAAAAAAAAoQ/0FPaTilE63I/s128/dsc02244.jpg
more photos...

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 desperategrowing 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 deadspeech 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,tendinitisand 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. Offer learning as part of the job benefits (conferences, books, courses, etc).
  3. Allow your developers to take project decisions.
  4. Use modern Java technologies (Still using Java 1.4?)
  5. Give the developers some stability and carrier perspective, and don't try that in a bureaucratic way.
  6. Flexible working time and remote office should be available.
  7. 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 :)
  8. Don't try poor copies of Google and IBM ideas, these companies are just richer than yours. Be creative and honest with your developers.

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.

http://i222.photobucket.com/albums/dd10/tagblog/game_monkeys.jpg

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. 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. include the following entry:
    3. 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 v3and Maven 2.x

  2. Download the sample project and unzip it somewhere

  3. 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

  4. 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 youlazy 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. Create a pom.xml file in the project root folder, with the following content:
  3. 
    <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>
       
    
  4. 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. If you use xsd:dateTime instead of a simplexsd:date, the default adapter of JAXB doesn't work anymore.

  3. Other surprise: you can't use thejava.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. Then you can import the project in your preferred IDE and configure the JAXB plugin in thepom.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>
    
  3. 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>
    
  4. Inspired by this blog I created the custom binderorg.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);
        }
    }
       
    
  5. 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 toconfigureand deploy the solution - a simplelogin/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.

This week I received one of that lovely and tricky tasks: to learn Canoo webtest, test it and prove its usefulness to the project in three days - convincing the managers that it should be part of the project. The goal of the project is to produce a finance report with ~200 pages and that report should be validated through azero-errors acceptance test. Several tools were considered, including Selenium and others, but Canoo was choosen due to its PDF test features.

Testing PDF documents with Maven & Canoo webtest

Canoo webtest can be used in three different ways:

  • Ant task: this is the original and very well documented webtest distribution. There is only one gotcha: the ant task depends on a library which you need to copy locally somewhere.

  • Groovy + GMaven: there is an entry in the Marc Guillemot's blog explaining how you can code your webtest in Groovy instead of using ANT. It is a perfect choice if you are already using Groovy but in my case an extra language would cost unnecessary explanations in the technical meeting :)

  • WebTest Maven2 Plugin: the webtest-maven-plugin is a pure Maven plugin that enables your application to test the generated PDF files without any dependencies to local artifacts and without the need to add Groovy to the technology set of your project. That's the way I was looking for and that's my prime choice.

After a first hour of euphoria the things started to get muddy with the configuration of the maven plugin. I am not sure if due to the tight deadline or just because of the scarce documentation on the web, but nevertheless after joining the mailing list of Canoo I started to find my way.

Maven configuration

    

<dependencies>
    <dependency>
        <groupId>com.canoo.webtest</groupId>
        <artifactId>webtest</artifactId>
        <version>3.1-SNAPSHOT</version>
        <scope>integration-test</scope>
    </dependency>
</dependencies>
<repositories>
    <repository>
        <id>webtest_dependencies_snapshot</id>
        <name>WebTest dependencies</name>
        <url>http://webtest.canoo.com/webtest/m2-repo-snapshots</url>
    </repository>
    <repository>
        <id>codehaus</id>
        <name>codehaus</name>
        <url>http://repository.codehaus.org</url>
    </repository>
    <repository>
        <id>ibiblio.mirrors</id>
        <url>http://mirrors.ibiblio.org/pub/mirrors/maven2</url>
    </repository>
</repositories>
<reporting>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>webtest-maven-plugin</artifactId>
        </plugin>
    </plugins>
</reporting>
http://www.canoo.com/images/logos/logo-webtest.png

The webtest configuration

The configuration of the test was a bit complicated because I couldn't find a runnable example on the web (the main motivation to this blog entry). After two days translating the ant samples to maven I finally got the below configuration. I believe other enhacements can be done in order to make the whole solution more elegant, but so far it does the job and I have my presentation ready for the managers ;)

<project name="Canoo Webtest Sample" basedir="." default="all">
    <target name="all">
        <ant antfile="checkPageCount.xml" /> <!-- 1 test per PDF page -->
        <ant antfile="checkWatermark.xml" />
    </target>
</project>

A test example, a simple test to check if the PDF contains a watermark with the word java.net

<project default="test">
    <property name="pdf.file" value="${basedir}/foo.pdf" />

    <taskdef resource="webtestTaskdefs.properties" />
    <target name="test">
        <webtest name="watermark">
            <config protocol="file" summary="${summary}" saveresponse="false"
                resultpath="${resultpath}" resultfile="${resultfile}"
                haltonfailure="${haltonfailure}" haltonerror="${haltonerror}"
                showhtmlparseroutput="${showhtmlparseroutput}"
                autorefresh="${autorefresh}" />
            
            <steps>
                <invoke description="get PDF document" url="${pdf.file}" />
                <pdfVerifyText description="Check watermark" 
                    text="java.net" startPage="1" endPage="1" />
            </steps>
        </webtest>
    </target>
</project>

Download the complete example

Here you can download the complete example, it only requires Maven 2 and should work out of the box. any problems trying that, please let me know. In order to run the example, please follow the below steps:

  1. Download and unzip the sample application.
  2. Open a console, go to the folder you unziped the application and type:
  3. mvn install eclipse:eclipse
  4. mvn webtest:clean webtest:test webtest:report

Done, you will find the report in the file.\myWebTestApp\target\site\webtest\index.html

Acknowledgments

I received a helpful support from the Webtest mailing lists, with special thanks to Christoph Lipp, nodjeand Marc Guillemot. My task is not yet finished but the support of those community members was fundamental to my first success using Canoo webtest.

Blog UPDATE: Canoo published a set of new samples, available here. Take the latest version, unzip and look in the foldersrc/test, specially the example it8 about PDF testing.

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 theUNIX-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!