/*OsmUi is a user interface for Osmosis Copyright (C) 2011 Verena Käfer, Peter Vollmer, Niklas Schnelle This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, 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 GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * */ package de.osmui.model.pipelinemodel; import java.util.List; import java.util.Observable; import de.osmui.i18n.I18N; import de.osmui.model.exceptions.TasksNotCompatibleException; import de.osmui.model.exceptions.TasksNotInModelException; /** * This is the abstract base class for all pipeline models * * @author Niklas Schnelle, Peter Vollmer, Verena Käfer * * @see AbstractPipelineModelTest * */ public abstract class AbstractPipelineModel extends Observable { /** * Gets all Source Tasks in the model, that is the Tasks without any * inputPipes one normally traverses the model from the SourceTasks to the * drains using the Task objects * * @return the list of SourceTasks */ public abstract List<AbstractTask> getSourceTasks(); /** * Adds the given task to the model * * @param task */ public abstract void addTask(AbstractTask task); /** * Adds the the child Task to the model using the parent task as parent, * that is connecting a compatible output of the parent to a compatible * input of the child. If there are no compatible pipes a * TasksNotCompatibleException will be thrown. If the parent is not yet in * the model TasksNotInModelException will be thrown * * @param parent * @param child * @throws TasksNotCompatibleException * @throws TasksNotInModelException */ public abstract void addTask(AbstractTask parent, AbstractTask child) throws TasksNotCompatibleException, TasksNotInModelException; /** * Removes the given task from the model, if successfull returns true false * otherwise * * @param task * @return boolean indicating success * @throws TasksNotInModelException */ public abstract boolean removeTask(AbstractTask task) throws TasksNotInModelException; /** * Cleans the model, all tasks will be removed */ public abstract void clean(); /** * Connects the given tasks using the first parameter as parent task of the * second parameter. If there is no compatible pipe left a * TasksNotCompatibleException will be thrown. The first unconnected * outputPipe of the parent that has an unconnected and compatible port on * the child will be connected with this port. The pipe with which the * connection was made is returned * * @param parent * @param child * @throws TasksNotCompatibleException * @throws TasksNotInModelException */ public AbstractPipe connectTasks(AbstractTask parent, AbstractTask child) throws TasksNotCompatibleException, TasksNotInModelException { if (parent == null || child == null) { throw new TasksNotCompatibleException(I18N.getString("AbstractPipelineModel.parentChildNull")); } else if (parent.getModel() != this || child.getModel() != this) { throw new TasksNotInModelException(I18N.getString("AbstractPipelineModel.parentChildNotInModel")); } else { // Test outputPipes of the parent for compatibility with ports on // the child List<AbstractPipe> pipes = parent.getOutputPipes(); List<AbstractPort> ports = child.getInputPorts(); boolean outVariable = false; boolean inVariable = false; // First check for unconnected pipes then we can also look for variable ones for (AbstractPipe out : pipes) { if(!out.isConnected()){ for (AbstractPort in : ports) { if(!(in.isConnected()) && out.getType().equals(in.getType())){ if(out.connect(in)){ return out; } else { throw new TasksNotCompatibleException(I18N.getString("AbstractPipelineModel.connectFaild")); } } } } } // If we got nothing yet check variable pipes for (AbstractPipe out : pipes) { outVariable = out instanceof VariablePipe; if(outVariable){ for (AbstractPort in : ports) { inVariable = in instanceof VariablePort; // test if types match if(out.getType().equals(in.getType())){ if(outVariable){ // Lets create a new pipe and reuse out out = ((VariablePipe) out).createPipe(); out.getSource().getOutputPipes().add(out); } if(inVariable){ // Lets create a new port and reuse in in = ((VariablePort) in).createPort(); in.getParent().getInputPorts().add(in); } if(out.connect(in)){ return out; } else { throw new TasksNotCompatibleException(I18N.getString("AbstractPipelineModel.connectFailed")); } } } } } // We haven't returned in the loop so no compatible pipe/port was // found throw throw new TasksNotCompatibleException(I18N.getString("AbstractPipelineModel.givenTasksNotComp")); } } /** * Connects the given output pipe with the given input port, if both corresponding tasks are in this * model * * @param outputAbstractPipe output, AbstractPort input * @param input * @return * @throws TasksNotCompatibleException * @throws TasksNotInModelException */ public AbstractPipe connectTasks(AbstractPipe output, AbstractPort input) throws TasksNotCompatibleException, TasksNotInModelException { if(output == null || input == null){ return null; } else { //The parent of the port is the child of the pipe, easy isn't it? AbstractTask child = input.getParent(); AbstractTask parent = output.getSource(); if(child.getModel() != this || parent.getModel() != this){ throw new TasksNotInModelException(I18N.getString("AbstractPipelineModel.parentChildNotInModel")); } else if (output.isConnected() || input.isConnected() || !output.connect(input)){ throw new TasksNotCompatibleException(I18N.getString("AbstractPipelineModel.parentChildNotCompatiblePort")); } return output; } } /** * Disconnects the two tasks if they were connected, does nothing otherwise * * @param parent * @param child * @return the pipe that was unconnected, null if nothing was disconnected */ public AbstractPipe disconnectTasks(AbstractTask parent, AbstractTask child) throws TasksNotInModelException { if (parent == null || child == null) { // Can't connect with null return null return null; } else if (parent.getModel() != this || child.getModel() != this) { throw new TasksNotInModelException(I18N.getString("AbstractPipelineModel.parentChildNotInModel")); } else { // First we need to find the connection between the two and then // remove it List<AbstractPipe> pipes = parent.getOutputPipes(); for (AbstractPipe out : pipes) { if (out.getTarget().getParent().equals(child)) { out.disconnect(); return out; } } return null; } } /** * Gets whether this model currently represents a executable pipeline that * is a pipeline that can be executed by osmosis * * @return true if executable false otherwise */ public abstract boolean isExecutable(); /** * @return Boolean for existing Pipe */ public abstract boolean isEmpty(); }