/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.ode.bpel.compiler; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.wsdl.Definition; import javax.wsdl.Import; import javax.wsdl.Message; import javax.wsdl.PortType; import javax.wsdl.Types; import javax.wsdl.extensions.ExtensibilityElement; import javax.xml.namespace.QName; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.ode.bpel.compiler.api.CompilationException; import org.apache.ode.bpel.compiler.api.CompilerContext; import org.apache.ode.bpel.compiler.bom.PartnerLinkType; import org.apache.ode.bpel.compiler.bom.PropertyAlias; import org.apache.ode.bpel.compiler.wsdl.Definition4BPEL; import org.apache.ode.bpel.compiler.wsdl.XMLSchemaType; import org.apache.ode.utils.DOMUtils; import org.apache.ode.utils.Namespaces; import org.apache.ode.utils.StreamUtils; import org.apache.ode.utils.msg.MessageBundle; import org.apache.ode.utils.xsd.SchemaModel; import org.apache.ode.utils.xsd.SchemaModelImpl; import org.apache.ode.utils.xsd.XSUtils; import org.apache.ode.utils.xsd.XsdException; import org.w3c.dom.Document; import org.xml.sax.InputSource; /** * A parsed collection of WSDL definitions, including BPEL-specific extensions. */ class WSDLRegistry { private static final Logger __log = LoggerFactory.getLogger(WSDLRegistry.class); private static final CommonCompilationMessages __cmsgs = MessageBundle.getMessages(CommonCompilationMessages.class); private final HashMap<String, ArrayList<Definition4BPEL>> _definitions = new HashMap<String, ArrayList<Definition4BPEL>>(); private final Map<URI, byte[]> _schemas = new HashMap<URI,byte[]>(); private final Map<URI, byte[]> _internalSchemas = new HashMap<URI, byte[]>(); private final Map<URI, Document> _documentSchemas = new HashMap<URI, Document>(); private SchemaModel _model; private CompilerContext _ctx; WSDLRegistry(CompilerContext cc) { // bogus schema to force schema creation _schemas.put(URI.create("http://fivesight.com/bogus/namespace"), ("<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" + " targetNamespace=\"http://fivesight.com/bogus/namespace\">" + "<xsd:simpleType name=\"__bogusType__\">" + "<xsd:restriction base=\"xsd:normalizedString\"/>" + "</xsd:simpleType>" + "</xsd:schema>").getBytes()); try { _schemas.put(URI.create(Namespaces.WSDL_11), StreamUtils.read(getClass().getResource("/wsdl.xsd"))); _schemas.put(URI.create("http://www.w3.org/2001/xml.xsd"), StreamUtils.read(getClass().getResource("/xml.xsd"))); } catch (IOException e) { throw new RuntimeException("Couldn't load default schemas.", e); } _ctx = cc; } public Definition4BPEL[] getDefinitions(){ ArrayList<Definition4BPEL> result = new ArrayList<Definition4BPEL>(); for (ArrayList<Definition4BPEL> definition4BPELs : _definitions.values()) { for (Definition4BPEL definition4BPEL : definition4BPELs) { result.add(definition4BPEL); } } return result.toArray(new Definition4BPEL[result.size()]); } /** * Get the schema model (XML Schema). * * @return schema model */ public SchemaModel getSchemaModel() { if (_model == null) { _model = SchemaModelImpl.newModel(_schemas); } assert _model != null; return _model; } /** * Adds a WSDL definition for use in resolving MessageType, PortType, * Operation and BPEL properties and property aliases * * @param def WSDL definition */ @SuppressWarnings("unchecked") public void addDefinition(Definition4BPEL def, ResourceFinder rf, URI defuri) throws CompilationException { if (def == null) throw new NullPointerException("def=null"); if (__log.isDebugEnabled()) { __log.debug("addDefinition(" + def.getTargetNamespace() + " from " + def.getDocumentBaseURI() + ")"); } if (_definitions.containsKey(def.getTargetNamespace())) { // This indicates that we imported a WSDL with the same namespace from // two different locations. This is not an error, but should be a warning. if (__log.isInfoEnabled()) { __log.info("WSDL at " + defuri + " is a duplicate import, your documents " + "should all be in different namespaces (its's not nice but will still work)."); } for (Definition4BPEL aDef : _definitions.get(def.getTargetNamespace())) { if (aDef.getDocumentBaseURI().equals(def.getDocumentBaseURI())) { if (__log.isInfoEnabled()) { __log.info("WSDL at " + defuri + " is already imported, this denotes a circular reference."); // no need to keep going: either return or throw an error } return; } } } ArrayList<Definition4BPEL> defs = null; if (_definitions.get(def.getTargetNamespace()) == null) defs = new ArrayList<Definition4BPEL>(); else defs = _definitions.get(def.getTargetNamespace()); defs.add(def); _definitions.put(def.getTargetNamespace(), defs); captureSchemas(def, rf, defuri); if (__log.isDebugEnabled()) __log.debug("Processing <imports> in " + def.getDocumentBaseURI()); for (List<Import> imports : ((Map<String, List<Import>>)def.getImports()).values()) { HashSet<String> imported = new HashSet<String>(); for (Import im : imports) { // If there are several imports in the same WSDL all importing the same namespace // that is a sure sign of programmer error. if (imported.contains(im.getNamespaceURI())) { if (__log.isInfoEnabled()) { __log.info("WSDL at " + im.getLocationURI() + " imports several documents in the same " + "namespace (" + im.getNamespaceURI() + "), your documents should all be in different " + "namespaces (its's not nice but will still work)."); } } Definition4BPEL importDef = (Definition4BPEL) im.getDefinition(); // The assumption here is that if the definition is not set on the // import object then there was some problem parsing the thing, // although it would have been nice to actually get the parse // error. if (importDef == null) { CompilationException ce = new CompilationException( __cmsgs.errWsdlImportNotFound(im.getNamespaceURI(), im.getLocationURI()).setSource(new SourceLocationImpl(defuri))); if (_ctx == null) throw ce; _ctx.recoveredFromError(new SourceLocationImpl(defuri), ce); continue; } imported.add(im.getNamespaceURI()); addDefinition((Definition4BPEL) im.getDefinition(), rf, defuri.resolve(im.getLocationURI())); } } } public void addSchemas(Map<URI, byte[]> capture) { _schemas.putAll(capture); } @SuppressWarnings("unchecked") private void captureSchemas(Definition def, ResourceFinder rf, URI defuri) throws CompilationException { assert def != null; if (__log.isDebugEnabled()) __log.debug("Processing XSD schemas in " + def.getDocumentBaseURI()); Types types = def.getTypes(); if (types != null) { addAllInternalSchemas(def); int localSchemaId = 0; for (Iterator<ExtensibilityElement> iter = ((List<ExtensibilityElement>)def.getTypes().getExtensibilityElements()).iterator(); iter.hasNext();) { ExtensibilityElement ee = iter.next(); if (ee instanceof XMLSchemaType) { byte[] schema = ((XMLSchemaType)ee).getXMLSchema(); WsdlFinderXMLEntityResolver resolver = new WsdlFinderXMLEntityResolver(rf, defuri, _internalSchemas, false); try { Map<URI, byte[]> capture = XSUtils.captureSchema(defuri, schema, resolver, localSchemaId); for (URI uri : capture.keySet()) { if (!_schemas.containsKey(uri)) { _schemas.put(uri, capture.get(uri)); } } // _schemas.putAll(capture); try { Document doc = DOMUtils.parse(new InputSource(new ByteArrayInputStream(schema))); String schemaTargetNS = doc.getDocumentElement().getAttribute("targetNamespace"); if (schemaTargetNS != null && schemaTargetNS.length() > 0) { URI schemaNamespace = new URI(schemaTargetNS); if (!_internalSchemas.containsKey(schemaNamespace)) { _internalSchemas.put(schemaNamespace, schema); } if (!_documentSchemas.containsKey(schemaNamespace)) { _documentSchemas.put(schemaNamespace, doc); } } } catch (Exception e) { throw new RuntimeException("Couldn't parse schema in " + def.getTargetNamespace(), e); } } catch (XsdException xsde) { __log.debug("captureSchemas: capture failed for " + defuri,xsde); LinkedList<XsdException> exceptions = new LinkedList<XsdException>(); while (xsde != null) { exceptions.addFirst(xsde); xsde = xsde.getPrevious(); } for (XsdException ex : exceptions) { // TODO: the line number here is going to be wrong for the in-line schema. // String location = ex.getSystemId() + ":" + ex.getLineNumber(); CompilationException ce = new CompilationException( __cmsgs.errSchemaError(ex.getDetailMessage()).setSource(new SourceLocationImpl(defuri))); if (_ctx != null) _ctx.recoveredFromError(new SourceLocationImpl(defuri),ce); else throw ce; } } // invalidate model _model = null; localSchemaId ++; } } } } @SuppressWarnings("unchecked") private void addAllInternalSchemas(Definition def) { for (Iterator<ExtensibilityElement> iter = ((List<ExtensibilityElement>) def.getTypes().getExtensibilityElements()).iterator(); iter.hasNext();) { ExtensibilityElement ee = iter.next(); if (ee instanceof XMLSchemaType) { byte[] schema = ((XMLSchemaType) ee).getXMLSchema(); try { Document doc = DOMUtils.parse(new InputSource(new ByteArrayInputStream(schema))); String schemaTargetNS = doc.getDocumentElement().getAttribute("targetNamespace"); if (schemaTargetNS != null && schemaTargetNS.length() > 0) { _internalSchemas.put(new URI(schemaTargetNS), schema); _documentSchemas.put(new URI(schemaTargetNS), doc); } } catch (Exception e) { throw new RuntimeException("Couldn't parse schema in " + def.getTargetNamespace(), e); } } } } public org.apache.ode.bpel.compiler.bom.Property getProperty(QName name) { ArrayList<Definition4BPEL> defs = _definitions.get(name.getNamespaceURI()); if (defs == null) return null; for (Definition4BPEL definition4BPEL : defs) { if (definition4BPEL != null && definition4BPEL.getProperty(name) != null) return definition4BPEL.getProperty(name); } return null; } public PropertyAlias getPropertyAlias(QName propertyName, QName messageType) { ArrayList<Definition4BPEL> defs = _definitions.get(propertyName.getNamespaceURI()); if (defs == null) return null; for (Definition4BPEL definition4BPEL : defs) { if (definition4BPEL != null && definition4BPEL.getPropertyAlias(propertyName, messageType) != null) return definition4BPEL.getPropertyAlias(propertyName, messageType); } return null; } public PartnerLinkType getPartnerLinkType(QName partnerLinkType) { ArrayList<Definition4BPEL> defs = _definitions.get(partnerLinkType.getNamespaceURI()); if (defs == null) return null; for (Definition4BPEL definition4BPEL : defs) { if (definition4BPEL != null && definition4BPEL.getPartnerLinkType(partnerLinkType) != null) return definition4BPEL.getPartnerLinkType(partnerLinkType); } return null; } public PortType getPortType(QName portType) { ArrayList<Definition4BPEL> defs = _definitions.get(portType.getNamespaceURI()); if (defs == null) return null; for (Definition4BPEL definition4BPEL : defs) { if (definition4BPEL != null && definition4BPEL.getPortType(portType) != null) return definition4BPEL.getPortType(portType); } return null; } public Message getMessage(QName msgType) { ArrayList<Definition4BPEL> defs = _definitions.get(msgType.getNamespaceURI()); if (defs == null) return null; for (Definition4BPEL definition4BPEL : defs) { if (definition4BPEL != null && definition4BPEL.getMessage(msgType) != null) return definition4BPEL.getMessage(msgType); } return null; } /** * @return All parsed schemas. This doesn't include schemas from bpel imports. */ Map<URI, Document> getSchemaDocuments() { return _documentSchemas; } /** * @return All captured schema sources including those from bpel imports. */ Map<URI, Source> getSchemaSources() { Map<URI, Source> schemaSources = new HashMap<URI, Source>(); for (URI uri : _documentSchemas.keySet()) { Document document = _documentSchemas.get(uri); schemaSources.put(uri, new DOMSource(document)); } for (URI uri : _schemas.keySet()) { schemaSources.put(uri, new StreamSource(new ByteArrayInputStream(_schemas.get(uri)))); } return schemaSources; } }