*/
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.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+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.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
import org.opendaylight.yangtools.binding.generator.util.Types;
import org.opendaylight.yangtools.concepts.Delegator;
import org.opendaylight.yangtools.concepts.Identifiable;
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.CodeGenerationException;
import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
-import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
import org.opendaylight.yangtools.yang.binding.Augmentable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.Node;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Field;
-import java.lang.reflect.ParameterizedType;
-import java.util.ArrayList;
-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.Objects;
-import java.util.Set;
-import java.util.WeakHashMap;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-public class LazyGeneratedCodecRegistry implements //
- CodecRegistry, //
- SchemaContextListener, //
- GeneratorListener {
-
- private final static Logger LOG = LoggerFactory.getLogger(LazyGeneratedCodecRegistry.class);
- private final static LateMixinCodec NOT_READY_CODEC = new LateMixinCodec();
-
- private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
- private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec();
+class LazyGeneratedCodecRegistry implements CodecRegistry, SchemaContextListener, GeneratorListener {
- private TransformerGenerator generator;
+ private static final Logger LOG = LoggerFactory.getLogger(LazyGeneratedCodecRegistry.class);
// Concrete class to codecs
private static final Map<Class<?>, DataContainerCodec<?>> containerCodecs = Collections
.synchronizedMap(new WeakHashMap<Class<?>, DataContainerCodec<?>>());
private static final Map<Class<?>, IdentifierCodec<?>> identifierCodecs = Collections
.synchronizedMap(new WeakHashMap<Class<?>, IdentifierCodec<?>>());
- private static final Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = Collections
- .synchronizedMap(new WeakHashMap<Class<?>, ChoiceCodecImpl<?>>());
+ private static final Map<Class<?>, PublicChoiceCodecImpl<?>> choiceCodecs = Collections
+ .synchronizedMap(new WeakHashMap<Class<?>, PublicChoiceCodecImpl<?>>());
private static final Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = Collections
.synchronizedMap(new WeakHashMap<Class<?>, ChoiceCaseCodecImpl<?>>());
- private static final Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = Collections
- .synchronizedMap(new WeakHashMap<Class<?>, AugmentableCompositeCodec>());
- private static final Map<Class<?>, AugmentationCodec<?>> augmentationCodecs = Collections
- .synchronizedMap(new WeakHashMap<Class<?>, AugmentationCodec<?>>());
+ private static final Map<Class<?>, AugmentableDispatchCodec> augmentableCodecs = Collections
+ .synchronizedMap(new WeakHashMap<Class<?>, AugmentableDispatchCodec>());
+ private static final Map<Class<?>, AugmentationCodecWrapper<?>> augmentationCodecs = Collections
+ .synchronizedMap(new WeakHashMap<Class<?>, AugmentationCodecWrapper<?>>());
+
+ private static final Map<Class<?>, LocationAwareDispatchCodec<?>> dispatchCodecs = Collections
+ .synchronizedMap(new WeakHashMap<Class<?>, LocationAwareDispatchCodec<?>>());
+
private static final Map<Class<?>, QName> identityQNames = Collections
.synchronizedMap(new WeakHashMap<Class<?>, QName>());
private static final Map<QName, Type> qnamesToIdentityMap = new ConcurrentHashMap<>();
- /** Binding type to encountered classes mapping **/
- @SuppressWarnings("rawtypes")
- private static final Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
-
- @SuppressWarnings("rawtypes")
- private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
- private final CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
+ private static final ConcurrentMap<Type, ChoiceCaseNode> caseTypeToCaseSchema = new ConcurrentHashMap<>();
- private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+ private static final Map<SchemaPath, Type> pathToType = new ConcurrentHashMap<>();
private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
- private static final Map<AugmentationSchema, Type> augmentToType = new ConcurrentHashMap<>();
+ private static final BiMap<Type, AugmentationSchema> typeToAugment = HashBiMap
+ .create(new ConcurrentHashMap<Type, AugmentationSchema>());
+
+ private static final Multimap<Type, Type> augmentableToAugmentations = Multimaps.synchronizedMultimap(HashMultimap
+ .<Type, Type> create());
+ private static final Multimap<Type, Type> choiceToCases = Multimaps.synchronizedMultimap(HashMultimap
+ .<Type, Type> create());
+ private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
+ 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(SchemaLock lock, 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(TransformerGenerator generator) {
- this.generator = generator;
- }
-
@Override
public InstanceIdentifierCodec getInstanceIdentifierCodec() {
return instanceIdentifierCodec;
}
+ @SuppressWarnings("unchecked")
@Override
- public <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object) {
- AugmentationCodec<T> codec = null;
+ public <T extends Augmentation<?>> AugmentationCodecWrapper<T> getCodecForAugmentation(final Class<T> augClass) {
+ AugmentationCodecWrapper<T> codec = null;
@SuppressWarnings("rawtypes")
- AugmentationCodec potentialCodec = augmentationCodecs.get(object);
+ AugmentationCodecWrapper potentialCodec = augmentationCodecs.get(augClass);
if (potentialCodec != null) {
codec = potentialCodec;
- } else
- try {
- lock.waitForSchema(object);
- Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentRawCodec = generator
- .augmentationTransformerFor(object);
- BindingCodec<Map<QName, Object>, Object> rawCodec = augmentRawCodec.newInstance();
- codec = new AugmentationCodecWrapper<T>(rawCodec);
- augmentationCodecs.put(object, codec);
- } catch (InstantiationException e) {
- LOG.error("Can not instantiate raw augmentation codec {}", object.getSimpleName(), e);
- } catch (IllegalAccessException e) {
- LOG.debug(
- "Run-time consistency issue: constructor {} is not available. This indicates either a code generation bug or a misconfiguration of JVM.",
- object.getSimpleName(), e);
- }
- Class<? extends Augmentable<?>> objectSupertype = getAugmentableArgumentFrom(object);
- if (objectSupertype != null) {
- getAugmentableCodec(objectSupertype).addAugmentationCodec(object, codec);
} else {
- LOG.warn("Could not find augmentation target for augmentation {}", object);
+ lock.waitForSchema(augClass);
+ Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentRawCodec = generator
+ .augmentationTransformerFor(augClass);
+
+ BindingCodec<Map<QName, Object>, Object> rawCodec = newInstanceOf(augmentRawCodec);
+ codec = new AugmentationCodecWrapper<T>(rawCodec, augClass);
+ augmentationCodecs.put(augClass, codec);
+ }
+
+ final Class<? extends Augmentable<?>> objectSupertype;
+ try {
+ objectSupertype = BindingReflections.findAugmentationTarget(augClass);
+ } catch (Exception e) {
+ LOG.warn("Failed to find target for augmentation {}, ignoring it", augClass, e);
+ return codec;
}
+
+ if (objectSupertype == null) {
+ LOG.warn("Augmentation target for {} not found, ignoring it", augClass);
+ return codec;
+ }
+
+ getAugmentableCodec(objectSupertype).addImplementation(codec);
return codec;
}
+ @SuppressWarnings("unchecked")
@Override
- public QName getQNameForAugmentation(Class<?> cls) {
+ public QName getQNameForAugmentation(final Class<?> cls) {
Preconditions.checkArgument(Augmentation.class.isAssignableFrom(cls));
- return getCodecForAugmentation((Class<? extends Augmentation>) cls).getAugmentationQName();
- }
-
- private static Class<? extends Augmentable<?>> getAugmentableArgumentFrom(
- final Class<? extends Augmentation<?>> augmentation) {
- try {
- Class<? extends Augmentable<?>> ret = ClassLoaderUtils.withClassLoader(augmentation.getClassLoader(),
- new Callable<Class<? extends Augmentable<?>>>() {
- @Override
- @SuppressWarnings("unchecked")
- public Class<? extends Augmentable<?>> call() throws Exception {
- for (java.lang.reflect.Type supertype : augmentation.getGenericInterfaces()) {
- if (supertype instanceof ParameterizedType
- && Augmentation.class.equals(((ParameterizedType) supertype).getRawType())) {
- ParameterizedType augmentationGeneric = (ParameterizedType) supertype;
- return (Class<? extends Augmentable<?>>) augmentationGeneric
- .getActualTypeArguments()[0];
- }
- }
- return null;
- }
- });
- return ret;
- } catch (Exception e) {
- LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e);
- return null;
- }
+ return getCodecForAugmentation((Class<? extends Augmentation<?>>) cls).getAugmentationQName();
}
@Override
- public Class<?> getClassForPath(List<QName> names) {
+ public Class<?> getClassForPath(final List<QName> names) {
DataSchemaNode node = getSchemaNode(names);
- SchemaPath path = node.getPath();
- Type type = pathToType.get(path);
- if (type != null) {
- type = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+ Preconditions.checkArgument(node != null, "Path %s points to invalid schema location", names);
+ SchemaNode originalDefinition = SchemaNodeUtils.getRootOriginalIfPossible(node);
+ if (originalDefinition instanceof DataSchemaNode) {
+ node = (DataSchemaNode) originalDefinition;
+ }
+ final SchemaPath path = node.getPath();
+ final Type t = pathToType.get(path);
+
+ final Type type;
+ if (t != null) {
+ type = new ReferencedTypeImpl(t.getPackageName(), t.getName());
} else {
type = pathToInstantiatedType.get(names);
+ Preconditions.checkState(type != null, "Failed to lookup instantiated type for path %s", path);
}
- @SuppressWarnings("rawtypes")
- WeakReference<Class> weakRef = typeToClass.get(type);
- if (weakRef == null) {
- LOG.error("Could not find loaded class for path: {} and type: {}", path, type.getFullyQualifiedName());
+
+ try {
+ return classLoadingStrategy.loadClass(type);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(String.format("Could not find loaded class for path: %s and type: %s",
+ path, type.getFullyQualifiedName()));
}
- return weakRef.get();
}
@Override
- public void putPathToClass(List<QName> names, Class<?> cls) {
- Type reference = Types.typeForClass(cls);
+ public void putPathToClass(final List<QName> names, final Class<?> cls) {
+ final Type reference = Types.typeForClass(cls);
pathToInstantiatedType.put(names, reference);
+ LOG.trace("Path {} attached to class {} reference {}", names, cls, reference);
bindingClassEncountered(cls);
}
@Override
- public IdentifierCodec<?> getKeyCodecForPath(List<QName> names) {
+ public IdentifierCodec<?> getKeyCodecForPath(final List<QName> names) {
@SuppressWarnings("unchecked")
Class<? extends Identifiable<?>> cls = (Class<? extends Identifiable<?>>) getClassForPath(names);
return getIdentifierCodecForIdentifiable(cls);
}
@Override
- public <T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(Class<T> type) {
+ public <T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(final Class<T> type) {
@SuppressWarnings("unchecked")
DataContainerCodec<T> ret = (DataContainerCodec<T>) containerCodecs.get(type);
if (ret != null) {
@Override
@SuppressWarnings("rawtypes")
- public void bindingClassEncountered(Class cls) {
-
- ConcreteType typeRef = Types.typeForClass(cls);
- if (typeToClass.containsKey(typeRef)) {
- return;
- }
- LOG.trace("Binding Class {} encountered.", cls);
- WeakReference<Class> weakRef = new WeakReference<>(cls);
- typeToClass.put(typeRef, weakRef);
+ public void bindingClassEncountered(final Class cls) {
if (Augmentation.class.isAssignableFrom(cls)) {
-
+ // Intentionally NOOP
} else if (DataObject.class.isAssignableFrom(cls)) {
- @SuppressWarnings({ "unchecked", "unused" })
- Object cdc = getCodecForDataObject((Class<? extends DataObject>) cls);
+ getCodecForDataObject((Class<? extends DataObject>) cls);
}
}
@Override
- public void onClassProcessed(Class<?> cls) {
- ConcreteType typeRef = Types.typeForClass(cls);
- if (typeToClass.containsKey(typeRef)) {
- return;
- }
- LOG.trace("Binding Class {} encountered.", cls);
- @SuppressWarnings("rawtypes")
- WeakReference<Class> weakRef = new WeakReference<Class>(cls);
- typeToClass.put(typeRef, weakRef);
+ public void onClassProcessed(final Class<?> cls) {
+
}
- private DataSchemaNode getSchemaNode(List<QName> path) {
+ private DataSchemaNode getSchemaNode(final List<QName> path) {
QName firstNode = path.get(0);
DataNodeContainer previous = currentSchema.findModuleByNamespaceAndRevision(firstNode.getNamespace(),
firstNode.getRevision());
+ Preconditions.checkArgument(previous != null, "Failed to find module %s for path %s", firstNode, path);
+
Iterator<QName> iterator = path.iterator();
while (iterator.hasNext()) {
QName arg = iterator.next();
return (DataSchemaNode) previous;
}
- private DataSchemaNode searchInChoices(DataNodeContainer node, QName arg) {
- Set<DataSchemaNode> children = node.getChildNodes();
- for (DataSchemaNode child : children) {
+ private DataSchemaNode searchInChoices(final DataNodeContainer node, final QName arg) {
+ for (DataSchemaNode child : node.getChildNodes()) {
if (child instanceof ChoiceNode) {
ChoiceNode choiceNode = (ChoiceNode) child;
DataSchemaNode potential = searchInCases(choiceNode, arg);
return null;
}
- private DataSchemaNode searchInCases(ChoiceNode choiceNode, QName arg) {
+ private DataSchemaNode searchInCases(final ChoiceNode choiceNode, final QName arg) {
Set<ChoiceCaseNode> cases = choiceNode.getCases();
for (ChoiceCaseNode caseNode : cases) {
DataSchemaNode node = caseNode.getDataChildByName(arg);
return null;
}
- private <T> T newInstanceOf(Class<?> newType) {
+ private static <T> T newInstanceOf(final Class<?> cls) {
try {
@SuppressWarnings("unchecked")
- T ret = (T) newType.newInstance();
+ T ret = (T) cls.newInstance();
return ret;
} catch (InstantiationException e) {
- throw new IllegalStateException(e);
+ LOG.error("Failed to instantiate codec {}", cls.getSimpleName(), e);
+ throw new IllegalStateException(String.format("Failed to instantiate codec %s", cls), e);
} catch (IllegalAccessException e) {
- throw new IllegalStateException(e);
+ LOG.debug(
+ "Run-time consistency issue: constructor for {} is not available. This indicates either a code generation bug or a misconfiguration of JVM.",
+ cls.getSimpleName(), e);
+ throw new IllegalStateException(String.format("Cannot access contructor of %s", cls), e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public IdentifierCodec<?> getIdentifierCodecForIdentifiable(final Class identifiable) {
+
+ Class identifier = ClassLoaderUtils.findFirstGenericArgument(identifiable,
+ org.opendaylight.yangtools.yang.binding.Identifiable.class);
+ IdentifierCodec<?> obj = identifierCodecs.get(identifier);
+ if (obj != null) {
+ return obj;
}
+ return createIdentifierCodec(identifier, identifiable);
}
@Override
- public <T extends Identifiable<?>> IdentifierCodec<?> getIdentifierCodecForIdentifiable(Class<T> type) {
- IdentifierCodec<?> obj = identifierCodecs.get(type);
+ public <T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(final Class<T> identifier) {
+ @SuppressWarnings("unchecked")
+ IdentifierCodec<T> obj = (IdentifierCodec<T>) identifierCodecs.get(identifier);
if (obj != null) {
return obj;
}
+ Class<? extends Identifiable<T>> identifiable = ClassLoaderUtils.findFirstGenericArgument(identifier,
+ Identifier.class);
+ return createIdentifierCodec(identifier, identifiable);
+ }
+
+ private <T extends Identifier<?>> IdentifierCodec<T> createIdentifierCodec(final Class<T> identifier,
+ final Class<? extends Identifiable<T>> identifiable) {
Class<? extends BindingCodec<Map<QName, Object>, Object>> newCodec = generator
- .keyTransformerForIdentifiable(type);
+ .keyTransformerForIdentifiable(identifiable);
BindingCodec<Map<QName, Object>, Object> newInstance;
newInstance = newInstanceOf(newCodec);
- IdentifierCodecImpl<?> newWrapper = new IdentifierCodecImpl<>(newInstance);
- identifierCodecs.put(type, newWrapper);
+ IdentifierCodecImpl<T> newWrapper = new IdentifierCodecImpl<>(newInstance);
+ identifierCodecs.put(identifier, newWrapper);
return newWrapper;
}
return identityRefCodec;
}
+ @SuppressWarnings("unchecked")
@Override
- public <T extends BaseIdentity> IdentityCodec<T> getCodecForIdentity(Class<T> codec) {
+ public <T extends BaseIdentity> IdentityCodec<T> getCodecForIdentity(final Class<T> codec) {
bindingClassEncountered(codec);
return identityRefCodec;
}
@Override
- public void onCodecCreated(Class<?> cls) {
+ public void onCodecCreated(final Class<?> cls) {
CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec);
CodecMapping.setIdentityRefCodec(cls, identityRefCodec);
}
- @Override
- public <T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(Class<T> object) {
- @SuppressWarnings("unchecked")
- IdentifierCodec<T> obj = (IdentifierCodec<T>) identifierCodecs.get(object);
- if (obj != null) {
- return obj;
- }
- Class<? extends BindingCodec<Map<QName, Object>, Object>> newCodec = generator
- .keyTransformerForIdentifier(object);
- BindingCodec<Map<QName, Object>, Object> newInstance;
- newInstance = newInstanceOf(newCodec);
- IdentifierCodecImpl<T> newWrapper = new IdentifierCodecImpl<>(newInstance);
- identifierCodecs.put(object, newWrapper);
- return newWrapper;
- }
-
@SuppressWarnings("rawtypes")
- public ChoiceCaseCodecImpl getCaseCodecFor(Class caseClass) {
+ public ChoiceCaseCodecImpl getCaseCodecFor(final Class caseClass) {
ChoiceCaseCodecImpl<?> potential = caseCodecs.get(caseClass);
if (potential != null) {
return potential;
}
ConcreteType typeref = Types.typeForClass(caseClass);
- ChoiceCaseCodecImpl caseCodec = typeToCaseCodecs.get(typeref);
+ ChoiceCaseNode caseSchema = caseTypeToCaseSchema.get(typeref);
- Preconditions.checkState(caseCodec != null, "Case Codec was not created proactivelly for %s",
- 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());
+ Preconditions.checkState(caseSchema != null, "Case schema is not available for %s", caseClass.getName());
+ Class<? extends BindingCodec> newCodec = generator.caseCodecFor(caseClass, caseSchema);
BindingCodec newInstance = newInstanceOf(newCodec);
- caseCodec.setDelegate(newInstance);
+ @SuppressWarnings("unchecked")
+ ChoiceCaseCodecImpl caseCodec = new ChoiceCaseCodecImpl(caseClass, caseSchema, newInstance);
caseCodecs.put(caseClass, caseCodec);
-
- for (Entry<Class<?>, ChoiceCodecImpl<?>> choice : choiceCodecs.entrySet()) {
- if (choice.getKey().isAssignableFrom(caseClass)) {
- choice.getValue().cases.put(caseClass, caseCodec);
- }
- }
return caseCodec;
}
- public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
+ public void onModuleContextAdded(final SchemaContext schemaContext, final Module module, final ModuleContext context) {
pathToType.putAll(context.getChildNodes());
- augmentToType.putAll(context.getTypeToAugmentation().inverse());
+
+ BiMap<Type, AugmentationSchema> bimap = context.getTypeToAugmentation();
+ for (Map.Entry<Type, AugmentationSchema> entry : bimap.entrySet()) {
+ Type key = entry.getKey();
+ AugmentationSchema value = entry.getValue();
+ Collection<DataSchemaNode> augmentedNodes = value.getChildNodes();
+ if (augmentedNodes != null && !augmentedNodes.isEmpty()) {
+ typeToAugment.put(key, value);
+ }
+ }
+
qnamesToIdentityMap.putAll(context.getIdentities());
for (Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
typeToQname.put(
new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),
identity.getKey());
}
- captureCases(context.getCases(), schemaContext);
- }
-
- private void captureCases(Map<SchemaPath, GeneratedTypeBuilder> cases, SchemaContext module) {
- for (Entry<SchemaPath, GeneratedTypeBuilder> caseNode : cases.entrySet()) {
- ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode
- .getValue().getName());
-
- pathToType.put(caseNode.getKey(), caseNode.getValue());
-
- ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey());
- if (node == null) {
- LOG.warn("Failed to find YANG SchemaNode for {}, with path {} was not found in context.",
- typeref.getFullyQualifiedName(), caseNode.getKey());
- @SuppressWarnings("rawtypes")
- ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl();
- typeToCaseCodecs.putIfAbsent(typeref, value);
- continue;
- }
- @SuppressWarnings("rawtypes")
- ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node);
- typeToCaseCodecs.putIfAbsent(typeref, value);
+ synchronized (augmentableToAugmentations) {
+ augmentableToAugmentations.putAll(context.getAugmentableToAugmentations());
+ }
+ synchronized (choiceToCases) {
+ choiceToCases.putAll(context.getChoiceToCases());
+ }
+ synchronized (caseTypeToCaseSchema) {
+ caseTypeToCaseSchema.putAll(context.getCaseTypeToSchemas());
}
}
@Override
- public void onGlobalContextUpdated(SchemaContext context) {
+ public void onGlobalContextUpdated(final SchemaContext context) {
currentSchema = context;
+ resetDispatchCodecsAdaptation();
+
+ }
+
+ /**
+ * Resets / clears adaptation for all schema context sensitive codecs in
+ * order for them to adapt to new schema context and maybe newly discovered
+ * augmentations This ensure correct behaviour for augmentations and
+ * augmented cases for preexisting codecs, which augmentations were
+ * introduced at later point in time.
+ *
+ * This also makes removed augmentations unavailable.
+ */
+ private void resetDispatchCodecsAdaptation() {
+ synchronized (dispatchCodecs) {
+ for (LocationAwareDispatchCodec<?> codec : dispatchCodecs.values()) {
+ codec.resetCodec(this);
+ }
+ }
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
- public void onChoiceCodecCreated(Class<?> choiceClass,
- Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec, ChoiceNode schema) {
+ public void onChoiceCodecCreated(final Class<?> choiceClass,
+ final Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec, final ChoiceNode schema) {
ChoiceCodec<?> oldCodec = choiceCodecs.get(choiceClass);
Preconditions.checkState(oldCodec == null);
BindingCodec<Map<QName, Object>, Object> delegate = newInstanceOf(choiceCodec);
- ChoiceCodecImpl<?> newCodec = new ChoiceCodecImpl(delegate);
+ PublicChoiceCodecImpl<?> newCodec = new PublicChoiceCodecImpl(delegate);
+ DispatchChoiceCodecImpl dispatchCodec = new DispatchChoiceCodecImpl(choiceClass, this);
choiceCodecs.put(choiceClass, newCodec);
- CodecMapping.setClassToCaseMap(choiceCodec, classToCaseRawCodec);
- CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase());
-
- tryToCreateCasesCodecs(schema);
-
- }
-
- private void tryToCreateCasesCodecs(ChoiceNode schema) {
- for (ChoiceCaseNode caseNode : schema.getCases()) {
- SchemaPath path = caseNode.getPath();
- GeneratedTypeBuilder type;
- if (path != null && (type = pathToType.get(path)) != null) {
- ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
- ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref);
- if (partialCodec.getSchema() == null) {
- partialCodec.setSchema(caseNode);
- }
- try {
- Class<?> caseClass = classLoadingStrategy.loadClass(type.getFullyQualifiedName());
- getCaseCodecFor(caseClass);
- } catch (ClassNotFoundException e) {
- LOG.trace("Could not proactivelly create case codec for {}", type, e);
- }
- }
+ synchronized (dispatchCodecs) {
+ dispatchCodecs.put(choiceClass, dispatchCodec);
}
-
+ CodecMapping.setDispatchCodec(choiceCodec, dispatchCodec);
}
@Override
- public void onValueCodecCreated(Class<?> valueClass, Class<?> valueCodec) {
+ public void onValueCodecCreated(final Class<?> valueClass, final Class<?> valueCodec) {
}
@Override
- public void onCaseCodecCreated(Class<?> choiceClass,
- Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec) {
+ public void onCaseCodecCreated(final Class<?> choiceClass,
+ final Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec) {
}
@Override
- public void onDataContainerCodecCreated(Class<?> dataClass, Class<? extends BindingCodec<?, ?>> dataCodec) {
+ public void onDataContainerCodecCreated(final Class<?> dataClass,
+ final Class<? extends BindingCodec<?, ?>> dataCodec) {
if (Augmentable.class.isAssignableFrom(dataClass)) {
- AugmentableCompositeCodec augmentableCodec = getAugmentableCodec(dataClass);
+ AugmentableDispatchCodec augmentableCodec = getAugmentableCodec(dataClass);
CodecMapping.setAugmentationCodec(dataCodec, augmentableCodec);
}
-
}
- public AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
- AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass);
+ public synchronized AugmentableDispatchCodec getAugmentableCodec(final Class<?> dataClass) {
+ AugmentableDispatchCodec ret = augmentableCodecs.get(dataClass);
if (ret != null) {
return ret;
}
- ret = new AugmentableCompositeCodec(dataClass);
+ ret = new AugmentableDispatchCodec(dataClass, this);
augmentableCodecs.put(dataClass, ret);
-
- Map<Type, SchemaNode> typeToSchemaNode = generator.getTypeToSchemaNode();
- Type refType = new ReferencedTypeImpl(dataClass.getPackage().getName(), dataClass.getSimpleName());
- SchemaNode node = typeToSchemaNode.get(refType);
- tryToLoadAugmentations(node);
-
- return ret;
- }
-
- private void tryToLoadAugmentations(SchemaNode schemaNode) {
- if (schemaNode instanceof AugmentationTarget) {
- AugmentationTarget augmentationTarget = (AugmentationTarget) schemaNode;
- Set<AugmentationSchema> augments = augmentationTarget.getAvailableAugmentations();
- Set<Type> augmentTypes = new HashSet<>();
- if (augments != null) {
- for (AugmentationSchema augment : augments) {
- Type augmentType = augmentToType.get(augment);
- if (augmentType == null) {
- LOG.warn("Failed to find type for augmentation of {}", augment);
- } else {
- augmentTypes.add(augmentType);
- }
- }
- for (Type augmentType : augmentTypes) {
- Class<? extends Augmentation<?>> clazz = null;
- try {
- clazz = (Class<? extends Augmentation<?>>) classLoadingStrategy.loadClass(augmentType);
- getCodecForAugmentation(clazz);
- } catch (ClassNotFoundException e) {
- LOG.warn("Failed to find class for augmentation of {}, reason: {}", augmentType, e.toString());
- } catch (CodeGenerationException e) {
- LOG.warn("Failed to proactively generate augment coded for {}, reason: {}", augmentType, e.toString());
- }
- }
- }
- }
-
- if (schemaNode instanceof DataNodeContainer) {
- Set<DataSchemaNode> childNodes = ((DataNodeContainer) schemaNode).getChildNodes();
- for (DataSchemaNode child : childNodes) {
- tryToLoadAugmentations(child);
- }
+ synchronized (dispatchCodecs) {
+ dispatchCodecs.put(dataClass, ret);
}
+ ret.tryToLoadImplementations();
+ return ret;
}
- private static abstract class IntermediateCodec<T> implements //
- DomCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
+ private static abstract class IntermediateCodec<T> implements DomCodec<T>,
+ Delegator<BindingCodec<Map<QName, Object>, Object>> {
private final BindingCodec<Map<QName, Object>, Object> delegate;
return delegate;
}
- public IntermediateCodec(BindingCodec<Map<QName, Object>, Object> delegate) {
+ public IntermediateCodec(final BindingCodec<Map<QName, Object>, Object> delegate) {
this.delegate = delegate;
}
@Override
- public Node<?> serialize(ValueWithQName<T> input) {
+ public Node<?> serialize(final ValueWithQName<T> input) {
Map<QName, Object> intermediateOutput = delegate.serialize(input);
return IntermediateMapping.toNode(intermediateOutput);
}
+
}
- private static class IdentifierCodecImpl<T extends Identifier<?>> //
- extends IntermediateCodec<T> //
- implements IdentifierCodec<T> {
+ private static class IdentifierCodecImpl<T extends Identifier<?>> extends IntermediateCodec<T> implements
+ IdentifierCodec<T> {
- public IdentifierCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
+ public IdentifierCodecImpl(final BindingCodec<Map<QName, Object>, Object> delegate) {
super(delegate);
}
@Override
- public ValueWithQName<T> deserialize(Node<?> input) {
+ public ValueWithQName<T> deserialize(final Node<?> input) {
QName qname = input.getNodeType();
@SuppressWarnings("unchecked")
T value = (T) getDelegate().deserialize((Map<QName, Object>) input);
}
@Override
- public CompositeNode serialize(ValueWithQName<T> input) {
+ public ValueWithQName<T> deserialize(final Node<?> input, final InstanceIdentifier<?> bindingIdentifier) {
+ QName qname = input.getNodeType();
+ @SuppressWarnings("unchecked")
+ T value = (T) getDelegate().deserialize((Map<QName, Object>) input, bindingIdentifier);
+ return new ValueWithQName<T>(qname, value);
+ }
+
+ @Override
+ public CompositeNode serialize(final ValueWithQName<T> input) {
return (CompositeNode) super.serialize(input);
}
}
- private static class DataContainerCodecImpl<T extends DataContainer> //
- extends IntermediateCodec<T> //
- implements DataContainerCodec<T> {
+ private static class DataContainerCodecImpl<T extends DataContainer> extends IntermediateCodec<T> implements
+ DataContainerCodec<T> {
- public DataContainerCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
+ public DataContainerCodecImpl(final BindingCodec<Map<QName, Object>, Object> delegate) {
super(delegate);
}
@Override
- public ValueWithQName<T> deserialize(Node<?> input) {
+ public ValueWithQName<T> deserialize(final Node<?> input) {
if (input == null) {
return null;
}
}
@Override
- public CompositeNode serialize(ValueWithQName<T> input) {
+ public ValueWithQName<T> deserialize(final Node<?> input, final InstanceIdentifier<?> bindingIdentifier) {
+ if (input == null) {
+ return null;
+ }
+ QName qname = input.getNodeType();
+ @SuppressWarnings("unchecked")
+ T value = (T) getDelegate().deserialize((Map<QName, Object>) input, bindingIdentifier);
+ return new ValueWithQName<T>(qname, value);
+ }
+
+ @Override
+ public CompositeNode serialize(final ValueWithQName<T> input) {
return (CompositeNode) super.serialize(input);
}
}
- @SuppressWarnings("rawtypes")
- private static class ChoiceCaseCodecImpl<T extends DataContainer> implements ChoiceCaseCodec<T>, //
- Delegator<BindingCodec> {
- private boolean augmenting;
- private BindingCodec delegate;
+ private interface LocationAwareBindingCodec<P, I> extends BindingCodec<P, I> {
- private Set<String> validNames;
- private Set<QName> validQNames;
- private ChoiceCaseNode schema;
+ boolean isApplicable(InstanceIdentifier<?> parentPath, CompositeNode data);
- public void setSchema(ChoiceCaseNode caseNode) {
- this.schema = caseNode;
- validNames = new HashSet<>();
- validQNames = new HashSet<>();
- for (DataSchemaNode node : caseNode.getChildNodes()) {
- QName qname = node.getQName();
- validQNames.add(qname);
- validNames.add(qname.getLocalName());
- }
- augmenting = caseNode.isAugmenting();
- }
+ public Class<?> getDataType();
+
+ }
- public ChoiceCaseCodecImpl() {
- this.delegate = NOT_READY_CODEC;
+ @SuppressWarnings("rawtypes")
+ private static abstract class LocationAwareDispatchCodec<T extends LocationAwareBindingCodec> implements
+ BindingCodec {
+
+ private final Map<Class, T> implementations = Collections.synchronizedMap(new WeakHashMap<Class, T>());
+ private final Set<InstanceIdentifier<?>> adaptedForPaths = new HashSet<>();
+ private LazyGeneratedCodecRegistry registry;
+
+ protected LocationAwareDispatchCodec(final LazyGeneratedCodecRegistry registry) {
+ this.registry = registry;
}
- public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) {
- this.delegate = NOT_READY_CODEC;
- setSchema(caseNode);
+ protected Map<Class, T> getImplementations() {
+ return implementations;
}
- @Override
- public ValueWithQName<T> deserialize(Node<?> input) {
- throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+ /**
+ * Resets codec adaptation based on location and schema context.
+ *
+ * This is required if new cases / augmentations were introduced or
+ * removed and first use of codec is triggered by invocation from DOM to
+ * Java, so the implementations may change and this may require loading
+ * of new codecs and/or removal of existing ones.
+ *
+ */
+ public synchronized void resetCodec(final LazyGeneratedCodecRegistry currentRegistry) {
+ registry = currentRegistry;
+ adaptedForPaths.clear();
+ resetAdaptationImpl();
}
- @Override
- public CompositeNode serialize(ValueWithQName<T> input) {
- throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+ protected void resetAdaptationImpl() {
+ // Intentionally NOOP, subclasses may specify their custom
+ // behaviour.
}
- @Override
- public BindingCodec getDelegate() {
- return delegate;
+ protected final LazyGeneratedCodecRegistry getRegistry() {
+ return registry;
}
- public void setDelegate(BindingCodec delegate) {
- this.delegate = delegate;
+ protected void addImplementation(final T implementation) {
+ implementations.put(implementation.getDataType(), implementation);
}
- public ChoiceCaseNode getSchema() {
- return schema;
+ @Override
+ public final Object deserialize(final Object input) {
+ throw new UnsupportedOperationException("Invocation of deserialize without Tree location is unsupported");
}
@Override
- public boolean isAcceptable(Node<?> input) {
- if (input instanceof CompositeNode) {
- if (augmenting) {
- return checkAugmenting((CompositeNode) input);
- } else {
- return checkLocal((CompositeNode) input);
+ public final Object deserialize(final Object parent, final InstanceIdentifier parentPath) {
+ adaptForPath(parentPath);
+ Preconditions.checkArgument(parent instanceof CompositeNode, "node must be of CompositeNode type.");
+ CompositeNode parentData = (CompositeNode) parent;
+ ArrayList<T> applicable = new ArrayList<>(implementations.size());
+
+ /*
+ * Codecs are filtered to only ones, which are applicable in
+ * supplied parent context.
+ */
+ for (T impl : getImplementations().values()) {
+ @SuppressWarnings("unchecked")
+ boolean codecApplicable = impl.isApplicable(parentPath, parentData);
+ if (codecApplicable) {
+ applicable.add(impl);
}
}
- return false;
+ LOG.trace("{}: Deserializing mixins from {}, Schema Location {}, Applicable Codecs: {}, All Codecs: {}",
+ this, parent, parentPath, applicable, getImplementations().values());
+
+ /*
+ * In case of none is applicable, we return null. Since there is no
+ * mixin which is applicable in this location.
+ */
+ if (applicable.isEmpty()) {
+ return null;
+ }
+ return deserializeImpl(parentData, parentPath, applicable);
}
- private boolean checkLocal(CompositeNode input) {
- QName parent = input.getNodeType();
- for (Node<?> childNode : input.getChildren()) {
- QName child = childNode.getNodeType();
- if (!Objects.equals(parent.getNamespace(), child.getNamespace())
- || !Objects.equals(parent.getRevision(), child.getRevision())) {
- continue;
- }
- if (validNames.contains(child.getLocalName())) {
- return true;
- }
+ protected abstract Object deserializeImpl(final CompositeNode input, final InstanceIdentifier<?> parentPath,
+ Iterable<T> applicableCodecs);
+
+ @Override
+ public Object serialize(final Object input) {
+ Preconditions.checkArgument(input instanceof DataContainer);
+ Class<? extends DataContainer> inputType = ((DataContainer) input).getImplementedInterface();
+ T implementation = implementations.get(inputType);
+ if (implementation == null) {
+ implementation = tryToLoadImplementationImpl(inputType);
}
- return false;
+
+ return null;
+ }
+
+ private T tryToLoadImplementationImpl(final Class<? extends DataContainer> inputType) {
+ T implementation = tryToLoadImplementation(inputType);
+ Preconditions.checkArgument(implementation != null, "Data type %s is not supported.", inputType);
+ addImplementation(implementation);
+ return implementation;
}
- private boolean checkAugmenting(CompositeNode input) {
- for (Node<?> child : input.getChildren()) {
- if (validQNames.contains(child.getNodeType())) {
- return true;
+ protected final synchronized void adaptForPath(final InstanceIdentifier<?> path) {
+ if (adaptedForPaths.contains(path)) {
+ return;
+ }
+ LOG.debug("Adapting mixin codec {} for path {}", this, path);
+ /**
+ * We search in schema context if the use of this location aware
+ * codec (augmentable codec, case codec) makes sense on provided
+ * location (path)
+ *
+ */
+ Optional<DataNodeContainer> contextNode = BindingSchemaContextUtils.findDataNodeContainer(
+ getRegistry().currentSchema, path);
+ /**
+ * If context node is present, this codec makes sense on provided
+ * location.
+ *
+ */
+ if (contextNode.isPresent()) {
+ synchronized (this) {
+ /**
+ *
+ * We adapt (turn on / off) possible implementations of
+ * child codecs (augmentations, cases) based on this
+ * location.
+ *
+ *
+ */
+
+ adaptForPathImpl(path, contextNode.get());
+ try {
+ /**
+ * We trigger serialization of instance identifier, to
+ * make sure instance identifier codec is aware of
+ * combination of this path / augmentation / case
+ */
+ getRegistry().getInstanceIdentifierCodec().serialize(path);
+ } catch (Exception e) {
+ LOG.warn("Exception during preparation of instance identifier codec for path {}.", path, e);
+ }
+ adaptedForPaths.add(path);
}
+ } else {
+ LOG.debug("Context node (parent node) not found for {}", path);
}
- return false;
}
- }
- private static class ChoiceCodecImpl<T> implements ChoiceCodec<T> {
+ protected abstract T tryToLoadImplementation(Class<? extends DataContainer> inputType);
- private final BindingCodec<Map<QName, Object>, Object> delegate;
-
- @SuppressWarnings("rawtypes")
- private final Map<Class, ChoiceCaseCodecImpl<?>> cases = Collections
- .synchronizedMap(new WeakHashMap<Class, ChoiceCaseCodecImpl<?>>());
+ protected abstract void tryToLoadImplementations();
- private final CaseCompositeNodeMapFacade CompositeToCase;
+ protected abstract void adaptForPathImpl(InstanceIdentifier<?> path, DataNodeContainer ctx);
+ }
- public ChoiceCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
- this.delegate = delegate;
- this.CompositeToCase = new CaseCompositeNodeMapFacade(cases);
+ @SuppressWarnings("rawtypes")
+ private static class ChoiceCaseCodecImpl<T extends DataContainer> implements ChoiceCaseCodec<T>, //
+ Delegator<BindingCodec>, LocationAwareBindingCodec<Node<?>, ValueWithQName<T>> {
+ private final BindingCodec delegate;
+ private final ChoiceCaseNode schema;
+ private final Map<InstanceIdentifier<?>, ChoiceCaseNode> instantiatedLocations;
+ private final Class<?> dataType;
+
+ public ChoiceCaseCodecImpl(final Class<?> caseClass, final ChoiceCaseNode caseNode,
+ final BindingCodec newInstance) {
+ this.delegate = newInstance;
+ this.dataType = caseClass;
+ this.schema = caseNode;
+ instantiatedLocations = new HashMap<>();
}
@Override
- public ValueWithQName<T> deserialize(Node<?> input) {
+ public ValueWithQName<T> deserialize(final Node<?> input) {
throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
}
@Override
- public Node<?> serialize(ValueWithQName<T> input) {
- throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
- }
-
- public CaseCompositeNodeMapFacade getCompositeToCase() {
- return CompositeToCase;
+ public ValueWithQName<T> deserialize(final Node<?> input, final InstanceIdentifier<?> bindingIdentifier) {
+ if (input == null) {
+ return null;
+ }
+ QName qname = input.getNodeType();
+ synchronized (instantiatedLocations) {
+ ChoiceCaseNode instantiation = instantiatedLocations.get(bindingIdentifier);
+ if (instantiation != null) {
+ qname = instantiatedLocations.get(bindingIdentifier).getQName();
+ }
+ }
+ @SuppressWarnings("unchecked")
+ T value = (T) getDelegate().deserialize(new SimpleEntry(qname, input), bindingIdentifier);
+ return new ValueWithQName<T>(qname, value);
}
- public Map<Class, ChoiceCaseCodecImpl<?>> getCases() {
- return cases;
+ @Override
+ public CompositeNode serialize(final ValueWithQName<T> input) {
+ throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
}
- public BindingCodec<Map<QName, Object>, Object> getDelegate() {
+ @Override
+ public BindingCodec getDelegate() {
return delegate;
}
- }
-
- @SuppressWarnings("rawtypes")
- private class CaseClassMapFacade extends MapFacadeBase {
-
- @Override
- public Set<Entry<Class, BindingCodec<Object, Object>>> entrySet() {
- return Collections.emptySet();
+ public ChoiceCaseNode getSchema() {
+ return schema;
}
@Override
- public BindingCodec get(Object key) {
- if (key instanceof Class) {
- Class cls = (Class) key;
- // bindingClassEncountered(cls);
- ChoiceCaseCodecImpl caseCodec = getCaseCodecFor(cls);
- return caseCodec.getDelegate();
+ @Deprecated
+ public boolean isAcceptable(final Node<?> input) {
+ return checkAgainstSchema(schema, input);
+ }
+
+ private static boolean checkAgainstSchema(final ChoiceCaseNode schema, final Node<?> node) {
+ if (node instanceof CompositeNode) {
+ CompositeNode input = (CompositeNode) node;
+ for (Node<?> childNode : input.getValue()) {
+ QName child = childNode.getNodeType();
+ if (schema.getDataChildByName(child) != null) {
+ return true;
+ }
+ }
}
- return null;
+ return false;
}
- }
-
- @SuppressWarnings("rawtypes")
- private static class CaseCompositeNodeMapFacade extends MapFacadeBase<CompositeNode> {
- final Map<Class, ChoiceCaseCodecImpl<?>> choiceCases;
+ @Override
+ public Class<?> getDataType() {
+ return dataType;
+ }
- public CaseCompositeNodeMapFacade(Map<Class, ChoiceCaseCodecImpl<?>> choiceCases) {
- this.choiceCases = choiceCases;
+ public void adaptForPath(final InstanceIdentifier<?> augTarget, final ChoiceCaseNode choiceCaseNode) {
+ synchronized (instantiatedLocations) {
+ instantiatedLocations.put(augTarget, choiceCaseNode);
+ }
}
@Override
- public BindingCodec get(Object key) {
- if (!(key instanceof CompositeNode)) {
- return null;
+ public boolean isApplicable(final InstanceIdentifier path, final CompositeNode input) {
+ ChoiceCaseNode instantiatedSchema = null;
+ synchronized (instantiatedLocations) {
+ instantiatedSchema = instantiatedLocations.get(path);
+ }
+ if (instantiatedSchema == null) {
+ return false;
+ }
+ return checkAgainstSchema(instantiatedSchema, input);
+ }
+
+ protected boolean isAugmenting(final QName choiceName, final QName proposedQName) {
+ if (schema.isAugmenting()) {
+ return true;
+ }
+ // Choice QName
+ QName parentQName = Iterables.get(schema.getPath().getPathTowardsRoot(), 1);
+ if (!parentQName.getNamespace().equals(schema.getQName().getNamespace())) {
+ return true;
}
- for (Entry<Class, ChoiceCaseCodecImpl<?>> entry : choiceCases.entrySet()) {
- ChoiceCaseCodecImpl<?> codec = entry.getValue();
- if (codec.isAcceptable((CompositeNode) key)) {
- return codec.getDelegate();
+ if (!parentQName.equals(choiceName)) {
+ // This item is instantiation of choice via uses in other YANG
+ // module
+ if (choiceName.getNamespace().equals(schema.getQName())) {
+ // Original definition of grouping is in same namespace
+ // as original definition of case
+ // so for sure case is introduced via instantiation of
+ // grouping
+ return false;
}
+ // Since we are still here, that means case has same namespace
+ // as its parent, which is instantiation of grouping
+ // but case namespace is different from parent node
+ // so it is augmentation.
+ return true;
}
- return null;
+ return false;
}
+ @Override
+ public String toString() {
+ return "ChoiceCaseCodec [case=" + dataType + ", knownLocations=" + instantiatedLocations.keySet() + "]";
+ }
}
- /**
- * This map is used as only facade for
- * {@link org.opendaylight.yangtools.yang.binding.BindingCodec} in different
- * classloaders to retrieve codec dynamicly based on provided key.
- *
- * @param <T>
- * Key type
- */
- @SuppressWarnings("rawtypes")
- private static abstract class MapFacadeBase<T> implements Map<T, BindingCodec<?, ?>> {
+ private static class PublicChoiceCodecImpl<T> implements ChoiceCodec<T>,
+ Delegator<BindingCodec<Map<QName, Object>, Object>> {
- @Override
- public boolean containsKey(Object key) {
- return get(key) != null;
- }
+ private final BindingCodec<Map<QName, Object>, Object> delegate;
- @Override
- public void clear() {
- throw notModifiable();
+ public PublicChoiceCodecImpl(final BindingCodec<Map<QName, Object>, Object> delegate) {
+ this.delegate = delegate;
}
@Override
- public boolean equals(Object obj) {
- return super.equals(obj);
+ public ValueWithQName<T> deserialize(final Node<?> input) {
+ throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
}
@Override
- public BindingCodec remove(Object key) {
- return null;
+ public ValueWithQName<T> deserialize(final Node<?> input, final InstanceIdentifier<?> bindingIdentifier) {
+ throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
}
@Override
- public int size() {
- return 0;
+ public Node<?> serialize(final ValueWithQName<T> input) {
+ throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
}
@Override
- public Collection<BindingCodec<?, ?>> values() {
- return Collections.emptySet();
+ public BindingCodec<Map<QName, Object>, Object> getDelegate() {
+ return delegate;
}
- private UnsupportedOperationException notModifiable() {
- return new UnsupportedOperationException("Not externally modifiable.");
+ }
+
+ class DispatchChoiceCodecImpl extends LocationAwareDispatchCodec<ChoiceCaseCodecImpl<?>> {
+ private final Class<?> choiceType;
+ private final QName choiceName;
+
+ private DispatchChoiceCodecImpl(final Class<?> type, final LazyGeneratedCodecRegistry registry) {
+ super(registry);
+ choiceType = type;
+ choiceName = BindingReflections.findQName(type);
}
@Override
- public BindingCodec<Map<QName, Object>, Object> put(T key, BindingCodec<?, ?> value) {
- throw notModifiable();
+ public Object deserializeImpl(final CompositeNode input, final InstanceIdentifier<?> path,
+ final Iterable<ChoiceCaseCodecImpl<?>> codecs) {
+ ChoiceCaseCodecImpl<?> caseCodec = Iterables.getOnlyElement(codecs);
+ ValueWithQName<?> value = caseCodec.deserialize(input, path);
+ if (value != null) {
+ return value.getValue();
+ }
+ return null;
}
+ @SuppressWarnings("unchecked")
@Override
- public void putAll(Map<? extends T, ? extends BindingCodec<?, ?>> m) {
- throw notModifiable();
+ public Object serialize(final Object input) {
+ Preconditions.checkArgument(input instanceof Map.Entry<?, ?>, "Input must be QName, Value");
+ @SuppressWarnings("rawtypes")
+ QName derivedQName = (QName) ((Map.Entry) input).getKey();
+ @SuppressWarnings("rawtypes")
+ Object inputValue = ((Map.Entry) input).getValue();
+ Preconditions.checkArgument(inputValue instanceof DataObject);
+ Class<? extends DataContainer> inputType = ((DataObject) inputValue).getImplementedInterface();
+ ChoiceCaseCodecImpl<?> codec = tryToLoadImplementation(inputType);
+ Preconditions.checkState(codec != null, "Unable to get codec for %s", inputType);
+ if (codec.isAugmenting(choiceName, derivedQName)) {
+ // If choice is augmenting we use QName which defined this
+ // augmentation
+ return codec.getDelegate().serialize(new ValueWithQName<>(codec.getSchema().getQName(), inputValue));
+ }
+ return codec.getDelegate().serialize(input);
}
- @Override
- public int hashCode() {
- return super.hashCode();
+ @SuppressWarnings("rawtypes")
+ protected Optional<ChoiceCaseCodecImpl> tryToLoadImplementation(final Type potential) {
+ try {
+ @SuppressWarnings("unchecked")
+ Class<? extends DataContainer> clazz = (Class<? extends DataContainer>) classLoadingStrategy
+ .loadClass(potential);
+ ChoiceCaseCodecImpl codec = tryToLoadImplementation(clazz);
+ addImplementation(codec);
+ return Optional.of(codec);
+ } catch (ClassNotFoundException e) {
+ LOG.warn("Failed to find class for choice {}", potential, e);
+ }
+ return Optional.absent();
}
@Override
- public boolean isEmpty() {
- return true;
+ protected ChoiceCaseCodecImpl<?> tryToLoadImplementation(final Class<? extends DataContainer> inputType) {
+ ChoiceCaseCodecImpl<?> codec = getCaseCodecFor(inputType);
+ addImplementation(codec);
+ return codec;
}
@Override
- public Set<T> keySet() {
- return Collections.emptySet();
+ protected void tryToLoadImplementations() {
+ Type type = referencedType(choiceType);
+ Collection<Type> potentialCases;
+ synchronized (choiceToCases) {
+ potentialCases = choiceToCases.get(type);
+ }
+ for (Type potential : potentialCases) {
+ try {
+ tryToLoadImplementation(potential);
+ } catch (CodeGenerationException e) {
+ LOG.warn("Failed to proactively generate choice code for {}", type, e);
+ }
+ }
}
@Override
- public Set<Entry<T, BindingCodec<?, ?>>> entrySet() {
- return Collections.emptySet();
+ protected void adaptForPathImpl(final InstanceIdentifier<?> augTarget, final DataNodeContainer ctxNode) {
+ Optional<ChoiceNode> newChoice = BindingSchemaContextUtils.findInstantiatedChoice(ctxNode, choiceType);
+ tryToLoadImplementations();
+ Preconditions.checkState(newChoice.isPresent(), "BUG: Unable to find instantiated choice node in schema.");
+ for (@SuppressWarnings("rawtypes")
+ Entry<Class, ChoiceCaseCodecImpl<?>> codec : getImplementations().entrySet()) {
+ ChoiceCaseCodecImpl<?> caseCodec = codec.getValue();
+ Optional<ChoiceCaseNode> instantiatedSchema = BindingSchemaContextUtils.findInstantiatedCase(
+ newChoice.get(), caseCodec.getSchema());
+ if (instantiatedSchema.isPresent()) {
+ caseCodec.adaptForPath(augTarget, instantiatedSchema.get());
+ }
+ }
}
@Override
- public boolean containsValue(Object value) {
- return false;
+ public String toString() {
+ return "DispatchChoiceCodecImpl [choiceType=" + choiceType + "]";
}
}
+ /**
+ *
+ * Dispatch codec for augmented object, which processes augmentations
+ * <p>
+ * This codec is used from DataObject codec generated using
+ * {@link TransformerGenerator#transformerFor(Class)} and is wired during
+ * {@link LazyGeneratedCodecRegistry#onDataContainerCodecCreated(Class, Class)}.
+ * <p>
+ * Instance of this codec is associated with class of Binding DTO which
+ * represents target for augmentations.
+ *
+ */
@SuppressWarnings({ "rawtypes", "unchecked" })
- private class AugmentableCompositeCodec implements BindingCodec {
+ static class AugmentableDispatchCodec extends LocationAwareDispatchCodec<AugmentationCodecWrapper> {
private final Class augmentableType;
- Map<Class, AugmentationCodec<?>> localAugmentationCodecs = Collections
- .synchronizedMap(new WeakHashMap<Class, AugmentationCodec<?>>());
-
- public AugmentableCompositeCodec(Class type) {
+ /**
+ * Construct augmetable dispatch codec.
+ *
+ * @param type
+ * Class representing augmentation target
+ * @param registry
+ * Registry with which this codec is associated.
+ */
+ public AugmentableDispatchCodec(final Class type, final LazyGeneratedCodecRegistry registry) {
+ super(registry);
Preconditions.checkArgument(Augmentable.class.isAssignableFrom(type));
augmentableType = type;
}
+ /**
+ * Serializes object to list of values which needs to be injected into
+ * resulting DOM Node. Injection of data to parent DOM Node is handled
+ * by caller (in this case generated codec).
+ *
+ * TODO: Deprecate use of augmentation codec without instance instance
+ * identifier
+ *
+ * @return list of nodes, which needs to be added to parent node.
+ *
+ */
@Override
- public Object serialize(Object input) {
+ public Object serialize(final Object input) {
+ Preconditions.checkArgument(augmentableType.isInstance(input), "Object %s is not instance of %s ", input,
+ augmentableType);
if (input instanceof Augmentable<?>) {
-
- Map<Class, Augmentation> augmentations = getAugmentations(input);
+ Map<Class<? extends Augmentation<?>>, Augmentation<?>> augmentations = BindingReflections
+ .getAugmentations((Augmentable<?>) input);
return serializeImpl(augmentations);
}
return null;
}
- private Map<Class, Augmentation> getAugmentations(Object input) {
- Field augmentationField;
- try {
- augmentationField = input.getClass().getDeclaredField("augmentation");
- augmentationField.setAccessible(true);
- Map<Class, Augmentation> augMap = (Map<Class, Augmentation>) augmentationField.get(input);
- return augMap;
- } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
- LOG.debug("Could not read augmentations for {}", input, e);
- }
- return Collections.emptyMap();
- }
-
- private List serializeImpl(Map<Class, Augmentation> input) {
+ /**
+ *
+ * Serialization of augmentations, returns list of composite nodes,
+ * which needs to be injected to parent node.
+ *
+ * @param input
+ * Map of classes to augmentations
+ * @return List of nodes, which should be added to parent node.
+ */
+ private List serializeImpl(final Map<Class<? extends Augmentation<?>>, Augmentation<?>> input) {
List ret = new ArrayList<>();
- for (Entry<Class, Augmentation> entry : input.entrySet()) {
- AugmentationCodec codec = getCodecForAugmentation(entry.getKey());
+ for (Entry<Class<? extends Augmentation<?>>, Augmentation<?>> entry : input.entrySet()) {
+ AugmentationCodec codec = getRegistry().getCodecForAugmentation(entry.getKey());
CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue()));
- ret.addAll(node.getChildren());
+ ret.addAll(node.getValue());
}
return ret;
}
- public synchronized <T extends Augmentation<?>> void addAugmentationCodec(Class<T> augmentationClass,
- AugmentationCodec<T> value) {
- localAugmentationCodecs.put(augmentationClass, value);
- }
-
+ /**
+ *
+ * Deserialization of augmentation which is location aware.
+ *
+ * Note: In case of composite nodes as an input, each codec is invoked
+ * since there is no augmentation identifier and we need to look for
+ * concrete classes. FIXME: Maybe faster variation will be by extending
+ * {@link AugmentationCodecWrapper} to look for particular QNames, which
+ * will filter incoming set of codecs.
+ *
+ *
+ * @param input
+ * Input representation of data
+ * @param path
+ * Wildcarded instance identifier representing location of
+ * augmentation parent in conceptual schema tree
+ * @param codecs
+ * Set of codecs which are applicable for supplied
+ * <code>path</code>, selected by caller to be used by
+ * deserialization
+ *
+ *
+ */
@Override
- public Map<Class, Augmentation> deserialize(Object input) {
+ public Map<Class, Augmentation> deserializeImpl(final CompositeNode input, final InstanceIdentifier<?> path,
+ final Iterable<AugmentationCodecWrapper> codecs) {
+ LOG.trace("{}: Going to deserialize augmentations from {} in location {}. Available codecs {}", this,
+ input, path, codecs);
Map<Class, Augmentation> ret = new HashMap<>();
- if (input instanceof CompositeNode) {
- List<Entry<Class, AugmentationCodec<?>>> codecs = new ArrayList<>(localAugmentationCodecs.entrySet());
- for (Entry<Class, AugmentationCodec<?>> codec : codecs) {
- ValueWithQName<?> value = codec.getValue().deserialize((CompositeNode) input);
- if (value != null && value.getValue() != null) {
- ret.put(codec.getKey(), (Augmentation) value.getValue());
- }
+ for (AugmentationCodecWrapper codec : codecs) {
+ // We add Augmentation Identifier to path, in order to
+ // correctly identify children.
+ Class type = codec.getDataType();
+ final InstanceIdentifier augmentPath = path.augmentation(type);
+ ValueWithQName<?> value = codec.deserialize(input, augmentPath);
+ if (value != null && value.getValue() != null) {
+ ret.put(type, (Augmentation) value.getValue());
}
}
return ret;
}
- public Class getAugmentableType() {
- return augmentableType;
+ /**
+ *
+ * Tries to load implementation of concrete augmentation codec for
+ * supplied type
+ *
+ * Loading of codec may fail, because of supplied type may not be
+ * visible by classloaders known by registry. If class was not found
+ * returns {@link Optional#absent()}.
+ *
+ * @param potential
+ * Augmentation class identifier for which codecs should be
+ * loaded.
+ * @return Optional with codec for supplied type
+ *
+ */
+ protected Optional<AugmentationCodecWrapper> tryToLoadImplementation(final Type potential) {
+ try {
+ Class<? extends Augmentation<?>> clazz = (Class<? extends Augmentation<?>>) getRegistry().classLoadingStrategy
+ .loadClass(potential);
+ return Optional.of(tryToLoadImplementation(clazz));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("Failed to find class for augmentation of {}", potential, e);
+ }
+ return Optional.absent();
}
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private static class LateMixinCodec implements BindingCodec, Delegator<BindingCodec> {
- private BindingCodec delegate;
+ @Override
+ protected AugmentationCodecWrapper tryToLoadImplementation(final Class inputType) {
+ AugmentationCodecWrapper<? extends Augmentation<?>> potentialImpl = getRegistry().getCodecForAugmentation(
+ inputType);
+ addImplementation(potentialImpl);
+ return potentialImpl;
+ }
@Override
- public BindingCodec getDelegate() {
- if (delegate == null) {
- throw new IllegalStateException("Codec not initialized yet.");
+ protected void tryToLoadImplementations() {
+ Type type = referencedType(augmentableType);
+ Collection<Type> potentialAugmentations;
+ synchronized (augmentableToAugmentations) {
+ potentialAugmentations = new ArrayList(augmentableToAugmentations.get(type));
+ }
+ for (Type potential : potentialAugmentations) {
+ try {
+ tryToLoadImplementation(potential);
+ } catch (CodeGenerationException e) {
+ LOG.warn("Failed to proactively generate augment code for {}", type, e);
+ }
}
- return delegate;
}
@Override
- public Object deserialize(Object input) {
- return getDelegate().deserialize(input);
+ protected void adaptForPathImpl(final InstanceIdentifier<?> augTarget, final DataNodeContainer ctxNode) {
+ if (ctxNode instanceof AugmentationTarget) {
+ Set<AugmentationSchema> availableAugmentations = ((AugmentationTarget) ctxNode)
+ .getAvailableAugmentations();
+ if (!availableAugmentations.isEmpty()) {
+ updateAugmentationMapping(augTarget, availableAugmentations);
+ }
+ }
+ }
+
+ /**
+ *
+ * Adapts augmentation codec for specific provider location (target)
+ *
+ * Since augmentation are not forward-referencing and may be discovered
+ * during runtime, we need to adapt {@link AugmentableDispatchCodec},
+ * {@link AugmentationCodecWrapper} and {@link InstanceIdentifierCodec}
+ * for this newly discovered location where augmentation may be used.
+ *
+ * Adaptation consists of:
+ * <ol>
+ * <li>scan of available (valid) augmentations for current location
+ * <li>lookup for Java classes derived from this augmentations
+ * <li>generation of missing codecs
+ * <li>updating Augmentation codecs to work with new location
+ * <li>updating Instance Identifier to work with new location
+ *
+ */
+ private void updateAugmentationMapping(final InstanceIdentifier<?> augTarget,
+ final Set<AugmentationSchema> availableAugmentations) {
+ for (AugmentationSchema aug : availableAugmentations) {
+
+ Type potentialType = getTypeForAugmentation(aug);
+ if (potentialType != null) {
+ Optional<AugmentationCodecWrapper> potentialImpl = tryToLoadImplementation(potentialType);
+ if (potentialImpl.isPresent()) {
+ potentialImpl.get().addApplicableFor(augTarget, aug);
+ Class augType = potentialImpl.get().getDataType();
+ InstanceIdentifier augPath = augTarget.augmentation(augType);
+ try {
+
+ org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier domPath = getRegistry()
+ .getInstanceIdentifierCodec().serialize(augPath);
+ if (domPath == null) {
+ LOG.error("Unable to serialize instance identifier for {}", augPath);
+ }
+ } catch (Exception e) {
+ LOG.error("Unable to serialize instance identifiers for {}", augPath, e);
+ }
+
+ }
+ } else {
+ // Omits warning for empty augmentations since they are not
+ // represented in data
+ if (!aug.getChildNodes().isEmpty()) {
+ LOG.warn("Could not find generated type for augmentation {} with children {}", aug,
+ aug.getChildNodes());
+ }
+ }
+ }
+ }
+
+ private Type getTypeForAugmentation(final AugmentationSchema aug) {
+ Optional<AugmentationSchema> currentAug = Optional.of(aug);
+ while (currentAug.isPresent()) {
+ Type potentialType = typeToAugment.inverse().get(currentAug.get());
+ if (potentialType != null) {
+ return potentialType;
+ }
+ currentAug = currentAug.get().getOriginalDefinition();
+ }
+ return null;
}
@Override
- public Object serialize(Object input) {
- return getDelegate().serialize(input);
+ public String toString() {
+ return "AugmentableDispatchCodec [augmentable=" + augmentableType + "]";
}
+
}
+ @SuppressWarnings("rawtypes")
private static class AugmentationCodecWrapper<T extends Augmentation<?>> implements AugmentationCodec<T>,
- Delegator<BindingCodec> {
+ Delegator<BindingCodec>, LocationAwareBindingCodec<Node<?>, ValueWithQName<T>> {
private final BindingCodec delegate;
private final QName augmentationQName;
+ private final Multimap<InstanceIdentifier<?>, QName> validAugmentationTargets;
+ private final Class<?> augmentationType;
- public AugmentationCodecWrapper(BindingCodec<Map<QName, Object>, Object> rawCodec) {
+ public AugmentationCodecWrapper(final BindingCodec<Map<QName, Object>, Object> rawCodec, final Class<?> dataType) {
this.delegate = rawCodec;
+ this.augmentationType = dataType;
this.augmentationQName = BindingReflections.findQName(rawCodec.getClass());
+ this.validAugmentationTargets = Multimaps.synchronizedSetMultimap(HashMultimap
+ .<InstanceIdentifier<?>, QName> create());
+ }
+
+ public void addApplicableFor(final InstanceIdentifier<?> path, final AugmentationSchema aug) {
+ for (DataSchemaNode child : aug.getChildNodes()) {
+ validAugmentationTargets.put(path, child.getQName());
+ }
}
@Override
}
@Override
- public CompositeNode serialize(ValueWithQName<T> input) {
+ public CompositeNode serialize(final ValueWithQName<T> input) {
@SuppressWarnings("unchecked")
List<Map<QName, Object>> rawValues = (List<Map<QName, Object>>) getDelegate().serialize(input);
List<Node<?>> serialized = new ArrayList<>(rawValues.size());
@Override
@SuppressWarnings("unchecked")
- public ValueWithQName<T> deserialize(Node<?> input) {
+ public ValueWithQName<T> deserialize(final Node<?> input) {
Object rawCodecValue = getDelegate().deserialize(input);
return new ValueWithQName<T>(input.getNodeType(), (T) rawCodecValue);
}
+ @Override
+ @SuppressWarnings("unchecked")
+ public ValueWithQName<T> deserialize(final Node<?> input, final InstanceIdentifier<?> bindingIdentifier) {
+ Object rawCodecValue = getDelegate().deserialize(input, bindingIdentifier);
+ return new ValueWithQName<T>(input.getNodeType(), (T) rawCodecValue);
+ }
+
@Override
public QName getAugmentationQName() {
return augmentationQName;
}
+
+ @Override
+ public boolean isAcceptable(final InstanceIdentifier<?> path) {
+ if (path == null) {
+ return false;
+ }
+ return validAugmentationTargets.containsKey(path);
+ }
+
+ @Override
+ public boolean isApplicable(final InstanceIdentifier parentPath, final CompositeNode parentData) {
+ return isAcceptable(parentPath);
+ }
+
+ @Override
+ public Class<?> getDataType() {
+ return augmentationType;
+ }
+
+ @Override
+ public String toString() {
+ return "AugmentationCodecWrapper [augmentation=" + augmentationType + ", knownLocations="
+ + validAugmentationTargets.keySet() + "]";
+ }
}
+ @SuppressWarnings("rawtypes")
private class IdentityCompositeCodec implements IdentityCodec {
@Override
- public Object deserialize(Object input) {
+ public Object deserialize(final Object input) {
Preconditions.checkArgument(input instanceof QName);
return deserialize((QName) input);
}
@Override
- public Class<?> deserialize(QName input) {
+ public Class<?> deserialize(final QName input) {
+ if (input == null) {
+ return null;
+ }
Type type = qnamesToIdentityMap.get(input);
if (type == null) {
- return null;
+ String packageName = BindingMapping.getRootPackageName(input);
+ String className = BindingMapping.getClassName(input);
+ type = new ReferencedTypeImpl(packageName, className);
}
- ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
- WeakReference<Class> softref = typeToClass.get(typeref);
- if (softref == null) {
-
- try {
- Class<?> cls = classLoadingStrategy.loadClass(typeref.getFullyQualifiedName());
- if (cls != null) {
- serialize(cls);
- return cls;
- }
- } catch (Exception e) {
- LOG.warn("Identity {} was not deserialized, because of missing class {}", input,
- typeref.getFullyQualifiedName());
+ try {
+ final Class<?> cls = classLoadingStrategy.loadClass(type);
+ if (cls != null) {
+ serialize(cls);
+ return cls;
}
- return null;
+ } catch (Exception e) {
+ LOG.warn("Identity {} was not deserialized, because of missing class {}", input,
+ type.getFullyQualifiedName(), e);
}
- return softref.get();
+ return null;
+
}
@Override
- public QName serialize(Class input) {
+ public Object deserialize(final Object input, final InstanceIdentifier bindingIdentifier) {
+ return deserialize(input);
+ }
+
+ @Override
+ public QName serialize(final Class input) {
Preconditions.checkArgument(BaseIdentity.class.isAssignableFrom(input));
bindingClassEncountered(input);
QName qname = identityQNames.get(input);
if (qname != null) {
return qname;
}
- ConcreteType typeref = Types.typeForClass(input);
- qname = typeToQname.get(typeref);
+ qname = BindingReflections.findQName(input);
if (qname != null) {
identityQNames.put(input, qname);
}
}
@Override
- public Object serialize(Object input) {
+ public Object serialize(final Object input) {
Preconditions.checkArgument(input instanceof Class);
return serialize((Class) input);
}
+
}
- public boolean isCodecAvailable(Class<? extends DataContainer> cls) {
- if (containerCodecs.containsKey(cls)) {
- return true;
- }
- if (identifierCodecs.containsKey(cls)) {
- return true;
- }
- if (choiceCodecs.containsKey(cls)) {
- return true;
- }
- if (caseCodecs.containsKey(cls)) {
- return true;
- }
- if (augmentableCodecs.containsKey(cls)) {
- return true;
- }
- if (augmentationCodecs.containsKey(cls)) {
- return true;
- }
- return false;
+ private static final Type referencedType(final Class<?> augmentableType) {
+ return new ReferencedTypeImpl(augmentableType.getPackage().getName(), augmentableType.getSimpleName());
}
+
}