-->

mardi 20 janvier 2015

CXF3 and Spring 4 : Parameter validation with XSD ...

Introduction :

For many times, we still believe validate our web services parameters against a xsd file. During this short tutorial, we will learn how to generate a xsd file from our Java classes in a context of maven project and then we will validate the data sent by the client with our xsd already generated.

Generate XSD :

There are the jaxb2-maven-plugin to manipulate Java and XSD :This plugin uses jaxb2 to generate Java classes from XML Schemas (and binding files) and to create XML Schemas for Existing Java classes. For using this plugin, we should know goals plugins : 

  • jaxb2:schemagen Creates XML Schema Definition (XSD) file(s) from annotated Java sources. 
  • jaxb2:testSchemagen Creates XML Schema Definition (XSD) file(s) from annotated Java test sources. 
  • jaxb2:xjc Generates Java sources from XML Schema(s). 
  • jaxb2:testXjc Generates Java test sources from XML Schema(s).

And now, to generate our file, we will use the first goal : schemagen. To do this, it's so simple, we should add in our pom.xml this plugin and configure the how to access java classes :

 org.codehaus.mojo
 jaxb2-maven-plugin
 1.5
 
  
   
    schemagen
   
   generate-sources
   
    ${project.build.directory}/schemas
    ${project.build.directory}/generated-sources/jaxb
    
     fr/mjhazbri/webservices/schema/*.java
     fr/mjhazbri/webservices/validation/parameter/*.java
    
    
     
      http://www.mjhazbri.fr/parameter
      parameter.xsd
     
    
   
  
 

With this addition to our pom.xml was that each file in the directory fr/mjhazbri/webservices/validation/parameter/*.java will be generated as a parameter to our web services and that will be generated with the namespace http://www.mjhazbri.fr/parameter For this, we will add a small package-info in this same directory :
@javax.xml.bind.annotation.XmlSchema(
  namespace="http://www.mjhazbri.fr/parameter",
  elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package fr.mjhazbri.webservices.schema;

Parameter validation with our XSD generated:

To do this, we will create a first interface to represents parameter, it look like this :
package fr.mjhazbri.webservices.validation.parameter;

public interface Parameter {

}
The result of the web services validation :
package fr.mjhazbri.webservices.validation.result;

public class Result {

 /**
  * Is validation ok.
  */
 private boolean isValid = true;

 /**
  * Message from validation.
  */
 private String message = null;

 public final boolean isValid() {
  return isValid;
 }

 public final void setValid(boolean isValid) {
  this.isValid = isValid;
 }

 public final String getMessage() {
  return message;
 }

 public final void setMessage(String message) {
  this.message = message;
 }
}
And a second interface to represent the methods needed :
**
 * 
 */
package fr.mjhazbri.webservices.validation.service.api;

import java.io.File;

import fr.mjhazbri.webservices.validation.parameter.Parameter;
import fr.mjhazbri.webservices.validation.result.Result;

/**
 * @author jhazbri
 * 
 */
public interface ParameterValidationService<T extends Parameter> {

 Result validateParam(final T param, final File xsdFile);
}
And now, we will code the class ParameterValidationService that implements the logic of validation :
/**
 * 
 */
package fr.mjhazbri.webservices.validation.service;

import java.io.File;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.util.JAXBSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.log4j.Logger;
import org.xml.sax.SAXParseException;

import fr.mjhazbri.webservices.validation.parameter.Parameter;
import fr.mjhazbri.webservices.validation.result.Result;
import fr.mjhazbri.webservices.validation.service.api.ParameterValidationService;

/**
 * @author jhazbri
 * 
 */
public class ParameterValidationServiceImpl<T extends Parameter> implements ParameterValidationService<T> {

	private static final Logger LOGGER = Logger.getLogger(ParameterValidationServiceImpl.class);

	private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
	private static final ConcurrentHashMap<Class<?>, JAXBContext> CONTEXTS = new ConcurrentHashMap<Class<?>, JAXBContext>();
	private static final ConcurrentMap<String, Validator> VALIDATORS = new ConcurrentHashMap<String, Validator>();

 @Override
 public synchronized Result validateParam(T param, File xsdFile)
 {
  Result result = new Result() ; 
  try 
  {
   // Validate source.
   LOGGER.debug(String.format("Begins validation - param %s - xsdPath %s !", param.getClass().toString(), xsdFile.toString()));
   Validator validator = VALIDATORS.get(xsdFile.toString());
   if (validator == null )
   {
    LOGGER.debug("VALIDATOR - resources : " + ParameterValidationServiceImpl.class.getResource("."));
    LOGGER.debug("xsd File : " + xsdFile.toString());
    final Schema schema = SCHEMA_FACTORY.newSchema(xsdFile);
    validator = schema.newValidator();
    VALIDATORS.putIfAbsent(xsdFile.toString(), validator);
   }
   
   JAXBContext context = CONTEXTS.get(param.getClass());
   if (context == null) 
   {
    context = JAXBContext.newInstance(param.getClass());
    CONTEXTS.putIfAbsent(param.getClass(), context);
   }
   validator.validate(new JAXBSource(context ,param));
         LOGGER.debug("Ends validation !");
  } catch (SAXParseException spe)
  {
   LOGGER.warn(spe.getMessage(), spe);
   result.setValid(false);
   result.setMessage(spe.getMessage());
  }
  catch (Exception exception)
  {
   LOGGER.warn(exception.getMessage(), exception);
   result.setValid(false);
   result.setMessage(exception.getMessage());
  }
        LOGGER.debug("isValid : " + result.isValid());
  return result;
 }

}

Aucun commentaire :

Enregistrer un commentaire