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