/*
* 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.lang.ref.SoftReference;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import com.rapidminer.gui.renderer.RendererService;
import com.rapidminer.operator.IOObject;
import com.rapidminer.operator.UserError;
import com.rapidminer.operator.ports.Port;
import com.rapidminer.operator.ports.Ports;
import com.rapidminer.operator.ports.metadata.MetaDataError;
import com.rapidminer.operator.ports.quickfix.QuickFix;
import com.rapidminer.tools.AbstractObservable;
/** Implemented by keeping a weak reference to the data that can be cleared at any time
* by the garbage collector.
*
* In addition to the week reference, this class also keeps
* a hard reference to the data, freeing it when calling {@link #freeMemory()}.
*
* @author Simon Fischer
*
*/
public abstract class AbstractPort extends AbstractObservable<Port> implements Port {
private final List<MetaDataError> errorList = new LinkedList<MetaDataError>();
private final Ports<? extends Port> ports;
private String name;
private SoftReference<IOObject> weakDataReference;
private IOObject hardDataReference;
private final boolean simulatesStack;
private boolean locked = false;
protected AbstractPort(Ports<? extends Port> owner, String name, boolean simulatesStack) {
this.name = name;
this.ports = owner;
this.simulatesStack = simulatesStack;
}
protected final void setData(IOObject object) {
this.weakDataReference = new SoftReference<IOObject>(object);
this.hardDataReference = object;
}
@Override
public final <T extends IOObject> T getData() throws UserError {
T data = this.<T>getDataOrNull();
if (data == null) {
throw new UserError(getPorts().getOwner().getOperator(), 149, getSpec() + (isConnected() ? " (connected)" : " (disconnected)"));
} else {
return data;
}
}
@Override
public final IOObject getAnyDataOrNull() {
if (hardDataReference != null) {
return hardDataReference;
} else {
return this.weakDataReference != null ? this.weakDataReference.get() : null;
}
}
@Override
public final <T extends IOObject> T getData(Class<T> desiredClass) throws UserError {
IOObject data = getData();
if (desiredClass.isAssignableFrom(data.getClass())) {
return desiredClass.cast(data);
} else {
throw new UserError(getPorts().getOwner().getOperator(), 156, RendererService.getName(data.getClass()), this.getName(), RendererService.getName(desiredClass));
}
}
@Override
public final <T extends IOObject> T getDataOrNull() throws UserError {
IOObject data = getAnyDataOrNull();
try {
return (T) data;
} catch (ClassCastException e) {
throw new UserError(getPorts().getOwner().getOperator(), 150, data.getClass().getSimpleName());
}
}
@Override
public final String getName() {
return name;
}
@Override
public String toString() {
return getSpec();
}
@Override
public Ports<? extends Port> getPorts() {
return ports;
}
@Override
public String getShortName() {
if (name.length() > 3) {
return name.substring(0, 3);
} else {
return name;
}
}
/** Don't use this method. Use {@link Ports#renamePort(Port,String)}. */
protected void setName(String newName) {
this.name = newName;
}
@Override
public void addError(MetaDataError metaDataError) {
errorList.add(metaDataError);
}
@Override
public Collection<MetaDataError> getErrors() {
return Collections.unmodifiableCollection(errorList);
}
@Override
public void clear(int clearFlags) {
if ((clearFlags & CLEAR_META_DATA_ERRORS) > 0) {
this.errorList.clear();
}
if ((clearFlags & CLEAR_DATA) > 0) {
this.weakDataReference = null;
this.hardDataReference = null;
}
}
@Override
public List<QuickFix> collectQuickFixes() {
List<QuickFix> fixes = new LinkedList<QuickFix>();
for (MetaDataError error : getErrors()) {
fixes.addAll(error.getQuickFixes());
}
Collections.sort(fixes);
return fixes;
}
@Override
public String getSpec() {
if (getPorts() != null) {
return getPorts().getOwner().getOperator().getName() + "." + getName();
} else {
return "DUMMY."+getName();
}
}
@Override
public boolean simulatesStack() {
return simulatesStack;
}
@Override
public boolean isLocked() {
return locked;
}
@Override
public void unlock() {
this.locked = false;
}
@Override
public void lock() {
this.locked = true;
}
/** Releases of the hard reference. */
@Override
public void freeMemory() {
this.hardDataReference = null;
}
}