/*
* Copyright (c) 2015 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.ui.functions.custom.pages;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.xml.namespace.QName;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.ToolBar;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import eu.esdihumboldt.hale.common.align.custom.CustomPropertyFunctionType;
import eu.esdihumboldt.hale.common.align.custom.DefaultCustomPropertyFunction;
import eu.esdihumboldt.hale.common.align.custom.DefaultCustomPropertyFunctionEntity;
import eu.esdihumboldt.hale.common.align.custom.groovy.CustomGroovyTransformation;
import eu.esdihumboldt.hale.common.align.extension.function.FunctionParameterDefinition;
import eu.esdihumboldt.hale.common.align.model.ChildContext;
import eu.esdihumboldt.hale.common.align.model.EntityDefinition;
import eu.esdihumboldt.hale.common.align.model.ParameterValue;
import eu.esdihumboldt.hale.common.align.model.impl.PropertyEntityDefinition;
import eu.esdihumboldt.hale.common.core.io.Value;
import eu.esdihumboldt.hale.common.schema.SchemaSpaceID;
import eu.esdihumboldt.hale.common.schema.model.PropertyDefinition;
import eu.esdihumboldt.hale.common.schema.model.TypeDefinition;
import eu.esdihumboldt.hale.common.schema.model.constraint.property.Cardinality;
import eu.esdihumboldt.hale.common.schema.model.constraint.type.Binding;
import eu.esdihumboldt.hale.common.schema.model.constraint.type.HasValueFlag;
import eu.esdihumboldt.hale.common.schema.model.impl.DefaultPropertyDefinition;
import eu.esdihumboldt.hale.common.schema.model.impl.DefaultTypeDefinition;
import eu.esdihumboldt.hale.ui.functions.custom.CustomPropertyFunctionWizard;
import eu.esdihumboldt.hale.ui.functions.groovy.GroovyScriptPage;
import eu.esdihumboldt.hale.ui.functions.groovy.internal.InstanceBuilderCompletions;
import eu.esdihumboldt.hale.ui.functions.groovy.internal.PageHelp;
import eu.esdihumboldt.hale.ui.functions.groovy.internal.TypeStructureTray;
import eu.esdihumboldt.hale.ui.functions.groovy.internal.TypeStructureTray.TypeProvider;
import eu.esdihumboldt.hale.ui.util.groovy.SimpleGroovySourceViewerConfiguration;
import eu.esdihumboldt.hale.ui.util.groovy.ast.GroovyAST;
import eu.esdihumboldt.hale.ui.util.source.CompilingSourceViewer;
/**
* Configuration page for custom property function script.
*
* @author Simon Templer
*/
@SuppressWarnings("restriction")
public class PropertyFunctionScriptPage extends GroovyScriptPage<CustomPropertyFunctionWizard>
implements CustomFunctionWizardPage {
// private final TestValues testValues;
/**
* Default constructor.
*/
public PropertyFunctionScriptPage() {
super();
setTitle("Custom function script");
setDescription("Specify a Groovy script to determine the output value or structure");
// testValues = new InstanceTestValues();
}
@Override
protected SourceViewerConfiguration createConfiguration() {
InstanceBuilderCompletions targetCompletions = new InstanceBuilderCompletions(
definitionImages) {
@Override
protected TypeDefinition getTargetType() {
DefaultCustomPropertyFunctionEntity targetDef = getWizard().getUnfinishedFunction()
.getTarget();
if (targetDef.getBindingType() != null) {
return targetDef.getBindingType();
}
else {
// simple or not specified type
return null;
}
}
};
return new SimpleGroovySourceViewerConfiguration(colorManager,
ImmutableList.of(BINDING_BUILDER, BINDING_TARGET, BINDING_SOURCE_TYPES,
BINDING_TARGET_TYPE, BINDING_CELL, BINDING_LOG, BINDING_CELL_CONTEXT,
BINDING_FUNCTION_CONTEXT, BINDING_TRANSFORMATION_CONTEXT,
CustomGroovyTransformation.BINDING_PARAMS),
ImmutableList.of(targetCompletions));
}
@Override
protected void onShowPage(boolean firstShow) {
super.onShowPage(firstShow);
// variables and settings may have changed
forceValidation();
}
@Override
protected boolean validate(String document) {
super.validate(document);
if (getWizard().getUnfinishedFunction() == null)
return false;
@SuppressWarnings("unused")
List<DefaultCustomPropertyFunctionEntity> sources = getWizard().getUnfinishedFunction()
.getSources();
// TODO create test values and do validation?
// List<PropertyValue> values = new ArrayList<PropertyValue>();
// for (EntityDefinition var : getVariables()) {
// if (var instanceof PropertyEntityDefinition) {
// PropertyEntityDefinition property = (PropertyEntityDefinition) var;
// values.add(new PropertyValueImpl(testValues.get(property), property));
// }
// }
//
// Property targetProperty = (Property) CellUtil.getFirstEntity(getWizard()
// .getUnfinishedCell().getTarget());
// if (targetProperty == null) {
// // not yet selected (NewRelationWizard)
// return false;
// }
//
// InstanceBuilder builder = GroovyTransformation
// .createBuilder(targetProperty.getDefinition());
//
// Cell cell = getWizard().getUnfinishedCell();
//
// boolean useInstanceValues = CellUtil.getOptionalParameter(cell,
// GroovyTransformation.PARAM_INSTANCE_VARIABLES, Value.of(false)).as(Boolean.class);
//
// AlignmentService as = (AlignmentService) PlatformUI.getWorkbench().getService(
// AlignmentService.class);
// GroovyService gs = HaleUI.getServiceProvider().getService(GroovyService.class);
// Script script = null;
// try {
// Collection<? extends Cell> typeCells = as.getAlignment().getTypeCells(cell);
// // select one matching type cell, the script has to run for all
// // matching cells
// // if there is no matching cell it may produce a npe, which is okay
// Cell typeCell = null;
// if (!typeCells.isEmpty()) {
// typeCell = typeCells.iterator().next();
// }
// CellLog log = new CellLog(new DefaultTransformationReporter("dummy", false), cell);
// ExecutionContext context = new DummyExecutionContext(HaleUI.getServiceProvider());
// groovy.lang.Binding binding;
// if (cell.getTransformationIdentifier().equals(GroovyGreedyTransformation.ID)) {
// binding = GroovyGreedyTransformation.createGroovyBinding(values, null, cell,
// typeCell, builder, useInstanceValues, log, context);
// }
// else {
// binding = GroovyTransformation.createGroovyBinding(values, null, cell, typeCell,
// builder, useInstanceValues, log, context);
// }
// script = gs.parseScript(document, binding);
//
// GroovyTransformation.evaluate(script, builder, targetProperty.getDefinition()
// .getDefinition().getPropertyType(), gs);
// } catch (final Exception e) {
// return handleValidationResult(script, e);
// }
//
// return handleValidationResult(script, null);
return true;
}
/**
* Get the list of source entities configured as variables.
*
* @return the source entities configured as variables
*/
protected List<EntityDefinition> getVariables() {
List<DefaultCustomPropertyFunctionEntity> sources = getWizard().getUnfinishedFunction()
.getSources();
if (sources != null) {
List<EntityDefinition> result = new ArrayList<>();
for (DefaultCustomPropertyFunctionEntity source : sources) {
result.add(createDummyEntity(source, SchemaSpaceID.SOURCE));
}
return result;
}
return Collections.emptyList();
}
private EntityDefinition createDummyEntity(DefaultCustomPropertyFunctionEntity entity,
SchemaSpaceID ssid) {
DefaultTypeDefinition parent = new DefaultTypeDefinition(new QName("dummy"));
DefaultPropertyDefinition property = new DefaultPropertyDefinition(
new QName(entity.getName()), parent, createDummyType(entity));
property.setConstraint(
Cardinality.get(entity.getMinOccurrence(), entity.getMaxOccurrence()));
return new PropertyEntityDefinition(parent,
Collections.singletonList(new ChildContext(property)), ssid, null);
}
private TypeDefinition createDummyType(DefaultCustomPropertyFunctionEntity entity) {
if (entity.getBindingType() != null) {
return entity.getBindingType();
}
else if (entity.getBindingClass() != null) {
return createBindingDummy(entity.getBindingClass());
}
else {
return createBindingDummy(Object.class);
}
}
private TypeDefinition createBindingDummy(Class<?> clazz) {
DefaultTypeDefinition type = new DefaultTypeDefinition(new QName(clazz.getName()));
type.setConstraint(Binding.get(clazz));
type.setConstraint(HasValueFlag.ENABLED);
return type;
}
@Override
protected void addActions(ToolBar toolbar, CompilingSourceViewer<GroovyAST> viewer) {
super.addActions(toolbar, viewer);
PageHelp.createToolItem(toolbar, this);
TypeStructureTray.createToolItem(toolbar, this, SchemaSpaceID.SOURCE, new TypeProvider() {
@Override
public Collection<? extends TypeDefinition> getTypes() {
// create a dummy type with the variables as children
DefaultTypeDefinition dummy = new DefaultTypeDefinition(
TypeStructureTray.VARIABLES_TYPE_NAME);
DefaultCustomPropertyFunction cf = getWizard().getUnfinishedFunction();
int index = 0;
for (EntityDefinition variable : getVariables()) {
DefaultCustomPropertyFunctionEntity source = cf.getSources().get(index);
if (variable.getDefinition() instanceof PropertyDefinition) {
PropertyDefinition prop = (PropertyDefinition) variable.getDefinition();
TypeDefinition propertyType;
boolean useInstanceValue = CustomGroovyTransformation
.useInstanceVariableForSource(source);
if (useInstanceValue) {
// use instance type
propertyType = prop.getPropertyType();
}
else {
// use dummy type with only the
// binding/HasValueFlag copied
DefaultTypeDefinition crippledType = new DefaultTypeDefinition(
prop.getPropertyType().getName());
crippledType.setConstraint(
prop.getPropertyType().getConstraint(Binding.class));
crippledType.setConstraint(
prop.getPropertyType().getConstraint(HasValueFlag.class));
propertyType = crippledType;
}
DefaultPropertyDefinition dummyProp = new DefaultPropertyDefinition(
new QName(source.getName()), dummy, propertyType);
// for greedy transformation the property can occur any
// number of times
if (source.isEager())
dummyProp.setConstraint(Cardinality.CC_ANY_NUMBER);
}
index++;
}
return Collections.singleton(dummy);
}
});
TypeStructureTray.createToolItem(toolbar, this, SchemaSpaceID.TARGET, new TypeProvider() {
@Override
public Collection<? extends TypeDefinition> getTypes() {
DefaultCustomPropertyFunctionEntity target = getWizard().getUnfinishedFunction()
.getTarget();
if (target != null) {
return Collections.singleton(createDummyType(target));
}
return Collections.emptyList();
}
});
}
@Override
public void apply() {
DefaultCustomPropertyFunction cf = getWizard().getResultFunction();
if (cf == null)
return;
cf.setFunctionType(CustomPropertyFunctionType.GROOVY);
List<ParameterValue> script = getConfiguration().get(PARAMETER_SCRIPT);
if (script != null && !script.isEmpty()) {
cf.setFunctionDefinition(script.get(0));
}
else {
cf.setFunctionDefinition(Value.NULL);
}
}
@Override
protected void createContent(Composite page) {
getConfiguration().clear();
DefaultCustomPropertyFunction cf = getWizard().getResultFunction();
if (cf.getFunctionDefinition() != null) {
ListMultimap<String, ParameterValue> initialValues = ArrayListMultimap.create();
initialValues.put(PARAMETER_SCRIPT, new ParameterValue(cf.getFunctionDefinition()));
setParameter(Collections.<FunctionParameterDefinition> emptySet(), initialValues);
}
super.createContent(page);
}
@Override
public String getHelpContext() {
return "eu.esdihumboldt.cst.functions.groovy.script";
}
}