blob: 38f8c1c48245ab305dfcb8d3f543a287d8b3f330 [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2018 The University of York.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.epsilon.eol.launch;
import java.util.*;
import org.eclipse.epsilon.common.concurrent.ConcurrencyUtils;
import org.eclipse.epsilon.common.launch.ProfilableRunConfiguration;
import org.eclipse.epsilon.common.parse.problem.ParseProblem;
import org.eclipse.epsilon.common.util.CollectionUtil;
import org.eclipse.epsilon.common.util.StringProperties;
import static org.eclipse.epsilon.common.util.profiling.BenchmarkUtils.profileExecutionStage;
import org.eclipse.epsilon.eol.exceptions.EolParseException;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.exceptions.models.EolModelLoadingException;
import org.eclipse.epsilon.eol.execute.context.IEolContext;
import org.eclipse.epsilon.eol.execute.context.concurrent.EolContextParallel;
import org.eclipse.epsilon.eol.execute.context.concurrent.IEolContextParallel;
import org.eclipse.epsilon.eol.execute.control.ExecutionController;
import org.eclipse.epsilon.eol.execute.control.ExecutionProfiler;
import org.eclipse.epsilon.eol.models.CachedModel;
import org.eclipse.epsilon.eol.models.IModel;
import org.eclipse.epsilon.eol.models.ModelRepository;
import org.eclipse.epsilon.eol.EolModule;
import org.eclipse.epsilon.eol.IEolModule;
import org.eclipse.epsilon.eol.concurrent.EolModuleParallel;
/**
* Convenience class for running EOL programs over models.
*
* @author Sina Madani
* @since 1.6
*/
public class EolRunConfiguration extends ProfilableRunConfiguration {
public final Map<IModel, StringProperties> modelsAndProperties;
public final Map<String, Object> parameters;
protected boolean loadModels;
private final IEolModule module;
public static Builder<? extends EolRunConfiguration, ?> Builder() {
return new Builder<>(EolRunConfiguration.class);
}
public EolRunConfiguration(Builder<? extends EolRunConfiguration, ?> builder) {
super(builder);
this.parameters = builder.parameters;
this.modelsAndProperties = builder.modelsAndProperties;
this.loadModels = builder.loadModels;
this.module = Objects.requireNonNull(builder.module, "Module cannot be null!");
IEolContext context = module.getContext();
if (builder.isParallel() && builder.parallelism > 0 && context instanceof IEolContextParallel) {
IEolContextParallel pContext = (IEolContextParallel) context;
pContext.setParallelism(builder.parallelism);
}
this.id = Optional.ofNullable(builder.id).orElseGet(() ->
Objects.hash(
super.id,
Objects.toString(this.modelsAndProperties),
Objects.toString(this.module.getSourceUri())
)
);
}
public EolRunConfiguration(EolRunConfiguration other) {
super(other);
this.modelsAndProperties = other.modelsAndProperties;
this.module = other.module;
this.parameters = other.parameters;
this.loadModels = other.loadModels;
}
/**
*
* @return The concrete instance of IEolModule.
*/
public IEolModule getModule() {
return module;
}
@Override
protected void preExecute() throws Exception {
super.preExecute();
if (isFirstRepeat()) {
prepareModule();
}
else if (targetRepeats > 1) {
module.getContext().getFrameStack().dispose();
prepareFrameStack();
}
if (modelsAndProperties != null && !modelsAndProperties.isEmpty()) {
addModelsToRepo();
if (loadModels && (isFirstRepeat() || targetRepeats == 1)) {
loadModels();
}
}
}
protected void addModelsToRepo() throws Exception {
ModelRepository modelRepo = module.getContext().getModelRepository();
for (Map.Entry<IModel, StringProperties> modelAndProp : modelsAndProperties.entrySet()) {
IModel model = modelAndProp.getKey();
if (!modelRepo.getModels().contains(model)) {
modelRepo.addModel(model);
}
}
}
protected void prepareModule() throws Exception {
if (profileExecution) {
profileExecutionStage(profiledStages, "Parsing script", () -> module.parse(script));
}
else {
module.parse(script);
}
Collection<ParseProblem> parseProblems = module.getParseProblems();
if (!parseProblems.isEmpty()) {
writeOut(parseProblems);
throw new EolParseException(parseProblems);
}
prepareFrameStack();
module.getContext().setProfilingEnabled(profileExecution);
}
protected void prepareFrameStack() {
if (!parameters.isEmpty()) {
module.getContext().getFrameStack().put(parameters, false);
}
}
protected final void loadModels() throws EolModelLoadingException {
if (profileExecution) {
profileExecutionStage(profiledStages, "Loading model(s)", this::loadModelsImpl);
}
else {
this.loadModelsImpl();
}
}
protected void loadModelsImpl() throws EolModelLoadingException {
for (Map.Entry<IModel, StringProperties> modelAndProp : modelsAndProperties.entrySet()) {
IModel model = modelAndProp.getKey();
if (!(model instanceof CachedModel) || !((CachedModel<?>) model).isLoaded()) {
StringProperties modelProperties = modelAndProp.getValue();
if (modelProperties != null) {
model.load(modelProperties);
}
else {
model.load();
}
}
}
}
@Override
public void reset() throws Exception {
super.reset();
module.getContext().dispose();
}
public void dispose() throws Exception {
reset();
module.getContext().getFrameStack().dispose();
module.getContext().getModelRepository().dispose();
}
@Override
protected Object execute() throws EolRuntimeException {
Object execResult;
if (profileExecution) {
if (module instanceof ProfilableIEolModule) {
ProfilableIEolModule profMod = (ProfilableIEolModule) module;
execResult = profMod.profileExecution();
profiledStages.addAll(profMod.getProfiledStages());
}
else {
execResult = profileExecutionStage(profiledStages, "execute()", module::execute);
}
}
else {
execResult = module.execute();
}
return execResult;
}
@Override
protected List<Object> getProfilingOutput() {
ExecutionController executionController = getModule().getContext().getExecutorFactory().getExecutionController();
List<Object> prof = new ArrayList<>(super.getProfilingOutput());
if (executionController instanceof ExecutionProfiler) {
prof.addAll(Arrays.asList(printMarker, executionController));
}
return prof;
}
@Override
public String toString() {
return super.toString()+
", moduleClass="+module.getClass().getName()+
", module="+module+
"', models='"+Objects.toString(modelsAndProperties)+"'";
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), module, modelsAndProperties);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!super.equals(obj)) return false;
EolRunConfiguration other = (EolRunConfiguration) obj;
return
Objects.equals(this.module, other.module) &&
CollectionUtil.equalsIgnoreOrder(this.modelsAndProperties.keySet(), other.modelsAndProperties.keySet());
}
@SuppressWarnings("unchecked")
public static class Builder<C extends EolRunConfiguration, B extends Builder<C, B>> extends ProfilableRunConfiguration.Builder<C, B> {
protected Builder() {
super();
}
protected Builder(Class<C> runConfigClass) {
super(runConfigClass);
}
@Override
public C build() {
if (module == null) {
module = createModule();
}
module.getContext().setProfilingEnabled(profileExecution);
return buildReflective(() -> {
class InstantiableEOC extends EolRunConfiguration {
public InstantiableEOC(Builder<C, B> builder) {
super(builder);
}
};
return (C) new InstantiableEOC(this);
});
}
protected IEolModule createModule() {
return isParallel() ? new EolModuleParallel(new EolContextParallel(parallelism)) : new EolModule();
}
public IEolModule module;
public Map<IModel, StringProperties> modelsAndProperties = new LinkedHashMap<>(4);
public Map<String, Object> parameters = new LinkedHashMap<>(4);
public boolean loadModels = true;
public int parallelism = Integer.MIN_VALUE;
protected boolean sequential = false;
public B skipModelLoading() {
return loadModels(false);
}
public B withModelLoading(boolean load) {
return loadModels(load);
}
public B loadModels(boolean load) {
this.loadModels = load;
return (B) this;
}
public B withModule(IEolModule module) {
this.module = module;
return (B) this;
}
public B withModel(IModel model) {
return withModel(model, null);
}
public B withModel(IModel model, StringProperties properties) {
this.modelsAndProperties.put(model, properties);
return (B) this;
}
public B withModels(Map<IModel, StringProperties> modelsAndProps) {
this.modelsAndProperties.putAll(modelsAndProps);
return (B) this;
}
public B withModels(IModel... models) {
for (IModel model : models) {
withModel(model);
}
return (B) this;
}
public B withProperties(Map<?, ?> properties) {
modelsAndProperties.values().forEach(prop -> prop.putAll(properties));
return (B) this;
}
public B withProperty(String name, Object value) {
modelsAndProperties.values().forEach(prop -> prop.put(name, value));
return (B) this;
}
public B withParameter(String name, Object value) {
this.parameters.put(name, value);
return (B) this;
}
public B withParameters(Map<String, Object> params) {
this.parameters.putAll(params);
return (B) this;
}
public B withParallelism(int parallelism) {
sequential = (this.parallelism = parallelism) < 0;
return (B) this;
}
public B withParallelism() {
return parallel(true);
}
public B sequential() {
return parallel(false);
}
public B parallel(boolean parallel) {
return withParallelism(parallel ? ConcurrencyUtils.DEFAULT_PARALLELISM : Integer.MIN_VALUE);
}
public B parallel() {
return parallel(true);
}
public boolean isSequential() {
return sequential;
}
public boolean isParallel() {
return parallelism > -1;
}
}
}