Populate yang-parser-api
[yangtools.git] / yang / yang-test-util / src / main / java / org / opendaylight / yangtools / yang / test / util / YangParserTestUtils.java
1 /*
2  * Copyright (c) 2016 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
9 package org.opendaylight.yangtools.yang.test.util;
10
11 import com.google.common.annotations.Beta;
12 import java.io.File;
13 import java.io.FileFilter;
14 import java.io.IOException;
15 import java.net.URI;
16 import java.net.URISyntaxException;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collection;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.ServiceLoader;
23 import java.util.Set;
24 import java.util.stream.Collectors;
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.common.YangConstants;
28 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29 import org.opendaylight.yangtools.yang.model.parser.api.YangParser;
30 import org.opendaylight.yangtools.yang.model.parser.api.YangParserException;
31 import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory;
32 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
33 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
34 import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode;
35 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
36
37 /**
38  * Utility class which provides convenience methods for producing effective schema context based on the supplied
39  * yang/yin sources or paths to these sources.
40  */
41 @Beta
42 public final class YangParserTestUtils {
43
44     private static final FileFilter YANG_FILE_FILTER = file -> {
45         final String name = file.getName().toLowerCase();
46         return name.endsWith(YangConstants.RFC6020_YANG_FILE_EXTENSION) && file.isFile();
47     };
48
49     private static final @NonNull YangParserFactory PARSER_FACTORY;
50
51     static {
52         final Iterator<@NonNull YangParserFactory> it = ServiceLoader.load(YangParserFactory.class).iterator();
53         if (!it.hasNext()) {
54             throw new IllegalStateException("No YangParserFactory found");
55         }
56         PARSER_FACTORY = it.next();
57     }
58
59     private YangParserTestUtils() {
60         throw new UnsupportedOperationException("Utility class should not be instantiated.");
61     }
62
63     /**
64      * Creates a new effective schema context containing the specified YANG source. Statement parser mode is set to
65      * default mode and all YANG features are supported.
66      *
67      * @param resource relative path to the YANG file to be parsed
68      *
69      * @return effective schema context
70      */
71     public static SchemaContext parseYangResource(final String resource) {
72         return parseYangResource(resource, StatementParserMode.DEFAULT_MODE);
73     }
74
75     /**
76      * Creates a new effective schema context containing the specified YANG source. All YANG features are supported.
77      *
78      * @param resource relative path to the YANG file to be parsed
79      * @param parserMode mode of statement parser
80      * @return effective schema context
81      */
82     public static SchemaContext parseYangResource(final String resource, final StatementParserMode parserMode) {
83         return parseYangResource(resource, parserMode, null);
84     }
85
86     /**
87      * Creates a new effective schema context containing the specified YANG source. Statement parser mode is set to
88      * default mode.
89      *
90      * @param resource relative path to the YANG file to be parsed
91      * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG
92      *                          model are resolved
93      * @return effective schema context
94      */
95     public static SchemaContext parseYangResource(final String resource, final Set<QName> supportedFeatures) {
96         return parseYangResource(resource, StatementParserMode.DEFAULT_MODE, supportedFeatures);
97     }
98
99     /**
100      * Creates a new effective schema context containing the specified YANG source.
101      *
102      * @param resource relative path to the YANG file to be parsed
103      * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG
104      *                          model are resolved
105      * @param parserMode mode of statement parser
106      * @return effective schema context
107      */
108     public static SchemaContext parseYangResource(final String resource, final StatementParserMode parserMode,
109             final Set<QName> supportedFeatures) {
110         final YangTextSchemaSource source = YangTextSchemaSource.forResource(YangParserTestUtils.class, resource);
111         return parseYangSources(parserMode, supportedFeatures, source);
112     }
113
114     /**
115      * Creates a new effective schema context containing the specified YANG sources. Statement parser mode is set to
116      * default mode and all YANG features are supported.
117      *
118      * @param files YANG files to be parsed
119      * @return effective schema context
120      */
121     public static SchemaContext parseYangFiles(final File... files) {
122         return parseYangFiles(Arrays.asList(files));
123     }
124
125     /**
126      * Creates a new effective schema context containing the specified YANG sources. Statement parser mode is set to
127      * default mode and all YANG features are supported.
128      *
129      * @param files collection of YANG files to be parsed
130      * @return effective schema context
131      */
132     public static SchemaContext parseYangFiles(final Collection<File> files) {
133         return parseYangFiles(StatementParserMode.DEFAULT_MODE, files);
134     }
135
136     /**
137      * Creates a new effective schema context containing the specified YANG sources. Statement parser mode is set to
138      * default mode.
139      *
140      * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG
141      *                          models are resolved
142      * @param files YANG files to be parsed
143      * @return effective schema context
144      */
145     public static SchemaContext parseYangFiles(final Set<QName> supportedFeatures, final File... files) {
146         return parseYangFiles(supportedFeatures, Arrays.asList(files));
147     }
148
149     public static SchemaContext parseYangFiles(final Set<QName> supportedFeatures, final Collection<File> files) {
150         return parseYangFiles(supportedFeatures, StatementParserMode.DEFAULT_MODE, files);
151     }
152
153     /**
154      * Creates a new effective schema context containing the specified YANG sources. All YANG features are supported.
155      *
156      * @param parserMode mode of statement parser
157      * @param files YANG files to be parsed
158      * @return effective schema context
159      */
160     public static SchemaContext parseYangFiles(final StatementParserMode parserMode, final File... files) {
161         return parseYangFiles(parserMode, Arrays.asList(files));
162     }
163
164     /**
165      * Creates a new effective schema context containing the specified YANG sources. All YANG features are supported.
166      *
167      * @param parserMode mode of statement parser
168      * @param files collection of YANG files to be parsed
169      * @return effective schema context
170      */
171     public static SchemaContext parseYangFiles(final StatementParserMode parserMode, final Collection<File> files) {
172         return parseYangFiles(null, parserMode, files);
173     }
174
175     /**
176      * Creates a new effective schema context containing the specified YANG sources.
177      *
178      * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG
179      *                          models are resolved
180      * @param parserMode mode of statement parser
181      * @param files YANG files to be parsed
182      * @return effective schema context
183      */
184     public static SchemaContext parseYangFiles(final Set<QName> supportedFeatures,
185             final StatementParserMode parserMode, final File... files) {
186         return parseYangFiles(supportedFeatures, parserMode, Arrays.asList(files));
187     }
188
189     /**
190      * Creates a new effective schema context containing the specified YANG sources.
191      *
192      * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG
193      *                          models are resolved
194      * @param parserMode mode of statement parser
195      * @param files YANG files to be parsed
196      * @return effective schema context
197      */
198     public static SchemaContext parseYangFiles(final Set<QName> supportedFeatures,
199             final StatementParserMode parserMode, final Collection<File> files) {
200         return parseSources(parserMode, supportedFeatures,
201             files.stream().map(YangTextSchemaSource::forFile).collect(Collectors.toList()));
202     }
203
204     /**
205      * Creates a new effective schema context containing the specified YANG sources. Statement parser mode is set to
206      * default mode and all YANG features are supported.
207      *
208      * @param resourcePath relative path to the directory with YANG files to be parsed
209      * @return effective schema context
210      */
211     public static SchemaContext parseYangResourceDirectory(final String resourcePath) {
212         return parseYangResourceDirectory(resourcePath, StatementParserMode.DEFAULT_MODE);
213     }
214
215     /**
216      * Creates a new effective schema context containing the specified YANG sources. All YANG features are supported.
217      *
218      * @param resourcePath relative path to the directory with YANG files to be parsed
219      * @param parserMode mode of statement parser
220      * @return effective schema context
221      */
222     public static SchemaContext parseYangResourceDirectory(final String resourcePath,
223             final StatementParserMode parserMode) {
224         return parseYangResourceDirectory(resourcePath, null, parserMode);
225     }
226
227     /**
228      * Creates a new effective schema context containing the specified YANG sources. Statement parser mode is set to
229      * default mode.
230      *
231      * @param resourcePath relative path to the directory with YANG files to be parsed
232      * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG
233      *                          models are resolved
234      * @return effective schema context
235      */
236     public static SchemaContext parseYangResourceDirectory(final String resourcePath,
237             final Set<QName> supportedFeatures) {
238         return parseYangResourceDirectory(resourcePath, supportedFeatures, StatementParserMode.DEFAULT_MODE);
239     }
240
241     /**
242      * Creates a new effective schema context containing the specified YANG sources.
243      *
244      * @param resourcePath relative path to the directory with YANG files to be parsed
245      * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG
246      *                          models are resolved
247      * @param parserMode mode of statement parser
248      * @return effective schema context
249      */
250     public static SchemaContext parseYangResourceDirectory(final String resourcePath,
251             final Set<QName> supportedFeatures, final StatementParserMode parserMode) {
252         final URI directoryPath;
253         try {
254             directoryPath = YangParserTestUtils.class.getResource(resourcePath).toURI();
255         } catch (URISyntaxException e) {
256             throw new IllegalArgumentException("Failed to open resource " + resourcePath, e);
257         }
258         return parseYangFiles(supportedFeatures, parserMode, new File(directoryPath).listFiles(YANG_FILE_FILTER));
259     }
260
261     /**
262      * Creates a new effective schema context containing the specified YANG sources. Statement parser mode is set to
263      * default mode and all YANG features are supported.
264      *
265      * @param clazz Resource lookup base
266      * @param resources Resource names to be looked up
267      * @return effective schema context
268      */
269     public static SchemaContext parseYangResources(final Class<?> clazz, final String... resources) {
270         return parseYangResources(clazz, Arrays.asList(resources));
271     }
272
273     public static SchemaContext parseYangResources(final Class<?> clazz, final Collection<String> resources) {
274         final List<YangTextSchemaSource> sources = new ArrayList<>(resources.size());
275         for (final String r : resources) {
276             sources.add(YangTextSchemaSource.forResource(clazz, r));
277         }
278         return parseSources(StatementParserMode.DEFAULT_MODE, null, sources);
279     }
280
281     /**
282      * Creates a new effective schema context containing the specified YANG sources. Statement parser mode is set to
283      * default mode.
284      *
285      * @param yangDirs relative paths to the directories containing YANG files to be parsed
286      * @param yangFiles relative paths to the YANG files to be parsed
287      * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG
288      *                          models are resolved
289      * @return effective schema context
290      */
291     public static SchemaContext parseYangResources(final List<String> yangDirs, final List<String> yangFiles,
292             final Set<QName> supportedFeatures) {
293         return parseYangResources(yangDirs, yangFiles, supportedFeatures, StatementParserMode.DEFAULT_MODE);
294     }
295
296     /**
297      * Creates a new effective schema context containing the specified YANG sources. All YANG features are supported.
298      *
299      * @param yangResourceDirs relative paths to the directories containing YANG files to be parsed
300      * @param yangResources relative paths to the YANG files to be parsed
301      * @param statementParserMode mode of statement parser
302      * @return effective schema context
303      */
304     public static SchemaContext parseYangResources(final List<String> yangResourceDirs,
305             final List<String> yangResources, final StatementParserMode statementParserMode) {
306         return parseYangResources(yangResourceDirs, yangResources, null, statementParserMode);
307     }
308
309     /**
310      * Creates a new effective schema context containing the specified YANG sources.
311      *
312      * @param yangResourceDirs relative paths to the directories containing YANG files to be parsed
313      * @param yangResources relative paths to the YANG files to be parsed
314      * @param supportedFeatures set of supported features based on which all if-feature statements in the parsed YANG
315      *                          models are resolved
316      * @param statementParserMode mode of statement parser
317      * @return effective schema context
318      */
319     public static SchemaContext parseYangResources(final List<String> yangResourceDirs,
320             final List<String> yangResources, final Set<QName> supportedFeatures,
321             final StatementParserMode statementParserMode) {
322         final List<File> allYangFiles = new ArrayList<>();
323         for (final String yangDir : yangResourceDirs) {
324             allYangFiles.addAll(getYangFiles(yangDir));
325         }
326
327         for (final String yangFile : yangResources) {
328             try {
329                 allYangFiles.add(new File(YangParserTestUtils.class.getResource(yangFile).toURI()));
330             } catch (URISyntaxException e) {
331                 throw new IllegalArgumentException("Invalid resource " + yangFile, e);
332             }
333         }
334
335         return parseYangFiles(supportedFeatures, statementParserMode, allYangFiles);
336     }
337
338     public static SchemaContext parseYangSources(final StatementParserMode parserMode,
339             final Set<QName> supportedFeatures, final YangTextSchemaSource... sources) {
340         return parseSources(parserMode, supportedFeatures, Arrays.asList(sources));
341     }
342
343     public static SchemaContext parseSources(final StatementParserMode parserMode, final Set<QName> supportedFeatures,
344             final Collection<? extends SchemaSourceRepresentation> sources) {
345         final YangParser parser = PARSER_FACTORY.createParser(parserMode);
346         if (supportedFeatures != null) {
347             parser.setSupportedFeatures(supportedFeatures);
348         }
349
350         try {
351             parser.addSources(sources);
352         } catch (YangSyntaxErrorException e) {
353             throw new IllegalArgumentException("Malformed source", e);
354         } catch (IOException e) {
355             throw new IllegalArgumentException("Failed to read a source", e);
356         }
357
358         try {
359             return parser.buildSchemaContext();
360         } catch (YangParserException e) {
361             throw new IllegalStateException("Failed to assemble SchemaContext", e);
362         }
363     }
364
365     private static Collection<File> getYangFiles(final String resourcePath) {
366         final URI directoryPath;
367         try {
368             directoryPath = YangParserTestUtils.class.getResource(resourcePath).toURI();
369         } catch (URISyntaxException e) {
370             throw new IllegalArgumentException("Failed to open resource directory " + resourcePath, e);
371         }
372         return Arrays.asList(new File(directoryPath).listFiles(YANG_FILE_FILTER));
373     }
374 }