X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=code-generator%2Fbinding-generator-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fsal%2Fbinding%2Fgenerator%2Fimpl%2FLazyGeneratedCodecRegistry.java;h=f70b168e299b0dead41c27b5b30b61f68d66e214;hb=f4a1cd91e68daeeaeed50984e9ab8fb45ba0223b;hp=edc186e0ebe0dbe5aabd5305502508f0a2abae6d;hpb=607a44f23acde9c0f13f9375b2fcda157605cbbc;p=yangtools.git diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java index edc186e0eb..f70b168e29 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java @@ -7,8 +7,17 @@ */ package org.opendaylight.yangtools.sal.binding.generator.impl; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.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.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; @@ -18,12 +27,10 @@ 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.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; @@ -33,11 +40,11 @@ import org.opendaylight.yangtools.sal.binding.generator.util.CodeGenerationExcep 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; @@ -68,26 +75,18 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; 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 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.Multimap; -import com.google.common.collect.Multimaps; - class LazyGeneratedCodecRegistry implements // CodecRegistry, // SchemaContextListener, // GeneratorListener { private static final Logger LOG = LoggerFactory.getLogger(LazyGeneratedCodecRegistry.class); - private static final LateMixinCodec NOT_READY_CODEC = new LateMixinCodec(); // Concrete class to codecs private static final Map, DataContainerCodec> containerCodecs = Collections @@ -102,6 +101,10 @@ class LazyGeneratedCodecRegistry implements // .synchronizedMap(new WeakHashMap, AugmentableDispatchCodec>()); private static final Map, AugmentationCodecWrapper> augmentationCodecs = Collections .synchronizedMap(new WeakHashMap, AugmentationCodecWrapper>()); + + private static final Map, LocationAwareDispatchCodec> dispatchCodecs = Collections + .synchronizedMap(new WeakHashMap, LocationAwareDispatchCodec>()); + private static final Map, QName> identityQNames = Collections .synchronizedMap(new WeakHashMap, QName>()); private static final Map qnamesToIdentityMap = new ConcurrentHashMap<>(); @@ -109,10 +112,9 @@ class LazyGeneratedCodecRegistry implements // @SuppressWarnings("rawtypes") private static final Map> typeToClass = new ConcurrentHashMap<>(); - @SuppressWarnings("rawtypes") - private static final ConcurrentMap typeToCaseCodecs = new ConcurrentHashMap<>(); + private static final ConcurrentMap caseTypeToCaseSchema = new ConcurrentHashMap<>(); - private static final Map pathToType = new ConcurrentHashMap<>(); + private static final Map pathToType = new ConcurrentHashMap<>(); private static final Map, Type> pathToInstantiatedType = new ConcurrentHashMap<>(); private static final Map typeToQname = new ConcurrentHashMap<>(); private static final BiMap typeToAugment = HashBiMap @@ -124,7 +126,6 @@ class LazyGeneratedCodecRegistry implements // . create()); private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this); - private final CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade(); private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec(); private final ClassLoadingStrategy classLoadingStrategy; private final AbstractTransformerGenerator generator; @@ -151,35 +152,36 @@ class LazyGeneratedCodecRegistry implements // @SuppressWarnings("unchecked") @Override - public > AugmentationCodecWrapper getCodecForAugmentation(final Class object) { + public > AugmentationCodecWrapper getCodecForAugmentation(final Class augClass) { AugmentationCodecWrapper 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, Object>> augmentRawCodec = generator - .augmentationTransformerFor(object); - BindingCodec, Object> rawCodec = augmentRawCodec.newInstance(); - - codec = new AugmentationCodecWrapper(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, Object>> augmentRawCodec = generator + .augmentationTransformerFor(augClass); + + BindingCodec, Object> rawCodec = newInstanceOf(augmentRawCodec); + codec = new AugmentationCodecWrapper(rawCodec, augClass); + augmentationCodecs.put(augClass, codec); } - Class> objectSupertype = getAugmentableArgumentFrom(object); - if (objectSupertype != null) { - getAugmentableCodec(objectSupertype).addImplementation(codec); - } else { - LOG.warn("Could not find augmentation target for augmentation {}", object); + + final Class> 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; } @@ -190,21 +192,14 @@ class LazyGeneratedCodecRegistry implements // return getCodecForAugmentation((Class>) cls).getAugmentationQName(); } - private static Class> getAugmentableArgumentFrom( - final Class> augmentation) { - try { - Class> 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 names) { - final DataSchemaNode node = getSchemaNode(names); + DataSchemaNode node = getSchemaNode(names); + 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); @@ -218,8 +213,14 @@ class LazyGeneratedCodecRegistry implements // @SuppressWarnings("rawtypes") final WeakReference 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(); + if(weakRef != null) { + return weakRef.get(); + } + 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())); + } } @Override @@ -263,10 +264,9 @@ class LazyGeneratedCodecRegistry implements // WeakReference weakRef = new WeakReference<>(cls); typeToClass.put(typeRef, weakRef); if (Augmentation.class.isAssignableFrom(cls)) { - + // Intentionally NOOP } else if (DataObject.class.isAssignableFrom(cls)) { - @SuppressWarnings({ "unchecked", "unused" }) - Object cdc = getCodecForDataObject((Class) cls); + getCodecForDataObject((Class) cls); } } @@ -286,6 +286,8 @@ class LazyGeneratedCodecRegistry implements // 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 iterator = path.iterator(); while (iterator.hasNext()) { QName arg = iterator.next(); @@ -328,15 +330,19 @@ class LazyGeneratedCodecRegistry implements // return null; } - private T newInstanceOf(final Class newType) { + private static 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); } } @@ -396,22 +402,14 @@ class LazyGeneratedCodecRegistry implements // 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()); - Class newCodec = generator.caseCodecFor(caseClass, caseCodec.getSchema()); + Preconditions.checkState(caseSchema != null, "Case schema is not available for %s", caseClass.getName()); + Class 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, PublicChoiceCodecImpl> choice : choiceCodecs.entrySet()) { - if (choice.getKey().isAssignableFrom(caseClass)) { - choice.getValue().cases.put(caseClass, caseCodec); - } - } return caseCodec; } @@ -435,41 +433,39 @@ class LazyGeneratedCodecRegistry implements // 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 cases, final SchemaContext module) { - for (Entry 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()); } } @Override 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" }) @@ -480,43 +476,12 @@ class LazyGeneratedCodecRegistry implements // Preconditions.checkState(oldCodec == null); BindingCodec, Object> delegate = newInstanceOf(choiceCodec); 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); - - } - - @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); - } - } + synchronized (dispatchCodecs) { + dispatchCodecs.put(choiceClass, dispatchCodec); } - + CodecMapping.setDispatchCodec(choiceCodec, dispatchCodec); } @Override @@ -537,13 +502,16 @@ class LazyGeneratedCodecRegistry implements // } } - public AugmentableDispatchCodec getAugmentableCodec(final Class dataClass) { + public synchronized AugmentableDispatchCodec getAugmentableCodec(final Class dataClass) { AugmentableDispatchCodec ret = augmentableCodecs.get(dataClass); if (ret != null) { return ret; } - ret = new AugmentableDispatchCodec(dataClass); + ret = new AugmentableDispatchCodec(dataClass,this); augmentableCodecs.put(dataClass, ret); + synchronized (dispatchCodecs) { + dispatchCodecs.put(dataClass, ret); + } ret.tryToLoadImplementations(); return ret; } @@ -638,22 +606,51 @@ class LazyGeneratedCodecRegistry implements // private interface LocationAwareBindingCodec extends BindingCodec { - boolean isApplicable(InstanceIdentifier location); + boolean isApplicable(InstanceIdentifier parentPath, CompositeNode data); public Class getDataType(); } @SuppressWarnings("rawtypes") - private abstract class LocationAwareDispatchCodec implements BindingCodec { + private static abstract class LocationAwareDispatchCodec implements BindingCodec { private final Map implementations = Collections.synchronizedMap(new WeakHashMap()); private final Set> adaptedForPaths = new HashSet<>(); + private LazyGeneratedCodecRegistry registry; + + + protected LocationAwareDispatchCodec(final LazyGeneratedCodecRegistry registry) { + this.registry = registry; + } protected Map getImplementations() { return implementations; } + /** + * 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(); + } + + protected void resetAdaptationImpl() { + // Intentionally NOOP, subclasses may specify their custom + // behaviour. + } + + protected final LazyGeneratedCodecRegistry getRegistry() { + return registry; + } protected void addImplementation(final T implementation) { implementations.put(implementation.getDataType(), implementation); } @@ -663,6 +660,40 @@ class LazyGeneratedCodecRegistry implements // throw new UnsupportedOperationException("Invocation of deserialize without Tree location is unsupported"); } + @Override + 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 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); + } + } + 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); + } + + protected abstract Object deserializeImpl(final CompositeNode input, final InstanceIdentifier parentPath, + Iterable applicableCodecs); + @Override public Object serialize(final Object input) { Preconditions.checkArgument(input instanceof DataContainer); @@ -682,43 +713,50 @@ class LazyGeneratedCodecRegistry implements // return implementation; } - protected final void adaptForPath(final InstanceIdentifier path) { + 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) + * We search in schema context if the use of this location aware + * codec (augmentable codec, case codec) makes sense on provided + * location (path) * */ - Optional contextNode = BindingSchemaContextUtils.findDataNodeContainer(currentSchema, path); + Optional contextNode = BindingSchemaContextUtils.findDataNodeContainer(getRegistry().currentSchema, + path); /** - * If context node is present, this codec makes sense on provided location. + * 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. + * We adapt (turn on / off) possible implementations of + * child codecs (augmentations, cases) based on this + * location. * * */ + adaptForPathImpl(path, contextNode.get()); - try { + try { /** - * We trigger serialization of instance identifier, to make sure instance identifier - * codec is aware of combination of this path / augmentation / case + * We trigger serialization of instance identifier, to + * make sure instance identifier codec is aware of + * combination of this path / augmentation / case */ - instanceIdentifierCodec.serialize(path); + getRegistry().getInstanceIdentifierCodec().serialize(path); } catch (Exception e) { - LOG.warn("Exception during preparation of instance identifier codec for path {}.",path,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); } } @@ -732,41 +770,17 @@ class LazyGeneratedCodecRegistry implements // @SuppressWarnings("rawtypes") private static class ChoiceCaseCodecImpl implements ChoiceCaseCodec, // Delegator, LocationAwareBindingCodec, ValueWithQName> { - private boolean augmenting; - private boolean uses; - private BindingCodec delegate; - - private Set validNames; - private Set validQNames; - private ChoiceCaseNode schema; - private Set> applicableLocations; - - @Override - public boolean isApplicable(final InstanceIdentifier location) { - return applicableLocations.contains(location); - } - - public void setSchema(final ChoiceCaseNode caseNode) { + private final BindingCodec delegate; + private final ChoiceCaseNode schema; + private final Map, 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; - 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 @@ -776,7 +790,19 @@ class LazyGeneratedCodecRegistry implements // @Override public ValueWithQName 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(qname, value); } @Override @@ -789,72 +815,94 @@ class LazyGeneratedCodecRegistry implements // 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 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 false; } - @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; - } + @Override + public Class getDataType() { + return dataType; + } + + public void adaptForPath(final InstanceIdentifier augTarget, final ChoiceCaseNode choiceCaseNode) { + synchronized (instantiatedLocations) { + instantiatedLocations.put(augTarget, choiceCaseNode); } - return false; } - @SuppressWarnings("deprecation") - private boolean checkAugmenting(final CompositeNode input) { - for (Node child : input.getChildren()) { - if (validQNames.contains(child.getNodeType())) { - return true; + @Override + 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; + } + 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 false; } @Override - public Class getDataType() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Not implemented Yet."); + public String toString() { + return "ChoiceCaseCodec [case=" + dataType + + ", knownLocations=" + instantiatedLocations.keySet() + "]"; } } - private static class PublicChoiceCodecImpl implements ChoiceCodec, Delegator, Object>> { + private static class PublicChoiceCodecImpl implements ChoiceCodec, + Delegator, Object>> { private final BindingCodec, Object> delegate; - @SuppressWarnings("rawtypes") - private final Map> cases = Collections - .synchronizedMap(new WeakHashMap>()); - - private final CaseCompositeNodeMapFacade CompositeToCase; - public PublicChoiceCodecImpl(final BindingCodec, Object> delegate) { this.delegate = delegate; - this.CompositeToCase = new CaseCompositeNodeMapFacade(cases); } @Override @@ -872,10 +920,6 @@ class LazyGeneratedCodecRegistry implements // throw new UnsupportedOperationException("Direct invocation of this codec is not allowed."); } - public CaseCompositeNodeMapFacade getCompositeToCase() { - return CompositeToCase; - } - @Override public BindingCodec, Object> getDelegate() { return delegate; @@ -883,178 +927,154 @@ class LazyGeneratedCodecRegistry implements // } - @SuppressWarnings("unused") - private class DispatchChoiceCodecImpl extends LocationAwareDispatchCodec> { + class DispatchChoiceCodecImpl extends LocationAwareDispatchCodec> { + private final Class choiceType; + private final QName choiceName; - @Override - public Object deserialize(final Object input, @SuppressWarnings("rawtypes") final InstanceIdentifier bindingIdentifier) { - // TODO Auto-generated method stub - return null; + private DispatchChoiceCodecImpl(final Class type, final LazyGeneratedCodecRegistry registry) { + super(registry); + choiceType = type; + choiceName = BindingReflections.findQName(type); } @Override - public Object serialize(final Object input) { - // TODO Auto-generated method stub + public Object deserializeImpl(final CompositeNode input, final InstanceIdentifier path, + final Iterable> codecs) { + ChoiceCaseCodecImpl caseCodec = Iterables.getOnlyElement(codecs); + ValueWithQName value = caseCodec.deserialize(input, path); + if (value != null) { + return value.getValue(); + } return null; } + @SuppressWarnings("unchecked") @Override - protected ChoiceCaseCodecImpl tryToLoadImplementation(final Class inputType) { - return getCaseCodecFor(inputType); + 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 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 - protected void tryToLoadImplementations() { - // TODO Auto-generated method stub - + @SuppressWarnings("rawtypes") + protected Optional tryToLoadImplementation(final Type potential) { + try { + @SuppressWarnings("unchecked") + Class clazz = (Class) 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 - protected void adaptForPathImpl(final InstanceIdentifier path, final DataNodeContainer ctx) { - // TODO Auto-generated method stub - + protected ChoiceCaseCodecImpl tryToLoadImplementation(final Class inputType) { + ChoiceCaseCodecImpl codec = getCaseCodecFor(inputType); + addImplementation(codec); + return codec; } - } - - @SuppressWarnings("rawtypes") - private class CaseClassMapFacade extends MapFacadeBase { @Override - public Set>> entrySet() { - return Collections.emptySet(); + protected void tryToLoadImplementations() { + Type type = referencedType(choiceType); + Collection 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 BindingCodec get(final Object key) { - if (key instanceof Class) { - Class cls = (Class) key; - // bindingClassEncountered(cls); - ChoiceCaseCodecImpl caseCodec = getCaseCodecFor(cls); - return caseCodec.getDelegate(); + protected void adaptForPathImpl(final InstanceIdentifier augTarget, final DataNodeContainer ctxNode) { + Optional newChoice = BindingSchemaContextUtils.findInstantiatedChoice(ctxNode, choiceType); + tryToLoadImplementations(); + Preconditions.checkState(newChoice.isPresent(), "BUG: Unable to find instantiated choice node in schema."); + for (@SuppressWarnings("rawtypes") + Entry> codec : getImplementations().entrySet()) { + ChoiceCaseCodecImpl caseCodec = codec.getValue(); + Optional instantiatedSchema = BindingSchemaContextUtils.findInstantiatedCase(newChoice.get(), + caseCodec.getSchema()); + if (instantiatedSchema.isPresent()) { + caseCodec.adaptForPath(augTarget, instantiatedSchema.get()); + } } - return null; } - } - @SuppressWarnings("rawtypes") - private static class CaseCompositeNodeMapFacade extends MapFacadeBase { - final Map> choiceCases; - - public CaseCompositeNodeMapFacade(final Map> choiceCases) { - this.choiceCases = choiceCases; - } @Override - public BindingCodec get(final Object key) { - if (!(key instanceof CompositeNode)) { - return null; - } - for (Entry> entry : choiceCases.entrySet()) { - ChoiceCaseCodecImpl codec = entry.getValue(); - if (codec.isAcceptable((CompositeNode) key)) { - return codec.getDelegate(); - } - } - return null; + public String toString() { + return "DispatchChoiceCodecImpl [choiceType=" + choiceType + "]"; } - } /** - * 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 - * Key type + * Dispatch codec for augmented object, which processes augmentations + *

+ * This codec is used from DataObject codec generated using + * {@link TransformerGenerator#transformerFor(Class)} and is wired + * during {@link LazyGeneratedCodecRegistry#onDataContainerCodecCreated(Class, Class)}. + *

+ * Instance of this codec is associated with class of Binding DTO which + * represents target for augmentations. + * */ - @SuppressWarnings("rawtypes") - private abstract static class MapFacadeBase implements Map> { - - @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; - } - - @Override - public int size() { - return 0; - } - - @Override - public Collection> values() { - return Collections.emptySet(); - } - - private UnsupportedOperationException notModifiable() { - return new UnsupportedOperationException("Not externally modifiable."); - } - - @Override - public BindingCodec, Object> put(final T key, final BindingCodec value) { - throw notModifiable(); - } - - @Override - public void putAll(final Map> m) { - throw notModifiable(); - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public Set keySet() { - return Collections.emptySet(); - } - - @Override - public Set>> entrySet() { - return Collections.emptySet(); - } - - @Override - public boolean containsValue(final Object value) { - return false; - } - } - @SuppressWarnings({ "rawtypes", "unchecked" }) - private class AugmentableDispatchCodec extends LocationAwareDispatchCodec { + static class AugmentableDispatchCodec extends LocationAwareDispatchCodec { private final Class augmentableType; - public AugmentableDispatchCodec(final 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 - // TODO deprecate use without iid 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 augmentations = getAugmentations(input); return serializeImpl(augmentations); @@ -1062,6 +1082,15 @@ class LazyGeneratedCodecRegistry implements // return null; } + /** + * + * Extracts augmentation from Binding DTO field using reflection + * + * @param input Instance of DataObject which is augmentable and + * may contain augmentation + * @return Map of augmentations if read was successful, otherwise + * empty map. + */ private Map getAugmentations(final Object input) { Field augmentationField; try { @@ -1075,143 +1104,186 @@ class LazyGeneratedCodecRegistry implements // return Collections.emptyMap(); } + /** + * + * 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. + */ @SuppressWarnings("deprecation") private List serializeImpl(final Map input) { List ret = new ArrayList<>(); for (Entry entry : input.entrySet()) { - AugmentationCodec codec = getCodecForAugmentation(entry.getKey()); + AugmentationCodec codec = getRegistry().getCodecForAugmentation(entry.getKey()); CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue())); ret.addAll(node.getChildren()); } return ret; } - @Override - public Map deserialize(final Object input, final InstanceIdentifier path) { - adaptForPath(path); + /** + * + * 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 path, + * selected by caller to be used by deserialization + * + * + */ + @Override + public Map deserializeImpl(final CompositeNode input, final InstanceIdentifier path, + final Iterable codecs) { + LOG.trace("{}: Going to deserialize augmentations from {} in location {}. Available codecs {}",this,input,path,codecs); Map ret = new HashMap<>(); - - if (input instanceof CompositeNode) { - List> codecs = new ArrayList<>(getImplementations().entrySet()); - for (Entry codec : codecs) { - AugmentationCodec ac = codec.getValue(); - if (ac.isAcceptable(path)) { - // We add Augmentation Identifier to path, in order to - // correctly identify children. - InstanceIdentifier augmentPath = path.builder().augmentation(codec.getKey()).build(); - ValueWithQName value = codec.getValue().deserialize((CompositeNode) input, augmentPath); - 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; } + /** + * + * 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 tryToLoadImplementation(final Type potential) { try { - Class> clazz = (Class>) classLoadingStrategy + Class> clazz = (Class>) getRegistry().classLoadingStrategy .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(); } @Override protected AugmentationCodecWrapper tryToLoadImplementation(final Class inputType) { - AugmentationCodecWrapper> potentialImpl = getCodecForAugmentation(inputType); + AugmentationCodecWrapper> potentialImpl = getRegistry().getCodecForAugmentation(inputType); addImplementation(potentialImpl); return potentialImpl; - } @Override protected void tryToLoadImplementations() { Type type = referencedType(augmentableType); Collection 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 availableAugmentations = ((AugmentationTarget) ctxNode) .getAvailableAugmentations(); if (!availableAugmentations.isEmpty()) { - updateAugmentationMapping(path,availableAugmentations); + updateAugmentationMapping(augTarget, availableAugmentations); } - } } - private void updateAugmentationMapping(final InstanceIdentifier path, final Set 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: + *

    + *
  1. scan of available (valid) augmentations for current location + *
  2. lookup for Java classes derived from this augmentations + *
  3. generation of missing codecs + *
  4. updating Augmentation codecs to work with new location + *
  5. updating Instance Identifier to work with new location + * + */ + private void updateAugmentationMapping(final InstanceIdentifier augTarget, + final Set availableAugmentations) { for (AugmentationSchema aug : availableAugmentations) { Type potentialType = getTypeForAugmentation(aug); if (potentialType != null) { Optional 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 = 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 { - 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 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(); } return null; } - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private static class LateMixinCodec implements BindingCodec, Delegator { - - 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); + public String toString() { + return "AugmentableDispatchCodec [augmentable=" + augmentableType + "]"; } } @@ -1222,20 +1294,20 @@ class LazyGeneratedCodecRegistry implements // private final BindingCodec delegate; private final QName augmentationQName; - private final Multimap,QName> validAugmentationTargets; + private final Multimap, QName> validAugmentationTargets; private final Class augmentationType; - public AugmentationCodecWrapper(final BindingCodec, Object> rawCodec, - final InstanceIdentifier targetId, final Class dataType) { + public AugmentationCodecWrapper(final BindingCodec, Object> rawCodec, final Class dataType) { this.delegate = rawCodec; this.augmentationType = dataType; this.augmentationQName = BindingReflections.findQName(rawCodec.getClass()); - this.validAugmentationTargets = Multimaps.synchronizedSetMultimap(HashMultimap.,QName>create()); + this.validAugmentationTargets = Multimaps.synchronizedSetMultimap(HashMultimap + ., 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()); } } @@ -1265,9 +1337,6 @@ class LazyGeneratedCodecRegistry implements // @Override @SuppressWarnings("unchecked") public ValueWithQName deserialize(final Node input, final InstanceIdentifier bindingIdentifier) { - // if (!isAcceptable(bindingIdentifier)) { - // return null; - // } Object rawCodecValue = getDelegate().deserialize(input, bindingIdentifier); return new ValueWithQName(input.getNodeType(), (T) rawCodecValue); } @@ -1286,14 +1355,20 @@ class LazyGeneratedCodecRegistry implements // } @Override - public boolean isApplicable(final InstanceIdentifier location) { - return isAcceptable(location); + 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") @@ -1307,9 +1382,14 @@ class LazyGeneratedCodecRegistry implements // @Override 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 softref = typeToClass.get(typeref); @@ -1331,10 +1411,10 @@ class LazyGeneratedCodecRegistry implements // } @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; + throw new IllegalArgumentException( "Invalid for \"" + input + "\"." ); } ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName()); WeakReference softref = typeToClass.get(typeref); @@ -1363,8 +1443,7 @@ class LazyGeneratedCodecRegistry implements // 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); } @@ -1379,32 +1458,7 @@ class LazyGeneratedCodecRegistry implements // } - public boolean isCodecAvailable(final Class cls) { - // FIXME: enforce type? - // Preconditions.checkArgument(DataContainer.class.isAssignableFrom(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()); } }