Merge "BUG-461 Test transformation of rpc input using XmlDocumentUtils"
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / SchemaContextImpl.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.impl;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Supplier;
12 import com.google.common.collect.ImmutableListMultimap;
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.ImmutableSet;
15 import com.google.common.collect.ImmutableSetMultimap;
16 import com.google.common.collect.ListMultimap;
17 import com.google.common.collect.Multimaps;
18 import com.google.common.collect.SetMultimap;
19
20 import java.net.URI;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.Date;
26 import java.util.HashSet;
27 import java.util.LinkedHashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.TreeMap;
32
33 import javax.annotation.concurrent.Immutable;
34
35 import org.opendaylight.yangtools.yang.common.QName;
36 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
37 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
38 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
40 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
41 import org.opendaylight.yangtools.yang.model.api.Module;
42 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
43 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
44 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
45 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
46 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
47 import org.opendaylight.yangtools.yang.model.api.Status;
48 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
49 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.UsesNode;
51 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
52
53 @Immutable
54 final class SchemaContextImpl implements SchemaContext {
55     private static final Supplier<HashSet<Module>> URI_SET_SUPPLIER = new Supplier<HashSet<Module>>() {
56         @Override
57         public HashSet<Module> get() {
58             return new HashSet<>();
59         }
60     };
61
62     private static final Supplier<ArrayList<Module>> MODULE_LIST_SUPPLIER = new Supplier<ArrayList<Module>>() {
63         @Override
64         public ArrayList<Module> get() {
65             return new ArrayList<>();
66         }
67     };
68
69     private static final Comparator<Module> REVISION_COMPARATOR = new Comparator<Module>() {
70         @Override
71         public int compare(final Module o1, final Module o2) {
72             return o1.getRevision().compareTo(o2.getRevision());
73         }
74     };
75
76     private final ImmutableMap<ModuleIdentifier, String> identifiersToSources;
77     private final ImmutableSetMultimap<URI, Module> namespaceToModules;
78     private final ImmutableListMultimap<String, Module> nameToModules;
79     private final ImmutableSet<Module> modules;
80
81     SchemaContextImpl(final Set<Module> modules, final Map<ModuleIdentifier, String> identifiersToSources) {
82         this.identifiersToSources = ImmutableMap.copyOf(identifiersToSources);
83
84         /*
85          * Instead of doing this on each invocation of getModules(), pre-compute
86          * it once and keep it around -- better than the set we got in.
87          */
88         this.modules = ImmutableSet.copyOf(ModuleDependencySort.sort(modules.toArray(new Module[modules.size()])));
89
90         /*
91          * The most common lookup is from Namespace->Module.
92          *
93          * RESTCONF performs lookups based on module name only, where it wants
94          * to receive the latest revision
95          *
96          * Invest some quality time in building up lookup tables for both.
97          */
98         final SetMultimap<URI, Module> nsMap = Multimaps.newSetMultimap(
99                 new TreeMap<URI, Collection<Module>>(), URI_SET_SUPPLIER);
100         final ListMultimap<String, Module> nameMap = Multimaps.newListMultimap(
101                 new TreeMap<String, Collection<Module>>(), MODULE_LIST_SUPPLIER);
102         for (Module m : modules) {
103             nameMap.put(m.getName(), m);
104             nsMap.put(m.getNamespace(), m);
105         }
106         for (String key : nameMap.keySet()) {
107             Collections.sort(nameMap.get(key), REVISION_COMPARATOR);
108         }
109
110         namespaceToModules = ImmutableSetMultimap.copyOf(nsMap);
111         nameToModules = ImmutableListMultimap.copyOf(nameMap);
112     }
113
114     @Override
115     public Set<DataSchemaNode> getDataDefinitions() {
116         final Set<DataSchemaNode> dataDefs = new HashSet<>();
117         for (Module m : modules) {
118             dataDefs.addAll(m.getChildNodes());
119         }
120         return dataDefs;
121     }
122
123     @Override
124     public Set<Module> getModules() {
125         return modules;
126     }
127
128     @Override
129     public Set<NotificationDefinition> getNotifications() {
130         final Set<NotificationDefinition> notifications = new HashSet<>();
131         for (Module m : modules) {
132             notifications.addAll(m.getNotifications());
133         }
134         return notifications;
135     }
136
137     @Override
138     public Set<RpcDefinition> getOperations() {
139         final Set<RpcDefinition> rpcs = new HashSet<>();
140         for (Module m : modules) {
141             rpcs.addAll(m.getRpcs());
142         }
143         return rpcs;
144     }
145
146     @Override
147     public Set<ExtensionDefinition> getExtensions() {
148         final Set<ExtensionDefinition> extensions = new HashSet<>();
149         for (Module m : modules) {
150             extensions.addAll(m.getExtensionSchemaNodes());
151         }
152         return extensions;
153     }
154
155     @Override
156     public Module findModuleByName(final String name, final Date revision) {
157         final List<Module> mods = nameToModules.get(name);
158         if (mods != null) {
159             for (final Module module : mods) {
160                 if (revision == null || module.getRevision().equals(revision)) {
161                     return module;
162                 }
163             }
164         }
165
166         return null;
167     }
168
169     @Override
170     public Set<Module> findModuleByNamespace(final URI namespace) {
171         final Set<Module> ret = namespaceToModules.get(namespace);
172         return ret == null ? Collections.<Module>emptySet() : ret;
173     }
174
175     @Override
176     public Module findModuleByNamespaceAndRevision(final URI namespace, final Date revision) {
177         if (namespace == null) {
178             return null;
179         }
180         final Set<Module> modules = findModuleByNamespace(namespace);
181         if (modules.isEmpty()) {
182             return null;
183         }
184
185         if (revision == null) {
186             // FIXME: The ordering of modules in Multimap could just guarantee this...
187             TreeMap<Date, Module> map = new TreeMap<>();
188             for (Module module : modules) {
189                 map.put(module.getRevision(), module);
190             }
191             if (map.isEmpty()) {
192                 return null;
193             }
194             return map.lastEntry().getValue();
195         } else {
196             for (Module module : modules) {
197                 if (module.getRevision().equals(revision)) {
198                     return(module);
199                 }
200             }
201         }
202         return null;
203     }
204
205     @Override
206     public boolean isAugmenting() {
207         return false;
208     }
209
210     @Override
211     public boolean isAddedByUses() {
212         return false;
213     }
214
215     @Override
216     public boolean isConfiguration() {
217         return false;
218     }
219
220     @Override
221     public ConstraintDefinition getConstraints() {
222         return null;
223     }
224
225     @Override
226     public QName getQName() {
227         return SchemaContext.NAME;
228     }
229
230     @Override
231     public SchemaPath getPath() {
232         return null;
233     }
234
235     @Override
236     public String getDescription() {
237         return null;
238     }
239
240     @Override
241     public String getReference() {
242         return null;
243     }
244
245     @Override
246     public Status getStatus() {
247         return Status.CURRENT;
248     }
249
250     @Override
251     public List<UnknownSchemaNode> getUnknownSchemaNodes() {
252         final List<UnknownSchemaNode> result = new ArrayList<>();
253         for (Module module : modules) {
254             result.addAll(module.getUnknownSchemaNodes());
255         }
256         return Collections.unmodifiableList(result);
257     }
258
259     @Override
260     public Set<TypeDefinition<?>> getTypeDefinitions() {
261         final Set<TypeDefinition<?>> result = new LinkedHashSet<>();
262         for (Module module : modules) {
263             result.addAll(module.getTypeDefinitions());
264         }
265         return Collections.unmodifiableSet(result);
266     }
267
268     @Override
269     public Set<DataSchemaNode> getChildNodes() {
270         final Set<DataSchemaNode> result = new LinkedHashSet<>();
271         for (Module module : modules) {
272             result.addAll(module.getChildNodes());
273         }
274         return Collections.unmodifiableSet(result);
275     }
276
277     @Override
278     public Set<GroupingDefinition> getGroupings() {
279         final Set<GroupingDefinition> result = new LinkedHashSet<>();
280         for (Module module : modules) {
281             result.addAll(module.getGroupings());
282         }
283         return Collections.unmodifiableSet(result);
284     }
285
286     @Override
287     public DataSchemaNode getDataChildByName(final QName name) {
288         DataSchemaNode result = null;
289         for (Module module : modules) {
290             result = module.getDataChildByName(name);
291             if (result != null) {
292                 break;
293             }
294         }
295         return result;
296     }
297
298     @Override
299     public DataSchemaNode getDataChildByName(final String name) {
300         DataSchemaNode result = null;
301         for (Module module : modules) {
302             result = module.getDataChildByName(name);
303             if (result != null) {
304                 break;
305             }
306         }
307         return result;
308     }
309
310     @Override
311     public Set<UsesNode> getUses() {
312         return Collections.emptySet();
313     }
314
315     @Override
316     public boolean isPresenceContainer() {
317         return false;
318     }
319
320     @Override
321     public Set<AugmentationSchema> getAvailableAugmentations() {
322         return Collections.emptySet();
323     }
324
325     //FIXME: should work for submodules too
326     @Override
327     public Set<ModuleIdentifier> getAllModuleIdentifiers() {
328         return identifiersToSources.keySet();
329     }
330
331     @Override
332     public Optional<String> getModuleSource(final ModuleIdentifier moduleIdentifier) {
333         String maybeSource = identifiersToSources.get(moduleIdentifier);
334         return Optional.fromNullable(maybeSource);
335     }
336
337     @Override
338     public String toString() {
339         return "SchemaContextImpl{" +
340                 "modules=" + modules +
341                 '}';
342     }
343 }