All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.integratedmodelling.engine.modelling.runtime.Task Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * 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.List;

import org.integratedmodelling.api.knowledge.IConcept;
import org.integratedmodelling.api.knowledge.IProperty;
import org.integratedmodelling.api.modelling.IActiveDirectObservation;
import org.integratedmodelling.api.modelling.IActiveSubject;
import org.integratedmodelling.api.modelling.IDirectObserver;
import org.integratedmodelling.api.modelling.IEvent;
import org.integratedmodelling.api.modelling.IKnowledgeObject;
import org.integratedmodelling.api.modelling.IModel;
import org.integratedmodelling.api.modelling.IModelBean;
import org.integratedmodelling.api.modelling.IObservableSemantics;
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.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.utils.CamelCase;
import org.integratedmodelling.common.utils.MiscUtilities;
import org.integratedmodelling.common.vocabulary.NS;
import org.integratedmodelling.common.vocabulary.ObservableSemantics;
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.monitor);
                this.target = (IActiveSubject) this.context.getSubject();
            }

            /*
             * legitimately null when we re-observe a ROI from the client side without
             * other observables.
             */
            if (this.target != null) {

                ((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 {

        if (this.observable instanceof IDirectObserver) {

            /*
             * add subject or event.
             */
            IActiveDirectObservation subj = KLAB.MFACTORY
                    .createSubject((IDirectObserver) this.observable, context, this.target, monitor);
            if (subj instanceof ISubject) {
                ((Subject) this.context.getSubject()).addSubject((ISubject) subj, null);
            } else if (subj instanceof IEvent) {
                ((Subject) this.context.getSubject()).addEvent((IEvent) subj);
            }

            return;
        }

        ((Subject) this.target).setMonitor(monitor);
        IObservableSemantics 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;
    }

    public static IObservableSemantics makeObservable(Object observable) {

        // CallTracer.indent("makeObservable()", this, observable);
        IObservableSemantics result;

        if (observable instanceof IModel) {
            result = new ObservableSemantics((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 ObservableSemantics((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 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());
        ret.setRunTask(runTask);

        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 - 2024 Weber Informatics LLC | Privacy Policy