/*
* Copyright (C) 2013 Serdar
*
* 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
* (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 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.fub.maps.project.detector.model.pipeline.postprocessors.tasks;
import static de.fub.maps.project.api.process.ProcessState.ERROR;
import static de.fub.maps.project.api.process.ProcessState.INACTIVE;
import static de.fub.maps.project.api.process.ProcessState.RUNNING;
import de.fub.maps.project.detector.model.Detector;
import de.fub.maps.project.detector.model.inference.InferenceModelResultDataSet;
import de.fub.maps.project.detector.model.pipeline.preprocessors.FilterProcess;
import de.fub.maps.project.detector.model.process.AbstractDetectorProcess;
import de.fub.maps.project.detector.model.process.DetectorProcess;
import de.fub.maps.project.detector.model.xmls.ProcessDescriptor;
import de.fub.utilsmodule.icons.IconRegister;
import de.fub.utilsmodule.node.CustomAbstractnode;
import de.fub.utilsmodule.node.property.ProcessProperty;
import de.fub.utilsmodule.synchronizer.ModelSynchronizer;
import java.awt.Image;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.List;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
/**
* Task represent a postprocessor that will be applied by an inferenceModel.
*
* @author Serdar
*/
public abstract class Task extends AbstractDetectorProcess<InferenceModelResultDataSet, Void> {
private InferenceModelResultDataSet resultDataSet;
public Task() {
}
/**
* Set the Result of the classification via a InferenceModel as input for
* this task.
*
* @param input an InferenceModelResultData instance, null not permitted.
*/
@Override
public void setInput(InferenceModelResultDataSet input) {
this.resultDataSet = input;
}
protected InferenceModelResultDataSet getResultDataSet() {
return resultDataSet;
}
/**
* Task don't have any result.
*
* @return null
*/
@Override
public Void getResult() {
return null;
}
/**
* Provides a way to cancel this task process execution. Default this method
* does nothing. Subclasses should overwrite this mothod, if they want to
* provide a way to cancel the process.
*
* @return default false;
*/
@Override
public boolean cancel() {
return false;
}
/**
* Creates the visual representer of this Task.
*
* @return Node instance, null not permitted.
*/
@Override
protected Node createNodeDelegate() {
return new TaskProcessNode(Task.this);
}
/**
* Returns the Icon, which the visuel representer of this task should use.
* Subclasses can overwrite this method to provide another image
* representations.
*
* @return Image instance
*/
@Override
protected Image getDefaultImage() {
return IconRegister.findRegisteredIcon("processIconNormal.png");
}
/**
* Factory method to get a collection of all via
* <code>@ServiceProvider</code> registered Task implementations.
*
* @return a list of Task instances.
*/
public static synchronized Collection<Task> findAll() {
return findAll(Task.class);
}
/**
* Finds and creates the via ProcessDescriptor specified Task
* implementation, and configures the Task with provided ProcessDescriptor
* and Detector instance.
*
* @param descriptor ProcessDescriptor instance, null not permitted.
* @param detector Detector instance or null.
* @return Detector instance
* @throws
* de.fub.maps.project.detector.model.process.DetectorProcess.DetectorProcessNotFoundException
* if the within specified Task implementations could not be found, because
* it is not registered via the <code>@ServiceProvider</code> annotation.
*/
public static synchronized Task find(ProcessDescriptor descriptor, Detector detector) throws DetectorProcessNotFoundException {
assert descriptor != null;
Task task = find(descriptor.getJavaType(), detector);
if (task != null) {
task.setProcessDescriptor(descriptor);
}
return task;
}
/**
* Finds or creates the via provided qualified name Task instance.
*
* @param qualifiedInstanceName The qualified name of the task, which should
* be instanciated. null not permitted.
* @param detector The Detector to which the created Task is associated.
* @return a Task instance.
* @throws
* de.fub.maps.project.detector.model.process.DetectorProcess.DetectorProcessNotFoundException
* if the specified implementation could not be found, because it's not
* registered via <code>@ServiceProvider</code> annotations, or
* instanciated.
*/
public static synchronized Task find(String qualifiedInstanceName, Detector detector) throws DetectorProcessNotFoundException {
Task taskProcess = null;
try {
Class<?> clazz = null;
ClassLoader classLoader = Lookup.getDefault().lookup(ClassLoader.class);
// prefer netbeans classloader
if (classLoader != null) {
clazz = classLoader.loadClass(qualifiedInstanceName);
} else {
// fall back
clazz = Class.forName(qualifiedInstanceName);
}
if (Task.class.isAssignableFrom(clazz)) {
@SuppressWarnings("unchecked")
Class<Task> taskProcessClass = (Class<Task>) clazz;
taskProcess = DetectorProcess.find(taskProcessClass, detector);
}
} catch (Throwable ex) {
throw new DetectorProcessNotFoundException(ex);
}
return taskProcess;
}
/**
* The Default implementation of the visual representation of a Task.
*/
@NbBundle.Messages({"CLT_Tesk_Parameter=Parameters"})
protected static class TaskProcessNode extends CustomAbstractnode implements PropertyChangeListener, ChangeListener {
private final Task taskProcess;
private Sheet.Set set;
private ModelSynchronizer.ModelSynchronizerClient modelSynchronizerClient;
public TaskProcessNode(Task taskProcess) {
this(Children.LEAF, taskProcess);
}
public TaskProcessNode(Children children, Task taskProcess) {
super(children, Lookups.fixed(taskProcess));
this.taskProcess = taskProcess;
this.taskProcess.addPropertyChangeListener(WeakListeners.propertyChange(TaskProcessNode.this, this.taskProcess));
setDisplayName(taskProcess.getName());
setShortDescription(taskProcess.getDescription());
}
@Override
protected Sheet createSheet() {
Sheet sheet = Sheet.createDefault();
if (taskProcess.getDetector() != null) {
modelSynchronizerClient = taskProcess.getDetector().create(TaskProcessNode.this);
set = Sheet.createPropertiesSet();
set.setDisplayName(Bundle.CLT_Tesk_Parameter());
sheet.put(set);
reinitSet();
}
return sheet;
}
private void reinitSet() {
List<de.fub.maps.project.detector.model.xmls.Property> propertyList = taskProcess.getProcessDescriptor().getProperties().getPropertyList();
ProcessProperty property = null;
for (de.fub.maps.project.detector.model.xmls.Property xmlProperty : propertyList) {
property = new ProcessProperty(modelSynchronizerClient, xmlProperty);
set.put(property);
}
}
@Override
public Image getIcon(int type) {
Image image = null;
Image backgroundIcon = null;
switch (this.taskProcess.getProcessState()) {
case ERROR:
backgroundIcon = IconRegister.findRegisteredIcon("processIconError.png");
break;
case SETTING_ERROR:
backgroundIcon = IconRegister.findRegisteredIcon("processIconError.png");
break;
case INACTIVE:
backgroundIcon = IconRegister.findRegisteredIcon("processIconNormal.png");
break;
case RUNNING:
backgroundIcon = IconRegister.findRegisteredIcon("processIconRun.png");
break;
default:
throw new AssertionError();
}
if (backgroundIcon != null) {
image = backgroundIcon;
}
return image != null ? image : super.getIcon(type);
}
@Override
public Image getOpenedIcon(int type) {
return getIcon(type);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (FilterProcess.PROP_NAME_PROCESS_STATE.equals(evt.getPropertyName())) {
fireIconChange();
}
}
@Override
public void stateChanged(ChangeEvent e) {
if (modelSynchronizerClient != null) {
reinitSet();
}
}
}
}