X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=code-generator%2Fbinding-data-codec%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fbinding%2Fdata%2Fcodec%2Fimpl%2FDataObjectCodecContext.java;h=0ca1d2b8504d3183bb01783312eb1ea4717dcc23;hb=3f754cccb393b989bafb8b194edf9da0ec3e9e8a;hp=5725e186ba0be23d12bf88251e4fc6e79e5daa8d;hpb=b1f4e95dbefd402a3b9bc9804184006229cfc30d;p=yangtools.git diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java index 5725e186ba..0ca1d2b850 100644 --- a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java +++ b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java @@ -9,9 +9,16 @@ package org.opendaylight.yangtools.binding.data.codec.impl; import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; @@ -24,6 +31,7 @@ import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy import org.opendaylight.yangtools.sal.binding.model.api.Type; import org.opendaylight.yangtools.yang.binding.Augmentable; import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.AugmentationHolder; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; @@ -42,85 +50,88 @@ import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -abstract class DataObjectCodecContext extends DataContainerCodecContext { +abstract class DataObjectCodecContext extends DataContainerCodecContext { private static final Logger LOG = LoggerFactory.getLogger(DataObjectCodecContext.class); - + private static final Lookup LOOKUP = MethodHandles.publicLookup(); + private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class, InvocationHandler.class); + private static final MethodType DATAOBJECT_TYPE = MethodType.methodType(DataObject.class, InvocationHandler.class); private static final Comparator METHOD_BY_ALPHABET = new Comparator() { - @Override public int compare(final Method o1, final Method o2) { return o1.getName().compareTo(o2.getName()); } }; - private final ImmutableMap leafChild; + private final ImmutableMap> leafChild; private final ImmutableMap byYang; private final ImmutableSortedMap byMethod; private final ImmutableMap, DataContainerCodecPrototype> byStreamClass; private final ImmutableMap, DataContainerCodecPrototype> byBindingArgClass; - protected final Method augmentationGetter; + private final MethodHandle proxyConstructor; protected DataObjectCodecContext(final DataContainerCodecPrototype prototype) { super(prototype); - this.leafChild = factory().getLeafNodes(bindingClass(), schema()); + this.leafChild = factory().getLeafNodes(getBindingClass(), schema()); - Map, Method> clsToMethod = BindingReflections.getChildrenClassToMethod(bindingClass()); + final Map, Method> clsToMethod = BindingReflections.getChildrenClassToMethod(getBindingClass()); - Map byYangBuilder = new HashMap<>(); - SortedMap byMethodBuilder = new TreeMap<>(METHOD_BY_ALPHABET); - Map, DataContainerCodecPrototype> byStreamClassBuilder = new HashMap<>(); - Map, DataContainerCodecPrototype> byBindingArgClassBuilder = new HashMap<>(); + final Map byYangBuilder = new HashMap<>(); + final SortedMap byMethodBuilder = new TreeMap<>(METHOD_BY_ALPHABET); + final Map, DataContainerCodecPrototype> byStreamClassBuilder = new HashMap<>(); + final Map, DataContainerCodecPrototype> byBindingArgClassBuilder = new HashMap<>(); // Adds leaves to mapping - for (LeafNodeCodecContext leaf : leafChild.values()) { + for (final LeafNodeCodecContext leaf : leafChild.values()) { byMethodBuilder.put(leaf.getGetter(), leaf); byYangBuilder.put(leaf.getDomPathArgument(), leaf); } - for (Entry, Method> childDataObj : clsToMethod.entrySet()) { - DataContainerCodecPrototype childProto = loadChildPrototype(childDataObj.getKey()); + for (final Entry, Method> childDataObj : clsToMethod.entrySet()) { + final DataContainerCodecPrototype childProto = loadChildPrototype(childDataObj.getKey()); byMethodBuilder.put(childDataObj.getValue(), childProto); byStreamClassBuilder.put(childProto.getBindingClass(), childProto); byYangBuilder.put(childProto.getYangArg(), childProto); if (childProto.isChoice()) { - ChoiceNodeCodecContext choice = (ChoiceNodeCodecContext) childProto.get(); - for(Class cazeChild : choice.getCaseChildrenClasses()) { + final ChoiceNodeCodecContext choice = (ChoiceNodeCodecContext) childProto.get(); + for(final Class cazeChild : choice.getCaseChildrenClasses()) { byBindingArgClassBuilder.put(cazeChild, childProto); } } } this.byMethod = ImmutableSortedMap.copyOfSorted(byMethodBuilder); - if (Augmentable.class.isAssignableFrom(bindingClass())) { - try { - augmentationGetter = bindingClass().getMethod("getAugmentation", Class.class); - } catch (NoSuchMethodException | SecurityException e) { - throw new IllegalStateException("Could not get required method.",e); - } - ImmutableMap augmentations = factory().getRuntimeContext() + if (Augmentable.class.isAssignableFrom(getBindingClass())) { + final ImmutableMap augmentations = factory().getRuntimeContext() .getAvailableAugmentationTypes(schema()); - for (Entry augment : augmentations.entrySet()) { - DataContainerCodecPrototype augProto = getAugmentationPrototype(augment.getValue()); + for (final Entry augment : augmentations.entrySet()) { + final DataContainerCodecPrototype augProto = getAugmentationPrototype(augment.getValue()); if (augProto != null) { byYangBuilder.put(augProto.getYangArg(), augProto); byStreamClassBuilder.put(augProto.getBindingClass(), augProto); } } - } else { - augmentationGetter = null; } this.byYang = ImmutableMap.copyOf(byYangBuilder); this.byStreamClass = ImmutableMap.copyOf(byStreamClassBuilder); byBindingArgClassBuilder.putAll(byStreamClass); this.byBindingArgClass = ImmutableMap.copyOf(byBindingArgClassBuilder); + + final Class proxyClass = Proxy.getProxyClass(getBindingClass().getClassLoader(), new Class[] { getBindingClass(), AugmentationHolder.class }); + try { + proxyConstructor = LOOKUP.findConstructor(proxyClass, CONSTRUCTOR_TYPE).asType(DATAOBJECT_TYPE); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new IllegalStateException("Failed to find contructor for class " + proxyClass); + } } + + @SuppressWarnings("unchecked") @Override - protected DataContainerCodecContext getStreamChild(final Class childClass) { + public DataContainerCodecContext streamChild(final Class childClass) { DataContainerCodecPrototype childProto = byStreamClass.get(childClass); if (childProto != null) { - return childProto.get(); + return (DataContainerCodecContext) childProto.get(); } if (Augmentation.class.isAssignableFrom(childClass)) { @@ -131,9 +142,10 @@ abstract class DataObjectCodecContext extends DataC * * FIXME: Cache mapping of mismatched augmentation to real one, to speed up lookup. */ - Class augTarget = BindingReflections.findAugmentationTarget((Class) childClass); - if ((bindingClass().equals(augTarget))) { - for (DataContainerCodecPrototype realChild : byStreamClass.values()) { + @SuppressWarnings("rawtypes") + final Class augTarget = BindingReflections.findAugmentationTarget((Class) childClass); + if ((getBindingClass().equals(augTarget))) { + for (final DataContainerCodecPrototype realChild : byStreamClass.values()) { if (Augmentation.class.isAssignableFrom(realChild.getBindingClass()) && BindingReflections.isSubstitutionFor(childClass,realChild.getBindingClass())) { childProto = realChild; @@ -142,63 +154,64 @@ abstract class DataObjectCodecContext extends DataC } } } - Preconditions.checkArgument(childProto != null, " Child %s is not valid child.",childClass); - return childProto.get(); + return (DataContainerCodecContext) childNonNull(childProto, childClass, " Child %s is not valid child.").get(); } + + @SuppressWarnings("unchecked") @Override - protected Optional> getPossibleStreamChild(final Class childClass) { - DataContainerCodecPrototype childProto = byStreamClass.get(childClass); + public Optional> possibleStreamChild( + final Class childClass) { + final DataContainerCodecPrototype childProto = byStreamClass.get(childClass); if(childProto != null) { - return Optional.>of(childProto.get()); + return Optional.>of((DataContainerCodecContext) childProto.get()); } return Optional.absent(); } @Override - protected DataContainerCodecContext getIdentifierChild(final InstanceIdentifier.PathArgument arg, + public DataContainerCodecContext bindingPathArgumentChild(final InstanceIdentifier.PathArgument arg, final List builder) { - Class argType = arg.getType(); - DataContainerCodecPrototype ctxProto = byBindingArgClass.get(argType); - Preconditions.checkArgument(ctxProto != null,"Invalid child"); - - DataContainerCodecContext context = ctxProto.get(); - if(context instanceof ChoiceNodeCodecContext) { - ChoiceNodeCodecContext casted = (ChoiceNodeCodecContext) context; - casted.addYangPathArgument(arg, builder); - DataContainerCodecContext caze = casted.getCazeByChildClass(arg.getType()); + final Class argType = arg.getType(); + final DataContainerCodecPrototype ctxProto = byBindingArgClass.get(argType); + final DataContainerCodecContext context = + childNonNull(ctxProto, argType, "Class %s is not valid child of %s", argType, getBindingClass()).get(); + if (context instanceof ChoiceNodeCodecContext) { + final ChoiceNodeCodecContext choice = (ChoiceNodeCodecContext) context; + final DataContainerCodecContext caze = choice.getCazeByChildClass(arg.getType()); + choice.addYangPathArgument(arg, builder); caze.addYangPathArgument(arg, builder); - return caze.getIdentifierChild(arg, builder); + return caze.bindingPathArgumentChild(arg, builder); } context.addYangPathArgument(arg, builder); return context; } + @SuppressWarnings("unchecked") @Override - protected NodeCodecContext getYangIdentifierChild(YangInstanceIdentifier.PathArgument arg) { + public NodeCodecContext yangPathArgumentChild(YangInstanceIdentifier.PathArgument arg) { if(arg instanceof NodeIdentifierWithPredicates) { arg = new NodeIdentifier(arg.getNodeType()); } - NodeContextSupplier childSupplier = byYang.get(arg); - Preconditions.checkArgument(childSupplier != null, "Argument %s is not valid child of %s", arg, schema()); - return childSupplier.get(); + final NodeContextSupplier childSupplier = byYang.get(arg); + childNonNull(childSupplier != null, arg, "Argument %s is not valid child of %s", arg, schema()); + return (NodeCodecContext) childSupplier.get(); } - protected final LeafNodeCodecContext getLeafChild(final String name) { - final LeafNodeCodecContext value = leafChild.get(name); - Preconditions.checkArgument(value != null, "Leaf %s is not valid for %s", name, bindingClass()); - return value; + protected final LeafNodeCodecContext getLeafChild(final String name) { + final LeafNodeCodecContext value = leafChild.get(name); + return IncorrectNestingException.checkNonNull(value, "Leaf %s is not valid for %s", name, getBindingClass()); } private DataContainerCodecPrototype loadChildPrototype(final Class childClass) { - DataSchemaNode origDef = factory().getRuntimeContext().getSchemaDefinition(childClass); + final DataSchemaNode origDef = factory().getRuntimeContext().getSchemaDefinition(childClass); // Direct instantiation or use in same module in which grouping // was defined. DataSchemaNode sameName; try { sameName = schema().getDataChildByName(origDef.getQName()); - } catch (IllegalArgumentException e) { + } catch (final IllegalArgumentException e) { sameName = null; } final DataSchemaNode childSchema; @@ -216,8 +229,8 @@ abstract class DataObjectCodecContext extends DataC } } else { // We are looking for instantiation via uses in other module - QName instantiedName = QName.create(namespace(), origDef.getQName().getLocalName()); - DataSchemaNode potential = schema().getDataChildByName(instantiedName); + final QName instantiedName = QName.create(namespace(), origDef.getQName().getLocalName()); + final DataSchemaNode potential = schema().getDataChildByName(instantiedName); // We check if it is really instantiated from same // definition as class was derived if (potential != null && origDef.equals(SchemaNodeUtils.getRootOriginalIfPossible(potential))) { @@ -226,47 +239,59 @@ abstract class DataObjectCodecContext extends DataC childSchema = null; } } - Preconditions.checkArgument(childSchema != null, "Node %s does not have child named %s", schema(), childClass); - return DataContainerCodecPrototype.from(childClass, childSchema, factory()); + final DataSchemaNode nonNullChild = + childNonNull(childSchema, childClass, "Node %s does not have child named %s", schema(), childClass); + return DataContainerCodecPrototype.from(childClass, nonNullChild, factory()); } private DataContainerCodecPrototype getAugmentationPrototype(final Type value) { - ClassLoadingStrategy loader = factory().getRuntimeContext().getStrategy(); + final ClassLoadingStrategy loader = factory().getRuntimeContext().getStrategy(); @SuppressWarnings("rawtypes") final Class augClass; try { augClass = loader.loadClass(value); - } catch (ClassNotFoundException e) { + } catch (final ClassNotFoundException e) { LOG.warn("Failed to load augmentation prototype for {}", value, e); return null; } - Entry augSchema = factory().getRuntimeContext() + @SuppressWarnings("unchecked") + final Entry augSchema = factory().getRuntimeContext() .getResolvedAugmentationSchema(schema(), augClass); return DataContainerCodecPrototype.from(augClass, augSchema.getKey(), augSchema.getValue(), factory()); } @SuppressWarnings("rawtypes") Object getBindingChildValue(final Method method, final NormalizedNodeContainer domData) { - NodeCodecContext childContext = byMethod.get(method).get(); - Optional> domChild = domData.getChild(childContext.getDomPathArgument()); + final NodeCodecContext childContext = byMethod.get(method).get(); + @SuppressWarnings("unchecked") + final Optional> domChild = domData.getChild(childContext.getDomPathArgument()); if (domChild.isPresent()) { - return childContext.dataFromNormalizedNode(domChild.get()); + return childContext.deserializeObject(domChild.get()); } return null; } + protected final D createBindingProxy(final NormalizedNodeContainer node) { + try { + return (D) proxyConstructor.invokeExact((InvocationHandler)new LazyDataObject<>(this, node)); + } catch (final Throwable e) { + throw Throwables.propagate(e); + } + } + + @SuppressWarnings("unchecked") public Map>, Augmentation> getAllAugmentationsFrom( final NormalizedNodeContainer> data) { @SuppressWarnings("rawtypes") - Map map = new HashMap<>(); + final Map map = new HashMap<>(); - for(DataContainerCodecPrototype value : byStreamClass.values()) { + for(final DataContainerCodecPrototype value : byStreamClass.values()) { if(Augmentation.class.isAssignableFrom(value.getBindingClass())) { - Optional> augData = data.getChild(value.getYangArg()); + final Optional> augData = data.getChild(value.getYangArg()); if(augData.isPresent()) { - map.put(value.getBindingClass(), value.get().dataFromNormalizedNode(augData.get())); + map.put(value.getBindingClass(), value.get().deserializeObject(augData.get())); } } } @@ -278,4 +303,15 @@ abstract class DataObjectCodecContext extends DataC return byMethod.keySet(); } + @Override + public InstanceIdentifier.PathArgument deserializePathArgument(final YangInstanceIdentifier.PathArgument arg) { + Preconditions.checkArgument(getDomPathArgument().equals(arg)); + return bindingArg(); + } + + @Override + public YangInstanceIdentifier.PathArgument serializePathArgument(final InstanceIdentifier.PathArgument arg) { + Preconditions.checkArgument(bindingArg().equals(arg)); + return getDomPathArgument(); + } }