pl.touk.ode.validator.XQueryAnalyzer.java Source code

Java tutorial

Introduction

Here is the source code for pl.touk.ode.validator.XQueryAnalyzer.java

Source

package pl.touk.ode.validator;

import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;

import net.sf.saxon.Configuration;
import net.sf.saxon.pattern.CombinedNodeTest;
import net.sf.saxon.pattern.NodeTest;
import net.sf.saxon.query.StaticQueryContext;
import net.sf.saxon.query.XQueryExpression;
import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.ItemTypeFactory;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XQueryEvaluator;
import net.sf.saxon.s9api.XdmEmptySequence;
import net.sf.saxon.s9api.XdmItem;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XdmValue;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.AnyItemType;
import net.sf.saxon.type.AnyType;
import net.sf.saxon.type.AtomicType;
import net.sf.saxon.type.BuiltInAtomicType;
import net.sf.saxon.type.ItemType;
import net.sf.saxon.type.SchemaType;
import net.sf.saxon.type.SchemaURIResolver;
import net.sf.saxon.type.TypeHierarchy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ode.bpel.compiler.api.CompilationException;
import org.apache.ode.bpel.compiler.api.CompilationMessage;
import org.apache.ode.bpel.compiler.api.CompilerContext;
import org.apache.ode.bpel.compiler.api.SourceLocation;
import org.apache.ode.bpel.o.OElementVarType;
import org.apache.ode.bpel.o.OVarType;
import org.apache.ode.bpel.o.OXsdTypeVarType;
import org.apache.ode.utils.DOMUtils;
import org.xml.sax.InputSource;

public class XQueryAnalyzer {
    private static final Log __log = LogFactory.getLog(XQueryAnalyzer.class);

    private Configuration config;
    private Processor processor;

    public Map<String, List<URI>> schemaNamespaces;

    private String getSchemaTNS(XdmItem schema) throws SaxonApiException {
        XQueryEvaluator e = processor.newXQueryCompiler().compile(
                "declare namespace xsd = \"http://www.w3.org/2001/XMLSchema\"; xsd:string(xsd:schema/@targetNamespace)")
                .load();
        e.setContextItem(schema);
        XdmValue v = e.evaluate();
        if (v instanceof XdmEmptySequence)
            return null;
        else
            return v.toString();
    }

    private XdmNode buildXdmNode(Source s, URI baseURI) throws SaxonApiException {
        DocumentBuilder builder = processor.newDocumentBuilder();
        builder.setBaseURI(baseURI);
        return builder.build(s);
    }

    public void init(CompilerContext compilerContext) throws Exception {
        processor = new Processor(true);
        Configuration config2 = processor.getUnderlyingConfiguration();
        config2.displayLicenseMessage();
        config2.setValidationWarnings(true);

        config2.setErrorListener(new ErrorListener() {
            public void error(TransformerException arg0) throws TransformerException {
                __log.error(arg0);
            }

            public void fatalError(TransformerException arg0) throws TransformerException {
                if (!arg0.getMessage().contains("Duplicate")) {
                    __log.fatal(arg0);
                }
            }

            public void warning(TransformerException arg0) throws TransformerException {
                __log.warn(arg0);
            }
        });

        __log.debug("schemaSourcesURIs " + compilerContext.getSchemaSources().keySet());
        schemaNamespaces = new HashMap<String, List<URI>>();

        URI baseURI = compilerContext.getBaseResourceURI();
        Map<URI, Source> odeSchemaSources = compilerContext.getSchemaSources();
        final Map<URI, XdmNode> schemaSources = new HashMap<URI, XdmNode>();
        for (URI u : odeSchemaSources.keySet()) {
            schemaSources.put(u, buildXdmNode(odeSchemaSources.get(u), u.isAbsolute() ? u : baseURI));
        }
        schemaSources.put(URI.create("ode-validator.xsd"), buildXdmNode(
                new javax.xml.transform.stream.StreamSource(getClass().getResourceAsStream("/ode-validator.xsd")),
                baseURI));

        //        config2.setSchemaURIResolver(new SchemaURIResolver() {
        //         public Source[] resolve(String targetNamespace, String baseURI, String[] locations)
        //               throws XPathException {
        //            if (__log.isDebugEnabled()) {
        //               List<String> l = new ArrayList<String>();
        //               Collections.addAll(l, locations);
        //               __log.debug("resolve schema tns: " + targetNamespace + " baseURI: " + baseURI + " locations: " + l);
        //            }
        //            Source[] result = new Source[locations.length];
        //            for (int i = 0; i < locations.length; i++) {
        //               String location = locations[i];
        //               XdmNode n = schemaSources.get(URI.create(location));
        //               if (__log.isDebugEnabled()) {
        //                  __log.debug("schema: " + n);
        //               }
        //               result[i] = n == null ? null : n.asSource();
        //            }
        //            return result;
        //         }
        //
        //         public void setConfiguration(Configuration arg0) {
        //         }
        //        });

        for (URI u : schemaSources.keySet()) {
            XdmNode schema = schemaSources.get(u);
            String tns = getSchemaTNS(schema);
            __log.debug("Schema URI: " + u + " tns: " + tns);
            try {
                //              if (new File(u.toASCIIString()).exists()) {
                //                 config2.loadSchema(u.toASCIIString());
                //              } else {
                config2.addSchemaSource(schema.asSource());
                __log.debug("schema contents: " + schema);
                //              }

                if (tns != null) {
                    List<URI> l = schemaNamespaces.get(tns);
                    if (l == null) {
                        l = new ArrayList<URI>();
                        schemaNamespaces.put(tns, l);
                    }
                    l.add(u);
                }
            } catch (Exception e) {
                __log.warn("Can't load schema " + u + " due to " + e);
            }
        }

        //      config2.loadSchema("file:/home/joker/dev/mnp/manager/trunk/process-mnpm-portOut/ode-su/target/classes/CaseProcess.wsdl");

        //      __log.debug("loaded target namespace " + ((SchemaAwareConfiguration) config2).getSuperSchema().getTargetNamespaces());
    }

    ItemType resolveType(ItemTypeFactory itf, OVarType t) throws SaxonApiException {
        if (t instanceof OXsdTypeVarType) {
            return itf.getElementTest(null, new QName(((OXsdTypeVarType) t).xsdType), false)
                    .getUnderlyingItemType();
        } else if (t instanceof OElementVarType) {
            OElementVarType e = (OElementVarType) t;
            if (e.elementType.getNamespaceURI().contains("database")) {
                return AnyItemType.getInstance();
            } else {
                return itf.getSchemaElementTest(new QName(e.elementType)).getUnderlyingItemType();
            }
        } else {
            return null;
        }
    }

    public Object analyze(String query, URI baseResourceURI, SourceLocation sourceLocation, OVarType rootNodeType)
            throws CompilationException {
        Object resultType = null;
        config = processor.getUnderlyingConfiguration().copy();
        config.setHostLanguage(Configuration.XQUERY);

        final List<Object> errors = new ArrayList<Object>();
        config.setErrorListener(new ErrorListener() {

            public void error(TransformerException arg0) throws TransformerException {
                errors.add(arg0);
            }

            public void fatalError(TransformerException arg0) throws TransformerException {
                errors.add(arg0);
            }

            public void warning(TransformerException arg0) throws TransformerException {
                errors.add(arg0);
            }

        });

        StaticQueryContext staticEnv = new StaticQueryContext(config);
        try {
            {
                ItemTypeFactory itf = new ItemTypeFactory(processor);
                ItemType t = resolveType(itf, rootNodeType);
                __log.debug("resolved context item type " + t);
                staticEnv.setRequiredContextItemType(t);
            }
            staticEnv.setBaseURI(baseResourceURI.toString());

            XQueryExpression exp = staticEnv.compileQuery(query);

            resultType = exp.getExpression().getItemType(config.getTypeHierarchy());
        } catch (XPathException err) {
            int line = -1;
            String module = null;
            if (err.getLocator() != null) {
                line = err.getLocator().getLineNumber();
                module = err.getLocator().getSystemId();
            }
            errors.add("line " + line + " module " + module + " " + err);
        } catch (SaxonApiException e1) {
            __log.error(query, e1);
            errors.add(e1);
        } catch (Exception e) {
            __log.error(query, e);
            errors.add(e);
        }

        if (errors.size() > 0) {
            CompilationMessage m = new CompilationMessage();
            m.severity = CompilationMessage.ERROR;
            m.code = "";
            m.setSource(sourceLocation);
            m.messageText = errors.toString();
            __log.debug(m + " query: " + query + " errors " + errors);
            throw new CompilationException(m);
        }

        return resultType;
    }

    public ItemType unifyTypeFromODE(Object t) {
        ItemTypeFactory itf = new ItemTypeFactory(processor);
        if (t instanceof ItemType) {
            return (ItemType) t;
        } else if (t instanceof OVarType) {
            try {
                return resolveType(itf, (OVarType) t);
            } catch (SaxonApiException e) {
                __log.error(e);
                return null;
            }
        }
        return null;
    }

    /**
     * @return Whether to insert 'validate { }' code into generated xquery expression
     */
    public boolean doValidate(Object requestedType) {
        ItemType t = unifyTypeFromODE(requestedType);
        t = simplify(t);
        if (t == null || t.isAtomicType())
            return false;
        return true;
    }

    /**
     * Simplify type so that hierarchy comparison could be accurate.
     */
    private ItemType simplify(ItemType it) {
        TypeHierarchy th = processor.getUnderlyingConfiguration().getTypeHierarchy();

        if (it instanceof CombinedNodeTest) {
            CombinedNodeTest n = (CombinedNodeTest) it;
            __log.debug(n.getComponentNodeTests());
            return simplify(n.getComponentNodeTests()[1]);
        } else if (it instanceof NodeTest) {
            NodeTest n = (NodeTest) it;
            __log.debug(n);

            SchemaType t = n.getContentType();
            if (t.isSimpleType() || t.equals(AnyType.getInstance())) {
                AtomicType at = it.getAtomizedItemType();
                while (!at.isBuiltInType())
                    at = at.getSuperType(th).getAtomizedItemType();
                return at;
            } else if (t.isComplexType()) {
                return n;
            } else {
                return AnyItemType.getInstance();
            }
        } else {
            if (it == null)
                return null;
            else
                return it.getAtomizedItemType();
        }
    }

    public boolean checkAssign(ItemType to, ItemType from) {
        TypeHierarchy th = processor.getUnderlyingConfiguration().getTypeHierarchy();
        return th.isSubType(from, to);
    }

    /**
     * Test if assign is ok for toType := fromType
     * @param sourceLocation
     * @param expr
     * @param toType
     * @param fromType
     * @throws CompilationException
     */
    public void verifyAssignable(SourceLocation sourceLocation, String expr, Object toType, Object fromType)
            throws CompilationException {
        ItemType toType2 = unifyTypeFromODE(toType);
        ItemType fromType2 = unifyTypeFromODE(fromType);

        if (toType2 != null && fromType2 != null) {
            ItemType toType3 = simplify(toType2);
            ItemType fromType3 = simplify(fromType2);
            __log.debug("resolved: " + toType2 + " := " + fromType2 + " simplified: " + toType3 + " := " + fromType3
                    + " expression: " + expr);

            if (toType3.equals(BuiltInAtomicType.ANY_ATOMIC) || fromType3.equals(BuiltInAtomicType.ANY_ATOMIC)) {
                __log.debug("omiting verify assign due to anyTypes " + toType2 + " := " + fromType2 + " "
                        + sourceLocation);
                return;
            }

            if (!checkAssign(toType3, fromType3)) {
                CompilationMessage m = new CompilationMessage();
                m.severity = CompilationMessage.ERROR;
                m.code = "";
                m.setSource(sourceLocation);
                m.messageText = "Incompatible copy error: " + toType2 + " := " + fromType2 + " simplified: "
                        + toType3 + " := " + fromType3 + " expression: " + expr;
                throw new CompilationException(m);
            }
        } else {
            __log.warn("Unable to verify assign " + toType2 + " := " + fromType2 + " " + sourceLocation);
        }
    }

}