BUG-981: untangle interfaces 76/6876/7
authorRobert Varga <rovarga@cisco.com>
Sun, 11 May 2014 11:05:34 +0000 (13:05 +0200)
committerRobert Varga <rovarga@cisco.com>
Sun, 11 May 2014 20:33:13 +0000 (22:33 +0200)
This patch untangles the interactions between the three classes that
constitute the binding generator implementation. This provides a
baseline for analyzing thread safety and ensuring its proper function.

TypeResolver is a new interface, which encapsulates the lookup services
provided by RuntimeGeneratedMappingServiceImpl to TransformerGenerator.

AbstractTransformerGenerator is a new abstract class, which defines the
interface of TransformerGenerator to the rest of the package, such that
Java classes do not have direct dependency on xtend code. Furthermore it
acts defines the interface which the xtend code expects of the Java
runtime.

Change-Id: I0a4fdc23aa25c69e45a3cea63aab0168ee2fe3ce
Signed-off-by: Robert Varga <rovarga@cisco.com>
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratorListener.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TransformerGenerator.xtend
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TypeResolver.java [new file with mode: 0644]

diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java
new file mode 100644 (file)
index 0000000..eb04795
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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.sal.binding.generator.impl;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+
+import javassist.ClassPool;
+
+import org.eclipse.xtext.xbase.lib.Extension;
+import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Abstract base class which defines the baseline for the real {@link TransformerGenerator}.
+ * This class exists to expose the basic interface and common interactions with the rest
+ * of the package.
+ */
+abstract class AbstractTransformerGenerator {
+    private static final Map<SchemaPath, InstanceIdentifier<?>> PATH_TO_BINDING_IDENTIFIER = new ConcurrentHashMap<>();
+
+    /*
+     * The generator has to always use this strategy, otherwise we may end up
+     * will VerificationErrors.
+     */
+    @Extension
+    protected static final ClassLoadingStrategy CLASS_LOADING_STRATEGY =
+            GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+    @Extension
+    protected final TypeResolver typeResolver;
+    @Extension
+    protected final JavassistUtils javAssist;
+
+    /*
+     * This is effectively final, but we have an implementation circle, where this
+     * class notifies LazyGeneratedCodecRegistry and it calls our methods. The
+     * listener is initialized to non-null before it is exposed.
+     */
+    private GeneratorListener listener;
+
+    protected AbstractTransformerGenerator(final TypeResolver typeResolver, final ClassPool pool) {
+        this.typeResolver = Preconditions.checkNotNull(typeResolver);
+        this.javAssist = JavassistUtils.forClassPool(pool);
+    }
+
+    protected final GeneratorListener getListener() {
+        if (listener == null) {
+            synchronized (this) {
+                Preconditions.checkState(listener != null, "Implementation not fully initialized");
+            }
+        }
+
+        return listener;
+    }
+
+    synchronized final void setListener(final GeneratorListener listener) {
+        Preconditions.checkState(this.listener == null, "Implementation already initialized");
+        this.listener = Preconditions.checkNotNull(listener);
+    }
+
+    protected final <V> V runOnClassLoader(final ClassLoader cls, final Callable<V> function) throws Exception {
+        final Lock lock = javAssist.getLock();
+
+        lock.lock();
+        try {
+            javAssist.appendClassLoaderIfMissing(cls);
+            return ClassLoaderUtils.withClassLoader(cls, function);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    private static final Map<SchemaPath, InstanceIdentifier<?>> pathToBindingIdentifier = new ConcurrentHashMap<>();
+
+    protected final InstanceIdentifier<?> getBindingIdentifierByPath(final SchemaPath path) {
+        return pathToBindingIdentifier.get(path);
+    }
+
+    protected final void putPathToBindingIdentifier(final SchemaPath path, final InstanceIdentifier<?> bindingIdentifier) {
+        pathToBindingIdentifier.put(path, bindingIdentifier);
+    }
+
+    protected final InstanceIdentifier<?> putPathToBindingIdentifier(final SchemaPath path,
+            final InstanceIdentifier<?> bindingIdentifier, final Class<?> childClass) {
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        InstanceIdentifier<?> newId = bindingIdentifier.builder().child((Class) childClass).build();
+        pathToBindingIdentifier.put(path, newId);
+        return newId;
+    }
+
+    // Called from LazyGeneratedCodecRegistry
+    abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentationTransformerFor(Class<?> inputType);
+    abstract Class<? extends BindingCodec<Object, Object>> caseCodecFor(Class<?> inputType, ChoiceCaseNode node);
+    abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifiable(Class<?> parentType);
+    abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifier(Class<?> inputType);
+    abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType);
+}
index 5ba85e988893743b544d047e63053c3cdacc28e6..a67550954583d7b4062297874df5fb5103fc5b02 100644 (file)
@@ -14,9 +14,6 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 
 public interface GeneratorListener {
-
-
-
     void onClassProcessed(Class<?> cl);
 
     void onCodecCreated(Class<?> codec);
index 1a73c6243669b0caa367e24e3ddf7513e1c93754..edc186e0ebe0dbe5aabd5305502508f0a2abae6d 100644 (file)
@@ -81,7 +81,7 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multimaps;
 
-public class LazyGeneratedCodecRegistry implements //
+class LazyGeneratedCodecRegistry implements //
         CodecRegistry, //
         SchemaContextListener, //
         GeneratorListener {
@@ -89,11 +89,6 @@ public class LazyGeneratedCodecRegistry implements //
     private static final Logger LOG = LoggerFactory.getLogger(LazyGeneratedCodecRegistry.class);
     private static final LateMixinCodec NOT_READY_CODEC = new LateMixinCodec();
 
-    private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
-    private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec();
-
-    private TransformerGenerator generator;
-
     // Concrete class to codecs
     private static final Map<Class<?>, DataContainerCodec<?>> containerCodecs = Collections
             .synchronizedMap(new WeakHashMap<Class<?>, DataContainerCodec<?>>());
@@ -117,9 +112,6 @@ public class LazyGeneratedCodecRegistry implements //
     @SuppressWarnings("rawtypes")
     private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
 
-    private final CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
-
-    private static final Map<SchemaPath, InstanceIdentifier<?>> pathToBindingIdentifier = new ConcurrentHashMap<>();
     private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
     private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
     private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
@@ -131,30 +123,27 @@ public class LazyGeneratedCodecRegistry implements //
     private static final Multimap<Type, Type> choiceToCases = Multimaps.synchronizedMultimap(HashMultimap
             .<Type, Type> create());
 
+    private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
+    private final CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
+    private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec();
+    private final ClassLoadingStrategy classLoadingStrategy;
+    private final AbstractTransformerGenerator generator;
     private final SchemaLock lock;
 
     // FIXME: how is this protected?
     private SchemaContext currentSchema;
 
-    private final ClassLoadingStrategy classLoadingStrategy;
-
-    LazyGeneratedCodecRegistry(final SchemaLock lock, final ClassLoadingStrategy identityClassLoadingStrategy) {
+    LazyGeneratedCodecRegistry(final SchemaLock lock, final AbstractTransformerGenerator generator,
+            final ClassLoadingStrategy classLoadingStrategy) {
         this.lock = Preconditions.checkNotNull(lock);
-        this.classLoadingStrategy = identityClassLoadingStrategy;
+        this.classLoadingStrategy = Preconditions.checkNotNull(classLoadingStrategy);
+        this.generator = Preconditions.checkNotNull(generator);
     }
 
     public SchemaLock getLock() {
         return lock;
     }
 
-    public TransformerGenerator getGenerator() {
-        return generator;
-    }
-
-    public void setGenerator(final TransformerGenerator generator) {
-        this.generator = generator;
-    }
-
     @Override
     public InstanceIdentifierCodec getInstanceIdentifierCodec() {
         return instanceIdentifierCodec;
@@ -241,22 +230,6 @@ public class LazyGeneratedCodecRegistry implements //
         bindingClassEncountered(cls);
     }
 
-    public InstanceIdentifier<?> getBindingIdentifierByPath(final SchemaPath path) {
-        return pathToBindingIdentifier.get(path);
-    }
-
-    public void putPathToBindingIdentifier(final SchemaPath path, final InstanceIdentifier<?> bindingIdentifier) {
-        pathToBindingIdentifier.put(path, bindingIdentifier);
-    }
-
-    public InstanceIdentifier<?> putPathToBindingIdentifier(final SchemaPath path,
-            final InstanceIdentifier<?> bindingIdentifier, final Class<?> childClass) {
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        InstanceIdentifier<?> newId = bindingIdentifier.builder().child((Class) childClass).build();
-        pathToBindingIdentifier.put(path, newId);
-        return newId;
-    }
-
     @Override
     public IdentifierCodec<?> getKeyCodecForPath(final List<QName> names) {
         @SuppressWarnings("unchecked")
@@ -429,7 +402,6 @@ public class LazyGeneratedCodecRegistry implements //
                 caseClass.getName());
         Preconditions.checkState(caseCodec.getSchema() != null, "Case schema is not available for %s",
                 caseClass.getName());
-        @SuppressWarnings("unchecked")
         Class<? extends BindingCodec> newCodec = generator.caseCodecFor(caseClass, caseCodec.getSchema());
         BindingCodec newInstance = newInstanceOf(newCodec);
         caseCodec.setDelegate(newInstance);
index 80dec5a29ed465e0cc2ea4ab107cc36b5a107fd7..8ac4a9441a9fbb43f0171b7deb6917ea1a0c34ac 100644 (file)
@@ -54,6 +54,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;
@@ -73,13 +74,10 @@ import com.google.common.collect.Multimap;
 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<>();
 
     /**
@@ -92,9 +90,19 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
 
     // FIXME: will become final
     private ClassPool pool;
-    private TransformerGenerator binding;
+    private AbstractTransformerGenerator binding;
     private LazyGeneratedCodecRegistry registry;
 
+    /*
+     * 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<>();
+
+    // FIXME: need to figure these out
+    private final ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap<>();
     private SchemaContext schemaContext;
 
     @Deprecated
@@ -120,15 +128,9 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
     }
 
     private void doInit() {
-        binding = new TransformerGenerator(pool);
-        registry = new LazyGeneratedCodecRegistry(this, classLoadingStrategy);
-
-        registry.setGenerator(binding);
-        // binding.staticFieldsInitializer = registry
+        binding = new TransformerGenerator(this, pool);
+        registry = new LazyGeneratedCodecRegistry(this, binding, classLoadingStrategy);
         binding.setListener(registry);
-        binding.setTypeToDefinition(typeToDefinition);
-        binding.setTypeToSchemaNode(typeToSchemaNode);
-        binding.setTypeDefinitions(typeDefinitions);
 
         // if (ctx !== null) {
         // listenerRegistration = ctx.registerService(SchemaServiceListener,
@@ -161,7 +163,7 @@ public class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMap
         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);
@@ -182,20 +184,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);
             }
@@ -428,8 +430,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) {
@@ -460,4 +461,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);
+    }
 }
index a7c3772302fe2a8183bcb090bc02d520224bfcfe..f27e16a05a4072fb3b174f831852249d56d354f2 100644 (file)
@@ -7,89 +7,83 @@
  */
 package org.opendaylight.yangtools.sal.binding.generator.impl
 
+import com.google.common.base.Joiner
+import java.io.File
+import java.security.ProtectionDomain
+import java.util.AbstractMap.SimpleEntry
+import java.util.Collection
+import java.util.Collections
+import java.util.HashMap
+import java.util.HashSet
+import java.util.Iterator
+import java.util.List
+import java.util.Map
+import java.util.Map.Entry
+import java.util.Set
+import java.util.TreeSet
+import javassist.CannotCompileException
 import javassist.ClassPool
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
-import org.opendaylight.yangtools.yang.model.api.SchemaNode
-import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils
 import javassist.CtClass
-import java.util.Map
-import org.opendaylight.yangtools.yang.common.QName
 import javassist.CtField
-import static javassist.Modifier.*
-import static org.opendaylight.yangtools.sal.binding.generator.impl.CodecMapping.*
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
-import org.opendaylight.yangtools.sal.binding.model.api.Type
-import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
-import org.opendaylight.yangtools.binding.generator.util.Types
-import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType
-import java.util.HashMap
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+import javassist.CtMethod
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
-import java.util.List
-import java.util.TreeSet
-import com.google.common.base.Joiner
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
-import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
-import static org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils.*;
-import org.opendaylight.yangtools.yang.binding.BindingDeserializer
-import org.opendaylight.yangtools.yang.binding.BindingCodec
-import org.slf4j.LoggerFactory
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
+import org.opendaylight.yangtools.binding.generator.util.Types
+import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils
 import org.opendaylight.yangtools.sal.binding.generator.util.CodeGenerationException
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode
-import java.security.ProtectionDomain
-import java.io.File
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.yangtools.sal.binding.generator.util.XtendHelper
+import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
-import java.util.Map.Entry
-import java.util.AbstractMap.SimpleEntry
-import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
+import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType
+import org.opendaylight.yangtools.sal.binding.model.api.Type
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
 import org.opendaylight.yangtools.yang.binding.Augmentation
-import java.util.Iterator
+import org.opendaylight.yangtools.yang.binding.BindingCodec
+import org.opendaylight.yangtools.yang.binding.BindingDeserializer
+import org.opendaylight.yangtools.yang.binding.BindingMapping
+import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.yangtools.yang.common.QName
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
-import java.util.concurrent.ConcurrentHashMap
-import static extension org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils.*;
-import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
-import org.opendaylight.yangtools.yang.model.util.ExtendedType
-import org.opendaylight.yangtools.yang.model.util.EnumerationType
-import static com.google.common.base.Preconditions.*
-import org.opendaylight.yangtools.yang.model.api.SchemaPath
-import javassist.CtMethod
-import javassist.CannotCompileException
-import java.util.concurrent.locks.Lock
-import java.util.concurrent.Callable
-import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
+import org.opendaylight.yangtools.yang.model.api.SchemaNode
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
-import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
-import java.util.HashSet
-import java.util.Collections
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit
-import java.util.Set
-import org.opendaylight.yangtools.sal.binding.generator.util.XtendHelper
-import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
-import org.opendaylight.yangtools.yang.binding.BindingMapping
 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition
-import java.util.Collection
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition
+import org.opendaylight.yangtools.yang.model.util.EnumerationType
+import org.opendaylight.yangtools.yang.model.util.ExtendedType
+import org.slf4j.LoggerFactory
 
-class TransformerGenerator {
+import static com.google.common.base.Preconditions.*
+import static javassist.Modifier.*
+import static org.opendaylight.yangtools.sal.binding.generator.impl.CodecMapping.*
+
+import static extension org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils.*
+
+class TransformerGenerator extends AbstractTransformerGenerator {
 
     private static val log = LoggerFactory.getLogger(TransformerGenerator)
 
     public static val STRING = Types.typeForClass(String);
     public static val BOOLEAN = Types.typeForClass(Boolean);
     public static val INTEGER = Types.typeForClass(Integer);
-    public static val INSTANCE_IDENTIFIER = Types.typeForClass(InstanceIdentifier)
+    public static val INSTANCE_IDENTIFIER = Types.typeForClass(InstanceIdentifier);
 
     //public static val DECIMAL = Types.typeForClass(Decimal);
     public static val LONG = Types.typeForClass(Long);
 
-    val extension JavassistUtils utils;
-
     CtClass BINDING_CODEC
 
     CtClass ctQName
@@ -97,49 +91,26 @@ class TransformerGenerator {
     @Property
     var File classFileCapturePath;
 
-    @Property
-    var Map<Type, Type> typeDefinitions = new ConcurrentHashMap();
-
-    @Property
-    var Map<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
-
-    @Property
-    var Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap();
-
-    @Property
-    var Map<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
-
-    @Property
-    var Map<Type, AugmentationSchema> typeToAugmentation = new ConcurrentHashMap();
-
-    @Property
-    var LazyGeneratedCodecRegistry listener;
-
-    @Property
-    var extension GeneratedClassLoadingStrategy classLoadingStrategy
-
     public static val CLASS_TYPE = Types.typeForClass(Class);
 
-    public new(ClassPool pool) {
-        utils = JavassistUtils.forClassPool(pool)
+    public new(TypeResolver typeResolver, ClassPool pool) {
+        super(typeResolver, pool)
 
         BINDING_CODEC = BindingCodec.asCtClass;
         ctQName = QName.asCtClass
-
-        this.classLoadingStrategy = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
     }
 
-    def Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType) {
-        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+    override Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class inputType) {
+        return runOnClassLoader(inputType.classLoader) [ |
             val ret = getGeneratedClass(inputType)
             if (ret !== null) {
                 listener.onClassProcessed(inputType);
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
             val ref = Types.typeForClass(inputType)
-            val node = typeToSchemaNode.get(ref)
+            val node = getSchemaNode(ref)
             createMapping(inputType, node, null)
-            val typeSpecBuilder = typeToDefinition.get(ref)
+            val typeSpecBuilder = getDefinition(ref)
             checkState(typeSpecBuilder !== null, "Could not find typedefinition for %s", inputType.name);
             val typeSpec = typeSpecBuilder.toInstance();
             val newret = generateTransformerFor(inputType, typeSpec, node);
@@ -149,7 +120,7 @@ class TransformerGenerator {
     }
 
     def Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType, DataSchemaNode node) {
-        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+        return runOnClassLoader(inputType.classLoader) [ |
             createMapping(inputType, node, null)
             val ret = getGeneratedClass(inputType)
             if (ret !== null) {
@@ -157,9 +128,9 @@ class TransformerGenerator {
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
             val ref = Types.typeForClass(inputType)
-            var typeSpecBuilder = typeToDefinition.get(ref)
+            var typeSpecBuilder = getDefinition(ref)
             if (typeSpecBuilder == null) {
-                typeSpecBuilder = pathToType.get(node.path);
+                typeSpecBuilder = getTypeBuilder(node.path);
             }
 
             checkState(typeSpecBuilder !== null, "Could not find TypeDefinition for %s, $s", inputType.name, node);
@@ -170,16 +141,16 @@ class TransformerGenerator {
         ]
     }
 
-    def Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentationTransformerFor(Class<?> inputType) {
-        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+    override Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentationTransformerFor(Class inputType) {
+        return runOnClassLoader(inputType.classLoader) [ |
 
             val ret = getGeneratedClass(inputType)
             if (ret !== null) {
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
             val ref = Types.typeForClass(inputType)
-            val node = typeToAugmentation.get(ref)
-            val typeSpecBuilder = typeToDefinition.get(ref)
+            val node = getAugmentation(ref)
+            val typeSpecBuilder = getDefinition(ref)
             val typeSpec = typeSpecBuilder.toInstance();
             //mappingForNodes(node.childNodes, typeSpec.allProperties, bindingId)
             val newret = generateAugmentationTransformerFor(inputType, typeSpec, node);
@@ -188,23 +159,23 @@ class TransformerGenerator {
         ]
     }
 
-    def Class<? extends BindingCodec<Object, Object>> caseCodecFor(Class<?> inputType, ChoiceCaseNode node) {
-        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+    override Class<? extends BindingCodec<Object, Object>> caseCodecFor(Class inputType, ChoiceCaseNode node) {
+        return runOnClassLoader(inputType.classLoader) [ |
             createMapping(inputType, node, null)
             val ret = getGeneratedClass(inputType)
             if (ret !== null) {
                 return ret as Class<? extends BindingCodec<Object, Object>>;
             }
             val ref = Types.typeForClass(inputType)
-            val typeSpecBuilder = typeToDefinition.get(ref)
+            val typeSpecBuilder = getDefinition(ref)
             val typeSpec = typeSpecBuilder.toInstance();
             val newret = generateCaseCodec(inputType, typeSpec, node);
             return newret as Class<? extends BindingCodec<Object, Object>>;
         ]
     }
 
-    def Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifiable(Class<?> parentType) {
-        return withClassLoaderAndLock(parentType.classLoader, lock) [ |
+    override Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifiable(Class parentType) {
+        return runOnClassLoader(parentType.classLoader) [ |
             val inputName = parentType.name + "Key";
             val inputType = loadClass(inputName);
             val ret = getGeneratedClass(inputType)
@@ -212,8 +183,8 @@ class TransformerGenerator {
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
             val ref = Types.typeForClass(parentType)
-            val node = typeToSchemaNode.get(ref) as ListSchemaNode
-            val typeSpecBuilder = typeToDefinition.get(ref)
+            val node = getSchemaNode(ref) as ListSchemaNode
+            val typeSpecBuilder = getDefinition(ref)
             val typeSpec = typeSpecBuilder.identifierDefinition;
             val newret = generateKeyTransformerFor(inputType, typeSpec, node);
             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
@@ -225,29 +196,29 @@ class TransformerGenerator {
         if (cl === null) {
             cl = Thread.currentThread.contextClassLoader
         }
-        withClassLoader(cl,
+        ClassLoaderUtils.withClassLoader(cl,
             [ |
                 if (!(node instanceof DataNodeContainer)) {
                     return null
                 }
-                var InstanceIdentifier<?> bindingId = listener.getBindingIdentifierByPath(node.path)
+                var InstanceIdentifier<?> bindingId = getBindingIdentifierByPath(node.path)
                 if (bindingId != null) {
                     return null
                 }
                 val ref = Types.typeForClass(inputType)
-                var typeSpecBuilder = typeToDefinition.get(ref)
+                var typeSpecBuilder = getDefinition(ref)
                 if (typeSpecBuilder == null) {
-                    typeSpecBuilder = pathToType.get(node.path);
+                    typeSpecBuilder = getTypeBuilder(node.path);
                 }
-                checkState(typeSpecBuilder !== null, "Could not find typedefinition for %s, $s", inputType.name, node);
+                checkState(typeSpecBuilder !== null, "Could not find type definition for %s, $s", inputType.name, node);
                 val typeSpec = typeSpecBuilder.toInstance();
                 var InstanceIdentifier<?> parent
                 if (parentId == null) {
                     bindingId = InstanceIdentifier.create(inputType as Class)
                     parent = bindingId
-                    listener.putPathToBindingIdentifier(node.path, bindingId)
+                    putPathToBindingIdentifier(node.path, bindingId)
                 } else {
-                    parent = listener.putPathToBindingIdentifier(node.path, parentId, inputType)
+                    parent = putPathToBindingIdentifier(node.path, parentId, inputType)
                 }
                 val Map<String, Type> properties = typeSpec.allProperties
                 if (node instanceof DataNodeContainer) {
@@ -282,15 +253,15 @@ class TransformerGenerator {
         return keyMethod.returnType as GeneratedTransferObject
     }
 
-    def Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifier(Class<?> inputType) {
-        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+    override Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifier(Class inputType) {
+        return runOnClassLoader(inputType.classLoader) [ |
             val ret = getGeneratedClass(inputType)
             if (ret !== null) {
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
             val ref = Types.typeForClass(inputType)
-            val node = typeToSchemaNode.get(ref) as ListSchemaNode
-            val typeSpecBuilder = typeToDefinition.get(ref)
+            val node = getSchemaNode(ref) as ListSchemaNode
+            val typeSpecBuilder = getDefinition(ref)
             val typeSpec = typeSpecBuilder.toInstance();
             val newret = generateKeyTransformerFor(inputType, typeSpec, node);
             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
@@ -298,7 +269,7 @@ class TransformerGenerator {
     }
 
     private def Class<?> keyTransformerFor(Class<?> inputType, GeneratedType type, ListSchemaNode schema) {
-        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+        return runOnClassLoader(inputType.classLoader) [ |
             val transformer = getGeneratedClass(inputType)
             if (transformer != null) {
                 return transformer;
@@ -338,7 +309,7 @@ class TransformerGenerator {
             baseType = baseType.baseType;
         }
         val finalType = baseType;
-        return withClassLoaderAndLock(cls.classLoader, lock) [ |
+        return runOnClassLoader(cls.classLoader) [ |
             val valueTransformer = generateValueTransformer(cls, type, finalType);
             return valueTransformer;
         ]
@@ -351,7 +322,7 @@ class TransformerGenerator {
             return transformer;
         }
 
-        return withClassLoaderAndLock(cls.classLoader, lock) [ |
+        return runOnClassLoader(cls.classLoader) [ |
             val valueTransformer = generateValueTransformer(cls, type);
             return valueTransformer;
         ]
@@ -480,7 +451,7 @@ class TransformerGenerator {
                 ]
                 method(Object, "fromDomStatic", #[QName, Object, InstanceIdentifier]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = deserializeBody(type, node, listener.getBindingIdentifierByPath(node.path))
+                    bodyChecked = deserializeBody(type, node, getBindingIdentifierByPath(node.path))
                 ]
                 method(Object, "deserialize", #[Object, InstanceIdentifier]) [
                     bodyChecked = '''
@@ -535,7 +506,7 @@ class TransformerGenerator {
 
                 method(Object, "fromDomStatic", #[QName, Object, InstanceIdentifier]) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    bodyChecked = deserializeBody(typeSpec, node, listener.getBindingIdentifierByPath(node.path))
+                    bodyChecked = deserializeBody(typeSpec, node, getBindingIdentifierByPath(node.path))
                 ]
 
                 method(Object, "deserialize", #[Object, InstanceIdentifier]) [
@@ -1244,7 +1215,7 @@ class TransformerGenerator {
     private def Class<?> generateValueTransformer(Class<?> inputType, Enumeration typeSpec) {
         try {
             val typeRef = new ReferencedTypeImpl(typeSpec.packageName, typeSpec.name);
-            val schema = typeToSchemaNode.get(typeRef) as ExtendedType;
+            val schema = getSchemaNode(typeRef) as ExtendedType;
             val enumSchema = schema.baseType as EnumerationType;
 
             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
@@ -1645,10 +1616,6 @@ class TransformerGenerator {
         }
     }
 
-    private def <V> V withClassLoaderAndLock(ClassLoader cls, Lock lock, Callable<V> function) throws Exception {
-        appendClassLoaderIfMissing(cls);
-        ClassLoaderUtils.withClassLoaderAndLock(cls, lock, function);
-    }
 
 }
 
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TypeResolver.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TypeResolver.java
new file mode 100644 (file)
index 0000000..ba9aa1b
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.sal.binding.generator.impl;
+
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * Internal interface exposed to TransformerGenerator
+ */
+interface TypeResolver {
+    AugmentationSchema getAugmentation(Type type);
+    GeneratedTypeBuilder getDefinition(Type type);
+    SchemaNode getSchemaNode(Type type);
+    GeneratedTypeBuilder getTypeBuilder(SchemaPath path);
+}