I'm trying to use a spring ws source code and spring xml api to create an xfire
handler to validate xml payload like spring xs, with xds file param, and
returned xfirefault.
Now I have a code like this:
import java.io.IOException;
import java.util.Locale;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.xfire.MessageContext;
import org.codehaus.xfire.exchange.InMessage;
import org.codehaus.xfire.exchange.OutMessage;
import org.codehaus.xfire.fault.XFireFault;
import org.codehaus.xfire.handler.AbstractHandler;
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.Document;
import org.jdom.Element;
import org.jdom.transform.JDOMSource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.xml.namespace.QNameUtils;
import org.springframework.xml.validation.XmlValidator;
import org.springframework.xml.validation.XmlValidatorFactory;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* @author hamdi_makni
* @since V18
*/
public class PayloadValidator extends AbstractHandler {
/**
* log user by this class
*/
protected final Log log = LogFactory.getLog(getClass());
/**
* Default SOAP Fault Detail name used when a validation errors occur
on the
* request.
*
* @see #setDetailElementName(javax.xml.namespace.QName)
*/
public static final QName DEFAULT_DETAIL_ELEMENT_NAME = QNameUtils
.createQName("http://springframework.org/spring-ws",
"ValidationError", "spring-ws");
/**
* Default SOAP Fault string used when a validation errors occur on the
* request.
*
* @see #setFaultStringOrReason(String)
*/
public static final String DEFAULT_FAULTSTRING_OR_REASON = "Validation
error";
/**
* addValidationErrorDetail
*/
private boolean addValidationErrorDetail = true;
/**
* detailElementName
*/
private QName detailElementName = DEFAULT_DETAIL_ELEMENT_NAME;
/**
* faultStringOrReason
*/
private String faultStringOrReason = DEFAULT_FAULTSTRING_OR_REASON;
/**
* faultStringOrReasonLocale
*/
private Locale faultStringOrReasonLocale = Locale.ENGLISH;
/**
* schemaLanguage
*/
private String schemaLanguage = XmlValidatorFactory.SCHEMA_W3C_XML;
/**
* schemas
*/
private Resource[] schemas;
/**
* validateRequest
*/
private boolean validateRequest = true;
/**
* validateResponse
*/
private boolean validateResponse = false;
/**
* validator
*/
private XmlValidator validator;
/**
* document
*/
protected Document doc;
/**
* constructeur sans param utilisé par SpringIOC
*
* @throws Exception
* Exception
*/
public PayloadValidator() throws Exception {
super();
setPhase(Phase.PARSE);
before(ReadHeadersHandler.class.getName());
System
.setProperty(
"javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema",
"org.apache.xerces.jaxp.validation.XMLSchemaFactory");
}
public String getSchemaLanguage() {
return schemaLanguage;
}
/**
* Sets the schema language. Default is the W3C XML Schema:
* <code>http://www.w3.org/2001/XMLSchema"</code>.
*
* @see
org.springframework.xml.validation.XmlValidatorFactory#SCHEMA_W3C_XML
* @see
org.springframework.xml.validation.XmlValidatorFactory#SCHEMA_RELAX_NG
* @param schemaLanguage
* schemaLanguage
*/
public void setSchemaLanguage(String schemaLanguage) {
this.schemaLanguage = schemaLanguage;
}
/**
* Returns the schema resources to use for validation.
*
* @return schemas
*/
public Resource[] getSchemas() {
return schemas;
}
/**
* Sets the schema resources to use for validation. Setting either this
* property or <code>schema</code> is required.
*
* @param schemas
* schemas
*/
public void setSchemas(Resource[] schemas) {
Assert.notEmpty(schemas, "schemas must not be empty or null");
for (int i = 0; i < schemas.length; i++) {
Assert.notNull(schemas[i], "schema must not be null");
Assert.isTrue(schemas[i].exists(), "schema \"" +
schemas[i]
+ "\" does not exit");
}
this.schemas = schemas;
}
/**
* Sets the schema resource to use for validation. Setting either this
* property or <code>schemas</code> is required.
*
* @param schema
* schema
*/
public void setSchema(Resource schema) {
setSchemas(new Resource[] { schema });
}
/**
* Indicates whether the request should be validated against the schema.
* Default is <code>true</code>.
*
* @param validateRequest
* validateRequest
*/
public void setValidateRequest(boolean validateRequest) {
this.validateRequest = validateRequest;
}
/**
* Indicates whether the response should be validated against the
schema.
* Default is <code>false</code>.
*
* @param validateResponse
* validateResponse
*/
public void setValidateResponse(boolean validateResponse) {
this.validateResponse = validateResponse;
}
/**
* Validates the request message in the given message context.
Validation
* only occurs if <code>validateRequest</code> is set to
<code>true</code>,
* which is the default. <p/> Returns <code>true</code> if the request
is
* valid, or <code>false</code> if it isn't. Additionally, when the
* <code>messageContext</code> is a <code>SoapMessageContext</code>, a
* SOAP Fault is added as response.
*
* @param messageContext
* the message context
* @return <code>true</code> if the message is valid; <code>false</code>
* otherwise
* @throws XMLStreamException
* XMLStreamException
* @throws IOException
* IOException
* @throws SAXException
* SAXException
* @throws TransformerException
* TransformerException
* @throws XFireFault XFireFault
* @see #setValidateRequest(boolean)
*/
public boolean handleRequest(MessageContext messageContext)
throws IOException, SAXException, TransformerException,
XMLStreamException, XFireFault {
if (validateRequest) {
Source requestSource =
getValidationRequestSource(messageContext);
if (requestSource != null) {
SAXParseException[] errors =
validator.validate(requestSource);
if (!ObjectUtils.isEmpty(errors)) {
return
handleRequestValidationErrors(messageContext, errors);
} else if (log.isDebugEnabled()) {
log.debug("Request message validated");
}
}
}
return true;
}
/**
* Validates the response message in the given message context.
Validation
* only occurs if <code>validateResponse</code> is set to
* <code>true</code>, which is <strong>not</strong> the default. <p/>
* Returns <code>true</code> if the request is valid, or
* <code>false</code> if it isn't.
*
* @param messageContext
* the message context.
* @return <code>true</code> if the response is valid;
<code>false</code>
* otherwise
* @throws IOException
* IOException
* @throws SAXException
* SAXException
* @see #setValidateResponse(boolean)
*/
public boolean handleResponse(MessageContext messageContext)
throws IOException, SAXException {
if (validateResponse) {
Source responseSource =
getValidationResponseSource(messageContext);
if (responseSource != null) {
SAXParseException[] errors =
validator.validate(responseSource);
if (!ObjectUtils.isEmpty(errors)) {
return
handleResponseValidationErrors(messageContext,
errors);
} else if (log.isDebugEnabled()) {
log.debug("Response message validated");
}
}
}
return true;
}
/**
* Template method that is called when the response message contains
* validation errors. Default implementation logs all errors, and
returns
* <code>false</code>, i.e. do not send the response.
*
* @param messageContext
* the message context
* @param errors
* the validation errors
* @return <code>true</code> to continue sending the response,
* <code>false</code> (the default) otherwise
*/
protected boolean handleResponseValidationErrors(
MessageContext messageContext, SAXParseException[]
errors) {
for (int i = 0; i < errors.length; i++) {
log.error("XML validation error on response: "
+ errors[i].getMessage());
}
return false;
}
/**
* afterPropertiesSet
*
* @throws Exception
* Exception
*/
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.isInfoEnabled()) {
log.info("Validating using "
+
StringUtils.arrayToCommaDelimitedString(schemas));
}
validator = XmlValidatorFactory
.createValidator(schemas, schemaLanguage);
}
/**
* Returns whether a SOAP Fault detail element should be created when a
* validation error occurs. This detail element will contain the exact
* validation errors. It is only added when the underlying message is a
* <code>SoapMessage</code>. Defaults to <code>true</code>.
*
* @see org.springframework.ws.soap.SoapFault#addFaultDetail()
* @return addValidationErrorDetail
*/
public boolean getAddValidationErrorDetail() {
return addValidationErrorDetail;
}
/**
* Indicates whether a SOAP Fault detail element should be created when
a
* validation error occurs. This detail element will contain the exact
* validation errors. It is only added when the underlying message is a
* <code>SoapMessage</code>. Defaults to <code>true</code>.
*
* @param addValidationErrorDetail
* addValidationErrorDetail
* @see org.springframework.ws.soap.SoapFault#addFaultDetail()
*/
public void setAddValidationErrorDetail(boolean
addValidationErrorDetail) {
this.addValidationErrorDetail = addValidationErrorDetail;
}
/**
* Returns the fault detail element name when validation errors occur
on the
* request.
*
* @return detailElementName
*/
public QName getDetailElementName() {
return detailElementName;
}
/**
* Sets the fault detail element name when validation errors occur on
the
* request. Defaults to <code>DEFAULT_DETAIL_ELEMENT_NAME</code>.
*
* @param detailElementName
* detailElementName
* @see #DEFAULT_DETAIL_ELEMENT_NAME
*/
public void setDetailElementName(QName detailElementName) {
this.detailElementName = detailElementName;
}
/**
* Sets the SOAP <code>faultstring</code> or <code>Reason</code> used
* when validation errors occur on the request.
*
* @return faultStringOrReason
*/
public String getFaultStringOrReason() {
return faultStringOrReason;
}
/**
* Sets the SOAP <code>faultstring</code> or <code>Reason</code> used
* when validation errors occur on the request. It is only added when
the
* underlying message is a <code>SoapMessage</code>. Defaults to
* <code>DEFAULT_FAULTSTRING_OR_REASON</code>.
*
* @param faultStringOrReason
* faultStringOrReason
* @see #DEFAULT_FAULTSTRING_OR_REASON
*/
public void setFaultStringOrReason(String faultStringOrReason) {
this.faultStringOrReason = faultStringOrReason;
}
/**
* Returns the SOAP fault reason locale used when validation errors
occur on
* the request.
*
* @return faultStringOrReasonLocale
*/
public Locale getFaultStringOrReasonLocale() {
return faultStringOrReasonLocale;
}
/**
* Sets the SOAP fault reason locale used when validation errors occur
on
* the request. It is only added when the underlying message is a
* <code>SoapMessage</code>. Defaults to English.
*
* @param faultStringOrReasonLocale
* faultStringOrReasonLocale
* @see java.util.Locale#ENGLISH
*/
public void setFaultStringOrReasonLocale(Locale
faultStringOrReasonLocale) {
this.faultStringOrReasonLocale = faultStringOrReasonLocale;
}
protected boolean handleRequestValidationErrors(
MessageContext messageContext, SAXParseException[]
errors)
throws TransformerException, XFireFault {
for (int i = 0; i < errors.length; i++) {
log.warn("XML validation error on request: "
+ errors[i].getMessage());
}
throw new XFireFault("Error Validation payload.
"+errors[0].getMessage(), errors[0], XFireFault.SENDER);
}
/**
* Returns the payload source of the given message.
*
* @throws XMLStreamException
* zz
*/
protected Source getValidationRequestSource(MessageContext request)
throws XMLStreamException {
InMessage message = request.getInMessage();
XMLStreamReader streamReader = message.getXMLStreamReader();
log.debug("streamReader " + streamReader);
StaxBuilder builder = new StaxBuilder();
log.debug("builder " + builder);
doc = builder.build(streamReader);
log.debug("doc " + doc);
log.debug("documentRoot: " + doc.getRootElement());
log.debug("First children of documentRoot: "
+ ((Element)
doc.getRootElement().getChildren().get(0))
.getName());
Element body = (Element)
doc.getRootElement().getChildren().get(1);
log.debug("Second children of documentRoot: " + body.getName());
Element payload = (Element) body.getChildren().get(0);
return new JDOMSource(payload);
}
/**
* Returns the payload source of the given message.
*/
protected Source getValidationResponseSource(MessageContext response) {
OutMessage message = response.getOutMessage();
return null;
}
/**
* [EMAIL PROTECTED]
*/
public void invoke(MessageContext messageContext) throws Exception {
log.debug("Begin validation");
afterPropertiesSet();
if (handleRequest(messageContext))
log.debug("Validation of requested payload finished by
SUCESS");
else
log.debug("Validation of requested payload finished by
FAULT");
messageContext.getInMessage().setXMLStreamReader(
new JDOMStreamReader(doc));
}
}
And a config file like:
<bean ...>
....
<property name="inHandlers">
<list>
<ref local="maqValidationHandler"/>
</list>
</property>
</bean>
<bean id="maqValidationHandler"
class="com.xxx.mobile.ws.validation.PayloadValidator">
<property name="schema" value="maq.xsd" />
<property name="validateRequest" value="true" />
<property name="validateResponse" value="false" />
<property name="addValidationErrorDetail" value="true" />
</bean>
I'll do some modifications, there are some undesired code till now.
-----Message d'origine-----
De : Tomek Sztelak [mailto:[EMAIL PROTECTED]
Envoyé : vendredi 20 avril 2007 15:45
À : [email protected]
Objet : Re: [xfire-user] How can I make validation for my payload?
Hi
When do you plan to finish this ? Maybe me could add support for your
framework to XFire distro.
On 4/20/07, Henning Jensen <[EMAIL PROTECTED]> wrote:
> Makni Hamdi wrote:
> > Hello,
> >
> >
> >
> > I'm using Xfire1.2.4, aegis, Spring 2 with java 1.4, and I want to make
> > validation for my payload.
> >
> > How can I do it? What framework should I use?
>
> Hi!
>
> I'm working on a framework that does exactly what you are asking for.
> With the framework you can define validation rules in a xml file and
> just add a handler to your service definitions.
>
> This work is part of a master thesis and you can find the project on:
>
> http://henning.fjas.no/ws-validator
>
> Not to much documentation yet, but a simple example and a download link
> is provided. The project uses Maven 2 and you can build it with mvn
> package to get jar files to put in your own project.
>
> --
> Henning Jensen
>
> ---------------------------------------------------------------------
> To unsubscribe from this list please visit:
>
> http://xircles.codehaus.org/manage_email
>
>
--
-----
When one of our products stops working, we'll blame another vendor
within 24 hours.
---------------------------------------------------------------------
To unsubscribe from this list please visit:
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list please visit:
http://xircles.codehaus.org/manage_email