Make SchemaNode.getPath() implementations as deprecated
[yangtools.git] / yang / yang-model-util / src / main / java / org / opendaylight / yangtools / yang / model / util / AbstractSchemaContext.java
1 /*
2  * Copyright (c) 2015 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.model.util;
10
11 import static com.google.common.base.Preconditions.checkArgument;
12 import static java.util.Objects.requireNonNull;
13
14 import com.google.common.collect.ImmutableMap;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.collect.Multimaps;
17 import com.google.common.collect.SetMultimap;
18 import java.lang.invoke.MethodHandles;
19 import java.lang.invoke.VarHandle;
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.HashMap;
26 import java.util.HashSet;
27 import java.util.LinkedHashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Optional;
31 import java.util.Set;
32 import java.util.TreeSet;
33 import org.opendaylight.yangtools.yang.common.QName;
34 import org.opendaylight.yangtools.yang.common.QNameModule;
35 import org.opendaylight.yangtools.yang.common.Revision;
36 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
39 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
40 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.Module;
42 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
43 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
44 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
45 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
46 import org.opendaylight.yangtools.yang.model.api.Status;
47 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
48 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.UsesNode;
50
51 public abstract class AbstractSchemaContext implements SchemaContext {
52     /**
53      * A {@link Module} comparator based on {@link Module#getRevision()}, placing latest revision first. Note this
54      * comparator does not take into account module name and so two modules with different names but same revisions
55      * compare as equal.
56      */
57     protected static final Comparator<Module> REVISION_COMPARATOR =
58         (first, second) -> Revision.compare(second.getRevision(), first.getRevision());
59
60     /**
61      * A {@link Module} comparator based on {@link Module#getName()} and {@link Module#getRevision()}, ordering modules
62      * lexicographically by their name and then in order of descending revision. This comparator assumes that
63      * the combination of these two attributes is sufficient to be consistent with hashCode/equals.
64      */
65     protected static final Comparator<Module> NAME_REVISION_COMPARATOR = (first, second) -> {
66         final int cmp = first.getName().compareTo(second.getName());
67         return cmp != 0 ? cmp : REVISION_COMPARATOR.compare(first, second);
68     };
69
70     /**
71      * Create a TreeSet for containing Modules with the same name, such that the set is ordered
72      * by {@link #REVISION_COMPARATOR}.
73      *
74      * @return A fresh TreeSet instance.
75      */
76     protected static final TreeSet<Module> createModuleSet() {
77         return new TreeSet<>(REVISION_COMPARATOR);
78     }
79
80     private static final VarHandle DERIVED_IDENTITIES;
81
82     static {
83         try {
84             DERIVED_IDENTITIES = MethodHandles.lookup().findVarHandle(AbstractSchemaContext.class, "derivedIdentities",
85                 ImmutableMap.class);
86         } catch (NoSuchFieldException | IllegalAccessException e) {
87             throw new ExceptionInInitializerError(e);
88         }
89     }
90
91     // Accessed via DERIVED_IDENTITIES
92     @SuppressWarnings("unused")
93     private volatile ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> derivedIdentities = null;
94
95     /**
96      * Returns the namespace-to-module mapping.
97      *
98      * @return Map of modules where key is namespace
99      */
100     protected abstract SetMultimap<URI, Module> getNamespaceToModules();
101
102     /**
103      * Returns the module name-to-module mapping.
104      *
105      * @return Map of modules where key is name of module
106      */
107     protected abstract SetMultimap<String, Module> getNameToModules();
108
109     /**
110      * Returns the namespace+revision-to-module mapping.
111      *
112      * @return Map of modules where key is Module's QNameModule.
113      */
114     protected abstract Map<QNameModule, Module> getModuleMap();
115
116     @Override
117     public Collection<? extends DataSchemaNode> getDataDefinitions() {
118         final Set<DataSchemaNode> dataDefs = new HashSet<>();
119         for (Module m : getModules()) {
120             dataDefs.addAll(m.getChildNodes());
121         }
122         return dataDefs;
123     }
124
125     @Override
126     public Collection<? extends NotificationDefinition> getNotifications() {
127         final Set<NotificationDefinition> notifications = new HashSet<>();
128         for (Module m : getModules()) {
129             notifications.addAll(m.getNotifications());
130         }
131         return notifications;
132     }
133
134     @Override
135     public Collection<? extends RpcDefinition> getOperations() {
136         final Set<RpcDefinition> rpcs = new HashSet<>();
137         for (Module m : getModules()) {
138             rpcs.addAll(m.getRpcs());
139         }
140         return rpcs;
141     }
142
143     @Override
144     public Collection<? extends ExtensionDefinition> getExtensions() {
145         final Set<ExtensionDefinition> extensions = new HashSet<>();
146         for (Module m : getModules()) {
147             extensions.addAll(m.getExtensionSchemaNodes());
148         }
149         return extensions;
150     }
151
152     @Override
153     public Optional<? extends Module> findModule(final String name, final Optional<Revision> revision) {
154         for (final Module module : getNameToModules().get(name)) {
155             if (revision.equals(module.getRevision())) {
156                 return Optional.of(module);
157             }
158         }
159
160         return Optional.empty();
161     }
162
163     @Override
164     public Optional<Module> findModule(final QNameModule qnameModule) {
165         return Optional.ofNullable(getModuleMap().get(qnameModule));
166     }
167
168     @Override
169     public Collection<? extends Module> findModules(final URI namespace) {
170         return getNamespaceToModules().get(namespace);
171     }
172
173     @Override
174     public Collection<? extends Module> findModules(final String name) {
175         return getNameToModules().get(name);
176     }
177
178     @Deprecated
179     @Override
180     public boolean isAugmenting() {
181         return false;
182     }
183
184     @Deprecated
185     @Override
186     public boolean isAddedByUses() {
187         return false;
188     }
189
190     @Override
191     public boolean isConfiguration() {
192         return false;
193     }
194
195     @Override
196     public QName getQName() {
197         // FIXME: YANGTOOLS-1074: we do not want this name
198         return SchemaContext.NAME;
199     }
200
201     @Override
202     @Deprecated
203     public SchemaPath getPath() {
204         return SchemaPath.ROOT;
205     }
206
207     @Override
208     public Status getStatus() {
209         return Status.CURRENT;
210     }
211
212     @Override
213     public Collection<? extends UnknownSchemaNode> getUnknownSchemaNodes() {
214         final List<UnknownSchemaNode> result = new ArrayList<>();
215         for (Module module : getModules()) {
216             result.addAll(module.getUnknownSchemaNodes());
217         }
218         return Collections.unmodifiableList(result);
219     }
220
221     @Override
222     public Collection<? extends TypeDefinition<?>> getTypeDefinitions() {
223         final Set<TypeDefinition<?>> result = new LinkedHashSet<>();
224         for (Module module : getModules()) {
225             result.addAll(module.getTypeDefinitions());
226         }
227         return Collections.unmodifiableSet(result);
228     }
229
230     @Override
231     public Collection<? extends DataSchemaNode> getChildNodes() {
232         final Set<DataSchemaNode> result = new LinkedHashSet<>();
233         for (Module module : getModules()) {
234             result.addAll(module.getChildNodes());
235         }
236         return Collections.unmodifiableSet(result);
237     }
238
239     @Override
240     public Collection<? extends GroupingDefinition> getGroupings() {
241         final Set<GroupingDefinition> result = new LinkedHashSet<>();
242         for (Module module : getModules()) {
243             result.addAll(module.getGroupings());
244         }
245         return Collections.unmodifiableSet(result);
246     }
247
248     @Override
249     public Optional<DataSchemaNode> findDataChildByName(final QName name) {
250         requireNonNull(name);
251         for (Module module : getModules()) {
252             final Optional<DataSchemaNode> result = module.findDataChildByName(name);
253             if (result.isPresent()) {
254                 return result;
255             }
256         }
257         return Optional.empty();
258     }
259
260     @Override
261     public Collection<? extends UsesNode> getUses() {
262         return Collections.emptySet();
263     }
264
265     @Override
266     public boolean isPresenceContainer() {
267         return false;
268     }
269
270     @Override
271     public Collection<? extends AugmentationSchemaNode> getAvailableAugmentations() {
272         return Collections.emptySet();
273     }
274
275     @Override
276     public Collection<? extends IdentitySchemaNode> getDerivedIdentities(final IdentitySchemaNode identity) {
277         ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> local =
278                 (ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>>)
279                 DERIVED_IDENTITIES.getAcquire(this);
280         if (local == null) {
281             local = loadDerivedIdentities();
282         }
283         final ImmutableSet<IdentitySchemaNode> result = local.get(requireNonNull(identity));
284         checkArgument(result != null, "Identity %s not found", identity);
285         return result;
286     }
287
288     private ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> loadDerivedIdentities() {
289         final SetMultimap<IdentitySchemaNode, IdentitySchemaNode> tmp =
290                 Multimaps.newSetMultimap(new HashMap<>(), HashSet::new);
291         final List<IdentitySchemaNode> identities = new ArrayList<>();
292         for (Module module : getModules()) {
293             final Collection<? extends IdentitySchemaNode> ids = module.getIdentities();
294             for (IdentitySchemaNode identity : ids) {
295                 for (IdentitySchemaNode base : identity.getBaseIdentities()) {
296                     tmp.put(base, identity);
297                 }
298             }
299             identities.addAll(ids);
300         }
301
302         final ImmutableMap.Builder<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> builder =
303                 ImmutableMap.builderWithExpectedSize(identities.size());
304         for (IdentitySchemaNode identity : identities) {
305             builder.put(identity, ImmutableSet.copyOf(tmp.get(identity)));
306         }
307
308         final ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> result = builder.build();
309         final Object witness = DERIVED_IDENTITIES.compareAndExchangeRelease(this, null, result);
310         return witness == null ? result : (ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>>) witness;
311     }
312 }