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