/* * RapidMiner * * Copyright (C) 2001-2011 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.operator.ports.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import com.rapidminer.operator.IOContainer; import com.rapidminer.operator.IOObject; import com.rapidminer.operator.ports.InputPort; import com.rapidminer.operator.ports.OutputPort; import com.rapidminer.operator.ports.Port; import com.rapidminer.operator.ports.PortException; import com.rapidminer.operator.ports.PortExtender; import com.rapidminer.operator.ports.PortOwner; import com.rapidminer.operator.ports.Ports; import com.rapidminer.tools.AbstractObservable; import com.rapidminer.tools.LogService; import com.rapidminer.tools.Observable; import com.rapidminer.tools.Observer; /** * @author Simon Fischer */ public abstract class AbstractPorts<T extends Port> extends AbstractObservable<Port> implements Ports<T> { private final List<T> portList = new ArrayList<T>(); private final Map<String,T> portMap = new HashMap<String,T>(); private String[] portNames; private boolean portNamesValid = false; private final PortOwner owner; private final Observer<Port> delegatingObserver = new Observer<Port>() { @Override public void update(Observable<Port> observable, Port arg) { fireUpdate(arg); } }; public AbstractPorts(PortOwner owner) { this.owner = owner; portNamesValid = false; } private void updatePortNames() { if (!portNamesValid) { portNames = new String[portList.size()]; int i = 0; for (Port port : portList) { portNames[i++] = port.getName(); } portNamesValid = true; } } @Override public void addPort(T port) throws PortException { if (portMap.containsKey(port.getName())) { throw new PortException("Port name already used: "+port.getName()); } assert(port.getPorts() == this); portList.add(port); portMap.put(port.getName(), port); portNamesValid = false; port.addObserver(delegatingObserver, false); fireUpdate(port); } @Override public void removePort(T port) throws PortException { if (!portList.contains(port) || (port.getPorts() != this)) { throw new PortException("Cannot remove " + port + "."); } else { if (port.isConnected()) { if (port instanceof OutputPort) { ((OutputPort)port).disconnect(); } else { ((InputPort)port).getSource().disconnect(); } } portList.remove(port); portMap.remove(port.getName()); port.removeObserver(delegatingObserver); fireUpdate(); } } @Override public void removeAll() { // don't iterate to avoid concurrent modification while (getNumberOfPorts() != 0) { removePort(getPortByIndex(0)); } } @Override public int getNumberOfPorts() { return portList.size(); } @Override public T getPortByIndex(int index) { return portList.get(index); } @Override public T getPortByName(String name) { T port = portMap.get(name); if (port != null) { return port; } else { LogService.getRoot().fine("Port '"+name+"' does not exist. Checking for extenders."); if (portExtenders != null) { for (PortExtender extender : portExtenders) { String prefix = extender.getNamePrefix(); if (name.startsWith(prefix)) { LogService.getRoot().fine("Found extender with prefix '"+prefix+"'. Trying to extend."); try { int index = Integer.parseInt(name.substring(prefix.length())); extender.ensureMinimumNumberOfPorts(index); // numbering starts at 1 T secondTry = portMap.get(name); if (secondTry == null) { LogService.getRoot().warning("Port extender "+prefix+" did not extend to size "+index+"."); } else { LogService.getRoot().fine("Port was created. Ports are now: "+getAllPorts()); } return secondTry; } catch (NumberFormatException e) { LogService.getRoot().log(Level.WARNING, "Cannot extend "+prefix+": "+e, e); return null; } } } } // no extender found return null; } } @Override public String[] getPortNames() { updatePortNames(); return portNames; } public List<T> getAllPorts() { return Collections.unmodifiableList(portList); } public String getMetaDataDescription() { StringBuilder b = new StringBuilder(); for (Port port : portList) { b.append(port.getName()); b.append(": "); b.append(port.getMetaData()); b.append("; "); } return b.toString(); } @Override public PortOwner getOwner() { return owner; } @Override public boolean containsPort(T port) { return portList.contains(port); } public void renamePort(T port, String newName) { if (portMap.containsKey(newName)) { throw new PortException("Port name already used: "+port.getName()); } portMap.remove(port.getName()); ((AbstractPort)port).setName(newName); portMap.put(newName, port); } @Override public void clear(int clearFlags) { for (T port : getAllPorts()) { port.clear(clearFlags); } } public IOContainer createIOContainer(boolean onlyConnected) { Collection<IOObject> output = new LinkedList<IOObject>(); for (Port port : getAllPorts()) { if (!onlyConnected || port.isConnected()) { IOObject data = port.getAnyDataOrNull(); if (data != null) { output.add(data); } } } return new IOContainer(output); } @Override public void pushDown(T port) { if (!portList.contains(port)) { throw new PortException("Cannot push down "+port.getName()+": port does not belong to "+this); } portList.remove(port); portList.add(port); } private List<PortExtender> portExtenders; public void registerPortExtender(PortExtender extender) { if (portExtenders == null) { portExtenders = new LinkedList<PortExtender>(); } portExtenders.add(extender); } public void unlockPortExtenders() { if (portExtenders != null) { for (PortExtender extender : portExtenders) { extender.ensureMinimumNumberOfPorts(0); } } } @Override public void freeMemory() { for (Port inputPort : getAllPorts()) { inputPort.freeMemory(); } } @Override public int getNumberOfConnectedPorts() { int count = 0; for (Port port : getAllPorts()) { if (port.isConnected()) { count++; } } return count; } @Override public String toString() { StringBuilder b = new StringBuilder(); boolean first = true; for (String port : getPortNames()) { if (first) { first = false; } else { b.append(", "); } b.append(port); } return b.toString(); } }