/* * Copyright 2014 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jbpm.kie.services.impl.store; import java.sql.SQLIntegrityConstraintViolationException; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.jbpm.services.api.DeploymentEvent; import org.jbpm.services.api.DeploymentEventListener; import org.jbpm.services.api.DeploymentService; import org.jbpm.services.api.ListenerSupport; import org.jbpm.services.api.model.DeployedUnit; import org.jbpm.services.api.model.DeploymentUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DeploymentSynchronizer implements DeploymentEventListener { private static final Logger logger = LoggerFactory.getLogger(DeploymentSynchronizer.class); public static final String DEPLOY_SYNC_INTERVAL = System.getProperty("org.jbpm.deploy.sync.int", "3"); public static final boolean DEPLOY_SYNC_ENABLED = Boolean.parseBoolean(System.getProperty("org.jbpm.deploy.sync.enabled", "true")); private final Map<String, DeploymentUnit> entries = new ConcurrentHashMap<String, DeploymentUnit>(); private DeploymentStore deploymentStore; private DeploymentService deploymentService; private Date lastSync = null; protected Class<?> targetExceptionClass; public DeploymentSynchronizer() { String clazz = System.getProperty("org.kie.constviol.exclass", "org.hibernate.exception.ConstraintViolationException"); try { targetExceptionClass = Class.forName(clazz); } catch (ClassNotFoundException e) { logger.error("Optimistic locking exception class not found {}", clazz, e); } } public boolean isActive() { return true; } public void setDeploymentStore(DeploymentStore deploymentStore) { this.deploymentStore = deploymentStore; } public void setDeploymentService(DeploymentService deploymentService) { this.deploymentService = deploymentService; ((ListenerSupport)this.deploymentService).addListener(this); } public synchronized void synchronize() { try { Collection<DeploymentUnit> enabledSet = new HashSet<DeploymentUnit>(); Collection<DeploymentUnit> disabledSet = new HashSet<DeploymentUnit>(); Collection<DeploymentUnit> activatedSet = new HashSet<DeploymentUnit>(); Collection<DeploymentUnit> deactivatedSet = new HashSet<DeploymentUnit>(); Date timeOfSync = new Date(); if (lastSync == null) { // initial load enabledSet = deploymentStore.getEnabledDeploymentUnits(); deactivatedSet = deploymentStore.getDeactivatedDeploymentUnits(); } else { deploymentStore.getDeploymentUnitsByDate(lastSync, enabledSet, disabledSet, activatedSet, deactivatedSet); } // update last sync date with time taken just before the query time this.lastSync = timeOfSync; logger.debug("About to synchronize deployment units, found new enabled {}, found new disabled {}", enabledSet, disabledSet); if (enabledSet != null) { for (DeploymentUnit unit : enabledSet) { if (!entries.containsKey(unit.getIdentifier()) && deploymentService.getDeployedUnit(unit.getIdentifier()) == null) { try { logger.debug("New deployment unit to be deployed {}", unit); entries.put(unit.getIdentifier(), unit); deploymentService.deploy(unit); } catch (Exception e) { entries.remove(unit.getIdentifier()); logger.warn("Deployment unit {} failed to deploy: {}", unit.getIdentifier(), e.getMessage()); } } } } if (disabledSet != null) { for (DeploymentUnit unit : disabledSet) { if (entries.containsKey(unit.getIdentifier()) && deploymentService.getDeployedUnit(unit.getIdentifier()) != null) { try { logger.debug("Existing deployment unit {} to be undeployed", unit.getIdentifier()); entries.remove(unit.getIdentifier()); deploymentService.undeploy(unit); } catch (Exception e) { logger.warn("Deployment unit {} failed to undeploy: {}", unit.getIdentifier(), e.getMessage(), e); entries.put(unit.getIdentifier(), unit); deploymentStore.markDeploymentUnitAsObsolete(unit); } } } } logger.debug("About to synchronize deployment units, found new activated {}, found new deactivated {}", activatedSet, deactivatedSet); if (activatedSet != null) { for (DeploymentUnit unit : activatedSet) { DeployedUnit deployed = deploymentService.getDeployedUnit(unit.getIdentifier()); if (deployed != null && !deployed.isActive()) { deploymentService.activate(unit.getIdentifier()); } } } if (deactivatedSet != null) { for (DeploymentUnit unit : deactivatedSet) { DeployedUnit deployed = deploymentService.getDeployedUnit(unit.getIdentifier()); if (deployed != null && deployed.isActive()) { deploymentService.deactivate(unit.getIdentifier()); } } } } catch (Throwable e) { logger.error("Error while synchronizing deployments: {}", e.getMessage(), e); } } @Override public void onDeploy(DeploymentEvent event) { if (event == null || event.getDeployedUnit() == null) { return; } DeploymentUnit unit = event.getDeployedUnit().getDeploymentUnit(); if (!entries.containsKey(unit.getIdentifier())) { try { deploymentStore.enableDeploymentUnit(unit); // when successfully stored add it to local store entries.put(unit.getIdentifier(), unit); logger.info("Deployment unit {} stored successfully", unit.getIdentifier()); } catch (Exception e) { if (isCausedByConstraintViolation(e)) { logger.info("Deployment {} already stored in deployment store", unit); } else { logger.error("Unable to store deployment {} in deployment store due to {}", unit, e.getMessage()); } } } } @Override public void onUnDeploy(DeploymentEvent event) { if (event != null && event.getDeployedUnit() != null) { DeploymentUnit unit = event.getDeployedUnit().getDeploymentUnit(); deploymentStore.disableDeploymentUnit(unit); entries.remove(unit.getIdentifier()); logger.info("Deployment unit {} removed successfully", unit.getIdentifier()); } } @Override public void onActivate(DeploymentEvent event) { if (event != null && event.getDeployedUnit() != null) { DeploymentUnit unit = event.getDeployedUnit().getDeploymentUnit(); deploymentStore.activateDeploymentUnit(unit); logger.info("Deployment unit {} activated successfully", unit.getIdentifier()); } } @Override public void onDeactivate(DeploymentEvent event) { if (event != null && event.getDeployedUnit() != null) { DeploymentUnit unit = event.getDeployedUnit().getDeploymentUnit(); deploymentStore.deactivateDeploymentUnit(unit); logger.info("Deployment unit {} deactivated successfully", unit.getIdentifier()); } } protected boolean isCausedByConstraintViolation(Throwable throwable) { if (targetExceptionClass == null) { return false; } while (throwable != null) { if (targetExceptionClass.isAssignableFrom(throwable.getClass()) || SQLIntegrityConstraintViolationException.class.isAssignableFrom(throwable.getClass())) { return true; } else { throwable = throwable.getCause(); } } return false; } }