2e43b885531b40f1f302bb4fb67d1d0e7be721c4
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / test / java / org / opendaylight / controller / sal / binding / test / util / BindingTestContext.java
1 /*
2  * Copyright (c) 2014 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.controller.sal.binding.test.util;
9
10 import static com.google.common.base.Preconditions.checkState;
11
12 import java.io.InputStream;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Set;
16 import java.util.concurrent.Future;
17
18 import javassist.ClassPool;
19
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl;
22 import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
23 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
24 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
25 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
26 import org.opendaylight.controller.sal.binding.api.mount.MountProviderService;
27 import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
28 import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl;
29 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
30 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer;
31 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
32 import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedBindingBrokerImpl;
33 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
34 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
35 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
36 import org.opendaylight.controller.sal.core.api.BrokerService;
37 import org.opendaylight.controller.sal.core.api.RpcImplementation;
38 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
39 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
40 import org.opendaylight.controller.sal.core.api.data.DataStore;
41 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
42 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
43 import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
44 import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
45 import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
46 import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
47 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
48 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
49 import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
50 import org.opendaylight.yangtools.concepts.ListenerRegistration;
51 import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
52 import org.opendaylight.yangtools.yang.common.QName;
53 import org.opendaylight.yangtools.yang.common.RpcResult;
54 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
55 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
56 import org.opendaylight.yangtools.yang.model.api.Module;
57 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
58 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
59 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
60 import org.reflections.Reflections;
61 import org.reflections.scanners.ResourcesScanner;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 import com.google.common.base.Predicate;
66 import com.google.common.collect.ClassToInstanceMap;
67 import com.google.common.collect.ImmutableClassToInstanceMap;
68 import com.google.common.collect.ImmutableMap;
69 import com.google.common.util.concurrent.ListeningExecutorService;
70
71 public class BindingTestContext implements AutoCloseable, SchemaContextProvider {
72
73     public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
74             .builder().toInstance();
75
76     private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class);
77
78     private RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
79
80     private DomForwardedBindingBrokerImpl baBrokerImpl;
81     private DataBrokerImpl baDataImpl;
82     private NotificationBrokerImpl baNotifyImpl;
83     private BindingIndependentConnector baConnectImpl;
84
85     private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
86     private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataLegacyBroker;
87     private BrokerImpl biBrokerImpl;
88     private HashMapDataStore rawDataStore;
89     private SchemaAwareDataStoreAdapter schemaAwareDataStore;
90     private DataStoreStatsWrapper dataStoreStats;
91     private DataStore dataStore;
92
93     private final boolean dataStoreStatisticsEnabled = false;
94
95     private final ListeningExecutorService executor;
96     private final ClassPool classPool;
97
98     private final boolean startWithSchema;
99
100     private MountPointManagerImpl biMountImpl;
101
102     private SchemaContext schemaContext;
103
104     private ImmutableMap<LogicalDatastoreType, DOMStore> newDatastores;
105
106     private BackwardsCompatibleDataBroker biCompatibleBroker;
107
108     private final List<SchemaContextListener> schemaListeners = new ArrayList<>();
109
110     @Override
111     public SchemaContext getSchemaContext() {
112         return schemaContext;
113     }
114
115     protected BindingTestContext(final ListeningExecutorService executor, final ClassPool classPool, final boolean startWithSchema) {
116         this.executor = executor;
117         this.classPool = classPool;
118         this.startWithSchema = startWithSchema;
119     }
120
121     public void startDomDataStore() {
122         checkState(dataStore == null, "DataStore already started.");
123         checkState(biDataImpl != null, "Dom Data Broker not present");
124         rawDataStore = new HashMapDataStore();
125         schemaAwareDataStore = new SchemaAwareDataStoreAdapter();
126         schemaAwareDataStore.changeDelegate(rawDataStore);
127         if (dataStoreStatisticsEnabled) {
128             dataStoreStats = new DataStoreStatsWrapper(schemaAwareDataStore);
129             dataStore = dataStoreStats;
130         } else {
131             dataStore = schemaAwareDataStore;
132         }
133
134         biDataImpl.registerConfigurationReader(TREE_ROOT, dataStore);
135         biDataImpl.registerOperationalReader(TREE_ROOT, dataStore);
136         biDataImpl.registerCommitHandler(TREE_ROOT, dataStore);
137     }
138
139     public void startDomDataBroker() {
140         checkState(executor != null, "Executor needs to be set");
141         biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl();
142         biDataImpl.setExecutor(executor);
143         biDataLegacyBroker = biDataImpl;
144     }
145
146     public void startNewDomDataBroker() {
147         checkState(executor != null, "Executor needs to be set");
148         InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER", executor);
149         InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG", executor);
150         newDatastores = ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
151                 .put(LogicalDatastoreType.OPERATIONAL, operStore)
152                 .put(LogicalDatastoreType.CONFIGURATION, configStore)
153                 .build();
154
155         DOMDataBrokerImpl newBiDataImpl = new DOMDataBrokerImpl(newDatastores, executor);
156
157         biCompatibleBroker = new BackwardsCompatibleDataBroker(newBiDataImpl);
158
159         schemaListeners.add(configStore);
160         schemaListeners.add(operStore);
161         schemaListeners.add(biCompatibleBroker);
162         biDataLegacyBroker = biCompatibleBroker;
163     }
164
165     public void startBindingDataBroker() {
166         checkState(executor != null, "Executor needs to be set");
167         baDataImpl = new DataBrokerImpl();
168         baDataImpl.setExecutor(executor);
169     }
170
171     public void startBindingBroker() {
172         checkState(executor != null, "Executor needs to be set");
173         checkState(baDataImpl != null, "Binding Data Broker must be started");
174         checkState(baNotifyImpl != null, "Notification Service must be started");
175         baBrokerImpl = new DomForwardedBindingBrokerImpl("test");
176
177         baBrokerImpl.getMountManager().setDataCommitExecutor(executor);
178         baBrokerImpl.getMountManager().setNotificationExecutor(executor);
179         baBrokerImpl.setRpcBroker(new RpcProviderRegistryImpl("test"));
180         baBrokerImpl.setDataBroker(baDataImpl);
181         baBrokerImpl.setNotificationBroker(baNotifyImpl);
182         baBrokerImpl.start();
183     }
184
185     public void startForwarding() {
186         checkState(baDataImpl != null, "Binding Data Broker needs to be started");
187         checkState(biDataLegacyBroker != null, "DOM Data Broker needs to be started.");
188         checkState(mappingServiceImpl != null, "DOM Mapping Service needs to be started.");
189
190         baConnectImpl = BindingDomConnectorDeployer.createConnector(getBindingToDomMappingService());
191         baConnectImpl.setDomRpcRegistry(getDomRpcRegistry());
192         baBrokerImpl.setConnector(baConnectImpl);
193         baBrokerImpl.setDomProviderContext(createMockContext());
194         baBrokerImpl.startForwarding();
195     }
196
197     private ProviderSession createMockContext() {
198
199         final ClassToInstanceMap<BrokerService> domBrokerServices = ImmutableClassToInstanceMap
200                 .<BrokerService> builder()
201                 //
202                 .put(org.opendaylight.controller.sal.core.api.data.DataProviderService.class, biDataLegacyBroker) //
203                 .put(RpcProvisionRegistry.class, biBrokerImpl.getRouter()) //
204                 .put(MountProvisionService.class, biMountImpl) //
205                 .build();
206
207         return new ProviderSession() {
208
209             @Override
210             public Future<RpcResult<CompositeNode>> rpc(final QName rpc, final CompositeNode input) {
211                 throw new UnsupportedOperationException();
212             }
213
214             @Override
215             public <T extends BrokerService> T getService(final Class<T> service) {
216                 return domBrokerServices.getInstance(service);
217             }
218
219             @Override
220             public boolean isClosed() {
221                 return false;
222             }
223
224             @Override
225             public Set<QName> getSupportedRpcs() {
226                 return null;
227             }
228
229             @Override
230             public void close() {
231             }
232
233             @Override
234             public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(
235                     final RpcRegistrationListener listener) {
236                 return null;
237             }
238
239             @Override
240             public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
241                     throws IllegalArgumentException {
242                 return null;
243             }
244
245             @Override
246             public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
247                 return null;
248             }
249
250             @Override
251             public RoutedRpcRegistration addMountedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
252                 return null;
253             }
254         };
255     }
256
257     public void startBindingToDomMappingService() {
258         checkState(classPool != null, "ClassPool needs to be present");
259         mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl();
260         mappingServiceImpl.setPool(classPool);
261         mappingServiceImpl.init();
262     }
263
264     public void updateYangSchema(final String[] files) {
265         schemaContext = getContext(files);
266
267         if (schemaAwareDataStore != null) {
268             schemaAwareDataStore.onGlobalContextUpdated(schemaContext);
269         }
270         if (mappingServiceImpl != null) {
271             mappingServiceImpl.onGlobalContextUpdated(schemaContext);
272         }
273         for(SchemaContextListener listener : schemaListeners) {
274             listener.onGlobalContextUpdated(schemaContext);
275         }
276     }
277
278     public static String[] getAllYangFilesOnClasspath() {
279         Predicate<String> predicate = new Predicate<String>() {
280             @Override
281             public boolean apply(final String input) {
282                 return input.endsWith(".yang");
283             }
284         };
285         Reflections reflection = new Reflections("META-INF.yang", new ResourcesScanner());
286         Set<String> result = reflection.getResources(predicate);
287         return result.toArray(new String[result.size()]);
288     }
289
290     private static SchemaContext getContext(final String[] yangFiles) {
291         ClassLoader loader = BindingTestContext.class.getClassLoader();
292         List<InputStream> streams = new ArrayList<>();
293         for (String string : yangFiles) {
294             InputStream stream = loader.getResourceAsStream(string);
295             streams.add(stream);
296         }
297         YangParserImpl parser = new YangParserImpl();
298         Set<Module> modules = parser.parseYangModelsFromStreams(streams);
299         return parser.resolveSchemaContext(modules);
300     }
301
302     public void startLegacy() {
303         startBindingDataBroker();
304         startBindingNotificationBroker();
305         startBindingBroker();
306         startDomDataBroker();
307         startDomDataStore();
308         startDomBroker();
309         startDomMountPoint();
310         startBindingToDomMappingService();
311         startForwarding();
312         if (startWithSchema) {
313             loadYangSchemaFromClasspath();
314         }
315     }
316
317     public void start() {
318         startBindingDataBroker();
319         startBindingNotificationBroker();
320         startBindingBroker();
321         startNewDomDataBroker();
322         startDomBroker();
323         startDomMountPoint();
324         startBindingToDomMappingService();
325         startForwarding();
326         if (startWithSchema) {
327             loadYangSchemaFromClasspath();
328         }
329     }
330
331     private void startDomMountPoint() {
332         biMountImpl = new MountPointManagerImpl();
333         biMountImpl.setDataBroker(getDomDataBroker());
334     }
335
336     private void startDomBroker() {
337         checkState(executor != null);
338         biBrokerImpl = new BrokerImpl();
339         biBrokerImpl.setExecutor(executor);
340         biBrokerImpl.setRouter(new SchemaAwareRpcBroker("/", this));
341
342     }
343
344     public void startBindingNotificationBroker() {
345         checkState(executor != null);
346         baNotifyImpl = new NotificationBrokerImpl(executor);
347
348     }
349
350     public void loadYangSchemaFromClasspath() {
351         String[] files = getAllYangFilesOnClasspath();
352         updateYangSchema(files);
353     }
354
355     public DataProviderService getBindingDataBroker() {
356         return baDataImpl;
357     }
358
359     public org.opendaylight.controller.sal.core.api.data.DataProviderService getDomDataBroker() {
360         return biDataLegacyBroker;
361     }
362
363     public DataStore getDomDataStore() {
364         return dataStore;
365     }
366
367     public BindingIndependentMappingService getBindingToDomMappingService() {
368         return mappingServiceImpl;
369     }
370
371     public void logDataStoreStatistics() {
372         if (dataStoreStats == null) {
373             return;
374         }
375
376         LOG.info("BIDataStore Statistics: Configuration Read Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
377                 dataStoreStats.getConfigurationReadCount(), dataStoreStats.getConfigurationReadTotalTime(),
378                 dataStoreStats.getConfigurationReadAverageTime());
379
380         LOG.info("BIDataStore Statistics: Operational Read Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
381                 dataStoreStats.getOperationalReadCount(), dataStoreStats.getOperationalReadTotalTime(),
382                 dataStoreStats.getOperationalReadAverageTime());
383
384         LOG.info("BIDataStore Statistics: Request Commit Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
385                 dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(),
386                 dataStoreStats.getRequestCommitAverageTime());
387     }
388
389     public RpcProviderRegistry getBindingRpcRegistry() {
390         return baBrokerImpl.getRoot();
391     }
392
393     public RpcProvisionRegistry getDomRpcRegistry() {
394         if (biBrokerImpl == null) {
395             return null;
396         }
397         return biBrokerImpl.getRouter();
398     }
399
400     public RpcImplementation getDomRpcInvoker() {
401         return biBrokerImpl.getRouter();
402     }
403
404     @Override
405     public void close() throws Exception {
406
407     }
408
409     public MountProviderService getBindingMountProviderService() {
410         return baBrokerImpl.getMountManager();
411     }
412
413     public MountProvisionService getDomMountProviderService() {
414         return biMountImpl;
415     }
416 }