2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.mdsal.singleton.dom.impl;
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;
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
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
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> {
55 private static final Logger LOG = LoggerFactory
56 .getLogger(AbstractClusterSingletonServiceProviderImpl.class.getName());
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";
61 private final S entityOwnershipService;
62 private final ConcurrentMap<String, ClusterSingletonServiceGroup<P, E, C>> serviceGroupMap =
63 new ConcurrentHashMap<>();
65 /* EOS Entity Listeners Registration */
66 private R serviceEntityListenerReg;
67 private R asyncCloseEntityListenerReg;
72 * @param entityOwnershipService relevant EOS
74 protected AbstractClusterSingletonServiceProviderImpl(@Nonnull final S entityOwnershipService) {
75 this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService);
79 * This method must be called once on startup to initialize this provider.
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);
88 public final ClusterSingletonServiceRegistration registerClusterSingletonService(
89 @CheckForNull final ClusterSingletonService service) {
90 LOG.debug("Call registrationService {} method for ClusterSingletonService Provider {}", service,
91 this.getClass().getName());
93 Preconditions.checkArgument(service != null);
94 Preconditions.checkArgument(!Strings.isNullOrEmpty(service.getIdentifier().getValue()),
95 "ClusterSingletonService idetnifier can not be null. {}", service);
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();
107 return serviceGroup.registerService(service);
111 public final void close() {
112 LOG.debug("Close method for ClusterSingletonService Provider {}", this.getClass().getName());
114 if (serviceEntityListenerReg != null) {
115 serviceEntityListenerReg.close();
116 serviceEntityListenerReg = null;
119 final List<ListenableFuture<List<Void>>> listGroupCloseListFuture = new ArrayList<>();
121 for (final ClusterSingletonServiceGroup<P, E, C> serviceGroup : serviceGroupMap.values()) {
122 listGroupCloseListFuture.add(serviceGroup.closeClusterSingletonGroup());
125 final ListenableFuture<List<List<Void>>> finalCloseFuture = Futures.allAsList(listGroupCloseListFuture);
126 Futures.addCallback(finalCloseFuture, new FutureCallback<List<List<Void>>>() {
129 public void onSuccess(final List<List<Void>> result) {
130 cleaningProvider(null);
134 public void onFailure(final Throwable throwable) {
135 cleaningProvider(throwable);
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);
148 LOG.debug("ClusterSingletonServiceGroup was not found for serviceIdentifier {}", serviceIdentifier);
153 * Method implementation registers a defined {@link GenericEntityOwnershipListenerRegistration} type
154 * EntityOwnershipListenerRegistration.
156 * @param entityType the type of the entity
157 * @param entityOwnershipServiceInst - EOS type
158 * @return instance of EntityOwnershipListenerRegistration
160 protected abstract R registerListener(final String entityType, final S entityOwnershipServiceInst);
163 * Creates an extended {@link GenericEntity} instance.
165 * @param entityType the type of the entity
166 * @param entityIdentifier the identifier of the entity
167 * @return instance of Entity extended GenericEntity type
169 protected abstract E createEntity(final String entityType, final String entityIdentifier);
172 * Method is responsible for parsing ServiceGroupIdentifier from E entity.
174 * @param entity instance of GenericEntity type
175 * @return ServiceGroupIdentifier parsed from entity key value.
177 protected abstract String getServiceIdentifierFromEntity(final E entity);
180 * Method is called async. from close method in end of Provider lifecycle.
182 * @param throwable Throwable (needs for log)
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);
190 if (asyncCloseEntityListenerReg != null) {
191 asyncCloseEntityListenerReg.close();
192 asyncCloseEntityListenerReg = null;
194 serviceGroupMap.clear();