import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
+import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
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.ConcurrentHashMap;
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.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
-public class LazyGeneratedCodecRegistry implements //
+class LazyGeneratedCodecRegistry implements //
CodecRegistry, //
SchemaContextListener, //
GeneratorListener {
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
@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, InstanceIdentifier<?>> pathToBindingIdentifier = 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 BiMap<Type, AugmentationSchema> typeToAugment = HashBiMap
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(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;
@SuppressWarnings("unchecked")
@Override
- public <T extends Augmentation<?>> AugmentationCodecWrapper<T> getCodecForAugmentation(final Class<T> object) {
+ public <T extends Augmentation<?>> AugmentationCodecWrapper<T> getCodecForAugmentation(final Class<T> augClass) {
AugmentationCodecWrapper<T> codec = null;
@SuppressWarnings("rawtypes")
- AugmentationCodecWrapper 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, null, object);
- 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);
- }
+ 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);
}
- Class<? extends Augmentable<?>> objectSupertype = getAugmentableArgumentFrom(object);
- if (objectSupertype != null) {
- getAugmentableCodec(objectSupertype).addImplementation(codec);
- } else {
- LOG.warn("Could not find augmentation target for augmentation {}", object);
+
+ 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;
}
return getCodecForAugmentation((Class<? extends Augmentation<?>>) cls).getAugmentationQName();
}
- private static Class<? extends Augmentable<?>> getAugmentableArgumentFrom(
- final Class<? extends Augmentation<?>> augmentation) {
- try {
- Class<? extends Augmentable<?>> ret = BindingReflections.findAugmentationTarget(augmentation);
- return ret;
-
- } catch (Exception e) {
- LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e);
- return null;
- }
- }
-
@Override
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());
+ final DataSchemaNode node = getSchemaNode(names);
+ 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);
- }
- @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());
+ Preconditions.checkState(type != null, "Failed to lookup instantiated type for path %s", path);
}
+ @SuppressWarnings("rawtypes")
+ final WeakReference<Class> weakRef = typeToClass.get(type);
+ Preconditions.checkState(weakRef != null, "Could not find loaded class for path: %s and type: %s", path,
+ type.getFullyQualifiedName());
return weakRef.get();
}
@Override
public void putPathToClass(final List<QName> names, final Class<?> cls) {
- Type reference = Types.typeForClass(cls);
+ final Type reference = Types.typeForClass(cls);
pathToInstantiatedType.put(names, reference);
+ LOG.trace("Path {} attached to class {} reference {}", names, cls, reference);
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")
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 null;
}
- private <T> T newInstanceOf(final 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);
}
}
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);
+ ChoiceCaseCodecImpl caseCodec = new ChoiceCaseCodecImpl(caseClass, caseSchema, newInstance);
caseCodecs.put(caseClass, caseCodec);
for (Entry<Class<?>, PublicChoiceCodecImpl<?>> choice : choiceCodecs.entrySet()) {
identity.getKey());
}
- synchronized(augmentableToAugmentations) {
+ synchronized (augmentableToAugmentations) {
augmentableToAugmentations.putAll(context.getAugmentableToAugmentations());
}
- synchronized(choiceToCases) {
+ synchronized (choiceToCases) {
choiceToCases.putAll(context.getChoiceToCases());
}
- captureCases(context.getCases(), schemaContext);
- }
-
- private void captureCases(final Map<SchemaPath, GeneratedTypeBuilder> cases, final 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 (caseTypeToCaseSchema) {
+ caseTypeToCaseSchema.putAll(context.getCaseTypeToSchemas());
}
}
Preconditions.checkState(oldCodec == null);
BindingCodec<Map<QName, Object>, Object> delegate = newInstanceOf(choiceCodec);
PublicChoiceCodecImpl<?> newCodec = new PublicChoiceCodecImpl(delegate);
+ DispatchChoiceCodecImpl dispatchCodec = new DispatchChoiceCodecImpl(choiceClass);
choiceCodecs.put(choiceClass, newCodec);
- CodecMapping.setClassToCaseMap(choiceCodec, classToCaseRawCodec);
- CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase());
-
- tryToCreateCasesCodecs(schema);
-
- }
-
- @Deprecated
- private void tryToCreateCasesCodecs(final ChoiceNode schema) {
- for (ChoiceCaseNode choiceCase : schema.getCases()) {
- ChoiceCaseNode caseNode = choiceCase;
- if (caseNode.isAddedByUses()) {
- DataSchemaNode origCaseNode = SchemaContextUtil.findOriginal(caseNode, currentSchema);
- if (origCaseNode instanceof ChoiceCaseNode) {
- caseNode = (ChoiceCaseNode) origCaseNode;
- }
- }
- SchemaPath path = caseNode.getPath();
-
- GeneratedTypeBuilder type;
- if (path != null && (type = pathToType.get(path)) != null) {
- ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
- @SuppressWarnings("rawtypes")
- 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);
- }
- }
- }
-
+ CodecMapping.setDispatchCodec(choiceCodec, dispatchCodec);
}
@Override
}
}
- public AugmentableDispatchCodec getAugmentableCodec(final Class<?> dataClass) {
+ public synchronized AugmentableDispatchCodec getAugmentableCodec(final Class<?> dataClass) {
AugmentableDispatchCodec ret = augmentableCodecs.get(dataClass);
if (ret != null) {
return ret;
return implementation;
}
- protected final void adaptForPath(final InstanceIdentifier<?> path) {
+ protected final synchronized void adaptForPath(final InstanceIdentifier<?> path) {
if (adaptedForPaths.contains(path)) {
return;
}
- Optional<DataNodeContainer> contextNode = BindingSchemaContextUtils.findDataNodeContainer(currentSchema, 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(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
+ */
+ instanceIdentifierCodec.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);
+ LOG.debug("Context node (parent node) not found for {}", path);
}
}
@SuppressWarnings("rawtypes")
private static class ChoiceCaseCodecImpl<T extends DataContainer> implements ChoiceCaseCodec<T>, //
Delegator<BindingCodec>, LocationAwareBindingCodec<Node<?>, ValueWithQName<T>> {
- private boolean augmenting;
- private boolean uses;
- private BindingCodec delegate;
-
- private Set<String> validNames;
- private Set<QName> validQNames;
- private ChoiceCaseNode schema;
- private Set<InstanceIdentifier<?>> applicableLocations;
+ private final BindingCodec delegate;
+ private final ChoiceCaseNode schema;
+ private final Map<InstanceIdentifier<?>, ChoiceCaseNode> instantiatedLocations;
+ private final Class<?> dataType;
@Override
public boolean isApplicable(final InstanceIdentifier location) {
- return applicableLocations.contains(location);
+ return instantiatedLocations.containsKey(location);
}
- public void setSchema(final ChoiceCaseNode caseNode) {
+ public ChoiceCaseCodecImpl(final Class<?> caseClass, final ChoiceCaseNode caseNode, final BindingCodec newInstance) {
+ this.delegate = newInstance;
+ this.dataType = caseClass;
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();
- uses = caseNode.isAddedByUses();
- applicableLocations = new HashSet<>();
- }
-
- public ChoiceCaseCodecImpl() {
- this.delegate = NOT_READY_CODEC;
- }
-
- public ChoiceCaseCodecImpl(final ChoiceCaseNode caseNode) {
- this.delegate = NOT_READY_CODEC;
- setSchema(caseNode);
+ instantiatedLocations = new HashMap<>();
}
@Override
@Override
public ValueWithQName<T> deserialize(final Node<?> input, final InstanceIdentifier<?> bindingIdentifier) {
- throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+ 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);
}
@Override
return delegate;
}
- public void setDelegate(final BindingCodec delegate) {
- this.delegate = delegate;
- }
-
public ChoiceCaseNode getSchema() {
return schema;
}
@Override
+ @Deprecated
public boolean isAcceptable(final Node<?> input) {
- if (input instanceof CompositeNode) {
- if (augmenting && !uses) {
- return checkAugmenting((CompositeNode) input);
- } else {
- return checkLocal((CompositeNode) input);
- }
- }
- return false;
+ return checkAgainstSchema(schema, input);
}
- @SuppressWarnings("deprecation")
- private boolean checkLocal(final 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;
+ 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 false;
}
- @SuppressWarnings("deprecation")
- private boolean checkAugmenting(final CompositeNode input) {
- for (Node<?> child : input.getChildren()) {
- if (validQNames.contains(child.getNodeType())) {
- return true;
- }
+ @Override
+ public Class<?> getDataType() {
+ return dataType;
+ }
+
+ public void adaptForPath(final InstanceIdentifier<?> augTarget, final ChoiceCaseNode choiceCaseNode) {
+ synchronized (instantiatedLocations) {
+ instantiatedLocations.put(augTarget, choiceCaseNode);
}
- return false;
}
- @Override
- public Class<?> getDataType() {
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not implemented Yet.");
+ public boolean isAcceptable(final InstanceIdentifier path, final CompositeNode input) {
+ ChoiceCaseNode instantiatedSchema = null;
+ synchronized (instantiatedLocations) {
+ instantiatedSchema = instantiatedLocations.get(path);
+ }
+ if (instantiatedSchema == null) {
+ return false;
+ }
+ return checkAgainstSchema(instantiatedSchema, input);
}
}
- private static class PublicChoiceCodecImpl<T> implements ChoiceCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
+ private static class PublicChoiceCodecImpl<T> implements ChoiceCodec<T>,
+ Delegator<BindingCodec<Map<QName, Object>, Object>> {
private final BindingCodec<Map<QName, Object>, Object> delegate;
private final Map<Class, ChoiceCaseCodecImpl<?>> cases = Collections
.synchronizedMap(new WeakHashMap<Class, ChoiceCaseCodecImpl<?>>());
- private final CaseCompositeNodeMapFacade CompositeToCase;
-
public PublicChoiceCodecImpl(final BindingCodec<Map<QName, Object>, Object> delegate) {
this.delegate = delegate;
- this.CompositeToCase = new CaseCompositeNodeMapFacade(cases);
}
@Override
throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
}
- public CaseCompositeNodeMapFacade getCompositeToCase() {
- return CompositeToCase;
- }
-
@Override
public BindingCodec<Map<QName, Object>, Object> getDelegate() {
return delegate;
}
- @SuppressWarnings("unused")
- private class DispatchChoiceCodecImpl extends LocationAwareDispatchCodec<ChoiceCaseCodecImpl<?>> {
-
- @Override
- public Object deserialize(final Object input, @SuppressWarnings("rawtypes") final InstanceIdentifier bindingIdentifier) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Object serialize(final Object input) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- protected ChoiceCaseCodecImpl<?> tryToLoadImplementation(final Class<? extends DataContainer> inputType) {
- return getCaseCodecFor(inputType);
- }
-
- @Override
- protected void tryToLoadImplementations() {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- protected void adaptForPathImpl(final InstanceIdentifier<?> path, final DataNodeContainer ctx) {
- // TODO Auto-generated method stub
-
- }
- }
-
- @SuppressWarnings("rawtypes")
- private class CaseClassMapFacade extends MapFacadeBase {
+ class DispatchChoiceCodecImpl extends LocationAwareDispatchCodec<ChoiceCaseCodecImpl<?>> {
+ private final Class<?> choiceType;
+ private final QName choiceName;
- @Override
- public Set<Entry<Class, BindingCodec<Object, Object>>> entrySet() {
- return Collections.emptySet();
+ private DispatchChoiceCodecImpl(final Class<?> type) {
+ choiceType = type;
+ choiceName = BindingReflections.findQName(type);
}
@Override
- public BindingCodec get(final Object key) {
- if (key instanceof Class) {
- Class cls = (Class) key;
- // bindingClassEncountered(cls);
- ChoiceCaseCodecImpl caseCodec = getCaseCodecFor(cls);
- return caseCodec.getDelegate();
- }
- return null;
- }
- }
-
- @SuppressWarnings("rawtypes")
- private static class CaseCompositeNodeMapFacade extends MapFacadeBase<CompositeNode> {
-
- final Map<Class, ChoiceCaseCodecImpl<?>> choiceCases;
-
- public CaseCompositeNodeMapFacade(final Map<Class, ChoiceCaseCodecImpl<?>> choiceCases) {
- this.choiceCases = choiceCases;
- }
+ public Object deserialize(final Object input, @SuppressWarnings("rawtypes") final InstanceIdentifier path) {
+ adaptForPath(path);
- @Override
- public BindingCodec get(final Object key) {
- if (!(key instanceof CompositeNode)) {
- return null;
- }
- for (Entry<Class, ChoiceCaseCodecImpl<?>> entry : choiceCases.entrySet()) {
- ChoiceCaseCodecImpl<?> codec = entry.getValue();
- if (codec.isAcceptable((CompositeNode) key)) {
- return codec.getDelegate();
+ if (input instanceof CompositeNode) {
+ List<Entry<Class, ChoiceCaseCodecImpl<?>>> codecs = new ArrayList<>(getImplementations().entrySet());
+ for (Entry<Class, ChoiceCaseCodecImpl<?>> codec : codecs) {
+ ChoiceCaseCodecImpl<?> caseCodec = codec.getValue();
+ if (caseCodec.isAcceptable(path, (CompositeNode) input)) {
+ ValueWithQName<?> value = caseCodec.deserialize((CompositeNode) input, path);
+ if (value != null) {
+ return value.getValue();
+ }
+ return null;
+ }
}
}
return null;
}
- }
-
- /**
- * 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 abstract static class MapFacadeBase<T> implements Map<T, BindingCodec<?, ?>> {
-
- @Override
- public boolean containsKey(final Object key) {
- return get(key) != null;
- }
-
- @Override
- public void clear() {
- throw notModifiable();
- }
-
- @Override
- public boolean equals(final Object obj) {
- return super.equals(obj);
- }
-
- @Override
- public BindingCodec remove(final Object key) {
- return null;
- }
-
+ @SuppressWarnings("unchecked")
@Override
- public int size() {
- return 0;
+ public Object serialize(final Object input) {
+ Preconditions.checkArgument(input instanceof Map.Entry<?, ?>, "Input must be QName, Value");
+ @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(isAugmenting(codec.getSchema())) {
+ // 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 Collection<BindingCodec<?, ?>> values() {
- return Collections.emptySet();
+ private boolean isAugmenting(final ChoiceCaseNode schema) {
+ if(schema.isAugmenting()) {
+ return true;
+ }
+ QName parentQName = Iterables.get(schema.getPath().getPathTowardsRoot(), 2); // choice QName
+ if(!parentQName.getNamespace().equals(schema.getQName().getNamespace())) {
+ return true;
+ }
+ return false;
}
- private UnsupportedOperationException notModifiable() {
- return new UnsupportedOperationException("Not externally modifiable.");
+ @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 BindingCodec<Map<QName, Object>, Object> put(final T key, final BindingCodec<?, ?> value) {
- throw notModifiable();
+ protected ChoiceCaseCodecImpl<?> tryToLoadImplementation(final Class<? extends DataContainer> inputType) {
+ ChoiceCaseCodecImpl<?> codec = getCaseCodecFor(inputType);
+ addImplementation(codec);
+ return codec;
}
@Override
- public void putAll(final Map<? extends T, ? extends BindingCodec<?, ?>> m) {
- throw notModifiable();
+ 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 int hashCode() {
- return super.hashCode();
+ protected void adaptForPathImpl(final InstanceIdentifier<?> augTarget, final DataNodeContainer ctxNode) {
+ Optional<ChoiceNode> newChoice = findInstantiatedChoice(ctxNode, choiceName);
+ tryToLoadImplementations();
+ if (newChoice.isPresent()) {
+ for (@SuppressWarnings("rawtypes")
+ Entry<Class, ChoiceCaseCodecImpl<?>> codec : getImplementations().entrySet()) {
+ ChoiceCaseCodecImpl<?> caseCodec = codec.getValue();
+ Optional<ChoiceCaseNode> instantiatedSchema = findInstantiatedCase(newChoice.get(),
+ caseCodec.getSchema());
+ if (instantiatedSchema.isPresent()) {
+ caseCodec.adaptForPath(augTarget, instantiatedSchema.get());
+ }
+ }
+ }
}
- @Override
- public boolean isEmpty() {
- return true;
- }
+ private Optional<ChoiceNode> findInstantiatedChoice(final DataNodeContainer ctxNode, final QName choiceName) {
+ DataSchemaNode potential = ctxNode.getDataChildByName(choiceName);
+ if (potential == null) {
+ potential = ctxNode.getDataChildByName(choiceName.getLocalName());
+ }
- @Override
- public Set<T> keySet() {
- return Collections.emptySet();
- }
+ if (potential instanceof ChoiceNode) {
+ return Optional.of((ChoiceNode) potential);
+ }
- @Override
- public Set<Entry<T, BindingCodec<?, ?>>> entrySet() {
- return Collections.emptySet();
+ return Optional.absent();
}
- @Override
- public boolean containsValue(final Object value) {
- return false;
+ private Optional<ChoiceCaseNode> findInstantiatedCase(final ChoiceNode newChoice, final ChoiceCaseNode schema) {
+ ChoiceCaseNode potential = newChoice.getCaseNodeByName(schema.getQName());
+ if (potential != null) {
+ return Optional.of(potential);
+ }
+ // FIXME: Probably requires more extensive check
+ // e.g. we have one choice and two augmentations from different
+ // modules using same local name
+ // but different namespace / contents
+ return Optional.fromNullable(newChoice.getCaseNodeByName(schema.getQName().getLocalName()));
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
- private class AugmentableDispatchCodec extends LocationAwareDispatchCodec<AugmentationCodecWrapper> {
+ class AugmentableDispatchCodec extends LocationAwareDispatchCodec<AugmentationCodecWrapper> {
private final Class augmentableType;
.loadClass(potential);
return Optional.of(tryToLoadImplementation(clazz));
} catch (ClassNotFoundException e) {
- LOG.warn("Failed to find class for augmentation of {}, reason: {}", potential, e.toString());
+ LOG.warn("Failed to find class for augmentation of {}", potential, e);
}
return Optional.absent();
}
AugmentationCodecWrapper<? extends Augmentation<?>> potentialImpl = getCodecForAugmentation(inputType);
addImplementation(potentialImpl);
return potentialImpl;
-
}
@Override
protected void tryToLoadImplementations() {
Type type = referencedType(augmentableType);
Collection<Type> potentialAugmentations;
- synchronized(augmentableToAugmentations) {
+ 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 coded for {}, reason: {}", type, e.toString());
+ LOG.warn("Failed to proactively generate augment code for {}", type, e);
}
}
-
}
@Override
- protected void adaptForPathImpl(final InstanceIdentifier<?> path, final DataNodeContainer ctxNode) {
+ protected void adaptForPathImpl(final InstanceIdentifier<?> augTarget, final DataNodeContainer ctxNode) {
if (ctxNode instanceof AugmentationTarget) {
Set<AugmentationSchema> availableAugmentations = ((AugmentationTarget) ctxNode)
.getAvailableAugmentations();
if (!availableAugmentations.isEmpty()) {
- updateAugmentationMapping(path,availableAugmentations);
+ updateAugmentationMapping(augTarget, availableAugmentations);
}
-
}
}
- private void updateAugmentationMapping(final InstanceIdentifier<?> path, final Set<AugmentationSchema> 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(path,aug);
+ potentialImpl.get().addApplicableFor(augTarget, aug);
+ Class augType = potentialImpl.get().getDataType();
+ InstanceIdentifier augPath = augTarget.augmentation(augType);
+ try {
+
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = 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 {
- LOG.warn("Could not find generated type for augmentation {} with childs {}.",aug,aug.getChildNodes());
+ // 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());
+ }
}
}
- availableAugmentations.toString();
}
+
+
private Type getTypeForAugmentation(final AugmentationSchema aug) {
Optional<AugmentationSchema> currentAug = Optional.of(aug);
- while(currentAug.isPresent()) {
+ while (currentAug.isPresent()) {
Type potentialType = typeToAugment.inverse().get(currentAug.get());
- if(potentialType != null) {
+ if (potentialType != null) {
return potentialType;
}
currentAug = currentAug.get().getOriginalDefinition();
}
}
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private static class LateMixinCodec implements BindingCodec, Delegator<BindingCodec> {
-
- private BindingCodec delegate;
-
- @Override
- public BindingCodec getDelegate() {
- if (delegate == null) {
- throw new IllegalStateException("Codec not initialized yet.");
- }
- return delegate;
- }
-
- @Override
- public Object deserialize(final Object input) {
- return getDelegate().deserialize(input);
- }
-
- @Override
- public Object deserialize(final Object input, final InstanceIdentifier bindingIdentifier) {
- return getDelegate().deserialize(input, bindingIdentifier);
- }
-
- @Override
- public Object serialize(final Object input) {
- return getDelegate().serialize(input);
- }
-
- }
-
@SuppressWarnings("rawtypes")
private static class AugmentationCodecWrapper<T extends Augmentation<?>> implements AugmentationCodec<T>,
Delegator<BindingCodec>, LocationAwareBindingCodec<Node<?>, ValueWithQName<T>> {
private final BindingCodec delegate;
private final QName augmentationQName;
- private final Multimap<InstanceIdentifier<?>,QName> validAugmentationTargets;
+ private final Multimap<InstanceIdentifier<?>, QName> validAugmentationTargets;
private final Class<?> augmentationType;
- public AugmentationCodecWrapper(final BindingCodec<Map<QName, Object>, Object> rawCodec,
- final InstanceIdentifier<?> targetId, final Class<?> dataType) {
+ 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());
+ 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());
+ for (DataSchemaNode child : aug.getChildNodes()) {
+ validAugmentationTargets.put(path, child.getQName());
}
}
}
@Override
- public Object deserialize(final Object input,final InstanceIdentifier bindingIdentifier) {
+ public Object deserialize(final Object input, final InstanceIdentifier bindingIdentifier) {
Type type = qnamesToIdentityMap.get(input);
if (type == null) {
return null;
}
- public boolean isCodecAvailable(final 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;
- }
-
- public static final Type referencedType(final Class<?> augmentableType) {
+ private static final Type referencedType(final Class<?> augmentableType) {
return new ReferencedTypeImpl(augmentableType.getPackage().getName(), augmentableType.getSimpleName());
}
}