My Garbage Collector

Hamdi Makni's Blog

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/


Presented by Tareq Abed Rabbo
April 2007- tunis-Tunisia

I am interested this period to reporting tool, since a month ago I am searching the best tool to generate easily and perfectly a good report.
After Business Object and Cristal Report, JfreeChart, then Birt, finally I found jasper Report and his report design tool iRreport.
I choose jasper Report for three reasons. First, Jasper report is easily integrated with Spring framework, in fact, Spring offer a view class to integrate jasper report in your web application.Second, Jasper report use JrfeeCchart to generate some chat. Third, iReport is very good tool, easy to use, rich with his variety of chart. And finally, because with Jasper Report I can generate cross tabs.

To integrate an SVG document into an html file, there are three different tags.

We can use: embed, object or iframe, but the browsers not support all of this tag. Therefore, we have some compatibility problem with every tag.

Some web developers prefer iframe because it is compatible with the most of browser, but the main problem is with internet explorer browser. In fact, when we use this tag, internet explorer sends a couple of request for every document. We can test it, in my case, I have a servlet wich generate an xml file, and a filter to transform the xml to SVG document, so when I use internet explorer, I receive a couple consecutive request, but with firefox I have no problem.

Consequently, I prefer to use embed tag surrounded with object tag, and with this couple, I have not any problem with internet explorer and firefox browser.