/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it 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.
*
* The Whole Platform 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.workflows.visitors;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Set;
import org.whole.lang.artifacts.model.IArtifactsEntity;
import org.whole.lang.artifacts.util.ResourceArtifactsOperations;
import org.whole.lang.artifacts.visitors.ArtifactsDeleteVisitor;
import org.whole.lang.artifacts.visitors.ArtifactsSynchronizerVisitor;
import org.whole.lang.artifacts.visitors.ArtifactsSynchronizerVisitor.Synchronize;
import org.whole.lang.artifacts.visitors.ArtifactsSynchronizerVisitor.Traverse;
import org.whole.lang.bindings.BindingManagerFactory;
import org.whole.lang.bindings.IBindingManager;
import org.whole.lang.bindings.IBindingScope;
import org.whole.lang.bindings.ITransactionScope;
import org.whole.lang.codebase.ClasspathPersistenceProvider;
import org.whole.lang.codebase.FilePersistenceProvider;
import org.whole.lang.codebase.IPersistenceKit;
import org.whole.lang.codebase.IPersistenceProvider;
import org.whole.lang.codebase.StringPersistenceProvider;
import org.whole.lang.codebase.URLPersistenceProvider;
import org.whole.lang.commons.parsers.CommonsDataTypePersistenceParser;
import org.whole.lang.commons.reflect.CommonsEntityDescriptorEnum;
import org.whole.lang.commons.visitors.CommonsInterpreterVisitor;
import org.whole.lang.exceptions.IWholeRuntimeException;
import org.whole.lang.exceptions.WholeIllegalArgumentException;
import org.whole.lang.factories.GenericEntityFactory;
import org.whole.lang.factories.IEntityFactory;
import org.whole.lang.factories.IEntityRegistryProvider;
import org.whole.lang.factories.RegistryConfigurations;
import org.whole.lang.grammars.model.Grammar;
import org.whole.lang.grammars.util.GrammarsUtils;
import org.whole.lang.iterators.IEntityIterator;
import org.whole.lang.iterators.IteratorFactory;
import org.whole.lang.java.codebase.JavaClassTemplateFactory;
import org.whole.lang.java.model.CompilationUnit;
import org.whole.lang.java.util.JavaReflectUtils;
import org.whole.lang.matchers.Matcher;
import org.whole.lang.model.IEntity;
import org.whole.lang.model.NullEntity;
import org.whole.lang.model.adapters.IEntityAdapter;
import org.whole.lang.operations.ArtifactsGeneratorOperation;
import org.whole.lang.operations.InterpreterOperation;
import org.whole.lang.operations.NormalizerOperation;
import org.whole.lang.operations.PrettyPrinterOperation;
import org.whole.lang.operations.ValidatorOperation;
import org.whole.lang.parsers.ParseException;
import org.whole.lang.queries.iterators.QueriesIteratorFactory;
import org.whole.lang.reflect.EntityDescriptor;
import org.whole.lang.reflect.FeatureDescriptor;
import org.whole.lang.reflect.ReflectionFactory;
import org.whole.lang.templates.ITemplateFactory;
import org.whole.lang.util.BehaviorUtils;
import org.whole.lang.util.DataTypeUtils;
import org.whole.lang.util.EntityUtils;
import org.whole.lang.visitors.MissingVariableException;
import org.whole.lang.visitors.VisitException;
import org.whole.lang.workflows.model.Arguments;
import org.whole.lang.workflows.model.Assign;
import org.whole.lang.workflows.model.AssignActivity;
import org.whole.lang.workflows.model.Assignments;
import org.whole.lang.workflows.model.BooleanLiteral;
import org.whole.lang.workflows.model.Condition;
import org.whole.lang.workflows.model.ConditionalCase;
import org.whole.lang.workflows.model.CreateEntity;
import org.whole.lang.workflows.model.CreateJavaClassInstance;
import org.whole.lang.workflows.model.CreateModel;
import org.whole.lang.workflows.model.DeleteArtifacts;
import org.whole.lang.workflows.model.EmptyActivity;
import org.whole.lang.workflows.model.Expression;
import org.whole.lang.workflows.model.Expressions;
import org.whole.lang.workflows.model.ForeachLoop;
import org.whole.lang.workflows.model.IWorkflowsEntity;
import org.whole.lang.workflows.model.IntLiteral;
import org.whole.lang.workflows.model.InvokeJavaClassMethod;
import org.whole.lang.workflows.model.InvokeJavaInstanceMethod;
import org.whole.lang.workflows.model.InvokeOperation;
import org.whole.lang.workflows.model.InvokeQuery;
import org.whole.lang.workflows.model.LoadArtifacts;
import org.whole.lang.workflows.model.LoadJavaModel;
import org.whole.lang.workflows.model.LoadModel;
import org.whole.lang.workflows.model.Name;
import org.whole.lang.workflows.model.ObjectLiteral;
import org.whole.lang.workflows.model.OperationEnum;
import org.whole.lang.workflows.model.Parallel;
import org.whole.lang.workflows.model.Parse;
import org.whole.lang.workflows.model.PersistenceActivity;
import org.whole.lang.workflows.model.RegistryEnum;
import org.whole.lang.workflows.model.ResourceKind;
import org.whole.lang.workflows.model.ResourceKindEnum;
import org.whole.lang.workflows.model.SaveArtifacts;
import org.whole.lang.workflows.model.SaveModel;
import org.whole.lang.workflows.model.Sequence;
import org.whole.lang.workflows.model.StringLiteral;
import org.whole.lang.workflows.model.SwitchControl;
import org.whole.lang.workflows.model.SwitchTypeEnum;
import org.whole.lang.workflows.model.Task;
import org.whole.lang.workflows.model.Text;
import org.whole.lang.workflows.model.Unparse;
import org.whole.lang.workflows.model.Variable;
import org.whole.lang.workflows.model.WhileLoop;
import org.whole.lang.workflows.reflect.WorkflowsEntityDescriptorEnum;
/**
* @author Riccardo Solmi, Enrico Persiani
*/
public class WorkflowsInterpreterVisitor extends WorkflowsTraverseAllVisitor {
@Override
public InterpreterOperation getOperation() {
return (InterpreterOperation) super.getOperation();
}
@Override
public void setResultIterator(IEntityIterator<?> iterator) {
if (iterator != null)
iterator.setBindings(getBindings());
super.setResultIterator(iterator);
}
protected void setResult(Variable variable, IEntity model) {
if (DataTypeUtils.getDataKind(variable).isString())
getBindings().wDef(variable.getValue(), model);
setResult(model);
}
protected void setResult(Variable variable, Object resultValue, Class<?> resultType) {
if (resultValue instanceof IEntityIterator) {
setResultIterator((IEntityIterator<?>) resultValue);
} else if (Void.TYPE.equals(resultType)) {
if (EntityUtils.isNotResolver(variable))
throw new IllegalArgumentException("cannot bind a void result");
setResult(null);
} else
setResult(variable, box(resultValue, resultType));
}
protected String getResultString() {
return getResult().wStringValue();
}
protected Object getResultValue() {
return getResult().wGetValue();
}
protected void setResultValue(Object value) {
setResult(BindingManagerFactory.instance.createSpecificValue(value));
}
protected void evaluate(IWorkflowsEntity composite) {
setResult(null);
if (composite.wIsAdapter())
CommonsInterpreterVisitor.visitAdapter((IEntityAdapter) composite, getOperation());
else
composite.accept(this);
}
public void visit(Task entity) {
entity.getAssignments().accept(this);
entity.getDescription().accept(this);
String description = PrettyPrinterOperation.toPrettyPrintString(getResult());
Reader reader = getOperation().getReader();
try {
if (!reader.ready()) {
PrintWriter printWriter = getOperation().getPrintWriter();
printWriter.println(description);
printWriter.println("Confirm task completion[Yes/no]: ");
printWriter.flush();
}
BufferedReader bufferedReader = new BufferedReader(reader);
if (bufferedReader.readLine().equalsIgnoreCase("no"))
throw new VisitException("task not completed: "+description);
} catch (IOException e) {
throw new VisitException(e);
}
}
@Override
public void visit(Sequence entity) {
entity.getFlowObjects().accept(this);
}
@Override
public void visit(Parallel entity) {
entity.getFlowObjects().accept(this);
}
//TODO ? remove from interpreter or add to model ?
// public void visit(Repeat entity) {
// for (int i=0; i<entity.getTimes().wIntValue(); i++)
// entity.getFlowObject().accept(this);
// }
public void visit(WhileLoop entity) {
Condition condition = entity.getCondition();
while (BehaviorUtils.evaluatePredicate(condition, 0, getBindings())) {
handleCancelRequest();
entity.getFlowObject().accept(this);
}
}
protected void resetIterator(IEntityIterator<?> iterator) {
IEntity selfEntity = getBindings().wGet("self");
iterator.reset(selfEntity != null ? selfEntity : NullEntity.instance);
}
@Override
public void visit(ForeachLoop entity) {
evaluate(entity.getCompositeVariable());
IEntityIterator<?> iterator = null;
if (isResultIterator()) {
iterator = getResultIterator();
setResultIterator(null);
resetIterator(iterator);
} else {
IEntity result = getResult();
if (result == null)
return;
iterator = IteratorFactory.childIterator();
iterator.setBindings(getBindings());
iterator.reset(result);
}
Variable elementVariable = entity.getElementVariable();
String elementVar = DataTypeUtils.getDataKind(elementVariable).isString() ?
elementVariable.wStringValue() : null;
Variable indexVariable = entity.getIndexVariable();
String indexVar = DataTypeUtils.getDataKind(indexVariable).isString() ?
indexVariable.wStringValue() : null;
int index = 0;
while (iterator.hasNext()) {
handleCancelRequest();
if (indexVar != null)
getBindings().wDefValue(indexVar, index++);
if (elementVar != null)
getBindings().wDef(elementVar, iterator.next());
entity.getFlowObject().accept(this);
}
}
@Override
public void visit(SwitchControl entity) {
boolean isExclusive = entity.getSwitchType().wContainsValue(SwitchTypeEnum.exclusive);
IEntityIterator<ConditionalCase> i = IteratorFactory.childIterator();
i.reset(entity.getConditionalCases());
boolean executed = false;
while ((!isExclusive || !executed) && i.hasNext()) {
i.next().accept(this);
executed |= getResult().wBooleanValue();
}
if (!executed)
entity.getDefaultCase().accept(this);
}
//TODO ? remove from interpreter or add to model ?
// public void visit(DoWhileControl entity) {
// do {
// entity.getFlowObject().accept(visitor1);
// } while (booleanValue(entity.getCondition()));
// }
public void visit(ConditionalCase entity) {
Condition condition = entity.getCondition();
boolean isSatisfied = BehaviorUtils.evaluatePredicate(condition, 0, getBindings());
if (isSatisfied)
entity.getFlowObject().accept(this);
setResultValue(isSatisfied);
}
//TODO ? remove from interpreter or add to model ?
// public void visit(IfElseControl entity) {
// if (booleanValue(entity.getCondition()))
// entity.getTrueFlowObject().accept(visitor1);
// else
// entity.getFalseFlowObject().accept(visitor1);
// }
@Override
public void visit(BooleanLiteral entity) {
setResult(BindingManagerFactory.instance.createValue(entity.wBooleanValue()));
}
@Override
public void visit(IntLiteral entity) {
setResult(BindingManagerFactory.instance.createValue(entity.wIntValue()));
}
@Override
public void visit(StringLiteral entity) {
setResult(BindingManagerFactory.instance.createValue(entity.wStringValue()));
}
@Override
public void visit(ObjectLiteral entity) {
setResult(entity);
}
@Override
public void visit(Name entity) {
setResult(entity);
}
@Override
public void visit(ResourceKind entity) {
setResult(entity);
}
@Override
public void visit(Text entity) {
setResult(BindingManagerFactory.instance.createValue(entity.wStringValue()));
}
@Override
public void visit(Variable entity) {
IEntity result = getBindings().wGet(entity.getValue());
if (result == null)
throw new MissingVariableException(entity.getValue()).withSourceEntity(entity).withBindings(getBindings());
setResult(result);
}
@Override
public void visit(EmptyActivity entity) {
}
@Override
public void visit(AssignActivity entity) {
entity.getAssignments().accept(this);
}
@Override
public void visit(Assignments entity) {
define(getBindings(), entity);
}
public void define(IBindingScope bm, Assignments assignments) {
IEntity selfEntity = bm.wGet("self");
for (int i = 0; i < assignments.wSize(); i++) {
Assign assign = assignments.get(i);
define(bm, assign);
if (!assign.getName().getValue().equals("self"))
resetSelfEntity(selfEntity);
}
}
public void define(IBindingScope bm, Assign entity) {
String name = entity.getName().getValue();
evaluate(entity.getExpression());
if (isResultIterator()) {
IEntityIterator<?> iterator = getResultIterator();
setResultIterator(null);
resetIterator(iterator);
if (iterator.hasNext()) {
IEntity first = iterator.next();
if (iterator.hasNext()) {
final IEntity values = BindingManagerFactory.instance.createTuple();
values.wAdd(first);
do {
values.wAdd(iterator.next());
} while (iterator.hasNext());
bm.wDef(name, values);
} else
bm.wDef(name, first);
}
} else if (getResult() != null)
bm.wDef(name, getResult());
}
@Override
public void visit(InvokeOperation entity) {
try {
IBindingManager bm = getBindings();
bm.wEnterScope();
entity.getBindings().accept(this);
entity.getModel().accept(this);
IEntity model = getResult();
switch (entity.getOperation().getValue().getOrdinal()) {
case OperationEnum.VALIDATOR_ord:
ValidatorOperation.validate(model, bm);
break;
case OperationEnum.NORMALIZER_ord:
NormalizerOperation.normalize(model, bm);
break;
case OperationEnum.PRETTY_PRINTER_ord:
PrettyPrinterOperation.prettyPrint(model, bm);
break;
case OperationEnum.INTERPRETER_ord:
InterpreterOperation.interpret(model, bm, (Reader) null, (Writer) null);
break;
case OperationEnum.ARTIFACTS_GENERATOR_ord:
ArtifactsGeneratorOperation.generate(model, bm);
break;
case OperationEnum.JAVA_COMPILER_ord:
performJavaCompilerOperation(model);
}
bm.wExitScope();
//FIXME workaround
if (OperationEnum.NORMALIZER == entity.getOperation().getValue())
bm.setResult(model);
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
protected void performJavaCompilerOperation(IEntity model) {
throw new UnsupportedOperationException("The Eclipse JDT is not available");
}
@Override
public void visit(InvokeQuery entity) {
Variable queryName = entity.getQueryName();
Arguments arguments = entity.getArguments();
IEntityIterator<? extends IEntity>[] argsIterators = new IEntityIterator<?>[0];
Set<String> filterNames = getOperation().getResultsScope().wNames();
IBindingManager args = BindingManagerFactory.instance.createBindingManager(
BindingManagerFactory.instance.createExcludeFilterScope(filterNames).wWithEnclosingScope(getBindings()),
getBindings().wGetEnvironmentManager());
if (!EntityUtils.isNotResolver(arguments)) {
setResultValue(argsIterators);
arguments.accept(this);
argsIterators = (IEntityIterator<?>[]) getResultValue();
} else if (Matcher.match(WorkflowsEntityDescriptorEnum.Expressions, arguments)) {
IEntity selfEntity = getBindings().wGet("self");
argsIterators = new IEntityIterator<?>[arguments.wSize()];
for (int i = 0; i < argsIterators.length; i++) {
((Expressions) arguments).get(i).accept(this);
argsIterators[i] = getResultIterator();
setResultIterator(null);
resetSelfEntity(selfEntity);
}
} else
define(args, (Assignments) arguments);
IEntityIterator<?> iterator = QueriesIteratorFactory.callIterator(
queryName.getValue(), argsIterators);
iterator.setBindings(args);
resetIterator(iterator);
while (iterator.hasNext())
iterator.next();
}
@Override
public void visit(CreateEntity entity) {
try {
entity.getEntityName().accept(this);
String typeName = getResultString();
EntityDescriptor<?> ed = CommonsDataTypePersistenceParser.parseEntityDescriptor(typeName);
if (ed == null)
throw new WholeIllegalArgumentException("The requested entity does not exist: "+typeName).withSourceEntity(entity).withBindings(getBindings());
IEntityRegistryProvider provider = null;
switch (entity.getRegistry().getValue().getOrdinal()) {
case RegistryEnum.DEFAULT_ord:
provider = RegistryConfigurations.DEFAULT;
break;
case RegistryEnum.RESOLVER_ord:
provider = RegistryConfigurations.RESOLVER;
break;
case RegistryEnum.ADAPTER_ord:
provider = RegistryConfigurations.ADAPTER;
break;
case RegistryEnum.STRICT_ord:
provider = RegistryConfigurations.STRICT;
break;
case RegistryEnum.CUSTOM_ord:
provider = RegistryConfigurations.CUSTOM;
break;
}
IEntityFactory ef = GenericEntityFactory.instance(provider);
IEntity model;
Arguments arguments = entity.getArguments();
if (Matcher.matchImpl(WorkflowsEntityDescriptorEnum.Assignments, arguments)) {
ITransactionScope resettableScope = BindingManagerFactory.instance.createTransactionScope();
getBindings().wEnterScope(resettableScope);
arguments.accept(this);
for (int i = 0; i < arguments.wSize(); i++) {
String name = ((Assignments) arguments).get(i).getName().getValue();
FeatureDescriptor fd = ed.getFeatureDescriptorEnum().valueOf(name);
if (fd != null)
getBindings().wDef(name, EntityUtils.convertCloneIfReparenting(getBindings().wGet(name), ed.getEntityFeatureDescriptor(fd)));
}
model = ef.create(ed, getBindings());
resettableScope.rollback();
getBindings().wExitScope();
} else if (Matcher.matchImpl(WorkflowsEntityDescriptorEnum.Expressions, arguments)) {
IEntity selfEntity = getBindings().wGet("self");
if (ed.getEntityKind().isData()) {
((Expressions) arguments).get(0).accept(this);
model = DataTypeUtils.convertCloneIfParented(getResult(), ed);
resetSelfEntity(selfEntity);
} else {
IEntity[] values = new IEntity[arguments.wSize()];
for (int i = 0; i < values.length; i++) {
((Expressions) arguments).get(i).accept(this);
values[i] = EntityUtils.convertCloneIfReparenting(getResult(), ed.getEntityFeatureDescriptor(i));
resetSelfEntity(selfEntity);
}
model = ef.create(ed, values);
}
} else
model = ef.create(ed);
setResult(entity.getModel(), model);
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
@Override
public void visit(CreateModel entity) {
ITransactionScope resettableScope = BindingManagerFactory.instance.createTransactionScope();
getBindings().wEnterScope(resettableScope);
entity.getBindings().accept(this);
entity.getTemplate().accept(this);
IEntity model = getResult();
//TODO remove ?
if (Matcher.matchImpl(WorkflowsEntityDescriptorEnum.Name, entity.getTemplate())) {
IEntityIterator<IEntity> tii = QueriesIteratorFactory.templateInterpreterIterator(getResult());
tii.setBindings(getBindings());
tii.reset(entity);
model = tii.next();
}
resettableScope.rollback();
getBindings().wExitScope();
setResult(entity.getModel(), model);
}
@Override
public void visit(LoadJavaModel entity) {
try {
IEntity model = getJavaTemplateFactory(entity).create();
setResult(entity.getModel(), model);
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
protected ITemplateFactory<CompilationUnit> getJavaTemplateFactory(LoadJavaModel entity) {
entity.getClassName().accept(this);
String className = getResultString();
if (!Matcher.matchImpl(WorkflowsEntityDescriptorEnum.ClassPath, entity.getClassProvider()))
throw new UnsupportedOperationException("The Eclipse Workspace is not available");
try {
return new JavaClassTemplateFactory(
Class.forName(className, false, ReflectionFactory.getClassLoader(getBindings())));
} catch (ClassNotFoundException e) {
throw new WholeIllegalArgumentException(e).withSourceEntity(entity).withBindings(getBindings());
}
}
@Override
public void visit(DeleteArtifacts entity) {
try {
entity.getModel().accept(this);
IArtifactsEntity model = (IArtifactsEntity) getResult();
entity.getRootResource().accept(this);
String resource = getResultString();
ResourceKind resourceKind = entity.getRootResourceKind();
IBindingManager bindings = createArtifactsBindings(resource, resourceKind);
ArtifactsDeleteVisitor.delete(model, bindings);
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
@Override
public void visit(LoadArtifacts entity) {
try {
IArtifactsEntity model = null;
Variable variable = entity.getModel();
String variableName = variable.getValue();
boolean isDefined = getBindings().wIsSet(variableName);
if (isDefined) {
variable.accept(this);
model = (IArtifactsEntity) getResult();
}
entity.getRootResource().accept(this);
String resource = getResultString();
ResourceKind resourceKind = entity.getRootResourceKind();
Traverse traverse = Traverse.valueOf(
DataTypeUtils.getAsPersistenceString(entity.getTraversalStrategy()));
Synchronize synchronize = Synchronize.valueOf(
DataTypeUtils.getAsPersistenceString(entity.getSynchronizeStrategy()));
IPersistenceKit defaultPersistenceKit = getPersistenceKit(entity.getDefaultPersistence());
IArtifactsEntity result = ArtifactsSynchronizerVisitor.synchronize(
model, traverse, synchronize, createArtifactsBindings(resource, resourceKind),
defaultPersistenceKit, true);
if (isDefined) {
if (EntityUtils.hasParent(model))
model.wGetParent().wSet(model, result);
getBindings().wSet(variableName, result);
} else
getBindings().wDef(variableName, result);
setResult(result);
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
@Override
public void visit(SaveArtifacts entity) {
try {
entity.getModel().accept(this);
IArtifactsEntity model = (IArtifactsEntity) getResult();
entity.getRootResource().accept(this);
String resource = getResultString();
ResourceKind resourceKind = entity.getRootResourceKind();
Traverse traverse = Traverse.valueOf(
DataTypeUtils.getAsPersistenceString(entity.getTraversalStrategy()));
Synchronize synchronize = Synchronize.valueOf(
DataTypeUtils.getAsPersistenceString(entity.getSynchronizeStrategy()));
IPersistenceKit defaultPersistenceKit = getPersistenceKit(entity.getDefaultPersistence());
ArtifactsSynchronizerVisitor.synchronize(
model, traverse, synchronize,
createArtifactsBindings(resource, resourceKind),
defaultPersistenceKit, false);
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
protected IBindingManager createArtifactsBindings(String resource, ResourceKind resourceKind) {
if (ResourceKindEnum.WORKSPACE.equals(resourceKind.getValue()))
throw new UnsupportedOperationException("The Eclipse Workspace is not available");
File rootResource = new File(resource);
if (!rootResource.exists())
throw new IllegalArgumentException("root resource does not exist");
IBindingManager bindings = BindingManagerFactory.instance.createArguments();
bindings.wDefValue("artifactsOperations", new ResourceArtifactsOperations());
bindings.wDefValue("rootResource", rootResource);
bindings.wDefValue("folder", rootResource.getParentFile());
bindings.wDefValue("folderLocation", rootResource.getParent());
bindings.wDef("resourceKind", resourceKind);
return bindings;
}
@Override
public void visit(LoadModel entity) {
try {
IPersistenceKit persistenceKit = getPersistenceKit(entity.getPersistence());
IPersistenceProvider provider = getPersistenceProvider(entity);
try {
IEntity model = persistenceKit.readModel(provider);
setResult(entity.getModel(), model);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to load the resource with the given persistence: "
+getResourceString(entity)+", "+getPersistenceId(entity.getPersistence()), e);
}
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
@Override
public void visit(SaveModel entity) {
try {
IPersistenceKit persistenceKit = getPersistenceKit(entity.getPersistence());
IPersistenceProvider provider = getPersistenceProvider(entity);
entity.getModel().accept(this);
IEntity model = getResult();
try {
persistenceKit.writeModel(model, provider);
afterWriteModel(entity, provider);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to save the resource with the given persistence: "
+getResourceString(entity)+", "+getPersistenceId(entity.getPersistence()), e);
}
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
protected String getResourceString(PersistenceActivity entity) {
ResourceKind resourceKind = getResourceKind(entity);
if (resourceKind.wContainsValue(ResourceKindEnum.VARIABLE)) {
Variable variable = (Variable) entity.getResource();
return variable.getValue();
} else {
entity.getResource().accept(this);
return getResultString();
}
}
protected ResourceKind getResourceKind(PersistenceActivity entity) {
ResourceKind resourceKind = entity.getResourceKind();
setResult(null);
resourceKind.accept(this);
return (ResourceKind) getResult();
}
protected String getPersistenceId(Expression entity) {
try {
entity.accept(this);
return getResultString();
} catch (Exception e) {
return null;
}
}
protected IPersistenceKit getPersistenceKit(Expression entity) {
try {
String persistenceId = getPersistenceId(entity);
return ReflectionFactory.hasPersistenceKit(persistenceId) ? ReflectionFactory.getPersistenceKit(persistenceId) : null;
} catch (Exception e) {
return null;
}
}
protected void afterWriteModel(SaveModel entity, IPersistenceProvider provider) throws Exception {
if (getResourceKind(entity).wContainsValue(ResourceKindEnum.VARIABLE)) {
String result = ((StringPersistenceProvider) provider).getStore();
Variable variable = (Variable) entity.getResource();
getBindings().wDefValue(variable.getValue(), result);
}
}
protected IPersistenceProvider getPersistenceProvider(PersistenceActivity entity) {
IBindingManager bm = BindingManagerFactory.instance.createBindingManager();
getBindings().wEnterScope(bm, true);
entity.getBindings().accept(this);
getBindings().wExitScope();
String resource = getResourceString(entity);
ResourceKind resourceKind = getResourceKind(entity);
switch (resourceKind.getValue().getOrdinal()) {
case ResourceKindEnum.FILE_SYSTEM_ord:
return getFileSystemProvider(bm, resource);
case ResourceKindEnum.WORKSPACE_ord:
return getWorkspaceProvider(bm, resource);
case ResourceKindEnum.CLASSPATH_ord:
ReflectionFactory.setClassLoader(bm, ReflectionFactory.getClassLoader(getBindings()));
return getClasspathProvider(bm, resource);
case ResourceKindEnum.URL_ord:
return getURLProvider(bm, resource);
case ResourceKindEnum.VARIABLE_ord:
return getStringProvider(bm, resource);
default:
throw new IllegalArgumentException("Unsupported resource kind");
}
}
protected IPersistenceProvider getFileSystemProvider(IBindingManager bm, String resourceString) {
try {
return new FilePersistenceProvider(new File(resourceString), bm);
} catch (Exception e) {
throw new IllegalArgumentException("Cannot access the resource: "+resourceString, e);
}
}
protected IPersistenceProvider getURLProvider(IBindingManager bm, String resourceString) {
try {
return new URLPersistenceProvider(new URL(resourceString), bm);
} catch (Exception e) {
throw new IllegalArgumentException("Cannot load the specified resource", e);
}
}
protected IPersistenceProvider getStringProvider(IBindingManager bm, String resourceString) {
return new StringPersistenceProvider(getBindings().wIsSet(resourceString) ? getBindings().wStringValue(resourceString) : "", bm);
}
protected IPersistenceProvider getWorkspaceProvider(IBindingManager bm, String resourceString) {
throw new UnsupportedOperationException("The Eclipse Workspace is not available");
}
protected IPersistenceProvider getClasspathProvider(IBindingManager bm, String resourceString) {
return new ClasspathPersistenceProvider(resourceString, bm);
}
@Override
public void visit(Parse entity) {
try {
entity.getText().accept(this);
CharSequence text = (CharSequence) getResultValue();
entity.getGrammar().accept(this);
IEntity grammarOrUri = getResult();
if (!EntityUtils.isData(grammarOrUri)) {
stagedVisit(grammarOrUri);
grammarOrUri = ((Grammar) grammarOrUri).getUri();
}
String grammarUri = grammarOrUri.wStringValue();
IEntity model;
if (EntityUtils.isNotResolver(entity.getNt())) {
entity.getNt().accept(this);
model = GrammarsUtils.parse(text, grammarUri, getResult().wStringValue());
} else
model = GrammarsUtils.parse(text, grammarUri);
setResult(entity.getModel(), model);
} catch (ParseException e) {
throw e;//FIXME ?
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
@Override
public void visit(Unparse entity) {
try {
entity.getGrammar().accept(this);
IEntity grammarOrUri = getResult();
if (!EntityUtils.isData(grammarOrUri)) {
stagedVisit(grammarOrUri);
grammarOrUri = ((Grammar) grammarOrUri).getUri();
}
String grammarUri = grammarOrUri.wStringValue();
entity.getModel().accept(this);
IEntity model = getResult();
Expression text = entity.getText();
Appendable appendable = new StringBuilder();
boolean hasAppendable = false;
String variableName = null;
if (Matcher.matchImpl(WorkflowsEntityDescriptorEnum.Variable, text)) {
variableName = ((Variable) text).getValue();
if (getBindings().wIsSet(variableName)) {
try {
appendable = (Appendable) getBindings().wGetValue(variableName);
hasAppendable = true;
} catch (Exception e) {
throw new IllegalArgumentException("The text of an Unparse activity must be an Appendable", e);
}
}
} else if (EntityUtils.isNotResolver(text)) {
text.accept(this);
appendable = (Appendable) getResultValue();
hasAppendable = true;
}
//TODO if (EntityUtils.isImpl(entity.getNt())) {
GrammarsUtils.unparse(model, appendable, grammarUri);
IEntity resultEntity = hasAppendable ? BindingManagerFactory.instance.createValue(appendable) :
BindingManagerFactory.instance.createValue(appendable.toString());
if (variableName != null && !getBindings().wIsSet(variableName))
getBindings().wDef(variableName, resultEntity);
setResult(resultEntity);
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
@Override
public void visit(CreateJavaClassInstance entity) {
try {
entity.getClassName().accept(this);
String className = getResultString();
entity.getConstructor().accept(this);
IEntity constructorData = getResult();
Constructor<?> constructor;
if (DataTypeUtils.getDataKind(constructorData).isString())
constructor = JavaReflectUtils.getConstructor(
className, constructorData.wStringValue(), ReflectionFactory.getClassLoader(getBindings()));
else
constructor = (Constructor<?>) constructorData.wGetValue();
Object[] arguments = toArguments(constructor.getParameterTypes(),
constructor.isVarArgs(), entity.getArguments());
Object resultValue = JavaReflectUtils.invokeConstructor(constructor, arguments);
setResult(entity.getResult(), resultValue, constructor.getDeclaringClass());
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
@Override
public void visit(InvokeJavaClassMethod entity) {
try {
entity.getClassName().accept(this);
String className = getResultString();
entity.getMethod().accept(this);
IEntity methodData = getResult();
Method method;
if (DataTypeUtils.getDataKind(methodData).isString())
method = JavaReflectUtils.getMethod(
className, methodData.wStringValue(), ReflectionFactory.getClassLoader(getBindings()));
else
method = (Method) methodData.wGetValue();
Object[] arguments = toArguments(method.getParameterTypes(),
method.isVarArgs(), entity.getArguments());
Object resultValue = JavaReflectUtils.invokeMethod(null, method, arguments);
setResult(entity.getResult(), resultValue, method.getReturnType());
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
@Override
public void visit(InvokeJavaInstanceMethod entity) {
try {
entity.getClassName().accept(this);
String className = getResultString();
entity.getMethod().accept(this);
IEntity methodData = getResult();
Method method;
if (DataTypeUtils.getDataKind(methodData).isString())
method = JavaReflectUtils.getMethod(
className, methodData.wStringValue(), ReflectionFactory.getClassLoader(getBindings()));
else
method = (Method) methodData.wGetValue();
Object[] arguments = toArguments(method.getParameterTypes(),
method.isVarArgs(), entity.getArguments());
Variable object = entity.getObject();
Object instance = unbox(method.getDeclaringClass(), object, false);
Object resultValue = JavaReflectUtils.invokeMethod(instance, method, arguments);
setResult(entity.getResult(), resultValue, method.getReturnType());
} catch (Exception e) {
throw IWholeRuntimeException.asWholeException(e, entity, getBindings());
}
}
private Object unbox(Class<?> parameterType, Expression expression) {
return unbox(parameterType, expression, true);
}
private Object unbox(Class<?> parameterType, Expression expression, boolean unboxResolver) {
setResult(null);
expression.accept(this);
IEntity result = getResult();
if (result == null)
throw new IllegalArgumentException("cannot evaluate expression: "+expression);
return DataTypeUtils.unbox(result, parameterType, unboxResolver);
}
private IEntity box(Object value, Class<?> resultType) {
if (value == null && !IEntity.class.isAssignableFrom(resultType))
return BindingManagerFactory.instance.createSpecificValue(
value, DataTypeUtils.toDataKind(resultType));
else
return DataTypeUtils.box(value, CommonsEntityDescriptorEnum.Any);
}
private Object[] toArguments(Class<?>[] parameterTypes, boolean varArgs, Expressions expressions) {
if (!EntityUtils.isNotResolver(expressions)) {
setResultValue(new Object[0]);
expressions.accept(this);
return (Object[]) getResultValue();
}
int expressionsSize = expressions.wSize();
if (expressionsSize < parameterTypes.length)
throw new IllegalArgumentException("wrong parameter number");
Object[] parameters = new Object[parameterTypes.length];
IEntity selfEntity = getBindings().wGet("self");
// map simple parameters
int length = parameterTypes.length - (varArgs ? 1 : 0);
for (int i = 0; i < length; i++) {
parameters[i] = unbox(parameterTypes[i], expressions.get(i));
resetSelfEntity(selfEntity);
}
// map varArgs parameters
if (varArgs) {
Class<?> parameterType = parameterTypes[length].getComponentType();
Object varArgsArray = Array.newInstance(parameterType,
expressionsSize - length);
for (int j = 0, i = length; i < expressionsSize; i++, j++) {
Array.set(varArgsArray, j, unbox(parameterType, expressions.get(i)));
resetSelfEntity(selfEntity);
}
parameters[length] = varArgsArray;
}
return parameters;
}
protected void resetSelfEntity(IEntity selfEntity) {
if (getBindings().wGet("self") != selfEntity)
if (getBindings().wIsSet("self"))
getBindings().wSet("self", selfEntity);
else
getBindings().wDef("self", selfEntity);
}
}