2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.binding.dom.codec.impl;
10 import com.google.common.collect.Iterables;
11 import javax.annotation.concurrent.GuardedBy;
12 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeNode.ChildAddressabilitySummary;
13 import org.opendaylight.mdsal.binding.dom.codec.impl.NodeCodecContext.CodecContextFactory;
14 import org.opendaylight.yangtools.yang.binding.DataObject;
15 import org.opendaylight.yangtools.yang.binding.DataRoot;
16 import org.opendaylight.yangtools.yang.binding.Identifiable;
17 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
18 import org.opendaylight.yangtools.yang.common.QNameModule;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
22 import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
29 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
31 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
34 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 final class DataContainerCodecPrototype<T extends WithStatus> implements NodeContextSupplier {
39 private static final Logger LOG = LoggerFactory.getLogger(DataContainerCodecPrototype.class);
41 private final T schema;
42 private final QNameModule namespace;
43 private final CodecContextFactory factory;
44 private final Class<?> bindingClass;
45 private final Item<?> bindingArg;
46 private final PathArgument yangArg;
47 private final ChildAddressabilitySummary childAddressabilitySummary;
49 private volatile DataContainerCodecContext<?, T> instance = null;
51 @SuppressWarnings("unchecked")
52 private DataContainerCodecPrototype(final Class<?> cls, final PathArgument arg, final T nodeSchema,
53 final CodecContextFactory factory) {
54 this.bindingClass = cls;
56 this.schema = nodeSchema;
57 this.factory = factory;
58 this.bindingArg = Item.of((Class<? extends DataObject>) bindingClass);
60 if (arg instanceof AugmentationIdentifier) {
61 this.namespace = Iterables.getFirst(((AugmentationIdentifier) arg).getPossibleChildNames(), null)
64 this.namespace = arg.getNodeType().getModule();
67 this.childAddressabilitySummary = computeChildAddressabilitySummary(nodeSchema);
70 private static ChildAddressabilitySummary computeChildAddressabilitySummary(final WithStatus nodeSchema) {
71 if (nodeSchema instanceof DataNodeContainer) {
72 boolean haveAddressable = false;
73 boolean haveUnaddressable = false;
74 for (DataSchemaNode child : ((DataNodeContainer) nodeSchema).getChildNodes()) {
75 if (child instanceof ContainerSchemaNode || child instanceof AugmentationSchemaNode) {
76 haveAddressable = true;
77 } else if (child instanceof ListSchemaNode) {
78 if (((ListSchemaNode) child).getKeyDefinition().isEmpty()) {
79 haveUnaddressable = true;
81 haveAddressable = true;
83 } else if (child instanceof AnyDataSchemaNode || child instanceof AnyXmlSchemaNode
84 || child instanceof TypedDataSchemaNode) {
85 haveUnaddressable = true;
86 } else if (child instanceof ChoiceSchemaNode) {
87 switch (computeChildAddressabilitySummary(child)) {
89 haveAddressable = true;
92 haveAddressable = true;
93 haveUnaddressable = true;
96 haveUnaddressable = true;
99 throw new IllegalStateException("Unhandled accessibility summary for " + child);
102 LOG.warn("Unhandled child node {}", child);
106 if (!haveAddressable) {
107 // Empty or all are unaddressable
108 return ChildAddressabilitySummary.UNADDRESSABLE;
111 return haveUnaddressable ? ChildAddressabilitySummary.MIXED : ChildAddressabilitySummary.ADDRESSABLE;
112 } else if (nodeSchema instanceof ChoiceSchemaNode) {
113 boolean haveAddressable = false;
114 boolean haveUnaddressable = false;
115 for (CaseSchemaNode child : ((ChoiceSchemaNode) nodeSchema).getCases().values()) {
116 switch (computeChildAddressabilitySummary(child)) {
118 haveAddressable = true;
121 haveUnaddressable = true;
124 // A child is mixed, which means we are mixed, too
125 return ChildAddressabilitySummary.MIXED;
127 throw new IllegalStateException("Unhandled accessibility summary for " + child);
131 if (!haveAddressable) {
132 // Empty or all are unaddressable
133 return ChildAddressabilitySummary.UNADDRESSABLE;
136 return haveUnaddressable ? ChildAddressabilitySummary.MIXED : ChildAddressabilitySummary.ADDRESSABLE;
139 // No child nodes possible: return unaddressable
140 return ChildAddressabilitySummary.UNADDRESSABLE;
143 static DataContainerCodecPrototype<SchemaContext> rootPrototype(final CodecContextFactory factory) {
144 final SchemaContext schema = factory.getRuntimeContext().getSchemaContext();
145 final NodeIdentifier arg = NodeIdentifier.create(schema.getQName());
146 return new DataContainerCodecPrototype<>(DataRoot.class, arg, schema, factory);
149 @SuppressWarnings({ "unchecked", "rawtypes" })
150 static <T extends DataSchemaNode> DataContainerCodecPrototype<T> from(final Class<?> cls, final T schema,
151 final CodecContextFactory factory) {
152 return new DataContainerCodecPrototype(cls, NodeIdentifier.create(schema.getQName()), schema, factory);
155 @SuppressWarnings({ "rawtypes", "unchecked" })
156 static DataContainerCodecPrototype<?> from(final Class<?> augClass, final AugmentationIdentifier arg,
157 final AugmentationSchemaNode schema, final CodecContextFactory factory) {
158 return new DataContainerCodecPrototype(augClass, arg, schema, factory);
161 static DataContainerCodecPrototype<NotificationDefinition> from(final Class<?> augClass,
162 final NotificationDefinition schema, final CodecContextFactory factory) {
163 final PathArgument arg = NodeIdentifier.create(schema.getQName());
164 return new DataContainerCodecPrototype<>(augClass,arg, schema, factory);
167 protected T getSchema() {
171 ChildAddressabilitySummary getChildAddressabilitySummary() {
172 return childAddressabilitySummary;
175 protected QNameModule getNamespace() {
179 protected CodecContextFactory getFactory() {
183 protected Class<?> getBindingClass() {
187 protected Item<?> getBindingArg() {
191 protected PathArgument getYangArg() {
196 public DataContainerCodecContext<?,T> get() {
197 DataContainerCodecContext<?,T> tmp = instance;
199 synchronized (this) {
202 tmp = createInstance();
212 @SuppressWarnings({ "rawtypes", "unchecked" })
213 private DataContainerCodecContext<?,T> createInstance() {
214 // FIXME: make protected abstract
215 if (schema instanceof ContainerSchemaNode) {
216 return new ContainerNodeCodecContext(this);
217 } else if (schema instanceof ListSchemaNode) {
218 return Identifiable.class.isAssignableFrom(getBindingClass()) ? new KeyedListNodeCodecContext(this)
219 : new ListNodeCodecContext(this);
220 } else if (schema instanceof ChoiceSchemaNode) {
221 return new ChoiceNodeCodecContext(this);
222 } else if (schema instanceof AugmentationSchemaNode) {
223 return new AugmentationNodeContext(this);
224 } else if (schema instanceof CaseSchemaNode) {
225 return new CaseNodeCodecContext(this);
227 throw new IllegalArgumentException("Unsupported type " + bindingClass + " " + schema);
231 return schema instanceof ChoiceSchemaNode;