Merge "Changed NetconfDeviceDatastoreAdapter and NetconfDeviceTopologyAdapter to...
[controller.git] / opendaylight / md-sal / sal-rest-docgen / src / main / java / org / opendaylight / controller / sal / rest / doc / impl / ModelGenerator.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.controller.sal.rest.doc.impl;
9
10 import static org.opendaylight.controller.sal.rest.doc.impl.BaseYangSwaggerGenerator.MODULE_NAME_SUFFIX;
11 import static org.opendaylight.controller.sal.rest.doc.model.builder.OperationBuilder.Post.METHOD_NAME;
12 import static org.opendaylight.controller.sal.rest.doc.util.RestDocgenUtil.resolveNodesName;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableMap;
15 import com.google.common.collect.ImmutableMap.Builder;
16 import java.io.IOException;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import javax.annotation.concurrent.NotThreadSafe;
22 import org.apache.commons.lang3.BooleanUtils;
23 import org.json.JSONArray;
24 import org.json.JSONException;
25 import org.json.JSONObject;
26 import org.opendaylight.controller.sal.rest.doc.model.builder.OperationBuilder;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
30 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
32 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
34 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.Module;
40 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
41 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
42 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
44 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
45 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
46 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
47 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
48 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
49 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
50 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
51 import org.opendaylight.yangtools.yang.model.util.BooleanType;
52 import org.opendaylight.yangtools.yang.model.util.Decimal64;
53 import org.opendaylight.yangtools.yang.model.util.EnumerationType;
54 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
55 import org.opendaylight.yangtools.yang.model.util.Int16;
56 import org.opendaylight.yangtools.yang.model.util.Int32;
57 import org.opendaylight.yangtools.yang.model.util.Int64;
58 import org.opendaylight.yangtools.yang.model.util.Int8;
59 import org.opendaylight.yangtools.yang.model.util.StringType;
60 import org.opendaylight.yangtools.yang.model.util.Uint16;
61 import org.opendaylight.yangtools.yang.model.util.Uint32;
62 import org.opendaylight.yangtools.yang.model.util.Uint64;
63 import org.opendaylight.yangtools.yang.model.util.Uint8;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 /**
68  * Generates JSON Schema for data defined in Yang
69  */
70 @NotThreadSafe
71 public class ModelGenerator {
72
73     private static final Logger LOG = LoggerFactory.getLogger(ModelGenerator.class);
74
75     private static final String BASE_64 = "base64";
76     private static final String BINARY_ENCODING_KEY = "binaryEncoding";
77     private static final String MEDIA_KEY = "media";
78     private static final String ONE_OF_KEY = "oneOf";
79     private static final String UNIQUE_ITEMS_KEY = "uniqueItems";
80     private static final String MAX_ITEMS = "maxItems";
81     private static final String MIN_ITEMS = "minItems";
82     private static final String SCHEMA_URL = "http://json-schema.org/draft-04/schema";
83     private static final String SCHEMA_KEY = "$schema";
84     private static final String MAX_LENGTH_KEY = "maxLength";
85     private static final String MIN_LENGTH_KEY = "minLength";
86     private static final String REQUIRED_KEY = "required";
87     private static final String REF_KEY = "$ref";
88     private static final String ITEMS_KEY = "items";
89     private static final String TYPE_KEY = "type";
90     private static final String PROPERTIES_KEY = "properties";
91     private static final String DESCRIPTION_KEY = "description";
92     private static final String OBJECT_TYPE = "object";
93     private static final String ARRAY_TYPE = "array";
94     private static final String ENUM = "enum";
95     private static final String INTEGER = "integer";
96     private static final String NUMBER = "number";
97     private static final String BOOLEAN = "boolean";
98     private static final String STRING = "string";
99     private static final String ID_KEY = "id";
100     private static final String SUB_TYPES_KEY = "subTypes";
101
102     private static final Map<Class<?>, String> YANG_TYPE_TO_JSON_TYPE_MAPPING;
103
104     static {
105         final Builder<Class<?>, String> b = ImmutableMap.builder();
106
107         b.put(StringType.class, STRING);
108         b.put(BooleanType.class, BOOLEAN);
109         b.put(Int8.class, INTEGER);
110         b.put(Int16.class, INTEGER);
111         b.put(Int32.class, INTEGER);
112         b.put(Int64.class, INTEGER);
113         b.put(Uint16.class, INTEGER);
114         b.put(Uint32.class, INTEGER);
115         b.put(Uint64.class, INTEGER);
116         b.put(Uint8.class, INTEGER);
117         b.put(Decimal64.class, NUMBER);
118         b.put(EnumerationType.class, ENUM);
119         // TODO: Binary type
120
121         YANG_TYPE_TO_JSON_TYPE_MAPPING = b.build();
122     }
123
124     private Module topLevelModule;
125
126     public ModelGenerator() {
127     }
128
129     public JSONObject convertToJsonSchema(final Module module, final SchemaContext schemaContext) throws IOException, JSONException {
130         JSONObject models = new JSONObject();
131         topLevelModule = module;
132         processModules(module, models);
133         processContainersAndLists(module, models, schemaContext);
134         processRPCs(module, models, schemaContext);
135         processIdentities(module, models);
136         return models;
137     }
138
139     private void processModules(final Module module, final JSONObject models) throws JSONException {
140         createConcreteModelForPost(models, module.getName()+MODULE_NAME_SUFFIX, createPropertiesForPost(module));
141     }
142
143     private void processContainersAndLists(final Module module, final JSONObject models, final SchemaContext schemaContext)
144             throws IOException, JSONException {
145
146         String moduleName = module.getName();
147
148         for (DataSchemaNode childNode : module.getChildNodes()) {
149             // For every container and list in the module
150             if (childNode instanceof ContainerSchemaNode || childNode instanceof ListSchemaNode) {
151                 processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, true, schemaContext);
152                 processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, false, schemaContext);
153             }
154         }
155
156     }
157
158     /**
159      * Process the RPCs for a Module Spits out a file each of the name <rpcName>-input.json and <rpcName>-output.json
160      * for each RPC that contains input & output elements
161      *
162      * @param module
163      * @throws JSONException
164      * @throws IOException
165      */
166     private void processRPCs(final Module module, final JSONObject models, final SchemaContext schemaContext) throws JSONException,
167             IOException {
168
169         Set<RpcDefinition> rpcs = module.getRpcs();
170         String moduleName = module.getName();
171         for (RpcDefinition rpc : rpcs) {
172
173             ContainerSchemaNode input = rpc.getInput();
174             if (input != null) {
175                 JSONObject inputJSON = processDataNodeContainer(input, moduleName, models, schemaContext);
176                 String filename = "(" + rpc.getQName().getLocalName() + ")input";
177                 inputJSON.put("id", filename);
178                 // writeToFile(filename, inputJSON.toString(2), moduleName);
179                 models.put(filename, inputJSON);
180             }
181
182             ContainerSchemaNode output = rpc.getOutput();
183             if (output != null) {
184                 JSONObject outputJSON = processDataNodeContainer(output, moduleName, models, schemaContext);
185                 String filename = "(" + rpc.getQName().getLocalName() + ")output";
186                 outputJSON.put("id", filename);
187                 models.put(filename, outputJSON);
188             }
189         }
190     }
191
192     /**
193      * Processes the 'identity' statement in a yang model and maps it to a 'model' in the Swagger JSON spec.
194      *
195      * @param module
196      *            The module from which the identity stmt will be processed
197      * @param models
198      *            The JSONObject in which the parsed identity will be put as a 'model' obj
199      * @throws JSONException
200      */
201     private void processIdentities(final Module module, final JSONObject models) throws JSONException {
202
203         String moduleName = module.getName();
204         Set<IdentitySchemaNode> idNodes = module.getIdentities();
205         LOG.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size());
206
207         for (IdentitySchemaNode idNode : idNodes) {
208             JSONObject identityObj = new JSONObject();
209             String identityName = idNode.getQName().getLocalName();
210             LOG.debug("Processing Identity: {}", identityName);
211
212             identityObj.put(ID_KEY, identityName);
213             identityObj.put(DESCRIPTION_KEY, idNode.getDescription());
214
215             JSONObject props = new JSONObject();
216             IdentitySchemaNode baseId = idNode.getBaseIdentity();
217
218             if (baseId == null) {
219                 /**
220                  * This is a base identity. So lets see if it has sub types. If it does, then add them to the model
221                  * definition.
222                  */
223                 Set<IdentitySchemaNode> derivedIds = idNode.getDerivedIdentities();
224
225                 if (derivedIds != null) {
226                     JSONArray subTypes = new JSONArray();
227                     for (IdentitySchemaNode derivedId : derivedIds) {
228                         subTypes.put(derivedId.getQName().getLocalName());
229                     }
230                     identityObj.put(SUB_TYPES_KEY, subTypes);
231                 }
232             } else {
233                 /**
234                  * This is a derived entity. Add it's base type & move on.
235                  */
236                 props.put(TYPE_KEY, baseId.getQName().getLocalName());
237             }
238
239             // Add the properties. For a base type, this will be an empty object as required by the Swagger spec.
240             identityObj.put(PROPERTIES_KEY, props);
241             models.put(identityName, identityObj);
242         }
243     }
244
245     /**
246      * Processes the container and list nodes and populates the moduleJSON
247      *
248      * @param container
249      * @param moduleName
250      * @param isConfig
251      * @throws JSONException
252      * @throws IOException
253      */
254     private JSONObject processDataNodeContainer(final DataNodeContainer dataNode, final String moduleName, final JSONObject models,
255             final SchemaContext schemaContext) throws JSONException, IOException {
256         return processDataNodeContainer(dataNode, moduleName, models, (Boolean) null, schemaContext);
257     }
258
259     private JSONObject processDataNodeContainer(final DataNodeContainer dataNode, final String moduleName, final JSONObject models,
260             final Boolean isConfig, final SchemaContext schemaContext) throws JSONException, IOException {
261         if (dataNode instanceof ListSchemaNode || dataNode instanceof ContainerSchemaNode) {
262             Preconditions.checkArgument(dataNode instanceof SchemaNode, "Data node should be also schema node");
263             Iterable<DataSchemaNode> containerChildren = dataNode.getChildNodes();
264             JSONObject properties = processChildren(containerChildren, ((SchemaNode) dataNode).getQName(), moduleName,
265                     models, isConfig, schemaContext);
266
267             String nodeName = (BooleanUtils.isNotFalse(isConfig) ? OperationBuilder.CONFIG
268                     : OperationBuilder.OPERATIONAL) + ((SchemaNode) dataNode).getQName().getLocalName();
269
270             JSONObject childSchema = getSchemaTemplate();
271             childSchema.put(TYPE_KEY, OBJECT_TYPE);
272             childSchema.put(PROPERTIES_KEY, properties);
273             childSchema.put("id", nodeName);
274             models.put(nodeName, childSchema);
275
276             if (BooleanUtils.isNotFalse(isConfig)) {
277                 createConcreteModelForPost(models, ((SchemaNode) dataNode).getQName().getLocalName(),
278                         createPropertiesForPost(dataNode));
279             }
280
281             JSONObject items = new JSONObject();
282             items.put(REF_KEY, nodeName);
283             JSONObject dataNodeProperties = new JSONObject();
284             dataNodeProperties.put(TYPE_KEY, dataNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE);
285             dataNodeProperties.put(ITEMS_KEY, items);
286
287             return dataNodeProperties;
288         }
289         return null;
290     }
291
292     private void createConcreteModelForPost(final JSONObject models, final String localName, final JSONObject properties)
293             throws JSONException {
294         String nodePostName = OperationBuilder.CONFIG + localName + METHOD_NAME;
295         JSONObject postSchema = getSchemaTemplate();
296         postSchema.put(TYPE_KEY, OBJECT_TYPE);
297         postSchema.put("id", nodePostName);
298         postSchema.put(PROPERTIES_KEY, properties);
299         models.put(nodePostName, postSchema);
300     }
301
302     private JSONObject createPropertiesForPost(final DataNodeContainer dataNodeContainer) throws JSONException {
303         JSONObject properties = new JSONObject();
304         for (DataSchemaNode childNode : dataNodeContainer.getChildNodes()) {
305             if (childNode instanceof ListSchemaNode || childNode instanceof ContainerSchemaNode) {
306                 JSONObject items = new JSONObject();
307                 items.put(REF_KEY, "(config)" + childNode.getQName().getLocalName());
308                 JSONObject property = new JSONObject();
309                 property.put(TYPE_KEY, childNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE);
310                 property.put(ITEMS_KEY, items);
311                 properties.put(childNode.getQName().getLocalName(), property);
312             } else if (childNode instanceof LeafSchemaNode){
313                 JSONObject property = processLeafNode((LeafSchemaNode)childNode);
314                 properties.put(childNode.getQName().getLocalName(), property);
315             }
316         }
317         return properties;
318     }
319
320     private JSONObject processChildren(final Iterable<DataSchemaNode> nodes, final QName parentQName, final String moduleName,
321             final JSONObject models, final SchemaContext schemaContext) throws JSONException, IOException {
322         return processChildren(nodes, parentQName, moduleName, models, null, schemaContext);
323     }
324
325     /**
326      * Processes the nodes
327      *
328      * @param nodes
329      * @param parentQName
330      * @param moduleName
331      * @param isConfig
332      * @return
333      * @throws JSONException
334      * @throws IOException
335      */
336     private JSONObject processChildren(final Iterable<DataSchemaNode> nodes, final QName parentQName, final String moduleName,
337             final JSONObject models, final Boolean isConfig, final SchemaContext schemaContext) throws JSONException, IOException {
338
339         JSONObject properties = new JSONObject();
340
341         for (DataSchemaNode node : nodes) {
342             if (isConfig == null || node.isConfiguration() == isConfig) {
343
344                 String name = resolveNodesName(node, topLevelModule, schemaContext);
345                 JSONObject property = null;
346                 if (node instanceof LeafSchemaNode) {
347                     property = processLeafNode((LeafSchemaNode) node);
348                 } else if (node instanceof ListSchemaNode) {
349                     property = processDataNodeContainer((ListSchemaNode) node, moduleName, models, isConfig,
350                             schemaContext);
351
352                 } else if (node instanceof LeafListSchemaNode) {
353                     property = processLeafListNode((LeafListSchemaNode) node);
354
355                 } else if (node instanceof ChoiceSchemaNode) {
356                     property = processChoiceNode((ChoiceSchemaNode) node, moduleName, models, schemaContext);
357
358                 } else if (node instanceof AnyXmlSchemaNode) {
359                     property = processAnyXMLNode((AnyXmlSchemaNode) node);
360
361                 } else if (node instanceof ContainerSchemaNode) {
362                     property = processDataNodeContainer((ContainerSchemaNode) node, moduleName, models, isConfig,
363                             schemaContext);
364
365                 } else {
366                     throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass());
367                 }
368
369                 property.putOpt(DESCRIPTION_KEY, node.getDescription());
370                 properties.put(name, property);
371             }
372         }
373         return properties;
374     }
375
376     /**
377      *
378      * @param listNode
379      * @throws JSONException
380      */
381     private JSONObject processLeafListNode(final LeafListSchemaNode listNode) throws JSONException {
382         JSONObject props = new JSONObject();
383         props.put(TYPE_KEY, ARRAY_TYPE);
384
385         JSONObject itemsVal = new JSONObject();
386         processTypeDef(listNode.getType(), itemsVal);
387         props.put(ITEMS_KEY, itemsVal);
388
389         ConstraintDefinition constraints = listNode.getConstraints();
390         processConstraints(constraints, props);
391
392         return props;
393     }
394
395     /**
396      *
397      * @param choiceNode
398      * @param moduleName
399      * @throws JSONException
400      * @throws IOException
401      */
402     private JSONObject processChoiceNode(final ChoiceSchemaNode choiceNode, final String moduleName, final JSONObject models,
403             final SchemaContext schemaContext) throws JSONException, IOException {
404
405         Set<ChoiceCaseNode> cases = choiceNode.getCases();
406
407         JSONArray choiceProps = new JSONArray();
408         for (ChoiceCaseNode choiceCase : cases) {
409             String choiceName = choiceCase.getQName().getLocalName();
410             JSONObject choiceProp = processChildren(choiceCase.getChildNodes(), choiceCase.getQName(), moduleName,
411                     models, schemaContext);
412             JSONObject choiceObj = new JSONObject();
413             choiceObj.put(choiceName, choiceProp);
414             choiceObj.put(TYPE_KEY, OBJECT_TYPE);
415             choiceProps.put(choiceObj);
416         }
417
418         JSONObject oneOfProps = new JSONObject();
419         oneOfProps.put(ONE_OF_KEY, choiceProps);
420         oneOfProps.put(TYPE_KEY, OBJECT_TYPE);
421
422         return oneOfProps;
423     }
424
425     /**
426      *
427      * @param constraints
428      * @param props
429      * @throws JSONException
430      */
431     private void processConstraints(final ConstraintDefinition constraints, final JSONObject props) throws JSONException {
432         boolean isMandatory = constraints.isMandatory();
433         props.put(REQUIRED_KEY, isMandatory);
434
435         Integer minElements = constraints.getMinElements();
436         Integer maxElements = constraints.getMaxElements();
437         if (minElements != null) {
438             props.put(MIN_ITEMS, minElements);
439         }
440         if (maxElements != null) {
441             props.put(MAX_ITEMS, maxElements);
442         }
443     }
444
445     /**
446      *
447      * @param leafNode
448      * @return
449      * @throws JSONException
450      */
451     private JSONObject processLeafNode(final LeafSchemaNode leafNode) throws JSONException {
452         JSONObject property = new JSONObject();
453
454         String leafDescription = leafNode.getDescription();
455         property.put(DESCRIPTION_KEY, leafDescription);
456
457         processConstraints(leafNode.getConstraints(), property);
458         processTypeDef(leafNode.getType(), property);
459
460         return property;
461     }
462
463     /**
464      *
465      * @param leafNode
466      * @return
467      * @throws JSONException
468      */
469     private JSONObject processAnyXMLNode(final AnyXmlSchemaNode leafNode) throws JSONException {
470         JSONObject property = new JSONObject();
471
472         String leafDescription = leafNode.getDescription();
473         property.put(DESCRIPTION_KEY, leafDescription);
474
475         processConstraints(leafNode.getConstraints(), property);
476
477         return property;
478     }
479
480     /**
481      * @param property
482      * @throws JSONException
483      */
484     private void processTypeDef(final TypeDefinition<?> leafTypeDef, final JSONObject property) throws JSONException {
485
486         if (leafTypeDef instanceof ExtendedType) {
487             processExtendedType(leafTypeDef, property);
488         } else if (leafTypeDef instanceof EnumerationType) {
489             processEnumType((EnumerationType) leafTypeDef, property);
490
491         } else if (leafTypeDef instanceof BitsTypeDefinition) {
492             processBitsType((BitsTypeDefinition) leafTypeDef, property);
493
494         } else if (leafTypeDef instanceof UnionTypeDefinition) {
495             processUnionType((UnionTypeDefinition) leafTypeDef, property);
496
497         } else if (leafTypeDef instanceof IdentityrefTypeDefinition) {
498             property.putOpt(TYPE_KEY, ((IdentityrefTypeDefinition) leafTypeDef).getIdentity().getQName().getLocalName());
499         } else if (leafTypeDef instanceof BinaryTypeDefinition) {
500             processBinaryType((BinaryTypeDefinition) leafTypeDef, property);
501         } else {
502             // System.out.println("In else: " + leafTypeDef.getClass());
503             String jsonType = YANG_TYPE_TO_JSON_TYPE_MAPPING.get(leafTypeDef.getClass());
504             if (jsonType == null) {
505                 jsonType = "object";
506             }
507             property.putOpt(TYPE_KEY, jsonType);
508         }
509     }
510
511     /**
512      *
513      * @param leafTypeDef
514      * @param property
515      * @throws JSONException
516      */
517     private void processExtendedType(final TypeDefinition<?> leafTypeDef, final JSONObject property) throws JSONException {
518         Object leafBaseType = leafTypeDef.getBaseType();
519         if (leafBaseType instanceof ExtendedType) {
520             // recursively process an extended type until we hit a base type
521             processExtendedType((TypeDefinition<?>) leafBaseType, property);
522         } else {
523             List<LengthConstraint> lengthConstraints = ((ExtendedType) leafTypeDef).getLengthConstraints();
524             for (LengthConstraint lengthConstraint : lengthConstraints) {
525                 Number min = lengthConstraint.getMin();
526                 Number max = lengthConstraint.getMax();
527                 property.putOpt(MIN_LENGTH_KEY, min);
528                 property.putOpt(MAX_LENGTH_KEY, max);
529             }
530             String jsonType = YANG_TYPE_TO_JSON_TYPE_MAPPING.get(leafBaseType.getClass());
531             property.putOpt(TYPE_KEY, jsonType);
532         }
533
534     }
535
536     /*
537    *
538    */
539     private void processBinaryType(final BinaryTypeDefinition binaryType, final JSONObject property) throws JSONException {
540         property.put(TYPE_KEY, STRING);
541         JSONObject media = new JSONObject();
542         media.put(BINARY_ENCODING_KEY, BASE_64);
543         property.put(MEDIA_KEY, media);
544     }
545
546     /**
547      *
548      * @param enumLeafType
549      * @param property
550      * @throws JSONException
551      */
552     private void processEnumType(final EnumerationType enumLeafType, final JSONObject property) throws JSONException {
553         List<EnumPair> enumPairs = enumLeafType.getValues();
554         List<String> enumNames = new ArrayList<String>();
555         for (EnumPair enumPair : enumPairs) {
556             enumNames.add(enumPair.getName());
557         }
558         property.putOpt(ENUM, new JSONArray(enumNames));
559     }
560
561     /**
562      *
563      * @param bitsType
564      * @param property
565      * @throws JSONException
566      */
567     private void processBitsType(final BitsTypeDefinition bitsType, final JSONObject property) throws JSONException {
568         property.put(TYPE_KEY, ARRAY_TYPE);
569         property.put(MIN_ITEMS, 0);
570         property.put(UNIQUE_ITEMS_KEY, true);
571         JSONArray enumValues = new JSONArray();
572
573         List<Bit> bits = bitsType.getBits();
574         for (Bit bit : bits) {
575             enumValues.put(bit.getName());
576         }
577         JSONObject itemsValue = new JSONObject();
578         itemsValue.put(ENUM, enumValues);
579         property.put(ITEMS_KEY, itemsValue);
580     }
581
582     /**
583      *
584      * @param unionType
585      * @param property
586      * @throws JSONException
587      */
588     private void processUnionType(final UnionTypeDefinition unionType, final JSONObject property) throws JSONException {
589
590         StringBuilder type = new StringBuilder();
591         for (TypeDefinition<?> typeDef : unionType.getTypes()) {
592             if (type.length() > 0) {
593                 type.append(" or ");
594             }
595             type.append(YANG_TYPE_TO_JSON_TYPE_MAPPING.get(typeDef.getClass()));
596         }
597
598         property.put(TYPE_KEY, type);
599     }
600
601     /**
602      * Helper method to generate a pre-filled JSON schema object.
603      *
604      * @return
605      * @throws JSONException
606      */
607     private JSONObject getSchemaTemplate() throws JSONException {
608         JSONObject schemaJSON = new JSONObject();
609         schemaJSON.put(SCHEMA_KEY, SCHEMA_URL);
610
611         return schemaJSON;
612     }
613
614 }