/* * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.mdsal.singleton.dom.impl; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.opendaylight.mdsal.eos.common.api.GenericEntity; import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipChange; import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipListener; import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipListenerRegistration; import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipService; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration; import org.opendaylight.yangtools.concepts.Path; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Abstract class {@link AbstractClusterSingletonServiceProviderImpl} represents implementations of * {@link ClusterSingletonServiceProvider} and it implements {@link GenericEntityOwnershipListener} * for providing OwnershipChange for all registered {@link ClusterSingletonServiceGroup} entity * candidate. * * @param

the instance identifier path type * @param the GenericEntity type * @param the GenericEntityOwnershipChange type * @param the GenericEntityOwnershipListener type * @param the GenericEntityOwnershipService type * @param the GenericEntityOwnershipListenerRegistration type */ public abstract class AbstractClusterSingletonServiceProviderImpl

, E extends GenericEntity

, C extends GenericEntityOwnershipChange, G extends GenericEntityOwnershipListener, S extends GenericEntityOwnershipService, R extends GenericEntityOwnershipListenerRegistration> implements ClusterSingletonServiceProvider, GenericEntityOwnershipListener { private static final Logger LOG = LoggerFactory .getLogger(AbstractClusterSingletonServiceProviderImpl.class.getName()); private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType"; private static final String CLOSE_SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.AsyncServiceCloseEntityType"; private final S entityOwnershipService; private final ConcurrentMap> serviceGroupMap = new ConcurrentHashMap<>(); /* EOS Entity Listeners Registration */ private R serviceEntityListenerReg; private R asyncCloseEntityListenerReg; /** * Class constructor. * * @param entityOwnershipService relevant EOS */ protected AbstractClusterSingletonServiceProviderImpl(@Nonnull final S entityOwnershipService) { this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService); } /** * This method must be called once on startup to initialize this provider. */ public final void initializeProvider() { LOG.debug("Initialization method for ClusterSingletonService Provider {}", this.getClass().getName()); this.serviceEntityListenerReg = registerListener(SERVICE_ENTITY_TYPE, entityOwnershipService); this.asyncCloseEntityListenerReg = registerListener(CLOSE_SERVICE_ENTITY_TYPE, entityOwnershipService); } @Override public final ClusterSingletonServiceRegistration registerClusterSingletonService( @CheckForNull final ClusterSingletonService service) { LOG.debug("Call registrationService {} method for ClusterSingletonService Provider {}", service, this.getClass().getName()); Preconditions.checkArgument(service != null); Preconditions.checkArgument(!Strings.isNullOrEmpty(service.getIdentifier().getValue()), "ClusterSingletonService idetnifier can not be null. {}", service); final String serviceIdentifier = service.getIdentifier().getValue(); ClusterSingletonServiceGroup serviceGroup = serviceGroupMap.get(serviceIdentifier); if (serviceGroup == null) { final E mainEntity = createEntity(SERVICE_ENTITY_TYPE, serviceIdentifier); final E closeEntity = createEntity(CLOSE_SERVICE_ENTITY_TYPE, serviceIdentifier); serviceGroup = new ClusterSingletonServiceGroupImpl<>(serviceIdentifier, mainEntity, closeEntity, entityOwnershipService, serviceGroupMap); serviceGroupMap.put(service.getIdentifier().getValue(), serviceGroup); serviceGroup.initializationClusterSingletonGroup(); } return serviceGroup.registerService(service); } @Override public final void close() { LOG.debug("Close method for ClusterSingletonService Provider {}", this.getClass().getName()); if (serviceEntityListenerReg != null) { serviceEntityListenerReg.close(); serviceEntityListenerReg = null; } final List>> listGroupCloseListFuture = new ArrayList<>(); for (final ClusterSingletonServiceGroup serviceGroup : serviceGroupMap.values()) { listGroupCloseListFuture.add(serviceGroup.closeClusterSingletonGroup()); } final ListenableFuture>> finalCloseFuture = Futures.allAsList(listGroupCloseListFuture); Futures.addCallback(finalCloseFuture, new FutureCallback>>() { @Override public void onSuccess(final List> result) { cleaningProvider(null); } @Override public void onFailure(final Throwable throwable) { cleaningProvider(throwable); } }); } @Override public final void ownershipChanged(final C ownershipChange) { LOG.debug("Ownership change for ClusterSingletonService Provider {}", ownershipChange); final String serviceIdentifier = getServiceIdentifierFromEntity(ownershipChange.getEntity()); final ClusterSingletonServiceGroup serviceHolder = serviceGroupMap.get(serviceIdentifier); if (serviceHolder != null) { serviceHolder.ownershipChanged(ownershipChange); } else { LOG.debug("ClusterSingletonServiceGroup was not found for serviceIdentifier {}", serviceIdentifier); } } /** * Method implementation registers a defined {@link GenericEntityOwnershipListenerRegistration} type * EntityOwnershipListenerRegistration. * * @param entityType the type of the entity * @param entityOwnershipServiceInst - EOS type * @return instance of EntityOwnershipListenerRegistration */ protected abstract R registerListener(final String entityType, final S entityOwnershipServiceInst); /** * Creates an extended {@link GenericEntity} instance. * * @param entityType the type of the entity * @param entityIdentifier the identifier of the entity * @return instance of Entity extended GenericEntity type */ protected abstract E createEntity(final String entityType, final String entityIdentifier); /** * Method is responsible for parsing ServiceGroupIdentifier from E entity. * * @param entity instance of GenericEntity type * @return ServiceGroupIdentifier parsed from entity key value. */ protected abstract String getServiceIdentifierFromEntity(final E entity); /** * Method is called async. from close method in end of Provider lifecycle. * * @param throwable Throwable (needs for log) */ protected final void cleaningProvider(@Nullable final Throwable throwable) { LOG.debug("Final cleaning ClusterSingletonServiceProvider {}", this.getClass().getName()); if (throwable != null) { LOG.warn("Unexpected problem by closing ClusterSingletonServiceProvider {}", this.getClass().getName(), throwable); } if (asyncCloseEntityListenerReg != null) { asyncCloseEntityListenerReg.close(); asyncCloseEntityListenerReg = null; } serviceGroupMap.clear(); } }