My Garbage Collector

Hamdi Makni's Blog

J’étais hier soir à la soirée « Web » du ParisJUG, qui contenait deux sessions animées par les deux cofondateurs de Zenika, et un architecte du centre de compétence Open Source de Atos. C’était pour moi une soirée « retour vers le futur », le retour parce que, à mon avis personnelle, on est en train de vivre un retour vers les pratiques anciennes du codage des applications web, et là je parle de la tendance de « tout écrire en Java », c’est l’idée de base de plein de framework aujourd’hui comme l’alternative à JSF de apache, les wicket. La première session de la soirée était présenté par les deux cofondateur de Zenika, il ont fait une présentation sous forme de codage en live d’une application en wicket, intéressant, mais, ça me plait pas ce genre de technologies, ça m’embête de passer des heures à écrire des new Label (x, y). Suite à cette présentation, Zenika lance sur son blog un concours pour développer la même application avec moins de 163 lignes de codes, qui leur ont suffit à le faire avec wicket. C’est par ici :

Le futur, c’est le nouveau web, ce qu’ils appellent les marketers le Web 3, le web orienté données, informations, le web sémantique, ou Data Web, comme doit on l’interpréter, nous a fait comprendre Alexandre Bertails , le maître du sujet hier soir au ParisJUG qui nous a fait une superbe session, très bien présenté, qui montre une grande maîtrise de ce qu’il dit. Un sujet passionnant, à creuser, et qui demande beaucoup de lectures pour bien maîtriser en détail, le speaker de la sessions nous a montré quelques exemples pratiques du nouveau web, dont un jeux de Sudoku fait avec le langage sparql sur une application en GWT. Pour avoir une idée sur le résultat attendu, voir cette application en Flex, qui exploite en sparql la base de données de wikipedia, Dbpedia :
http://ccgi.arutherford.plus.com/website/flex/dbPedia/sparqlQueryViewer/#app=65e9&dd55-selectedIndex=0&e98b-selectedIndex=0
Des articles, des liens, des exemples, et pleins d’autres informations utilises sur http://websemantique.org/PagePrincipale
Bonne découverte (pour certains comme moi)

Je viens juste de rentrer des « Rencontres Spring » organisées par SpringSource France, et la société Sfeir, représentée par son directeur Technique, Didier Girard. L’évènement a commencé par une présentation de Sfeir (oui, c l’occasion de faire de la pub à sa boite) par Didier, et puis de SpringSource par Julien Dubois, directeur régional France de Spring Source. Rien n’est surprenant avec l’invité surprise de la matinée, qui n’est autre que Guillaume Laforge, qui vient d’être « racheté » par Spring, non, c’est plutôt sa boite G2One, propriétaire de Groovy/Grails, dont il est le chef de projet. Guillaume a parlé un peu histoire, sur 5 ans ça reste de l’histoire quand même, il a parlé des premiers pas de Groovy, des raisons de choix de Spring comme base de Grails, et du rachat de ces deux frameworks par Spring Source. La première partie de la matinée a été clôturé par une présentation (en anglais) du roadmap de Spring par Peter Cooper-Ellis, l’un des vices présidents chez SpringSource, et premier responsable des road map des projets Spring. On a appris entre autres que entre Janvier et Mars 2009, nous verrons la sortie de Spring 3, Spring DM 1.2 , Spring IDE 2.2, Groovy 1.6 (les nouvelles acquisitions) et Grails 1.1. Il a parlé ensuite de Spring ROO (un framework de Convention Over Configuration) qui va sortir entre Avril et Juin 2009 avec la DM2.0, Batch 2.0, Security 2.5. La présentation de Peter était très orientée commerciale, surtout qu’il a insisté à la fin sur Spring Tool Suite, Spring Application Management Suite, Spring Advenced Pack for Oracle Database et Spring ERS. Il faut dire que c’était l’orientation générale de cette première partie, 4 interventions avec des discours qui visent surtout des décideurs plutôt que des utilisateurs.
Après la pause, place aux choses sérieuses, une intervention très technique (en anglais) de Mark Thomas, qui n’a presque pas prononcé le mot Spring, il a parlé de Tomcat en production, comment faire le tuning de tomcat, comment avoir les meilleurs performances d’une application déployé sous tomcat. Il a parlé de l’optimisation des logs, l’utilisation des pool, de bien choisir le connecteur, de bien faire le tuning du connecteur (j’ai appris que 400 pour maxThreads, et 3000 pour connectionTimeout sont des valeurs raisonnables dans la configuration du connecteur) et du tuning de la JVM. Tout est classique, mais pas par tout le monde. A la fin il a donné quelques « hints and tips », j’ai noté : pas de Load-balancing/clustering pour moins de 3 instances, et « redeployment can expose memory leaks ». Mark parlai très vite, j’avais du mal à le suivre comme il faut, heureusement qu’il parle purement technique, contrairement à de Peter Cooper (la vitesse de parler est elle inversement proportionnelle à l’âge ?).
Dernier intervenant, et bien sûr le meilleur, place à un vrai artiste, au principale commiteur de Spring Framework, et co-fondateur du framework, Juergen Hoeller a fait une présentation intitulée « Spring 3.0 ». En toute simplicité a parlé des nouveautés de Spring 3, avec un petit rappel des nouveautés de Spring 2.5 déjà releasé par rapport aux autres versions. En utilisant des exemples, il nous a montré le nouveau Expression Langage de Spring, qu’on peut utiliser dans la configuration des beans, on peut par exemple référencer la valeur d’une propriété depuis un autre bean, sur les fichiers de configuration, ou par annotation, il a parlé aussi de la suivie des nouveauté de JEE5 dans Spring, du support des Portlet 2.0, du travail fait du coté de REST, et des nouveautés dans la validation des beans avec des expressions simple, en utilisant l’annotation, avec le support de la validation Hibernate et du JSR303.
Fin du rêve, retour à la réalité du marché Français. Je fait ma conclusion avant de parler de ce qui a suivi, le marché Français est très novice avec les projets Spring. En fait, après l’intervention de Jurgen, y’avait une table ronde, avec, soit disons, les principaux et plus grands utilisateurs de Spring en France. Devant nous y’avait des responsables techniques de Voyage-Sncf technologie, Société Generale Corporate and Investissement Banking, HSBC, G2One et une autre boite. Ils sont censé être des grands utilisateurs de Spring. En réalité, Voyage-Sncf (j’ai déjà passé 8 mois avec eux) utilisent Spring core, pas plus déjà, en suivant un tas de mauvaises pratiques, comme le passage par un FactoryBean fait maison pour charger un bean, comme l’interdiction de tout ce qui est AOP, j’espère que ça a changé. L’SGCIB eux aussi présument utiliser Spring, sauf que c’est pareil, ils n’utilisent que le cœur de Spring, et aucun autre module ni projet de Spring Portfolio, HSBC se sont allé plus loin, ils intègrent juste Spring Core dans un framework fait maison, donc il y’a toute une couche au dessus, ce qui rend Spring invisible par les développeurs, G2One se base sur Spring comme conteneur léger de leurs applications Grails. Personne n’a parlé de Spring Web Flow, de Spring MVC, de AspectJ, de Spring WS, .... Ah oui, ils ont quand même parlé SpringSecurity, et ils disent être intéressé par Spring DM. Je crois pas que passer de WebSphere par exemple à SpringDM sera si facile avec les "têtus" de la prod chez SGCIB ou HSBC.
Didier Girard a dit une phrase qui m’a beaucoup plu, c'était dans ce sens là: «dans ma boite, quelqu'un qui se présente avec un CV qui contient pas le mot Spring, pour moi il n’a pas encore fait son boulot de développeur Java, il n’a pas sa place entre nous»

------------------------
update (14-11-2008) : les slides sont disponibles sur le site des Rencontres Spring ici.

Our more repeated code in classes is the data input validations perform, because it’s very important to validate transported object between applications, and between application layers.
On a classic web context, we have some validation form framework like Struts Validator Framework, who can validate form in the client side and server side, based on xml files. On web service context, payload validation is a basic function proposed with the most web service framework. These classic web and web services frameworks send formatted message to client if any data validations fail, and block performing the standard processing. Otherwise, processing continues.
In my case, I have an application core class with a public method invoked from other internal classes, or from another application layer, for example, a DAO method invoked from a service layer. Usually, we need to validate input parameters in your public methods. So we have generally to write some code like this, in the top of your method:


public void myMethod (MethodIN inParameter){
//input method validation
if(inParameter==null)
throw new Exception(…);
if(inParameter.getSimpleProperty()==null)
throw new Exception(…);
if(inParameter.aMyFirstBean!=null){
if(inParameter.aMyFirstBean.getCodeAsString() == null)
throw new Exception(…);
if(inParameter.aMyFirstBean.getCodeAsString().length() <2 || inParameter.aMyFirstBean.getCodeAsString().length() > 40)
throw new Exception(…);
//do something with the input parameters
…………

}

This code is repeated every time when you have to use a mandatory input or strict formatted parameters.
Spring-modules have a validation package witch can used to validate data beans property with annotation or with xml document. In the xml file we must define the validation rules for every class and every property you want to validate. So I think that we can use spring-modules validator to validate input methods by using a method interceptor. The interceptor, wired in an aop-proxy of any service bean of my application, intercepts some methods, when you want to validate inputs, and proceed with the validation perform. The validator is configured in the application context file, and uses an xml file to get the validation rules.
So when the method is called, we fetch received object as input parameter, and put it to the “validation machine”. When fails, the interceptor throw an exception and stop method execution.

import java.util.Iterator;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springmodules.validation.bean.BeanValidator;

/**
* @author Hamdi MAKNI
*/
public class InputBeanValidator implements MethodInterceptor {

private BeanValidator beanValidator;
private Log log = LogFactory.getLog(this.getClass());

public Object invoke (MethodInvocation methodInvocation) throws Throwable {
Object[] arguments = methodInvocation.getArguments();
Errors errors = new BindException(this, this.getClass().toString());
String errorMessage = "";
for (int i = 0; i < arguments.length; i++) {
Object object = arguments[i];
if (object != null) {
Errors errorss = new BindException(object, object.getClass().toString());
beanValidator.validate(object, errorss);
// errors.getAllErrors().addAll(errorss.getAllErrors());
for (Iterator j = errorss.getAllErrors().iterator(); j.hasNext();) {
FieldError err = (FieldError ) j.next();
log.error(err.toString());
}
if (errorss.hasErrors())
errorMessage+=errorss.toString();
}
}
for (Iterator j = errors.getAllErrors().iterator(); j.hasNext();) {
Error err = (Error ) j.next();
log.debug(err.toString());
}
if(!errorMessage.equals(""))
throw new Exception(errorMessage);
Object out = (Object ) methodInvocation.proceed();
return out;
}

}


And then, we need a proxy creator to create your service with a method interceptor. The interceptor






MyServiceBeanDefinition




inputBeanValidatorInterceptor










.*myMethod*











classpath:validation.xml









and we have to write an xml file whith the validation rules, like that:



xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="validator.xsd">













One of the most important phases in the web service request execution process is the SOAP document validation. In fact, like forms in web application, it is recommended to validate received information from client before proceeding to the real action.
One year ago, I had a consulting mission with a firm specialised in booking train ticket services.
The project consisted of exposing some services to a WAP application. We chose Xfire framework as a web service stack, because the competitive intelligence team advise it as the best framework in java web services implementation word (they says).
I already know that we can make web service payload validation in SpringWS with an interceptor. The interceptor called PayloadValidator, is wired in a web service endpoint, and validates automatically the payload document, based on a schema definition document, and using an xml framework with validation function like Jaxb.
I looked into Xfire implementation, but I didn't find a satisfactory solution. So I decided to pick up the Spring-Ws Interceptor idea and code, and adapt it to work as an Xfire handler. I just made some changes on the spring code, especially to read the document and write fault in the response.

Like the Spring-WS Interceptor, I have an abstract super class named AbstractPayloadValidator, with an invoke abstract method, implemented by the subclasses. This method is the main handler method.


import java.util.Locale;
import javax.xml.namespace.QName;
import org.codehaus.xfire.MessageContext;
import org.codehaus.xfire.handler.AbstractHandler;
import org.jdom.Document;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.xml.namespace.QNameUtils;
import org.springframework.xml.validation.XmlValidator;
import org.springframework.xml.validation.XmlValidatorFactory;

public abstract class AbstractPayloadValidator extends AbstractHandler {

public static final QName DEFAULT_DETAIL_ELEMENT_NAME = QNameUtils
.createQName("http://springframework.org/spring-ws",
"ValidationError", "spring-ws");
public static final String DEFAULT_FAULTSTRING_OR_REASON = "Validation error";
private boolean addValidationErrorDetail = true;
private QName detailElementName = DEFAULT_DETAIL_ELEMENT_NAME;
private String faultStringOrReason = DEFAULT_FAULTSTRING_OR_REASON;
private Locale faultStringOrReasonLocale = Locale.ENGLISH;
private String schemaLanguage = XmlValidatorFactory.SCHEMA_W3C_XML;
private Resource[] schemas;
protected XmlValidator validator;
protected Document doc;
public AbstractPayloadValidator() throws Exception {
super();
System.setProperty(
"javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema",
"org.apache.xerces.jaxp.validation.XMLSchemaFactory");
}

public void afterPropertiesSet() throws Exception {
Assert.notEmpty(schemas,"setting either the schema or schemas property is required");
Assert.hasLength(schemaLanguage, "schemaLanguage is required");
for (int i = 0; i < schemas.length; i++) {
Assert.isTrue(schemas[i].exists(), "schema [" + schemas[i] + "] does not exist");
}
if (log.isDevLevelEnabled()) {
log.debug("Validating using " + StringUtils.arrayToCommaDelimitedString(schemas));
}
validator = XmlValidatorFactory.createValidator(schemas, schemaLanguage);
}
public abstract void invoke(MessageContext messageContext) throws Exception;
}

RequestPayloadValidator is the request validator implementation of my abstract class. Normally, I must implement another class to validate the response.
In the invoke method, It will call the handelRequest method to do the validation. In the validation fails, a SOAP fault is sent to the client with the detailed message of the validation rules.

import java.io.IOException;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import org.codehaus.xfire.MessageContext;
import org.codehaus.xfire.exchange.InMessage;
import org.codehaus.xfire.fault.XFireFault;
import org.codehaus.xfire.handler.Phase;
import org.codehaus.xfire.soap.handler.ReadHeadersHandler;
import org.codehaus.xfire.util.jdom.StaxBuilder;
import org.codehaus.xfire.util.stax.JDOMStreamReader;
import org.jdom.Element;
import org.jdom.transform.JDOMSource;
import org.springframework.util.ObjectUtils;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import ….PayloadValidationException;

public class RequestPayloadValidator extends AbstractPayloadValidator {

public RequestPayloadValidator() throws Exception {
super();
setPhase(Phase.PARSE);
before(ReadHeadersHandler.class.getName());

}

protected Source getValidationRequestSource(MessageContext request)
throws XMLStreamException {
InMessage message = request.getInMessage();
XMLStreamReader streamReader = message.getXMLStreamReader();
StaxBuilder builder = new StaxBuilder();

doc = builder.build(streamReader);
Element body = ((Element) doc.getRootElement().getChildren().get(0));
if(!body.getName().equals("Body")) body = (Element) doc.getRootElement().getChildren().get(1);
Element payload = (Element) body.getChildren().get(0);
return new JDOMSource(payload);
}
protected boolean handleRequestValidationErrors(
MessageContext messageContext, SAXParseException[] errors)
throws TransformerException, XFireFault, PayloadValidationException {
String faultMessage = "";
for (int i = 0; i < errors.length; i++) {
faultMessage += errors[i].getMessage();
log.debug("XML validation error on request: " + errors[i].getMessage());
}

messageContext.getExchange().getFaultMessage().setBody(new XFireFault(faultMessage, new PayloadValidationException(),XFireFault.SENDER));
return false;

}

public boolean handleRequest(MessageContext messageContext)
throws IOException, SAXException, TransformerException,
XMLStreamException, XFireFault, PayloadValidationException {
Source requestSource = getValidationRequestSource(messageContext);
if (requestSource != null) {
SAXParseException[] errors = validator.validate(requestSource);
if (!ObjectUtils.isEmpty(errors)) {
return handleRequestValidationErrors(messageContext, errors);
} else if (log.isDevLevelEnabled()) {
log.debug("Request message validated");
}
}
return true;
}

public void invoke(MessageContext messageContext) throws Exception {
afterPropertiesSet();
if (handleRequest(messageContext))
log.debug("Validation of requested payload finished by SUCCESS");
else
log.debug("Validation of requested payload finished by FAULT");
messageContext.getInMessage().setXMLStreamReader(
new JDOMStreamReader(doc));

}
}

I used this handler named ErrorValidationHandler to throw the fault and log it.

import org.codehaus.xfire.MessageContext;
import org.codehaus.xfire.fault.XFireFault;
import org.codehaus.xfire.handler.AbstractHandler;
import org.codehaus.xfire.handler.Phase;
import org.codehaus.xfire.soap.handler.SoapBodyHandler;

public class ErrorValidationHandler extends AbstractHandler {

protected final Log log = new Log(getClass());

public ErrorValidationHandler() {
super();
setPhase(Phase.DISPATCH);
after(SoapBodyHandler.class.getName());
}

public void invoke(MessageContext messageContext) throws Exception {
XFireFault fault = (XFireFault) messageContext.getExchange()
.getFaultMessage().getBody();
if (fault != null){
log.debug("fault received from the payload validator handler.");
throw fault;
}
}
}

In my spring applicationContext file, I wired my handlers in the service exporter, as an inHandlers.






com…...MYWs


myWs.wsdl









I set the schema file location in the validator bean

class="com…...validation.RequestPayloadValidator">




class="com…...validation.ErrorValidationHandler">

Like the other web service stacks, Xfire make a first level validation of received request document, but with this handler we can validate any type of rules with a rich xsd file.
An amelioration of this solution is to get dynamically the shema definition part from the WSDL file.

Après quelques mois de préparation, le JUG tunisien est enfin crée.
Le Java User Group Tunisien porte le nom de TeeJUG.
Le but est d'avoir une vrai communauté java tunisienne, active, reférencée par sun
TeeJUG commence par un google groupe et un blog sous blogger.
http://groups.google.com/group/teejug
http://teejug.blogspot.com/