Sunday, July 25, 2010

GWT 2.1: logging API

One of the new functionality implemented into GWT 2.1 M2 is a Java logging API. The development team doesn't choose to implements a new API, but to use the logging API provided by Java SDK by emulating it. So, to use it, you just should create a logger as usual in your class and use it like that:


public class Gwt_log implements EntryPoint {
// create the logger
private static final Logger logger = Logger.getLogger(Gwt_log.class.getName());

public void onModuleLoad() {
// use it
logger.info("Module is loading");
}
}


As usual in GWT, your module, to use this API, must inherit from the logging module:

<inherits name='com.google.gwt.logging.Logging'/>

Inherit from this module set a numerous properties dedicated to logging API:
  • gwt.logging.enabled: enable or disable logging API, set to TRUE by default,
  • gwt.logging.logLevel: logging level, by default, set to INFO. Other available values are: ALL, FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE,
  • gwt.logging.consoleHandler: log message into the IDE console, by default, set to ENABLED. It doesn't have any effect in production mode,
  • gwt.logging.developmentModeHandler: log message into dev mode console. By default, set to ENABLED,
  • gwt.logging.firebugHandler: log message into Fiebug console. By default, set to ENABLED,
  • gwt.logging.popupHandler: log message into a popup window into the GWT application. By default, set to ENABLED,
  • gwt.logging.systemHandler: log message with a level upper than WARNING on System.err, else, on System.out. By default, set to ENABLED,
  • gwt.logging.simpleRemoteHandler: log message on server side by using a service defined by GWT. By default, set to ENABLED.
To use the remote logging capabilities of GWT, an additional effort is needed. GWT provides a service that logs message on server side. It implements a simple delegate log, by using the standard Java logging API, of the messages logged on client side. So, the logging on server side can be configured in any manner you usually do. You only need to declare the service into the file web.xml as following:
<servlet>
<servlet-name>remoteLogger</servlet-name>
<servlet-class>com.google.gwt.logging.server.RemoteLoggingServiceImpl</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>remoteLogger</servlet-name>
<url-pattern>/gwt_log/remote_logging</url-pattern>
</servlet-mapping>

In future post, I will explain how to use the MVP framework, the validation API, the new paging table widgets, and the new binding mechanism between client and server.

For other feature, have a look to: GWT 2.1: validation API.

Friday, July 23, 2010

DAO or not DAO? This is the question...

In a multi tiers architecture application, data access are managed by dedicated object, called: Data Access Object, aka DAO. They are responsible how to connect to data store and brings functionalities for making operation on data. For the following explanation, I will use JPA as ORM.

DAO approach

A general way to implement the DAO layer is a parametrized interface defining contract for CRUD operations:

public interface GenericDao<E, PK> {
E findByPrimaryKey(PK pk);

void save(E entity);

void update(E entity);

void delete(E entity);
}

And now, we define an abstract class implementing a JPA dedicated DAO. The default constructor is used to determine the type of the entity and the primary key type, that allows to implement CRUD operation:

public abstract class JpaDao<E, PK> implements GenericDao<E, PK> {

private EntityManager entityManager;

public JpaDao() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
this.entityType = (Class<E>) genericSuperclass.getActualTypeArguments()[0];
}

protected EntityManager getEntityManager() {
return entityManager;
}

public E findByPrimaryKey(PK pk) throws DataAccessException {
return entityManager.find(entityType, pk);
}

public void save(E entity) throws DataAccessException {
entityManager.persist(entity);
}

public void update(E entity) throws DataAccessException {
entityManager.merge(entity);
entityManager.flush();
}

public void delete(E entity) throws DataAccessException {
entityManager.remove(entity);
}

public List<E> findAll() throws DataAccessException {
Query query = entityManager.createQuery("SELECT e FROM " + entityType.getName() + " AS e");
return query.getResultList();
}
}

This implementation forces to get one DAO per entity, even in case non additional operations are needed. And separate DAO and entities encourages AnemicDomainModel discussed by Martin Follower. In this case, entities are only by bag of getters and setters without any behavior.

Brings DAO functionalities to entities

My proposal is to implement a utility class to manage data access. A kind of generic DAO.

Utilities for DAO implementation

This class has to be a singleton that shares an EntityManager between every entities. It implements too methods to create and commit transaction. Generic functions are implemented fro CRUD operation and takes a entity class object as parameter to apply CRUD on entity class:

public final class EntityUtility {
private EntityManager entityManager;

private static EntityUtility instance = new EntityUtility();

public static EntityUtility instance() {
return instance;
}

public final EntityManager getEntityManager() {
return entityManager;
}

public final void setEntityManager(EntityManager em) {
entityManager = em;
}

public <T> List<T> find(Class<T> entityClass, String where, Object... values) {
EntityTransaction transaction = getEntityManager().getTransaction();
transaction.begin();
StringBuilder builder = new StringBuilder("SELECT e FROM ");
builder.append(entityClass.getName());
builder.append(" AS e WHERE ");
builder.append(where);
Query query = getEntityManager().createQuery(builder.toString());
for(int i = 0; i < values.length; i++) {
query.setParameter(i + 1, values[i]);
}

List<T> result = query.getResultList();
transaction.commit();
return result;
}

public <T> List<T> findAll(Class<T> entityClass) {
EntityTransaction transaction = getEntityManager().getTransaction();
transaction.begin();
StringBuilder builder = new StringBuilder("SELECT e FROM ");
builder.append(entityClass.getName());
builder.append(" AS e");
Query query = getEntityManager().createQuery(builder.toString());
List<T> result = query.getResultList();
transaction.commit();
return result;
}

public <T> void save(T entity) {
EntityTransaction transaction = getEntityManager().getTransaction();
transaction.begin();
getEntityManager().persist(entity);
transaction.commit();
}

public <T> void delete(T entity) {
EntityTransaction transaction = getEntityManager().getTransaction();
transaction.begin();
getEntityManager().remove(entity);
transaction.commit();
}

public <T> void refresh(T entity) {
EntityTransaction transaction = getEntityManager().getTransaction();
transaction.begin();
getEntityManager().refresh(entity);
transaction.commit();
}

public <T> void update(T entity) {
EntityTransaction transaction = getEntityManager().getTransaction();
transaction.begin();
getEntityManager().merge(entity);
transaction.commit();
}
}

Entity superclass

To bring data access capabilities to entities, I need a class to bring CRUD methods implementation to entity classes. This class should provide implementation for creation, deletion and update methods:


public class Model {
protected static EntityUtility utility = EntityUtility.instance();

public final void save() {
utility.save(this);
}
public final void refresh(){
utility.refresh(this);
}
public final void update() {
utility.update(this);
}
public final void delete() {
utility.delete(this);
}

Entity implementation

Methods such find and findAll should be implemented as static method in entity level, but use EntityUtility functionality that provides methods to find entities by using where clause passed as parameter:

@Entity
public class User extends Model {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public Long getId() {
return id;
}

public static List<User> find(String where, Object... values) {
return utility.find(User.class, where, values);
}

public static List<User> findAll() {
return utility.findAll(User.class);
}
}

Conclusion

In this case, entities should inherit a class. It could be seen as a regression as JPA brings ORM POJO based implementation. But the Model class gives ORM functionalities such:

  • persistence
  • remove
  • refresh state
  • update

Model miss methods for search functionalities. So, Entity classes can implement static methods as delegate of EntityUtility methods.

Friday, July 16, 2010

New GWT versions

GWT 2.0.4 is available

Apple has recently released Safari 5, which include a bug where non-integral right-shifts were not being evaluated properly.
In case you experienced this bug, you need to recompile and redeploy your application.
The release is available here.

GWT 2.1 Milestone 2

This new version brings some improvement of the previous milestone:
  • simplification the process of configuring a RequestFactory
  • made record creation within a RequestFactory more extensible
  • moved project out of bikeshed
A full list of new festure and bug fixed can be found here.
The milestone is available here.

Spring 3 et Rest

C'est seulement depuis la version 3.0 de Spring que le MVC supporte les services Rest. Biensur, le framework intègre les principales implémentations tel Jersey ou Restlet, mais dans la partie concernant les web services. La décision d'ajouter une implémentation Rest dans Spring MVC vient de l'orientation prise par le framework:

  • les méthodes des contrôleurs fournissent des vues en résultat
  • des annotations trés similaires à celles de Rest permettent:
    • le binding d'une URL vers un contrôleur
    • le binding des paramétres vers les arguments des méthodes d'un contrôleur

Configurer l'application web

Pour commencer, il faut déclarer le DispatcherServlet dans le fichier de configuration de l'application web: web.xml.

<web-app>

<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/app-config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

</web-app>

En lui spécifiant le paramètre contextConfigLocation, la servlet va charger le context Spring a sa création. Le fichier de context se trouve: /WEB-INF/spring. La servlet doit mapper toutes les URLs du type:

<app_context>/services/*

Configuration Spring

La configuration Spring se fait en deux fichiers différents:

  • le context principal, le fichier app-config.xml, qui contient la configuration du backend: DAO, services et mappers.
  • le context MVC, dans le fichier mvc-config.xml, qui contient la configuration... du MVC.
<beans xmlns="<a class="external free" title="http://www.springframework.org/schema/beans" rel="nofollow" href="http://www.springframework.org/schema/beans">http://www.springframework.org/schema/beans</a>"
xmlns:xsi="<a class="external free" title="http://www.w3.org/2001/XMLSchema-instance" rel="nofollow" href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>"
xmlns:mvc="<a class="external free" title="http://www.springframework.org/schema/mvc" rel="nofollow" href="http://www.springframework.org/schema/mvc">http://www.springframework.org/schema/mvc</a>"
xsi:schemaLocation="
<a class="external free" title="http://www.springframework.org/schema/beans" rel="nofollow" href="http://www.springframework.org/schema/beans">http://www.springframework.org/schema/beans</a>
<a class="external free" title="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" rel="nofollow" href="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">http://www.springframework.org/schema/beans/spring-beans-3.0.xsd</a>
<a class="external free" title="http://www.springframework.org/schema/mvc" rel="nofollow" href="http://www.springframework.org/schema/mvc">http://www.springframework.org/schema/mvc</a>
<a class="external free" title="http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" rel="nofollow" href="http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd</a>">

<mvc:annotation-driven />

</beans>

Cette configuration permet d'utiliser l'annotation @Controller pour déclarer les beans gérés par Spring MVC.

Implémentation d'un contrôleur

L'exemple suivant se base sur la gestion d'objets SampleBean:

public class SampleBean {

private String name;
private long id;
}

Et utilise le SampleController pour effectuer une recherche par id sur les SampleBean.

@Controller
@RequestMapping("/sample")
public class SampleController {

@RequestMapping(value="{id}", method=RequestMethod.GET)
public @ResponseBody SampleBean get(@PathVariable long id) {
return persistence.get(id);
}
}
  1. L'annotation @RequestMapping("/sample") sur la classe permet de mapper toutes les requêtes du type /services/sample sur ce contrôleur. /services étant l'URL sur lequel le DispatcherServlet est mappé.
  2. L'annotation @RequestMapping(value="{id}", method=RequestMethod.GET) sur la méthode get spécifie cette méthode sera appelé pour toutes les URL pouvant mapper avec /services/sample/4 pour les requêtes dont la méthode est GET.
  3. L'annotation @PathVariable permet de spécifier que l'une des valeurs ente {} de l'URL doit être mapper sur cette variable.
  4. @ResponseBody permet de déclarer que la valeur de retour de la méthode sera renvoyer dans le corps de la réponse. Reste à le convertir dans un format quelconque.

Mapper le résultat vers un format spécifique

Pour mettre en place la convertion, il faut configurer un bean de type ContentNegotiatingViewResolver. En Rest, l'opération de mapping des valeurs de retour et des paramètres vers des objets s'appel: négociation. La négociation se fait en ce basant sur la valeur du header Accept de la requête. Pour cet exemple, le mapping se fera vers du JSon. le header Accept aura donc pour valeur: application/json. Spring fournit parmis ces dépendances, le parseur Jackson, qui est utiliser dans ce qui suit:

 <bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" p:order="1">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>

La configuration se fait en spécifiant les formats supportés avec l'attribut mediaTypes et les implémentations des mappers ave la propriété defaultViews. La propriété mediaTypes correspond au contenu du header Accept de la requête reçu par le DispatcherServvlet.

Flexmojos et les charts

Une configuration standard du plugin Flexmojos ne permet pas de compiler des charts. La compilation renvoie l'erreur suivante:

[ERROR] Could not resolve <mx:linechart> to a component implementation.

Les dépendances nécessaires ne sont pas disponibles sur un repo Maven. Il faut les ajouter dans le repo local à partir d'une installation du SDK Flex.

Pour commencer, il faut ajouter les dépendances dans le fichier Maven:

<dependency>
<groupid>com.adobe.flex.sdk</groupid>
<artifactid>datavisualization</artifactid>
<type>swc</type>
<scope>merged</scope>
<version>3.2.0.3958</version>
</dependency>
<dependency>
<groupid>com.adobe.flex.sdk</groupid>
<artifactid>datavisualization</artifactid>
<version>3.2.0.3958</version>
<type>rb.swc</type>
<classifier>en_US</classifier>
</dependency>

La seconde dépendances permet d'éviter l'erreur de compilation:

Unable to resolve resource bundle "charts" for locale "en_US".

Ensuite, il faut rajouter les dépendances dans le repo Maven local:

mvn install:install-file -DgroupId=com.adobe.flex.sdk
-DartifactId=datavisualization
-Dversion=3.2.0.3958
-Dpackaging=swc
-Dfile="/Applications/Adobe Flex Builder 3/sdks/3.2.0/frameworks/libs/datavisualization.swc"

Ensuite, il faut rajouter le ressource bundle:

mvn install:install-file -DgroupId=com.adobe.flex.sdk
-DartifactId=datavisualization
-Dversion=3.2.0.3958
-Dclassifier=en_US
-Dpackaging=rb.swc
-Dfile="/Applications/Adobe Flex Builder 3/sdks/3.2.0/frameworks/local/locale/en_US/datavisualization_rb.swc"

Si le scope de l'artifact datavisualization n'est pas mis à merge, l'application compilera, mais l'erreur suivante arrivera à l'exécution:

VerifyError: Error #1014: Class mx.charts::LineChart could not be found.

Il reste encore un problème à résoudre: la licence. Avec la configuration actuelle, les charts vont être affichés avec le message: Trial Visualization.

Il faut configurer le pom pour qu'il utilise la licence à la compilation:

<build>
<sourcedirectory>src/main/flex</sourcedirectory>
<plugins>
<plugin>
<groupid>org.sonatype.flexmojos</groupid>
<artifactid>flexmojos-maven-plugin</artifactid>
<version>3.5.0</version>
<extensions>true</extensions>
<configuration>
<contextroot>/appcontext</contextroot>
<debug>true</debug>
<licenses>
<flexbuilder3>nnnn-nnnn-nnnn-nnnn-nnnn-nnnn</flexbuilder3>
</licenses>
<sourcefile>App.mxml</sourcefile>
<targetplayer>9.0.124</targetplayer>
</configuration>
<dependencies>
<dependency>
<groupid>com.adobe.flex</groupid>
<artifactid>license</artifactid>
<type>jar</type>
<version>3.2.0.3958</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

La dépendance ne doit être rajouté qu'au plugin, pas au projet.

Le jar nécessaire à la licence n'est pas disponible non plus sur un repo maven, il faut donc l'installer à partir d'une installation Flex avec la commande suivante:

mvn install:install-file
-DgroupId=com.adobe.flex
-DartifactId=license
-Dversion=3.2.0.3958
-Dpackaging=jar
-Dfile="C:\Program Files\Adobe\Flex Builder 3 Plug-in\sdks\3.2.0\lib\license.jar"

Aprés une compilation, les charts s'afficheront sans le message de trial.

Intégration Spring Flex

Spring Source a présenté l'année dernière à SpringOne, son projet d'intégration Spring et Flex, Spring Flex. Ce projet veut simplifier la mise en place d'un backend Spring derrière BlazeDS, le message broker free de Adobe. L'exemple suivant décrit les fichiers de nécessaires pour une configuration standard avec des Remote Object.

Fichier Maven

Le plugin utilisé pour compiler Flex est FlexMojos.
Sans passer par l'intégration de Spring Flex, il faut déclarer chaque jar BlazeDS comme dépendance, ce qui fait une demi douzaine de dépendances au total, Adobe n'ayant pas géré les dépendances entre les modules de BlazeDS.
Le fichier Maven de Spring Flex référence tous les modules nécessaires de BlazeDS.

<dependency>
<groupid>org.springframework.flex</groupid>
<artifactid>spring-flex</artifactid>
<version>1.0.3.RELEASE</version>
<type>jar</type>
<scope>runtime</scope>
</dependency>

Cette version de Spring Flex est dépendante de la version 2.5.6 de Spring.

Structure du WAR

L'application est configurée pour utiliser les répertoires suivant sous le répertoire WEB-INF:
  • conf: configuration SpringFlex
  • flex: configuration BlazeDS
  • spring: configuration vers le backend

Déclaration dans le fichier web.xml

La configuration de Spring se fait en utilisant les fonctionnalités de Spring MVC. Le chargement du context Spring se fait en déclarant les contextes du backend a charger et le listener de chargement.

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/*-context.xml
</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Ensuite, le DispatcherServlet est déclarer pour matcher toutes les requêtes vers le message broker. Il doit être initialisé avec un fichier de contexte Spring configurant l'intégration SpringFlex.

<servlet>
<servlet-name>flex</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/web-application-config.xml</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>flex</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>

Configuration de BlazeDS

La configuration de BlazeDS passe par le fichier de contexte Spring utilisé par le DispatcherServlet: /WEB-INF/config/web-application-config.xml. Il ne fait que déclarer la configuration du message broker. Dans notre cas, la configuration par défaut est suffisante.
Le message broker est configurer pour charger le fichier de configuration des services BlazeDS
dans: WEB-INF/flex/services-config.xml.

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:flex="http://www.springframework.org/schema/flex" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/flex
http://www.springframework.org/schema/flex/spring-flex-1.0.xsd">

<flex:message-broker/>

</beans>

C'est dans ce fichier que l'on pourra déclarer les Remote Object.

Le fichier des services BlazeDS est réduit au minimal pour une configuration standard. Dans notre cas, il n'est pas nécessaire d'avoir d'autres fichiers de configuration.
Il suffit de déclarer le channel par défaut et de le configurer.

<services-config>

<services>
<default-channels>
<channel ref="my-amf">
</default-channels>
</services>

<channels>
<channel-definition id="my-amf"
class="mx.messaging.channels.AMFChannel">
<endpoint
url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
class="flex.messaging.endpoints.AMFEndpoint" />
</channel-definition>
</channels>
</services-config>

Déclaration des Remote Object

SpringFlex offre deux façons de déclarer des Remote Object:
  • Par configuration
  • Par annotation

Par configuration

Le namespace flex apporte l'élément remoting-destination qui permet de référencer un bean Spring et de l'exposer comme Remote Object. L'attribut ref permet de référencer un bean par son id. Et l'attribut destination-id permet de déclarer le nom du Remote Object coté Flex. Par défaut, destination-id est égale à l'id du bean.

<flex:remoting-destination id="userService" ref="userService"/>

Par annotation

L'annotation RemotingDestination de SpringFlex permet de déclarer au niveau de la classe d'un bean, qu'il doit être exposé à Flex via le message broker. Elle permet également de déclarer la destination, mais par défaut, il s'agira du nom du bean avec la première lettre en minuscule.
Cet approche couple directement les beans du backend à la technologie du frontend, ce qui, dans le cas d'un changement de technologie web, obligera les développeurs à garder des dépendances inutiles.