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