/*
 * AbstractConverterPlugIn.java
 *
 * Created on October 11, 2004, 3:52 PM
 */

package org.joone.util;

import java.util.*;
import java.io.*;
import org.joone.net.NetCheck;
import org.joone.engine.*;
import org.joone.log.*;

/**
 * This abstract class must be extended to implement plug-ins for input or output
 * data pre- or post-processing.
 *
 * 
 *
 * @author  Boris Jansen
 */
public abstract class AbstractConverterPlugIn implements java.io.Serializable, PlugInListener {
    
    /** The serial version of this object. */
    private static final long serialVersionUID = 5698511686417862414L;
    /** The object used when logging debug, errors, warnings and info. */
    private static final ILogger log = LoggerFactory.getLogger(AbstractConverterPlugIn.class);
    
    /** The next plugin in this series of cascading plugins. */
    private AbstractConverterPlugIn nextPlugIn = null;
    
    /** The name of this plug-in object. */
    private String name;
    
    /** This flag indicates if this plug-in is connected. Whenever a plug in is connected
     * it cannot be connected / added to another input stream / plug-in. */
    private boolean connected;
    
    /** A vector of objects that are listening to this object for plug-in (data changed) events. */
    protected Vector pluginListeners;
    
    /** The Vector of input patterns which this converter must process. */
    private transient Vector InputVector;
    
    /**
     * The AdvancedSerieSelector instructs this plug-in what serie/columns
     * it should process. The format of this specification is a common separated list of
     * values and ranges. E.g '1,2,5,7' will instruct the converter to convert serie 1
     * and 2 and 5 and 7. A range can also be used e.g '2,4,5-8,9' will instruct the
     * converter to process serie 2 and 4 and 5 and 6 and 7 and 8 and 9.  A range is specifed
     * using a '-' character with the number of the serie on either side.
     * 

Note NO negative numbers can be used in the AdvancedSerieSelector.

*/ private String AdvancedSerieSelector = new String(""); /** The series to be converted. */ private transient int [] serieSelected; /** Creates a new instance of AbstractConverterPlugIn */ public AbstractConverterPlugIn() { } /** * Creates a new instance of AbstractConverterPlugIn * * @param anAdvancedSerieSelector the advanced serie selector to use. * @see setAdvancedSerieSelector() */ public AbstractConverterPlugIn(String anAdvancedSerieSelector) { setAdvancedSerieSelector(anAdvancedSerieSelector); } /** * Converts all the patterns contained by {@link #InputVector} and on the * serie specifed by the call to {@link setAdvancedSerieSelector#setAdvancedSerieSelector}. * It cascades also the conversion to the next-plugin connected in the chain. */ public void convertPatterns() { apply(); cascade(); } /** * Applies all the conversions on the patterns contained by {@link #InputVector} * @return true if the input buffer is changed */ protected boolean apply() { boolean retValue = false; if ((getInputVector() != null) && (getInputVector().size() > 0)) { retValue = applyOnColumns() | applyOnRows(); } else { log.warn( getName()+" : Plugin has no input data to convert." ); } return retValue; } /** * Applies the conversion on the patterns contained by {@link #InputVector} and on the * columns specifed by the call to {@link setAdvancedSerieSelector#setAdvancedSerieSelector}. */ protected boolean applyOnColumns() { boolean retValue = false; Pattern currPE = (Pattern) getInputVector().elementAt(0); int aSize = currPE.getArray().length; // Use Advanced Serie Selector to select the serie to convert if ( (getAdvancedSerieSelector() != null ) && (!getAdvancedSerieSelector().equals(new String(""))) ) { int [] mySerieSelected = getSerieSelected(); for(int i = 0; i < mySerieSelected.length; i++) { if(mySerieSelected[i]-1 < aSize) { // Check we don't go over array bounds. retValue = convert(mySerieSelected[i]-1) | retValue; } else { log.warn(getName() + " : Advanced Serie Selector contains too many serie. Check the number of columns in the appropriate input synapse."); } } } return retValue; } /** * Applies the conversion on the patterns contained by {@link #InputVector} * on all the rows. Override this empty method to apply any change to the * order of the input vector's rows. */ protected boolean applyOnRows() { return false; } /** * Cascades the convertPatterns() method call to the next plug-in. */ protected void cascade() { if (getNextPlugIn() != null) { // Loop through other cascading plugins AbstractConverterPlugIn myPlugIn = getNextPlugIn(); myPlugIn.setInputVector(getInputVector()); myPlugIn.convertPatterns(); } } /** * Applies the conversion on the Nth serie of the buffered pattern data. The method is abstract * and should be overridden by the implementing class. Implementing classes can obtain the * input patterns by calling the {@link #getInputVector()} method. The result is a * Vector of Pattern objects which this method should use by converting * the requested serie. * * @param serie the serie to convert */ protected abstract boolean convert(int serie); /** * Gets the double value at the specified row (point) in the specifed serie / * column. * * @param point The row at which to get the pattern's double value. * @param serie The serie or column from which to obtain the value. * @return The value at the specified point in the input vector. */ protected double getValuePoint(int point, int serie) { Pattern currPE = (Pattern) getInputVector().elementAt(point); return currPE.getArray()[serie]; } /** * Gets the name of this plug-in object. * * @return The name of this plug-in. */ public String getName() { return name; } /** * Sets the name of this plug-in object. * * @param aName New name for this object. */ public void setName(String aName) { name = aName; } /** * Getter for property connected. * This property is true when this plugin has been * attached either to a StreamInputSynapse or to * another plugin. * @return Value of property connected. */ public boolean isConnected() { return connected; } /** * Setter for property connected. * This property is true when this plugin has been * attached either to a StreamInputSynapse or to * another plugin. * @param aConnected New value of property connected. */ public void setConnected(boolean aConnected) { connected = aConnected; } /** * Adds an {@link PlugInListener} to this plug-in. Usually this will be the * previous plug-in in the series of cascading plug-ins or the stream * input/output synapse. * * @param aListener The listener that requires notification of events from * this plug-in whenever data changes. */ public synchronized void addPlugInListener(PlugInListener aListener) { if(!getPluginListeners().contains(aListener)) { getPluginListeners().add(aListener); } } /** * Removes a {@link PlugInListener} that was previously registered to receive * plugin (data changed) events. * * @param aListener The listener that does not want to receive any events * anymore from this plug-in. */ public synchronized void removePlugInListener(PlugInListener aListener) { if (getPluginListeners().contains(aListener)) { getPluginListeners().remove(aListener); } } /** * Gets a vector of all the {@link PlugInListener}s that have been registerd * to receive events from this plug-in. * * @return The vector of PlugInListeners listening to this * converter plug-in object. */ protected Vector getPluginListeners() { if (pluginListeners == null) { pluginListeners = new Vector(); } return pluginListeners; } public void dataChanged(PlugInEvent anEvent) { fireDataChanged(); } /** * Fires a data changed event to all {@link PlugInListeners} that are registered * to receive events from this plug-in object. This method calls the * {@link InputPlugInListener#dataChanged()} method in all registered listeners. */ protected void fireDataChanged() { Object[] myList; synchronized (this) { myList = getPluginListeners().toArray(); } for (int i=0; i < myList.length; ++i) { PlugInListener myListener = (PlugInListener)myList[i]; if (myListener != null) { myListener.dataChanged(new PlugInEvent(this)); } } } /** * Gets the AdvancedSerieSelector. * * @return Value of property AdvancedSerieSelector. */ public String getAdvancedSerieSelector() { return AdvancedSerieSelector; } /** * Sets the AdvancedSerieSelector for this plugin. *

The AdvancedSerieSelector instructs this plug-in what serie/columns it * should process. The format of this specification is a common seperated list of * values and ranges. E.g '1,2,5,7' will instruct the converter to convert serie 1 * and 2 and 5 and 7. A range can also be used e.g '2,4,5-8,9' will instruct the * converter to process serie 2 and 4 and 5 and 6 and 7 and 8 and 9. A range is specifed * using a '-' character with the number of the serie on either side. *

Note NO negative numbers can be used in the AdvancedSerieSelector.

* * @param aNewSerieSelector New value for the AdvancedSerieSelector. */ public void setAdvancedSerieSelector(String aNewSerieSelector) { if((AdvancedSerieSelector == null) || (AdvancedSerieSelector.compareTo(aNewSerieSelector) != 0)) { AdvancedSerieSelector = aNewSerieSelector; serieSelected = null; fireDataChanged(); } } /** * Getter for property serieSelected. Returns the list of * selected columns to elaborate. * * @return Value of property serieSelected. */ protected int[] getSerieSelected() { if(serieSelected == null) { // if the advanced serie selected string is not parsed yet, then parse // it now to obtain the serie selected CSVParser myParser = new CSVParser(getAdvancedSerieSelector(), true); serieSelected = myParser.parseInt(); } return serieSelected; } /** * Adds a plug-in at the end of the list of plug-ins. * * @param aNewPlugIn the new plug in to add at the end of plug ins. * @return true when the plug in is added succesfully, * false when the plug in is not added, e.g. in case the * plug in is already added / connected to another synapse / plug-in. */ public boolean addPlugIn(AbstractConverterPlugIn aNewPlugIn) { if(nextPlugIn == aNewPlugIn) { return false; } // The null parameter is used to detach or delete a plugin if(aNewPlugIn == null) { // We need to declare the next plugin, if existing, // as not more used, so it could be used again. if (nextPlugIn != null) { nextPlugIn.setConnected(false); } nextPlugIn = null; fireDataChanged(); return true; } if(aNewPlugIn.isConnected()) { // The new plugin is already connected to another plugin, // hence cannot be used. return false; } if(nextPlugIn == null) { aNewPlugIn.setConnected(true); aNewPlugIn.addPlugInListener(this); nextPlugIn = aNewPlugIn; fireDataChanged(); return true; } else { return nextPlugIn.addPlugIn(aNewPlugIn); } } /** * Removes (and disconnects) all (cascading) plug ins. */ public void removeAllPlugIns() { if(nextPlugIn != null) { nextPlugIn.setConnected(false); nextPlugIn.removeAllPlugIns(); nextPlugIn = null; } else { // this is the last plug-in in a chain of plug ins that are removed // just only one time it should be notified that these plug-ins are // not used anymore (the data should not be converted anymore), so // here we fire a data changed event JUST ONCE. fireDataChanged(); } } /** * Sets the next plug-in in a cascading series of plugins. * * @param aNewNextPlugIn The next plug-in in the series. * @return true when the plug-in is successfully added, * false otherwise. * @deprecated {@link addPlugIn(AbstractConverterPlugIn)} */ public boolean setNextPlugin(AbstractConverterPlugIn aNewNextPlugIn) { if (aNewNextPlugIn == nextPlugIn) { return false; } if (aNewNextPlugIn == null) { nextPlugIn.setConnected(false); } else { if (aNewNextPlugIn.isConnected()) { return false; } aNewNextPlugIn.setConnected(true); aNewNextPlugIn.addPlugInListener(this); } nextPlugIn = aNewNextPlugIn; fireDataChanged(); return true; } /** * Gets the next converter plug-in within this cascading series of plug-ins. * * @return the next plug-in within this cascading series of plug-ins. */ public AbstractConverterPlugIn getNextPlugIn() { return nextPlugIn; } /** * Added for XML serialization *

**** DO NOT USE **** *

Use {@link #addPlugIn(AbstractConverterPlugIn)} */ public void setNextPlugIn(AbstractConverterPlugIn newNextPlugIn) { addPlugIn(newNextPlugIn); } /** * Sets the input vector of Patterns that this converter plugin should process. * @param newInputVector The vector of Pattern objects to process. */ public void setInputVector(java.util.Vector newInputVector) { InputVector = newInputVector; } /** * Gets the input vector of Patterns with which this converter must process. * * @return the vector with patterns that this converter processes. */ protected Vector getInputVector() { return InputVector; } /** * This method is called to perform a check on this converter's properties to * ensure there are no errors or problems. If there is an error or problem with * one of the properties then the issues are returned in a TreeSet * object. * * @param checks A TreeSet of issues that should be added to by this * plug-in. * @return A TreeSet of errors or problems relating to the setup of * this converter plug-in object. * @see Synapse */ public TreeSet check(TreeSet checks) { if(AdvancedSerieSelector == null || AdvancedSerieSelector.equals(new String(""))) { checks.add(new NetCheck(NetCheck.FATAL, "Advanced Serie Selector should be populated, e.g 1,2,4." , this)); } // Call next converter plug-in in the chain of converter plug-ins if(getNextPlugIn() != null) { getNextPlugIn().check(checks); } return checks; } /** * Gets the index of the current serie number. * @return int -1 if the serie could not be found in the serie specification. */ protected int getSerieIndexNumber(int serie) { CSVParser Parse = new CSVParser(getAdvancedSerieSelector(),true); int [] checker = Parse.parseInt(); for ( int i=0; i

Ads help maintain this website.