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.eclipse.jdt.annotation.NonNull;
13 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeNode.ChildAddressabilitySummary;
14 import org.opendaylight.mdsal.binding.dom.codec.impl.NodeCodecContext.CodecContextFactory;
15 import org.opendaylight.yangtools.yang.binding.DataObject;
16 import org.opendaylight.yangtools.yang.binding.DataRoot;
17 import org.opendaylight.yangtools.yang.binding.Identifiable;
18 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
19 import org.opendaylight.yangtools.yang.common.QNameModule;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
23 import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
30 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
32 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
34 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
35 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 final class DataContainerCodecPrototype<T extends WithStatus> implements NodeContextSupplier {
40 private static final Logger LOG = LoggerFactory.getLogger(DataContainerCodecPrototype.class);
42 private final T schema;
43 private final QNameModule namespace;
44 private final CodecContextFactory factory;
45 private final Item<?> bindingArg;
46 private final PathArgument yangArg;
47 private final ChildAddressabilitySummary childAddressabilitySummary;
49 private volatile DataContainerCodecContext<?, T> instance;
51 @SuppressWarnings("unchecked")
52 private DataContainerCodecPrototype(final Class<?> cls, final PathArgument arg, final T nodeSchema,
53 final CodecContextFactory factory) {
54 this(Item.of((Class<? extends DataObject>) cls), arg, nodeSchema, factory);
57 private DataContainerCodecPrototype(final Item<?> bindingArg, final PathArgument arg, final T nodeSchema,
58 final CodecContextFactory factory) {
59 this.bindingArg = bindingArg;
61 this.schema = nodeSchema;
62 this.factory = factory;
64 if (arg instanceof AugmentationIdentifier) {
65 this.namespace = Iterables.getFirst(((AugmentationIdentifier) arg).getPossibleChildNames(), null)
68 this.namespace = arg.getNodeType().getModule();
71 this.childAddressabilitySummary = computeChildAddressabilitySummary(nodeSchema);
74 private static ChildAddressabilitySummary computeChildAddressabilitySummary(final WithStatus nodeSchema) {
75 if (nodeSchema instanceof DataNodeContainer) {
76 boolean haveAddressable = false;
77 boolean haveUnaddressable = false;
78 for (DataSchemaNode child : ((DataNodeContainer) nodeSchema).getChildNodes()) {
79 if (child instanceof ContainerSchemaNode || child instanceof AugmentationSchemaNode) {
80 haveAddressable = true;
81 } else if (child instanceof ListSchemaNode) {
82 if (((ListSchemaNode) child).getKeyDefinition().isEmpty()) {
83 haveUnaddressable = true;
85 haveAddressable = true;
87 } else if (child instanceof AnyDataSchemaNode || child instanceof AnyXmlSchemaNode
88 || child instanceof TypedDataSchemaNode) {
89 haveUnaddressable = true;
90 } else if (child instanceof ChoiceSchemaNode) {
91 switch (computeChildAddressabilitySummary(child)) {
93 haveAddressable = true;
96 haveAddressable = true;
97 haveUnaddressable = true;
100 haveUnaddressable = true;
103 throw new IllegalStateException("Unhandled accessibility summary for " + child);
106 LOG.warn("Unhandled child node {}", child);
110 if (!haveAddressable) {
111 // Empty or all are unaddressable
112 return ChildAddressabilitySummary.UNADDRESSABLE;
115 return haveUnaddressable ? ChildAddressabilitySummary.MIXED : ChildAddressabilitySummary.ADDRESSABLE;
116 } else if (nodeSchema instanceof ChoiceSchemaNode) {
117 boolean haveAddressable = false;
118 boolean haveUnaddressable = false;
119 for (CaseSchemaNode child : ((ChoiceSchemaNode) nodeSchema).getCases().values()) {
120 switch (computeChildAddressabilitySummary(child)) {
122 haveAddressable = true;
125 haveUnaddressable = true;
128 // A child is mixed, which means we are mixed, too
129 return ChildAddressabilitySummary.MIXED;
131 throw new IllegalStateException("Unhandled accessibility summary for " + child);
135 if (!haveAddressable) {
136 // Empty or all are unaddressable
137 return ChildAddressabilitySummary.UNADDRESSABLE;
140 return haveUnaddressable ? ChildAddressabilitySummary.MIXED : ChildAddressabilitySummary.ADDRESSABLE;
143 // No child nodes possible: return unaddressable
144 return ChildAddressabilitySummary.UNADDRESSABLE;
147 static DataContainerCodecPrototype<SchemaContext> rootPrototype(final CodecContextFactory factory) {
148 final SchemaContext schema = factory.getRuntimeContext().getSchemaContext();
149 final NodeIdentifier arg = NodeIdentifier.create(schema.getQName());
150 return new DataContainerCodecPrototype<>(DataRoot.class, arg, schema, factory);
153 @SuppressWarnings({ "unchecked", "rawtypes" })
154 static <T extends DataSchemaNode> DataContainerCodecPrototype<T> from(final Class<?> cls, final T schema,
155 final CodecContextFactory factory) {
156 return new DataContainerCodecPrototype(cls, NodeIdentifier.create(schema.getQName()), schema, factory);
159 @SuppressWarnings({ "unchecked", "rawtypes" })
160 static <T extends DataSchemaNode> DataContainerCodecPrototype<T> from(final Item<?> bindingArg, final T schema,
161 final CodecContextFactory factory) {
162 return new DataContainerCodecPrototype(bindingArg, NodeIdentifier.create(schema.getQName()), schema, factory);
165 @SuppressWarnings({ "rawtypes", "unchecked" })
166 static DataContainerCodecPrototype<?> from(final Class<?> augClass, final AugmentationIdentifier arg,
167 final AugmentationSchemaNode schema, final CodecContextFactory factory) {
168 return new DataContainerCodecPrototype(augClass, arg, schema, factory);
171 static DataContainerCodecPrototype<NotificationDefinition> from(final Class<?> augClass,
172 final NotificationDefinition schema, final CodecContextFactory factory) {
173 final PathArgument arg = NodeIdentifier.create(schema.getQName());
174 return new DataContainerCodecPrototype<>(augClass,arg, schema, factory);
177 protected T getSchema() {
181 ChildAddressabilitySummary getChildAddressabilitySummary() {
182 return childAddressabilitySummary;
185 protected QNameModule getNamespace() {
189 protected CodecContextFactory getFactory() {
193 protected Class<?> getBindingClass() {
194 return bindingArg.getType();
197 protected Item<?> getBindingArg() {
201 protected PathArgument getYangArg() {
206 public DataContainerCodecContext<?,T> get() {
207 DataContainerCodecContext<?,T> tmp = instance;
209 synchronized (this) {
212 instance = tmp = createInstance();
221 @SuppressWarnings({ "rawtypes", "unchecked" })
222 private @NonNull DataContainerCodecContext<?, T> createInstance() {
223 // FIXME: make protected abstract
224 if (schema instanceof ContainerSchemaNode) {
225 return new ContainerNodeCodecContext(this);
226 } else if (schema instanceof ListSchemaNode) {
227 return Identifiable.class.isAssignableFrom(getBindingClass()) ? new KeyedListNodeCodecContext(this)
228 : new ListNodeCodecContext(this);
229 } else if (schema instanceof ChoiceSchemaNode) {
230 return new ChoiceNodeCodecContext(this);
231 } else if (schema instanceof AugmentationSchemaNode) {
232 return new AugmentationNodeContext(this);
233 } else if (schema instanceof CaseSchemaNode) {
234 return new CaseNodeCodecContext(this);
236 throw new IllegalArgumentException("Unsupported type " + getBindingClass() + " " + schema);
240 return schema instanceof ChoiceSchemaNode;