Refactored parsing of yang uses statement.
[yangtools.git] / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / RefineUtils.java
1 /*
2  * Copyright (c) 2013 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.yang.parser.util;
9
10 import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.*;
11
12 import java.lang.reflect.Method;
13 import java.util.List;
14
15 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
16 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
17 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
18 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
19 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
20 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
23 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
24 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
25 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
26 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
27 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
28 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
29 import org.opendaylight.yangtools.yang.parser.builder.impl.AnyXmlBuilder;
30 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
31 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
32 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
33 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
34 import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder;
35 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
36
37 /**
38  * Utility class with helper methods to perform operations tied to refine
39  * process.
40  */
41 public class RefineUtils {
42
43     private RefineUtils() {
44     }
45
46     /**
47      * Find original builder of node to refine and return copy of this builder.
48      * <p>
49      * We must create and use a copy of builder to preserve original builder
50      * state, because this object will be refined (modified) and later added to
51      * {@link UsesNodeBuilder}.
52      * </p>
53      *
54      * @param targetGrouping
55      *            builder of grouping which should contains node to refine
56      * @param refine
57      *            refine object containing informations about refine
58      * @param moduleName
59      *            current module name
60      * @return
61      */
62     public static DataSchemaNodeBuilder getRefineNodeFromGroupingBuilder(final GroupingBuilder targetGrouping,
63             final RefineHolder refine, final String moduleName) {
64         DataSchemaNodeBuilder result = null;
65         final Builder lookedUpBuilder = targetGrouping.getDataChildByName(refine.getName());
66         if (lookedUpBuilder == null) {
67             throw new YangParseException(moduleName, refine.getLine(), "Target node '" + refine.getName()
68                     + "' not found");
69         }
70         if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
71             result = new LeafSchemaNodeBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
72         } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
73             result = new ContainerSchemaNodeBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
74         } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
75             result = new ListSchemaNodeBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
76         } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
77             result = new LeafListSchemaNodeBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
78         } else if (lookedUpBuilder instanceof ChoiceBuilder) {
79             result = new ChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
80         } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
81             result = new AnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
82         } else {
83             throw new YangParseException(moduleName, refine.getLine(), "Target '" + refine.getName()
84                     + "' can not be refined");
85         }
86         return result;
87     }
88
89     /**
90      * Create builder object from refine target node.
91      *
92      * @param grouping
93      *            grouping which should contains node to refine
94      * @param refine
95      *            refine object containing informations about refine
96      * @return
97      */
98     public static DataSchemaNodeBuilder getRefineNodeFromGroupingDefinition(final GroupingDefinition grouping,
99             final RefineHolder refine) {
100         final String moduleName = refine.getModuleName();
101         final int line = refine.getLine();
102         DataSchemaNodeBuilder result = null;
103         final Object lookedUpNode = grouping.getDataChildByName(refine.getName());
104         if (lookedUpNode == null) {
105             throw new YangParseException(moduleName, line, "Refine target node '" + refine.getName() + "' not found");
106         }
107         if (lookedUpNode instanceof LeafSchemaNode) {
108             result = createLeafBuilder((LeafSchemaNode) lookedUpNode, moduleName, line);
109         } else if (lookedUpNode instanceof ContainerSchemaNode) {
110             result = createContainer((ContainerSchemaNode) lookedUpNode, moduleName, line);
111         } else if (lookedUpNode instanceof ListSchemaNode) {
112             result = createList((ListSchemaNode) lookedUpNode, moduleName, line);
113         } else if (lookedUpNode instanceof LeafListSchemaNode) {
114             result = createLeafList((LeafListSchemaNode) lookedUpNode, moduleName, line);
115         } else if (lookedUpNode instanceof ChoiceNode) {
116             result = createChoice((ChoiceNode) lookedUpNode, moduleName, line);
117         } else if (lookedUpNode instanceof AnyXmlSchemaNode) {
118             result = createAnyXml((AnyXmlSchemaNode) lookedUpNode, moduleName, line);
119         } else {
120             throw new YangParseException(moduleName, line, "Target '" + refine.getName() + "' can not be refined");
121         }
122         return result;
123     }
124
125     public static void refineLeaf(LeafSchemaNodeBuilder leaf, RefineHolder refine) {
126         String defaultStr = refine.getDefaultStr();
127         Boolean mandatory = refine.isMandatory();
128         MustDefinition must = refine.getMust();
129         List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
130
131         if (defaultStr != null && !("".equals(defaultStr))) {
132             leaf.setDefaultStr(defaultStr);
133         }
134         if (mandatory != null) {
135             leaf.getConstraints().setMandatory(mandatory);
136         }
137         if (must != null) {
138             leaf.getConstraints().addMustDefinition(must);
139         }
140         if (unknownNodes != null) {
141             for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
142                 leaf.addUnknownNodeBuilder(unknown);
143             }
144         }
145     }
146
147     public static void refineContainer(ContainerSchemaNodeBuilder container, RefineHolder refine, int line) {
148         Boolean presence = refine.isPresence();
149         MustDefinition must = refine.getMust();
150         List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
151
152         if (presence != null) {
153             container.setPresence(presence);
154         }
155         if (must != null) {
156             container.getConstraints().addMustDefinition(must);
157         }
158         if (unknownNodes != null) {
159             for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
160                 container.addUnknownNodeBuilder(unknown);
161             }
162         }
163     }
164
165     public static void refineList(ListSchemaNodeBuilder list, RefineHolder refine, int line) {
166         MustDefinition must = refine.getMust();
167         Integer min = refine.getMinElements();
168         Integer max = refine.getMaxElements();
169         List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
170
171         if (must != null) {
172             list.getConstraints().addMustDefinition(must);
173         }
174         if (min != null) {
175             list.getConstraints().setMinElements(min);
176         }
177         if (max != null) {
178             list.getConstraints().setMaxElements(max);
179         }
180         if (unknownNodes != null) {
181             for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
182                 list.addUnknownNodeBuilder(unknown);
183             }
184         }
185     }
186
187     public static void refineLeafList(LeafListSchemaNodeBuilder leafList, RefineHolder refine, int line) {
188         MustDefinition must = refine.getMust();
189         Integer min = refine.getMinElements();
190         Integer max = refine.getMaxElements();
191         List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
192
193         if (must != null) {
194             leafList.getConstraints().addMustDefinition(must);
195         }
196         if (min != null) {
197             leafList.getConstraints().setMinElements(min);
198         }
199         if (max != null) {
200             leafList.getConstraints().setMaxElements(max);
201         }
202         if (unknownNodes != null) {
203             for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
204                 leafList.addUnknownNodeBuilder(unknown);
205             }
206         }
207     }
208
209     public static void refineChoice(ChoiceBuilder choice, RefineHolder refine, int line) {
210         String defaultStr = refine.getDefaultStr();
211         Boolean mandatory = refine.isMandatory();
212         List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
213
214         if (defaultStr != null) {
215             choice.setDefaultCase(defaultStr);
216         }
217         if (mandatory != null) {
218             choice.getConstraints().setMandatory(mandatory);
219         }
220         if (unknownNodes != null) {
221             for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
222                 choice.addUnknownNodeBuilder(unknown);
223             }
224         }
225     }
226
227     public static void refineAnyxml(AnyXmlBuilder anyXml, RefineHolder refine, int line) {
228         Boolean mandatory = refine.isMandatory();
229         MustDefinition must = refine.getMust();
230         List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
231
232         if (mandatory != null) {
233             anyXml.getConstraints().setMandatory(mandatory);
234         }
235         if (must != null) {
236             anyXml.getConstraints().addMustDefinition(must);
237         }
238         if (unknownNodes != null) {
239             for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
240                 anyXml.addUnknownNodeBuilder(unknown);
241             }
242         }
243     }
244
245     /**
246      * Check if refine can be performed on given node.
247      *
248      * @param node
249      *            node to refine
250      * @param refine
251      *            refine object containing information about refine process
252      */
253     public static void checkRefine(SchemaNodeBuilder node, RefineHolder refine) {
254         String moduleName = refine.getModuleName();
255         int line = refine.getLine();
256         String name = node.getQName().getLocalName();
257
258         String defaultStr = refine.getDefaultStr();
259         Boolean mandatory = refine.isMandatory();
260         Boolean presence = refine.isPresence();
261         MustDefinition must = refine.getMust();
262         Integer min = refine.getMinElements();
263         Integer max = refine.getMaxElements();
264
265         if (node instanceof AnyXmlBuilder) {
266             checkRefineDefault(node, defaultStr, moduleName, line);
267             checkRefinePresence(node, presence, moduleName, line);
268             checkRefineMinMax(name, min, max, moduleName, line);
269         } else if (node instanceof ChoiceBuilder) {
270             checkRefinePresence(node, presence, moduleName, line);
271             checkRefineMust(node, must, moduleName, line);
272             checkRefineMinMax(name, min, max, moduleName, line);
273         } else if (node instanceof ContainerSchemaNodeBuilder) {
274             checkRefineDefault(node, defaultStr, moduleName, line);
275             checkRefineMandatory(node, mandatory, moduleName, line);
276             checkRefineMust(node, must, moduleName, line);
277             checkRefineMinMax(name, min, max, moduleName, line);
278         } else if (node instanceof LeafSchemaNodeBuilder) {
279             checkRefinePresence(node, presence, moduleName, line);
280             checkRefineMinMax(name, min, max, moduleName, line);
281         } else if (node instanceof LeafListSchemaNodeBuilder || node instanceof ListSchemaNodeBuilder) {
282             checkRefineDefault(node, defaultStr, moduleName, line);
283             checkRefinePresence(node, presence, moduleName, line);
284             checkRefineMandatory(node, mandatory, moduleName, line);
285         } else if (node instanceof GroupingBuilder || node instanceof TypeDefinitionBuilder
286                 || node instanceof UsesNodeBuilder) {
287             checkRefineDefault(node, defaultStr, moduleName, line);
288             checkRefinePresence(node, presence, moduleName, line);
289             checkRefineMandatory(node, mandatory, moduleName, line);
290             checkRefineMust(node, must, moduleName, line);
291             checkRefineMinMax(name, min, max, moduleName, line);
292         }
293     }
294
295     private static void checkRefineDefault(SchemaNodeBuilder node, String defaultStr, String moduleName, int line) {
296         if (defaultStr != null) {
297             throw new YangParseException(moduleName, line, "Can not refine 'default' for '"
298                     + node.getQName().getLocalName() + "'.");
299         }
300     }
301
302     private static void checkRefineMandatory(SchemaNodeBuilder node, Boolean mandatory, String moduleName, int line) {
303         if (mandatory != null) {
304             throw new YangParseException(moduleName, line, "Can not refine 'mandatory' for '"
305                     + node.getQName().getLocalName() + "'.");
306         }
307     }
308
309     private static void checkRefinePresence(SchemaNodeBuilder node, Boolean presence, String moduleName, int line) {
310         if (presence != null) {
311             throw new YangParseException(moduleName, line, "Can not refine 'presence' for '"
312                     + node.getQName().getLocalName() + "'.");
313         }
314     }
315
316     private static void checkRefineMust(SchemaNodeBuilder node, MustDefinition must, String moduleName, int line) {
317         if (must != null) {
318             throw new YangParseException(moduleName, line, "Can not refine 'must' for '"
319                     + node.getQName().getLocalName() + "'.");
320         }
321     }
322
323     private static void checkRefineMinMax(String refineTargetName, Integer min, Integer max, String moduleName, int line) {
324         if (min != null || max != null) {
325             throw new YangParseException(moduleName, line, "Can not refine 'min-elements' or 'max-elements' for '"
326                     + refineTargetName + "'.");
327         }
328     }
329
330     /**
331      * Perform refine operation of following parameters:
332      * <ul>
333      * <li>description</li>
334      * <li>reference</li>
335      * <li>config</li>
336      * </ul>
337      *
338      * These parameters may be refined for any node.
339      *
340      * @param node
341      *            node to refine
342      * @param refine
343      *            refine object containing information about refine process
344      */
345     public static void refineDefault(final Builder node, final RefineHolder refine) {
346         final String moduleName = refine.getModuleName();
347         final int line = refine.getLine();
348         Class<? extends Builder> cls = node.getClass();
349
350         String description = refine.getDescription();
351         if (description != null) {
352             try {
353                 Method method = cls.getDeclaredMethod("setDescription", String.class);
354                 method.invoke(node, description);
355             } catch (Exception e) {
356                 throw new YangParseException(moduleName, line, "Cannot refine description in " + cls.getName(), e);
357             }
358         }
359
360         String reference = refine.getReference();
361         if (reference != null) {
362             try {
363                 Method method = cls.getDeclaredMethod("setReference", String.class);
364                 method.invoke(node, reference);
365             } catch (Exception e) {
366                 throw new YangParseException(moduleName, line, "Cannot refine reference in " + cls.getName(), e);
367             }
368         }
369
370         Boolean config = refine.isConfiguration();
371         if (config != null) {
372             try {
373                 Method method = cls.getDeclaredMethod("setConfiguration", Boolean.class);
374                 method.invoke(node, config);
375             } catch (Exception e) {
376                 throw new YangParseException(moduleName, line, "Cannot refine config in " + cls.getName(), e);
377             }
378         }
379     }
380
381     /**
382      * Perform refine operation on given node.
383      *
384      * @param nodeToRefine
385      *            builder of node to refine
386      * @param refine
387      *            refine object containing information about refine process
388      * @param line
389      *            current line in yang model
390      */
391     public static void performRefine(SchemaNodeBuilder nodeToRefine, RefineHolder refine, int line) {
392         checkRefine(nodeToRefine, refine);
393         refineDefault(nodeToRefine, refine);
394         if (nodeToRefine instanceof LeafSchemaNodeBuilder) {
395             refineLeaf((LeafSchemaNodeBuilder) nodeToRefine, refine);
396         } else if (nodeToRefine instanceof ContainerSchemaNodeBuilder) {
397             refineContainer((ContainerSchemaNodeBuilder) nodeToRefine, refine, line);
398         } else if (nodeToRefine instanceof ListSchemaNodeBuilder) {
399             refineList((ListSchemaNodeBuilder) nodeToRefine, refine, line);
400         } else if (nodeToRefine instanceof LeafListSchemaNodeBuilder) {
401             refineLeafList((LeafListSchemaNodeBuilder) nodeToRefine, refine, line);
402         } else if (nodeToRefine instanceof ChoiceBuilder) {
403             refineChoice((ChoiceBuilder) nodeToRefine, refine, line);
404         } else if (nodeToRefine instanceof AnyXmlBuilder) {
405             refineAnyxml((AnyXmlBuilder) nodeToRefine, refine, line);
406         }
407     }
408
409 }