
org.integratedmodelling.engine.modelling.runtime.Task Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (C) 2007, 2015:
*
* - Ferdinando Villa - integratedmodelling.org - any
* other authors listed in @author annotations
*
* All rights reserved. This file is part of the k.LAB software suite, meant to enable
* modular, collaborative, integrated development of interoperable data and model
* components. For details, see http://integratedmodelling.org.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the Affero General Public License Version 3 or 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 Affero General Public License for more details.
*
* You should have received a copy of the Affero General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA. The license is also available at:
* https://www.gnu.org/licenses/agpl.html
*******************************************************************************/
package org.integratedmodelling.engine.modelling.runtime;
import java.util.Date;
import java.util.List;
import org.integratedmodelling.api.knowledge.IConcept;
import org.integratedmodelling.api.knowledge.IProperty;
import org.integratedmodelling.api.modelling.IActiveSubject;
import org.integratedmodelling.api.modelling.IDirectObserver;
import org.integratedmodelling.api.modelling.IKnowledgeObject;
import org.integratedmodelling.api.modelling.IModel;
import org.integratedmodelling.api.modelling.IModelBean;
import org.integratedmodelling.api.modelling.IObservable;
import org.integratedmodelling.api.modelling.ISubject;
import org.integratedmodelling.api.modelling.resolution.IDataflow;
import org.integratedmodelling.api.modelling.resolution.IResolution;
import org.integratedmodelling.api.modelling.scheduling.ITransition;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.monitoring.Messages;
import org.integratedmodelling.api.provenance.IProvenance;
import org.integratedmodelling.api.runtime.IContext;
import org.integratedmodelling.common.beans.Transition;
import org.integratedmodelling.common.configuration.KLAB;
import org.integratedmodelling.common.interfaces.NetworkSerializable;
import org.integratedmodelling.common.monitoring.Monitor;
import org.integratedmodelling.common.owl.Knowledge;
import org.integratedmodelling.common.provenance.ObservationAction;
import org.integratedmodelling.common.utils.CamelCase;
import org.integratedmodelling.common.utils.MiscUtilities;
import org.integratedmodelling.common.vocabulary.NS;
import org.integratedmodelling.common.vocabulary.Observable;
import org.integratedmodelling.engine.introspection.CallTracer;
import org.integratedmodelling.engine.scripting.ModelProxy;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import org.integratedmodelling.exceptions.KlabValidationException;
import com.ibm.icu.text.NumberFormat;
/*
* Tasks basically drive the context through observations. It's a little awkward without a
* Task being a member of Context, but I'd rather keep the class files shorter although
* the continuous reference to the context member looks weird.
* @author ferdinando.villa
*/
public class Task extends AbstractBaseTask implements NetworkSerializable {
private Context context;
private Object observable;
private boolean optional = false;
private List scenarios;
private IActiveSubject target;
private ITransition lastTransition;
private IDataflow dataflow;
private IResolution resolution;
private String exception;
/*
* when true, this task runs temporal transitions on a previously initialized context.
*/
private boolean runTask;
/**
* Created for first observations by {@link Context#observeInternal}
*
* @param context
* @param monitor
* @param scenarios
*/
Task(Context context, IMonitor monitor, List scenarios) {
super(monitor);
this.context = context;
this.session = context.getSession();
this.scenarios = scenarios;
this.description = (context.getSubject() == null ? context.deferredObservableId
: context.getSubject().getName());
this.target = (IActiveSubject) context.getSubject();
}
/**
* Created for secondary observations by {@link Context#observeInternal}
*
* @param context
* @param monitor
* @param scenarios
*/
Task(Context context, IMonitor monitor, List scenarios, Object observable,
ISubject targetSubject) {
this(context, monitor, scenarios);
this.target = (IActiveSubject) targetSubject;
this.observable = observable;
this.description = this.observable + " in " + this.context.getSubject().getName();
}
/**
* When this is used, run() will run the temporal actions. Use through
* {@link #newTemporalTransitionTask()} for understandable semantics.
*/
private Task(Context context, IMonitor monitor) {
super(monitor);
this.context = context;
this.session = context.getSession();
runTask = true;
this.target = (IActiveSubject) context.getSubject();
this.description = "temporal contextualization of " + this.context.getSubject().getName();
}
/**
* Create
*
* @param context
* @param monitor
* @return a task that will run the temporal transitions in the passed context.
*/
public static Task newTemporalTransitionTask(Context context, IMonitor monitor) {
return new Task(context, monitor);
}
@Override
public IContext finish() {
for (;;) {
synchronized (this.status) {
if (this.status == Status.FINISHED || this.status == Status.ERROR
|| this.status == Status.INTERRUPTED) {
break;
}
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
this.status = Status.INTERRUPTED;
Thread.currentThread().interrupt();
}
}
return this.context;
}
@Override
public void run() {
/*
* use a task monitor with this task's ID after resolution.
*/
IMonitor monitor = ((Monitor) this.context.getMonitor()).get(this);
monitor.send(this);
try {
if (this.context.isDeferred) {
this.context.resolveObservable();
this.target = (IActiveSubject) this.context.getSubject();
}
((Subject) this.target).setMonitor(monitor);
if (this.runTask) {
monitor.info("running temporal transitions", Messages.INFOCLASS_MODEL);
this.target.contextualize();
} else {
/*
* establish the context - either a previous one or a new one if we're
* observing a new subject - and notify the listener.
*/
if (this.observable == null) {
observeSubject(monitor);
} else {
/*
* ensure strings and the like are resolved to something valid.
*/
this.observable = resolveObservable(this.observable);
observeInContext(monitor);
}
}
} catch (Exception e) {
synchronized (this.status) {
this.status = Status.ERROR;
}
this.exception = MiscUtilities.throwableToString(e);
monitor.send(Messages.TASK_FAILED);
// monitor.error(e);
} finally {
if (this.status != Status.ERROR) {
monitor.send(Messages.TASK_FINISHED);
}
this.endTime = System.currentTimeMillis();
synchronized (this.status) {
if (this.status != Status.ERROR) {
this.status = Status.FINISHED;
}
}
}
}
private void observeSubject(IMonitor monitor) throws KlabException {
try {
/*
* record original observation
*/
// IProvenance.Action userAction = context.provenance
// .add(context.provenance.getUser(), new ObservationAction(), context.provenance
// .get(target));
((Subject) this.target).setContext(this.context);
((Subject) this.target).setMonitor(monitor);
this.context
.setCoverage(((Subject) this.target)
.initialize(this.context.resolutionContext, null /* userAction */, monitor));
this.context.status = Context.INITIALIZED;
if (this.context.getCoverage().isEmpty()) {
monitor.error("subject initialization failed: empty coverage");
}
} catch (Throwable e) {
monitor.error(e);
}
}
private void observeInContext(IMonitor monitor) throws KlabException {
((Subject) this.target).setMonitor(monitor);
IObservable observable = makeObservable(this.observable);
if (observable.getModel() != null && observable.getModel().getErrorCount() > 0) {
// TODO find where the errors are stored and report them. They're in
// _errors
// but no way to get
// them out.
monitor.error("model " + observable.getModel().getId() + " has runtime errors");
throw new KlabException("cannot observe model " + observable.getModel().getId()
+ ": runtime errors");
}
/*
* record user action
*/
// IProvenance.Action userAction = context.provenance
// .add(context.provenance.getUser(), new ObservationAction(), context.provenance
// .get(observable));
this.context
.setCoverage(((Subject) this.target)
.observe(observable, this.scenarios, optional, /* userAction */ null, monitor));
if (!this.context.getCoverage().isEmpty()) {
monitor.info("observation of " + observable.getFormalName() + " in "
+ this.context.getSubject().getName()
+ " covers " + NumberFormat.getPercentInstance()
.format(this.context.getCoverage().getCoverage()), Messages.INFOCLASS_MODEL);
} else {
monitor.warn("observation of " + observable.getFormalName() + " in "
+ this.context.getSubject().getName()
+ " is empty");
}
}
Object resolveObservable(Object observable) throws KlabException {
// CallTracer.indent("resolveObservable()", this, observable);
Object ret = null;
if (observable instanceof String) {
if (observable.toString().contains(":")) {
ret = Knowledge.parse(observable.toString());
if (ret instanceof IProperty) {
throw new KlabValidationException("relationships cannot be observed directly: " + ret);
}
} else {
ret = KLAB.MMANAGER.findModelObject(observable.toString());
}
} else if (observable instanceof IKnowledgeObject) {
ret = KLAB.c(((IKnowledgeObject) observable).getName());
} else if (observable instanceof IConcept || observable instanceof IModel
|| observable instanceof IDirectObserver) {
ret = observable;
} else if (observable instanceof ModelProxy) {
ret = ((ModelProxy) observable).getModel();
}
if (ret == null) {
// CallTracer.msg("ERROR: unable to observe the given observable parameter.");
// CallTracer.unIndent();
throw new KlabValidationException("unable to observe " + observable);
}
// CallTracer.msg("returning valid observable: " + CallTracer.detailedDescription(ret));
// CallTracer.unIndent();
return ret;
}
private IObservable makeObservable(Object observable) {
// CallTracer.indent("makeObservable()", this, observable);
IObservable result;
if (observable instanceof IModel) {
result = new Observable((IModel) observable, ((IModel) observable).getId());
// CallTracer.msg("got Observable result for IModel parameter: "
// + CallTracer.detailedDescription(result));
// CallTracer.unIndent();
return result;
} else if (observable instanceof IConcept) {
result = new Observable((IConcept) observable, NS.getObservationTypeFor((IConcept) observable),
// TODO use current subject type for inherency
CamelCase.toLowerCase(((IConcept) observable).getLocalName(), '-'));
// CallTracer.msg("got Observable result for IConcept parameter: "
// + CallTracer.detailedDescription(result));
// CallTracer.unIndent();
return result;
}
// CallTracer.msg("parameter was not IConcept or IModel. returning null.");
// CallTracer.unIndent();
return null;
}
@Override
public IContext getContext() {
return this.context;
}
@SuppressWarnings("unchecked")
@Override
public T serialize(Class extends IModelBean> desiredClass) {
if (!desiredClass.isAssignableFrom(org.integratedmodelling.common.beans.Task.class)) {
throw new KlabRuntimeException("cannot serialize a Task to a " + desiredClass.getCanonicalName());
}
org.integratedmodelling.common.beans.Task ret = new org.integratedmodelling.common.beans.Task();
ret.setId(getTaskId());
ret.setDescription(getDescription());
ret.setEndTime(getEndTime());
ret.setStartTime(getStartTime());
ret.setStatus(getStatus().name());
ret.setContextId(getContext().getId());
ret.setSessionId(getContext().getSession().getId());
if (lastTransition != null) {
ret.setCurrentTransition(KLAB.MFACTORY.adapt(lastTransition, Transition.class));
}
if (exception != null) {
ret.setException(exception);
exception = null;
}
return (T) ret;
}
@Override
public IDataflow getDataflow() {
return this.dataflow;
}
public void setCurrentTransition(ITransition result) {
lastTransition = result;
}
@Override
public IResolution getResolution() {
return this.resolution;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy