Skip to content

Commit

Permalink
Requirements cherrypick (#12)
Browse files Browse the repository at this point in the history
* [568173] Import ReqIf fails for model size greater than Integer.MAX_SIZE

- Replace the Model Resource save by a Session save
- Run resource save in Workspace Runnable
- Improve performance by avoiding resource unloading and loading after
save

Change-Id: I6fea74041880d9da362d6cc016c86dbd4913aa25
Signed-off-by: Sandu Postaru <sandu.postaru@thalesgroup.com>

* [test] Update Transposer transformation test

Change-Id: I74b208d586891b97e2d249391382dd1be101a95f
Signed-off-by: Sandu Postaru <sandu.postaru@thalesgroup.com>

* [568336] Iterative ReqIf import does not match CapellaOutgoingRelations

- Fix the bug
-- In addition to the Requif Elements also remove CapellaRelations
during the construction of the intermediate data set
-- For more details check
https://bugs.eclipse.org/bugs/show_bug.cgi?id=568336

- Add JUnit
-- Since this commit is a cherry pick, the test model was migrated to
the current version

Change-Id: Ib8b3eb6f8db9d020d7ff6dbd362f61858af3952d
Signed-off-by: Sandu Postaru <sandu.postaru@thalesgroup.com>

* [releng] Update Jenkinsfile

- Update Capella download URL to '1.4.x' branch instead of 'master'

Change-Id: Id71a70993e4bdba1ff2df1dbd9bb4576867509b1
Signed-off-by: Sandu Postaru <sandu.postaru@thalesgroup.com>
  • Loading branch information
sandupostaru authored Nov 4, 2020
1 parent c9ce0a3 commit 4e4d7fc
Show file tree
Hide file tree
Showing 14 changed files with 1,977 additions and 92 deletions.
7 changes: 4 additions & 3 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ pipeline {

environment {
BUILD_KEY = (github.isPullRequest() ? CHANGE_TARGET : BRANCH_NAME).replaceFirst(/^v/, '')
CAPELLA_PRODUCT_PATH = "${WORKSPACE}/capella/capella"
CAPELLA_PRODUCT_PATH = "${WORKSPACE}/capella/eclipse/eclipse"
CAPELLA_BRANCH = '1.4.x'
}

stages {
Expand Down Expand Up @@ -63,7 +64,7 @@ pipeline {

steps {
script {
def capellaURL = capella.getDownloadURL("${BUILD_KEY}", 'linux', '')
def capellaURL = capella.getDownloadURL("${CAPELLA_BRANCH}", 'linux', '')

sh "curl -k -o capella.zip ${capellaURL}"
sh "unzip -q capella.zip"
Expand All @@ -84,7 +85,7 @@ pipeline {
sh "chmod 755 ${CAPELLA_PRODUCT_PATH}"

eclipse.installFeature("${CAPELLA_PRODUCT_PATH}", 'http://download.eclipse.org/tools/orbit/downloads/drops/R20130827064939/repository', 'org.jsoup')
eclipse.installFeature("${CAPELLA_PRODUCT_PATH}", capella.getTestUpdateSiteURL("${BUILD_KEY}"), 'org.polarsys.capella.test.feature.feature.group')
eclipse.installFeature("${CAPELLA_PRODUCT_PATH}", capella.getTestUpdateSiteURL("${CAPELLA_BRANCH}"), 'org.polarsys.capella.test.feature.feature.group')

eclipse.installFeature("${CAPELLA_PRODUCT_PATH}", "file:/${WORKSPACE}/releng/org.polarsys.capella.vp.requirements.site/target/repository/".replace("\\", "/"), 'org.polarsys.capella.vp.requirements.feature.feature.group')
eclipse.installFeature("${CAPELLA_PRODUCT_PATH}", "file:/${WORKSPACE}/releng/org.polarsys.capella.vp.requirements.site/target/repository/".replace("\\", "/"), 'org.polarsys.capella.vp.requirements.tests.feature.feature.group')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,33 @@
package org.polarsys.capella.vp.requirements.importer.transposer.activities;

import java.io.IOException;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;

import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.diffmerge.api.scopes.IEditableModelScope;
import org.eclipse.emf.diffmerge.bridge.api.IBridgeTrace;
import org.eclipse.emf.diffmerge.bridge.api.incremental.IIncrementalBridgeExecution;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.plugin.EcorePlugin;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.sirius.business.api.session.Session;
import org.eclipse.sirius.business.api.session.SessionManager;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.UIJob;
import org.polarsys.capella.common.ef.ExecutionManager;
import org.polarsys.capella.common.ef.command.AbstractReadWriteCommand;
import org.polarsys.capella.common.helpers.TransactionHelper;
import org.polarsys.capella.core.data.cs.BlockArchitecture;
Expand All @@ -42,93 +50,230 @@
import org.polarsys.kitalpha.transposer.rules.handler.rules.api.IContext;

/**
* @author Joao Barata
* This class managers the merge of requirements into the model and the save of the associated resources.
*
*/
public class TransposerTransformation extends AbstractActivity {

public static String getId() {
return TransposerTransformation.class.getCanonicalName();
/**
* Flag to detect if the merge operation was canceled by the user. This is required since the merge operation and the
* save of the resources are executed in two different transactions. If they are executed in the same transaction, the
* Sirius Session does not detect that the model has changed, and thus the save does not have any effect.
*
* The second transactions depends on the first one.
*
* There must be a cleaner way to achieve this. But for the moment this will do.
*/
final boolean[] mergeOperationCanceled = { false };

/**
* The UI job that manages the transformation.
*/
private class MergeAndSaveRequirementsUIJob extends UIJob {

private ActivityParameters activityParams;

public MergeAndSaveRequirementsUIJob(ActivityParameters activityParams) {
super("Import and Merge Requirements Job");
this.activityParams = activityParams;
}

@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
return mergeAndSave(activityParams, monitor);
}
}

/**
* The Workspace Runnable that manages the resource save. The save must be executed in a Workspace Runnable, since it
* is the workspace who manages the lifecycle of the save.
*
* <b>Reason:</b> When resources are saved, the buffer used to save the resource can be flushed multiple times if the
* resource content is bigger than the buffer. For resources that are not saved in a WorkspaceRunnable (by invoking
* <code>resource.save()</code> for example, the workspace detects that a resource has changed and notifies any
* listener that is registered to the event. The problem is that if multiple flushes are required, the file is
* incomplete for all flushed except the last one, so the listener fail since the resource is corrupted. Thus only the
* last flush should generated a notification, and the runnable ensured this.
*
* In our case we do a <code>resource.save()</code> for the <code>bridgetraces</code> resource, since this resource is
* not a semantic resource of our model, and thus the session save does not have an effect on it.
*
* Running the save in a Workspace Runnable ensure that the Workspace does not get confused.
*/
private class SaveResourcesWorkspaceRunnable implements IWorkspaceRunnable {
private Resource modelResource;
private Resource traceResource;

public SaveResourcesWorkspaceRunnable(Resource modelResource, Resource traceResource) {
this.modelResource = modelResource;
this.traceResource = traceResource;
}

@Override
public void run(IProgressMonitor monitor) throws CoreException {
SubMonitor subMonitor = SubMonitor.convert(monitor, "Save resources", 100);
subMonitor.split(30);
try {
traceResource.save(Collections.emptyMap());
Session session = SessionManager.INSTANCE.getSession(modelResource);
session.save(subMonitor.split(70));
} catch (IOException e) {
e.printStackTrace();
}
}
};

@Override
protected IStatus _run(final ActivityParameters activityParams) {
Job job = new UIJob("Merge of ReqIF elements") {
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
return mergeAndSave(activityParams);
}
};

Job job = new MergeAndSaveRequirementsUIJob(activityParams);

job.setRule(ReqIFJobSchedulingRule.getInstance());
job.setPriority(Job.SHORT);
job.schedule();

return Status.OK_STATUS;
}

protected IStatus mergeAndSave(ActivityParameters activityParams) {
final IContext context = (IContext) activityParams.getParameter(ITransposerWorkflow.TRANSPOSER_CONTEXT).getValue();
/**
* The main method executed by the MergeAndSaveRequirementsUIJob.
*
* @param activityParams
* @param monitor
* @return the execution status.
*/
protected IStatus mergeAndSave(ActivityParameters activityParams, IProgressMonitor monitor) {
IContext context = (IContext) activityParams.getParameter(ITransposerWorkflow.TRANSPOSER_CONTEXT).getValue();

Object reqIfContainsModule = context.get(IRequirementsImporterBridgeConstants.REQIF_MODEL_CONTAINS_MODULE);
// Only run diffmerge activity if at least a module found in the reqif file
if (reqIfContainsModule instanceof Boolean && ((Boolean) reqIfContainsModule).booleanValue()) {
if (reqIfContainsModule(context)) {
BlockArchitecture blockArchitecture = (BlockArchitecture) context
.get(IRequirementsImporterBridgeConstants.TARGET_ELEMENT);
RequirementsVPBridge requirementBridge = (RequirementsVPBridge) context
.get(IRequirementsImporterBridgeConstants.BRIDGE);
IIncrementalBridgeExecution requirementBridgeExecution = (IIncrementalBridgeExecution) context
.get(IRequirementsImporterBridgeConstants.BRIDGE_EXECUTION);

final IEditableModelScope targetScope = (IEditableModelScope) context
.get(IRequirementsImporterBridgeConstants.TARGET_SCOPE);
BlockArchitecture target = (BlockArchitecture) context.get(IRequirementsImporterBridgeConstants.TARGET_ELEMENT);
ExecutionManager executionManager = TransactionHelper.getExecutionManager(blockArchitecture);

TransactionHelper.getExecutionManager(target).execute(new AbstractReadWriteCommand() {
@Override
public void run() {
RequirementsVPBridge bridge = (RequirementsVPBridge) context.get(IRequirementsImporterBridgeConstants.BRIDGE);
Resource traceResource = (Resource) context.get(IRequirementsImporterBridgeConstants.TRACE_RESOURCE);
final IIncrementalBridgeExecution execution2 = (IIncrementalBridgeExecution) context
.get(IRequirementsImporterBridgeConstants.BRIDGE_EXECUTION);
SubMonitor subMonitor = SubMonitor.convert(monitor, "Merge and Save requirements", 2);

IStatus result = bridge.mergeInteractively(execution2, new NullProgressMonitor());
if (result == Status.CANCEL_STATUS) {
throw new OperationCanceledException(result.getMessage());
}
mergeRequirements(executionManager, requirementBridge, requirementBridgeExecution, subMonitor.split(1));

// Save traces and output model
save(execution2, traceResource, execution2.getTrace(), targetScope);
if (!isMergeOperationCanceled()) {
IEditableModelScope targetScope = (IEditableModelScope) context
.get(IRequirementsImporterBridgeConstants.TARGET_SCOPE);

TransactionHelper.getExecutionManager(traceResource).execute(new AbstractReadWriteCommand() {
@Override
public void run() {
HoldingResourceHelper
.flushHoldingResource(TransactionHelper.getEditingDomain(targetScope.getContents().get(0)));
}
});
List<EObject> targetScopeContents = targetScope.getContents();

if (!targetScopeContents.isEmpty()) {
EObject rootScopeElement = targetScopeContents.get(0);
Resource modelResource = rootScopeElement.eResource();
Resource traceResource = (Resource) context.get(IRequirementsImporterBridgeConstants.TRACE_RESOURCE);

saveAndCleanResources(executionManager, modelResource, traceResource, subMonitor.split(1));
}
});
} else {
}

Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
String title = Messages.ReqIfImport_NoModuleFoundPopup_Title;
String content = Messages.ReqIfImport_NoModuleFoundPopup_Content;
MessageDialog.openInformation(shell, title, content);
} else {
displayNoModuleFoundInformationDialog();
}
return Status.OK_STATUS;
}

/**
* Displays the Diff Merge Window, and merges the Requirements on user feedback. The code is executed in a
* transaction.
*
* @param executionManager
* @param requirementBridge
* @param requirementBridgeExecution
* @param monitor
*/
private void mergeRequirements(ExecutionManager executionManager, RequirementsVPBridge requirementBridge,
IIncrementalBridgeExecution requirementBridgeExecution, SubMonitor monitor) {

monitor.beginTask("Merge requirements", 1);
setMergeOperationCanceled(false);

executionManager.execute(new AbstractReadWriteCommand() {
@Override
public void run() {
IStatus result = requirementBridge.mergeInteractively(requirementBridgeExecution, monitor);
if (result == Status.CANCEL_STATUS) {
setMergeOperationCanceled(true);
throw new OperationCanceledException(result.getMessage());
}
}
});
}

/**
* Saves the model resource, trace resource and cleans existing holding resources.
*
* @param executionManager
* @param modelResource
* @param traceResource
* @param monitor
*/
private void saveAndCleanResources(ExecutionManager executionManager, Resource modelResource, Resource traceResource,
SubMonitor monitor) {
executionManager.execute(new AbstractReadWriteCommand() {
@Override
public void run() {
saveResources(modelResource, traceResource, monitor);

HoldingResourceHelper.flushHoldingResource(TransactionHelper.getEditingDomain(modelResource));
}
});
}

/**
* Saves the model and trace resources in a workspace runnable.
*
* @param modelResource
* @param traceResource
* @param trace
* @param progressMonitor
*/
@SuppressWarnings("rawtypes")
private void save(IIncrementalBridgeExecution execution, Resource traceResource, IBridgeTrace trace,
IEditableModelScope targetScope) {

try {
// setTrace(traceResource, execution.getTrace());
// compact(traceResource);
traceResource.save(new HashMap());
targetScope.getContents().get(0).eResource().save(new HashMap());
} catch (IOException e) {
e.printStackTrace();
private void saveResources(Resource modelResource, Resource traceResource, SubMonitor progressMonitor) {

IWorkspaceRoot workspaceRoot = EcorePlugin.getWorkspaceRoot();
if (workspaceRoot != null) {
IWorkspace workspace = workspaceRoot.getWorkspace();

if (workspace != null) {
SaveResourcesWorkspaceRunnable saveRunnable = new SaveResourcesWorkspaceRunnable(modelResource, traceResource);

try {
workspace.run(saveRunnable, progressMonitor);
} catch (CoreException e) {
e.printStackTrace();
}
}
}
}

private void displayNoModuleFoundInformationDialog() {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
String title = Messages.ReqIfImport_NoModuleFoundPopup_Title;
String content = Messages.ReqIfImport_NoModuleFoundPopup_Content;
MessageDialog.openInformation(shell, title, content);
}

private void setMergeOperationCanceled(boolean isCanceled) {
mergeOperationCanceled[0] = isCanceled;
}

private boolean isMergeOperationCanceled() {
return mergeOperationCanceled[0];
}

public static String getId() {
return TransposerTransformation.class.getCanonicalName();
}

private boolean reqIfContainsModule(IContext context) {
Object isModulePresent = context.get(IRequirementsImporterBridgeConstants.REQIF_MODEL_CONTAINS_MODULE);
return isModulePresent instanceof Boolean && ((Boolean) isModulePresent).booleanValue();
}

protected static void compact(Resource resource) {
Expand Down
Loading

0 comments on commit 4e4d7fc

Please sign in to comment.