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