In JAX-WS, to validate the incoming request, one of the ways is to use @SchemaValidation as suggested in below link.
JAX-WS and XSD Validation
However the application server (WAS 7) I am using does not yet support @SchemaValidation. (Please correct me if WAS 7 does support this annotation)
So I am looking at other options like implementing a handler to validate the incoming request. Either in the handler or the endpoint class itself, I can create the JAXBContext and use the JAXB validator. Do I need to create the JAXBContext explicitly or is it available as a resource / annotation since JAX-WS internally uses JAXB?
Is this a good way to implement validation in JAX-WS? (In the absence of @SchemaValidation validation)
Is it a standard practice to validate the incoming request xml in web services or is it given a skip due to performance hit it might take?
It is a good practice to validate the incoming request xml as is the case with every MVC system. (MVC might not fit here but in principle, its same just that the view is XML). If the mentioned annotation (@SchemaValidation
) is not supported, then one way out is is use handler which will validate the incoming request using JAXB Validation.
Better practice if you are a LARGE organization is to use DataPower. It will do the validations for you along with a variety of features. As far as best practice goes, I would suggest DataPower just because it was designed for that, but you need to make sure you develop code that can validate as well otherwise you'd hit the validation issues on runtime.
I also do NOT recommend using @SchemaValidation since that is vendor specific rather than standard.
That being said, I wrote the following when I was playing around interceptors for my reference Java EE application which does not use any vendor specific APIs.
/**
* Validates the XML streams going in the request and response if the log level
* is {@link Level#FINER} or below against {@value #LOGGER_NAME}. If
* {@link Level#FINEST} is used it will also dump the XML that were sent.
*
* @author Archimedes Trajano
*
*/
public class XmlValidationInterceptor {
/**
* Logger.
*/
private static final Logger LOG;
/**
* Name of the logger.
*/
public static final String LOGGER_NAME = "xml.validation"; //$NON-NLS-1$
static {
LOG = Logger.getLogger(LOGGER_NAME, "Messages"); //$NON-NLS-1$
}
/**
* Contains a composite of multiple schema files into one schema that used
* on all message validations.
*/
private final Schema schema;
/**
* Loads up the schema into memory. This uses the default
*
* @throws SAXException
* problem parsing the schema files.
*/
public XmlValidationInterceptor() throws SAXException {
final SchemaFactory sf = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schema = sf.newSchema();
}
/**
* Loads up the schema from the specified array of {@link Source} into
* memory.
*
* @param schemaSources
* schema sources.
* @throws SAXException
* problem parsing the schema files.
*/
public XmlValidationInterceptor(final Source... schemaSources)
throws SAXException {
final SchemaFactory sf = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schema = sf.newSchema(schemaSources);
}
/**
* Writes the object as XML to the logger.
*
* @param param
* object to marshal
* @param context
* invocation context used for logging.
* @throws JAXBException
* problem with the Java binding except schema issues because
* schema validation errors are caught and processed
* differently.
*/
private void marshalObject(final Object param,
final InvocationContext context) throws JAXBException {
if (!param.getClass().isAnnotationPresent(XmlRootElement.class)) {
return;
}
// validate against known schemas
final JAXBContext jaxbContext = JAXBContext.newInstance(param
.getClass());
final Marshaller m = jaxbContext.createMarshaller();
m.setSchema(schema);
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
try {
final StringWriter w = new StringWriter();
m.marshal(param, w);
LOG.finest(w.toString());
} catch (final MarshalException e) {
if (!(e.getLinkedException() instanceof SAXParseException)) {
throw e;
}
final SAXParseException parseException = (SAXParseException) e
.getLinkedException();
LOG.log(Level.SEVERE,
"XmlValidationInterceptor.parseException", // $NON-NLS-1$
new Object[] { context.getMethod(), param,
parseException.getMessage() });
m.setSchema(null);
final StringWriter w = new StringWriter();
m.marshal(param, w);
LOG.finest(w.toString());
}
}
/**
* Validates the data in the parameters and return values.
*
* @param context
* invocation context
* @return invocation return value
* @throws Exception
* invocation exception
*/
@AroundInvoke
public Object validate(final InvocationContext context) throws Exception {
if (!LOG.isLoggable(Level.FINER)) {
return context.proceed();
}
final Object[] params = context.getParameters();
for (final Object param : params) {
marshalObject(param, context);
}
final Object ret = context.proceed();
if (ret != null) {
marshalObject(ret, context);
}
return ret;
}
}