Binding2 runtime - Module info context 76/58976/1
authorJakub Toth <jakub.toth@pantheon.tech>
Thu, 8 Jun 2017 16:31:19 +0000 (18:31 +0200)
committerMartin Ciglan <martin.ciglan@pantheon.tech>
Wed, 14 Jun 2017 19:46:11 +0000 (19:46 +0000)
  * fix template for yangModuleInfo baed on change in
    YangModuleInfo interface

Change-Id: I3161bc19559b1bd38bccaf2148a6745c12141745
Signed-off-by: Jakub Toth <jakub.toth@pantheon.tech>
(cherry picked from commit 1498be778f25c028f751c4e3f18e547bb316c3a1)

binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding/javav2/java/api/generator/yangModuleInfoTemplate.scala.txt
binding2/mdsal-binding2-runtime/src/main/java/org/opendaylight/mdsal/binding/javav2/runtime/context/ModuleInfoBackedContext.java [new file with mode: 0644]
binding2/mdsal-binding2-spec/src/main/java/org/opendaylight/mdsal/binding/javav2/spec/runtime/YangModuleInfo.java

index f212792e6a106a895503c560a6078e99b78551ac..894f0ff293092ebbe59efc7c9bdac5d5ee586921 100644 (file)
@@ -124,6 +124,15 @@ public final class @{MODULE_INFO_CLASS_NAME} implements @{importedNames.get("yan
         return null;
     }
 
+    @@Override
+    public @{importedNames.get("inputStream")} getModuleSourceStream() {
+        @{importedNames.get("inputStream")} stream = @{MODULE_INFO_CLASS_NAME}.class.getResourceAsStream(resourcePath);
+        if (stream == null) {
+            throw new IllegalStateException("Resource '" + resourcePath + "' is missing");
+        }
+        return stream;
+    }
+
     @@Override
     public @{importedNames.get("set")}<@{importedNames.get("yangModuleInfo")}> getImportedModules() {
         return importedModules;
diff --git a/binding2/mdsal-binding2-runtime/src/main/java/org/opendaylight/mdsal/binding/javav2/runtime/context/ModuleInfoBackedContext.java b/binding2/mdsal-binding2-runtime/src/main/java/org/opendaylight/mdsal/binding/javav2/runtime/context/ModuleInfoBackedContext.java
new file mode 100644 (file)
index 0000000..ea7f83d
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.runtime.context;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.base.Optional;
+import com.google.common.io.ByteSource;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.opendaylight.mdsal.binding.javav2.generator.api.ClassLoadingStrategy;
+import org.opendaylight.mdsal.binding.javav2.generator.api.ModuleInfoRegistry;
+import org.opendaylight.mdsal.binding.javav2.generator.impl.GeneratedClassLoadingStrategy;
+import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.YangModuleInfo;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+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.SchemaSourceProvider;
+import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Module info context.
+ */
+@Beta
+public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy
+        implements ModuleInfoRegistry, SchemaContextProvider, SchemaSourceProvider<YangTextSchemaSource> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ModuleInfoBackedContext.class);
+
+    private final YangTextSchemaContextResolver ctxResolver = YangTextSchemaContextResolver.create("binding-context");
+    private final ConcurrentMap<String, WeakReference<ClassLoader>> packageNameToClassLoader =
+            new ConcurrentHashMap<>();
+    private final ConcurrentMap<SourceIdentifier, YangModuleInfo> sourceIdentifierToModuleInfo =
+            new ConcurrentHashMap<>();
+    private final ClassLoadingStrategy backingLoadingStrategy;
+
+
+    private ModuleInfoBackedContext(final ClassLoadingStrategy loadingStrategy) {
+        this.backingLoadingStrategy = loadingStrategy;
+    }
+
+    /**
+     * Create new module info context.
+     *
+     * @return new module info context
+     */
+    public static ModuleInfoBackedContext create() {
+        return new ModuleInfoBackedContext(getTCCLClassLoadingStrategy());
+    }
+
+    /**
+     * Create new module info context based on specific loading strategy.
+     *
+     * @param loadingStrategy
+     *            - specific loading strategy
+     * @return new module info cotext based on specific loading strategy
+     */
+    public static ModuleInfoBackedContext create(final ClassLoadingStrategy loadingStrategy) {
+        return new ModuleInfoBackedContext(loadingStrategy);
+    }
+
+    @Override
+    public Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
+        final String modulePackageName = BindingReflections.getModelRootPackageName(fullyQualifiedName);
+        final WeakReference<ClassLoader> classLoaderRef = packageNameToClassLoader.get(modulePackageName);
+        if (classLoaderRef != null) {
+            final ClassLoader classLoader = classLoaderRef.get();
+            if (classLoader != null) {
+                return ClassLoaderUtils.loadClass(classLoader, fullyQualifiedName);
+            }
+        }
+
+        if (backingLoadingStrategy == null) {
+            throw new ClassNotFoundException(fullyQualifiedName);
+        }
+
+        final Class<?> cls = backingLoadingStrategy.loadClass(fullyQualifiedName);
+        if (BindingReflections.isBindingClass(cls)) {
+            resolveModuleInfo(cls);
+        }
+
+        return cls;
+    }
+
+    // TODO finish schema parsing and expose as SchemaService
+    // Unite with current SchemaService
+    // Implement remove ModuleInfo to update SchemaContext
+
+    /**
+     * Resolving of schema context.
+     *
+     * @return optional of schema context
+     */
+    public Optional<SchemaContext> tryToCreateSchemaContext() {
+        return ctxResolver.getSchemaContext();
+    }
+
+    private boolean resolveModuleInfo(final Class<?> cls) {
+        try {
+            return resolveModuleInfo(BindingReflections.getModuleInfo(cls));
+        } catch (final Exception e) {
+            throw new IllegalStateException(String.format("Failed to resolve module information for class %s", cls), e);
+        }
+    }
+
+    private boolean resolveModuleInfo(final YangModuleInfo moduleInfo) {
+
+        final SourceIdentifier identifier = sourceIdentifierFrom(moduleInfo);
+        final YangModuleInfo previous = sourceIdentifierToModuleInfo.putIfAbsent(identifier, moduleInfo);
+        final ClassLoader moduleClassLoader = moduleInfo.getClass().getClassLoader();
+        try {
+            if (previous == null) {
+                final String modulePackageName = moduleInfo.getClass().getPackage().getName();
+                packageNameToClassLoader.putIfAbsent(modulePackageName,
+                        new WeakReference<>(moduleClassLoader));
+                ctxResolver.registerSource(toYangTextSource(identifier, moduleInfo));
+                for (final YangModuleInfo importedInfo : moduleInfo.getImportedModules()) {
+                    resolveModuleInfo(importedInfo);
+                }
+            } else {
+                return false;
+            }
+        } catch (final Exception e) {
+            LOG.error("Not including {} in YANG sources because of error.", moduleInfo, e);
+        }
+        return true;
+    }
+
+    private static YangTextSchemaSource toYangTextSource(final SourceIdentifier identifier, final YangModuleInfo moduleInfo) {
+        return new YangTextSchemaSource(identifier) {
+
+            @Override
+            public InputStream openStream() throws IOException {
+                return moduleInfo.getModuleSourceStream();
+            }
+
+            @Override
+            protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
+                return toStringHelper;
+            }
+        };
+    }
+
+    private static SourceIdentifier sourceIdentifierFrom(final YangModuleInfo moduleInfo) {
+        return RevisionSourceIdentifier.create(moduleInfo.getName(), Optional.of(moduleInfo.getRevision()));
+    }
+
+    /**
+     * Add new module info into context.
+     *
+     * @param moduleInfos
+     *            - new module info
+     */
+    public void addModuleInfos(final Iterable<? extends YangModuleInfo> moduleInfos) {
+        for (final YangModuleInfo yangModuleInfo : moduleInfos) {
+            registerModuleInfo(yangModuleInfo);
+        }
+    }
+
+    @Override
+    public ObjectRegistration<YangModuleInfo> registerModuleInfo(final YangModuleInfo yangModuleInfo) {
+        final YangModuleInfoRegistration registration = new YangModuleInfoRegistration(yangModuleInfo, this);
+        resolveModuleInfo(yangModuleInfo);
+        return registration;
+    }
+
+    @Override public CheckedFuture<? extends YangTextSchemaSource, SchemaSourceException> getSource(
+        final SourceIdentifier sourceIdentifier) {
+        final YangModuleInfo yangModuleInfo = sourceIdentifierToModuleInfo.get(sourceIdentifier);
+
+        if (yangModuleInfo == null) {
+            LOG.debug("Unknown schema source requested: {}, available sources: {}", sourceIdentifier, sourceIdentifierToModuleInfo.keySet());
+            return Futures
+                .immediateFailedCheckedFuture(new SchemaSourceException("Unknown schema source: " + sourceIdentifier));
+        }
+
+        return Futures
+            .immediateCheckedFuture(YangTextSchemaSource.delegateForByteSource(sourceIdentifier, new ByteSource() {
+                @Override public InputStream openStream() throws IOException {
+                        return yangModuleInfo.getModuleSourceStream();
+                }
+            }));
+    }
+
+    private static class YangModuleInfoRegistration extends AbstractObjectRegistration<YangModuleInfo> {
+
+        private final ModuleInfoBackedContext context;
+
+        public YangModuleInfoRegistration(final YangModuleInfo instance, final ModuleInfoBackedContext context) {
+            super(instance);
+            this.context = context;
+        }
+
+        @Override
+        protected void removeRegistration() {
+            context.remove(this);
+        }
+
+    }
+
+    private void remove(final YangModuleInfoRegistration registration) {
+        // FIXME implement
+    }
+
+    @Override
+    public SchemaContext getSchemaContext() {
+        final Optional<SchemaContext> contextOptional = tryToCreateSchemaContext();
+        if (contextOptional.isPresent()) {
+            return contextOptional.get();
+        }
+        throw new IllegalStateException("Unable to recreate SchemaContext, error while parsing");
+    }
+}
index 244a6349335f993b25394e94bde701230ac5a8f0..1e6706ac38395cb968e5e82c269e613d5d086025 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.mdsal.binding.javav2.spec.runtime;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;
+import java.io.InputStream;
 import java.util.Set;
 import org.opendaylight.yangtools.concepts.SemVer;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
@@ -60,4 +61,11 @@ public interface YangModuleInfo {
      */
     SchemaSourceRepresentation getModuleSourceRepresentation();
 
+    /**
+     * Get stream of module source
+     *
+     * @return input stream of module source
+     */
+    InputStream getModuleSourceStream();
+
 }