bb6d22c8120dd392e408abf4cc6687011273806b
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / DataContainerCodecPrototype.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.mdsal.binding.dom.codec.impl;
9
10 import com.google.common.collect.Iterables;
11 import javax.annotation.concurrent.GuardedBy;
12 import org.opendaylight.mdsal.binding.dom.codec.impl.NodeCodecContext.CodecContextFactory;
13 import org.opendaylight.yangtools.yang.binding.DataRoot;
14 import org.opendaylight.yangtools.yang.binding.Identifiable;
15 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
16 import org.opendaylight.yangtools.yang.common.QNameModule;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
21 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
27 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
29 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
30
31 final class DataContainerCodecPrototype<T extends WithStatus> implements NodeContextSupplier {
32
33     private final T schema;
34     private final QNameModule namespace;
35     private final CodecContextFactory factory;
36     private final Class<?> bindingClass;
37     private final InstanceIdentifier.Item<?> bindingArg;
38     private final YangInstanceIdentifier.PathArgument yangArg;
39     private volatile DataContainerCodecContext<?, T> instance = null;
40
41     @SuppressWarnings({"rawtypes", "unchecked"})
42     private DataContainerCodecPrototype(final Class<?> cls, final YangInstanceIdentifier.PathArgument arg,
43             final T nodeSchema, final CodecContextFactory factory) {
44         this.bindingClass = cls;
45         this.yangArg = arg;
46         this.schema = nodeSchema;
47         this.factory = factory;
48         this.bindingArg = new InstanceIdentifier.Item(bindingClass);
49
50         if (arg instanceof AugmentationIdentifier) {
51             this.namespace = Iterables.getFirst(((AugmentationIdentifier) arg).getPossibleChildNames(), null)
52                     .getModule();
53         } else {
54             this.namespace = arg.getNodeType().getModule();
55         }
56     }
57
58     static DataContainerCodecPrototype<SchemaContext> rootPrototype(final CodecContextFactory factory) {
59         final SchemaContext schema = factory.getRuntimeContext().getSchemaContext();
60         final NodeIdentifier arg = NodeIdentifier.create(schema.getQName());
61         return new DataContainerCodecPrototype<>(DataRoot.class, arg, schema, factory);
62     }
63
64     @SuppressWarnings({ "unchecked", "rawtypes" })
65     static <T extends DataSchemaNode> DataContainerCodecPrototype<T> from(final Class<?> cls, final T schema,
66             final CodecContextFactory factory) {
67         return new DataContainerCodecPrototype(cls, NodeIdentifier.create(schema.getQName()), schema, factory);
68     }
69
70     @SuppressWarnings({ "rawtypes", "unchecked" })
71     static DataContainerCodecPrototype<?> from(final Class<?> augClass, final AugmentationIdentifier arg,
72             final AugmentationSchemaNode schema, final CodecContextFactory factory) {
73         return new DataContainerCodecPrototype(augClass, arg, schema, factory);
74     }
75
76     static DataContainerCodecPrototype<NotificationDefinition> from(final Class<?> augClass,
77             final NotificationDefinition schema, final CodecContextFactory factory) {
78         final PathArgument arg = NodeIdentifier.create(schema.getQName());
79         return new DataContainerCodecPrototype<>(augClass,arg, schema, factory);
80     }
81
82     protected T getSchema() {
83         return schema;
84     }
85
86     protected QNameModule getNamespace() {
87         return namespace;
88     }
89
90     protected CodecContextFactory getFactory() {
91         return factory;
92     }
93
94     protected Class<?> getBindingClass() {
95         return bindingClass;
96     }
97
98     protected InstanceIdentifier.Item<?> getBindingArg() {
99         return bindingArg;
100     }
101
102     protected YangInstanceIdentifier.PathArgument getYangArg() {
103         return yangArg;
104     }
105
106     @Override
107     public DataContainerCodecContext<?,T> get() {
108         DataContainerCodecContext<?,T> tmp = instance;
109         if (tmp == null) {
110             synchronized (this) {
111                 tmp = instance;
112                 if (tmp == null) {
113                     tmp = createInstance();
114                     instance = tmp;
115                 }
116             }
117         }
118
119         return tmp;
120     }
121
122     @GuardedBy("this")
123     @SuppressWarnings({ "rawtypes", "unchecked" })
124     private DataContainerCodecContext<?,T> createInstance() {
125         // FIXME: make protected abstract
126         if (schema instanceof ContainerSchemaNode) {
127             return new ContainerNodeCodecContext(this);
128         } else if (schema instanceof ListSchemaNode) {
129             if (Identifiable.class.isAssignableFrom(getBindingClass())) {
130                 return new KeyedListNodeCodecContext(this);
131             } else {
132                 return new ListNodeCodecContext(this);
133             }
134         } else if (schema instanceof ChoiceSchemaNode) {
135             return new ChoiceNodeCodecContext(this);
136         } else if (schema instanceof AugmentationSchemaNode) {
137             return new AugmentationNodeContext(this);
138         } else if (schema instanceof CaseSchemaNode) {
139             return new CaseNodeCodecContext(this);
140         }
141         throw new IllegalArgumentException("Unsupported type " + bindingClass + " " + schema);
142     }
143
144     boolean isChoice() {
145         return schema instanceof ChoiceSchemaNode;
146     }
147 }