axis-java-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "John Pfeifer" <john.pfei...@hnpsolutions.com>
Subject RE: Schema validation Axis 1.3
Date Fri, 10 Nov 2006 14:15:59 GMT
Here is the filter... The trick with this is that you have to wrap the HttpServletRequest so
that you can send the request on to filters down stream once you have read the input stream.
 You can do this using HttpServletRequestWrapper.  I will be happy to post this somewhere,
but I am not sure where to post it.

public class XMLValidationFilter extends GenericFilterBean {

    /**
     * The object that is used for logging.
     */
    private static Log log = LogFactory.getLog(XMLValidationFilter.class);

    /**
     * schemaMap 
     */
    private Map schemaMap = null;
  
    /** (non-Javadoc)
     * @see javax.servlet.Filter#destroy()
     */
    public void destroy() {
        super.destroy();
    }
    
    /**
     * Initialize schemaMap from Spring Context
     */
    private void initSchemaMap() {
        if (schemaMap == null) {
            schemaMap = (Map) WebApplicationContextUtils.getWebApplicationContext(getServletContext()).getBean("schemaToURIMap");
        }
    }
    
    /** (non-Javadoc)
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, 
     * javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

    throws IOException, ServletException {
        final String methodName = "doFilter()";
        if (log.isTraceEnabled()) {
            log.trace(methodName + ": Entry");
        }
        
        HttpServletRequest httpRequest = ((HttpServletRequest) request);

        if (log.isDebugEnabled()) {
            log.debug("XMLValidationFilter: doFilter");
            log.debug("Schema Map Entries "+ schemaMap);
        }

        // set the schemaMap from the spring context, the
        // context is loaded after the filter is initialized but 
        // before the first request can be handled
        initSchemaMap();
        
        if (schemaMap.get(httpRequest.getRequestURI()) == null) {
            if (log.isDebugEnabled()) {
                log.debug("No schema found for RequestURI " + httpRequest.getRequestURI());
            }
            
            // continue with rest of the filter chain as no further processing is required
            chain.doFilter(request, response);
            return;
        } else {
            if (log.isDebugEnabled()) {
                log.debug("Schema found for RequestURI " + httpRequest.getRequestURI());
            }
        }
        
        XMLValidationRequestWrapper requestWrapper = 
            new XMLValidationRequestWrapper((HttpServletRequest) request);
        String queryString = httpRequest.getQueryString();
        if (log.isDebugEnabled()) {
            log.debug("queryString = " + queryString);
        }
        boolean isValid = true;
        if (!StringUtils.equalsIgnoreCase(queryString, "wsdl"))
        {
            isValid = validateIncomingXML(httpRequest, requestWrapper);
        }
        else
        {
            if (log.isInfoEnabled()) {
                log.info("Skipping XML Schema validation.");
            }
        }
        
        if (isValid) {
            if (log.isDebugEnabled()) {
                log.debug("Continue processing filter chain");
            }
            
            chain.doFilter(requestWrapper, response);
        } else {
            log.error("Schema validation failed");            
            generateSOAPFault(response.getOutputStream());
        }
        
        if (log.isTraceEnabled()) {
            log.trace(methodName + ": Exit");
        }
    }

    /**
     * validateIncomingXML
     * @param request
     * @param httpRequest
     * @param buffer
     * @param requestWrapper
     * @return
     */
    private boolean validateIncomingXML(HttpServletRequest httpRequest, 
            XMLValidationRequestWrapper requestWrapper) {
        boolean isValid = false;
        StringBuffer buffer = new StringBuffer();
        InputStream xmlIn;
        String soapRequest;
        String xmlBody;
        try {
            
            xmlIn = httpRequest.getInputStream();
            
            int x = 0;
            while ((xmlIn != null) && ((x = xmlIn.read()) >= 0)) {
                 buffer.append((char) x);
            }
        
            soapRequest = buffer.toString();
            
            if (log.isDebugEnabled()) {
                log.debug("Original SOAP Request = " + soapRequest);
            }
                        
            xmlBody = SOAPUtils.getSOAPBody(buffer.toString());
            
            if (log.isDebugEnabled()) {
                log.debug("XML to be validated = " + xmlBody);
            }
            
            XMLSchemaValidator validator = new XMLSchemaValidator();
            URL url = this.getClass().getResource((String) schemaMap.get(httpRequest.getRequestURI()));

            if (log.isDebugEnabled()) {
                log.debug("XSD Url = " + url);
            }
            
            isValid = validator.validateDocument(xmlBody, url);
            
            if (log.isDebugEnabled()) {
               log.debug("Schema validation isValid = " + isValid); 
            }
            
            requestWrapper.setBodyText(soapRequest);   
            
            // Don't parse the request again, set it as a request attribute to be 
            // used by ServiceRequestProxyServlet down stream
            requestWrapper.setAttribute(ServiceRequestProxyServlet.SOAP_REQUEST_ATTRIBUTE,
soapRequest);
            
        } catch (Throwable t) {
            log.error("Error validating xml", t);
        }
        return isValid;
    }
    
    private void generateSOAPFault(OutputStream out) {

        String soapFault = SOAPUtils.generateSOAPFault(
            "Server", "Invalid XML", "Test Actor", "..... Details ....");
        
        try {
            
            if (log.isDebugEnabled()) {
                log.debug("SOAP Fault = " + soapFault);
            }
            
            out.write(soapFault.getBytes());
            out.flush();
            
        } catch (Throwable t) {
            log.error("Error Generating SOAP Fault", t);
        }
        finally {
            try {
                out.close();
            } catch (Throwable t) {}
        }
                
    }

Here is the schema validator class
===========================================
public class XMLSchemaValidator {

    /**
     * logger 
     */
    private static Logger logger = Logger.getLogger(XMLSchemaValidator.class.getName());
    
    /**
     * JAXP_SCHEMA_LANGUAGE 
     */
    public static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
    /**
     * W3C_SCHEMA_LANGUAGE 
     */
    public static final String W3C_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";
    /**
     * JAXP_SCHEMA_SOURCE 
     */
    public static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
    
    /**
     * parser 
     */
    private ThreadLocal parser = new ThreadLocal() {
        
        protected Object initialValue() {
            
            if (logger.isDebugEnabled()) {
                logger.debug("Creating new thread local parser");
            }
            
            return createParser();
        }
    };

    /**
     * XMLSchemaValidator
     */
    public XMLSchemaValidator() {
    }
    
    /**
     * Returns the JDOM <code>SAXParser</code> associated to the
     * current thread.
     * <p>
     * If no SAXParser is yet associated to the current thread,
     * this implementation relies on {@link #createParser()} to
     * allocate and configure a new SAXParser.</p>
     *
     * @return the <code>DocumentBuilder</code> associated to the
     *         current thread.
     */
    protected final SAXParser getParser() {
       return (SAXParser) (this.parser.get());
       //return createParser();
    }

    /**
     * Create a SAX Parser settings it's properties
     * @return SAXParser
     */
    protected SAXParser createParser() {
       
        if (logger.isDebugEnabled()) {
            logger.debug("Creating new SAX Parser");
        }
        
        SAXParserFactory factory = null;
        SAXParser parser = null;
        
        try {
            factory = SAXParserFactory.newInstance();
            factory.setNamespaceAware(true);
            factory.setValidating(true);            
            parser = factory.newSAXParser();
            
            parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_SCHEMA_LANGUAGE);      
            
        } catch (SAXException se) {
            logger.error("SAXException creating SAXParser", se);
        } catch (ParserConfigurationException pe) {
            logger.error("ParserConfigurationException creating SAXParser", pe);
        }
        catch (Throwable t) {
            logger.error("Unknown Exception: ", t);
        }
        
        return parser;
    }
    
    /**
     * Validate an XML string against a specific xsd
     * @param xmlInput xmlInput
     * @param xsdName xsdName
     * @return isValid 
     * @throws XMLValidationException validationException 
     */
    public boolean validateDocument(String xmlInput, String xsdName) throws XMLValidationException
{ 
        URL url = null;
        
        try {
            url = this.getClass().getResource("/" + xsdName);
        } catch (Throwable t) {
            logger.error("Error retrieving xsd resource", t);
        }
        
        return validateDocument(new ByteArrayInputStream(xmlInput.getBytes()), url);
    }
    
    /**
     * Validate an XML string against a specific xsd
     * @param xmlInput xml doc
     * @param url schemaUrl
     * @return isValid
     * @throws XMLValidationException validationException  
     */
    public boolean validateDocument(String xmlInput, URL url) throws XMLValidationException
{
        return validateDocument(new ByteArrayInputStream(xmlInput.getBytes()), url);
    }
    
    /**
     * Validate an XML InputStream against a list of xsd's.
     * @param xmlInput xmlInput
     * @param url url
     * @return isValid
     * @throws XMLValidationException validationException 
     */
    public boolean validateDocument(InputStream xmlInput, URL url) throws XMLValidationException
{
        
        boolean isValid = false;
        
        try {
        
            if (logger.isDebugEnabled()) {
                logger.debug("XSD URL = " + url);
            }
            
            if (url != null) {
                this.getParser().setProperty(JAXP_SCHEMA_SOURCE, url.toString());
            }
            
            Validator validator = new Validator();
            
            if (logger.isDebugEnabled()) {
                logger.debug("Attempting to validate schema");
            }
            
            this.getParser().parse(xmlInput, validator);
            
            isValid = !validator.isValidationError();
            
            if (logger.isDebugEnabled()) {
                if (isValid) {
                    logger.debug("Validation passed");
                } else {
                    logger.debug("Validation failed");
                }
            }
            
            if (!isValid) {
                logger.error("Schema validation failed ", validator.getSaxParseException());
                throw new XMLValidationException(validator.getSaxParseException().getMessage());
            }
                
        } catch (XMLValidationException ve) {
          throw ve;
          
        } catch (Throwable t) {
     
            logger.error("Error validating schema", t);
            throw new XMLValidationException(t.getMessage());
        }
        
        return isValid;
    }
    
    /**
     * Error handler used to log SAX Parser Errors.
     * @author I4Commerce
     *
     */
    private class Validator extends DefaultHandler {
        
        /**
         * validationError 
         */
        private boolean validationError = false;

        /**
         * saxParseException 
         */
        private SAXParseException saxParseException = null;

        /** (non-Javadoc)
         * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
         */
        public void error(SAXParseException exception) throws SAXException {
            validationError = true;
            saxParseException = exception;
        }

        /** (non-Javadoc)
         * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
         */
        public void fatalError(SAXParseException exception) throws SAXException {
            validationError = true;
            saxParseException = exception;
        }

        /** (non-Javadoc)
         * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
         */
        public void warning(SAXParseException exception) throws SAXException {
            saxParseException = exception;
        }

        /**
         * Get validationError
         * @return the validationError
         */
        public boolean isValidationError() {
            return validationError;
        }

        /**
         * Get saxParseException
         * @return the saxParseException
         */
        public SAXParseException getSaxParseException() {
            return saxParseException;
        }

        /**
         * Set saxParseException
         * @param saxParseException the saxParseException to set
         */
        public void setSaxParseException(SAXParseException saxParseException) {
            this.saxParseException = saxParseException;
        }
    }    
}


-----Original Message-----
From: Rodrigo Ruiz [mailto:rruiz@gridsystems.com]
Sent: Fri 11/10/2006 9:06 AM
To: axis-user@ws.apache.org
Subject: Re: Schema validation Axis 1.3
 
Hi John, how complex is your filter code? It would be a great entry in
the Axis wiki ;-)

Regards,
Rodrigo Ruiz

John Pfeifer wrote:
> 
> Good luck with this one.  I have posted several times about schema
> validation in axis2 and it looks like you have to do it yourself.  I
> wrote a servlet filter that sits in front of the axis servlet and
> validates the request against a given xsd. 
> 
-- 
-------------------------------------------------------------------
GRIDSYSTEMS S.A.               Rodrigo Ruiz
Parc Bit - Son Espanyol        R & D
07120 Palma de Mallorca        rruiz at gridsystems dot com
Baleares - EspaƱa              Tel: +34 971 435 085
http://www.gridsystems.com/    Fax: +34 971 435 082
-------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: axis-user-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-user-help@ws.apache.org



Mime
View raw message