it.cnr.icar.eric.server.cms.CanonicalXMLValidationService.java Source code

Java tutorial

Introduction

Here is the source code for it.cnr.icar.eric.server.cms.CanonicalXMLValidationService.java

Source

/*
 * ====================================================================
 * This file is part of the ebXML Registry by Icar Cnr v3.2 
 * ("eRICv32" in the following disclaimer).
 *
 * "eRICv32" is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * "eRICv32" is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License Version 3
 * along with "eRICv32".  If not, see <http://www.gnu.org/licenses/>.
 *
 * eRICv32 is a forked, derivative work, based on:
 *    - freebXML Registry, a royalty-free, open source implementation of the ebXML Registry standard,
 *      which was published under the "freebxml License, Version 1.1";
 *   - ebXML OMAR v3.2 Edition, published under the GNU GPL v3 by S. Krushe & P. Arwanitis.
 * 
 * All derivative software changes and additions are made under
 *
 * Copyright (C) 2013 Ing. Antonio Messina <messina@pa.icar.cnr.it>
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the freebxml Software Foundation.  For more
 * information on the freebxml Software Foundation, please see
 * "http://www.freebxml.org/".
 *
 * This product includes software developed by the Apache Software
 * Foundation (http://www.apache.org/).
 *
 * ====================================================================
 */
package it.cnr.icar.eric.server.cms;

import it.cnr.icar.eric.common.RepositoryItem;
import it.cnr.icar.eric.common.Utility;
import it.cnr.icar.eric.common.exceptions.ValidationException;
import it.cnr.icar.eric.server.common.ServerRequestContext;
import it.cnr.icar.eric.server.util.ServerResourceBundle;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.FileReader;
import java.net.URL;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.MissingResourceException;
import org.oasis.ebxml.registry.bindings.rim.ExternalLinkType;
import org.oasis.ebxml.registry.bindings.rim.RegistryObjectType;
import org.xml.sax.InputSource;

import javax.xml.transform.ErrorListener;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.registry.RegistryException;

import org.oasis.ebxml.registry.bindings.rim.ExtrinsicObjectType;
import org.oasis.ebxml.registry.bindings.rim.ServiceType;
import org.oasis.ebxml.registry.bindings.rim.UserType;

/**
 * Canonical XML Content Validation Service
 *
 * @author Paul Sterk
 *
 */
public class CanonicalXMLValidationService extends ContentValidationServiceImpl {
    private static final Log log = LogFactory.getLog(CanonicalXMLValidationService.class.getName());
    private static final String TMP_DIR = System.getProperty("java.io.tmpdir");
    private static StreamSource schematronXSLTFileSrc = null;

    public ServiceOutput invoke(ServerRequestContext context, ServiceInput input, ServiceType service,
            InvocationController invocationController, UserType user) throws RegistryException {

        ServerRequestContext outputContext = context;

        try {
            //ExtrinsicObjectType eo = (ExtrinsicObjectType)input.getRegistryObject();
            //RepositoryItem repositoryItem = input.getRepositoryItem();
            //DataHandler dh = repositoryItem.getDataHandler();
            InputSource inputSource = null;

            //registryObject MUST be ExrinsicObject or ExternalLink of objectType WSDL
            ExtrinsicObjectType ebExtrinsicObjectType = null;
            ExternalLinkType ebExternalLinkType = null;
            RegistryObjectType ebRegistryObjectType = input.getRegistryObject();
            if (ebRegistryObjectType instanceof ExtrinsicObjectType) {
                ebExtrinsicObjectType = (ExtrinsicObjectType) ebRegistryObjectType;
                RepositoryItem repositoryItem = input.getRepositoryItem();
                if (repositoryItem == null) {
                    // Section 8.10 of the [ebRS] spec specifies that the RI
                    // is optional. Log message and return
                    log.info(ServerResourceBundle.getInstance().getString("message.noRepositoryItemIncluded",
                            new String[] { ebRegistryObjectType.getId() }));
                    ServiceOutput so = new ServiceOutput();
                    so.setOutput(outputContext);
                    return so;
                }
                inputSource = new InputSource(repositoryItem.getDataHandler().getInputStream());
            } else if (ebRegistryObjectType instanceof ExternalLinkType) {
                ebExternalLinkType = (ExternalLinkType) ebRegistryObjectType;
                String urlStr = ebExternalLinkType.getExternalURI();
                urlStr = Utility.absolutize(Utility.getFileOrURLName(urlStr));
                URL url = new URL(urlStr);
                InputStream is = url.openStream();
                inputSource = new InputSource(is);
            } else {
                throw new ValidationException("RegistryObject not ExtrinsicObject or ExternalLink");
            }

            StreamSource schematronInvControlFileSrc = rm.getAsStreamSource(invocationController.getEoId());
            //Commenting out caching until we figure out how to reinit the stream position at begining
            //Currently if we cache then subsequent uses result in error: "Could not compile stylesheet"
            // The schematron XSLT file is expected to be stable and change infrequently. So, cache it.
            //if (schematronXSLTFileSrc == null) {
            schematronXSLTFileSrc = new StreamSource(this.getClass().getClassLoader()
                    .getResourceAsStream("it/cnr/icar/eric/server/cms/conf/skeleton1-5.xsl"));
            //}

            if (log.isDebugEnabled()) {
                dumpStream(schematronInvControlFileSrc);
                dumpStream(schematronXSLTFileSrc);
            }

            // Use the Schematron Invocation Control File and Schematron XSLT to
            // create the XSLT Invocation Control File
            File xsltInvocationControlFile = File.createTempFile("InvocationControlFile_WSDLValidation", ".xslt");
            xsltInvocationControlFile.deleteOnExit();
            StreamResult xsltInvocationControlFileSR = new StreamResult(xsltInvocationControlFile);

            TransformerFactory tFactory = TransformerFactory.newInstance();
            Transformer transformer = tFactory.newTransformer(schematronXSLTFileSrc);

            configureTransformer(transformer);

            // This call creates the XSLT Invocation Control File using
            // schematron invocation control file and schematron xslt files
            transformer.transform(schematronInvControlFileSrc, xsltInvocationControlFileSR);

            // Use generated XSLT Invocation Control File to validate the WSDL file(s)
            StreamSource xsltInvocationControlFileSrc = new StreamSource(xsltInvocationControlFile);
            transformer = tFactory.newTransformer(xsltInvocationControlFileSrc);

            configureTransformer(transformer);

            //Set respository item as parameter
            transformer.setParameter("repositoryItem", input.getRegistryObject().getId());

            if ((ebExtrinsicObjectType != null)
                    && (ebExtrinsicObjectType.getMimeType().equalsIgnoreCase("application/zip"))) {
                ArrayList<File> files = Utility.unZip(TMP_DIR, inputSource.getByteStream());

                //Now iterate and create ExtrinsicObject - Repository Item pair for each unzipped file
                Iterator<File> iter = files.iterator();
                while (iter.hasNext()) {
                    File file = iter.next();
                    @SuppressWarnings("resource")
                    BufferedReader br = new BufferedReader(new FileReader(file));
                    StringBuffer sb = new StringBuffer();
                    while (br.ready()) {
                        sb.append(br.readLine());
                    }
                    StringReader reader = new StringReader(sb.toString());
                    StreamSource inputSrc = new StreamSource(reader);
                    validateXMLFile(inputSrc, transformer);
                }
            } else {
                //Following will fail if there are unresolved imports in the WSDL
                StreamSource inputSrc = new StreamSource(inputSource.getByteStream());
                //dumpStream(inputSrc);
                //inputSrc = new StreamSource(inputSource.getByteStream());
                validateXMLFile(inputSrc, transformer);
            }
        } catch (ValidationException e) {
            if (outputContext != context) {
                outputContext.rollback();
            }
            log.error(ServerResourceBundle.getInstance().getString("message.errorValidatingXML"), e);
            throw e;
        } catch (Exception e) {
            if (outputContext != context) {
                outputContext.rollback();
            }
            log.error(ServerResourceBundle.getInstance().getString("message.errorValidatingXML"), e);
            throw new RegistryException(e);
        }

        ServiceOutput so = new ServiceOutput();
        so.setOutput(outputContext);

        if (outputContext != context) {
            outputContext.commit();
        }

        return so;
    }

    private void configureTransformer(Transformer transformer) {
        transformer.setURIResolver(rm.getURIResolver());
        transformer.setErrorListener(new ErrorListener() {
            public void error(TransformerException exception) throws TransformerException {
                log.info(exception);
            }

            public void fatalError(TransformerException exception) throws TransformerException {
                log.error(exception);
                throw exception;
            }

            public void warning(TransformerException exception) throws TransformerException {
                log.info(exception);
            }
        });
    }

    private void validateXMLFile(StreamSource inputSrc, Transformer transformer)
            throws IOException, TransformerException, RegistryException {
        //Create the output file with validation results
        File outputFile = File.createTempFile("CanonicalXMLValidationService_OutputFile", ".xml");
        outputFile.deleteOnExit();
        if (log.isDebugEnabled()) {
            dumpStream(inputSrc);
            log.debug("Tempfile= " + outputFile.getAbsolutePath());
        }

        StreamResult sr = new StreamResult(outputFile);

        transformer.transform(inputSrc, sr);

        @SuppressWarnings("resource")
        BufferedReader outputFileReader = new BufferedReader(new FileReader(outputFile));
        StringBuffer sb2 = null;
        while (outputFileReader.ready()) {
            String line = outputFileReader.readLine();
            if (line.indexOf("error") != -1) {
                // if the line has the word 'error', a validation error has occurred
                // obtain the message and store. There may be multiple
                // violations. So, loop through all, then pass to exception
                if (sb2 == null) {
                    sb2 = new StringBuffer();
                    sb2.append(ServerResourceBundle.getInstance().getString("message.errorValidatingXML"));
                }
                // The error message SHOULD contain the key to an i18n message
                // in the server ResourceBundle.properties file.
                String key = line;
                try {
                    line = ServerResourceBundle.getInstance().getString(key);
                } catch (MissingResourceException ex) {
                    log.error(ServerResourceBundle.getInstance().getString("message.missingMessage",
                            new Object[] { key }));
                }
                sb2.append(line).append(' ');
            }
        }
        if (sb2 != null) {
            throw new ValidationException(sb2.toString());
        }
    }

    protected void dumpStream(StreamSource ss) {
        /* Commented because call screws up subsequent actual read of the stream source.
         * Adding reset at the end did not fix this problem for some reason.
        BufferedReader br = null;
            
        try {
        InputStream inputStream = ss.getInputStream();
        Reader inputReader = ss.getReader();
            
        if (inputStream != null) {
            br = new BufferedReader(new InputStreamReader(inputStream));
        } else if (inputReader != null) {
            br = new BufferedReader(inputReader);
        }
            
        if (br == null) {
            System.err.println("No reader for StreamSource");
            
            return;
        }
            
        String line;
            
        while ((line = br.readLine()) != null) {
            System.err.print(line);
        }
            
        System.err.println();
            
        //Reposition to begining oif stream
        inputStream.reset();
        } catch (Exception e) {
        }
         */
    }
}