X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-binding-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fbinding%2Fdom%2Fserializer%2Fimpl%2FLazyGeneratedCodecRegistry.java;h=cabb1bc4e2c5359582bc95e1e30514f557801b64;hp=de6836489e6a6b970fb96a409e832876d02e82a7;hb=9212fed678702583f4a555641208cf1c7b45b829;hpb=428c5b93a8f6c99cc81eab5bcb6809f1b809cb38 diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java index de6836489e..cabb1bc4e2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java @@ -1,7 +1,9 @@ package org.opendaylight.controller.sal.binding.dom.serializer.impl; +import java.awt.CompositeContext; import java.lang.ref.WeakReference; import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -12,11 +14,13 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.Set; import java.util.WeakHashMap; +import org.apache.commons.lang3.text.translate.AggregateTranslator; import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec; import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCaseCodec; import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCodec; @@ -24,6 +28,7 @@ import org.opendaylight.controller.sal.binding.dom.serializer.api.CodecRegistry; import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec; import org.opendaylight.controller.sal.binding.dom.serializer.api.DomCodec; import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec; +import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentitityCodec; import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec; import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName; import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils; @@ -34,6 +39,7 @@ import org.opendaylight.yangtools.concepts.Delegator; import org.opendaylight.yangtools.concepts.Identifiable; 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.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -41,6 +47,7 @@ import org.opendaylight.yangtools.yang.binding.Identifier; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; @@ -61,10 +68,12 @@ import static org.opendaylight.controller.sal.binding.dom.serializer.impl.Interm import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext; 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.model.api.Module; import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; +import com.google.common.collect.FluentIterable; import com.google.common.util.concurrent.CycleDetectingLockFactory.WithExplicitOrdering; public class LazyGeneratedCodecRegistry implements // @@ -76,27 +85,31 @@ public class LazyGeneratedCodecRegistry implements // private final static 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 Map, DataContainerCodec> containerCodecs = new WeakHashMap<>(); - private Map, IdentifierCodec> identifierCodecs = new WeakHashMap<>(); - private Map, ChoiceCodecImpl> choiceCodecs = new WeakHashMap<>(); - private Map, ChoiceCaseCodecImpl> caseCodecs = new WeakHashMap<>(); - private Map, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>(); - + private static final Map, DataContainerCodec> containerCodecs = new WeakHashMap<>(); + private static final Map, IdentifierCodec> identifierCodecs = new WeakHashMap<>(); + private static final Map, ChoiceCodecImpl> choiceCodecs = new WeakHashMap<>(); + private static final Map, ChoiceCaseCodecImpl> caseCodecs = new WeakHashMap<>(); + private static final Map, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>(); + private static final Map, AugmentationCodec> augmentationCodecs = new WeakHashMap<>(); + private static final Map, QName> identityQNames = new WeakHashMap<>(); + private static final Map qnamesToIdentityMap = new ConcurrentHashMap<>(); /** Binding type to encountered classes mapping **/ @SuppressWarnings("rawtypes") - Map> typeToClass = new ConcurrentHashMap<>(); + private static final Map> typeToClass = new ConcurrentHashMap<>(); @SuppressWarnings("rawtypes") - private ConcurrentMap typeToCaseNodes = new ConcurrentHashMap<>(); + private static final ConcurrentMap typeToCaseCodecs = new ConcurrentHashMap<>(); private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade(); - Map pathToType = new ConcurrentHashMap<>(); - Map, Type> pathToInstantiatedType = 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 SchemaContext currentSchema; @@ -115,8 +128,56 @@ public class LazyGeneratedCodecRegistry implements // @Override public > AugmentationCodec getCodecForAugmentation(Class object) { - // TODO Auto-generated method stub - return null; + AugmentationCodec codec = null; + @SuppressWarnings("rawtypes") + AugmentationCodec potentialCodec = augmentationCodecs.get(object); + if (potentialCodec != null) { + codec = potentialCodec; + } else + try { + Class, Object>> augmentRawCodec = generator + .augmentationTransformerFor(object); + BindingCodec, Object> rawCodec = augmentRawCodec.newInstance(); + codec = new AugmentationCodecWrapper(rawCodec); + augmentationCodecs.put(augmentRawCodec, codec); + } catch (InstantiationException e) { + LOG.error("Can not instantiate raw augmentation codec {}", object.getSimpleName(), e); + } catch (IllegalAccessException e) { + LOG.debug("BUG: Constructor for {} is not accessible.", object.getSimpleName(), e); + } + Class> objectSupertype = getAugmentableArgumentFrom(object); + if (objectSupertype != null) { + getAugmentableCodec(objectSupertype).addAugmentationCodec(object, codec); + } else { + LOG.warn("Could not find augmentation target for augmentation {}", object); + } + return codec; + } + + private static Class> getAugmentableArgumentFrom( + final Class> augmentation) { + try { + Class> ret = ClassLoaderUtils.withClassLoader(augmentation.getClassLoader(), + new Callable>>() { + @Override + @SuppressWarnings("unchecked") + public Class> call() throws Exception { + for (java.lang.reflect.Type supertype : augmentation.getGenericInterfaces()) { + if (supertype instanceof ParameterizedType + && Augmentation.class.equals(((ParameterizedType) supertype).getRawType())) { + ParameterizedType augmentationGeneric = (ParameterizedType) supertype; + return (Class>) augmentationGeneric + .getActualTypeArguments()[0]; + } + } + return null; + } + }); + return ret; + } catch (Exception e) { + LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e); + return null; + } } @Override @@ -136,15 +197,14 @@ public class LazyGeneratedCodecRegistry implements // } return weakRef.get(); } - + @Override - public void putPathToClass(List names,Class cls) { + public void putPathToClass(List names, Class cls) { Type reference = Types.typeForClass(cls); - pathToInstantiatedType.put(names, reference ); + pathToInstantiatedType.put(names, reference); bindingClassEncountered(cls); } - @Override public IdentifierCodec getKeyCodecForPath(List names) { @SuppressWarnings("unchecked") @@ -166,7 +226,6 @@ public class LazyGeneratedCodecRegistry implements // return newWrapper; } - @Override @SuppressWarnings("rawtypes") public void bindingClassEncountered(Class cls) { @@ -174,7 +233,7 @@ public class LazyGeneratedCodecRegistry implements // if (typeToClass.containsKey(typeRef)) { return; } - LOG.info("Binding Class {} encountered.", cls); + LOG.trace("Binding Class {} encountered.", cls); WeakReference weakRef = new WeakReference<>(cls); typeToClass.put(typeRef, weakRef); if (Augmentation.class.isAssignableFrom(cls)) { @@ -191,7 +250,7 @@ public class LazyGeneratedCodecRegistry implements // if (typeToClass.containsKey(typeRef)) { return; } - LOG.info("Binding Class {} encountered.", cls); + LOG.trace("Binding Class {} encountered.", cls); WeakReference weakRef = new WeakReference<>((Class) cls); typeToClass.put(typeRef, weakRef); } @@ -269,9 +328,21 @@ public class LazyGeneratedCodecRegistry implements // return newWrapper; } + @Override + public IdentitityCodec getIdentityCodec() { + return identityRefCodec; + } + + @Override + public IdentitityCodec getCodecForIdentity(Class codec) { + bindingClassEncountered(codec); + return identityRefCodec; + } + @Override public void onCodecCreated(Class cls) { CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec); + CodecMapping.setIdentityRefCodec(cls, identityRefCodec); } @Override @@ -297,10 +368,12 @@ public class LazyGeneratedCodecRegistry implements // return potential; } ConcreteType typeref = Types.typeForClass(caseClass); - ChoiceCaseCodecImpl caseCodec = typeToCaseNodes.get(typeref); + ChoiceCaseCodecImpl caseCodec = typeToCaseCodecs.get(typeref); + checkState(caseCodec != null, "Case Codec was not created proactivelly for %s", caseClass.getName()); + checkState(caseCodec.getSchema() != null, "Case schema is not available for %s", caseClass.getName()); @SuppressWarnings("unchecked") - Class newCodec = generator.caseCodecFor(caseClass, caseCodec.schema); + Class newCodec = generator.caseCodecFor(caseClass, caseCodec.getSchema()); BindingCodec newInstance = newInstanceOf(newCodec); caseCodec.setDelegate(newInstance); caseCodecs.put(caseClass, caseCodec); @@ -315,6 +388,12 @@ public class LazyGeneratedCodecRegistry implements // public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) { pathToType.putAll(context.getChildNodes()); + qnamesToIdentityMap.putAll(context.getIdentities()); + for (Entry identity : context.getIdentities().entrySet()) { + typeToQname.put( + new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()), + identity.getKey()); + } captureCases(context.getCases(), schemaContext); } @@ -322,17 +401,22 @@ public class LazyGeneratedCodecRegistry implements // 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.error("YANGTools Bug: SchemaNode for {}, with path {} was not found in context.", typeref.getFullyQualifiedName(), caseNode.getKey()); + @SuppressWarnings("rawtypes") + ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(); + typeToCaseCodecs.putIfAbsent(typeref, value); continue; } - - pathToType.put(caseNode.getKey(), caseNode.getValue()); @SuppressWarnings("rawtypes") ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node); - typeToCaseNodes.putIfAbsent(typeref, value); + typeToCaseCodecs.putIfAbsent(typeref, value); } } @@ -352,18 +436,24 @@ public class LazyGeneratedCodecRegistry implements // choiceCodecs.put(choiceClass, newCodec); CodecMapping.setClassToCaseMap(choiceCodec, (Map, BindingCodec>) classToCaseRawCodec); CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase()); - + tryToCreateCasesCodecs(schema); } private void tryToCreateCasesCodecs(ChoiceNode schema) { - for(ChoiceCaseNode caseNode : schema.getCases()) { + for (ChoiceCaseNode caseNode : schema.getCases()) { SchemaPath path = caseNode.getPath(); GeneratedTypeBuilder type; - if(path != null && (type = pathToType.get(path)) != null) { + if (path != null && (type = pathToType.get(path)) != null) { + ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName()); + ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref); + if (partialCodec.getSchema() == null) { + partialCodec.setSchema(caseNode); + } + Class caseClass = ClassLoaderUtils.tryToLoadClassWithTCCL(type.getFullyQualifiedName()); - if(caseClass != null) { + if (caseClass != null) { getCaseCodecFor(caseClass); } } @@ -381,8 +471,7 @@ public class LazyGeneratedCodecRegistry implements // } @Override - public void onDataContainerCodecCreated(Class dataClass, - Class> dataCodec) { + public void onDataContainerCodecCreated(Class dataClass, Class> dataCodec) { if (Augmentable.class.isAssignableFrom(dataClass)) { AugmentableCompositeCodec augmentableCodec = getAugmentableCodec(dataClass); CodecMapping.setAugmentationCodec(dataCodec, augmentableCodec); @@ -390,7 +479,7 @@ public class LazyGeneratedCodecRegistry implements // } - private AugmentableCompositeCodec getAugmentableCodec(Class dataClass) { + public AugmentableCompositeCodec getAugmentableCodec(Class dataClass) { AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass); if (ret != null) { return ret; @@ -471,15 +560,15 @@ public class LazyGeneratedCodecRegistry implements // @SuppressWarnings("rawtypes") private static class ChoiceCaseCodecImpl implements ChoiceCaseCodec, // Delegator { - private final boolean augmenting; + private boolean augmenting; private BindingCodec delegate; - private final Set validNames; - private final Set validQNames; + private Set validNames; + private Set validQNames; private ChoiceCaseNode schema; - public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) { - this.delegate = NOT_READY_CODEC; + public void setSchema(ChoiceCaseNode caseNode) { + this.schema = schema; this.schema = caseNode; validNames = new HashSet<>(); validQNames = new HashSet<>(); @@ -491,6 +580,15 @@ public class LazyGeneratedCodecRegistry implements // augmenting = caseNode.isAugmenting(); } + public ChoiceCaseCodecImpl() { + this.delegate = NOT_READY_CODEC; + } + + public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) { + this.delegate = NOT_READY_CODEC; + setSchema(caseNode); + } + @Override public ValueWithQName deserialize(Node input) { throw new UnsupportedOperationException("Direct invocation of this codec is not allowed."); @@ -718,7 +816,7 @@ public class LazyGeneratedCodecRegistry implements // private final Class augmentableType; - Map rawAugmentationCodecs = new WeakHashMap<>(); + Map> localAugmentationCodecs = new WeakHashMap<>(); public AugmentableCompositeCodec(Class type) { checkArgument(Augmentable.class.isAssignableFrom(type)); @@ -751,53 +849,33 @@ public class LazyGeneratedCodecRegistry implements // private List serializeImpl(Map input) { List ret = new ArrayList<>(); for (Entry entry : input.entrySet()) { - BindingCodec codec = getRawCodecForAugmentation(entry.getKey()); - List output = (List) codec.serialize(new ValueWithQName(null, entry.getValue())); - ret.addAll(output); + AugmentationCodec codec = getCodecForAugmentation(entry.getKey()); + CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue())); + ret.addAll(node.getChildren()); } return ret; } - private BindingCodec getRawCodecForAugmentation(Class key) { - BindingCodec ret = rawAugmentationCodecs.get(key); - if (ret != null) { - return ret; - } - try { - Class retClass = generator.augmentationTransformerFor(key); - ret = retClass.newInstance(); - rawAugmentationCodecs.put(key, ret); - return ret; - } catch (InstantiationException e) { - LOG.error("Can not instantiate raw augmentation codec {}", key.getSimpleName(), e); - } catch (IllegalAccessException e) { - LOG.debug("BUG: Constructor for {} is not accessible.", key.getSimpleName(), e); - } - return null; + public synchronized > void addAugmentationCodec(Class augmentationClass, + AugmentationCodec value) { + localAugmentationCodecs.put(augmentationClass, value); } @Override public Map deserialize(Object input) { Map ret = new HashMap<>(); if (input instanceof CompositeNode) { - for (Entry codec : rawAugmentationCodecs.entrySet()) { - Augmentation value = (Augmentation) codec.getValue().deserialize(input); - if (value != null) { - ret.put(codec.getKey(), value); + List>> codecs = new ArrayList<>(localAugmentationCodecs.entrySet()); + for (Entry> codec : codecs) { + ValueWithQName value = codec.getValue().deserialize((CompositeNode) input); + if (value != null && value.getValue() != null) { + ret.put(codec.getKey(), (Augmentation) value.getValue()); } } } return ret; } - public Map getRawAugmentationCodecs() { - return rawAugmentationCodecs; - } - - public void setRawAugmentationCodecs(Map rawAugmentationCodecs) { - this.rawAugmentationCodecs = rawAugmentationCodecs; - } - public Class getAugmentableType() { return augmentableType; } @@ -826,4 +904,104 @@ public class LazyGeneratedCodecRegistry implements // return getDelegate().serialize(input); } } + + private static class AugmentationCodecWrapper> implements AugmentationCodec, + Delegator { + + private BindingCodec delegate; + + public AugmentationCodecWrapper(BindingCodec, Object> rawCodec) { + this.delegate = rawCodec; + } + + @Override + public BindingCodec getDelegate() { + return delegate; + } + + @Override + public CompositeNode serialize(ValueWithQName input) { + @SuppressWarnings("unchecked") + List> rawValues = (List>) getDelegate().serialize(input); + List> serialized = new ArrayList<>(rawValues.size()); + for (Map val : rawValues) { + serialized.add(toNode(val)); + } + return new CompositeNodeTOImpl(input.getQname(), null, serialized); + } + + @Override + @SuppressWarnings("unchecked") + public ValueWithQName deserialize(Node input) { + Object rawCodecValue = getDelegate().deserialize((Map) input); + return new ValueWithQName(input.getNodeType(), (T) rawCodecValue); + } + } + + private class IdentityCompositeCodec implements IdentitityCodec { + + @Override + public Object deserialize(Object input) { + checkArgument(input instanceof QName); + return deserialize((QName) input); + } + + @Override + public Class deserialize(QName input) { + Type type = qnamesToIdentityMap.get(input); + if (type == null) { + return null; + } + ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName()); + WeakReference softref = typeToClass.get(typeref); + if (softref == null) { + return null; + } + return softref.get(); + } + + @Override + public QName serialize(Class input) { + checkArgument(BaseIdentity.class.isAssignableFrom(input)); + bindingClassEncountered(input); + QName qname = identityQNames.get(input); + if (qname != null) { + return qname; + } + ConcreteType typeref = Types.typeForClass(input); + qname = typeToQname.get(typeref); + if (qname != null) { + identityQNames.put(input, qname); + } + return qname; + } + + @Override + public Object serialize(Object input) { + checkArgument(input instanceof Class); + return serialize((Class) input); + } + } + + public boolean isCodecAvailable(Class 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; + } } \ No newline at end of file