Adjust to yangtools-2.0.0 changes
[controller.git] / opendaylight / config / config-manager-facade-xml / src / main / java / org / opendaylight / controller / config / facade / xml / osgi / YangStoreService.java
1 /*
2  * Copyright (c) 2015, 2017 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.controller.config.facade.xml.osgi;
10
11 import com.google.common.collect.Collections2;
12 import com.google.common.collect.ImmutableSet;
13 import com.google.common.collect.Sets;
14 import com.google.common.util.concurrent.ThreadFactoryBuilder;
15 import java.util.Collections;
16 import java.util.HashSet;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.concurrent.ExecutorService;
20 import java.util.concurrent.Executors;
21 import javax.annotation.concurrent.GuardedBy;
22 import org.opendaylight.controller.config.util.capability.Capability;
23 import org.opendaylight.controller.config.util.capability.ModuleListener;
24 import org.opendaylight.controller.config.util.capability.YangModuleCapability;
25 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
26 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.model.api.Module;
29 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
30 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
31 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
32 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
33 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
34
35 public class YangStoreService implements YangStoreContext {
36
37     private final SchemaSourceProvider<YangTextSchemaSource> sourceProvider;
38     private final ExecutorService notificationExecutor = Executors.newSingleThreadExecutor(
39             new ThreadFactoryBuilder().setDaemon(true).setNameFormat("yangstore-capability-notifications").build());
40
41     /**
42      * Guarded by explicit lock to allow for properly synchronizing the initial
43      * notification and modification of the listener set.
44      */
45     @GuardedBy("listeners")
46     private final Set<ModuleListener> listeners = new HashSet<>();
47
48     /**
49      * This is the latest snapshot. Some of its state is always initialized, but the
50      * MXBean maps potentially cause recomputation. Accessing those two specific
51      * methods needs to re-check whether the snapshot has changed asynchronously and
52      * retry if it didi.
53      */
54     private volatile YangStoreSnapshot snap;
55
56     public YangStoreService(final SchemaContextProvider schemaContextProvider,
57             final SchemaSourceProvider<YangTextSchemaSource> sourceProvider) {
58         this.sourceProvider = sourceProvider;
59     }
60
61     public YangStoreContext getCurrentSnapshot() {
62         return this.snap;
63     }
64
65     @Deprecated
66     @Override
67     public Map<String, Map<String, ModuleMXBeanEntry>> getModuleMXBeanEntryMap() {
68         Map<String, Map<String, ModuleMXBeanEntry>> ret;
69         YangStoreSnapshot snapshot;
70
71         do {
72             snapshot = this.snap;
73             ret = snapshot.getModuleMXBeanEntryMap();
74         } while (!snapshot.equals(this.snap));
75
76         return ret;
77     }
78
79     @Override
80     public Map<QName, Map<String, ModuleMXBeanEntry>> getQNamesToIdentitiesToModuleMXBeanEntries() {
81         Map<QName, Map<String, ModuleMXBeanEntry>> ret;
82         YangStoreSnapshot snapshot;
83
84         do {
85             snapshot = this.snap;
86             ret = snapshot.getQNamesToIdentitiesToModuleMXBeanEntries();
87         } while (!snapshot.equals(this.snap));
88
89         return ret;
90     }
91
92     @Override
93     public Set<Module> getModules() {
94         return this.snap.getModules();
95     }
96
97     @Override
98     public String getModuleSource(final SourceIdentifier moduleIdentifier) {
99         return this.snap.getModuleSource(moduleIdentifier);
100     }
101
102     @Override
103     public EnumResolver getEnumResolver() {
104         return this.snap.getEnumResolver();
105     }
106
107     public void refresh(final BindingRuntimeContext runtimeContext) {
108         final YangStoreSnapshot next = new YangStoreSnapshot(runtimeContext, this.sourceProvider);
109         final YangStoreSnapshot previous = this.snap;
110         this.snap = next;
111         this.notificationExecutor.submit(() -> notifyListeners(previous, next));
112     }
113
114     public AutoCloseable registerModuleListener(final ModuleListener listener) {
115         final YangStoreContext context = this.snap;
116
117         synchronized (this.listeners) {
118             if (context != null) {
119                 listener.onCapabilitiesChanged(toCapabilities(context.getModules(), context),
120                         Collections.<Capability>emptySet());
121             }
122             this.listeners.add(listener);
123         }
124
125         return () -> {
126             synchronized (YangStoreService.this.listeners) {
127                 YangStoreService.this.listeners.remove(listener);
128             }
129         };
130     }
131
132     void notifyListeners(final YangStoreSnapshot previous, final YangStoreSnapshot current) {
133         final Set<Module> prevModules = previous.getModules();
134         final Set<Module> currModules = current.getModules();
135         final Set<Module> removed = Sets.difference(prevModules, currModules);
136         final Set<Module> added = Sets.difference(currModules, prevModules);
137
138         final Set<Capability> addedCaps = toCapabilities(added, current);
139         final Set<Capability> removedCaps = toCapabilities(removed, current);
140
141         synchronized (this.listeners) {
142             for (final ModuleListener listener : this.listeners) {
143                 listener.onCapabilitiesChanged(addedCaps, removedCaps);
144             }
145         }
146     }
147
148     private static Set<Capability> toCapabilities(final Set<Module> modules, final YangStoreContext current) {
149         return ImmutableSet.copyOf(Collections2.transform(modules,
150             input -> new YangModuleCapability(input, current.getModuleSource(
151                 RevisionSourceIdentifier.create(input.getName(), input.getRevision())))));
152     }
153 }