it.unibo.alchemist.model.implementations.actions.RunProtelisProgram.java Source code

Java tutorial

Introduction

Here is the source code for it.unibo.alchemist.model.implementations.actions.RunProtelisProgram.java

Source

/*
 * Copyright (C) 2010-2015, Danilo Pianini and contributors
 * listed in the project's pom.xml file.
 * 
 * This file is part of Alchemist, and is distributed under the terms of
 * the GNU General Public License, with a linking exception, as described
 * in the file LICENSE in the Alchemist distribution's top directory.
 */
package it.unibo.alchemist.model.implementations.actions;

import java.io.IOException;
import java.io.ObjectInputStream;
import org.apache.commons.math3.random.RandomGenerator;
import org.danilopianini.lang.LangUtils;
import org.danilopianini.util.ListSet;
import org.protelis.lang.ProtelisLoader;
import org.protelis.vm.ExecutionContext;
import org.protelis.vm.ProtelisVM;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import it.unibo.alchemist.model.implementations.molecules.SimpleMolecule;
import it.unibo.alchemist.model.implementations.nodes.ProtelisNode;
import it.unibo.alchemist.model.interfaces.Action;
import it.unibo.alchemist.model.interfaces.Context;
import it.unibo.alchemist.model.interfaces.Environment;
import it.unibo.alchemist.model.interfaces.Molecule;
import it.unibo.alchemist.model.interfaces.Node;
import it.unibo.alchemist.model.interfaces.Reaction;
import it.unibo.alchemist.protelis.AlchemistExecutionContext;
import it.unibo.alchemist.protelis.AlchemistNetworkManager;

/**
 */
@SuppressFBWarnings(value = "EQ_DOESNT_OVERRIDE_EQUALS", justification = "This is desired.")
public class RunProtelisProgram implements Action<Object> {

    private static final long serialVersionUID = 2207914086772704332L;
    private boolean computationalCycleComplete;
    private final Environment<Object> environment;
    private final Molecule name;
    private final ProtelisNode node;
    private String originalProgram = "unknown";
    private final org.protelis.vm.ProtelisProgram program;
    @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "All the random engines provided by Apache are Serializable")
    private final RandomGenerator random;
    private final Reaction<Object> reaction;
    private final double retentionTime;
    private transient ProtelisVM vm;

    private RunProtelisProgram(final Environment<Object> env, final ProtelisNode n, final Reaction<Object> r,
            final RandomGenerator rand, final org.protelis.vm.ProtelisProgram prog, final double retentionTime) {
        //        super(prog.getName());
        name = new SimpleMolecule(prog.getName());
        LangUtils.requireNonNull(env, r, n, prog, rand);
        program = prog;
        environment = env;
        node = n;
        random = rand;
        reaction = r;
        final AlchemistNetworkManager netmgr = new AlchemistNetworkManager(environment, node, reaction, this,
                retentionTime);
        node.addNetworkManger(this, netmgr);
        final ExecutionContext ctx = new AlchemistExecutionContext(env, n, r, rand, netmgr);
        vm = new ProtelisVM(prog, ctx);
        this.retentionTime = retentionTime;
    }

    /**
     * @param env
     *            the environment
     * @param n
     *            the node
     * @param r
     *            the reaction
     * @param rand
     *            the random engine
     * @param prog
     *            the Protelis program
     * @throws SecurityException
     *             if you are not authorized to load required classes
     * @throws ClassNotFoundException
     *             if required classes can not be found
     */
    public RunProtelisProgram(final Environment<Object> env, final ProtelisNode n, final Reaction<Object> r,
            final RandomGenerator rand, final String prog) throws SecurityException, ClassNotFoundException {
        this(env, n, r, rand, prog, Double.NaN);
    }

    /**
     * @param env
     *            the environment
     * @param n
     *            the node
     * @param r
     *            the reaction
     * @param rand
     *            the random engine
     * @param prog
     *            the Protelis program
     * @param retentionTime
     *            how long the messages will be stored. Pass {@link Double#NaN}
     *            to mean that they should get eliminated upon node awake.
     * @throws SecurityException
     *             if you are not authorized to load required classes
     * @throws ClassNotFoundException
     *             if required classes can not be found
     */
    public RunProtelisProgram(final Environment<Object> env, final ProtelisNode n, final Reaction<Object> r,
            final RandomGenerator rand, final String prog, final double retentionTime)
            throws SecurityException, ClassNotFoundException {
        this(env, n, r, rand, ProtelisLoader.parse(prog), retentionTime);
        originalProgram = prog;
    }

    /**
     * @return the molecule associated with the execution of this program
     */
    public final Molecule asMolecule() {
        return name;
    }

    @Override
    public RunProtelisProgram cloneAction(final Node<Object> n, final Reaction<Object> r) {
        if (n instanceof ProtelisNode) {
            try {
                return new RunProtelisProgram(getEnvironment(), (ProtelisNode) n, r, getRandomGenerator(),
                        originalProgram, getRetentionTime());
            } catch (SecurityException | ClassNotFoundException e) {
                throw new IllegalStateException(e);
            }
        }
        throw new IllegalArgumentException("The node must be a " + ProtelisNode.class.getSimpleName());
    }

    @Override
    public boolean equals(final Object other) {
        if (other == this) {
            return true;
        }
        if (other != null && other.getClass() == getClass()) {
            return name.equals(((RunProtelisProgram) other).name);
        }
        return false;
    }

    @Override
    public void execute() {
        vm.runCycle();
        node.setConcentration(name, vm.getCurrentValue());
        computationalCycleComplete = true;
    }

    @Override
    public Context getContext() {
        /*
         * A Protelis program never writes in other nodes
         */
        return Context.LOCAL;
    }

    /**
     * @return the environment
     */
    protected final Environment<Object> getEnvironment() {
        return environment;
    }

    @Override
    public ListSet<? extends Molecule> getModifiedMolecules() {
        /*
         * A Protelis program may modify any molecule (global variable)
         */
        return null;
    }

    /**
     * @return the node
     */
    protected final ProtelisNode getNode() {
        return node;
    }

    /**
     * @return the internal {@link RandomGenerator}
     */
    protected RandomGenerator getRandomGenerator() {
        return random;
    }

    /**
     * @return the retention time
     */
    protected double getRetentionTime() {
        return retentionTime;
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }

    /**
     * @return true if the Program has finished its last computation, and is ready to send a new message (used for dependency management)
     */
    public boolean isComputationalCycleComplete() {
        return computationalCycleComplete;
    }

    /**
     * Resets the computation status (used for dependency management).
     */
    public void prepareForComputationalCycle() {
        this.computationalCycleComplete = false;
    }

    private void readObject(final ObjectInputStream stream) throws ClassNotFoundException, IOException {
        stream.defaultReadObject();
        final AlchemistNetworkManager netmgr = new AlchemistNetworkManager(environment, node, reaction, this);
        node.addNetworkManger(this, netmgr);
        vm = new ProtelisVM(program, new AlchemistExecutionContext(environment, node, reaction, random, netmgr));
    }

    @Override
    public String toString() {
        return name + "@" + node.getId();
    }

}