aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gno...@apache.org
Subject svn commit: r1738921 - in /aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint: container/BlueprintContainerImpl.java namespace/NamespaceHandlerRegistryImpl.java
Date Wed, 13 Apr 2016 10:39:36 GMT
Author: gnodet
Date: Wed Apr 13 10:39:35 2016
New Revision: 1738921

URL: http://svn.apache.org/viewvc?rev=1738921&view=rev
Log:
[ARIES-1503] Another fix and small refactoring

The trick is to remember loaded resources and recognize 'bad' behaving namespace handlers,
i.e. those that always return the same url, irrespective of the resource trying to be loaded.
If a loader returns an already loaded url for a resource, we ignore those.

In order for this to work, we also need to be smarter about identifying similar resources.
We need to cope with the fact that a schema can be imported with or without a location for
example, so we ignore the systemId when the schema is imported.  If the resource has already
been loaded, quickly return the previously loaded resource.

The blueprint container is also fixed wrt to added namespaces.  The handler set now do a copy
of the schemas, and we use those to find missing namespaces.  Whenever a handler is removed,
we can't easily find out which namespaces have been dynamically added, so we simply recreate
the handler set completely.

Modified:
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java

Modified: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java?rev=1738921&r1=1738920&r2=1738921&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java
(original)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java
Wed Apr 13 10:39:35 2016
@@ -315,7 +315,7 @@ public class BlueprintContainerImpl
                     {
                         List<String> missing = new ArrayList<String>();
                         List<URI> missingURIs = new ArrayList<URI>();
-                        for (URI ns : namespaces) {
+                        for (URI ns : handlerSet.getNamespaces()) {
                             if (handlerSet.getNamespaceHandler(ns) == null) {
                                 missing.add("(&(" + Constants.OBJECTCLASS + "=" + NamespaceHandler.class.getName()
+ ")(" + NamespaceHandlerRegistryImpl.NAMESPACE + "=" + ns + "))");
                                 missingURIs.add(ns);
@@ -351,7 +351,7 @@ public class BlueprintContainerImpl
                         } catch (MissingNamespaceException e) {
                             // If we found a missing namespace when parsing the schema,
                             // we remain in the current state
-                            namespaces.add(e.getNamespace());
+                            handlerSet.getNamespaces().add(e.getNamespace());
                         }
                         break;
                     }
@@ -933,13 +933,13 @@ public class BlueprintContainerImpl
     }
 
     public void namespaceHandlerRegistered(URI uri) {
-        if (namespaces != null && namespaces.contains(uri)) {
+        if (handlerSet != null && handlerSet.getNamespaces().contains(uri)) {
             schedule();
         }
     }
 
     public void namespaceHandlerUnregistered(URI uri) {
-        if (namespaces != null && namespaces.contains(uri)) {
+        if (handlerSet != null && handlerSet.getNamespaces().contains(uri)) {
             synchronized (scheduled) {
                 if (destroyed.get()) {
                     return;
@@ -948,6 +948,10 @@ public class BlueprintContainerImpl
                 resetComponentDefinitionRegistry();
                 cancelFutureIfPresent();
                 this.repository = null;
+                handlerSet.removeListener(this);
+                handlerSet.destroy();
+                handlerSet = handlers.getNamespaceHandlers(namespaces, getBundle());
+                handlerSet.addListener(this);
                 state = State.WaitForNamespaceHandlers;
                 schedule();
             }

Modified: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java?rev=1738921&r1=1738920&r2=1738921&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java
(original)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java
Wed Apr 13 10:39:35 2016
@@ -44,7 +44,6 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
-import javax.xml.XMLConstants;
 import javax.xml.transform.Source;
 import javax.xml.transform.stream.StreamSource;
 import javax.xml.validation.Schema;
@@ -64,6 +63,10 @@ import org.w3c.dom.ls.LSInput;
 import org.w3c.dom.ls.LSResourceResolver;
 import org.xml.sax.SAXException;
 
+import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI;
+import static javax.xml.XMLConstants.XML_NS_URI;
+import static org.apache.aries.blueprint.parser.Parser.BLUEPRINT_NAMESPACE;
+
 /**
  * Default implementation of the NamespaceHandlerRegistry.
  * 
@@ -94,7 +97,7 @@ public class NamespaceHandlerRegistryImp
 
     // Access to this factory is synchronized on itself
     private final SchemaFactory schemaFactory =
-                        SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+                        SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI);
 
     // Access to this variable is must be synchronized on itself
     private final ArrayList<NamespaceHandlerSetImpl> sets =
@@ -388,7 +391,7 @@ public class NamespaceHandlerRegistryImp
 
         public NamespaceHandlerSetImpl(Set<URI> namespaces, Bundle bundle) {
             this.listeners = new CopyOnWriteArrayList<Listener>();
-            this.namespaces = namespaces;
+            this.namespaces = new HashSet<URI>(namespaces);
             this.bundle = bundle;
             handlers = new ConcurrentHashMap<URI, NamespaceHandler>();
             for (URI ns : namespaces) {
@@ -458,13 +461,155 @@ public class NamespaceHandlerRegistryImp
             return schema;
         }
 
+        private class Loader implements LSResourceResolver, AutoCloseable {
+            final List<StreamSource> sources = new ArrayList<StreamSource>();
+            final Map<String, URL> loaded = new HashMap<String, URL>();
+            final Map<String, String> namespaces = new HashMap<String, String>();
+            @Override
+            public LSInput resolveResource(String type, String namespaceURI, String publicId,
String systemId, String baseURI) {
+                // Compute id
+                String id;
+                String prevNamespace = baseURI != null ? namespaces.get(baseURI) : null;
+                if (namespaceURI != null && prevNamespace != null && namespaceURI.equals(prevNamespace))
{
+                    // This is an include
+                    id = getId(type, namespaceURI, publicId, systemId);
+                } else {
+                    id = getId(type, namespaceURI, publicId, null);
+                }
+                // Check if it has already been loaded
+                if (loaded.containsKey(id)) {
+                    return createLSInput(loaded.get(id), id, namespaceURI);
+                }
+                // Schema map
+                //-----------
+                // Use provided schema map to find the resource.
+                // If the schema map contains the namespaceURI, publicId or systemId,
+                // load the corresponding resource directly from the bundle.
+                String loc = null;
+                if (namespaceURI != null) {
+                    loc = schemaMap.getProperty(namespaceURI);
+                }
+                if (loc == null && publicId != null) {
+                    loc = schemaMap.getProperty(publicId);
+                }
+                if (loc == null && systemId != null) {
+                    loc = schemaMap.getProperty(systemId);
+                }
+                if (loc != null) {
+                    URL url = bundle.getResource(loc);
+                    if (url != null) {
+                        return createLSInput(url, id, namespaceURI);
+                    }
+                }
+                // Relative uris
+                //---------------
+                // For relative uris, don't use the namespace handlers, but simply resolve
the uri
+                // and use that one directly to load the resource.
+                String resolved = resolveIfRelative(systemId, baseURI);
+                if (resolved != null) {
+                    URL url;
+                    try {
+                        url = new URL(resolved);
+                    } catch (IOException e) {
+                        throw new RuntimeException(e);
+                    }
+                    return createLSInput(url, id, namespaceURI);
+                }
+                // Only support xml schemas from now on
+                if (namespaceURI == null || !W3C_XML_SCHEMA_NS_URI.equals(type)) {
+                    return null;
+                }
+                // We are now loading a schema, or schema part with
+                //  * notNull(namespaceURI)
+                //  * null(systemId) or absolute(systemId)
+                URI nsUri = URI.create(namespaceURI);
+                String rid = systemId != null ? systemId : namespaceURI;
+                NamespaceHandler h = getNamespaceHandler(nsUri);
+                // This is a resource from a known namespace
+                if (h != null) {
+                    URL url = h.getSchemaLocation(rid);
+                    if (isCorrectUrl(url)) {
+                        return createLSInput(url, id, namespaceURI);
+                    }
+                }
+                else {
+                    // Ask known handlers if they have this schema
+                    for (NamespaceHandler hd : handlers.values()) {
+                        URL url = hd.getSchemaLocation(rid);
+                        if (isCorrectUrl(url)) {
+                            return createLSInput(url, id, namespaceURI);
+                        }
+                    }
+                    // Find a compatible namespace handler
+                    LOGGER.warn("Dynamically adding namespace handler {} to bundle {}/{}",
+                            nsUri, bundle.getSymbolicName(), bundle.getVersion());
+                    h = findCompatibleNamespaceHandler(nsUri);
+                    if (h != null) {
+                        URL url = h.getSchemaLocation(rid);
+                        if (isCorrectUrl(url)) {
+                            return createLSInput(url, id, namespaceURI);
+                        }
+                    }
+                }
+                return null;
+            }
+
+            public String getId(String type, String namespaceURI, String publicId, String
systemId) {
+                return type + "|" + namespaceURI + "|" + publicId + "|" + systemId;
+            }
+
+            public StreamSource use(URL resource, String id, String namespace) throws IOException
{
+                String url = resource.toExternalForm();
+                StreamSource ss = new StreamSource(resource.openStream(), url);
+                sources.add(ss);
+                loaded.put(id, resource);
+                namespaces.put(url, namespace);
+                return ss;
+            }
+
+            @Override
+            public void close() {
+                for (StreamSource source : sources) {
+                    closeQuietly(source.getInputStream());
+                }
+            }
+
+            public Source[] getSources() {
+                return sources.toArray(new Source[sources.size()]);
+            }
+
+            private boolean isCorrectUrl(URL url) {
+                return url != null && !loaded.values().contains(url);
+            }
+            private String resolveIfRelative(String systemId, String baseURI) {
+                if (baseURI != null && systemId != null) {
+                    URI sId = URI.create(systemId);
+                    if (!sId.isAbsolute()) {
+                        return URI.create(baseURI).resolve(sId).toString();
+                    }
+                }
+                return null;
+            }
+            private LSInput createLSInput(URL url, String id, String namespace) {
+                try {
+                    return new SourceLSInput(use(url, id, namespace));
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+
         private Schema createSchema(Map<String, String> locations) throws IOException,
SAXException {
-            final List<StreamSource> schemaSources = new ArrayList<StreamSource>();
+            Loader loader = new Loader();
             try {
-                schemaSources.add(new StreamSource(getClass().getResourceAsStream("/org/apache/aries/blueprint/blueprint.xsd")));
-                schemaSources.add(new StreamSource(getClass().getResourceAsStream("/org/apache/aries/blueprint/ext/impl/xml.xsd")));
-                // Create a schema for all namespaces known at this point
-                // It will speed things as it can be reused for all other blueprint containers
+                loader.use(getClass().getResource("/org/osgi/service/blueprint/blueprint.xsd"),
+                           loader.getId(W3C_XML_SCHEMA_NS_URI, BLUEPRINT_NAMESPACE, null,
null),
+                           BLUEPRINT_NAMESPACE);
+                loader.use(getClass().getResource("/org/apache/aries/blueprint/ext/impl/xml.xsd"),
+                           loader.getId(W3C_XML_SCHEMA_NS_URI, XML_NS_URI, null, null),
+                           XML_NS_URI);
+
+                // Create a schema for the namespaces
                 for (URI ns : handlers.keySet()) {
                     URL url = handlers.get(ns).getSchemaLocation(ns.toString());
                     if (url == null && locations != null) {
@@ -476,7 +621,7 @@ public class NamespaceHandlerRegistryImp
                     if (url == null) {
                         LOGGER.warn("No URL is defined for schema " + ns + ". This schema
will not be validated");
                     } else {
-                        schemaSources.add(new StreamSource(url.openStream(), url.toExternalForm()));
+                        loader.use(url, loader.getId(W3C_XML_SCHEMA_NS_URI, ns.toString(),
null, null), ns.toString());
                     }
                 }
                 for (Object ns : schemaMap.values()) {
@@ -484,89 +629,18 @@ public class NamespaceHandlerRegistryImp
                     if (url == null) {
                         LOGGER.warn("No URL is defined for schema " + ns + ". This schema
will not be validated");
                     } else {
-                        schemaSources.add(new StreamSource(url.openStream(), url.toExternalForm()));
+                        loader.use(url, loader.getId(W3C_XML_SCHEMA_NS_URI, ns.toString(),
null, null), ns.toString());
                     }
                 }
-                LSResourceResolver resolver = new LSResourceResolver() {
-                    public LSInput resolveResource(String type,
-                                                   final String namespaceURI,
-                                                   final String publicId,
-                                                   String systemId,
-                                                   String baseURI) {
-                        URI nsUri = namespaceURI != null ? URI.create(namespaceURI) : null;
-                        // Use provided schema map to find the resource
-                        String loc = null;
-                        if (namespaceURI != null) {
-                            loc = schemaMap.getProperty(namespaceURI);
-                        }
-                        if (loc == null && publicId != null) {
-                            loc = schemaMap.getProperty(publicId);
-                        }
-                        if (loc == null && systemId != null) {
-                            loc = schemaMap.getProperty(systemId);
-                        }
-                        if (loc != null) {
-                            URL url = bundle.getResource(loc);
-                            if (url != null) {
-                                return createLSInput(url);
-                            }
-                        }
-                        // Support include-relative-path case
-                        if (baseURI != null && systemId != null && !systemId.matches("^[a-z][-+.0-9a-z]*:.*"))
{
-                            URL url;
-                            try {
-                                url = new URL(new URL(baseURI), systemId);
-                            } catch (IOException e) {
-                                throw new RuntimeException(e);
-                            }
-                            return createLSInput(url);
-                        }
-                        if (namespaceURI != null) {
-                            String id = systemId != null ? systemId : namespaceURI;
-                            // This is a namespace with a known handler
-                            NamespaceHandler h = getNamespaceHandler(nsUri);
-                            if (h == null) {
-                                // Find a compatible namespace
-                                LOGGER.warn("Dynamically adding namespace handler {} to bundle
{}/{}",
-                                        nsUri, bundle.getSymbolicName(), bundle.getVersion());
-                                h = findCompatibleNamespaceHandler(nsUri);
-                            }
-                            // Load from the handler
-                            if (h != null) {
-                                URL url = h.getSchemaLocation(id);
-                                if (url != null) {
-                                    return createLSInput(url);
-                                }
-                            } else {
-                                throw new MissingNamespaceException(nsUri);
-                            }
-                        }
-                        return null;
-                    }
-
-                    private LSInput createLSInput(URL url) {
-                        try {
-                            String systemId = url.toExternalForm();
-                            final StreamSource source = new StreamSource(url.openStream(),
systemId);
-                            schemaSources.add(source);
-                            return new SourceLSInput(source);
-                        } catch (IOException e) {
-                            throw new RuntimeException(e);
-                        }
-                    }
-                };
                 synchronized (schemaFactory) {
-                    schemaFactory.setResourceResolver(resolver);
-                    return schemaFactory.newSchema(schemaSources.toArray(new Source[schemaSources.size()]));
+                    schemaFactory.setResourceResolver(loader);
+                    return schemaFactory.newSchema(loader.getSources());
                 }
             } finally {
-                for (StreamSource s : schemaSources) {
-                    closeQuietly(s.getInputStream());
-                }
+                loader.close();
             }
         }
 
-
         public void addListener(Listener listener) {
             listeners.add(listener);
         }



Mime
View raw message