/* * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * InstanceStreamToBatchMaker.java * Copyright (C) 2008 University of Waikato, Hamilton, New Zealand * */ package weka.gui.beans; import java.awt.BorderLayout; import java.beans.EventSetDescriptor; import java.util.ArrayList; import javax.swing.JPanel; import weka.core.Instance; import weka.core.Instances; import weka.gui.Logger; /** * Bean that converts an instance stream into a (batch) data set. * Useful in conjunction with the Reservoir sampling filter. * * @author Mark Hall (mhall{[at]}pentaho{[dot]}com) * @version $Revision: 5563 $ */ public class InstanceStreamToBatchMaker extends JPanel implements BeanCommon, Visible, InstanceListener, EventConstraints, DataSource { /** * For serialization */ private static final long serialVersionUID = -7037141087208627799L; protected BeanVisual m_visual = new BeanVisual("InstanceStreamToBatchMaker", BeanVisual.ICON_PATH+"InstanceStreamToBatchMaker.gif", BeanVisual.ICON_PATH+"InstanceStreamToBatchMaker_animated.gif"); /** * The log. */ private transient Logger m_log; /** * Component connected to us. */ private Object m_listenee; private ArrayList<DataSourceListener> m_dataListeners = new ArrayList<DataSourceListener>(); /** * Collects up the instances. */ private ArrayList<Instance> m_batch; private Instances m_structure; public InstanceStreamToBatchMaker() { setLayout(new BorderLayout()); add(m_visual, BorderLayout.CENTER); } /** * Accept an instance to add to the batch. * * @param e an <code>InstanceEvent</code> value */ public void acceptInstance(InstanceEvent e) { if (e.getStatus() == InstanceEvent.FORMAT_AVAILABLE) { m_batch = new ArrayList<Instance>(); m_structure = e.getStructure(); // notify dataset listeners of structure available if (m_log != null) { m_log.logMessage("[InstanceStreamToBatch] passing on structure."); } DataSetEvent dse = new DataSetEvent(this, m_structure); notifyDataListeners(dse); } else if (e.getStatus() == InstanceEvent.INSTANCE_AVAILABLE) { m_batch.add(e.getInstance()); } else { // batch finished // add the last instance m_batch.add(e.getInstance()); // create the new Instances Instances dataSet = new Instances(m_structure, m_batch.size()); for (Instance i : m_batch) { dataSet.add(i); } dataSet.compactify(); // save memory m_batch = null; if (m_log != null) { m_log.logMessage("[InstanceStreamToBatch] sending batch to listeners."); } // notify dataset listeners DataSetEvent dse = new DataSetEvent(this, dataSet); notifyDataListeners(dse); } } /** * Returns true if, at this time, * the object will accept a connection according to the supplied * EventSetDescriptor * * @param esd the EventSetDescriptor * @return true if the object will accept a connection */ public boolean connectionAllowed(EventSetDescriptor esd) { return connectionAllowed(esd.getName()); } /** * Returns true if, at this time, * the object will accept a connection with respect to the named event * * @param eventName the event * @return true if the object will accept a connection */ public boolean connectionAllowed(String eventName) { if (m_listenee != null || !eventName.equals("instance")) { return false; } return true; } /** * Notify this object that it has been registered as a listener with * a source with respect to the named event * * @param eventName the event * @param source the source with which this object has been registered as * a listener */ public void connectionNotification(String eventName, Object source) { if (connectionAllowed(eventName)) { m_listenee = source; } } /** * Notify this object that it has been deregistered as a listener with * a source with respect to the supplied event name * * @param eventName the event * @param source the source with which this object has been registered as * a listener */ public void disconnectionNotification(String eventName, Object source) { m_listenee = null; } /** * Returns true if, at the current time, the named event could be * generated. * * @param eventName the name of the event in question * @return true if the named event could be generated */ public boolean eventGeneratable(String eventName) { if (!eventName.equals("dataSet")) { return false; } if (m_listenee == null) { return false; } if (m_listenee instanceof EventConstraints) { if (!((EventConstraints)m_listenee).eventGeneratable("instance")) { return false; } } return true; } /** * Get the custom (descriptive) name for this bean (if one has been set) * * @return the custom name (or the default name) */ public String getCustomName() { return m_visual.getText(); } /** * Set a custom (descriptive) name for this bean * * @param name the name to use */ public void setCustomName(String name) { m_visual.setText(name); } /** * Set a logger * * @param logger a <code>Logger</code> value */ public void setLog(Logger logger) { m_log = logger; } /** * Returns true if. at this time, the bean is busy with some * (i.e. perhaps a worker thread is performing some calculation). * * @return true if the bean is busy. */ public boolean isBusy() { return false; } /** * Stop any action (if possible). */ public void stop() { // not much we can do. Stopping depends on upstream components. } /** * Gets the visual appearance of this wrapper bean */ public BeanVisual getVisual() { return m_visual; } /** * Sets the visual appearance of this wrapper bean * * @param newVisual a <code>BeanVisual</code> value */ public void setVisual(BeanVisual newVisual) { m_visual = newVisual; } /** * Use the default visual appearance for this bean */ public void useDefaultVisual() { m_visual.loadIcons(BeanVisual.ICON_PATH+"InstanceStreamToBatchMaker.gif", BeanVisual.ICON_PATH+"InstanceStreamToBatchMaker_animated.gif"); } /** * Notify all data source listeners. * * @param tse the DataSetEvent to pass on. */ protected void notifyDataListeners(DataSetEvent tse) { ArrayList<DataSourceListener> l; synchronized (this) { l = (ArrayList<DataSourceListener>)m_dataListeners.clone(); } if (l.size() > 0) { for(int i = 0; i < l.size(); i++) { l.get(i).acceptDataSet(tse); } } } public synchronized void addDataSourceListener(DataSourceListener tsl) { m_dataListeners.add(tsl); // pass on any format that we might know about if (m_structure != null) { DataSetEvent e = new DataSetEvent(this, m_structure); tsl.acceptDataSet(e); } } public synchronized void removeDataSourceListener(DataSourceListener tsl) { m_dataListeners.remove(tsl); } public synchronized void addInstanceListener(InstanceListener il) { // we don't produce instance events } public synchronized void removeInstanceListener(InstanceListener il) { // we don't produce instance events } }