Merge "BUG-997: Evolve the SchemaRegistry concepts"
authorTony Tkacik <ttkacik@cisco.com>
Sun, 3 Aug 2014 18:13:58 +0000 (18:13 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Sun, 3 Aug 2014 18:13:58 +0000 (18:13 +0000)
35 files changed:
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/AcceptingSchemaSourceFilter.java [deleted file]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/MissingSchemaSourceException.java [new file with mode: 0644]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactory.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaRepository.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaResolutionException.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaSourceException.java [moved from yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaSourceTransformationException.java with 53% similarity]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaSourceFilter.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaSourceRepresentation.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SourceIdentifier.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/YangTextSchemaSource.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/YinSchemaSource.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/PotentialSchemaSource.java [new file with mode: 0644]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaListenerRegistration.java [moved from yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaTransformerRegistration.java with 58% similarity]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaSourceListener.java [new file with mode: 0644]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaSourceProvider.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaSourceRegistration.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaSourceRegistry.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaSourceTransformer.java [deleted file]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaListenerRegistration.java [new file with mode: 0644]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaRepository.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaSourceCache.java [new file with mode: 0644]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaSourceRegistration.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaTransformerRegistration.java [deleted file]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/InMemorySchemaSourceCache.java [new file with mode: 0644]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/RefcountedRegistration.java [new file with mode: 0644]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/SchemaSourceTransformer.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/AbstractURLRegistration.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/DependencyResolver.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepository.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/URLRegistration.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/URLSchemaContextResolver.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ASTSchemaSource.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/TextToASTTransformer.java

diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/AcceptingSchemaSourceFilter.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/AcceptingSchemaSourceFilter.java
deleted file mode 100644 (file)
index e101d9d..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/eplv10.html
- */
-package org.opendaylight.yangtools.yang.model.repo.api;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * A {@link SchemaSourceFilter} which accepts any schema source it is presented with.
- */
-public final class AcceptingSchemaSourceFilter implements SchemaSourceFilter {
-    private static final AcceptingSchemaSourceFilter INSTANCE = new AcceptingSchemaSourceFilter();
-
-    private final Iterable<Class<? extends SchemaSourceRepresentation>> representations;
-
-    private AcceptingSchemaSourceFilter() {
-        final Builder<Class<? extends SchemaSourceRepresentation>> b = ImmutableList.builder();
-        b.add(SchemaSourceRepresentation.class);
-        representations = b.build();
-    }
-
-    /**
-     * Return the singleton instance of this filter.
-     *
-     * @return Singleton shared instance.
-     */
-    public static final AcceptingSchemaSourceFilter getSingletonInstance() {
-        return INSTANCE;
-    }
-
-    @Override
-    public Iterable<Class<? extends SchemaSourceRepresentation>> supportedRepresentations() {
-        return representations;
-    }
-
-    @Override
-    public ListenableFuture<Boolean> apply(final SchemaSourceRepresentation schemaSource) {
-        return Futures.immediateFuture(Boolean.TRUE);
-    }
-}
diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/MissingSchemaSourceException.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/MissingSchemaSourceException.java
new file mode 100644 (file)
index 0000000..17c9c90
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/eplv10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.api;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Exception thrown when a the specified schema source is not available.
+ */
+@Beta
+public class MissingSchemaSourceException extends SchemaSourceException {
+    private static final long serialVersionUID = 1L;
+
+    public MissingSchemaSourceException(final String message) {
+        super(message);
+    }
+
+    public MissingSchemaSourceException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
index 8869c9eb3ddb11a9d17732ba33bb0e0056e01986..2597e9c185481d8886d4ee65155e74d9264cdc37 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.api;
 
+import com.google.common.annotations.Beta;
 import com.google.common.util.concurrent.CheckedFuture;
 
 import java.util.Collection;
@@ -20,6 +21,7 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
  * based on a specification of what {@link SourceIdentifier}s are required
  * and dynamic recursive resolution.
  */
+@Beta
 public interface SchemaContextFactory {
     /**
      * Create a new schema context containing specified sources, pulling in
index 807bbf05de62bcf4ae7d3863fa47a6e843e214d8..73569d384d3cd76091466ebe5474c70a96b57e6c 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.api;
 
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.CheckedFuture;
+
 import javax.annotation.Nonnull;
 
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -15,6 +18,7 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
  * Interface exposed by repository implementations. A schema repository is a logically
  * centralized place for model storage and creation of {@link SchemaContext} instances.
  */
+@Beta
 public interface SchemaRepository {
     /**
      * Instantiate a new {@link SchemaContextFactory}, which will filter available schema
@@ -26,4 +30,6 @@ public interface SchemaRepository {
      * @return A new schema context factory.
      */
     SchemaContextFactory createSchemaContextFactory(@Nonnull SchemaSourceFilter filter);
+
+    <T extends SchemaSourceRepresentation> CheckedFuture<T, SchemaSourceException> getSchemaSource(@Nonnull SourceIdentifier id, @Nonnull Class<T> represetation);
 }
index b47e366a79755273b37be9e2a1a25335d3c6123a..e0be4adb7936c6afab7cd2be00e69440b6f4af0d 100644 (file)
@@ -7,38 +7,48 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.api;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
 
-import java.util.Map;
+import java.util.Collection;
+import java.util.Collections;
 
 import javax.annotation.Nonnull;
 
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+
 /**
  * Exception thrown when a Schema Source fails to resolve.
  */
-public class SchemaResolutionException extends Exception {
+@Beta
+public class SchemaResolutionException extends SchemaSourceException {
     private static final long serialVersionUID = 1L;
-    private final Map<SourceIdentifier, Throwable> unresolvedSources;
+    private final Multimap<SourceIdentifier, ModuleImport> unsatisfiedImports;
+    private final Collection<SourceIdentifier> resolvedSources;
 
     public SchemaResolutionException(final @Nonnull String message) {
         this(message, (Throwable)null);
     }
 
     public SchemaResolutionException(final @Nonnull String message, final Throwable cause) {
-        this(message, cause, ImmutableMap.<SourceIdentifier, Exception>of());
+        this(message, cause, Collections.<SourceIdentifier>emptySet(), ImmutableMultimap.<SourceIdentifier, ModuleImport>of());
     }
 
-    public SchemaResolutionException(final @Nonnull String message, final @Nonnull Map<SourceIdentifier, ? extends Throwable> unresolvedSources) {
-        super(Preconditions.checkNotNull(message));
-        this.unresolvedSources = ImmutableMap.copyOf(unresolvedSources);
+    public SchemaResolutionException(final @Nonnull String message, final Collection<SourceIdentifier> resolvedSources,
+            final @Nonnull Multimap<SourceIdentifier, ModuleImport> unsatisfiedImports) {
+        this(message, null, Collections.<SourceIdentifier>emptySet(), unsatisfiedImports);
     }
 
-    public SchemaResolutionException(final @Nonnull String message, final Throwable cause, @Nonnull final Map<SourceIdentifier, ? extends Throwable> unresolvedSources) {
+    public SchemaResolutionException(final @Nonnull String message, final Throwable cause,
+            @Nonnull final Collection<SourceIdentifier> resolvedSources,
+            @Nonnull final Multimap<SourceIdentifier, ModuleImport> unsatisfiedImports) {
         super(message, cause);
-        this.unresolvedSources = ImmutableMap.copyOf(unresolvedSources);
+        this.unsatisfiedImports = ImmutableMultimap.copyOf(unsatisfiedImports);
+        this.resolvedSources = ImmutableList.copyOf(resolvedSources);
     }
 
     /**
@@ -47,13 +57,19 @@ public class SchemaResolutionException extends Exception {
      *
      * @return Source/reason map.
      */
-    public final Map<SourceIdentifier, Throwable> getUnresolvedSources() {
-        return unresolvedSources;
+    public final Multimap<SourceIdentifier, ModuleImport> getUnsatisfiedImports() {
+        return unsatisfiedImports;
+    }
+
+
+    // FIXME: should be leak actual mapping?
+    public final Collection<SourceIdentifier> getResolvedSources() {
+        return resolvedSources;
     }
 
     @Override
     public final String toString() {
-        return addToStringAttributes(Objects.toStringHelper(this).add("unresolvedSources", unresolvedSources)).toString();
+        return addToStringAttributes(Objects.toStringHelper(this).add("unsatisfiedImports", unsatisfiedImports)).toString();
     }
 
     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
@@ -5,20 +5,22 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/eplv10.html
  */
-package org.opendaylight.yangtools.yang.model.repo.spi;
+package org.opendaylight.yangtools.yang.model.repo.api;
+
+import com.google.common.annotations.Beta;
 
 /**
- * Exception thrown when a failure to translate a schema source between
- * representations.
+ * Exception thrown when a failure to acquire a schema source occurs.
  */
-public class SchemaSourceTransformationException extends Exception {
+@Beta
+public class SchemaSourceException extends Exception {
     private static final long serialVersionUID = 1L;
 
-    public SchemaSourceTransformationException(final String message) {
+    public SchemaSourceException(final String message) {
         super(message);
     }
 
-    public SchemaSourceTransformationException(final String message, final Throwable cause) {
+    public SchemaSourceException(final String message, final Throwable cause) {
         super(message, cause);
     }
 }
index 188f83c0c592c47b6134bf080d4ed0a99924dfce..f881900754a53642d3696bfab3e67e2a47934ac2 100644 (file)
@@ -7,9 +7,55 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.api;
 
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
+import java.util.Collections;
+
+/*
+ * A filter of schema sources. This is used to restrict which sources representation
+ * instances are allowed to participate in construction of a schema context. This
+ * allows, for example, to create an non-shared island, or require the sources to
+ * be certified before use.
+ */
+@Beta
 public interface SchemaSourceFilter {
+    /**
+     * A {@link SchemaSourceFilter} which accepts any schema source it is presented with.
+     */
+    public static final SchemaSourceFilter ALWAYS_ACCEPT = new SchemaSourceFilter() {
+        private final Iterable<Class<? extends SchemaSourceRepresentation>> REPRESENTATIONS =
+                Collections.<Class<? extends SchemaSourceRepresentation>>singletonList(SchemaSourceRepresentation.class);
+
+        @Override
+        public Iterable<Class<? extends SchemaSourceRepresentation>> supportedRepresentations() {
+            return REPRESENTATIONS;
+        }
+
+        @Override
+        public ListenableFuture<Boolean> apply(final SchemaSourceRepresentation schemaSource) {
+            return Futures.immediateFuture(Boolean.TRUE);
+        }
+    };
+
+    /**
+     * Get the representations this filter supports. A schema source is translated
+     * into one of these representations before it is presented for filtering.
+     *
+     * @return Set of supported representations.
+     */
     Iterable<Class<? extends SchemaSourceRepresentation>> supportedRepresentations();
+
+    /**
+     * Check if a particular schema source is acceptable to the filter. The process
+     * of checking may be asynchronous, but at some point it needs to produce an
+     * affirmative or negative answer before the schema context construction can
+     * proceed.
+     *
+     * @param schemaSource Schema source to be filtered
+     * @return Promise of a filtering decision. The result should be {@link Boolean#TRUE}
+     *         if the source is acceptable.
+     */
     ListenableFuture<Boolean> apply(SchemaSourceRepresentation schemaSource);
 }
index b1261a9cd48a5883c86b955b12c3f187315a5cf8..90fc5ae740c2bf5cf2d07f0328681d1e1f987f07 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.api;
 
+import com.google.common.annotations.Beta;
+
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.Immutable;
 
@@ -35,6 +37,7 @@ import org.opendaylight.yangtools.concepts.Immutable;
  * Implementations of this interface expected to comply with the {@link Immutable}
  * contract.
  */
+@Beta
 public interface SchemaSourceRepresentation extends Identifiable<SourceIdentifier>, Immutable {
     /**
      * {@inheritDoc}
index cd3a0fbefcaaed7198980ee545f7fe510654ac0b..58b011c36811cd60c3f9c0af9a1a7f93d9990988 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.api;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 
@@ -14,7 +15,6 @@ import org.opendaylight.yangtools.concepts.Identifier;
 import org.opendaylight.yangtools.concepts.Immutable;
 
 /**
- *
  * YANG Schema source identifier
  *
  * Simple transfer object represents identifier of source for YANG schema (module or submodule),
@@ -34,9 +34,8 @@ import org.opendaylight.yangtools.concepts.Immutable;
  * <p>
  * (For further reference see: http://tools.ietf.org/html/rfc6020#section-5.2 and
  * http://tools.ietf.org/html/rfc6022#section-3.1 ).
- *
- *
  */
+@Beta
 public final class SourceIdentifier implements Identifier, Immutable {
     private static final long serialVersionUID = 1L;
     private final String revision;
index be52a90f777131055f9423d98d9893d0568c3371..50ee12ef4d03358729456081c76216a020f5db71 100644 (file)
@@ -7,8 +7,12 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.api;
 
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.annotations.Beta;
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.io.ByteSource;
 
@@ -21,6 +25,7 @@ import org.opendaylight.yangtools.concepts.Delegator;
  * YANG text schema source representation. Exposes an RFC6020 text representation
  * as an {@link InputStream}.
  */
+@Beta
 public abstract class YangTextSchemaSource extends ByteSource implements SchemaSourceRepresentation {
     private final SourceIdentifier identifier;
 
@@ -28,6 +33,12 @@ public abstract class YangTextSchemaSource extends ByteSource implements SchemaS
         this.identifier = Preconditions.checkNotNull(identifier);
     }
 
+    public static SourceIdentifier identifierFromFilename(final String name) {
+        checkArgument(name.endsWith(".yang"), "Filename %s does not have a .yang extension", name);
+        // FIXME: add revision-awareness
+        return SourceIdentifier.create(name.substring(0, name.length() - 5), Optional.<String>absent());
+    }
+
     /**
      * {@inheritDoc}
      */
index b67aae628914c20e7b5fe2779152abb63814c2a1..f09f525533e62982f6610c96344501414bcfa8b4 100644 (file)
@@ -7,12 +7,15 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.api;
 
+import com.google.common.annotations.Beta;
+
 import org.w3c.dom.Document;
 
 /**
  * Yin schema source representation. Exposes an RFC6020 YIN XML representation
  * as an W3C {@link Document}.
  */
+@Beta
 public interface YinSchemaSource extends SchemaSourceRepresentation {
     /**
      * {@inheritDoc}
diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/PotentialSchemaSource.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/PotentialSchemaSource.java
new file mode 100644 (file)
index 0000000..fae4467
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/eplv10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.spi;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+
+/**
+ * A potential schema source. Instances of this class track the various
+ * representations of a schema source and the cost attached to obtaining
+ * the source from them.
+ */
+@Beta
+public final class PotentialSchemaSource<T extends SchemaSourceRepresentation> {
+    /**
+     * Each registered source has a cost associated with it. Since a particular
+     * representation can be acquired by various means, here are general constants
+     * for common cases.
+     */
+    public enum Costs {
+        /**
+         * The source is immediately available, via a lookup or similar.
+         */
+        IMMEDIATE(0),
+        /**
+         * The source is available via a computation. For transformation-type
+         * computation, the cost of acquiring the cost needs to be added, too.
+         */
+        COMPUTATION(1),
+        /**
+         * The source is available by performing local IO, such that reading
+         * from a disk.
+         */
+        LOCAL_IO(4),
+        /**
+         * The source is available by performing remote IO, such as fetching
+         * from an HTTP server or similar.
+         */
+        REMOTE_IO(8);
+
+        private final int value;
+
+        private Costs(final int value) {
+            this.value = value;
+        }
+
+        /**
+         * The the cost value.
+         *
+         * @return Const constant.
+         */
+        public int getValue() {
+            return value;
+        }
+    }
+
+    private final Class<? extends T> representation;
+    private final SourceIdentifier sourceIdentifier;
+    private final int cost;
+
+    private PotentialSchemaSource(final SourceIdentifier sourceIdentifier, final Class<? extends T> representation, final int cost) {
+        this.representation = Preconditions.checkNotNull(representation);
+        this.sourceIdentifier = Preconditions.checkNotNull(sourceIdentifier);
+        Preconditions.checkArgument(cost >= 0, "cost has to be non-negative");
+        this.cost = cost;
+    }
+
+    public static final <T extends SchemaSourceRepresentation> PotentialSchemaSource<T> create(final SourceIdentifier sourceIdentifier, final Class<? extends T> representation, final int cost) {
+        return new PotentialSchemaSource<>(sourceIdentifier, representation, cost);
+    }
+
+    public SourceIdentifier getSourceIdentifier() {
+        return sourceIdentifier;
+    }
+
+    public Class<? extends T> getRepresentation() {
+        return representation;
+    }
+
+    public int getCost() {
+        return cost;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + cost;
+        result = prime * result + representation.hashCode();
+        result = prime * result + sourceIdentifier.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof PotentialSchemaSource)) {
+            return false;
+        }
+        final PotentialSchemaSource<?> other = (PotentialSchemaSource<?>) obj;
+        if (cost != other.cost) {
+            return false;
+        }
+        if (!representation.equals(other.representation)) {
+            return false;
+        }
+        if (!sourceIdentifier.equals(other.sourceIdentifier)) {
+            return false;
+        }
+        return true;
+    }
+}
@@ -7,9 +7,14 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.spi;
 
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import com.google.common.annotations.Beta;
+
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * Registration of a SchemaSourceListener.
+ */
+@Beta
+public interface SchemaListenerRegistration extends ListenerRegistration<SchemaSourceListener> {
 
-public interface SchemaTransformerRegistration extends ObjectRegistration<SchemaSourceTransformer<?, ?>> {
-    @Override
-    void close();
 }
diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaSourceListener.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaSourceListener.java
new file mode 100644 (file)
index 0000000..b4f55a8
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/eplv10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.spi;
+
+import com.google.common.annotations.Beta;
+
+import java.util.EventListener;
+
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+
+/**
+ * Listener for schema source lifecycle events.
+ */
+@Beta
+public interface SchemaSourceListener extends EventListener {
+    /**
+     * Invoked when the registry sees a concrete source. This callback is typically
+     * used by cache-type listeners, who intercept the source, store it locally and
+     * announce themselves as a provider of that particular schema source.
+     *
+     * @param source Schema source
+     */
+    void schemaSourceEncountered(SchemaSourceRepresentation source);
+
+    /**
+     * Invoked when a new schema source is registered by a provider. This call
+     * callback, along with {@link #schemaSourceUnregistered(PotentialSchemaSource)}
+     * is typically used by transformer-type listeners, who intercept the registration
+     * if the advertised representation matches their input type and register
+     * themselves as a potential provider of the same source in their output
+     * representation type.
+     *
+     * @param sources Newly available sources
+     */
+    void schemaSourceRegistered(Iterable<PotentialSchemaSource<?>> sources);
+
+    /**
+     * Invoked when a schema source is unregistered.
+     *
+     * @param source Schema source representation
+     */
+    void schemaSourceUnregistered(PotentialSchemaSource<?> source);
+}
index a0a141bd3759f4f1a4dac00e3f3cb2706d1114bd..70ad6813e8286f4c22025b312395af34ebbc6418 100644 (file)
@@ -8,9 +8,10 @@
 package org.opendaylight.yangtools.yang.model.repo.spi;
 
 import com.google.common.annotations.Beta;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.CheckedFuture;
 
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 
@@ -29,10 +30,9 @@ public interface SchemaSourceProvider<T extends SchemaSourceRepresentation> {
      *
      * <ul>
      * <li> If the source identifier specifies a revision, this method returns either
-     * a representation of that particular revision, or report the identifier as absent
-     * by returning {@link Optional#absent()}.
+     * a representation of that particular revision or throw {@link MissingSchemaSourceException}.
      * <li> If the source identifier does not specify a revision, this method returns
-     * the newest available revision, or {@link Optional#absent()}.
+     * the newest available revision, or throws {@link MissingSchemaSourceException}.
      *
      * In either case the returned representation is required to report a non-null
      * revision in the {@link SourceIdentifier} returned from
@@ -43,7 +43,7 @@ public interface SchemaSourceProvider<T extends SchemaSourceRepresentation> {
      *
      * @param sourceIdentifier source identifier
      * @return source representation if supplied YANG module is available
-     *         {@link Optional#absent()} otherwise.
+     *
      */
-    ListenableFuture<Optional<T>> getSource(SourceIdentifier sourceIdentifier);
+    CheckedFuture<? extends T, SchemaSourceException> getSource(SourceIdentifier sourceIdentifier);
 }
index 3c3c5fef7748dda7a9bdbe3ae507118a46c4f617..6937c53e98ecbc42544cf61fa7f00b0ee792e880 100644 (file)
@@ -7,10 +7,16 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.spi;
 
+import com.google.common.annotations.Beta;
+
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
 
-public interface SchemaSourceRegistration extends ObjectRegistration<SourceIdentifier> {
+/**
+ * Registration of a schema source.
+ */
+@Beta
+public interface SchemaSourceRegistration<T extends SchemaSourceRepresentation> extends ObjectRegistration<PotentialSchemaSource<T>> {
     @Override
     void close();
 }
index f9acf3d456cb260f4f924356c08caad549e4b128..075fcb5382d44ffb34532d20685c92de4cf86c7a 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.spi;
 
+import com.google.common.annotations.Beta;
+
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 
@@ -17,29 +19,28 @@ import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
  * {@link SchemaSourceProvider} instances which would then acquire the schema
  * source.
  */
+@Beta
 public interface SchemaSourceRegistry {
     /**
      * Register a new schema source which is potentially available from a provider.
      * A registration does not guarantee that a subsequent call to
      * {@link SchemaSourceProvider#getSource(SourceIdentifier)} will succeed.
      *
-     * @param identifier Schema source identifier
      * @param provider Resolver which can potentially resolve the identifier
-     * @param representation Schema source representation which the source may
-     *                       be available.
+     * @param source Schema source details
      * @return A registration handle. Invoking {@link SchemaSourceRegistration#close()}
      *         will cancel the registration.
      */
-    <T extends SchemaSourceRepresentation> SchemaSourceRegistration registerSchemaSource(
-            SourceIdentifier identifier, SchemaSourceProvider<? super T> provider, Class<T> representation);
+    <T extends SchemaSourceRepresentation> SchemaSourceRegistration<T> registerSchemaSource(SchemaSourceProvider<? super T> provider, PotentialSchemaSource<T> source);
 
     /**
-     * Register a schema transformer. The registry can invoke it to transform between
-     * the various schema source formats.
+     * Register a schema source listener. The listener will be notified as new
+     * sources and their representations become available, subject to the provided
+     * filter.
      *
-     * @param transformer Schema source transformer
-     * @return A registration handle. Invoking {@link SchemaTransformerRegistration#close()}
+     * @param listener Schema source listener
+     * @return A registration handle. Invoking {@link SchemaListenerRegistration#close()}
      *         will cancel the registration.
      */
-    SchemaTransformerRegistration registerSchemaSourceTransformer(SchemaSourceTransformer<?, ?> transformer);
+    SchemaListenerRegistration registerSchemaSourceListener(SchemaSourceListener listener);
 }
diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaSourceTransformer.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/spi/SchemaSourceTransformer.java
deleted file mode 100644 (file)
index 13d309e..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/eplv10.html
- */
-package org.opendaylight.yangtools.yang.model.repo.spi;
-
-import com.google.common.util.concurrent.CheckedFuture;
-
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
-
-/**
- * An schema source representation transformation service. An instance can create
- * some output schema source representation based on some input source representation.
- *
- * @param <I> Input {@link SchemaSourceRepresentation}
- * @param <O> Output {@link SchemaSourceRepresentation}
- */
-public interface SchemaSourceTransformer<I extends SchemaSourceRepresentation, O extends SchemaSourceRepresentation> {
-    /**
-     * Return the {@link SchemaSourceRepresentation} which this transformer
-     * accepts on its input.
-     *
-     * @return The input source representation type.
-     */
-    Class<I> getInputRepresentation();
-
-    /**
-     * Return the {@link SchemeSourceRepresentation} which this transformer
-     * produces on its output.
-     *
-     * @return The output source representation type.
-     */
-    Class<O> getOutputRepresentation();
-
-    /**
-     * Transform a schema source representation from its input form to
-     * the transformers output form.
-     *
-     * @param source Schema source in its source representation
-     * @return A future which produces the output schema source representation.
-     */
-    CheckedFuture<O, SchemaSourceTransformationException> transformSchemaSource(I source);
-
-    /**
-     * Return the relative cost of performing the transformation. When in doubt,
-     * return 1.
-     *
-     * @return Relative cost.
-     */
-    int getCost();
-}
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaListenerRegistration.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaListenerRegistration.java
new file mode 100644 (file)
index 0000000..e720f8d
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/eplv10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.util;
+
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaListenerRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
+
+public abstract class AbstractSchemaListenerRegistration extends AbstractListenerRegistration<SchemaSourceListener> implements SchemaListenerRegistration {
+    protected AbstractSchemaListenerRegistration(final SchemaSourceListener listener) {
+        super(listener);
+    }
+}
index 4dd30b90a99c3470c92cbd1082ed2793598d4bd1..53563fde69cea887b7d0a90e5be70350f58e8925 100644 (file)
  */
 package org.opendaylight.yangtools.yang.model.repo.util;
 
-import com.google.common.base.Optional;
+import com.google.common.annotations.Beta;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
-import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureFallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
+import org.opendaylight.yangtools.util.concurrent.ReflectiveExceptionMapper;
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaListenerRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
 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.spi.SchemaSourceTransformationException;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformer;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaTransformerRegistration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class AbstractSchemaRepository implements SchemaRepository, SchemaSourceRegistry {
+/**
+ * Abstract base class for {@link SchemaRepository} implementations. It handles registration
+ * and lookup of schema sources, subclasses need only to provide their own
+ * {@link #createSchemaContextFactory(SchemaSourceFilter)} implementation.
+ */
+@Beta
+public abstract class AbstractSchemaRepository implements SchemaRepository, SchemaSourceRegistry {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractSchemaRepository.class);
-    private static final Comparator<SchemaTransformerRegistration> TRANSFORMER_COST_COMPARATOR = new Comparator<SchemaTransformerRegistration>() {
-        @Override
-        public int compare(final SchemaTransformerRegistration o1, final SchemaTransformerRegistration o2) {
-            return o1.getInstance().getCost() - o2.getInstance().getCost();
-        }
-    };
+    private static final ExceptionMapper<SchemaSourceException> FETCH_MAPPER = ReflectiveExceptionMapper.create("Schema source fetch", SchemaSourceException.class);
 
     /*
-     * Output-type -> transformer map. Our usage involves knowing the destination type,
-     * so we have to work backwards and find a transformer chain which will get us
-     * to that representation given our available sources.
+     * Source identifier -> representation -> provider map. We usually are looking for
+     * a specific representation of a source.
      */
-    private final Multimap<Class<? extends SchemaSourceRepresentation>, SchemaTransformerRegistration> transformers =
-            HashMultimap.create();
+    @GuardedBy("this")
+    private final Map<SourceIdentifier, Multimap<Class<? extends SchemaSourceRepresentation>, AbstractSchemaSourceRegistration<?>>> sources = new HashMap<>();
 
     /*
-     * Source identifier -> representation -> provider map. We usually are looking for
-     * a specific representation a source.
+     * Schema source listeners.
      */
-    private final Map<SourceIdentifier, Multimap<Class<?>, AbstractSchemaSourceRegistration>> sources = new HashMap<>();
+    @GuardedBy("this")
+    private final Collection<SchemaListenerRegistration> listeners = new ArrayList<>();
 
+    private static final <T extends SchemaSourceRepresentation> CheckedFuture<T, SchemaSourceException> fetchSource(final SourceIdentifier id, final Iterator<AbstractSchemaSourceRegistration<?>> it) {
+        final AbstractSchemaSourceRegistration<?> reg = it.next();
 
-    private static final <T extends SchemaSourceRepresentation> ListenableFuture<Optional<T>> fetchSource(final SourceIdentifier id, final Iterator<AbstractSchemaSourceRegistration> it) {
-        if (!it.hasNext()) {
-            return Futures.immediateFuture(Optional.<T>absent());
-        }
-
-        return Futures.transform(((SchemaSourceProvider<T>)it.next().getProvider()).getSource(id), new AsyncFunction<Optional<T>, Optional<T>>() {
+        @SuppressWarnings("unchecked")
+        final CheckedFuture<? extends T, SchemaSourceException> f = ((SchemaSourceProvider<T>)reg.getProvider()).getSource(id);
+        return Futures.makeChecked(Futures.withFallback(f, new FutureFallback<T>() {
             @Override
-            public ListenableFuture<Optional<T>> apply(final Optional<T> input) throws Exception {
-                if (input.isPresent()) {
-                    return Futures.immediateFuture(input);
-                } else {
+            public ListenableFuture<T> create(final Throwable t) throws SchemaSourceException {
+                LOG.debug("Failed to acquire source from {}", reg, t);
+
+                if (it.hasNext()) {
                     return fetchSource(id, it);
                 }
-            }
-        });
-    }
-
-    private <T extends SchemaSourceRepresentation> ListenableFuture<Optional<T>> transformSchemaSource(final SourceIdentifier id, final Class<T> representation) {
-        final Multimap<Class<?>, AbstractSchemaSourceRegistration> srcs = sources.get(id);
-        if (srcs.isEmpty()) {
-            return Futures.immediateFailedFuture(new SchemaSourceTransformationException(
-                    String.format("No providers producing a representation of %s registered", id)));
-        }
-
-        final Collection<SchemaTransformerRegistration> ts = transformers.get(representation);
-        if (ts.isEmpty()) {
-            return Futures.immediateFailedFuture(new SchemaSourceTransformationException(
-                    String.format("No transformers producing representation %s registered", representation)));
-        }
 
-        // Build up the candidate list
-        final List<SchemaTransformerRegistration> candidates = new ArrayList<>();
-        for (SchemaTransformerRegistration tr : ts) {
-            final SchemaSourceTransformer<?, ?> t = tr.getInstance();
-            final Class<?> i = t.getInputRepresentation();
-            if (srcs.containsKey(i)) {
-                candidates.add(tr);
-            } else {
-                LOG.debug("Provider for {} in {} not found, skipping transfomer {}", id, i, t);
+                throw new MissingSchemaSourceException("All available providers exhausted");
             }
-        }
-
-        if (candidates.isEmpty()) {
-            return Futures.immediateFailedFuture(new SchemaSourceTransformationException(
-                    String.format("No matching source/transformer pair for source %s representation %s found", id, representation)));
-        }
-
-        Collections.sort(candidates, TRANSFORMER_COST_COMPARATOR);
-        // return transform(candidates.iterator(), id);
-        return null;
+        }), FETCH_MAPPER);
     }
 
-    /**
-     * Obtain a SchemaSource is selected representation
-     */
-    protected <T extends SchemaSourceRepresentation> ListenableFuture<Optional<T>> getSchemaSource(final SourceIdentifier id, final Class<T> representation) {
-        final Multimap<Class<?>, AbstractSchemaSourceRegistration> srcs = sources.get(id);
+    @Override
+    public <T extends SchemaSourceRepresentation> CheckedFuture<T, SchemaSourceException> getSchemaSource(final SourceIdentifier id, final Class<T> representation) {
+        final Multimap<Class<? extends SchemaSourceRepresentation>, AbstractSchemaSourceRegistration<?>> srcs = sources.get(id);
         if (srcs == null) {
-            LOG.debug("No providers registered for source {}", id);
-            return Futures.immediateFuture(Optional.<T>absent());
+            return Futures.<T, SchemaSourceException>immediateFailedCheckedFuture(new MissingSchemaSourceException("No providers registered for source" + id));
         }
 
-        final Collection<AbstractSchemaSourceRegistration> candidates = srcs.get(representation);
-        return Futures.transform(AbstractSchemaRepository.<T>fetchSource(id, candidates.iterator()), new AsyncFunction<Optional<T>, Optional<T>>() {
-            @Override
-            public ListenableFuture<Optional<T>> apply(final Optional<T> input) throws Exception {
-                if (input.isPresent()) {
-                    return Futures.immediateFuture(input);
-                }
-
-                return transformSchemaSource(id, representation);
-            }
-        });
-    }
+        final Iterator<AbstractSchemaSourceRegistration<?>> regs = srcs.get(representation).iterator();
+        if (!regs.hasNext()) {
+            return Futures.<T, SchemaSourceException>immediateFailedCheckedFuture(
+                    new MissingSchemaSourceException("No providers for source " + id + " representation " + representation + " available"));
+        }
 
-    @Override
-    public SchemaContextFactory createSchemaContextFactory(final SchemaSourceFilter filter) {
-        // TODO Auto-generated method stub
-        return null;
+        return fetchSource(id, regs);
     }
 
-    private void addSource(final SourceIdentifier id, final Class<?> rep, final AbstractSchemaSourceRegistration reg) {
-        Multimap<Class<?>, AbstractSchemaSourceRegistration> m = sources.get(id);
+    private synchronized <T extends SchemaSourceRepresentation> void addSource(final PotentialSchemaSource<T> source, final AbstractSchemaSourceRegistration<T> reg) {
+        Multimap<Class<? extends SchemaSourceRepresentation>, AbstractSchemaSourceRegistration<?>> m = sources.get(source.getSourceIdentifier());
         if (m == null) {
             m = HashMultimap.create();
-            sources.put(id, m);
+            sources.put(source.getSourceIdentifier(), m);
         }
 
-        m.put(rep, reg);
+        m.put(source.getRepresentation(), reg);
+
+        final Collection<PotentialSchemaSource<?>> reps = Collections.<PotentialSchemaSource<?>>singleton(source);
+        for (SchemaListenerRegistration l : listeners) {
+            l.getInstance().schemaSourceRegistered(reps);
+        }
     }
 
-    private void removeSource(final SourceIdentifier id, final Class<?> rep, final SchemaSourceRegistration reg) {
-        final Multimap<Class<?>, AbstractSchemaSourceRegistration> m = sources.get(id);
+    private synchronized <T extends SchemaSourceRepresentation> void removeSource(final PotentialSchemaSource<?> source, final SchemaSourceRegistration<?> reg) {
+        final Multimap<Class<? extends SchemaSourceRepresentation>, AbstractSchemaSourceRegistration<?>> m = sources.get(source.getSourceIdentifier());
         if (m != null) {
-            m.remove(rep, reg);
+            m.remove(source.getRepresentation(), reg);
+
+            for (SchemaListenerRegistration l : listeners) {
+                l.getInstance().schemaSourceUnregistered(source);
+            }
+
             if (m.isEmpty()) {
                 sources.remove(m);
             }
@@ -163,29 +130,40 @@ public class AbstractSchemaRepository implements SchemaRepository, SchemaSourceR
     }
 
     @Override
-    public <T extends SchemaSourceRepresentation> SchemaSourceRegistration registerSchemaSource(
-            final SourceIdentifier identifier, final SchemaSourceProvider<? super T> provider, final Class<T> representation) {
-        final AbstractSchemaSourceRegistration ret = new AbstractSchemaSourceRegistration(identifier, provider) {
+    public <T extends SchemaSourceRepresentation> SchemaSourceRegistration<T> registerSchemaSource(final SchemaSourceProvider<? super T> provider, final PotentialSchemaSource<T> source) {
+        final AbstractSchemaSourceRegistration<T> ret = new AbstractSchemaSourceRegistration<T>(provider, source) {
             @Override
             protected void removeRegistration() {
-                removeSource(identifier, representation, this);
+                removeSource(source, this);
             }
         };
 
-        addSource(identifier, representation, ret);
+        addSource(source, ret);
         return ret;
     }
 
     @Override
-    public SchemaTransformerRegistration registerSchemaSourceTransformer(final SchemaSourceTransformer<?, ?> transformer) {
-        final SchemaTransformerRegistration ret = new AbstractSchemaTransformerRegistration(transformer) {
+    public SchemaListenerRegistration registerSchemaSourceListener(final SchemaSourceListener listener) {
+        final SchemaListenerRegistration ret = new AbstractSchemaListenerRegistration(listener) {
             @Override
             protected void removeRegistration() {
-                transformers.remove(transformer.getOutputRepresentation(), this);
+                listeners.remove(this);
             }
         };
 
-        transformers.put(transformer.getOutputRepresentation(), ret);
+        synchronized (this) {
+            final Collection<PotentialSchemaSource<?>> col = new ArrayList<>();
+            for (Multimap<Class<? extends SchemaSourceRepresentation>, AbstractSchemaSourceRegistration<?>> m : sources.values()) {
+                for (AbstractSchemaSourceRegistration<?> r : m.values()) {
+                    col.add(r.getInstance());
+                }
+            }
+
+            // Notify first, so translator-type listeners, who react by registering a source
+            // do not cause infinite loop.
+            listener.schemaSourceRegistered(col);
+            listeners.add(ret);
+        }
         return ret;
     }
 }
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaSourceCache.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaSourceCache.java
new file mode 100644 (file)
index 0000000..498f403
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.util;
+
+import com.google.common.base.Preconditions;
+
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+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.SchemaSourceListener;
+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;
+
+/**
+ * Abstract base class for cache-type SchemaSourceListeners. It needs to be
+ * registered with a {@link SchemaSourceRegistry}, where it gets notifications
+ * from. It performs filtering and {@link #offer(SchemaSourceRepresentation)}s
+ * conforming sources to the subclass.
+ *
+ * @param <T> Cached schema source type.
+ */
+public abstract class AbstractSchemaSourceCache<T extends SchemaSourceRepresentation> implements SchemaSourceListener, SchemaSourceProvider<T> {
+    private final SchemaSourceRegistry consumer;
+    private final Class<T> representation;
+    private final Costs cost;
+
+    protected AbstractSchemaSourceCache(final SchemaSourceRegistry consumer, final Class<T> representation, final Costs cost) {
+        this.consumer = Preconditions.checkNotNull(consumer);
+        this.representation = Preconditions.checkNotNull(representation);
+        this.cost = Preconditions.checkNotNull(cost);
+    }
+
+    /**
+     * Offer a schema source in requested representation for caching. Subclasses
+     * need to implement this method to store the schema source. Once they have
+     * determined to cache the source, they should call {@link #register(SourceIdentifier)}.
+     *
+     * @param source schema source
+     */
+    protected abstract void offer(T source);
+
+    /**
+     * Register the presence of a cached schema source with the consumer. Subclasses
+     * need to call this method once they have cached a schema source representation,
+     * or when they have determined they have a schema source is available -- like
+     * when a persistent cache reads its cache index.
+     *
+     * @param sourceIdentifier Source identifier
+     * @return schema source registration, which the subclass needs to
+     *         {@link SchemaSourceRegistration#close() once it expunges the source
+     *         from the cache.
+     */
+    protected final SchemaSourceRegistration<T> register(final SourceIdentifier sourceIdentifier) {
+        final PotentialSchemaSource<T> src = PotentialSchemaSource.create(sourceIdentifier, representation, cost.getValue());
+        return consumer.registerSchemaSource(this, src);
+    }
+
+    @Override
+    public void schemaSourceEncountered(final SchemaSourceRepresentation source) {
+        if (representation.isAssignableFrom(source.getType())) {
+            @SuppressWarnings("unchecked")
+            final T src = (T)source;
+            offer(src);
+        }
+    }
+
+    @Override
+    public final void schemaSourceRegistered(final Iterable<PotentialSchemaSource<?>> sources) {
+        // Not interesting
+    }
+
+    @Override
+    public final void schemaSourceUnregistered(final PotentialSchemaSource<?> source) {
+        // Not interesting
+    }
+}
index 9ed0afefc727eb1771d8055a7a661433cafd6128..241cc15996426321cf2f4051cd5a8c8a0f1e0444 100644 (file)
@@ -10,19 +10,20 @@ package org.opendaylight.yangtools.yang.model.repo.util;
 import com.google.common.base.Preconditions;
 
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
 
-public abstract class AbstractSchemaSourceRegistration extends AbstractObjectRegistration<SourceIdentifier> implements SchemaSourceRegistration {
+public abstract class AbstractSchemaSourceRegistration<T extends SchemaSourceRepresentation> extends AbstractObjectRegistration<PotentialSchemaSource<T>> implements SchemaSourceRegistration<T> {
     private final SchemaSourceProvider<?> provider;
 
-    protected AbstractSchemaSourceRegistration(final SourceIdentifier identifier, final SchemaSourceProvider<?> provider) {
-        super(identifier);
+    protected AbstractSchemaSourceRegistration(final SchemaSourceProvider<?> provider, final PotentialSchemaSource<T> source) {
+        super(source);
         this.provider = Preconditions.checkNotNull(provider);
     }
 
-    protected SchemaSourceProvider<?> getProvider() {
+    protected final SchemaSourceProvider<?> getProvider() {
         return provider;
     }
 }
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaTransformerRegistration.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaTransformerRegistration.java
deleted file mode 100644 (file)
index d264ae0..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/eplv10.html
- */
-package org.opendaylight.yangtools.yang.model.repo.util;
-
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformer;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaTransformerRegistration;
-
-public abstract class AbstractSchemaTransformerRegistration extends AbstractObjectRegistration<SchemaSourceTransformer<?, ?>> implements SchemaTransformerRegistration {
-    protected AbstractSchemaTransformerRegistration(
-            final SchemaSourceTransformer<?, ?> transformer) {
-        super(transformer);
-    }
-}
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/InMemorySchemaSourceCache.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/InMemorySchemaSourceCache.java
new file mode 100644 (file)
index 0000000..ac820d2
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.RemovalListener;
+import com.google.common.cache.RemovalNotification;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Costs;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+
+public class InMemorySchemaSourceCache<T extends SchemaSourceRepresentation> extends AbstractSchemaSourceCache<T> {
+    private static final class CacheEntry<T extends SchemaSourceRepresentation> {
+        private final SchemaSourceRegistration<T> reg;
+        private final T source;
+
+        public CacheEntry(final T source, final SchemaSourceRegistration<T> reg) {
+            this.source = Preconditions.checkNotNull(source);
+            this.reg = Preconditions.checkNotNull(reg);
+        }
+    }
+
+    private static final RemovalListener<SourceIdentifier, CacheEntry<?>> LISTENER = new RemovalListener<SourceIdentifier, CacheEntry<?>>() {
+        @Override
+        public void onRemoval(final RemovalNotification<SourceIdentifier, CacheEntry<?>> notification) {
+            notification.getValue().reg.close();
+        }
+    };
+
+    private final Cache<SourceIdentifier, CacheEntry<T>> cache;
+
+    protected InMemorySchemaSourceCache(final SchemaSourceRegistry consumer, final Class<T> representation, final int maxSize) {
+        super(consumer, representation, Costs.IMMEDIATE);
+        cache = CacheBuilder.newBuilder().softValues().maximumSize(maxSize).removalListener(LISTENER).build();
+    }
+
+    @Override
+    public CheckedFuture<? extends T, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+        final CacheEntry<T> present = cache.getIfPresent(sourceIdentifier);
+        if (present != null) {
+            return Futures.immediateCheckedFuture(present.source);
+        }
+
+        return Futures.<T, SchemaSourceException>immediateFailedCheckedFuture(new MissingSchemaSourceException("Source not found"));
+    }
+
+    @Override
+    protected void offer(final T source) {
+        final CacheEntry<T> present = cache.getIfPresent(source.getIdentifier());
+        if (present == null) {
+            final SchemaSourceRegistration<T> reg = register(source.getIdentifier());
+            cache.put(source.getIdentifier(), new CacheEntry<T>(source, reg));
+        }
+    }
+}
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/RefcountedRegistration.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/RefcountedRegistration.java
new file mode 100644 (file)
index 0000000..3cd59b2
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.util;
+
+import com.google.common.base.Preconditions;
+
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+
+final class RefcountedRegistration {
+    private final SchemaSourceRegistration<?> reg;
+    private int refcount = 1;
+
+    RefcountedRegistration(final SchemaSourceRegistration<?> reg) {
+        this.reg = Preconditions.checkNotNull(reg);
+    }
+
+    public void incRef() {
+        refcount++;
+    }
+
+    public boolean decRef() {
+        Preconditions.checkState(refcount > 0, "Refcount underflow: %s", refcount);
+
+        if (0 == --refcount) {
+            reg.close();
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/SchemaSourceTransformer.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/SchemaSourceTransformer.java
new file mode 100644 (file)
index 0000000..7b58006
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
+import org.opendaylight.yangtools.util.concurrent.ReflectiveExceptionMapper;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
+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;
+
+public class SchemaSourceTransformer<S extends SchemaSourceRepresentation, D extends SchemaSourceRepresentation> implements SchemaSourceListener, SchemaSourceProvider<D> {
+    private static final ExceptionMapper<SchemaSourceException> MAPPER = ReflectiveExceptionMapper.create("Source transformation", SchemaSourceException.class);
+
+    public static interface Transformation<S extends SchemaSourceRepresentation, D extends SchemaSourceRepresentation> extends AsyncFunction<S, D> {
+        @Override
+        CheckedFuture<D, SchemaSourceException> apply(final S input) throws Exception;
+    }
+
+    private final Map<PotentialSchemaSource<?>, RefcountedRegistration> sources = new HashMap<>();
+    private final SchemaSourceRegistry consumer;
+    private final SchemaRepository provider;
+    private final AsyncFunction<S, D> function;
+    private final Class<S> srcClass;
+    private final Class<D> dstClass;
+
+    public SchemaSourceTransformer(final SchemaRepository provider, final Class<S> srcClass,
+            final SchemaSourceRegistry consumer, final Class<D> dstClass, final AsyncFunction<S, D> function) {
+        this.provider = Preconditions.checkNotNull(provider);
+        this.consumer = Preconditions.checkNotNull(consumer);
+        this.function = Preconditions.checkNotNull(function);
+        this.srcClass = Preconditions.checkNotNull(srcClass);
+        this.dstClass = Preconditions.checkNotNull(dstClass);
+    }
+
+    @Override
+    public CheckedFuture<D, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+        final CheckedFuture<S, SchemaSourceException> f = provider.getSchemaSource(sourceIdentifier, srcClass);
+        return Futures.makeChecked(Futures.transform(f, function), MAPPER);
+    }
+
+    @Override
+    public final void schemaSourceEncountered(final SchemaSourceRepresentation source) {
+        // Not interesting
+    }
+
+    @Override
+    public final void schemaSourceRegistered(final Iterable<PotentialSchemaSource<?>> sources) {
+        for (PotentialSchemaSource<?> src : sources) {
+            final Class<?> rep = src.getRepresentation();
+            if (srcClass.isAssignableFrom(rep) && dstClass != rep) {
+                registerSource(src);
+            }
+        }
+    }
+
+    @Override
+    public final void schemaSourceUnregistered(final PotentialSchemaSource<?> source) {
+        final Class<?> rep = source.getRepresentation();
+        if (srcClass.isAssignableFrom(rep) && dstClass != rep) {
+            unregisterSource(source);
+        }
+    }
+
+    private void registerSource(final PotentialSchemaSource<?> src) {
+        RefcountedRegistration reg = sources.get(src);
+        if (reg != null) {
+            reg.incRef();
+            return;
+        }
+
+        final PotentialSchemaSource<D> newSrc = PotentialSchemaSource.create(src.getSourceIdentifier(), dstClass,
+                src.getCost() + PotentialSchemaSource.Costs.COMPUTATION.getValue());
+
+        final SchemaSourceRegistration<D> r = consumer.registerSchemaSource(this, newSrc);
+        sources.put(src, new RefcountedRegistration(r));
+    }
+
+    private void unregisterSource(final PotentialSchemaSource<?> src) {
+        final RefcountedRegistration reg = sources.get(src);
+        if (reg != null && reg.decRef()) {
+            sources.remove(src);
+        }
+    }
+}
index 50354f5ed8956fb29d03520f7affdfdeee54c2d7..45bedd8c3a9b7da64a762d74a141549adc13065a 100644 (file)
@@ -26,6 +26,7 @@ import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.st
 import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
 import com.google.common.collect.Iterables;
+
 import java.net.URI;
 import java.text.DateFormat;
 import java.text.ParseException;
@@ -33,7 +34,9 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
+
 import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
@@ -96,6 +99,7 @@ import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuil
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 public final class YangParserListenerImpl extends YangParserBaseListener {
     private static final Logger LOG = LoggerFactory.getLogger(YangParserListenerImpl.class);
     private static final Splitter COLON_SPLITTER = Splitter.on(':');
@@ -113,6 +117,24 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         this.sourcePath = sourcePath;
     }
 
+    /**
+     * Create a new instance.
+     *
+     * FIXME: the resulting type needs to be extracted, such that we can reuse
+     *        the "BaseListener" aspect, which need not be exposed to the user.
+     *        Maybe factor out a base class into repo.spi?
+     *
+     * @param sourcePath
+     * @param walker
+     * @param tree
+     * @return
+     */
+    public static YangParserListenerImpl create(final String sourcePath, final ParseTreeWalker walker, final ParseTree tree) {
+        final YangParserListenerImpl ret = new YangParserListenerImpl(sourcePath);
+        walker.walk(ret, tree);
+        return ret;
+    }
+
     @Override
     public void enterModule_stmt(final YangParser.Module_stmtContext ctx) {
         moduleName = stringFromNode(ctx);
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/AbstractURLRegistration.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/AbstractURLRegistration.java
new file mode 100644 (file)
index 0000000..8dee836
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.repo;
+
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+
+public abstract class AbstractURLRegistration extends AbstractObjectRegistration<YangTextSchemaSource> implements URLRegistration{
+    protected AbstractURLRegistration(final YangTextSchemaSource text) {
+        super(text);
+    }
+}
\ No newline at end of file
index 45ad366285af4c7f5244ebed4ff22c6b3429e336..5bc6616c869013f2d13cbb28406ba8df14922dba 100644 (file)
@@ -71,6 +71,8 @@ final class DependencyResolver {
         return rev == null && findWildcard(haystack, mi.getModuleName()) != null;
     }
 
+
+
     public static final DependencyResolver create(final Map<SourceIdentifier, YangModelDependencyInfo> depInfo) {
         final Collection<SourceIdentifier> resolved = new ArrayList<>(depInfo.size());
         final Collection<SourceIdentifier> pending = new ArrayList<>(depInfo.keySet());
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java
new file mode 100644 (file)
index 0000000..5873856
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.repo;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
+import org.opendaylight.yangtools.util.concurrent.ReflectiveExceptionMapper;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserListenerImpl;
+import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
+import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class SharedSchemaContextFactory implements SchemaContextFactory {
+    private static final ExceptionMapper<SchemaResolutionException> MAPPER = ReflectiveExceptionMapper.create("resolve sources", SchemaResolutionException.class);
+    private static final Logger LOG = LoggerFactory.getLogger(SharedSchemaContextFactory.class);
+
+    private final Function<SourceIdentifier, ListenableFuture<ASTSchemaSource>> requestSources = new Function<SourceIdentifier, ListenableFuture<ASTSchemaSource>>() {
+        @Override
+        public ListenableFuture<ASTSchemaSource> apply(final SourceIdentifier input) {
+            return repository.getSchemaSource(input, ASTSchemaSource.class);
+        }
+    };
+    private final Cache<Collection<SourceIdentifier>, SchemaContext> cache = CacheBuilder.newBuilder().softValues().build();
+
+    private final AsyncFunction<List<ASTSchemaSource>, SchemaContext> assembleSources = new AsyncFunction<List<ASTSchemaSource>, SchemaContext>() {
+        @Override
+        public ListenableFuture<SchemaContext> apply(final List<ASTSchemaSource> sources) throws SchemaResolutionException {
+            final Map<SourceIdentifier, ASTSchemaSource> srcs =
+                    Maps.uniqueIndex(sources, ASTSchemaSource.GET_IDENTIFIER);
+            final Map<SourceIdentifier, YangModelDependencyInfo> deps =
+                    Maps.transformValues(srcs, ASTSchemaSource.GET_DEPINFO);
+
+            LOG.debug("Resolving dependency reactor {}", deps);
+
+            final DependencyResolver res = DependencyResolver.create(deps);
+            if (!res.getUnresolvedSources().isEmpty()) {
+                LOG.debug("Omitting models {} due to unsatisfied imports {}", res.getUnresolvedSources(), res.getUnsatisfiedImports());
+
+                // FIXME: push into DependencyResolver
+
+                throw new SchemaResolutionException("Failed to resolve required models",
+                        res.getResolvedSources(), res.getUnsatisfiedImports());
+            }
+
+            final Map<SourceIdentifier, ParserRuleContext> asts =
+                    Maps.transformValues(srcs, ASTSchemaSource.GET_AST);
+
+            final ParseTreeWalker walker = new ParseTreeWalker();
+            final Map<SourceIdentifier, ModuleBuilder> sourceToBuilder = new LinkedHashMap<>();
+
+            for (Entry<SourceIdentifier, ParserRuleContext> entry : asts.entrySet()) {
+                ModuleBuilder moduleBuilder =
+                        YangParserListenerImpl.create(entry.getKey().getName(), walker, entry.getValue()).getModuleBuilder();
+
+                moduleBuilder.setSource(srcs.get(entry.getKey()).getYangText());
+                sourceToBuilder.put(entry.getKey(), moduleBuilder);
+            }
+            LOG.debug("Modules ready for integration");
+
+            final YangParserImpl parser = YangParserImpl.getInstance();
+            final Collection<Module> modules = parser.buildModules(sourceToBuilder.values());
+            LOG.debug("Integrated cross-references modules");
+            return Futures.immediateCheckedFuture(parser.assembleContext(modules));
+        }
+    };
+
+    private final SharedSchemaRepository repository;
+    // FIXME: ignored right now
+    private final SchemaSourceFilter filter;
+
+    public SharedSchemaContextFactory(final SharedSchemaRepository repository, final SchemaSourceFilter filter) {
+        this.repository = Preconditions.checkNotNull(repository);
+        this.filter = Preconditions.checkNotNull(filter);
+    }
+
+    @Override
+    public CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(final Collection<SourceIdentifier> requiredSources) {
+        final SchemaContext existing = cache.getIfPresent(requiredSources);
+        if (existing != null) {
+            LOG.debug("Returning cached context {}", existing);
+            return Futures.immediateCheckedFuture(existing);
+        }
+
+        // Request all sources be loaded
+        final ListenableFuture<List<ASTSchemaSource>> sf = Futures.allAsList(Collections2.transform(requiredSources, requestSources));
+
+        // Assemble sources into a schemacontext
+        final ListenableFuture<SchemaContext> cf = Futures.transform(sf, assembleSources);
+
+        // Populate cache when successful
+        Futures.addCallback(cf, new FutureCallback<SchemaContext>() {
+            @Override
+            public void onSuccess(final SchemaContext result) {
+                cache.put(requiredSources, result);
+            }
+
+            @Override
+            public void onFailure(final Throwable t) {
+                LOG.info("Failed to assemble sources", t);
+            }
+        });
+
+        return Futures.makeChecked(cf, MAPPER);
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepository.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepository.java
new file mode 100644 (file)
index 0000000..1ff9f32
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.repo;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+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.util.AbstractSchemaRepository;
+
+/**
+ * A {@link SchemaRepository} which allows sharing of {@link SchemaContext} as
+ * long as their specification is the same.
+ *
+ * Note: for current implementation, "same" means the same filter and the same
+ * set of {@link SourceIdentifier}s.
+ */
+@Beta
+public final class SharedSchemaRepository extends AbstractSchemaRepository implements Identifiable<String> {
+    private final LoadingCache<SchemaSourceFilter, SchemaContextFactory> cache =
+            CacheBuilder.newBuilder().softValues().build(new CacheLoader<SchemaSourceFilter, SchemaContextFactory>() {
+                @Override
+                public SchemaContextFactory load(final SchemaSourceFilter key) {
+                    return new SharedSchemaContextFactory(SharedSchemaRepository.this, key);
+                }
+            });
+    private final String id;
+
+    public SharedSchemaRepository(final String id) {
+        this.id = Preconditions.checkNotNull(id);
+    }
+
+    @Override
+    public String getIdentifier() {
+        return id;
+    }
+
+    @Override
+    public SchemaContextFactory createSchemaContextFactory(final SchemaSourceFilter filter) {
+        return cache.getUnchecked(filter);
+    }
+
+    @Override
+    public String toString() {
+        return "SchemaRepository: " + id;
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/URLRegistration.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/URLRegistration.java
new file mode 100644 (file)
index 0000000..d49ecc9
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.repo;
+
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+
+public interface URLRegistration extends ObjectRegistration<YangTextSchemaSource> {
+    @Override
+    void close();
+}
\ No newline at end of file
index 8ee18e58a5a562d40bb65e0de26fef2b9ffebb58..47de6b1a540b5bd1b0a14014ce9a5364447977b3 100644 (file)
@@ -9,155 +9,78 @@ package org.opendaylight.yangtools.yang.parser.repo;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
-import com.google.common.base.Function;
+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.collect.ArrayListMultimap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Maps.EntryTransformer;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.ImmutableList;
 import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.atomic.AtomicReference;
 
-import javax.annotation.concurrent.GuardedBy;
-import javax.annotation.concurrent.ThreadSafe;
-
-import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.tree.ParseTreeWalker;
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
-import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+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.SchemaSourceTransformationException;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserListenerImpl;
-import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+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.parser.util.ASTSchemaSource;
 import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-@ThreadSafe
-public class URLSchemaContextResolver {
+@Beta
+public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSchemaSource> {
     private static final Logger LOG = LoggerFactory.getLogger(URLSchemaContextResolver.class);
-    private static final Function<ASTSchemaSource, YangModelDependencyInfo> EXTRACT_DEPINFO = new Function<ASTSchemaSource, YangModelDependencyInfo>() {
-        @Override
-        public YangModelDependencyInfo apply(final ASTSchemaSource input) {
-            return input.getDependencyInformation();
-        }
-    };
-    private static final EntryTransformer<SourceIdentifier, Collection<YangModelDependencyInfo>, YangModelDependencyInfo> SQUASH_DEPINFO =
-            new EntryTransformer<SourceIdentifier, Collection<YangModelDependencyInfo>, YangModelDependencyInfo>() {
-        @Override
-        public YangModelDependencyInfo transformEntry(final SourceIdentifier key, final Collection<YangModelDependencyInfo> value) {
-            // FIXME: validate that all the info objects are the same
-            return value.iterator().next();
-        }
-    };
-    private static final Function<ASTSchemaSource, ParserRuleContext> EXTRACT_AST = new Function<ASTSchemaSource, ParserRuleContext>() {
-        @Override
-        public ParserRuleContext apply(final ASTSchemaSource input) {
-            return input.getAST();
-        }
-    };
-    private static final EntryTransformer<SourceIdentifier, Collection<ParserRuleContext>, ParserRuleContext> SQUASH_AST =
-            new EntryTransformer<SourceIdentifier, Collection<ParserRuleContext>, ParserRuleContext>() {
-        @Override
-        public ParserRuleContext transformEntry(final SourceIdentifier key, final Collection<ParserRuleContext> value) {
-            // FIXME: validate that all the info objects are the same
-            return value.iterator().next();
-        }
-    };
-
-    @GuardedBy("this")
-    private final Multimap<SourceIdentifier, ASTSchemaSource> resolvedRegs = ArrayListMultimap.create();
-    private final AtomicReference<Optional<SchemaContext>> currentSchemaContext = new AtomicReference<>(Optional.<SchemaContext>absent());
-    private final Queue<URLRegistration> outstandingRegs = new ConcurrentLinkedQueue<>();
-    private final TextToASTTransformer transformer;
-    @GuardedBy("this")
-    private Object version = new Object();
-    @GuardedBy("this")
-    private Object contextVersion = version;
-
-    private final class URLRegistration extends AbstractObjectRegistration<URL> {
-        @GuardedBy("this")
-        private CheckedFuture<ASTSchemaSource, SchemaSourceTransformationException> future;
-        @GuardedBy("this")
-        private ASTSchemaSource result;
-
-        protected URLRegistration(final URL url, final CheckedFuture<ASTSchemaSource, SchemaSourceTransformationException> future) {
-            super(url);
-            this.future = Preconditions.checkNotNull(future);
-        }
-
-        private synchronized boolean setResult(final ASTSchemaSource result) {
-            if (future != null) {
-                this.result = result;
-                return true;
-            } else {
-                return false;
-            }
-        }
 
-        @Override
-        protected void removeRegistration() {
-            // Cancel the future, but it may already be completing
-            future.cancel(false);
-
-            synchronized (this) {
-                future = null;
-                outstandingRegs.remove(this);
-                if (result != null) {
-                    removeSchemaSource(result);
-                }
-            }
-        }
-    }
-
-    private URLSchemaContextResolver(final TextToASTTransformer transformer) {
-        this.transformer = Preconditions.checkNotNull(transformer);
+    private final Cache<SourceIdentifier, YangTextSchemaSource> sources = CacheBuilder.newBuilder().build();
+    private final Collection<SourceIdentifier> requiredSources = new ConcurrentLinkedDeque<>();
+    private final AtomicReference<Optional<SchemaContext>> currentSchemaContext =
+            new AtomicReference<>(Optional.<SchemaContext>absent());
+    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);
     }
 
     public static URLSchemaContextResolver create(final String name) {
-        final ThreadFactory f = new ThreadFactoryBuilder().setDaemon(true).setNameFormat(name + "yangparser-%d").build();
-        final ListeningExecutorService s = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(f));
-
-        return new URLSchemaContextResolver(TextToASTTransformer.create(s));
+        final SharedSchemaRepository sharedRepo = new SharedSchemaRepository(name);
+        return new URLSchemaContextResolver(sharedRepo, sharedRepo);
     }
 
     /**
      * Register a URL hosting a YANG Text file.
      *
      * @param url URL
+     * @throws YangSyntaxErrorException When the YANG file is syntactically invalid
+     * @throws IOException when the URL is not readable
+     * @throws SchemaSourceException When parsing encounters general error
      */
-    public ObjectRegistration<URL> registerSource(final URL url) {
+    public URLRegistration registerSource(final URL url) throws SchemaSourceException, IOException, YangSyntaxErrorException {
         checkArgument(url != null, "Supplied URL must not be null");
 
-        final SourceIdentifier id = SourceIdentifier.create(url.getFile().toString(), Optional.<String>absent());
-        final YangTextSchemaSource text = new YangTextSchemaSource(id) {
+        final SourceIdentifier guessedId = new SourceIdentifier(url.getFile(), Optional.<String>absent());
+        final YangTextSchemaSource text = new YangTextSchemaSource(guessedId) {
             @Override
             public InputStream openStream() throws IOException {
                 return url.openStream();
@@ -169,39 +92,27 @@ public class URLSchemaContextResolver {
             }
         };
 
-        final CheckedFuture<ASTSchemaSource, SchemaSourceTransformationException> ast = transformer.transformSchemaSource(text);
-        final URLRegistration reg = new URLRegistration(url, ast);
-        outstandingRegs.add(reg);
+        final ASTSchemaSource ast = TextToASTTransformer.TRANSFORMATION.apply(text).checkedGet();
+        LOG.trace("Resolved URL {} to source {}", url, ast);
 
-        Futures.addCallback(ast, new FutureCallback<ASTSchemaSource>() {
-            @Override
-            public void onSuccess(final ASTSchemaSource result) {
-                LOG.trace("Resolved URL {} to source {}", url, result);
+        final SourceIdentifier resolvedId = ast.getIdentifier();
+        final SchemaSourceRegistration<YangTextSchemaSource> reg = registry.registerSchemaSource(this,
+                PotentialSchemaSource.create(resolvedId, YangTextSchemaSource.class, 0));
 
-                outstandingRegs.remove(reg);
-                if (reg.setResult(result)) {
-                    addSchemaSource(result);
-                }
-            }
+        requiredSources.add(resolvedId);
+        LOG.trace("Added source {} to schema context requirements", resolvedId);
+        version = new Object();
 
+        return new AbstractURLRegistration(text) {
             @Override
-            public void onFailure(final Throwable t) {
-                LOG.warn("Failed to parse YANG text from {}, ignoring it", url, t);
-                outstandingRegs.remove(reg);
+            protected void removeRegistration() {
+                requiredSources.remove(resolvedId);
+                LOG.trace("Removed source {} from schema context requirements", resolvedId);
+                version = new Object();
+                reg.close();
+                sources.invalidate(resolvedId);
             }
-        });
-
-        return reg;
-    }
-
-    private synchronized void addSchemaSource(final ASTSchemaSource src) {
-        resolvedRegs.put(src.getIdentifier(), src);
-        version = new Object();
-    }
-
-    private synchronized void removeSchemaSource(final ASTSchemaSource src) {
-        resolvedRegs.put(src.getIdentifier(), src);
-        version = new Object();
+        };
     }
 
     /**
@@ -210,64 +121,57 @@ public class URLSchemaContextResolver {
      *         new schema context was successfully built.
      */
     public Optional<SchemaContext> getSchemaContext() {
-        while (true) {
-            Optional<SchemaContext> result;
-            final Multimap<SourceIdentifier, ASTSchemaSource> sources;
-            final Object v;
-            synchronized (this) {
-                result = currentSchemaContext.get();
-                if (version == contextVersion) {
-                    return result;
+        final SchemaContextFactory factory = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+        Optional<SchemaContext> sc;
+        Object v;
+        do {
+            // Spin get stable context version
+            Object cv;
+            do {
+                cv = contextVersion;
+                sc = currentSchemaContext.get();
+                if (version == cv) {
+                    return sc;
                 }
+            } while (cv != contextVersion);
 
-                sources = ImmutableMultimap.copyOf(resolvedRegs);
+            // Version has been updated
+            Collection<SourceIdentifier> sources;
+            do {
                 v = version;
-            }
-
-            if (!sources.isEmpty()) {
-                final Map<SourceIdentifier, YangModelDependencyInfo> deps =
-                        Maps.transformEntries(Multimaps.transformValues(sources, EXTRACT_DEPINFO).asMap(), SQUASH_DEPINFO);
-
-                LOG.debug("Resolving dependency reactor {}", deps);
-                final DependencyResolver res = DependencyResolver.create(deps);
-                if (!res.getUnresolvedSources().isEmpty()) {
-                    LOG.debug("Omitting models {} due to unsatisfied imports {}", res.getUnresolvedSources(), res.getUnsatisfiedImports());
+                sources = ImmutableList.copyOf(requiredSources);
+            } while (v != version);
+
+            while (true) {
+                final CheckedFuture<SchemaContext, SchemaResolutionException> f = factory.createSchemaContext(sources);
+                try {
+                    sc = Optional.of(f.checkedGet());
+                    break;
+                } catch (SchemaResolutionException e) {
+                    LOG.info("Failed to fully assemble schema context for {}", sources, e);
+                    sources = e.getResolvedSources();
                 }
-
-                final Map<SourceIdentifier, ParserRuleContext> asts =
-                        Maps.transformEntries(Multimaps.transformValues(sources, EXTRACT_AST).asMap(), SQUASH_AST);
-
-                final ParseTreeWalker walker = new ParseTreeWalker();
-                final Map<SourceIdentifier, ModuleBuilder> sourceToBuilder = new LinkedHashMap<>();
-
-                for (Entry<SourceIdentifier, ParserRuleContext> entry : asts.entrySet()) {
-                    final YangParserListenerImpl yangModelParser = new YangParserListenerImpl(entry.getKey().getName());
-                    walker.walk(yangModelParser, entry.getValue());
-                    ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
-
-                    moduleBuilder.setSource(sources.get(entry.getKey()).iterator().next().getYangText());
-                    sourceToBuilder.put(entry.getKey(), moduleBuilder);
-                }
-                LOG.debug("Modules ready for integration");
-
-                final YangParserImpl parser = YangParserImpl.getInstance();
-                final Collection<Module> modules = parser.buildModules(sourceToBuilder.values());
-                LOG.debug("Integrated cross-references modules");
-
-                result = Optional.of(parser.assembleContext(modules));
-            } else {
-                result = Optional.absent();
             }
 
             synchronized (this) {
-                if (v == version) {
-                    currentSchemaContext.set(result);
-                    contextVersion = version;
-                    return result;
+                if (contextVersion == cv) {
+                    currentSchemaContext.set(sc);
+                    contextVersion = v;
                 }
-
-                LOG.debug("Context version {} expected {}, retry", version, v);
             }
+        } while (version == v);
+
+        return sc;
+    }
+
+    @Override
+    public CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+        final YangTextSchemaSource ret = sources.getIfPresent(sourceIdentifier);
+        if (ret == null) {
+            return Futures.<YangTextSchemaSource, SchemaSourceException>immediateFailedCheckedFuture(
+                    new MissingSchemaSourceException("URL for " + sourceIdentifier + " not registered"));
         }
+
+        return Futures.immediateCheckedFuture(ret);
     }
 }
index ab353a04ad54c7b221e3bebbc194362d93e6cc6e..5ff245962e11d94856e82c40834863959186fc2a 100644 (file)
@@ -6,6 +6,8 @@
  */
 package org.opendaylight.yangtools.yang.parser.util;
 
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 
@@ -27,7 +29,27 @@ import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
  * passes basic semantic validation and we were able to extract dependency
  * information.
  */
+@Beta
 public final class ASTSchemaSource implements SchemaSourceRepresentation {
+    public static final Function<ASTSchemaSource, SourceIdentifier> GET_IDENTIFIER = new Function<ASTSchemaSource, SourceIdentifier>() {
+        @Override
+        public SourceIdentifier apply(final ASTSchemaSource input) {
+            return input.getIdentifier();
+        }
+    };
+    public static final Function<ASTSchemaSource, YangModelDependencyInfo> GET_DEPINFO = new Function<ASTSchemaSource, YangModelDependencyInfo>() {
+        @Override
+        public YangModelDependencyInfo apply(final ASTSchemaSource input) {
+            return input.getDependencyInformation();
+        }
+    };
+    public static final Function<ASTSchemaSource, ParserRuleContext> GET_AST = new Function<ASTSchemaSource, ParserRuleContext>() {
+        @Override
+        public ParserRuleContext apply(final ASTSchemaSource input) {
+            return input.getAST();
+        }
+    };
+
     private final YangModelDependencyInfo depInfo;
     private final ParserRuleContext tree;
     private final SourceIdentifier id;
index ce9d6a8ce9331ea2bf1d0149257cb17e46fc630b..211e6a21743a666065e5e0ebc27aebb5cbb8de87 100644 (file)
@@ -6,26 +6,24 @@
  */
 package org.opendaylight.yangtools.yang.parser.util;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Charsets;
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
 import com.google.common.io.CharStreams;
 import com.google.common.io.InputSupplier;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListeningExecutorService;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.concurrent.Callable;
 
 import org.antlr.v4.runtime.tree.ParseTreeWalker;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
-import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformationException;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformer;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.opendaylight.yangtools.yang.model.repo.util.SchemaSourceTransformer;
 import org.opendaylight.yangtools.yang.parser.impl.YangModelBasicValidationListener;
 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 import org.slf4j.Logger;
@@ -34,73 +32,43 @@ import org.slf4j.LoggerFactory;
 /**
  * A {@link SchemaSourceTransformer} which handles translation of models from
  * {@link YangTextSchemaSource} representation into {@link ASTSchemaSource}.
- *
- * While this class is currently used explicitly, its long-term purpose is to
- * be registered with a {@link org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry}
- * and be invoked on demand when the processing pipeline requests the
- * ASTSchemaSource representation.
  */
-public final class TextToASTTransformer implements SchemaSourceTransformer<YangTextSchemaSource, ASTSchemaSource> {
-    private static final Logger LOG = LoggerFactory.getLogger(TextToASTTransformer.class);
-    private static final Function<Exception, SchemaSourceTransformationException> MAPPER = new ExceptionMapper<SchemaSourceTransformationException>("Source transformation", SchemaSourceTransformationException.class) {
+@Beta
+public final class TextToASTTransformer extends SchemaSourceTransformer<YangTextSchemaSource, ASTSchemaSource> {
+    public static final class TextToASTTransformation implements Transformation<YangTextSchemaSource, ASTSchemaSource> {
         @Override
-        protected SchemaSourceTransformationException newWithCause(final String message, final Throwable cause) {
-            return new SchemaSourceTransformationException(message, cause);
-        }
-    };
-
-    private final ListeningExecutorService executor;
-
-    private TextToASTTransformer(final ListeningExecutorService executor) {
-        this.executor = Preconditions.checkNotNull(executor);
-    }
-
-    public static final TextToASTTransformer create(final ListeningExecutorService executor) {
-        return new TextToASTTransformer(executor);
-    }
+        public CheckedFuture<ASTSchemaSource, SchemaSourceException> apply(final YangTextSchemaSource input) throws IOException, YangSyntaxErrorException {
+            try (InputStream is = input.openStream()) {
+                final YangContext ctx = YangParserImpl.parseYangSource(is);
+                LOG.debug("Model {} parsed successfully", input);
 
-    @Override
-    public Class<YangTextSchemaSource> getInputRepresentation() {
-        return YangTextSchemaSource.class;
-    }
-
-    @Override
-    public Class<ASTSchemaSource> getOutputRepresentation() {
-        return ASTSchemaSource.class;
-    }
+                final ParseTreeWalker walker = new ParseTreeWalker();
+                final YangModelBasicValidationListener validator = new YangModelBasicValidationListener();
+                walker.walk(validator, ctx);
+                LOG.debug("Model {} validated successfully", input);
 
-    @Override
-    public CheckedFuture<ASTSchemaSource, SchemaSourceTransformationException> transformSchemaSource(final YangTextSchemaSource source) {
-        return Futures.makeChecked(executor.submit(new Callable<ASTSchemaSource>() {
-            @Override
-            public ASTSchemaSource call() throws IOException, YangSyntaxErrorException {
-                try (InputStream is = source.openStream()) {
-                    final YangContext ctx = YangParserImpl.parseYangSource(is);
-                    LOG.debug("Model {} parsed successfully", source);
+                // Backwards compatibility
+                final String text = CharStreams.toString(
+                        CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
+                            @Override
+                            public InputStream getInput() throws IOException {
+                                return input.openStream();
+                            }
+                        }, Charsets.UTF_8));
 
-                    final ParseTreeWalker walker = new ParseTreeWalker();
-                    final YangModelBasicValidationListener validator = new YangModelBasicValidationListener();
-                    walker.walk(validator, ctx);
-                    LOG.debug("Model {} validated successfully", source);
+                return Futures.immediateCheckedFuture(ASTSchemaSource.create(input.getIdentifier().getName(), ctx, text));
+            }
+        }
+    };
 
-                    // Backwards compatibility
-                    final String text = CharStreams.toString(
-                            CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
-                                @Override
-                                public InputStream getInput() throws IOException {
-                                    return source.openStream();
-                                }
-                            }, Charsets.UTF_8));
+    public static final TextToASTTransformation TRANSFORMATION = new TextToASTTransformation();
+    private static final Logger LOG = LoggerFactory.getLogger(TextToASTTransformer.class);
 
-                    return ASTSchemaSource.create(source.getIdentifier().getName(), ctx, text);
-                }
-            }
-        }), MAPPER);
+    private TextToASTTransformer(final SchemaRepository provider, final SchemaSourceRegistry consumer) {
+        super(provider, YangTextSchemaSource.class, consumer, ASTSchemaSource.class, TRANSFORMATION);
     }
 
-    @Override
-    public int getCost() {
-        // We perform a direct translation, so the cost is 1.
-        return 1;
+    public static final TextToASTTransformer create(final SchemaRepository provider, final SchemaSourceRegistry consumer) {
+        return new TextToASTTransformer(provider, consumer);
     }
 }