Enable modernizer in sal-distributed-datastore
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / OSGiDistributedDataStore.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. 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.cluster.datastore;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import java.util.Dictionary;
16 import java.util.Hashtable;
17 import java.util.Map;
18 import org.checkerframework.checker.lock.qual.GuardedBy;
19 import org.gaul.modernizer_maven_annotations.SuppressModernizer;
20 import org.opendaylight.controller.cluster.ActorSystemProvider;
21 import org.opendaylight.controller.cluster.datastore.config.Configuration;
22 import org.opendaylight.controller.cluster.datastore.config.ConfigurationImpl;
23 import org.opendaylight.controller.cluster.datastore.config.ModuleShardConfigProvider;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
25 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
26 import org.osgi.service.component.ComponentFactory;
27 import org.osgi.service.component.ComponentInstance;
28 import org.osgi.service.component.annotations.Activate;
29 import org.osgi.service.component.annotations.Component;
30 import org.osgi.service.component.annotations.Deactivate;
31 import org.osgi.service.component.annotations.Modified;
32 import org.osgi.service.component.annotations.Reference;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37  * Global bootstrap component. It is responsible to start all distributed datastore instances and activate
38  * {@link OSGiDOMStore} as appropriate. It also provides routing of datastore proprerties towards AbstractDataStore.
39  */
40 @Beta
41 @Component(immediate = true, configurationPid = "org.opendaylight.controller.cluster.datastore")
42 public final class OSGiDistributedDataStore {
43     /**
44      * Internal state associated with a particular datastore. An instance is created for each datastore and once the
45      * datastore settles, we create a new component configuration of {@link OSGiDOMStore}. This indirection is needed
46      * to not block Service Component Runtime from activating other components while we are waiting for the datastore
47      * to settle (which can take a long time).
48      */
49     private final class DatastoreState implements FutureCallback<Object> {
50         private final DatastoreContextIntrospector introspector;
51         private final LogicalDatastoreType datastoreType;
52         private final AbstractDataStore datastore;
53         private final String serviceType;
54
55         @GuardedBy("this")
56         private ComponentInstance component;
57         @GuardedBy("this")
58         private boolean stopped;
59
60         DatastoreState(final DatastoreContextIntrospector introspector, final LogicalDatastoreType datastoreType,
61                 final AbstractDataStore datastore, final String serviceType) {
62             this.introspector = requireNonNull(introspector);
63             this.datastoreType = requireNonNull(datastoreType);
64             this.datastore = requireNonNull(datastore);
65             this.serviceType = requireNonNull(serviceType);
66         }
67
68         synchronized void updateProperties(final Map<String, Object> properties) {
69             if (introspector.update(properties)) {
70                 datastore.onDatastoreContextUpdated(introspector.newContextFactory());
71             }
72         }
73
74         void stop() {
75             LOG.info("Distributed Datastore type {} stopping", datastoreType);
76
77             synchronized (this) {
78                 stopped = true;
79                 if (component != null) {
80                     component.dispose();
81                     component = null;
82                 }
83                 datastore.close();
84                 LOG.info("Distributed Datastore type {} stopped", datastoreType);
85             }
86         }
87
88         @Override
89         @SuppressModernizer
90         public void onSuccess(final Object result) {
91             LOG.debug("Distributed Datastore type {} reached initial settle", datastoreType);
92
93             synchronized (this) {
94                 if (!stopped) {
95                     final Dictionary<String, Object> dict = new Hashtable<>();
96                     dict.put(OSGiDOMStore.DATASTORE_TYPE_PROP, datastoreType);
97                     dict.put(OSGiDOMStore.DATASTORE_INST_PROP, datastore);
98                     dict.put("type", serviceType);
99                     component = datastoreFactory.newInstance(dict);
100                     LOG.info("Distributed Datastore type {} started", datastoreType);
101                 }
102             }
103         }
104
105         @Override
106         public synchronized void onFailure(final Throwable cause) {
107             LOG.error("Distributed Datastore type {} failed to settle", datastoreType, cause);
108         }
109     }
110
111     private static final Logger LOG = LoggerFactory.getLogger(OSGiDistributedDataStore.class);
112
113     @Reference
114     DOMSchemaService schemaService = null;
115     @Reference
116     ActorSystemProvider actorSystemProvider = null;
117     @Reference
118     DatastoreContextIntrospectorFactory introspectorFactory = null;
119     @Reference
120     DatastoreSnapshotRestore snapshotRestore = null;
121     @Reference
122     ModuleShardConfigProvider configProvider = null;
123     @Reference(target = "(component.factory=" + OSGiDOMStore.FACTORY_NAME + ")")
124     ComponentFactory datastoreFactory = null;
125
126     private DatastoreState configDatastore;
127     private DatastoreState operDatastore;
128
129     @Activate
130     void activate(final Map<String, Object> properties) {
131         configDatastore = createDatastore(LogicalDatastoreType.CONFIGURATION, "distributed-config", null);
132         operDatastore = createDatastore(LogicalDatastoreType.OPERATIONAL, "distributed-operational",
133             new ConfigurationImpl(configProvider));
134         modified(properties);
135     }
136
137     @Modified
138     void modified(final Map<String, Object> properties) {
139         LOG.debug("Overlaying settings: {}", properties);
140         configDatastore.updateProperties(properties);
141         operDatastore.updateProperties(properties);
142     }
143
144     @Deactivate
145     void deactivate() {
146         operDatastore.stop();
147         operDatastore = null;
148         configDatastore.stop();
149         configDatastore = null;
150     }
151
152     private DatastoreState createDatastore(final LogicalDatastoreType datastoreType, final String serviceType,
153             final Configuration config) {
154         LOG.info("Distributed Datastore type {} starting", datastoreType);
155         final DatastoreContextIntrospector introspector = introspectorFactory.newInstance(datastoreType);
156         final AbstractDataStore datastore = DistributedDataStoreFactory.createInstance(actorSystemProvider,
157             introspector.getContext(), introspector, snapshotRestore, config);
158         datastore.setCloseable(schemaService.registerSchemaContextListener(datastore));
159         final DatastoreState state = new DatastoreState(introspector, datastoreType, datastore, serviceType);
160
161         Futures.addCallback(datastore.initialSettleFuture(), state,
162             // Note we are invoked from shard manager and therefore could block it, hence the round-trip to executor
163             datastore.getActorUtils().getClientDispatcher()::execute);
164         return state;
165     }
166 }