2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.yangtools.yang.model.util;
11 import static com.google.common.base.Preconditions.checkArgument;
12 import static java.util.Objects.requireNonNull;
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;
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;
30 import java.util.Optional;
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;
51 public abstract class AbstractSchemaContext implements SchemaContext {
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
57 protected static final Comparator<Module> REVISION_COMPARATOR =
58 (first, second) -> Revision.compare(second.getRevision(), first.getRevision());
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.
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);
71 * Create a TreeSet for containing Modules with the same name, such that the set is ordered
72 * by {@link #REVISION_COMPARATOR}.
74 * @return A fresh TreeSet instance.
76 protected static final TreeSet<Module> createModuleSet() {
77 return new TreeSet<>(REVISION_COMPARATOR);
80 private static final VarHandle DERIVED_IDENTITIES;
84 DERIVED_IDENTITIES = MethodHandles.lookup().findVarHandle(AbstractSchemaContext.class, "derivedIdentities",
86 } catch (NoSuchFieldException | IllegalAccessException e) {
87 throw new ExceptionInInitializerError(e);
91 // Accessed via DERIVED_IDENTITIES
92 @SuppressWarnings("unused")
93 private volatile ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> derivedIdentities = null;
96 * Returns the namespace-to-module mapping.
98 * @return Map of modules where key is namespace
100 protected abstract SetMultimap<URI, Module> getNamespaceToModules();
103 * Returns the module name-to-module mapping.
105 * @return Map of modules where key is name of module
107 protected abstract SetMultimap<String, Module> getNameToModules();
110 * Returns the namespace+revision-to-module mapping.
112 * @return Map of modules where key is Module's QNameModule.
114 protected abstract Map<QNameModule, Module> getModuleMap();
117 public Collection<? extends DataSchemaNode> getDataDefinitions() {
118 final Set<DataSchemaNode> dataDefs = new HashSet<>();
119 for (Module m : getModules()) {
120 dataDefs.addAll(m.getChildNodes());
126 public Collection<? extends NotificationDefinition> getNotifications() {
127 final Set<NotificationDefinition> notifications = new HashSet<>();
128 for (Module m : getModules()) {
129 notifications.addAll(m.getNotifications());
131 return notifications;
135 public Collection<? extends RpcDefinition> getOperations() {
136 final Set<RpcDefinition> rpcs = new HashSet<>();
137 for (Module m : getModules()) {
138 rpcs.addAll(m.getRpcs());
144 public Collection<? extends ExtensionDefinition> getExtensions() {
145 final Set<ExtensionDefinition> extensions = new HashSet<>();
146 for (Module m : getModules()) {
147 extensions.addAll(m.getExtensionSchemaNodes());
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);
160 return Optional.empty();
164 public Optional<Module> findModule(final QNameModule qnameModule) {
165 return Optional.ofNullable(getModuleMap().get(qnameModule));
169 public Collection<? extends Module> findModules(final URI namespace) {
170 return getNamespaceToModules().get(namespace);
174 public Collection<? extends Module> findModules(final String name) {
175 return getNameToModules().get(name);
180 public boolean isAugmenting() {
186 public boolean isAddedByUses() {
191 public boolean isConfiguration() {
196 public QName getQName() {
197 return SchemaContext.NAME;
201 public SchemaPath getPath() {
202 return SchemaPath.ROOT;
206 public Status getStatus() {
207 return Status.CURRENT;
211 public Collection<? extends UnknownSchemaNode> getUnknownSchemaNodes() {
212 final List<UnknownSchemaNode> result = new ArrayList<>();
213 for (Module module : getModules()) {
214 result.addAll(module.getUnknownSchemaNodes());
216 return Collections.unmodifiableList(result);
220 public Collection<? extends TypeDefinition<?>> getTypeDefinitions() {
221 final Set<TypeDefinition<?>> result = new LinkedHashSet<>();
222 for (Module module : getModules()) {
223 result.addAll(module.getTypeDefinitions());
225 return Collections.unmodifiableSet(result);
229 public Collection<? extends DataSchemaNode> getChildNodes() {
230 final Set<DataSchemaNode> result = new LinkedHashSet<>();
231 for (Module module : getModules()) {
232 result.addAll(module.getChildNodes());
234 return Collections.unmodifiableSet(result);
238 public Collection<? extends GroupingDefinition> getGroupings() {
239 final Set<GroupingDefinition> result = new LinkedHashSet<>();
240 for (Module module : getModules()) {
241 result.addAll(module.getGroupings());
243 return Collections.unmodifiableSet(result);
247 public Optional<DataSchemaNode> findDataChildByName(final QName name) {
248 requireNonNull(name);
249 for (Module module : getModules()) {
250 final Optional<DataSchemaNode> result = module.findDataChildByName(name);
251 if (result.isPresent()) {
255 return Optional.empty();
259 public Collection<? extends UsesNode> getUses() {
260 return Collections.emptySet();
264 public boolean isPresenceContainer() {
269 public Collection<? extends AugmentationSchemaNode> getAvailableAugmentations() {
270 return Collections.emptySet();
274 public Collection<? extends IdentitySchemaNode> getDerivedIdentities(final IdentitySchemaNode identity) {
275 ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> local =
276 (ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>>)
277 DERIVED_IDENTITIES.getAcquire(this);
279 local = loadDerivedIdentities();
281 final ImmutableSet<IdentitySchemaNode> result = local.get(requireNonNull(identity));
282 checkArgument(result != null, "Identity %s not found", identity);
286 private ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> loadDerivedIdentities() {
287 final SetMultimap<IdentitySchemaNode, IdentitySchemaNode> tmp =
288 Multimaps.newSetMultimap(new HashMap<>(), HashSet::new);
289 final List<IdentitySchemaNode> identities = new ArrayList<>();
290 for (Module module : getModules()) {
291 final Collection<? extends IdentitySchemaNode> ids = module.getIdentities();
292 for (IdentitySchemaNode identity : ids) {
293 for (IdentitySchemaNode base : identity.getBaseIdentities()) {
294 tmp.put(base, identity);
297 identities.addAll(ids);
300 final ImmutableMap.Builder<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> builder =
301 ImmutableMap.builderWithExpectedSize(identities.size());
302 for (IdentitySchemaNode identity : identities) {
303 builder.put(identity, ImmutableSet.copyOf(tmp.get(identity)));
306 final ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> result = builder.build();
307 final Object witness = DERIVED_IDENTITIES.compareAndExchangeRelease(this, null, result);
308 return witness == null ? result : (ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>>) witness;