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%2FBindingCodecContext.java;h=e0e0c97777e2dfab31450eefb1480c7f954fabee;hb=1d4f950346e5f776f14cf4b75ccb28c2e2b9ded3;hp=6d1e31c2b47a1a3b7589ee060f89cbcd39156633;hpb=715451bf6fba178edbcf760e2a2ba8f46815c741;p=yangtools.git diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java index 6d1e31c2b4..e0e0c97777 100644 --- a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java +++ b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java @@ -9,15 +9,10 @@ package org.opendaylight.yangtools.binding.data.codec.impl; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSortedMap; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.AbstractMap.SimpleEntry; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; @@ -25,22 +20,26 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Callable; - import javax.annotation.Nonnull; import javax.annotation.Nullable; - +import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTree; +import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeNode; import org.opendaylight.yangtools.binding.data.codec.impl.NodeCodecContext.CodecContextFactory; import org.opendaylight.yangtools.concepts.Codec; import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext; +import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType; import org.opendaylight.yangtools.util.ClassLoaderUtils; -import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.BindingMapping; import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.DataObjectSerializer; import org.opendaylight.yangtools.yang.binding.Identifiable; import org.opendaylight.yangtools.yang.binding.Identifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem; +import org.opendaylight.yangtools.yang.binding.Notification; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -51,27 +50,33 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -class BindingCodecContext implements CodecContextFactory, Immutable { +final class BindingCodecContext implements CodecContextFactory, BindingCodecTree, Immutable { private static final Logger LOG = LoggerFactory.getLogger(BindingCodecContext.class); - private static final String GETTER_PREFIX = "get"; + static final String GETTER_PREFIX = "get"; - private final SchemaRootCodecContext root; + private final Codec> instanceIdentifierCodec; + private final Codec> identityCodec; + private final BindingNormalizedNodeCodecRegistry registry; private final BindingRuntimeContext context; - private final Codec> instanceIdentifierCodec = - new InstanceIdentifierCodec(); - private final Codec> identityCodec = new IdentityCodec(); + private final SchemaRootCodecContext root; - public BindingCodecContext(final BindingRuntimeContext context) { + BindingCodecContext(final BindingRuntimeContext context, BindingNormalizedNodeCodecRegistry registry) { this.context = Preconditions.checkNotNull(context, "Binding Runtime Context is required."); this.root = SchemaRootCodecContext.create(this); + this.identityCodec = new IdentityCodec(context); + this.instanceIdentifierCodec = new InstanceIdentifierCodec(this); + this.registry = Preconditions.checkNotNull(registry); } @Override @@ -87,24 +92,40 @@ class BindingCodecContext implements CodecContextFactory, Immutable { return identityCodec; } + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public DataObjectSerializer getEventStreamSerializer(Class type) { + return registry.getSerializer((Class) type); + } + public Entry newWriter(final InstanceIdentifier path, final NormalizedNodeStreamWriter domWriter) { - LinkedList yangArgs = new LinkedList<>(); - DataContainerCodecContext codecContext = getCodecContextNode(path, yangArgs); - BindingStreamEventWriter writer = new BindingToNormalizedStreamWriter(codecContext, domWriter); - return new SimpleEntry<>(YangInstanceIdentifier.create(yangArgs), writer); + final LinkedList yangArgs = new LinkedList<>(); + final DataContainerCodecContext codecContext = getCodecContextNode(path, yangArgs); + return new SimpleEntry<>(YangInstanceIdentifier.create(yangArgs), codecContext.createWriter(domWriter)); } public BindingStreamEventWriter newWriterWithoutIdentifier(final InstanceIdentifier path, final NormalizedNodeStreamWriter domWriter) { - return new BindingToNormalizedStreamWriter(getCodecContextNode(path, null), domWriter); + return getCodecContextNode(path, null).createWriter(domWriter); + } + + BindingStreamEventWriter newRpcWriter(final Class rpcInputOrOutput, + final NormalizedNodeStreamWriter domWriter) { + return root.getRpc(rpcInputOrOutput).createWriter(domWriter); + } + + BindingStreamEventWriter newNotificationWriter(final Class notification, + final NormalizedNodeStreamWriter domWriter) { + return root.getNotification(notification).createWriter(domWriter); } - public DataContainerCodecContext getCodecContextNode(final InstanceIdentifier binding, + public DataContainerCodecContext getCodecContextNode(final InstanceIdentifier binding, final List builder) { - DataContainerCodecContext currentNode = root; - for (InstanceIdentifier.PathArgument bindingArg : binding.getPathArguments()) { - currentNode = currentNode.getIdentifierChild(bindingArg, builder); + DataContainerCodecContext currentNode = root; + for (final InstanceIdentifier.PathArgument bindingArg : binding.getPathArguments()) { + currentNode = currentNode.bindingPathArgumentChild(bindingArg, builder); + Preconditions.checkArgument(currentNode != null, "Supplied Instance Identifier %s is not valid.",binding); } return currentNode; } @@ -119,16 +140,17 @@ class BindingCodecContext implements CodecContextFactory, Immutable { * @param bindingArguments Collection for traversed path arguments * @return Codec for target node, or @null if the node does not have a * binding representation (choice, case, leaf). + * */ - @Nullable NodeCodecContext getCodecContextNode(final @Nonnull YangInstanceIdentifier dom, + @Nullable NodeCodecContext getCodecContextNode(final @Nonnull YangInstanceIdentifier dom, final @Nonnull Collection bindingArguments) { - NodeCodecContext currentNode = root; - ListNodeCodecContext currentList = null; + NodeCodecContext currentNode = root; + ListNodeCodecContext currentList = null; - for (YangInstanceIdentifier.PathArgument domArg : dom.getPathArguments()) { - Preconditions.checkArgument(currentNode instanceof DataContainerCodecContext, "Unexpected child of non-container node %s", currentNode); - final DataContainerCodecContext previous = (DataContainerCodecContext) currentNode; - final NodeCodecContext nextNode = previous.getYangIdentifierChild(domArg); + for (final YangInstanceIdentifier.PathArgument domArg : dom.getPathArguments()) { + Preconditions.checkArgument(currentNode instanceof DataContainerCodecContext, "Unexpected child of non-container node %s", currentNode); + final DataContainerCodecContext previous = (DataContainerCodecContext) currentNode; + final NodeCodecContext nextNode = previous.yangPathArgumentChild(domArg); /* * List representation in YANG Instance Identifier consists of two @@ -149,13 +171,13 @@ class BindingCodecContext implements CodecContextFactory, Immutable { } else if (nextNode instanceof ListNodeCodecContext) { // We enter list, we do not update current Node yet, // since we need to verify - currentList = (ListNodeCodecContext) nextNode; + currentList = (ListNodeCodecContext) nextNode; } else if (nextNode instanceof ChoiceNodeCodecContext) { // We do not add path argument for choice, since // it is not supported by binding instance identifier. currentNode = nextNode; - } else if (nextNode instanceof DataContainerCodecContext) { - bindingArguments.add(((DataContainerCodecContext) nextNode).getBindingPathArgument(domArg)); + } else if (nextNode instanceof DataContainerCodecContext) { + bindingArguments.add(((DataContainerCodecContext) nextNode).getBindingPathArgument(domArg)); currentNode = nextNode; } else if (nextNode instanceof LeafNodeCodecContext) { LOG.debug("Instance identifier referencing a leaf is not representable (%s)", dom); @@ -181,11 +203,19 @@ class BindingCodecContext implements CodecContextFactory, Immutable { return currentNode; } + NotificationCodecContext getNotificationContext(final SchemaPath notification) { + return root.getNotification(notification); + } + + ContainerNodeCodecContext getRpcDataContext(final SchemaPath path) { + return root.getRpc(path); + } + @Override - public ImmutableMap getLeafNodes(final Class parentClass, + public ImmutableMap> getLeafNodes(final Class parentClass, final DataNodeContainer childSchema) { - HashMap getterToLeafSchema = new HashMap<>(); - for (DataSchemaNode leaf : childSchema.getChildNodes()) { + final HashMap getterToLeafSchema = new HashMap<>(); + for (final DataSchemaNode leaf : childSchema.getChildNodes()) { final TypeDefinition typeDef; if (leaf instanceof LeafSchemaNode) { typeDef = ((LeafSchemaNode) leaf).getType(); @@ -195,35 +225,35 @@ class BindingCodecContext implements CodecContextFactory, Immutable { continue; } - String getterName = getGetterName(leaf.getQName(), typeDef); + final String getterName = getGetterName(leaf.getQName(), typeDef); getterToLeafSchema.put(getterName, leaf); } return getLeafNodesUsingReflection(parentClass, getterToLeafSchema); } private String getGetterName(final QName qName, TypeDefinition typeDef) { - String suffix = BindingMapping.getClassName(qName); + final String suffix = BindingMapping.getClassName(qName); while (typeDef.getBaseType() != null) { typeDef = typeDef.getBaseType(); } - if (typeDef instanceof BooleanTypeDefinition) { + if (typeDef instanceof BooleanTypeDefinition || typeDef instanceof EmptyTypeDefinition) { return "is" + suffix; } return GETTER_PREFIX + suffix; } - private ImmutableMap getLeafNodesUsingReflection(final Class parentClass, + private ImmutableMap> getLeafNodesUsingReflection(final Class parentClass, final Map getterToLeafSchema) { - Map leaves = new HashMap<>(); - for (Method method : parentClass.getMethods()) { + final Map> leaves = new HashMap<>(); + for (final Method method : parentClass.getMethods()) { if (method.getParameterTypes().length == 0) { - DataSchemaNode schema = getterToLeafSchema.get(method.getName()); + final DataSchemaNode schema = getterToLeafSchema.get(method.getName()); final Class valueType; if (schema instanceof LeafSchemaNode) { valueType = method.getReturnType(); } else if (schema instanceof LeafListSchemaNode) { - Type genericType = ClassLoaderUtils.getFirstGenericParameter(method.getGenericReturnType()); + final Type genericType = ClassLoaderUtils.getFirstGenericParameter(method.getGenericReturnType()); if (genericType instanceof Class) { valueType = (Class) genericType; @@ -235,17 +265,23 @@ class BindingCodecContext implements CodecContextFactory, Immutable { } else { continue; // We do not have schema for leaf, so we will ignore it (eg. getClass, getImplementedInterface). } - Codec codec = getCodec(valueType, schema); - final LeafNodeCodecContext leafNode = new LeafNodeCodecContext(schema, codec, method); + final Codec codec = getCodec(valueType, schema); + final LeafNodeCodecContext leafNode = new LeafNodeCodecContext<>(schema, codec, method); leaves.put(schema.getQName().getLocalName(), leafNode); } } return ImmutableMap.copyOf(leaves); } - - private Codec getCodec(final Class valueType, final DataSchemaNode schema) { + final TypeDefinition instantiatedType; + if (schema instanceof LeafSchemaNode) { + instantiatedType = ((LeafSchemaNode) schema).getType(); + } else if (schema instanceof LeafListSchemaNode) { + instantiatedType = ((LeafListSchemaNode) schema).getType(); + } else { + throw new IllegalArgumentException("Unsupported leaf node type " + schema.getClass()); + } if (Class.class.equals(valueType)) { @SuppressWarnings({ "unchecked", "rawtypes" }) final Codec casted = (Codec) identityCodec; @@ -254,18 +290,12 @@ class BindingCodecContext implements CodecContextFactory, Immutable { @SuppressWarnings({ "unchecked", "rawtypes" }) final Codec casted = (Codec) instanceIdentifierCodec; return casted; - } else if (BindingReflections.isBindingClass(valueType)) { - final TypeDefinition instantiatedType; - if (schema instanceof LeafSchemaNode) { - instantiatedType = ((LeafSchemaNode) schema).getType(); - } else if (schema instanceof LeafListSchemaNode) { - instantiatedType = ((LeafListSchemaNode) schema).getType(); - } else { - instantiatedType = null; - } - if (instantiatedType != null) { - return getCodec(valueType, instantiatedType); + } else if (Boolean.class.equals(valueType)) { + if(instantiatedType instanceof EmptyTypeDefinition) { + return ValueTypeCodec.EMPTY_CODEC; } + } else if (BindingReflections.isBindingClass(valueType)) { + return getCodec(valueType, instantiatedType); } return ValueTypeCodec.NOOP_CODEC; } @@ -281,151 +311,48 @@ class BindingCodecContext implements CodecContextFactory, Immutable { } else if (rootType instanceof InstanceIdentifierTypeDefinition) { return ValueTypeCodec.encapsulatedValueCodecFor(valueType, instanceIdentifierCodec); } else if (rootType instanceof UnionTypeDefinition) { - Callable loader = UnionTypeCodec.loader(valueType, (UnionTypeDefinition) rootType); + final Callable loader = UnionTypeCodec.loader(valueType, (UnionTypeDefinition) rootType); try { return loader.call(); - } catch (Exception e) { + } catch (final Exception e) { throw new IllegalStateException("Unable to load codec for " + valueType, e); } + } else if(rootType instanceof LeafrefTypeDefinition) { + final Entry typeWithSchema = context.getTypeWithSchema(valueType); + final Object schema = typeWithSchema.getValue(); + Preconditions.checkState(schema instanceof TypeDefinition); + return getCodec(valueType, (TypeDefinition) schema); } return ValueTypeCodec.getCodecFor(valueType, instantiatedType); } - private class InstanceIdentifierCodec implements Codec> { - - @Override - public YangInstanceIdentifier serialize(final InstanceIdentifier input) { - List domArgs = new ArrayList<>(); - getCodecContextNode(input, domArgs); - return YangInstanceIdentifier.create(domArgs); - } - - @Override - public InstanceIdentifier deserialize(final YangInstanceIdentifier input) { - final List builder = new ArrayList<>(); - final NodeCodecContext codec = getCodecContextNode(input, builder); - return codec == null ? null : InstanceIdentifier.create(builder); - } - } - - private class IdentityCodec implements Codec> { - - @Override - public Class deserialize(final QName input) { - Preconditions.checkArgument(input != null, "Input must not be null."); - return context.getIdentityClass(input); - } - - @Override - public QName serialize(final Class input) { - Preconditions.checkArgument(BaseIdentity.class.isAssignableFrom(input)); - return BindingReflections.findQName(input); - } - } - - private static class ValueContext { - - Method getter; - Codec codec; - - public ValueContext(final Class identifier, final LeafNodeCodecContext leaf) { - final String getterName = GETTER_PREFIX - + BindingMapping.getClassName(leaf.getDomPathArgument().getNodeType()); - try { - getter = identifier.getMethod(getterName); - } catch (NoSuchMethodException | SecurityException e) { - throw new IllegalStateException(e); - } - codec = leaf.getValueCodec(); - } - - public Object getAndSerialize(final Object obj) { - try { - Object value = getter.invoke(obj); - Preconditions.checkArgument(value != null, - "All keys must be specified for %s. Missing key is %s. Supplied key is %s", - getter.getDeclaringClass(), getter.getName(), obj); - return codec.serialize(value); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalArgumentException(e); - } - } - - public Object deserialize(final Object obj) { - return codec.deserialize(obj); - } - - } - - private class IdentifiableItemCodec implements Codec> { - - private final ImmutableSortedMap keyValueContexts; - private final ListSchemaNode schema; - private final Constructor> constructor; - private final Class identifiable; - - public IdentifiableItemCodec(final ListSchemaNode schema, final Class> keyClass, - final Class identifiable, final Map keyValueContexts) { - this.schema = schema; - this.identifiable = identifiable; - this.keyValueContexts = ImmutableSortedMap.copyOf(keyValueContexts); - this.constructor = getConstructor(keyClass); - } - - @Override - public IdentifiableItem deserialize(final NodeIdentifierWithPredicates input) { - ArrayList bindingValues = new ArrayList<>(); - - for(QName key: schema.getKeyDefinition()) { - Object yangValue = input.getKeyValues().get(key); - bindingValues.add(keyValueContexts.get(key).deserialize(yangValue)); - } - try { - final Identifier identifier = constructor.newInstance(bindingValues.toArray()); - @SuppressWarnings({ "rawtypes", "unchecked" }) - final IdentifiableItem identifiableItem = new IdentifiableItem(identifiable, identifier); - return identifiableItem; - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException(e); - } - } - - @Override - public NodeIdentifierWithPredicates serialize(final IdentifiableItem input) { - Object value = input.getKey(); - - Map values = new HashMap<>(); - for (Entry valueCtx : keyValueContexts.entrySet()) { - values.put(valueCtx.getKey(), valueCtx.getValue().getAndSerialize(value)); - } - return new NodeIdentifierWithPredicates(schema.getQName(), values); - } - - } - - @SuppressWarnings("unchecked") - private static Constructor> getConstructor(final Class> clazz) { - for (@SuppressWarnings("rawtypes") Constructor constr : clazz.getConstructors()) { - Class[] parameters = constr.getParameterTypes(); - if (!clazz.equals(parameters[0])) { - // It is not copy constructor; - return constr; - } - } - throw new IllegalArgumentException("Supplied class " + clazz + "does not have required constructor."); - } - @Override public Codec> getPathArgumentCodec(final Class listClz, final ListSchemaNode schema) { - Class> identifier = ClassLoaderUtils.findFirstGenericArgument(listClz, + final Class> identifier = ClassLoaderUtils.findFirstGenericArgument(listClz, Identifiable.class); - Map valueCtx = new HashMap<>(); - for (LeafNodeCodecContext leaf : getLeafNodes(identifier, schema).values()) { - QName name = leaf.getDomPathArgument().getNodeType(); + final Map valueCtx = new HashMap<>(); + for (final LeafNodeCodecContext leaf : getLeafNodes(identifier, schema).values()) { + final QName name = leaf.getDomPathArgument().getNodeType(); valueCtx.put(name, new ValueContext(identifier, leaf)); } return new IdentifiableItemCodec(schema, identifier, listClz, valueCtx); } + @SuppressWarnings("unchecked") + @Override + public BindingCodecTreeNode getSubtreeCodec(InstanceIdentifier path) { + // TODO Do we need defensive check here? + return (BindingCodecTreeNode) getCodecContextNode(path, null); + } + + @Override + public BindingCodecTreeNode getSubtreeCodec(YangInstanceIdentifier path) { + return getCodecContextNode(path, null); + } + + @Override + public BindingCodecTreeNode getSubtreeCodec(SchemaPath path) { + throw new UnsupportedOperationException("Not implemented yet."); + } }