Remove mdsal-singleton-dom-api
[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.ClusterSingletonServiceRegistration;
30 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
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 = new ConcurrentHashMap<>();
63
64     /* EOS Entity Listeners Registration */
65     private R serviceEntityListenerReg;
66     private R asyncCloseEntityListenerReg;
67
68     /**
69      * Class constructor
70      *
71      * @param entityOwnershipService relevant EOS
72      */
73     protected AbstractClusterSingletonServiceProviderImpl(@Nonnull final S entityOwnershipService) {
74         this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService);
75     }
76
77     /**
78      * This method must be called once on startup to initialize this provider.
79      */
80     public final void initializeProvider() {
81         LOG.debug("Initialization method for ClusterSingletonService Provider {}", this.getClass().getName());
82         this.serviceEntityListenerReg = registerListener(SERVICE_ENTITY_TYPE, entityOwnershipService);
83         this.asyncCloseEntityListenerReg = registerListener(CLOSE_SERVICE_ENTITY_TYPE, entityOwnershipService);
84     }
85
86     @Override
87     public final ClusterSingletonServiceRegistration registerClusterSingletonService(
88             @CheckForNull final ClusterSingletonService service) {
89         LOG.debug("Call registrationService {} method for ClusterSingletonService Provider {}", service,
90                 this.getClass().getName());
91
92         Preconditions.checkArgument(service != null);
93         Preconditions.checkArgument(!Strings.isNullOrEmpty(service.getIdentifier().getValue()),
94                 "ClusterSingletonService idetnifier can not be null. {}", service);
95
96         final String serviceIdentifier = service.getIdentifier().getValue();
97         ClusterSingletonServiceGroup<P, E, C> serviceGroup = serviceGroupMap.get(serviceIdentifier);
98         if (serviceGroup == null) {
99             final E mainEntity = createEntity(SERVICE_ENTITY_TYPE, serviceIdentifier);
100             final E closeEntity = createEntity(CLOSE_SERVICE_ENTITY_TYPE, serviceIdentifier);
101             serviceGroup = new ClusterSingletonServiceGroupImpl<>(serviceIdentifier,
102                     mainEntity, closeEntity, entityOwnershipService, serviceGroupMap);
103             serviceGroupMap.put(service.getIdentifier().getValue(), serviceGroup);
104             serviceGroup.initializationClusterSingletonGroup();
105         }
106         return serviceGroup.registerService(service);
107     }
108
109     @Override
110     public final void close() {
111         LOG.debug("Close method for ClusterSingletonService Provider {}", this.getClass().getName());
112
113         if (serviceEntityListenerReg != null) {
114             serviceEntityListenerReg.close();
115             serviceEntityListenerReg = null;
116         }
117
118         final List<ListenableFuture<List<Void>>> listGroupCloseListFuture = new ArrayList<>();
119
120         for (final ClusterSingletonServiceGroup<P, E, C> serviceGroup : serviceGroupMap.values()) {
121             listGroupCloseListFuture.add(serviceGroup.closeClusterSingletonGroup());
122         }
123
124         final ListenableFuture<List<List<Void>>> finalCloseFuture = Futures.allAsList(listGroupCloseListFuture);
125         Futures.addCallback(finalCloseFuture, new FutureCallback<List<List<Void>>>() {
126
127             @Override
128             public void onSuccess(final List<List<Void>> result) {
129                 cleaningProvider(null);
130             }
131
132             @Override
133             public void onFailure(final Throwable t) {
134                 cleaningProvider(t);
135             }
136         });
137     }
138
139     @Override
140     public final void ownershipChanged(final C ownershipChange) {
141         LOG.debug("Ownership change for ClusterSingletonService Provider {}", ownershipChange);
142         final String serviceIdentifier = getServiceIdentifierFromEntity(ownershipChange.getEntity());
143         final ClusterSingletonServiceGroup<P, E, C> serviceHolder = serviceGroupMap.get(serviceIdentifier);
144         if (serviceHolder != null) {
145             serviceHolder.ownershipChanged(ownershipChange);
146         } else {
147             LOG.debug("ClusterSingletonServiceGroup was not found for serviceIdentifier {}", serviceIdentifier);
148         }
149     }
150
151     /**
152      * Method implementation registers a defined {@link GenericEntityOwnershipListenerRegistration} type
153      * EntityOwnershipListenerRegistration.
154      *
155      * @param entityType the type of the entity
156      * @param entityOwnershipServiceInst - EOS type
157      * @return instance of EntityOwnershipListenerRegistration
158      */
159     protected abstract R registerListener(final String entityType, final S entityOwnershipServiceInst);
160
161     /**
162      * Creates an extended {@link GenericEntity} instance.
163      *
164      * @param entityType the type of the entity
165      * @param entityIdentifier the identifier of the entity
166      * @return instance of Entity extended GenericEntity type
167      */
168     protected abstract E createEntity(final String entityType, final String entityIdentifier);
169
170     /**
171      * Method is responsible for parsing ServiceGroupIdentifier from E entity.
172      *
173      * @param entity
174      * @return ServiceGroupIdentifier parsed from entity key value.
175      */
176     protected abstract String getServiceIdentifierFromEntity(final E entity);
177
178     /**
179      * Method is called async. from close method in end of Provider lifecycle.
180      *
181      * @param t Throwable (needs for log)
182      */
183     protected final void cleaningProvider(@Nullable final Throwable t) {
184         LOG.debug("Final cleaning ClusterSingletonServiceProvider {}", this.getClass().getName());
185         if (t != null) {
186             LOG.warn("Unexpected problem by closing ClusterSingletonServiceProvider {}", this.getClass().getName(), t);
187         }
188         if (asyncCloseEntityListenerReg != null) {
189             asyncCloseEntityListenerReg.close();
190             asyncCloseEntityListenerReg = null;
191         }
192         serviceGroupMap.clear();
193     }
194 }