BUG-582: Optimize SchemaContextImpl.findModuleByNamespace()
[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 java.net.URI;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.Date;
15 import java.util.HashSet;
16 import java.util.LinkedHashSet;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.TreeMap;
21
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
24 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
25 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
27 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
28 import org.opendaylight.yangtools.yang.model.api.Module;
29 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
30 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
31 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
32 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
33 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
34 import org.opendaylight.yangtools.yang.model.api.Status;
35 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
36 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.UsesNode;
38 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
39
40 import com.google.common.base.Optional;
41 import com.google.common.base.Supplier;
42 import com.google.common.collect.ImmutableSetMultimap;
43 import com.google.common.collect.Multimaps;
44 import com.google.common.collect.SetMultimap;
45
46 final class SchemaContextImpl implements SchemaContext {
47     private static final Supplier<HashSet<Module>> URI_SET_SUPPLIER = new Supplier<HashSet<Module>>() {
48         @Override
49         public HashSet<Module> get() {
50             return new HashSet<>();
51         }
52     };
53
54     private final Map<ModuleIdentifier, String> identifiersToSources;
55     private final SetMultimap<URI, Module> namespaceToModules;
56     private final Set<Module> modules;
57
58     SchemaContextImpl(final Set<Module> modules, final Map<ModuleIdentifier, String> identifiersToSources) {
59         this.modules = modules;
60         this.identifiersToSources = identifiersToSources;
61
62         /*
63          * The most common lookup is from Namespace->Module. Invest some quality time in
64          * building that up.
65          */
66         final SetMultimap<URI, Module> multimap = Multimaps.newSetMultimap(
67                 new TreeMap<URI, Collection<Module>>(), URI_SET_SUPPLIER);
68         for (Module m : modules) {
69             multimap.put(m.getNamespace(), m);
70         }
71
72         namespaceToModules = ImmutableSetMultimap.copyOf(multimap);
73     }
74
75     @Override
76     public Set<DataSchemaNode> getDataDefinitions() {
77         final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
78         for (Module m : modules) {
79             dataDefs.addAll(m.getChildNodes());
80         }
81         return dataDefs;
82     }
83
84     @Override
85     public Set<Module> getModules() {
86         // FIXME: can we pre-compute this in the constructor?
87         List<Module> sorted = ModuleDependencySort.sort(modules.toArray(new Module[modules.size()]));
88         return new LinkedHashSet<Module>(sorted);
89     }
90
91     @Override
92     public Set<NotificationDefinition> getNotifications() {
93         final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
94         for (Module m : modules) {
95             notifications.addAll(m.getNotifications());
96         }
97         return notifications;
98     }
99
100     @Override
101     public Set<RpcDefinition> getOperations() {
102         final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
103         for (Module m : modules) {
104             rpcs.addAll(m.getRpcs());
105         }
106         return rpcs;
107     }
108
109     @Override
110     public Set<ExtensionDefinition> getExtensions() {
111         final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
112         for (Module m : modules) {
113             extensions.addAll(m.getExtensionSchemaNodes());
114         }
115         return extensions;
116     }
117
118     @Override
119     public Module findModuleByName(final String name, final Date revision) {
120         if (name != null) {
121             for (final Module module : modules) {
122                 if (revision == null) {
123                     if (module.getName().equals(name)) {
124                         return module;
125                     }
126                 } else if (module.getName().equals(name) && module.getRevision().equals(revision)) {
127                     return module;
128                 }
129             }
130         }
131         return null;
132     }
133
134     @Override
135     public Set<Module> findModuleByNamespace(final URI namespace) {
136         final Set<Module> ret = namespaceToModules.get(namespace);
137         return ret == null ? Collections.<Module>emptySet() : ret;
138     }
139
140     @Override
141     public Module findModuleByNamespaceAndRevision(final URI namespace, final Date revision) {
142         if (namespace != null) {
143             Set<Module> modules = findModuleByNamespace(namespace);
144
145             if (revision == null) {
146                 TreeMap<Date, Module> map = new TreeMap<Date, Module>();
147                 for (Module module : modules) {
148                     map.put(module.getRevision(), module);
149                 }
150                 if (map.isEmpty()) {
151                     return null;
152                 }
153                 return map.lastEntry().getValue();
154             } else {
155                 for (Module module : modules) {
156                     if (module.getRevision().equals(revision)) {
157                         return(module);
158                     }
159                 }
160             }
161         }
162         return null;
163     }
164
165     @Override
166     public boolean isAugmenting() {
167         return false;
168     }
169
170     @Override
171     public boolean isAddedByUses() {
172         return false;
173     }
174
175     @Override
176     public boolean isConfiguration() {
177         return false;
178     }
179
180     @Override
181     public ConstraintDefinition getConstraints() {
182         return null;
183     }
184
185     @Override
186     public QName getQName() {
187         return SchemaContext.NAME;
188     }
189
190     @Override
191     public SchemaPath getPath() {
192         return null;
193     }
194
195     @Override
196     public String getDescription() {
197         return null;
198     }
199
200     @Override
201     public String getReference() {
202         return null;
203     }
204
205     @Override
206     public Status getStatus() {
207         return Status.CURRENT;
208     }
209
210     @Override
211     public List<UnknownSchemaNode> getUnknownSchemaNodes() {
212         final List<UnknownSchemaNode> result = new ArrayList<>();
213         for (Module module : modules) {
214             result.addAll(module.getUnknownSchemaNodes());
215         }
216         return Collections.unmodifiableList(result);
217     }
218
219     @Override
220     public Set<TypeDefinition<?>> getTypeDefinitions() {
221         final Set<TypeDefinition<?>> result = new LinkedHashSet<>();
222         for (Module module : modules) {
223             result.addAll(module.getTypeDefinitions());
224         }
225         return Collections.unmodifiableSet(result);
226     }
227
228     @Override
229     public Set<DataSchemaNode> getChildNodes() {
230         final Set<DataSchemaNode> result = new LinkedHashSet<>();
231         for (Module module : modules) {
232             result.addAll(module.getChildNodes());
233         }
234         return Collections.unmodifiableSet(result);
235     }
236
237     @Override
238     public Set<GroupingDefinition> getGroupings() {
239         final Set<GroupingDefinition> result = new LinkedHashSet<>();
240         for (Module module : modules) {
241             result.addAll(module.getGroupings());
242         }
243         return Collections.unmodifiableSet(result);
244     }
245
246     @Override
247     public DataSchemaNode getDataChildByName(final QName name) {
248         DataSchemaNode result = null;
249         for (Module module : modules) {
250             result = module.getDataChildByName(name);
251             if (result != null) {
252                 break;
253             }
254         }
255         return result;
256     }
257
258     @Override
259     public DataSchemaNode getDataChildByName(final String name) {
260         DataSchemaNode result = null;
261         for (Module module : modules) {
262             result = module.getDataChildByName(name);
263             if (result != null) {
264                 break;
265             }
266         }
267         return result;
268     }
269
270     @Override
271     public Set<UsesNode> getUses() {
272         return Collections.emptySet();
273     }
274
275     @Override
276     public boolean isPresenceContainer() {
277         return false;
278     }
279
280     @Override
281     public Set<AugmentationSchema> getAvailableAugmentations() {
282         return Collections.emptySet();
283     }
284
285     //FIXME: should work for submodules too
286     @Override
287     public Set<ModuleIdentifier> getAllModuleIdentifiers() {
288         return identifiersToSources.keySet();
289     }
290
291     @Override
292     public Optional<String> getModuleSource(final ModuleIdentifier moduleIdentifier) {
293         String maybeSource = identifiersToSources.get(moduleIdentifier);
294         return Optional.fromNullable(maybeSource);
295     }
296 }