Merge "Fix for features - added missing dependency"
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / RuntimeGeneratedMappingServiceImpl.java
index eacbd93eb55e3c65c1b8d3dc03c846093d390ef7..29a532228dd54bfc6421c34035af5f91f923cafb 100644 (file)
@@ -7,8 +7,17 @@
  */
 package org.opendaylight.yangtools.sal.binding.generator.impl;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+
+import java.net.URI;
 import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -19,11 +28,11 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
 
 import javassist.ClassPool;
 
-import org.eclipse.xtext.xbase.lib.Extension;
+import javax.annotation.concurrent.GuardedBy;
+
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
 import org.opendaylight.yangtools.binding.generator.util.Types;
@@ -40,10 +49,10 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.codec.AugmentationCodec;
@@ -53,6 +62,7 @@ import org.opendaylight.yangtools.yang.data.impl.codec.DataContainerCodec;
 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
 import org.opendaylight.yangtools.yang.data.impl.codec.InstanceIdentifierCodec;
 import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -65,110 +75,76 @@ import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.HashMultimap;
-import com.google.common.util.concurrent.SettableFuture;
-
 public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaContextListener,
-        SchemaLock, AutoCloseable, SchemaContextHolder {
+SchemaLock, AutoCloseable, SchemaContextHolder, TypeResolver {
 
     private static final Logger LOG = LoggerFactory.getLogger(RuntimeGeneratedMappingServiceImpl.class);
 
-    private final ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap<>();
-    private final ConcurrentMap<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap<>();
-    private final ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap<>();
     private final ConcurrentMap<Type, Set<QName>> serviceTypeToRpc = new ConcurrentHashMap<>();
-    private final HashMultimap<Type, SettableFuture<Type>> promisedTypes = HashMultimap.create();
-    private final ClassLoadingStrategy classLoadingStrategy;
 
-    // FIXME: how is this thread-safe?
-    private ClassPool pool;
+    /**
+     * This is map of types which users are waiting for.
+     */
+    @GuardedBy("this")
+    private final Multimap<Type, SettableFuture<Type>> promisedTypes = HashMultimap.create();
 
-    // FIXME: how is this thread-safe?
-    @Extension
-    private TransformerGenerator binding;
+    private final ClassLoadingStrategy classLoadingStrategy;
 
-    // FIXME: how is this thread-safe?
-    @Extension
-    private LazyGeneratedCodecRegistry registry;
+    private final AbstractTransformerGenerator binding;
+    private final LazyGeneratedCodecRegistry registry;
+    private final ClassPool pool;
 
-    // FIXME: how is this thread-safe?
-    private SchemaContext schemaContext;
+    /*
+     * FIXME: updated here, access from AbstractTransformer
+     */
+    private final Map<Type, AugmentationSchema> typeToAugmentation = new ConcurrentHashMap<>();
+    private final ConcurrentMap<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap<>();
+    private final ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap<>();
+    private final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
 
-    public RuntimeGeneratedMappingServiceImpl() {
-        this(GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy());
-    }
+    // FIXME: need to figure these out
+    private final ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap<>();
+    private SchemaContext schemaContext;
 
-    public RuntimeGeneratedMappingServiceImpl(final ClassLoadingStrategy strat) {
-        classLoadingStrategy = strat;
+    public RuntimeGeneratedMappingServiceImpl(final ClassPool pool) {
+        this(pool, GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy());
     }
 
-    public ClassPool getPool() {
-        return this.pool;
-    }
+    public RuntimeGeneratedMappingServiceImpl(final ClassPool pool, final ClassLoadingStrategy strat) {
+        this.pool = Preconditions.checkNotNull(pool);
+        this.classLoadingStrategy = Preconditions.checkNotNull(strat);
+        // FIXME: this escapes constructor
+        binding = new TransformerGenerator(this, pool);
+        registry = new LazyGeneratedCodecRegistry(this, binding, classLoadingStrategy);
+        binding.setListener(registry);
 
-    public void setPool(final ClassPool pool) {
-        this.pool = pool;
+        // if (ctx !== null) {
+        // listenerRegistration = ctx.registerService(SchemaContextListener,
+        // this, new Hashtable<String, String>());
+        // }
     }
 
     @Override
-    public SchemaContext getSchemaContext() {
+    public synchronized SchemaContext getSchemaContext() {
         return schemaContext;
     }
 
-    public void setSchemaContext(final SchemaContext schemaContext) {
-        this.schemaContext = schemaContext;
-    }
-
-    public TransformerGenerator getBinding() {
-        return this.binding;
-    }
-
-    public void setBinding(final TransformerGenerator binding) {
-        this.binding = binding;
-    }
-
-    public LazyGeneratedCodecRegistry getRegistry() {
-        return registry;
-    }
-
-    public void setRegistry(final LazyGeneratedCodecRegistry registry) {
-        this.registry = registry;
-    }
-
-    public ConcurrentMap<Type, GeneratedTypeBuilder> getTypeToDefinition() {
-        return typeToDefinition;
-    }
-
-    public ConcurrentMap<Type, Type> getTypeDefinitions() {
-        return typeDefinitions;
-    }
-
-    public ConcurrentMap<Type, SchemaNode> getTypeToSchemaNode() {
-        return typeToSchemaNode;
-    }
-
-    public ConcurrentMap<Type, Set<QName>> getServiceTypeToRpc() {
-        return serviceTypeToRpc;
-    }
-
     @Override
-    public void onGlobalContextUpdated(final SchemaContext arg0) {
-        this.setSchemaContext(arg0);
-        this.recreateBindingContext(arg0);
-        LazyGeneratedCodecRegistry _registry = this.getRegistry();
-        _registry.onGlobalContextUpdated(arg0);
+    public synchronized void onGlobalContextUpdated(final SchemaContext context) {
+        this.schemaContext = Preconditions.checkNotNull(context);
+        this.recreateBindingContext(context);
+        this.registry.onGlobalContextUpdated(context);
     }
 
+    @GuardedBy("this")
     private void recreateBindingContext(final SchemaContext schemaContext) {
-        BindingGeneratorImpl newBinding = new BindingGeneratorImpl();
+        BindingGeneratorImpl newBinding = new BindingGeneratorImpl(false);
         newBinding.generateTypes(schemaContext);
 
         for (Map.Entry<Module, ModuleContext> entry : newBinding.getModuleContexts().entrySet()) {
 
             registry.onModuleContextAdded(schemaContext, entry.getKey(), entry.getValue());
-            binding.getPathToType().putAll(entry.getValue().getChildNodes());
+            pathToType.putAll(entry.getValue().getChildNodes());
             Module module = entry.getKey();
             ModuleContext context = entry.getValue();
             updateBindingFor(context.getChildNodes(), schemaContext);
@@ -189,20 +165,20 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
             for (Map.Entry<SchemaPath, Type> typedef : typedefs.entrySet()) {
                 Type value = typedef.getValue();
                 Type typeRef = new ReferencedTypeImpl(value.getPackageName(), value.getName());
-                binding.getTypeDefinitions().put(typeRef, value);
+                typeDefinitions.put(typeRef, value);
                 TypeDefinition<?> schemaNode = YangSchemaUtils.findTypeDefinition(schemaContext, typedef.getKey());
                 if (schemaNode != null) {
 
-                    binding.getTypeToSchemaNode().put(typeRef, schemaNode);
+                    typeToSchemaNode.put(typeRef, schemaNode);
                 } else {
                     LOG.error("Type definition for {} is not available", value);
                 }
             }
             List<GeneratedTypeBuilder> augmentations = context.getAugmentations();
             for (GeneratedTypeBuilder augmentation : augmentations) {
-                binding.getTypeToDefinition().put(augmentation, augmentation);
+                typeToDefinition.put(augmentation, augmentation);
             }
-            binding.getTypeToAugmentation().putAll(context.getTypeToAugmentation());
+            typeToAugmentation.putAll(context.getTypeToAugmentation());
             for (GeneratedTypeBuilder augmentation : augmentations) {
                 updatePromisedSchemas(augmentation);
             }
@@ -215,17 +191,17 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
     }
 
     @Override
-    public Entry<InstanceIdentifier, CompositeNode> toDataDom(
+    public Entry<YangInstanceIdentifier, CompositeNode> toDataDom(
             final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> entry) {
         try {
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier key = toDataDom(entry.getKey());
+            org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier key = toDataDom(entry.getKey());
             CompositeNode data;
             if (Augmentation.class.isAssignableFrom(entry.getKey().getTargetType())) {
                 data = toCompositeNodeImplAugument(key, entry.getValue());
             } else {
                 data = toCompositeNodeImpl(key, entry.getValue());
             }
-            return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>(key,
+            return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, CompositeNode>(key,
                     data);
 
         } catch (Exception e) {
@@ -241,9 +217,9 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
         return codec.serialize(new ValueWithQName<DataObject>(null, object));
     }
 
-    private CompositeNode toCompositeNodeImpl(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,
+    private CompositeNode toCompositeNodeImpl(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier identifier,
             final DataObject object) {
-        PathArgument last = identifier.getPath().get(identifier.getPath().size() - 1);
+        PathArgument last = identifier.getLastPathArgument();
         Class<? extends DataContainer> cls = object.getImplementedInterface();
         waitForSchema(cls);
         DataContainerCodec<DataObject> codec = (DataContainerCodec<DataObject>) registry.getCodecForDataObject(cls);
@@ -251,12 +227,11 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
     }
 
     private CompositeNode toCompositeNodeImplAugument(
-            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier, final DataObject object) {
+            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier identifier, final DataObject object) {
 
         // val cls = object.implementedInterface;
         // waitForSchema(cls);
-        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument last = identifier.getPath().get(
-                identifier.getPath().size() - 1);
+        org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument last = identifier.getLastPathArgument();
         AugmentationCodec codec = registry.getCodecForAugmentation((Class) object.getImplementedInterface());
         CompositeNode ret = codec.serialize(new ValueWithQName<DataObject>(last.getNodeType(), object));
         if (last instanceof NodeIdentifierWithPredicates) {
@@ -265,34 +240,34 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
             for (Map.Entry<QName, Object> predicate : predicates.getKeyValues().entrySet()) {
                 newNodes.add(new SimpleNodeTOImpl<Object>(predicate.getKey(), null, predicate.getValue()));
             }
-            newNodes.addAll(ret.getChildren());
+            newNodes.addAll(ret.getValue());
             return new CompositeNodeTOImpl(last.getNodeType(), null, newNodes);
         }
         return ret;
     }
 
     @Override
-    public void waitForSchema(final Class class1) {
-        if (registry.isCodecAvailable(class1)) {
-            return;
-        }
-        Type ref = Types.typeForClass(class1);
-        try {
-            getSchemaWithRetry(ref);
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.warn("Waiting for schema for class {} failed", class1, e);
-            throw new IllegalStateException(String.format("Failed to get schema for {}", class1), e);
+    public void waitForSchema(final Class<?> cls) {
+        final ListenableFuture<Type> f = getSchemaDefinition(cls);
+        if (f != null) {
+            try {
+                f.get();
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.warn("Waiting for schema for class {} failed", cls, e);
+                throw new IllegalStateException(String.format("Failed to get schema for %s", cls), e);
+            }
+            LOG.info("Schema for {} became available, thread unblocked", cls);
         }
     }
 
     @Override
-    public InstanceIdentifier toDataDom(
+    public YangInstanceIdentifier toDataDom(
             final org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path) {
         for (final org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : path.getPathArguments()) {
             this.waitForSchema(arg.getType());
         }
 
-        final InstanceIdentifierCodec c = getRegistry().getInstanceIdentifierCodec();
+        final InstanceIdentifierCodec c = registry.getInstanceIdentifierCodec();
         Preconditions.checkState(c != null, "InstanceIdentifierCodec not present");
         return c.serialize(path);
     }
@@ -310,7 +285,7 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
             // FIXME: deprecate use without iid
             final org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> wildcardedPath = createWildcarded(path);
 
-            final DataContainerCodec<? extends DataContainer> transformer = getRegistry().getCodecForDataObject(container);
+            final DataContainerCodec<? extends DataContainer> transformer = registry.getCodecForDataObject(container);
             Preconditions.checkState(transformer != null, "Failed to find codec for type %s", container);
 
             final ValueWithQName<? extends DataContainer> deserialize = transformer.deserialize(domData, wildcardedPath);
@@ -326,9 +301,9 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
     }
 
     @Override
-    public org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends Object> fromDataDom(final InstanceIdentifier entry) throws DeserializationException {
+    public org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends Object> fromDataDom(final YangInstanceIdentifier entry) throws DeserializationException {
         try {
-            final InstanceIdentifierCodec c = getRegistry().getInstanceIdentifierCodec();
+            final InstanceIdentifierCodec c = registry.getInstanceIdentifierCodec();
             Preconditions.checkState(c != null, "InstanceIdentifierCodec not present");
             return c.deserialize(entry);
         } catch (Exception e) {
@@ -339,7 +314,7 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
 
     @Override
     public CodecRegistry getCodecRegistry() {
-        return this.getRegistry();
+        return this.registry;
     }
 
     private void updateBindingFor(final Map<SchemaPath, GeneratedTypeBuilder> map, final SchemaContext module) {
@@ -356,22 +331,6 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
         }
     }
 
-    public void init() {
-        binding = new TransformerGenerator(pool);
-        registry = new LazyGeneratedCodecRegistry(this, classLoadingStrategy);
-
-        registry.setGenerator(binding);
-        // binding.staticFieldsInitializer = registry
-        binding.setListener(registry);
-        binding.setTypeToDefinition(typeToDefinition);
-        binding.setTypeToSchemaNode(typeToSchemaNode);
-        binding.setTypeDefinitions(typeDefinitions);
-
-        // if (ctx !== null) {
-        // listenerRegistration = ctx.registerService(SchemaServiceListener,
-        // this, new Hashtable<String, String>());
-        // }
-    }
 
     @Override
     public Set<QName> getRpcQNamesFor(final Class<? extends RpcService> service) {
@@ -383,30 +342,31 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
         return serviceRef;
     }
 
-    private void getSchemaWithRetry(final Type type) throws InterruptedException, ExecutionException {
-        if (!typeToDefinition.containsKey(type)) {
-            LOG.info("Thread blocked waiting for schema for: {}", type.getFullyQualifiedName());
-            waitForTypeDefinition(type).get();
-            LOG.info("Schema for {} became available, thread unblocked", type.getFullyQualifiedName());
-        }
-    }
+    private ListenableFuture<Type> getSchemaDefinition(final Class<?> cls) {
+        final Type type = Types.typeForClass(cls);
+        synchronized (this) {
+            if (typeToDefinition.containsKey(type)) {
+                return null;
+            }
 
-    private Future<Type> waitForTypeDefinition(final Type type) {
-        final SettableFuture<Type> future = SettableFuture.<Type> create();
-        promisedTypes.put(type, future);
-        return future;
+            LOG.info("Thread is going to wait for schema for: {}", type.getFullyQualifiedName());
+            final SettableFuture<Type> f = SettableFuture.create();
+            promisedTypes.put(type, f);
+            return f;
+        }
     }
 
+    @GuardedBy("this")
     private void updatePromisedSchemas(final Type builder) {
-        Type ref = new ReferencedTypeImpl(builder.getPackageName(), builder.getName());
-        Set<SettableFuture<Type>> futures = promisedTypes.get(ref);
-        if (futures == null || futures.isEmpty()) {
-            return;
-        }
-        for (SettableFuture<Type> future : futures) {
-            future.set(builder);
+        final Type ref = new ReferencedTypeImpl(builder.getPackageName(), builder.getName());
+        final Collection<SettableFuture<Type>> futures = promisedTypes.get(ref);
+
+        if (futures != null) {
+            for (SettableFuture<Type> future : futures) {
+                future.set(builder);
+            }
+            promisedTypes.removeAll(builder);
         }
-        promisedTypes.removeAll(builder);
     }
 
     @Override
@@ -433,10 +393,10 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
     }
 
     @Override
-    public Optional<Class<? extends RpcService>> getRpcServiceClassFor(final String namespace, final String revision) {
+    public synchronized Optional<Class<? extends RpcService>> getRpcServiceClassFor(final String namespace, final String revision) {
         Module module = null;
         if (schemaContext != null) {
-            module = schemaContext.findModuleByName(namespace, QName.parseRevision(revision));
+            module = schemaContext.findModuleByNamespaceAndRevision(URI.create(namespace), QName.parseRevision(revision));
         }
         if (module == null) {
             return Optional.absent();
@@ -444,8 +404,7 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
         try {
             Optional<Type> rpcTypeName = getRpcServiceType(module);
             if (rpcTypeName.isPresent()) {
-                Class<?> rpcClass = binding.getClassLoadingStrategy().loadClass(
-                        rpcTypeName.get().getFullyQualifiedName());
+                Class<?> rpcClass = classLoadingStrategy.loadClass(rpcTypeName.get().getFullyQualifiedName());
                 return Optional.<Class<? extends RpcService>> of((Class<? extends RpcService>) rpcClass);
             }
         } catch (Exception e) {
@@ -476,4 +435,24 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
         }
         return org.opendaylight.yangtools.yang.binding.InstanceIdentifier.create(wildcardedArgs);
     }
+
+    @Override
+    public final AugmentationSchema getAugmentation(final Type type) {
+        return typeToAugmentation.get(type);
+    }
+
+    @Override
+    public final GeneratedTypeBuilder getDefinition(final Type type) {
+        return typeToDefinition.get(type);
+    }
+
+    @Override
+    public final SchemaNode getSchemaNode(final Type type) {
+        return typeToSchemaNode.get(type);
+    }
+
+    @Override
+    public final GeneratedTypeBuilder getTypeBuilder(final SchemaPath path) {
+        return pathToType.get(path);
+    }
 }