Commit abff0c6d authored by Romain Bioteau's avatar Romain Bioteau
Browse files

Merge pull request #279 from bonitasoft/fix/BS-14246-inconsistentModelOnBoundaryDeletion

BS-14246 inconsistent model on boundary deletion
parents d04950c6 eeb948b9
/**
* 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.common.gmf.tools.convert;
import org.assertj.core.api.Assertions;
import org.bonitasoft.studio.model.process.Activity;
import org.bonitasoft.studio.model.process.BoundaryEvent;
import org.bonitasoft.studio.model.process.BoundaryMessageEvent;
import org.bonitasoft.studio.model.process.MainProcess;
import org.bonitasoft.studio.model.process.MessageFlow;
import org.bonitasoft.studio.model.process.Pool;
import org.bonitasoft.studio.model.process.ProcessFactory;
import org.bonitasoft.studio.model.process.SendTask;
import org.bonitasoft.studio.model.process.builders.MainProcessBuilder;
import org.bonitasoft.studio.model.process.builders.PoolBuilder;
import org.bonitasoft.studio.model.process.builders.SendTaskBuilder;
import org.bonitasoft.studio.model.process.builders.SequenceFlowBuilder;
import org.bonitasoft.studio.model.process.builders.TaskBuilder;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class RemoveBoundaryWithItsFlowsTest {
@Mock
private InternalTransactionalEditingDomain domain;
@Test
public void testBoundaryRemovedWithItsUniqueExceptionFlow() throws Exception {
final TaskBuilder taskTargetOfExceptionFlow = TaskBuilder.aTask().withName("Targeted Task of exception flow");
final TaskBuilder taskWithABoundary = TaskBuilder.aTask().withName("Task with Boundary");
final Pool pool = PoolBuilder.aPool().havingElements(taskWithABoundary, taskTargetOfExceptionFlow).build();
final Activity boundaryHolder = (Activity) pool.getElements().get(0);
final Activity boundaryTarget = (Activity) pool.getElements().get(1);
final BoundaryEvent boundaryToRemove = ProcessFactory.eINSTANCE.createBoundaryEvent();
boundaryHolder.getBoundaryIntermediateEvents().add(boundaryToRemove);
pool.getConnections().add(SequenceFlowBuilder.aSequenceFlow().havingSource(boundaryToRemove).havingTarget(boundaryTarget).build());
new RemoveBoundaryWithItsFlows(domain, boundaryToRemove, boundaryHolder).doExecute(null, null);
Assertions.assertThat(pool.getConnections()).isEmpty();
Assertions.assertThat(boundaryTarget.getIncoming()).isEmpty();
}
@Test
public void testBoundaryRemovedWithSeveralExceptionFlow() throws Exception {
final TaskBuilder firsTaskTargetOfExceptionFlow = TaskBuilder.aTask().withName("First Targeted Task of exception flow");
final TaskBuilder secondTargetOfExceptionFlow = TaskBuilder.aTask().withName("Second Targeted Task of exception flow");
final TaskBuilder taskWithABoundary = TaskBuilder.aTask().withName("Task with Boundary");
final Pool pool = PoolBuilder.aPool().havingElements(taskWithABoundary, firsTaskTargetOfExceptionFlow, secondTargetOfExceptionFlow).build();
final Activity boundaryHolder = (Activity) pool.getElements().get(0);
final Activity firstBoundaryTarget = (Activity) pool.getElements().get(1);
final Activity secondBoundaryTarget = (Activity) pool.getElements().get(2);
final BoundaryEvent boundaryToRemove = ProcessFactory.eINSTANCE.createBoundaryEvent();
boundaryHolder.getBoundaryIntermediateEvents().add(boundaryToRemove);
pool.getConnections().add(SequenceFlowBuilder.aSequenceFlow().havingSource(boundaryToRemove).havingTarget(firstBoundaryTarget).build());
pool.getConnections().add(SequenceFlowBuilder.aSequenceFlow().havingSource(boundaryToRemove).havingTarget(secondBoundaryTarget).build());
new RemoveBoundaryWithItsFlows(domain, boundaryToRemove, boundaryHolder).doExecute(null, null);
Assertions.assertThat(pool.getConnections()).isEmpty();
Assertions.assertThat(firstBoundaryTarget.getIncoming()).isEmpty();
Assertions.assertThat(secondBoundaryTarget.getIncoming()).isEmpty();
}
@Test
public void testBoundaryMessageRemovedWithMessageFlow() throws Exception {
final SendTaskBuilder taskSourceOfMessageFlow = SendTaskBuilder.aSendTask().withName("Source Task of message flow");
final TaskBuilder taskWithABoundary = TaskBuilder.aTask().withName("Task with Boundary Message");
final MainProcess diagram = MainProcessBuilder.aMainProcess()
.havingElements(
PoolBuilder.aPool().havingElements(taskWithABoundary),
PoolBuilder.aPool().havingElements(taskSourceOfMessageFlow)).build();
final Pool poolContainingBoundary = (Pool) diagram.getElements().get(0);
final Activity boundaryHolder = (Activity) poolContainingBoundary.getElements().get(0);
final BoundaryMessageEvent boundaryToRemove = ProcessFactory.eINSTANCE.createBoundaryMessageEvent();
boundaryHolder.getBoundaryIntermediateEvents().add(boundaryToRemove);
final Pool poolContainingSourceMessagFlow = (Pool) diagram.getElements().get(1);
final SendTask messageFlowSource = (SendTask) poolContainingSourceMessagFlow.getElements().get(0);
final MessageFlow messageFlow = ProcessFactory.eINSTANCE.createMessageFlow();
messageFlow.setSource(messageFlowSource);
messageFlow.setTarget(boundaryToRemove);
messageFlowSource.getOutgoingMessages().add(messageFlow);
new RemoveBoundaryWithItsFlows(domain, boundaryToRemove, boundaryHolder).doExecute(null, null);
Assertions.assertThat(poolContainingBoundary.getConnections()).isEmpty();
Assertions.assertThat(messageFlowSource.getOutgoingMessages()).isEmpty();
}
}
......@@ -226,55 +226,7 @@ public class ConvertBPMNTypeCommand extends AbstractTransactionalCommand {
// reset boundary connections
commands.clear();
for (final BoundaryEvent boundaryEvent : ((Activity) targetElement).getBoundaryIntermediateEvents()) {
final GraphicalEditPart boundaryEp = (GraphicalEditPart) targetEditPart.findEditPart(targetEditPart, boundaryEvent);
if (boundaryEp != null) {
for (int i = 0; i < boundaryEvent.getOutgoing().size(); i++) {
final Connection outgoing = boundaryEvent.getOutgoing().get(i);
final GraphicalEditPart boundaryTargetEP = (GraphicalEditPart) parentEditPart.findEditPart(parentEditPart.getRoot(),outgoing.getTarget());
if(boundaryTargetEP != null){
final ConnectionEditPart ep = (ConnectionEditPart) GMFTools.findEditPart((EditPart) parentEditPart.getRoot().getChildren().get(0),outgoing) ;
if(ep != null){
try {
new DeleteCommand(ep.getNotationView()).execute(null, null);
} catch (final ExecutionException e) {
BonitaStudioLog.error(e) ;
}
}
final AbstractEMFOperation recreateExceptionFlowsOperation = new AbstractEMFOperation(editingDomain, "Recreate Exception flow") {
@Override
protected IStatus doExecute(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
final IElementType elementType = ElementTypeRegistry.getInstance().getType("org.bonitasoft.studio.diagram.SequenceFlow_4001");
final Edge edge = ViewService.getInstance().createEdge(elementType,
ModelHelper.getDiagramFor(ModelHelper.getMainProcess(targetElement),editingDomain),
((IHintedType) elementType).getSemanticHint(), -1, true, targetEditPart.getDiagramPreferencesHint());
edge.setElement(outgoing);
edge.setSource(boundaryEp.getNotationView());
edge.setTarget(boundaryTargetEP.getNotationView());
edge.setVisible(true);
return new Status(IStatus.OK, "org.bonitasoft.studio.diagram.common", "Recreate Exception flow succeeded");
}
};
try {
recreateExceptionFlowsOperation.execute(monitor, null);
} catch (final ExecutionException e) {
BonitaStudioLog.error(e);
}
} else {
// TODO: remove target from list because it has been
// removed? for now this done at the end, in
// refreshBoundaryElements
}
}
}
}
handleBoundaries(monitor, editingDomain, parentEditPart, targetElement, targetEditPart);
}
// if (targetElement instanceof ConnectableElement) {
......@@ -290,11 +242,64 @@ public class ConvertBPMNTypeCommand extends AbstractTransactionalCommand {
targetEditPart.refresh();// need to call refresh in order that it
targetEditPart.getViewer().select(targetEditPart);
targetEditPart.getRoot().refresh();
/* Need to refresh the boundaries elment at the end of the conversion */
/* Need to refresh the boundaries element at the end of the conversion */
refreshBoundaryElements(editingDomain, targetElement, targetEditPart, childPositions);
return CommandResult.newOKCommandResult(targetEditPart);
}
protected void handleBoundaries(final IProgressMonitor monitor, final TransactionalEditingDomain editingDomain, final GraphicalEditPart parentEditPart,
final EObject targetElement, final GraphicalEditPart targetEditPart) {
for (final BoundaryEvent boundaryEvent : ((Activity) targetElement).getBoundaryIntermediateEvents()) {
final GraphicalEditPart boundaryEp = (GraphicalEditPart) targetEditPart.findEditPart(targetEditPart, boundaryEvent);
if (boundaryEp != null) {
for (int i = 0; i < boundaryEvent.getOutgoing().size(); i++) {
final Connection outgoing = boundaryEvent.getOutgoing().get(i);
final GraphicalEditPart boundaryTargetEP = (GraphicalEditPart) parentEditPart.findEditPart(parentEditPart.getRoot(),outgoing.getTarget());
if(boundaryTargetEP != null){
final ConnectionEditPart ep = (ConnectionEditPart) GMFTools.findEditPart((EditPart) parentEditPart.getRoot().getChildren().get(0),outgoing) ;
if(ep != null){
try {
new DeleteCommand(ep.getNotationView()).execute(null, null);
} catch (final ExecutionException e) {
BonitaStudioLog.error(e) ;
}
}
final AbstractEMFOperation recreateExceptionFlowsOperation = new AbstractEMFOperation(editingDomain, "Recreate Exception flow") {
@Override
protected IStatus doExecute(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
final IElementType elementType = ElementTypeRegistry.getInstance().getType("org.bonitasoft.studio.diagram.SequenceFlow_4001");
final Edge edge = ViewService.getInstance().createEdge(elementType,
ModelHelper.getDiagramFor(ModelHelper.getMainProcess(targetElement),editingDomain),
((IHintedType) elementType).getSemanticHint(), -1, true, targetEditPart.getDiagramPreferencesHint());
edge.setElement(outgoing);
edge.setSource(boundaryEp.getNotationView());
edge.setTarget(boundaryTargetEP.getNotationView());
edge.setVisible(true);
return new Status(IStatus.OK, "org.bonitasoft.studio.diagram.common", "Recreate Exception flow succeeded");
}
};
try {
recreateExceptionFlowsOperation.execute(monitor, null);
} catch (final ExecutionException e) {
BonitaStudioLog.error(e);
}
} else {
// TODO: remove target from list because it has been
// removed? for now this done at the end, in
// refreshBoundaryElements
}
}
}
}
}
protected static void refreshBoundaryElements(final TransactionalEditingDomain editingDomain, final EObject targetElement,
final GraphicalEditPart targetEditPart, final List<Pair<EObject, Point>> childPositions) {
for (final Pair<EObject, Point> pair : childPositions) {
......@@ -315,22 +320,12 @@ public class ConvertBPMNTypeCommand extends AbstractTransactionalCommand {
* can't be set on this kind of Element
*/
if (targetElement instanceof Activity) {
final AbstractEMFOperation operation = new AbstractEMFOperation(editingDomain, "Remove boundary child") {
@Override
protected IStatus doExecute(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
/*
* Remove the BoundaryEvent from the list and
* its outgoing transition
*/
((Activity) targetElement).getBoundaryIntermediateEvents().remove(childToResetPosition);
if (childToResetPosition instanceof BoundaryEvent) {
((BoundaryEvent) childToResetPosition).getOutgoing().clear();
}
return new Status(IStatus.OK, "org.bonitasoft.studio.diagram.common", "Remove boundary child succeeded");
}
};
/*
* Remove the BoundaryEvent from the list and
* its outgoing transition
*/
final AbstractEMFOperation operation = new RemoveBoundaryWithItsFlows(editingDomain, (BoundaryEvent) childToResetPosition,
(Activity) targetElement);
try {
operation.execute(new NullProgressMonitor(), null);
} catch (final ExecutionException e) {
......
/**
* 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.common.gmf.tools.convert;
import org.bonitasoft.studio.model.process.Activity;
import org.bonitasoft.studio.model.process.BoundaryEvent;
import org.bonitasoft.studio.model.process.BoundaryMessageEvent;
import org.bonitasoft.studio.model.process.Connection;
import org.bonitasoft.studio.model.process.MessageFlow;
import org.bonitasoft.studio.model.process.TargetElement;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.workspace.AbstractEMFOperation;
public final class RemoveBoundaryWithItsFlows extends AbstractEMFOperation {
private final BoundaryEvent boundaryToRemove;
private final Activity boundaryHolder;
public RemoveBoundaryWithItsFlows(final TransactionalEditingDomain domain, final BoundaryEvent boundaryToRemove, final Activity boundaryHolder) {
super(domain, "Remove boundary child");
this.boundaryToRemove = boundaryToRemove;
this.boundaryHolder = boundaryHolder;
}
@Override
protected IStatus doExecute(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
/*
* Remove the BoundaryEvent from the list and
* its incoming and outgoing transition
*/
boundaryHolder.getBoundaryIntermediateEvents().remove(boundaryToRemove);
cleanExceptionFlow();
cleanMessageFlow();
return new Status(IStatus.OK, "org.bonitasoft.studio.diagram.common", "Remove boundary child succeeded");
}
private void cleanMessageFlow() {
if (boundaryToRemove instanceof BoundaryMessageEvent) {
final MessageFlow messageFlow = ((BoundaryMessageEvent) boundaryToRemove).getIncomingMessag();
EcoreUtil.remove(messageFlow);
messageFlow.getSource().getOutgoingMessages().remove(messageFlow);
}
}
protected void cleanExceptionFlow() {
final EList<Connection> exceptionFlowsToDelete = boundaryToRemove.getOutgoing();
for (final Connection exceptionFlowToDelete : exceptionFlowsToDelete) {
EcoreUtil.remove(exceptionFlowToDelete);
final TargetElement target = exceptionFlowToDelete.getTarget();
if (target != null) {
target.getIncoming().remove(exceptionFlowToDelete);
}
}
exceptionFlowsToDelete.clear();
}
}
\ No newline at end of file
/**
* 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.diagram.test;
import java.io.IOException;
import org.assertj.core.api.Assertions;
import org.bonitasoft.studio.model.process.MainProcess;
import org.bonitasoft.studio.model.process.Pool;
import org.bonitasoft.studio.model.process.SendTask;
import org.bonitasoft.studio.model.process.ServiceTask;
import org.bonitasoft.studio.properties.i18n.Messages;
import org.bonitasoft.studio.swtbot.framework.diagram.BotProcessDiagramPerspective;
import org.bonitasoft.studio.swtbot.framework.rule.SWTGefBotRule;
import org.bonitasoft.studio.test.swtbot.util.SWTBotTestUtil;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.swtbot.eclipse.gef.finder.SWTBotGefTestCase;
import org.eclipse.swtbot.eclipse.gef.finder.widgets.SWTBotGefEditPart;
import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(SWTBotJunit4ClassRunner.class)
public class ConvertActivityTypeWithBoundariesIT extends SWTBotGefTestCase {
@Rule
public SWTGefBotRule botRule = new SWTGefBotRule(bot);
private final static String STEP_WITH_BOUNDARY_NAME = "Step1";
@Test
public void testConvertWithRemovedTimerBoundary() throws Exception {
final MainProcess diagram = importAndConvertStep1ToServiceTask(
"TestConvertActivtyWithTimerBoundary-1.0.bos",
"TestConvertActivtyWithTimerBoundary");
final Pool pool = (Pool) diagram.getElements().get(0);
Assertions.assertThat(pool.getConnections()).hasSize(0);
final ServiceTask serviceTask = (ServiceTask) pool.getElements().get(1);
Assertions.assertThat(serviceTask.getName()).isEqualTo(STEP_WITH_BOUNDARY_NAME);
Assertions.assertThat(serviceTask.getBoundaryIntermediateEvents()).hasSize(0);
}
@Test
public void testConvertWithRemovedMessageBoundary() throws Exception {
final MainProcess diagram = importAndConvertStep1ToServiceTask(
"TestConvertActivityWithMessageBoundary-1.0.bos",
"TestConvertActivityWithMessageBoundary");
final Pool pool = (Pool) diagram.getElements().get(0);
Assertions.assertThat(pool.getConnections()).hasSize(0);
final ServiceTask serviceTask = (ServiceTask) pool.getElements().get(1);
Assertions.assertThat(serviceTask.getName()).isEqualTo(STEP_WITH_BOUNDARY_NAME);
Assertions.assertThat(serviceTask.getBoundaryIntermediateEvents()).hasSize(0);
final Pool senderMessagePool = (Pool) diagram.getElements().get(1);
Assertions.assertThat(((SendTask) senderMessagePool.getElements().get(0)).getOutgoingMessages()).isEmpty();
}
@Test
public void testConvertKeepingBoundary() throws Exception {
final MainProcess diagram = importAndConvertStep1ToServiceTask(
"TestConvertActivityTypeWithCompatibleBoundary-1.0.bos",
"TestConvertActivityTypeWithCompatibleBoundary");
final Pool pool = (Pool) diagram.getElements().get(0);
Assertions.assertThat(pool.getConnections()).hasSize(1);
final ServiceTask serviceTask = (ServiceTask) pool.getElements().get(1);
Assertions.assertThat(serviceTask.getName()).isEqualTo(STEP_WITH_BOUNDARY_NAME);
Assertions.assertThat(serviceTask.getBoundaryIntermediateEvents()).hasSize(1);
}
protected MainProcess importAndConvertStep1ToServiceTask(final String resourceNameInClasspath, final String diagramEditorTitle) throws IOException {
SWTBotTestUtil.importProcessWIthPathFromClass(bot,
resourceNameInClasspath,
SWTBotTestUtil.IMPORTER_TITLE_BONITA,
diagramEditorTitle,
this.getClass(),
false);
final BotProcessDiagramPerspective botProcessDiagramPerspective = new BotProcessDiagramPerspective(bot);
botProcessDiagramPerspective.activeProcessDiagramEditor().selectElement(STEP_WITH_BOUNDARY_NAME);
botProcessDiagramPerspective.getDiagramPropertiesPart().selectGeneralTab().selectGeneralTab().setTaskType(Messages.activityType_serviceTask);
botProcessDiagramPerspective.activeProcessDiagramEditor().getGmfEditor().save();
final SWTBotGefEditPart mainEditPart = botProcessDiagramPerspective.activeProcessDiagramEditor().getGmfEditor().mainEditPart();
return (MainProcess) ((DiagramEditPart) (mainEditPart.part())).resolveSemanticElement();
}
}
/**
* Copyright (C) 2009 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
......@@ -25,6 +25,7 @@ import org.bonitasoft.studio.common.jface.FileActionDialog;
import org.bonitasoft.studio.common.log.BonitaStudioLog;
import org.bonitasoft.studio.configuration.test.swtbot.TestProcessDependencies;
import org.bonitasoft.studio.connectors.test.swtbot.ConnectorEditedInAsingleCommandIT;
import org.bonitasoft.studio.diagram.test.ConvertActivityTypeWithBoundariesIT;
import org.bonitasoft.studio.diagram.test.NewRunTest;
import org.bonitasoft.studio.diagram.test.SharedEditingDomainTests;
import org.bonitasoft.studio.diagram.test.TestBoundariesCreation;
......@@ -114,7 +115,8 @@ import org.junit.runners.Suite;
TestOrganizationPassword.class,
BarImportReportIT.class,
CallActivityMappingIT.class,
CreateDeployExportBusinessObjectIT.class
CreateDeployExportBusinessObjectIT.class,
ConvertActivityTypeWithBoundariesIT.class
})
public class AllSWTBotTests2 {
......
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