Java tutorial
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); } } }