6a9608bab06b10692ecafd8fad59a9975850135a
[transportpce.git] / common / src / main / java / org / opendaylight / transportpce / common / DataStoreContextImpl.java
1 /*
2  * Copyright © 2016 AT&T 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.transportpce.common;
9
10 import com.google.common.collect.ClassToInstanceMap;
11 import com.google.common.collect.ImmutableMap;
12 import com.google.common.util.concurrent.ListeningExecutorService;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Optional;
18 import java.util.ServiceLoader;
19 import java.util.concurrent.Executors;
20 import javassist.ClassPool;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.opendaylight.mdsal.binding.api.DataBroker;
23 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
24 import org.opendaylight.mdsal.binding.api.NotificationService;
25 import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMDataBrokerAdapter;
26 import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMNotificationPublishServiceAdapter;
27 import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMNotificationServiceAdapter;
28 import org.opendaylight.mdsal.binding.dom.adapter.BindingToNormalizedNodeCodec;
29 import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
30 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
31 import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
32 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
33 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
34 import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
35 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
36 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
37 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
38 import org.opendaylight.mdsal.dom.api.DOMSchemaServiceExtension;
39 import org.opendaylight.mdsal.dom.broker.DOMNotificationRouter;
40 import org.opendaylight.mdsal.dom.broker.SerializedDOMDataBroker;
41 import org.opendaylight.mdsal.dom.spi.store.DOMStore;
42 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
43 import org.opendaylight.yangtools.concepts.ListenerRegistration;
44 import org.opendaylight.yangtools.util.ListenerRegistry;
45 import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider;
46 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
47 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
48 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
49 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 public class DataStoreContextImpl implements DataStoreContext {
54
55     private static final Logger LOG = LoggerFactory.getLogger(DataStoreContextImpl.class);
56
57     private final Map<LogicalDatastoreType, DOMStore> datastores;
58     private final SchemaContextHolder mockedSchemaContext;
59     private final DOMNotificationRouter domNotificationRouter;
60     private final DOMDataBroker domDataBroker;
61     private final DataBroker dataBroker;
62     private final NotificationService notificationService;
63     private final NotificationPublishService notificationPublishService;
64
65     public DataStoreContextImpl() {
66         this(false);
67     }
68
69     public DataStoreContextImpl(boolean fromClasspath) {
70         this.mockedSchemaContext = new SchemaContextHolder(fromClasspath);
71         this.datastores = createDatastores();
72         this.domNotificationRouter = DOMNotificationRouter.create(16);
73         this.domDataBroker = createDOMDataBroker();
74         this.dataBroker = createDataBroker();
75         this.notificationService = createNotificationService();
76         this.notificationPublishService = createNotificationPublishService();
77         for (ListenerRegistration<? extends SchemaContextListener> listener :
78                                                         this.mockedSchemaContext.listeners.getRegistrations()) {
79             listener.getInstance().onGlobalContextUpdated(this.mockedSchemaContext.schemaContext);
80         }
81     }
82
83     @Override
84     public DataBroker getDataBroker() {
85         return this.dataBroker;
86     }
87
88     @Override
89     public DOMDataBroker getDOMDataBroker() {
90         return this.domDataBroker;
91     }
92
93     @Override
94     public NotificationService createNotificationService() {
95         return new BindingDOMNotificationServiceAdapter(this.domNotificationRouter,
96                 this.mockedSchemaContext.bindingStreamCodecs);
97     }
98
99     @Override
100     public NotificationPublishService createNotificationPublishService() {
101         return new BindingDOMNotificationPublishServiceAdapter(this.domNotificationRouter,
102                 this.mockedSchemaContext.bindingToNormalized);
103     }
104
105     @Override
106     public SchemaContext getSchemaContext() {
107         return this.mockedSchemaContext.schemaContext;
108     }
109
110     @Override
111     public BindingNormalizedNodeCodecRegistry getBindingToNormalizedNodeCodec() {
112         return this.mockedSchemaContext.bindingStreamCodecs;
113     }
114
115     @Override
116     public NotificationService getNotificationService() {
117         return this.notificationService;
118     }
119
120     @Override
121     public NotificationPublishService getNotificationPublishService() {
122         return this.notificationPublishService;
123     }
124
125     private DOMDataBroker createDOMDataBroker() {
126         return new SerializedDOMDataBroker(this.datastores,
127                 MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()));
128     }
129
130     private ListeningExecutorService getDataTreeChangeListenerExecutor() {
131         return MoreExecutors.newDirectExecutorService();
132     }
133
134     private DataBroker createDataBroker() {
135         return new BindingDOMDataBrokerAdapter(getDOMDataBroker(), this.mockedSchemaContext.bindingToNormalized);
136     }
137
138     private Map<LogicalDatastoreType, DOMStore> createDatastores() {
139         return ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
140                 .put(LogicalDatastoreType.OPERATIONAL, createOperationalDatastore())
141                 .put(LogicalDatastoreType.CONFIGURATION, createConfigurationDatastore()).build();
142     }
143
144     private DOMStore createConfigurationDatastore() {
145         final InMemoryDOMDataStore store = new InMemoryDOMDataStore("CFG", getDataTreeChangeListenerExecutor());
146         this.mockedSchemaContext.registerSchemaContextListener(store);
147         return store;
148     }
149
150     private DOMStore createOperationalDatastore() {
151         final InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", getDataTreeChangeListenerExecutor());
152         this.mockedSchemaContext.registerSchemaContextListener(store);
153         return store;
154     }
155
156     private final class SchemaContextHolder implements DOMSchemaService, SchemaContextProvider {
157
158         private final SchemaContext schemaContext;
159         private final ListenerRegistry<SchemaContextListener> listeners;
160         private final BindingNormalizedNodeCodecRegistry bindingStreamCodecs;
161         private final BindingToNormalizedNodeCodec bindingToNormalized;
162         private final ModuleInfoBackedContext moduleInfoBackedCntxt;
163
164         private SchemaContextHolder(boolean fromClasspath) {
165             List<YangModuleInfo> moduleInfos = loadModuleInfos();
166             this.moduleInfoBackedCntxt = ModuleInfoBackedContext.create();
167             this.schemaContext = getSchemaContext(moduleInfos);
168             this.listeners = ListenerRegistry.create();
169             this.bindingStreamCodecs = createBindingRegistry();
170             GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
171             this.bindingToNormalized = new BindingToNormalizedNodeCodec(loading, this.bindingStreamCodecs);
172             registerSchemaContextListener(this.bindingToNormalized);
173         }
174
175         @Override
176         public SchemaContext getSchemaContext() {
177             return this.schemaContext;
178         }
179
180         /**
181          * Get the schemacontext from loaded modules on classpath.
182          *
183          * @param moduleInfos a list of Yang module Infos
184          * @return SchemaContext a schema context
185          */
186         private SchemaContext getSchemaContext(List<YangModuleInfo> moduleInfos) {
187             this.moduleInfoBackedCntxt.addModuleInfos(moduleInfos);
188             Optional<SchemaContext> tryToCreateSchemaContext =
189                     this.moduleInfoBackedCntxt.tryToCreateSchemaContext();
190             if (!tryToCreateSchemaContext.isPresent()) {
191                 LOG.error("Could not create the initial schema context. Schema context is empty");
192                 throw new IllegalStateException();
193             }
194             return tryToCreateSchemaContext.get();
195         }
196
197         @Override
198         public SchemaContext getGlobalContext() {
199             return this.schemaContext;
200         }
201
202         @Override
203         public SchemaContext getSessionContext() {
204             return this.schemaContext;
205         }
206
207         @Override
208         public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(
209                 SchemaContextListener listener) {
210             return this.listeners.register(listener);
211         }
212
213         /**
214          * Loads all {@link YangModelBindingProvider} on the classpath.
215          *
216          * @return list of known {@link YangModuleInfo}
217          */
218         private List<YangModuleInfo> loadModuleInfos() {
219             List<YangModuleInfo> moduleInfos = new LinkedList<>();
220             ServiceLoader<YangModelBindingProvider> yangProviderLoader =
221                     ServiceLoader.load(YangModelBindingProvider.class);
222             for (YangModelBindingProvider yangModelBindingProvider : yangProviderLoader) {
223                 moduleInfos.add(yangModelBindingProvider.getModuleInfo());
224                 LOG.debug("Adding [{}] module into known modules", yangModelBindingProvider.getModuleInfo());
225             }
226             return moduleInfos;
227         }
228
229         /**
230          * Creates binding registry.
231          *
232          * @return BindingNormalizedNodeCodecRegistry the resulting binding registry
233          */
234         private BindingNormalizedNodeCodecRegistry createBindingRegistry() {
235             BindingRuntimeContext bindingContext =
236                 BindingRuntimeContext.create(this.moduleInfoBackedCntxt, this.schemaContext);
237             BindingNormalizedNodeCodecRegistry bindingNormalizedNodeCodecRegistry =
238                     new BindingNormalizedNodeCodecRegistry(
239                             StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault())));
240             bindingNormalizedNodeCodecRegistry.onBindingRuntimeContextUpdated(bindingContext);
241             return bindingNormalizedNodeCodecRegistry;
242         }
243
244         /* (non-Javadoc)
245          * @see org.opendaylight.mdsal.dom.api.DOMExtensibleService#getExtensions()
246          */
247         @Override
248         public @NonNull ClassToInstanceMap<DOMSchemaServiceExtension> getExtensions() {
249             // TODO Auto-generated method stub
250             return null;
251         }
252     }
253 }