Commit 3074ae5a authored by Romain Bioteau's avatar Romain Bioteau Committed by GitHub

fix(migration) add missing variable dependencies (#1488)

Closes BS-19095
parent 34f859e8
......@@ -213,11 +213,13 @@ public class BonitaProjectExplorer extends CommonNavigator {
@Override
protected void internalRefresh(Object element, boolean updateLabels) {
try {
fPendingRefreshes.add(element);
super.internalRefresh(element, updateLabels);
} finally {
fPendingRefreshes.remove(element);
if (!getTree().isDisposed()) {
try {
fPendingRefreshes.add(element);
super.internalRefresh(element, updateLabels);
} finally {
fPendingRefreshes.remove(element);
}
}
}
......
......@@ -137,18 +137,23 @@ public abstract class SourceRepositoryStore<T extends AbstractFileStore> extends
final IFolder packageFolder = packageStore.getResource();
final IFile file = packageFolder.getFile(className);
if (file.exists() && FileActionDialog.overwriteQuestion(fileName)) {
if (file.exists()) {
if (FileActionDialog.overwriteQuestion(fileName)) {
try {
file.delete(true, Repository.NULL_PROGRESS_MONITOR);
file.create(inputStream, true, Repository.NULL_PROGRESS_MONITOR);
} catch (final CoreException e) {
BonitaStudioLog.error(e);
}
}
} else {
try {
file.delete(true, Repository.NULL_PROGRESS_MONITOR);
file.create(inputStream, true, Repository.NULL_PROGRESS_MONITOR);
} catch (final CoreException e) {
BonitaStudioLog.error(e);
}
}
try {
file.create(inputStream, true, Repository.NULL_PROGRESS_MONITOR);
} catch (final CoreException e) {
BonitaStudioLog.error(e);
}
return createRepositoryFileStore(packageName);
}
......
......@@ -17,28 +17,37 @@ package org.bonitasoft.studio.migration.custom.migration;
import java.util.ArrayList;
import java.util.List;
import org.bonitasoft.studio.common.ExpressionConstants;
import org.bonitasoft.studio.migration.utils.StringToExpressionConverter;
import org.eclipse.emf.edapt.migration.CustomMigration;
import org.eclipse.emf.edapt.migration.MigrationException;
import org.eclipse.emf.edapt.spi.migration.Instance;
import org.eclipse.emf.edapt.spi.migration.Metamodel;
import org.eclipse.emf.edapt.spi.migration.Model;
/**
* @author Romain Bioteau
*/
public class DependenciesCopyCustomMigration extends CustomMigration {
/*
* (non-Javadoc)
* @see org.eclipse.emf.edapt.migration.CustomMigration#migrateAfter(org.eclipse.emf.edapt.spi.migration.Model, org.eclipse.emf.edapt.migration.Metamodel)
*/
@Override
public void migrateAfter(final Model model, final Metamodel metamodel) throws MigrationException {
final List<Instance> allReferencesToBeDeleted = new ArrayList<>();
for (final Instance expInstance : model.getAllInstances("expression.Expression")) {
final List<Instance> referencedElements = expInstance.get("referencedElements");
final List<Instance> newReferencedElements = new ArrayList<>();
final List<Instance> referencesToBeDeleted = new ArrayList<>();
if (referencedElements.isEmpty() && ExpressionConstants.VARIABLE_TYPE.equals(expInstance.get("type"))) {
String content = expInstance.get("content");
if (content != null && !content.isEmpty()) {
new StringToExpressionConverter(model, getScope(expInstance)).resolveDataDependencies(expInstance);
}
}
if (referencedElements.isEmpty() && ExpressionConstants.PARAMETER_TYPE.equals(expInstance.get("type"))) {
String content = expInstance.get("content");
if (content != null && !content.isEmpty()) {
new StringToExpressionConverter(model, getScope(expInstance)).resolveParameterDependencies(expInstance);
}
}
for (final Instance refElement : referencedElements) {
Instance newCleanedDependency = null;
if (refElement.instanceOf("process.Data")) {
......@@ -100,4 +109,12 @@ public class DependenciesCopyCustomMigration extends CustomMigration {
return newInstance;
}
protected Instance getScope(final Instance element) {
Instance container = element;
while (container != null
&& !container.instanceOf("process.AbstractProcess")) {
container = container.getContainer();
}
return container;
}
}
......@@ -44,6 +44,8 @@ public class StringToExpressionConverter {
private final Map<String, Instance> data = new HashMap<String, Instance>();
private final Map<String, Instance> parameters = new HashMap<>();
private final Map<String, Instance> widget = new HashMap<String, Instance>();
private final Map<String, Instance> documents = new HashMap<String, Instance>();
......@@ -55,6 +57,7 @@ public class StringToExpressionConverter {
Assert.isNotNull(model);
this.model = model;
initDataWithProcessData(model, container);
initParameters(model, container);
for (final Instance widget : model.getAllInstances("form.Widget")) {
if (isInScope(container, widget)) {
this.widget.put(FIELD_PREFIX + widget.get("name"),
......@@ -78,6 +81,14 @@ public class StringToExpressionConverter {
}
}
private void initParameters(final Model model, Instance container) {
for (final Instance parameter : model.getAllInstances("parameter.Parameter")) {
if (isInScope(container, parameter)) {
this.parameters.put((String) parameter.get("name"), parameter);
}
}
}
public static boolean isInScope(final Instance container,
final Instance element) {
Instance current = element;
......@@ -402,6 +413,33 @@ public class StringToExpressionConverter {
return hasAdded;
}
public boolean resolveParameterDependencies(final Instance expression) {
boolean hasAdded = false;
String currentParamName = expression.get("content");
if (currentParamName == null) {
currentParamName = expression.get("name");
}
if (currentParamName != null) {
for (final String paramName : parameters.keySet()) {
if (currentParamName.contains(paramName)) {
final int index = currentParamName.indexOf(paramName);
final boolean validPrefix = isValidPrefix(currentParamName, index);
final boolean validSuffix = isValidSuffix(currentParamName, paramName, index);
if (validPrefix && validSuffix) {
final Instance dependencyInstance = parameters.get(paramName).copy();
final List<Instance> instList = expression.get("referencedElements");
if (!dependancyAlreadyExists(instList, dependencyInstance)) {
expression.add("referencedElements", dependencyInstance);
hasAdded = true;
}
}
}
}
}
return hasAdded;
}
private boolean isValidSuffix(final String currentDataName,
final String dataName, final int index) {
boolean validSuffix = false;
......
......@@ -921,6 +921,22 @@
<target
class="Connector:http://www.bonitasoft.org/ns/studio/process">
</target>
</constraint>
<constraint
class="org.bonitasoft.studio.validation.constraints.ExpressionDependenciesConstraint"
id="org.bonitasoft.studio.validation.constraint.expressionDependencies"
isEnabledByDefault="true"
lang="Java"
mode="Batch"
name="Expression dependency consistency constraint"
severity="ERROR"
statusCode="1">
<message>
{0}
</message>
<target
class="Expression:http://www.bonitasoft.org/ns/studio/expression">
</target>
</constraint>
<constraint
class="org.bonitasoft.studio.validation.constraints.process.MultiInstanceIteratorConstraint"
......
/**
* Copyright (C) 2014 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.validation.constraints;
import static org.bonitasoft.studio.assertions.StatusAssert.assertThat;
import static org.bonitasoft.studio.model.expression.builders.ExpressionBuilder.aConstantExpression;
import static org.bonitasoft.studio.model.expression.builders.ExpressionBuilder.aVariableExpression;
import static org.bonitasoft.studio.model.process.builders.DataBuilder.aData;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.bonitasoft.studio.expression.editor.provider.ExpressionTypeLabelProvider;
import org.bonitasoft.studio.model.expression.Expression;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.validation.IValidationContext;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
/**
* @author Romain Bioteau
*/
@RunWith(MockitoJUnitRunner.class)
public class ExpressionDependenciesConstraintTest {
private ExpressionDependenciesConstraint expressionDependenciesConstraint;
@Mock
private IValidationContext ctx;
@Mock
private ExpressionTypeLabelProvider labelProvider;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
expressionDependenciesConstraint = new ExpressionDependenciesConstraint(labelProvider);
doReturn(ValidationStatus.ok()).when(ctx).createSuccessStatus();
doReturn(ValidationStatus.error("error")).when(ctx).createFailureStatus(any(Object.class));
}
@Test
public void should_return_a_valid_status_for_constant_expression_without_dependencies() throws Exception {
//Given
final Expression constantExpression = aConstantExpression().withContent("hello").build();
when(ctx.getTarget()).thenReturn(constantExpression);
//When
final IStatus status = expressionDependenciesConstraint.performBatchValidation(ctx);
//Then
assertThat(status).isOK();
}
@Test
public void should_return_an_error_status_for_variable_expression_without_dependencies() throws Exception {
//Given
final Expression variableExpression = aVariableExpression().withContent("myVar").build();
when(ctx.getTarget()).thenReturn(variableExpression);
//When
final IStatus status = expressionDependenciesConstraint.performBatchValidation(ctx);
//Then
assertThat(status).isNotOK();
verify(labelProvider).getText(variableExpression.getType());
}
@Test
public void should_return_an_valid_status_for_variable_expression_with_dependencies() throws Exception {
//Given
final Expression variableExpression = aVariableExpression().withContent("myVar")
.havingReferencedElements(aData().build()).build();
when(ctx.getTarget()).thenReturn(variableExpression);
//When
final IStatus status = expressionDependenciesConstraint.performBatchValidation(ctx);
//Then
assertThat(status).isOK();
}
}
/**
* Copyright (C) 2012 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.validation.constraints;
import java.util.HashSet;
import java.util.Set;
import org.bonitasoft.studio.common.ExpressionConstants;
import org.bonitasoft.studio.common.emf.tools.ModelHelper;
import org.bonitasoft.studio.expression.editor.provider.ExpressionTypeLabelProvider;
import org.bonitasoft.studio.model.expression.Expression;
import org.bonitasoft.studio.validation.i18n.Messages;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.validation.IValidationContext;
public class ExpressionDependenciesConstraint extends AbstractLiveValidationMarkerConstraint {
private static final String CONSTRAINT_ID = "org.bonitasoft.studio.validation.constraint.expressionDependencies";
private final ExpressionTypeLabelProvider expressionTypeLabelProvider;
private static Set<String> supportedTypes;
static {
supportedTypes = new HashSet<String>();
supportedTypes.add(ExpressionConstants.VARIABLE_TYPE);
supportedTypes.add(ExpressionConstants.PARAMETER_TYPE);
}
public ExpressionDependenciesConstraint() {
expressionTypeLabelProvider = new ExpressionTypeLabelProvider();
}
ExpressionDependenciesConstraint(final ExpressionTypeLabelProvider expressionTypeLabelProvider) {
this.expressionTypeLabelProvider = expressionTypeLabelProvider;
}
@Override
protected IStatus performBatchValidation(final IValidationContext context) {
final Expression expression = (Expression) context.getTarget();
if (shouldValidateExpression(expression)) {
return evaluateExpression(context, expression);
}
return context.createSuccessStatus();
}
private boolean shouldValidateExpression(final Expression expression) {
return expression.hasContent()
&& !ModelHelper.isAnExpressionCopy(expression)
&& appliesTo(expression.getType());
}
private boolean appliesTo(final String type) {
return supportedTypes.contains(type);
}
private IStatus evaluateExpression(final IValidationContext context, final EObject eObj) {
final Expression expression = (Expression) eObj;
final String type = expression.getType();
if (expression.getReferencedElements().isEmpty()) {
return context.createFailureStatus(Messages.bind(Messages.unresolvedDependenciesFor, expression.getName(),
expressionTypeLabelProvider.getText(type)));
}
return context.createSuccessStatus();
}
@Override
protected String getConstraintId() {
return CONSTRAINT_ID;
}
}
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