Commit bff3d67f authored by Aurelien Pupier's avatar Aurelien Pupier
Browse files

Merge pull request #295 from bonitasoft/fix/BS-14269_undeploy_processes_in_preview

BS-14269 Undeploy archived process instances before Preview
parents 425759a7 7e078c6e
/**
* Copyright (C) 2015 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.engine.operation;
import static org.bonitasoft.studio.model.process.builders.PoolBuilder.aPool;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.notNull;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.bonitasoft.engine.api.ProcessAPI;
import org.bonitasoft.engine.session.APISession;
import org.bonitasoft.studio.engine.BOSEngineManager;
import org.bonitasoft.studio.model.process.AbstractProcess;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class UndeployProcessOperationTest {
@Mock
private ProcessAPI processAPI;
@Test
public void should_disable_process_definition_before_deleting_instances_and_definition() throws Exception {
final UndeployProcessOperation operation = createFixture();
when(processAPI.getProcessDefinitionId("TestProcess", "1.0")).thenReturn(1L);
operation.undeployProcess(aPool().withName("TestProcess").withVersion("1.0").build(), new NullProgressMonitor());
final InOrder inOrder = inOrder(processAPI);
inOrder.verify(processAPI).disableProcess(1L);
inOrder.verify(processAPI).deleteProcessInstances(1L, 0, 1000);
inOrder.verify(processAPI).deleteArchivedProcessInstances(1L, 0, 1000);
inOrder.verify(processAPI).deleteProcessDefinition(1L);
}
private UndeployProcessOperation createFixture() throws Exception {
final BOSEngineManager engineManager = mock(BOSEngineManager.class);
when(engineManager.createSession(notNull(AbstractProcess.class), anyString(), any(IProgressMonitor.class))).thenReturn(mock(APISession.class));
when(engineManager.getProcessAPI(notNull(APISession.class))).thenReturn(processAPI);
when(processAPI.getNumberOfProcessDeploymentInfos()).thenReturn(1L);
return new UndeployProcessOperation(engineManager);
}
}
/**
* Copyright (C) 2009-2011 BonitaSoft S.A.
* BonitaSoft, 31 rue Gustave Eiffel - 38000 Grenoble
* Copyright (C) 2009-2015 BonitaSoft S.A.
* BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
......@@ -22,6 +22,7 @@ import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
......@@ -32,13 +33,10 @@ import java.util.Set;
import org.bonitasoft.engine.api.ProcessAPI;
import org.bonitasoft.engine.bpm.bar.BusinessArchive;
import org.bonitasoft.engine.bpm.process.Problem;
import org.bonitasoft.engine.bpm.process.ProcessActivationException;
import org.bonitasoft.engine.bpm.process.ProcessDefinition;
import org.bonitasoft.engine.bpm.process.ProcessDefinitionNotFoundException;
import org.bonitasoft.engine.bpm.process.ProcessDeployException;
import org.bonitasoft.engine.bpm.process.ProcessEnablementException;
import org.bonitasoft.engine.exception.DeletionException;
import org.bonitasoft.engine.exception.ProcessInstanceHierarchicalDeletionException;
import org.bonitasoft.engine.session.APISession;
import org.bonitasoft.studio.common.emf.tools.ExpressionHelper;
import org.bonitasoft.studio.common.emf.tools.ModelHelper;
......@@ -70,8 +68,6 @@ import com.google.common.base.Predicate;
*/
public class DeployProcessOperation {
private static final int MAX_RESULTS = 1000;
private Set<EObject> excludedObject = new HashSet<EObject>();
private String configurationId;
......@@ -110,14 +106,18 @@ public class DeployProcessOperation {
public IStatus run(final IProgressMonitor monitor) {
Assert.isTrue(!processes.isEmpty());
IStatus status = null;
try {
undeploy(monitor);
status = undeploy(processes, monitor);
} catch (final Exception e) {
BonitaStudioLog.error(e, EnginePlugin.PLUGIN_ID);
return new Status(Status.ERROR, EnginePlugin.PLUGIN_ID, Messages.undeploymentFailedMessage, e);
}
if (!status.isOK()) {
return status;
}
try {
IStatus status = deploy(monitor);
status = deploy(monitor);
if (status.getSeverity() == IStatus.OK) {
status = enable(monitor);
}
......@@ -262,7 +262,7 @@ public class DeployProcessOperation {
}
IStatus status = openProcessEnablementProblemsDialog(process, processResolutionProblems);
if (status.isOK()) {
undeployProcess(process, monitor);
undeploy(Collections.singletonList(process), monitor);
status = deployProcess(process, monitor);
if (status.getSeverity() != IStatus.OK) {
return status;
......@@ -273,83 +273,12 @@ public class DeployProcessOperation {
}
}
/**
* @param monitor
* @throws DeletingEnabledProcessException
* @throws Exception
*/
protected void undeploy(final IProgressMonitor monitor) throws Exception {
protected IStatus undeploy(final List<AbstractProcess> processes, final IProgressMonitor monitor) throws Exception {
final UndeployProcessOperation undeployProcessOperation = new UndeployProcessOperation(BOSEngineManager.getInstance());
for (final AbstractProcess process : processes) {
undeployProcess(process, monitor);
}
}
protected void undeployProcess(final AbstractProcess process, final IProgressMonitor monitor) throws Exception {
final APISession session = BOSEngineManager.getInstance().createSession(process, configurationId, monitor);
try {
final ProcessAPI processApi = BOSEngineManager.getInstance().getProcessAPI(session);
final long nbDeployedProcesses = processApi.getNumberOfProcessDeploymentInfos();
if (nbDeployedProcesses > 0) {
final long processDefinitionId = processApi.getProcessDefinitionId(process.getName(), process.getVersion());
disableProcessDefinition(process, processApi, processDefinitionId, monitor);
deleteProcessInstances(process, processApi, processDefinitionId, monitor);
deleteArchivedProcessInstances(processApi, processDefinitionId);
deleteProcessDefinition(process, processApi, processDefinitionId, monitor);
}
} catch (final ProcessDefinitionNotFoundException e) {
// Skip
} finally {
if (session != null) {
BOSEngineManager.getInstance().logoutDefaultTenant(session);
}
}
}
private void deleteProcessDefinition(final AbstractProcess process, final ProcessAPI processApi, final long processDefinitionId,
final IProgressMonitor monitor)
throws DeletionException {
monitor.subTask(Messages.bind(Messages.deletingProcessDefinition, getProcessLabel(process)));
processApi.deleteProcessDefinition(processDefinitionId);
}
private void deleteArchivedProcessInstances(final ProcessAPI processApi, final long processDefinitionId) throws DeletionException {
boolean allInstancesDeleted = false;
while (!allInstancesDeleted) {
final long nbDeletedProcessInstances = processApi.deleteArchivedProcessInstances(processDefinitionId, 0, MAX_RESULTS);
allInstancesDeleted = nbDeletedProcessInstances < MAX_RESULTS;
}
}
private void deleteProcessInstances(final AbstractProcess process, final ProcessAPI processApi, final long processDefinitionId,
final IProgressMonitor monitor)
throws DeletionException {
boolean allInstancesDeleted = false;
monitor.subTask(Messages.bind(Messages.deletingProcessInstances, getProcessLabel(process)));
while (!allInstancesDeleted) {
try {
final long nbDeletedProcessInstances = processApi.deleteProcessInstances(processDefinitionId, 0, MAX_RESULTS);
allInstancesDeleted = nbDeletedProcessInstances < MAX_RESULTS;
} catch (final DeletionException e) {
if (e instanceof ProcessInstanceHierarchicalDeletionException) {
final long blockingProcessId = ((ProcessInstanceHierarchicalDeletionException) e).getProcessInstanceId();
processApi.deleteProcessInstance(blockingProcessId);
} else {
throw e;
}
}
}
}
private void disableProcessDefinition(final AbstractProcess process, final ProcessAPI processApi, final long processDefinitionId,
final IProgressMonitor monitor)
throws ProcessDefinitionNotFoundException {
monitor.subTask(Messages.bind(Messages.undeploying, getProcessLabel(process)));
try {
monitor.subTask(Messages.bind(Messages.disablingProcessDefinition, getProcessLabel(process)));
processApi.disableProcess(processDefinitionId);
} catch (final ProcessActivationException e) {
BonitaStudioLog.debug("Failed to disable the process", e, EnginePlugin.PLUGIN_ID);
undeployProcessOperation.addProcessToUndeploy(process);
}
return undeployProcessOperation.run(monitor);
}
private String getProcessLabel(final AbstractProcess process) {
......
/**
* Copyright (C) 2015 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.engine.operation;
import java.util.ArrayList;
import java.util.List;
import org.bonitasoft.engine.api.ProcessAPI;
import org.bonitasoft.engine.bpm.process.ProcessActivationException;
import org.bonitasoft.engine.bpm.process.ProcessDefinitionNotFoundException;
import org.bonitasoft.engine.exception.DeletionException;
import org.bonitasoft.engine.exception.ProcessInstanceHierarchicalDeletionException;
import org.bonitasoft.engine.session.APISession;
import org.bonitasoft.studio.common.log.BonitaStudioLog;
import org.bonitasoft.studio.engine.BOSEngineManager;
import org.bonitasoft.studio.engine.EnginePlugin;
import org.bonitasoft.studio.engine.i18n.Messages;
import org.bonitasoft.studio.model.process.AbstractProcess;
import org.bonitasoft.studio.model.process.MainProcess;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
/**
* @author Romain Bioteau
* @author Aurelien Pupier
*/
public class UndeployProcessOperation {
private static final int MAX_RESULTS = 1000;
private String configurationId;
private final List<AbstractProcess> processes = new ArrayList<AbstractProcess>();
private final BOSEngineManager engineManager;
public UndeployProcessOperation(final BOSEngineManager engineManager) {
this.engineManager = engineManager;
}
public void addProcessToUndeploy(final AbstractProcess process) {
Assert.isTrue(!(process instanceof MainProcess), "process can't be a MainProcess");
if (!processes.contains(process)) {
processes.add(process);
}
}
public void setConfigurationId(final String configurationId) {
this.configurationId = configurationId;
}
public IStatus run(final IProgressMonitor monitor) {
Assert.isTrue(!processes.isEmpty());
try {
return undeploy(monitor);
} catch (final Exception e) {
BonitaStudioLog.error(e, EnginePlugin.PLUGIN_ID);
return new Status(Status.ERROR, EnginePlugin.PLUGIN_ID, Messages.undeploymentFailedMessage, e);
}
}
protected IStatus undeploy(final IProgressMonitor monitor) throws Exception {
for (final AbstractProcess process : processes) {
undeployProcess(process, monitor);
}
return Status.OK_STATUS;
}
protected void undeployProcess(final AbstractProcess process, final IProgressMonitor monitor) throws Exception {
final APISession session = engineManager.createSession(process, configurationId, monitor);
try {
final ProcessAPI processApi = engineManager.getProcessAPI(session);
final long nbDeployedProcesses = processApi.getNumberOfProcessDeploymentInfos();
if (nbDeployedProcesses > 0) {
final long processDefinitionId = processApi.getProcessDefinitionId(process.getName(), process.getVersion());
disableProcessDefinition(process, processApi, processDefinitionId, monitor);
deleteProcessInstances(process, processApi, processDefinitionId, monitor);
deleteArchivedProcessInstances(processApi, processDefinitionId);
deleteProcessDefinition(process, processApi, processDefinitionId, monitor);
}
} catch (final ProcessDefinitionNotFoundException e) {
// Skip
} finally {
if (session != null) {
BOSEngineManager.getInstance().logoutDefaultTenant(session);
}
}
}
private void deleteProcessDefinition(final AbstractProcess process, final ProcessAPI processApi, final long processDefinitionId,
final IProgressMonitor monitor)
throws DeletionException {
monitor.subTask(Messages.bind(Messages.deletingProcessDefinition, getProcessLabel(process)));
processApi.deleteProcessDefinition(processDefinitionId);
}
private void deleteArchivedProcessInstances(final ProcessAPI processApi, final long processDefinitionId) throws DeletionException {
boolean allInstancesDeleted = false;
while (!allInstancesDeleted) {
final long nbDeletedProcessInstances = processApi.deleteArchivedProcessInstances(processDefinitionId, 0, MAX_RESULTS);
allInstancesDeleted = nbDeletedProcessInstances < MAX_RESULTS;
}
}
private void deleteProcessInstances(final AbstractProcess process, final ProcessAPI processApi, final long processDefinitionId,
final IProgressMonitor monitor)
throws DeletionException {
boolean allInstancesDeleted = false;
monitor.subTask(Messages.bind(Messages.deletingProcessInstances, getProcessLabel(process)));
while (!allInstancesDeleted) {
try {
final long nbDeletedProcessInstances = processApi.deleteProcessInstances(processDefinitionId, 0, MAX_RESULTS);
allInstancesDeleted = nbDeletedProcessInstances < MAX_RESULTS;
} catch (final DeletionException e) {
if (e instanceof ProcessInstanceHierarchicalDeletionException) {
final long blockingProcessId = ((ProcessInstanceHierarchicalDeletionException) e).getProcessInstanceId();
processApi.deleteProcessInstance(blockingProcessId);
} else {
throw e;
}
}
}
}
private void disableProcessDefinition(final AbstractProcess process, final ProcessAPI processApi, final long processDefinitionId,
final IProgressMonitor monitor)
throws ProcessDefinitionNotFoundException {
monitor.subTask(Messages.bind(Messages.undeploying, getProcessLabel(process)));
try {
monitor.subTask(Messages.bind(Messages.disablingProcessDefinition, getProcessLabel(process)));
processApi.disableProcess(processDefinitionId);
} catch (final ProcessActivationException e) {
BonitaStudioLog.debug("Failed to disable the process", e, EnginePlugin.PLUGIN_ID);
}
}
private String getProcessLabel(final AbstractProcess process) {
return process.getName() + " (" + process.getVersion() + ")";
}
}
......@@ -24,29 +24,22 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;
import org.bonitasoft.engine.api.IdentityAPI;
import org.bonitasoft.engine.api.ProcessAPI;
import org.bonitasoft.engine.bpm.bar.BusinessArchive;
import org.bonitasoft.engine.bpm.flownode.HumanTaskInstance;
import org.bonitasoft.engine.bpm.process.ActivationState;
import org.bonitasoft.engine.bpm.process.IllegalProcessStateException;
import org.bonitasoft.engine.bpm.process.ProcessActivationException;
import org.bonitasoft.engine.bpm.process.ProcessDefinition;
import org.bonitasoft.engine.bpm.process.ProcessDefinitionNotFoundException;
import org.bonitasoft.engine.bpm.process.ProcessDeploymentInfo;
import org.bonitasoft.engine.bpm.process.ProcessDeploymentInfoCriterion;
import org.bonitasoft.engine.bpm.process.ProcessExecutionException;
import org.bonitasoft.engine.bpm.process.ProcessInstance;
import org.bonitasoft.engine.exception.BonitaHomeNotSetException;
import org.bonitasoft.engine.exception.DeletionException;
import org.bonitasoft.engine.exception.ServerAPIException;
import org.bonitasoft.engine.exception.UnknownAPITypeException;
import org.bonitasoft.engine.exception.UpdateException;
import org.bonitasoft.engine.identity.UserNotFoundException;
import org.bonitasoft.engine.session.APISession;
import org.bonitasoft.engine.session.InvalidSessionException;
import org.bonitasoft.studio.browser.operation.OpenBrowserOperation;
import org.bonitasoft.studio.common.BonitaConstants;
import org.bonitasoft.studio.common.ProjectUtil;
......@@ -63,6 +56,7 @@ import org.bonitasoft.studio.engine.BOSWebServerManager;
import org.bonitasoft.studio.engine.export.BarExporter;
import org.bonitasoft.studio.engine.operation.AbstractBonitaURLBuilder;
import org.bonitasoft.studio.engine.operation.ApplicationURLBuilder;
import org.bonitasoft.studio.engine.operation.UndeployProcessOperation;
import org.bonitasoft.studio.form.preview.i18n.Messages;
import org.bonitasoft.studio.model.configuration.Configuration;
import org.bonitasoft.studio.model.configuration.ConfigurationFactory;
......@@ -134,7 +128,9 @@ public class FormPreviewOperation implements IRunnableWithProgress {
processApi = BOSEngineManager.getInstance().getProcessAPI(session);
Assert.isNotNull(processApi);
undeployDeployedProcess(proc, processApi);
final UndeployProcessOperation undeployProcessOperation = new UndeployProcessOperation(BOSEngineManager.getInstance());
undeployProcessOperation.addProcessToUndeploy(proc);
undeployProcessOperation.run(monitor);
final BusinessArchive businessArchive = BarExporter.getInstance().createBusinessArchive(proc, configuration, Collections.EMPTY_SET, false);
cleanResources(proc, resource);
......@@ -269,33 +265,4 @@ public class FormPreviewOperation implements IRunnableWithProgress {
editingDomain.getCommandStack().execute(cc);
}
protected void undeployDeployedProcess(final AbstractProcess process, final ProcessAPI processApi) throws InvalidSessionException,
ProcessDefinitionNotFoundException, IllegalProcessStateException, DeletionException {
final long nbDeployedProcesses = processApi.getNumberOfProcessDeploymentInfos();
if (nbDeployedProcesses > 0) {
if (lastProcessDeployed == null) {
lastProcessDeployed = process.getName();
}
final List<ProcessDeploymentInfo> processes = processApi.getProcessDeploymentInfos(0, (int) nbDeployedProcesses,
ProcessDeploymentInfoCriterion.DEFAULT);
for (final ProcessDeploymentInfo info : processes) {
undeployProcess(processApi, info);
}
}
}
protected void undeployProcess(final ProcessAPI processApi, final ProcessDeploymentInfo info) throws ProcessDefinitionNotFoundException, DeletionException {
if (info.getName().equals(lastProcessDeployed) && info.getVersion().equals(AbstractFormPreviewInitialization.VERSION)) {
try {
processApi.deleteProcessInstances(info.getProcessId(), 0, 10);
if (processApi.getProcessDeploymentInfo(info.getProcessId()).getActivationState() == ActivationState.ENABLED) {
processApi.disableProcess(info.getProcessId());
}
} catch (final ProcessActivationException e) {
BonitaStudioLog.error(e);
}
processApi.deleteProcessDefinition(info.getProcessId());
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment