+++ /dev/null
-/*
- * 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);
- }
-}
--- /dev/null
+/*
+ * 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);
+ }
+}
*/
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;
* 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
*/
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;
* 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
* @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);
}
*/
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);
}
/**
*
* @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) {
* 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);
}
}
*/
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);
}
*/
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;
* Implementations of this interface expected to comply with the {@link Immutable}
* contract.
*/
+@Beta
public interface SchemaSourceRepresentation extends Identifiable<SourceIdentifier>, Immutable {
/**
* {@inheritDoc}
*/
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;
import org.opendaylight.yangtools.concepts.Immutable;
/**
- *
* YANG Schema source identifier
*
* Simple transfer object represents identifier of source for YANG schema (module or submodule),
* <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;
*/
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;
* 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;
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}
*/
*/
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}
--- /dev/null
+/*
+ * 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;
+ }
+}
*/
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();
}
--- /dev/null
+/*
+ * 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);
+}
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;
*
* <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
*
* @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);
}
*/
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();
}
*/
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;
* {@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);
}
+++ /dev/null
-/*
- * 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();
-}
--- /dev/null
+/*
+ * 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);
+ }
+}
*/
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);
}
}
@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;
}
}
--- /dev/null
+/*
+ * 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
+ }
+}
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;
}
}
+++ /dev/null
-/*
- * 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);
- }
-}
--- /dev/null
+/*
+ * 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));
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
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;
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;
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(':');
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);
--- /dev/null
+/*
+ * 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
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());
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
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();
}
};
- 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();
+ };
}
/**
* 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);
}
}
*/
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;
* 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;
*/
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;
/**
* 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);
}
}