Merge "BUG-997: Fix URLSchemaContextResolver"
authorTony Tkacik <ttkacik@cisco.com>
Mon, 25 Aug 2014 10:17:37 +0000 (10:17 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 25 Aug 2014 10:17:37 +0000 (10:17 +0000)
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/URLSchemaContextResolver.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/URLSchemaContextResolver.java

index 34c81911321ac42a698252cfdeb02f6b45fbccae..252a782e1567eea80aad6ed7365df494decb9bd4 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.io.ByteSource;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -20,8 +21,10 @@ import java.util.Collection;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+
 import javax.annotation.concurrent.GuardedBy;
 import javax.annotation.concurrent.ThreadSafe;
+
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
@@ -32,6 +35,11 @@ import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * @deprecated Use {@link org.opendaylight.yangtools.yang.parser.repo.URLSchemaContextResolver}
+ * instead.
+ */
+@Deprecated
 @ThreadSafe
 public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<InputStream> {
 
@@ -47,7 +55,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
     /**
      * Register new yang schema when it appears.
      */
-    public synchronized ObjectRegistration<URL> registerSource(URL source) {
+    public synchronized ObjectRegistration<URL> registerSource(final URL source) {
         checkArgument(source != null, "Supplied source must not be null");
         InputStream yangStream = getInputStream(source);
         YangModelDependencyInfo modelInfo = YangModelDependencyInfo.fromInputStream(yangStream);
@@ -63,7 +71,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
     }
 
     @Override
-    public synchronized Optional<InputStream> getSchemaSource(SourceIdentifier key) {
+    public synchronized Optional<InputStream> getSchemaSource(final SourceIdentifier key) {
         SourceContext ctx = availableSources.get(key);
         if (ctx != null) {
             InputStream stream = getInputStream(ctx.getInstance());
@@ -73,11 +81,11 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
     }
 
     @Override
-    public Optional<InputStream> getSchemaSource(String name, Optional<String> version) {
+    public Optional<InputStream> getSchemaSource(final String name, final Optional<String> version) {
         return getSchemaSource(SourceIdentifier.create(name, version));
     }
 
-    private static InputStream getInputStream(URL source) {
+    private static InputStream getInputStream(final URL source) {
         InputStream stream;
         try {
             stream = source.openStream();
@@ -93,7 +101,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
         final SourceIdentifier identifier;
         final YangModelDependencyInfo dependencyInfo;
 
-        public SourceContext(URL instance, SourceIdentifier identifier, YangModelDependencyInfo modelInfo) {
+        public SourceContext(final URL instance, final SourceIdentifier identifier, final YangModelDependencyInfo modelInfo) {
             super(instance);
             this.identifier = identifier;
             this.dependencyInfo = modelInfo;
@@ -114,7 +122,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
         }
     }
 
-    private synchronized void removeSource(SourceContext sourceContext) {
+    private synchronized void removeSource(final SourceContext sourceContext) {
         boolean removed = availableSources.remove(sourceContext.getIdentifier(), sourceContext);
         if (removed) {
             tryToUpdateSchemaContext();
index bbcd95e220eb34737f50374cadd359c7af17e749..02497a880921dc19edf213ea25e36d09d58fcead 100644 (file)
@@ -13,9 +13,9 @@ import com.google.common.annotations.Beta;
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 
@@ -37,30 +37,41 @@ import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Costs;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaListenerRegistration;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.opendaylight.yangtools.yang.model.repo.util.InMemorySchemaSourceCache;
 import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
 import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Beta
-public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSchemaSource> {
+public class URLSchemaContextResolver implements AutoCloseable, SchemaSourceProvider<YangTextSchemaSource> {
     private static final Logger LOG = LoggerFactory.getLogger(URLSchemaContextResolver.class);
 
-    private final Cache<SourceIdentifier, YangTextSchemaSource> sources = CacheBuilder.newBuilder().build();
     private final Collection<SourceIdentifier> requiredSources = new ConcurrentLinkedDeque<>();
+    private final Multimap<SourceIdentifier, YangTextSchemaSource> texts = ArrayListMultimap.create();
     private final AtomicReference<Optional<SchemaContext>> currentSchemaContext =
             new AtomicReference<>(Optional.<SchemaContext>absent());
+    private final InMemorySchemaSourceCache<ASTSchemaSource> cache;
+    private final SchemaListenerRegistration transReg;
     private final SchemaSourceRegistry registry;
     private final SchemaRepository repository;
     private volatile Object version = new Object();
     private volatile Object contextVersion = version;
 
+
     private URLSchemaContextResolver(final SchemaRepository repository, final SchemaSourceRegistry registry) {
         this.repository = Preconditions.checkNotNull(repository);
         this.registry = Preconditions.checkNotNull(registry);
+
+        final TextToASTTransformer t = TextToASTTransformer.create(repository, registry);
+        transReg = registry.registerSchemaSourceListener(t);
+
+        cache = InMemorySchemaSourceCache.createSoftCache(registry, ASTSchemaSource.class);
     }
 
     public static URLSchemaContextResolver create(final String name) {
@@ -96,23 +107,31 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
         LOG.trace("Resolved URL {} to source {}", url, ast);
 
         final SourceIdentifier resolvedId = ast.getIdentifier();
-        final SchemaSourceRegistration<YangTextSchemaSource> reg = registry.registerSchemaSource(this,
-                PotentialSchemaSource.create(resolvedId, YangTextSchemaSource.class, 0));
-
-        requiredSources.add(resolvedId);
-        LOG.trace("Added source {} to schema context requirements", resolvedId);
-        version = new Object();
 
-        return new AbstractURLRegistration(text) {
-            @Override
-            protected void removeRegistration() {
-                requiredSources.remove(resolvedId);
-                LOG.trace("Removed source {} from schema context requirements", resolvedId);
-                version = new Object();
-                reg.close();
-                sources.invalidate(resolvedId);
-            }
-        };
+        synchronized (this) {
+            texts.put(resolvedId, text);
+            LOG.debug("Populated {} with text", resolvedId);
+
+            final SchemaSourceRegistration<YangTextSchemaSource> reg = registry.registerSchemaSource(this,
+                PotentialSchemaSource.create(resolvedId, YangTextSchemaSource.class, Costs.IMMEDIATE.getValue()));
+            requiredSources.add(resolvedId);
+            cache.schemaSourceEncountered(ast);
+            LOG.debug("Added source {} to schema context requirements", resolvedId);
+            version = new Object();
+
+            return new AbstractURLRegistration(text) {
+                @Override
+                protected void removeRegistration() {
+                    synchronized (URLSchemaContextResolver.this) {
+                        requiredSources.remove(resolvedId);
+                        LOG.trace("Removed source {} from schema context requirements", resolvedId);
+                        version = new Object();
+                        reg.close();
+                        texts.remove(resolvedId, text);
+                    }
+                }
+            };
+        }
     }
 
     /**
@@ -139,7 +158,7 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
             Collection<SourceIdentifier> sources;
             do {
                 v = version;
-                sources = ImmutableList.copyOf(requiredSources);
+                sources = ImmutableSet.copyOf(requiredSources);
             } while (v != version);
 
             while (true) {
@@ -148,11 +167,13 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
                     sc = Optional.of(f.checkedGet());
                     break;
                 } catch (SchemaResolutionException e) {
-                    LOG.info("Failed to fully assemble schema context for {}", sources, e);
+                    LOG.debug("Failed to fully assemble schema context for {}", sources, e);
                     sources = e.getResolvedSources();
                 }
             }
 
+            LOG.debug("Resolved schema context for {}", sources);
+
             synchronized (this) {
                 if (contextVersion == cv) {
                     currentSchemaContext.set(sc);
@@ -165,13 +186,20 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
     }
 
     @Override
-    public CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
-        final YangTextSchemaSource ret = sources.getIfPresent(sourceIdentifier);
-        if (ret == null) {
+    public synchronized CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+        final Collection<YangTextSchemaSource> ret = texts.get(sourceIdentifier);
+
+        LOG.debug("Lookup {} result {}", sourceIdentifier, ret);
+        if (ret.isEmpty()) {
             return Futures.<YangTextSchemaSource, SchemaSourceException>immediateFailedCheckedFuture(
                     new MissingSchemaSourceException("URL for " + sourceIdentifier + " not registered", sourceIdentifier));
         }
 
-        return Futures.immediateCheckedFuture(ret);
+        return Futures.immediateCheckedFuture(ret.iterator().next());
+    }
+
+    @Override
+    public void close() {
+        transReg.close();
     }
 }