2955f6c941ec4f52c91cc0f20157ded7f2bec445
[mdsal.git] / singleton-service / mdsal-singleton-dom-impl / src / main / java / org / opendaylight / mdsal / singleton / dom / impl / AbstractClusterSingletonServiceProviderImpl.java
1 /*
2  * Copyright (c) 2016 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.mdsal.singleton.dom.impl;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Strings;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.ConcurrentMap;
20 import javax.annotation.CheckForNull;
21 import javax.annotation.Nonnull;
22 import javax.annotation.Nullable;
23 import org.opendaylight.mdsal.eos.common.api.GenericEntity;
24 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipChange;
25 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipListener;
26 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipListenerRegistration;
27 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipService;
28 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
29 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
30 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
31 import org.opendaylight.yangtools.concepts.Path;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * Abstract class {@link AbstractClusterSingletonServiceProviderImpl} represents implementations of
37  * {@link ClusterSingletonServiceProvider} and it implements {@link GenericEntityOwnershipListener}
38  * for providing OwnershipChange for all registered {@link ClusterSingletonServiceGroup} entity
39  * candidate.
40  *
41  * @param <P> the instance identifier path type
42  * @param <E> the GenericEntity type
43  * @param <C> the GenericEntityOwnershipChange type
44  * @param <G> the GenericEntityOwnershipListener type
45  * @param <S> the GenericEntityOwnershipService type
46  * @param <R> the GenericEntityOwnershipListenerRegistration type
47  */
48 public abstract class AbstractClusterSingletonServiceProviderImpl<P extends Path<P>, E extends GenericEntity<P>,
49         C extends GenericEntityOwnershipChange<P, E>,
50         G extends GenericEntityOwnershipListener<P, C>,
51         S extends GenericEntityOwnershipService<P, E, G>,
52         R extends GenericEntityOwnershipListenerRegistration<P, G>>
53         implements ClusterSingletonServiceProvider, GenericEntityOwnershipListener<P, C> {
54
55     private static final Logger LOG = LoggerFactory
56             .getLogger(AbstractClusterSingletonServiceProviderImpl.class.getName());
57
58     private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
59     private static final String CLOSE_SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.AsyncServiceCloseEntityType";
60
61     private final S entityOwnershipService;
62     private final ConcurrentMap<String, ClusterSingletonServiceGroup<P, E, C>> serviceGroupMap =
63             new ConcurrentHashMap<>();
64
65     /* EOS Entity Listeners Registration */
66     private R serviceEntityListenerReg;
67     private R asyncCloseEntityListenerReg;
68
69     /**
70      * Class constructor.
71      *
72      * @param entityOwnershipService relevant EOS
73      */
74     protected AbstractClusterSingletonServiceProviderImpl(@Nonnull final S entityOwnershipService) {
75         this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService);
76     }
77
78     /**
79      * This method must be called once on startup to initialize this provider.
80      */
81     public final void initializeProvider() {
82         LOG.debug("Initialization method for ClusterSingletonService Provider {}", this.getClass().getName());
83         this.serviceEntityListenerReg = registerListener(SERVICE_ENTITY_TYPE, entityOwnershipService);
84         this.asyncCloseEntityListenerReg = registerListener(CLOSE_SERVICE_ENTITY_TYPE, entityOwnershipService);
85     }
86
87     @Override
88     public final ClusterSingletonServiceRegistration registerClusterSingletonService(
89             @CheckForNull final ClusterSingletonService service) {
90         LOG.debug("Call registrationService {} method for ClusterSingletonService Provider {}", service,
91                 this.getClass().getName());
92
93         Preconditions.checkArgument(service != null);
94         Preconditions.checkArgument(!Strings.isNullOrEmpty(service.getIdentifier().getValue()),
95                 "ClusterSingletonService idetnifier can not be null. {}", service);
96
97         final String serviceIdentifier = service.getIdentifier().getValue();
98         ClusterSingletonServiceGroup<P, E, C> serviceGroup = serviceGroupMap.get(serviceIdentifier);
99         if (serviceGroup == null) {
100             final E mainEntity = createEntity(SERVICE_ENTITY_TYPE, serviceIdentifier);
101             final E closeEntity = createEntity(CLOSE_SERVICE_ENTITY_TYPE, serviceIdentifier);
102             serviceGroup = new ClusterSingletonServiceGroupImpl<>(serviceIdentifier,
103                     mainEntity, closeEntity, entityOwnershipService, serviceGroupMap);
104             serviceGroupMap.put(service.getIdentifier().getValue(), serviceGroup);
105             serviceGroup.initializationClusterSingletonGroup();
106         }
107         return serviceGroup.registerService(service);
108     }
109
110     @Override
111     public final void close() {
112         LOG.debug("Close method for ClusterSingletonService Provider {}", this.getClass().getName());
113
114         if (serviceEntityListenerReg != null) {
115             serviceEntityListenerReg.close();
116             serviceEntityListenerReg = null;
117         }
118
119         final List<ListenableFuture<List<Void>>> listGroupCloseListFuture = new ArrayList<>();
120
121         for (final ClusterSingletonServiceGroup<P, E, C> serviceGroup : serviceGroupMap.values()) {
122             listGroupCloseListFuture.add(serviceGroup.closeClusterSingletonGroup());
123         }
124
125         final ListenableFuture<List<List<Void>>> finalCloseFuture = Futures.allAsList(listGroupCloseListFuture);
126         Futures.addCallback(finalCloseFuture, new FutureCallback<List<List<Void>>>() {
127
128             @Override
129             public void onSuccess(final List<List<Void>> result) {
130                 cleaningProvider(null);
131             }
132
133             @Override
134             public void onFailure(final Throwable throwable) {
135                 cleaningProvider(throwable);
136             }
137         });
138     }
139
140     @Override
141     public final void ownershipChanged(final C ownershipChange) {
142         LOG.debug("Ownership change for ClusterSingletonService Provider {}", ownershipChange);
143         final String serviceIdentifier = getServiceIdentifierFromEntity(ownershipChange.getEntity());
144         final ClusterSingletonServiceGroup<P, E, C> serviceHolder = serviceGroupMap.get(serviceIdentifier);
145         if (serviceHolder != null) {
146             serviceHolder.ownershipChanged(ownershipChange);
147         } else {
148             LOG.debug("ClusterSingletonServiceGroup was not found for serviceIdentifier {}", serviceIdentifier);
149         }
150     }
151
152     /**
153      * Method implementation registers a defined {@link GenericEntityOwnershipListenerRegistration} type
154      * EntityOwnershipListenerRegistration.
155      *
156      * @param entityType the type of the entity
157      * @param entityOwnershipServiceInst - EOS type
158      * @return instance of EntityOwnershipListenerRegistration
159      */
160     protected abstract R registerListener(final String entityType, final S entityOwnershipServiceInst);
161
162     /**
163      * Creates an extended {@link GenericEntity} instance.
164      *
165      * @param entityType the type of the entity
166      * @param entityIdentifier the identifier of the entity
167      * @return instance of Entity extended GenericEntity type
168      */
169     protected abstract E createEntity(final String entityType, final String entityIdentifier);
170
171     /**
172      * Method is responsible for parsing ServiceGroupIdentifier from E entity.
173      *
174      * @param entity instance of GenericEntity type
175      * @return ServiceGroupIdentifier parsed from entity key value.
176      */
177     protected abstract String getServiceIdentifierFromEntity(final E entity);
178
179     /**
180      * Method is called async. from close method in end of Provider lifecycle.
181      *
182      * @param throwable Throwable (needs for log)
183      */
184     protected final void cleaningProvider(@Nullable final Throwable throwable) {
185         LOG.debug("Final cleaning ClusterSingletonServiceProvider {}", this.getClass().getName());
186         if (throwable != null) {
187             LOG.warn("Unexpected problem by closing ClusterSingletonServiceProvider {}",
188                     this.getClass().getName(), throwable);
189         }
190         if (asyncCloseEntityListenerReg != null) {
191             asyncCloseEntityListenerReg.close();
192             asyncCloseEntityListenerReg = null;
193         }
194         serviceGroupMap.clear();
195     }
196 }