/**
* Copyright (c) Codice Foundation
* <p>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package org.codice.ddf.registry.api.impl;
import java.security.PrivilegedActionException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.codice.ddf.registry.api.internal.RegistryStore;
import org.codice.ddf.registry.federationadmin.service.internal.FederationAdminService;
import org.codice.ddf.security.common.Security;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceReference;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ddf.catalog.data.Metacard;
/**
* This handler cleans up registry entries in the local catalog when a remote registry connection
* is removed.
*/
public class RegistryStoreCleanupHandler implements EventHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(RegistryStoreCleanupHandler.class);
private FederationAdminService federationAdminService;
private ExecutorService executor;
private static final int SHUTDOWN_TIMEOUT_SECONDS = 60;
private boolean cleanupRelatedMetacards = true;
private Map<Object, RegistryStore> registryStorePidToServiceMap = new ConcurrentHashMap<>();
public void bindRegistryStore(ServiceReference serviceReference) {
BundleContext bundleContext = getBundleContext();
if (serviceReference != null && bundleContext != null) {
RegistryStore registryStore =
(RegistryStore) bundleContext.getService(serviceReference);
registryStorePidToServiceMap.put(serviceReference.getProperty(Constants.SERVICE_PID),
registryStore);
}
}
@Override
public void handleEvent(Event event) {
Object eventProperty = event.getProperty(EventConstants.EVENT);
if (!cleanupRelatedMetacards || eventProperty == null
|| !(eventProperty instanceof ServiceEvent)) {
return;
}
if (((ServiceEvent) eventProperty).getType() != ServiceEvent.UNREGISTERING) {
return;
}
Object servicePid =
((ServiceEvent) event.getProperty(EventConstants.EVENT)).getServiceReference()
.getProperty(Constants.SERVICE_PID);
if (servicePid == null) {
return;
}
RegistryStore service = registryStorePidToServiceMap.get(servicePid);
if (service == null) {
return;
}
registryStorePidToServiceMap.remove(servicePid);
executor.execute(() -> {
String registryId = service.getRegistryId();
try {
Security security = Security.getInstance();
List<Metacard> metacards =
security.runAsAdminWithException(() -> federationAdminService.getInternalRegistryMetacardsByRegistryId(
registryId));
List<String> idsToDelete = metacards.stream()
.map(Metacard::getId)
.collect(Collectors.toList());
if (!idsToDelete.isEmpty()) {
security.runAsAdminWithException(() -> {
federationAdminService.deleteRegistryEntriesByMetacardIds(idsToDelete);
return null;
});
}
} catch (PrivilegedActionException e) {
LOGGER.info(
"Unable to clean up registry metacards after registry store {} was deleted",
service.getId(),
e);
}
});
}
public void destroy() {
executor.shutdown();
try {
if (!executor.awaitTermination(SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
executor.shutdownNow();
if (!executor.awaitTermination(SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
LOGGER.debug("Thread pool failed to terminate");
}
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
BundleContext getBundleContext() {
Bundle bundle = FrameworkUtil.getBundle(this.getClass());
if (bundle != null) {
return bundle.getBundleContext();
}
return null;
}
public void setCleanupRelatedMetacards(boolean cleanupRelatedMetacards) {
this.cleanupRelatedMetacards = cleanupRelatedMetacards;
}
public void setFederationAdminService(FederationAdminService federationAdminService) {
this.federationAdminService = federationAdminService;
}
public void setExecutor(ExecutorService executor) {
this.executor = executor;
}
}