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
.synchronizedMap(new WeakHashMap<Class<?>, DataContainerCodec<?>>());
@SuppressWarnings("rawtypes")
private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
- private final CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
-
- private static final Map<SchemaPath, InstanceIdentifier<?>> pathToBindingIdentifier = new ConcurrentHashMap<>();
- private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+ private static final Map<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 CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
+ private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec();
+ private final ClassLoadingStrategy classLoadingStrategy;
+ private final AbstractTransformerGenerator generator;
private final SchemaLock lock;
+ // FIXME: how is this protected?
private SchemaContext currentSchema;
- private final ClassLoadingStrategy classLoadingStrategy;
-
- LazyGeneratedCodecRegistry(final SchemaLock lock, final ClassLoadingStrategy identityClassLoadingStrategy) {
+ LazyGeneratedCodecRegistry(final SchemaLock lock, final AbstractTransformerGenerator generator,
+ final ClassLoadingStrategy classLoadingStrategy) {
this.lock = Preconditions.checkNotNull(lock);
- this.classLoadingStrategy = identityClassLoadingStrategy;
+ this.classLoadingStrategy = Preconditions.checkNotNull(classLoadingStrategy);
+ this.generator = Preconditions.checkNotNull(generator);
}
public SchemaLock getLock() {
return lock;
}
- public TransformerGenerator getGenerator() {
- return generator;
- }
-
- public void setGenerator(final TransformerGenerator generator) {
- this.generator = generator;
- }
-
@Override
public InstanceIdentifierCodec getInstanceIdentifierCodec() {
return instanceIdentifierCodec;
@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);
}
}
caseClass.getName());
Preconditions.checkState(caseCodec.getSchema() != null, "Case schema is not available for %s",
caseClass.getName());
- @SuppressWarnings("unchecked")
Class<? extends BindingCodec> newCodec = generator.caseCodecFor(caseClass, caseCodec.getSchema());
BindingCodec newInstance = newInstanceOf(newCodec);
caseCodec.setDelegate(newInstance);
identity.getKey());
}
- synchronized(augmentableToAugmentations) {
+ synchronized (augmentableToAugmentations) {
augmentableToAugmentations.putAll(context.getAugmentableToAugmentations());
}
- synchronized(choiceToCases) {
+ synchronized (choiceToCases) {
choiceToCases.putAll(context.getChoiceToCases());
}
captureCases(context.getCases(), schemaContext);
}
SchemaPath path = caseNode.getPath();
- GeneratedTypeBuilder type;
+ Type type;
if (path != null && (type = pathToType.get(path)) != null) {
ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
@SuppressWarnings("rawtypes")
}
}
- 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);
}
}
}
}
- 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 class DispatchChoiceCodecImpl extends LocationAwareDispatchCodec<ChoiceCaseCodecImpl<?>> {
@Override
- public Object deserialize(final Object input, @SuppressWarnings("rawtypes") final InstanceIdentifier bindingIdentifier) {
+ public Object deserialize(final Object input,
+ @SuppressWarnings("rawtypes") final InstanceIdentifier bindingIdentifier) {
// TODO Auto-generated method stub
return null;
}
}
@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();
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());
}
}