You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by gn...@apache.org on 2016/10/05 10:34:50 UTC

svn commit: r1763397 - /aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java

Author: gnodet
Date: Wed Oct  5 10:34:50 2016
New Revision: 1763397

URL: http://svn.apache.org/viewvc?rev=1763397&view=rev
Log:
[ARIES-1503] Wrap bad behaving NamespaceHandlers to fix their behavior

Modified:
    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/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=1763397&r1=1763396&r2=1763397&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 Oct  5 10:34:50 2016
@@ -31,39 +31,38 @@ import java.lang.ref.SoftReference;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-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 java.util.Properties;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
 
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamReader;
 import javax.xml.transform.Source;
 import javax.xml.transform.stream.StreamSource;
 import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
 
 import org.apache.aries.blueprint.NamespaceHandler;
+import org.apache.aries.blueprint.ParserContext;
 import org.apache.aries.blueprint.container.NamespaceHandlerRegistry;
 import org.apache.aries.blueprint.parser.NamespaceHandlerSet;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
+import org.osgi.service.blueprint.reflect.ComponentMetadata;
+import org.osgi.service.blueprint.reflect.Metadata;
 import org.osgi.util.tracker.ServiceTracker;
 import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 import org.w3c.dom.ls.LSInput;
 import org.w3c.dom.ls.LSResourceResolver;
 import org.xml.sax.SAXException;
@@ -541,19 +540,6 @@ public class NamespaceHandlerRegistryImp
                             return createLSInput(url, id, namespaceURI);
                         }
                     }
-                    // Find a compatible namespace handler
-                    h = findCompatibleNamespaceHandler(nsUri);
-                    if (h != null) {
-                        URL url = h.getSchemaLocation(namespaceURI);
-                        if (url == null) {
-                            url = h.getSchemaLocation(rid);
-                        }
-                        if (isCorrectUrl(url)) {
-                            LOGGER.warn("Dynamically adding namespace handler {} to bundle {}/{}",
-                                    nsUri, bundle.getSymbolicName(), bundle.getVersion());
-                            return createLSInput(url, id, namespaceURI);
-                        }
-                    }
                 }
                 LOGGER.warn("Unable to find namespace handler for {}", namespaceURI);
                 return null;
@@ -720,7 +706,7 @@ public class NamespaceHandlerRegistryImp
                     }
                     if (compat) {
                         namespaces.add(ns);
-                        handlers.put(ns, h);
+                        handlers.put(ns, wrapIfNeeded(h));
                         return h;
                     }
                 }
@@ -729,6 +715,80 @@ public class NamespaceHandlerRegistryImp
         }
     }
 
+    /**
+     * Wrap the handler if needed to fix its behavior.
+     * When asked for a schema location, some simple handlers always return
+     * the same url, whatever the asked location is.  This can lead to lots
+     * of problems, so we need to verify and fix those behaviors.
+     */
+    private static NamespaceHandler wrapIfNeeded(final NamespaceHandler handler) {
+        URL result = null;
+        try {
+            result = handler.getSchemaLocation("");
+        } catch (Throwable t) {
+            // Ignore
+        }
+        if (result != null) {
+            LOGGER.warn("NamespaceHandler " + handler.getClass().getName() + " is behaving badly and should be fixed");
+            final URL res = result;
+            return new NamespaceHandler() {
+                final ConcurrentMap<String, Boolean> cache = new ConcurrentHashMap<String, Boolean>();
+                @Override
+                public URL getSchemaLocation(String s) {
+                    URL url = handler.getSchemaLocation(s);
+                    if (url != null && url.equals(res)) {
+                        Boolean v, newValue;
+                        Boolean valid = ((v = cache.get(s)) == null &&
+                                (newValue = isValidSchema(s, url)) != null &&
+                                (v = cache.putIfAbsent(s, newValue)) == null) ? newValue : v;
+                        return valid ? url : null;
+                    }
+                    return url;
+                }
+                @Override
+                public Set<Class> getManagedClasses() {
+                    return handler.getManagedClasses();
+                }
+                @Override
+                public Metadata parse(Element element, ParserContext parserContext) {
+                    return handler.parse(element, parserContext);
+                }
+                @Override
+                public ComponentMetadata decorate(Node node, ComponentMetadata componentMetadata, ParserContext parserContext) {
+                    return handler.decorate(node, componentMetadata, parserContext);
+                }
+                private boolean isValidSchema(String ns, URL url) {
+                    try {
+                        InputStream is = url.openStream();
+                        try {
+                            XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader(is);
+                            try {
+                                reader.nextTag();
+                                String nsuri = reader.getNamespaceURI();
+                                String name = reader.getLocalName();
+                                if ("http://www.w3.org/2001/XMLSchema".equals(nsuri) && "schema".equals(name)) {
+                                    String target = reader.getAttributeValue(null, "targetNamespace");
+                                    if (ns.equals(target)) {
+                                        return true;
+                                    }
+                                }
+                            } finally {
+                                reader.close();
+                            }
+                        } finally {
+                            is.close();
+                        }
+                    } catch (Throwable t) {
+                        // Ignore
+                    }
+                    return false;
+                }
+            };
+        } else {
+            return handler;
+        }
+    }
+
     public static class LRUMap<K,V> extends AbstractMap<K,V> {
 
         private final int bound;