Package org.apache.tuscany.sca.xsd.xml

Source Code of org.apache.tuscany.sca.xsd.xml.XSDModelResolver$URIResolverImpl

/*
* 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.tuscany.sca.xsd.xml;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.tuscany.sca.assembly.xsd.Constants;
import org.apache.tuscany.sca.common.xml.XMLDocumentHelper;
import org.apache.tuscany.sca.contribution.Artifact;
import org.apache.tuscany.sca.contribution.Contribution;
import org.apache.tuscany.sca.contribution.DefaultImport;
import org.apache.tuscany.sca.contribution.Import;
import org.apache.tuscany.sca.contribution.namespace.NamespaceImport;
import org.apache.tuscany.sca.contribution.processor.ContributionRuntimeException;
import org.apache.tuscany.sca.contribution.processor.ProcessorContext;
import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
import org.apache.tuscany.sca.core.FactoryExtensionPoint;
import org.apache.tuscany.sca.xsd.DefaultXSDFactory;
import org.apache.tuscany.sca.xsd.XSDFactory;
import org.apache.tuscany.sca.xsd.XSDefinition;
import org.apache.tuscany.sca.xsd.impl.XSDefinitionImpl;
import org.apache.ws.commons.schema.XmlSchema;
import org.apache.ws.commons.schema.XmlSchemaCollection;
import org.apache.ws.commons.schema.XmlSchemaInclude;
import org.apache.ws.commons.schema.resolver.URIResolver;
import org.xml.sax.InputSource;

/**
* A Model Resolver for XSD models.
*
* @version $Rev: 943224 $ $Date: 2010-05-11 11:40:54 -0700 (Tue, 11 May 2010) $
*/
public class XSDModelResolver implements ModelResolver {
    private static final String AGGREGATED_XSD = "http://tuscany.apache.org/aggregated.xsd";
    private XSDFactory factory;
    private Contribution contribution;
    private Map<String, List<XSDefinition>> map = new HashMap<String, List<XSDefinition>>();
    private XmlSchemaCollection schemaCollection;

    public XSDModelResolver(Contribution contribution, FactoryExtensionPoint modelFactories) {
        this.contribution = contribution;
        this.schemaCollection = new XmlSchemaCollection();
        this.factory = new DefaultXSDFactory();
    }

    public void addModel(Object resolved, ProcessorContext context) {
        XSDefinition definition = (XSDefinition)resolved;
        List<XSDefinition> list = map.get(definition.getNamespace());
        if (list == null) {
            list = new ArrayList<XSDefinition>();
            map.put(definition.getNamespace(), list);
        }
        list.add(definition);
    }

    public Object removeModel(Object resolved, ProcessorContext context) {
        XSDefinition definition = (XSDefinition)resolved;
        List<XSDefinition> list = map.get(definition.getNamespace());
        if (list == null) {
            return null;
        } else {
            return list.remove(definition);
        }
    }

    public <T> T resolveModel(Class<T> modelClass, T unresolved, ProcessorContext context) {
        schemaCollection.setSchemaResolver(new URIResolverImpl(contribution, context));
      XSDefinition definition = (XSDefinition)unresolved;       
        String namespace = definition.getNamespace();
        XSDefinition resolved = null;
       
        // Lookup a definition for the given namespace, within the contribution
        List<XSDefinition> list = map.get(namespace);
       
        if (list == null ||
            (list != null && list.size() == 0)){
            // if no schema is found locally delegate to other
            // contributions via the imports
            resolved = resolutionDelegation(namespace, context);
            return modelClass.cast(resolved);
        }
       
        XSDefinition modelXSD = null;
        if (list != null && definition.getDocument() != null) {
            // Set the document for the inline schema
            int index = list.indexOf(definition);
            if (index != -1) {  // a matching (not identical) document was found
                modelXSD = list.get(index);
                modelXSD.setDocument(definition.getDocument());
            }
        }
        if (list == null && definition.getDocument() != null) {
            // Hit for the 1st time
            list = new ArrayList<XSDefinition>();
            list.add(definition);
            map.put(namespace, list);
        }       
        try {
            resolved = aggregate(list);
        } catch (IOException e) {
            throw new ContributionRuntimeException(e);
        }
        if (resolved != null && !resolved.isUnresolved()) {
            if (definition.isUnresolved() && definition.getSchema() == null && modelXSD != null) {
                // Update the unresolved model with schema information and mark it
                // resolved.  This information in the unresolved model is needed when
                // this method is called by WSDLModelResolver.readInlineSchemas().
                definition.setSchema(modelXSD.getSchema());
                definition.setSchemaCollection(modelXSD.getSchemaCollection());
                definition.setUnresolved(false);
            }
            return modelClass.cast(resolved);
        }
       
        return modelClass.cast(unresolved);
    }

    private void loadOnDemand(XSDefinition definition) throws IOException {
        if (definition.getSchema() != null) {
            return;
        }
        if (definition.getDocument() != null) {
            String uri = null;
            if (definition.getLocation() != null) {
                uri = definition.getLocation().toString();
            }
            XmlSchema schema = null;
            try {
                schema = schemaCollection.read(definition.getDocument(), uri, null);
            } catch (RuntimeException e) {
                // find original cause of the problem
                Throwable cause = e;
                while (cause.getCause() != null && cause != cause.getCause()) {
                    cause = cause.getCause();
                }
                throw new ContributionRuntimeException(cause);
            }
            definition.setSchemaCollection(schemaCollection);
            definition.setSchema(schema);
            definition.setUnresolved(false);
        } else if (definition.getLocation() != null) {
            if (definition.getLocation().getFragment() != null) {
                // It's an inline schema
                return;
            }
            // Read an XSD document
            XmlSchema schema = null;
            for (XmlSchema d : schemaCollection.getXmlSchemas()) {
                if (isSameNamespace(d.getTargetNamespace(), definition.getNamespace()))  {
                    if (d.getSourceURI().equals(definition.getLocation().toString())) {
                        schema = d;
                        break;
                    }
                }
            }
            if (schema == null) {
                InputSource xsd = null;
                try {
                    xsd = XMLDocumentHelper.getInputSource(definition.getLocation().toURL());
                } catch (IOException e) {
                    throw new ContributionRuntimeException(e);
                }

                try {
                    schema = schemaCollection.read(xsd, null);
                } catch (RuntimeException e) {
                    // find original cause of the problem
                    Throwable cause = e;
                    while (cause.getCause() != null && cause != cause.getCause()) {
                        cause = cause.getCause();
                    }
                    throw new ContributionRuntimeException(cause);
                }
            }
            definition.setSchemaCollection(schemaCollection);
            definition.setSchema(schema);
        }
    }

    private boolean isSameNamespace(String ns1, String ns2) {
        if (ns1 == null) {
            return ns2 == null;
        } else {
            return ns1.equals(ns2);
        }
    }
    /**
     * Create a facade XmlSchema which includes all the definitions
     *
     * @param definitions A list of the XmlSchema under the same target
     *                namespace
     * @return The aggregated XmlSchema
     */
    private XSDefinition aggregate(List<XSDefinition> definitions) throws IOException {
        if (definitions == null || definitions.size() == 0) {
            return null;
        }
        if (definitions.size() == 1) {
            XSDefinition d = definitions.get(0);
            loadOnDemand(d);
            return d;
        }
        XSDefinition aggregated = factory.createXSDefinition();
        for (XSDefinition d : definitions) {
            loadOnDemand(d);
        }
        String ns = definitions.get(0).getNamespace();
       
        XmlSchema facade = null;
        // Check if the facade XSD is already in the collection
        for (XmlSchema s : schemaCollection.getXmlSchema(AGGREGATED_XSD)) {
            if (ns.equals(s.getTargetNamespace())) {
                facade = s;
                break;
            }
        }
        if (facade == null) {
            // This will add the facade into the collection
            facade = new XmlSchema(ns, AGGREGATED_XSD, schemaCollection);
        }

        for (XmlSchema d : schemaCollection.getXmlSchemas()) {
            if (ns.equals(d.getTargetNamespace())) {
                if (d == facade) {
                    continue;
                }
                XmlSchemaInclude include = new XmlSchemaInclude();
                include.setSchema(d);
                include.setSourceURI(d.getSourceURI());
                include.setSchemaLocation(d.getSourceURI());
                facade.getIncludes().add(include);
                facade.getItems().add(include);
            }
        }
        aggregated.setUnresolved(true);
        aggregated.setSchema(facade);
        aggregated.setNamespace(ns);
        aggregated.setAggregatedDefinitions(definitions);
        aggregated.setUnresolved(false);

        // FIXME: [rfeng] This is hacky
        //definitions.clear();
        //definitions.add(aggregated);
        return aggregated;
    }

    private XSDefinition resolutionDelegation(String namespace, ProcessorContext context){
        // Delegate the resolution to namespace imports
        XSDefinition resolved = null;               
        XSDefinition unresolved = new XSDefinitionImpl();
        unresolved.setUnresolved(true);
        unresolved.setNamespace(namespace);
                       
        for (Import import_ : this.contribution.getImports()) {
            if (import_ instanceof NamespaceImport) {
                NamespaceImport namespaceImport = (NamespaceImport)import_;
                if (namespaceImport.getNamespace().equals(namespace)) {                          
                    // Delegate the resolution to the namespace import resolver
                    resolved =
                        namespaceImport.getModelResolver().resolveModel(XSDefinition.class, (XSDefinition)unresolved, context);
                    if (!resolved.isUnresolved()) {
                        return resolved;
                    }
                }
            } else if (import_ instanceof DefaultImport) {
                // Delegate the resolution to the default import resolver
                resolved =
                    import_.getModelResolver().resolveModel(XSDefinition.class, (XSDefinition)unresolved, context);
                if (!resolved.isUnresolved()) {
                    return resolved;
                }
            }
        }
       
        return resolved;
    }
   
    /**
     * URI resolver implementation for XML schema
     */
    public static class URIResolverImpl implements URIResolver {
        private Contribution contribution;
        private ProcessorContext context;

        public URIResolverImpl(Contribution contribution, ProcessorContext context) {
            this.contribution = contribution;
            this.context = context;
        }

        public org.xml.sax.InputSource resolveEntity(java.lang.String targetNamespace,
                                                     java.lang.String schemaLocation,
                                                     java.lang.String baseUri) {
            try {
                if (schemaLocation == null) {
                    return null;
                }
                URL url = null;
               
                // Delegate the resolution to namespace imports
                XSDefinition resolved = null;               
                XSDefinition unresolved = new XSDefinitionImpl();
                unresolved.setUnresolved(true);
                unresolved.setLocation(new URI(schemaLocation));
                unresolved.setNamespace(targetNamespace);
                               
                for (Import import_ : this.contribution.getImports()) {
                    if (import_ instanceof NamespaceImport) {
                        NamespaceImport namespaceImport = (NamespaceImport)import_;
                        if (namespaceImport.getNamespace().equals(targetNamespace)) {                         
                          // Delegate the resolution to the namespace import resolver
                          resolved =
                              namespaceImport.getModelResolver().resolveModel(XSDefinition.class, (XSDefinition)unresolved, context);
                          if (!resolved.isUnresolved()) {
                            return XMLDocumentHelper.getInputSource(resolved.getLocation().toURL());
                          }
                        }
                    } else if (import_ instanceof DefaultImport) {
                        // Delegate the resolution to the default import resolver
                        resolved =
                            import_.getModelResolver().resolveModel(XSDefinition.class, (XSDefinition)unresolved, context);
                        if (!resolved.isUnresolved()) {
                          return XMLDocumentHelper.getInputSource(resolved.getLocation().toURL());
                        }
                    }
                }
               
                // Not found, lookup a definition for the given namespace
                // within the current contribution.
                if (schemaLocation.startsWith("/")) {
                    // The URI is relative to the contribution
                    String uri = schemaLocation.substring(1);
                    for (Artifact a : contribution.getArtifacts()) {
                        if (a.getURI().equals(uri)) {
                            url = new URL(a.getLocation());
                            break;
                        }
                    }
                    if (url == null) {
                        // URI not found in the contribution; return a default InputSource
                        // so that the XmlSchema code will produce a useful diagnostic
                        return new InputSource(schemaLocation);
                    }
                } else {
                    // look to see whether Tuscany has a local version of the
                    // required schema. It can load the local version rather
                    // than going out to the network in order to improve performance
                    url = Constants.CACHED_XSDS.get(targetNamespace);
                   
                    if (url == null) {
                        url = new URL(new URL(baseUri), schemaLocation);
                    }
                }
                return XMLDocumentHelper.getInputSource(url);
            } catch (IOException e) {
              // Invalid URI; return a default InputSource so that the
                // XmlSchema code will produce a useful diagnostic
                return new InputSource(schemaLocation);
            } catch (URISyntaxException e) {
              // Invalid URI; return a default InputSource so that the
                // XmlSchema code will produce a useful diagnostic
                return new InputSource(schemaLocation);
            }
        }
    }

}
TOP

Related Classes of org.apache.tuscany.sca.xsd.xml.XSDModelResolver$URIResolverImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.