source: branches/MetisMQI/src/main/java/weka/gui/beans/Filter.java

Last change on this file was 29, checked in by gnappo, 15 years ago

Taggata versione per la demo e aggiunto branch.

File size: 30.0 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    Filter.java
19 *    Copyright (C) 2002 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.beans;
24
25import weka.core.Instance;
26import weka.core.Instances;
27import weka.core.OptionHandler;
28import weka.core.Utils;
29import weka.filters.AllFilter;
30import weka.filters.StreamableFilter;
31import weka.filters.SupervisedFilter;
32import weka.gui.Logger;
33
34import java.awt.BorderLayout;
35import java.beans.EventSetDescriptor;
36import java.io.Serializable;
37import java.util.Enumeration;
38import java.util.EventObject;
39import java.util.Hashtable;
40import java.util.Vector;
41
42import javax.swing.JPanel;
43
44/**
45 * A wrapper bean for Weka filters
46 *
47 * @author <a href="mailto:mhall@cs.waikato.ac.nz">Mark Hall</a>
48 * @version $Revision: 5247 $
49 */
50/**
51 * @author mhall
52 *
53 */
54/**
55 * @author mhall
56 *
57 */
58public class Filter
59  extends JPanel
60  implements BeanCommon, Visible, WekaWrapper,
61             Serializable, UserRequestAcceptor,
62             TrainingSetListener, TestSetListener,
63             TrainingSetProducer, TestSetProducer,
64             DataSource, DataSourceListener, 
65             InstanceListener, EventConstraints,
66             ConfigurationProducer {
67
68  /** for serialization */
69  private static final long serialVersionUID = 8249759470189439321L;
70
71  protected BeanVisual m_visual = 
72    new BeanVisual("Filter",
73                   BeanVisual.ICON_PATH+"DefaultFilter.gif",
74                   BeanVisual.ICON_PATH+"DefaultFilter_animated.gif");
75
76  private static int IDLE = 0;
77  private static int FILTERING_TRAINING = 1;
78  private static int FILTERING_TEST = 2;
79  private int m_state = IDLE;
80
81  protected Thread m_filterThread = null;
82
83  private transient Instances m_trainingSet;
84  private transient Instances m_testingSet;
85
86  /**
87   * Global info for the wrapped filter (if it exists).
88   */
89  protected String m_globalInfo;
90
91  /**
92   * Objects talking to us
93   */
94  private Hashtable m_listenees = new Hashtable();
95
96  /**
97   * Objects listening for training set events
98   */
99  private Vector m_trainingListeners = new Vector();
100
101  /**
102   * Objects listening for test set events
103   */
104  private Vector m_testListeners = new Vector();
105
106  /**
107   * Objects listening for instance events
108   */
109  private Vector m_instanceListeners = new Vector();
110
111  /**
112   * Objects listening for data set events
113   */
114  private Vector m_dataListeners = new Vector();
115
116  /**
117   * The filter to use.
118   */
119  private weka.filters.Filter m_Filter = new AllFilter();
120
121  /**
122   * Instance event object for passing on filtered instance streams
123   */
124  private InstanceEvent m_ie = new InstanceEvent(this);
125
126  /**
127   * Logging.
128   */
129  private transient Logger m_log = null;
130 
131  /**
132   * Counts incoming streamed instances.
133   */
134  private transient int m_instanceCount;
135 
136  /**
137   * Global info (if it exists) for the wrapped filter
138   *
139   * @return the global info
140   */
141  public String globalInfo() {
142    return m_globalInfo;
143  }
144
145  public Filter() {
146    setLayout(new BorderLayout());
147    add(m_visual, BorderLayout.CENTER);
148    setFilter(m_Filter);
149  }
150
151  /**
152   * Set a custom (descriptive) name for this bean
153   *
154   * @param name the name to use
155   */
156  public void setCustomName(String name) {
157    m_visual.setText(name);
158  }
159
160  /**
161   * Get the custom (descriptive) name for this bean (if one has been set)
162   *
163   * @return the custom name (or the default name)
164   */
165  public String getCustomName() {
166    return m_visual.getText();
167  }
168
169  /**
170   * Set the filter to be wrapped by this bean
171   *
172   * @param c a <code>weka.filters.Filter</code> value
173   */
174  public void setFilter(weka.filters.Filter c) {
175    boolean loadImages = true;
176    if (c.getClass().getName().
177        compareTo(m_Filter.getClass().getName()) == 0) {
178      loadImages = false;
179    }
180    m_Filter = c;
181    String filterName = c.getClass().toString();
182    filterName = filterName.substring(filterName.
183                                      indexOf('.')+1, 
184                                      filterName.length());
185    if (loadImages) {
186      if (m_Filter instanceof Visible) {
187        m_visual = ((Visible) m_Filter).getVisual();
188      } else {
189        if (!m_visual.loadIcons(BeanVisual.ICON_PATH+filterName+".gif",
190                                BeanVisual.ICON_PATH+filterName+"_animated.gif")) {
191          useDefaultVisual();
192        }
193      }
194    }
195    m_visual.setText(filterName.substring(filterName.lastIndexOf('.')+1,
196                                          filterName.length()));
197
198    if (m_Filter instanceof LogWriter && m_log != null) {
199      ((LogWriter) m_Filter).setLog(m_log);
200    }
201
202    if (!(m_Filter instanceof StreamableFilter) &&
203        (m_listenees.containsKey("instance"))) {
204      if (m_log != null) {
205        m_log.logMessage("[Filter] " + 
206            statusMessagePrefix() + " WARNING : "
207            + m_Filter.getClass().getName()
208            + " is not an incremental filter");
209        m_log.statusMessage(statusMessagePrefix()
210            + "WARNING: Not an incremental filter.");
211      }
212    }
213   
214    // get global info
215    m_globalInfo = KnowledgeFlowApp.getGlobalInfo(m_Filter);
216  }
217
218  public weka.filters.Filter getFilter() {
219    return m_Filter;
220  }
221
222  /**
223   * Set the filter to be wrapped by this bean
224   *
225   * @param algorithm a weka.filters.Filter
226   * @exception IllegalArgumentException if an error occurs
227   */
228  public void setWrappedAlgorithm(Object algorithm) {
229   
230    if (!(algorithm instanceof weka.filters.Filter)) { 
231      throw new IllegalArgumentException(algorithm.getClass()+" : incorrect "
232                                         +"type of algorithm (Filter)");
233    }
234    setFilter((weka.filters.Filter)algorithm);
235  }
236
237  /**
238   * Get the filter wrapped by this bean
239   *
240   * @return an <code>Object</code> value
241   */
242  public Object getWrappedAlgorithm() {
243    return getFilter();
244  }
245
246  /**
247   * Accept a training set
248   *
249   * @param e a <code>TrainingSetEvent</code> value
250   */
251  public void acceptTrainingSet(TrainingSetEvent e) {
252    processTrainingOrDataSourceEvents(e);
253  }
254
255  private boolean m_structurePassedOn = false;
256  /**
257   * Accept an instance for processing by StreamableFilters only
258   *
259   * @param e an <code>InstanceEvent</code> value
260   */
261  public void acceptInstance(InstanceEvent e) {
262    // to do!
263    if (m_filterThread != null) {
264      String messg = "[Filter] " + statusMessagePrefix() 
265        + " is currently batch processing!";
266      if (m_log != null) {
267        m_log.logMessage(messg);
268        m_log.statusMessage(statusMessagePrefix()
269            + "WARNING: Filter is currently batch processing.");
270      } else {
271        System.err.println(messg);
272      }
273      return;
274    }
275    if (!(m_Filter instanceof StreamableFilter)) {
276      stop(); // stop all processing
277      if (m_log != null) {
278        m_log.logMessage("[Filter] " + statusMessagePrefix() 
279            + " ERROR : "+m_Filter.getClass().getName()
280            +"can't process streamed instances; can't continue");
281        m_log.statusMessage(statusMessagePrefix()
282            + "ERROR: Can't process streamed instances; can't continue.");
283      }
284      return;
285    }
286    if (e.getStatus() == InstanceEvent.FORMAT_AVAILABLE) {
287      try {
288        m_instanceCount = 0;
289        //notifyInstanceListeners(e);
290        //      Instances dataset = e.getInstance().dataset();
291        Instances dataset = e.getStructure();
292        if (m_Filter instanceof SupervisedFilter) {
293          // defualt to last column if no class is set
294          if (dataset.classIndex() < 0) {
295            dataset.setClassIndex(dataset.numAttributes()-1);
296          }
297        }
298        // initialize filter
299        m_Filter.setInputFormat(dataset);
300        // attempt to determine post-filtering
301        // structure. If successful this can be passed on to instance
302        // listeners as a new FORMAT_AVAILABLE event.
303        m_structurePassedOn = false;
304        try {
305          if (m_Filter.isOutputFormatDefined()) {
306//          System.err.println("Filter - passing on output format...");
307            //      System.err.println(m_Filter.getOutputFormat());
308            m_ie.setStructure(m_Filter.getOutputFormat());
309            notifyInstanceListeners(m_ie);
310            m_structurePassedOn = true;
311          }
312        } catch (Exception ex) {
313          stop(); // stop all processing
314          if (m_log != null) {
315            m_log.logMessage("[Filter] " + statusMessagePrefix() 
316                + " Error in obtaining post-filter structure. " 
317                + ex.getMessage());
318            m_log.statusMessage(statusMessagePrefix()
319                +"ERROR (See log for details).");
320          } else {
321            System.err.println("[Filter] " + statusMessagePrefix() 
322                + " Error in obtaining post-filter structure");
323          }
324        }
325      } catch (Exception ex) {
326        ex.printStackTrace();
327      }
328      return;
329    }
330   
331    if (e.getStatus() == InstanceEvent.BATCH_FINISHED) {
332      // get the last instance (if available)
333      try {
334        if (m_log != null) {
335          m_log.statusMessage(statusMessagePrefix() 
336              + "Stream finished.");
337        }
338        if (m_Filter.input(e.getInstance())) {
339          Instance filteredInstance = m_Filter.output();
340          if (filteredInstance != null) {
341            if (!m_structurePassedOn) {
342              // pass on the new structure first
343              m_ie.setStructure(new Instances(filteredInstance.dataset(), 0));
344              notifyInstanceListeners(m_ie);
345              m_structurePassedOn = true;
346            }
347
348            m_ie.setInstance(filteredInstance);
349           
350            // if there are instances pending for output don't want to send
351            // a batch finisehd at this point...
352            //System.err.println("Filter - in batch finisehd...");
353            if (m_Filter.batchFinished() && m_Filter.numPendingOutput() > 0) {
354              m_ie.setStatus(InstanceEvent.INSTANCE_AVAILABLE);
355            } else {
356              m_ie.setStatus(e.getStatus());
357            }
358            notifyInstanceListeners(m_ie);
359          }
360        }
361        if (m_log != null) {
362          m_log.statusMessage(statusMessagePrefix() + "Done.");
363        }
364      } catch (Exception ex) {
365        stop(); // stop all processing
366        if (m_log != null) {
367          m_log.logMessage("[Filter] " 
368              + statusMessagePrefix() + ex.getMessage());
369          m_log.statusMessage(statusMessagePrefix()
370              + "ERROR (See log for details).");
371        }
372        ex.printStackTrace();
373      }
374     
375      // check for any pending instances that we might need to pass on
376      try {
377        if (m_Filter.batchFinished() && m_Filter.numPendingOutput() > 0) {
378          if (m_log != null) {
379            m_log.statusMessage(statusMessagePrefix() 
380                + "Passing on pending instances...");
381          }
382          Instance filteredInstance = m_Filter.output();
383          if (filteredInstance != null) {
384            if (!m_structurePassedOn) {
385              // pass on the new structure first
386              m_ie.setStructure(new Instances(filteredInstance.dataset(), 0));
387              notifyInstanceListeners(m_ie);
388              m_structurePassedOn = true;
389            }
390
391            m_ie.setInstance(filteredInstance);
392           
393            //TODO here is the problem I think
394            m_ie.setStatus(InstanceEvent.INSTANCE_AVAILABLE);
395            notifyInstanceListeners(m_ie);
396          }
397          while (m_Filter.numPendingOutput() > 0) {
398            filteredInstance = m_Filter.output();
399            m_ie.setInstance(filteredInstance);
400//            System.err.println("Filter - sending pending...");
401            if (m_Filter.numPendingOutput() == 0) {
402              m_ie.setStatus(InstanceEvent.BATCH_FINISHED);
403            } else {
404              m_ie.setStatus(InstanceEvent.INSTANCE_AVAILABLE);
405            }
406            notifyInstanceListeners(m_ie);
407          }
408          if (m_log != null) {
409            m_log.statusMessage(statusMessagePrefix() + "Finished.");
410          }
411        }
412      } catch (Exception ex) {
413        stop(); // stop all processing
414        if (m_log != null) {
415          m_log.logMessage("[Filter] " 
416              + statusMessagePrefix() 
417              + ex.toString());
418          m_log.statusMessage(statusMessagePrefix()
419              + "ERROR (See log for details.");
420        }
421        ex.printStackTrace();
422      }
423    } else {
424      // pass instance through the filter
425      try {
426        if (!m_Filter.input(e.getInstance())) {
427//          System.err.println("Filter - inputing instance into filter...");
428          /* if (m_log != null) {
429            m_log.logMessage("ERROR : filter not ready to output instance");
430          } */
431         
432          // quietly return. Filter might be able to output some instances
433          // once the batch is finished.
434          return;
435        }
436
437        // collect output instance.
438        Instance filteredInstance = m_Filter.output();
439        if (filteredInstance == null) {
440          return;
441        }
442        m_instanceCount++;
443       
444        if (!m_structurePassedOn) {
445          // pass on the new structure first
446          m_ie.setStructure(new Instances(filteredInstance.dataset(), 0));
447          notifyInstanceListeners(m_ie);
448          m_structurePassedOn = true;
449        }
450
451        m_ie.setInstance(filteredInstance);
452        m_ie.setStatus(e.getStatus());
453       
454        if (m_log != null && (m_instanceCount % 10000 == 0)) {
455          m_log.statusMessage(statusMessagePrefix()
456              + "Received " + m_instanceCount + " instances.");
457        }
458        notifyInstanceListeners(m_ie);
459      } catch (Exception ex) {
460        stop(); // stop all processing
461        if (m_log != null) {
462          m_log.logMessage("[Filter] " + statusMessagePrefix() 
463              + ex.toString());
464          m_log.statusMessage(statusMessagePrefix()
465              + "ERROR (See log for details).");
466        }
467        ex.printStackTrace();
468      }
469    }
470  }
471
472  private void processTrainingOrDataSourceEvents(final EventObject e) {
473    boolean structureOnly = false;
474    if (e instanceof DataSetEvent) {
475      structureOnly = ((DataSetEvent)e).isStructureOnly();
476      if(structureOnly){
477       notifyDataOrTrainingListeners(e); 
478      }
479    }
480    if (e instanceof TrainingSetEvent) {
481      structureOnly = ((TrainingSetEvent)e).isStructureOnly();
482      if(structureOnly){
483       notifyDataOrTrainingListeners(e); 
484      }
485    }
486    if (structureOnly && !(m_Filter instanceof StreamableFilter)) {
487      return; // nothing can be done
488    }
489   
490    if (m_filterThread == null) {
491      try {
492        if (m_state == IDLE) {
493          synchronized (this) {
494            m_state = FILTERING_TRAINING;
495          }
496          m_trainingSet = (e instanceof TrainingSetEvent) 
497            ? ((TrainingSetEvent)e).getTrainingSet()
498            : ((DataSetEvent)e).getDataSet();
499
500//        final String oldText = m_visual.getText();
501          m_filterThread = new Thread() {
502              public void run() {
503                try {
504                  if (m_trainingSet != null) {
505                    m_visual.setAnimated();
506//                  m_visual.setText("Filtering training data...");
507                    if (m_log != null) {
508                      m_log.statusMessage(statusMessagePrefix() 
509                          + "Filtering training data ("
510                          + m_trainingSet.relationName() + ")");
511                    }
512                    m_Filter.setInputFormat(m_trainingSet);
513                    Instances filteredData = 
514                      weka.filters.Filter.useFilter(m_trainingSet, m_Filter);
515//                  m_visual.setText(oldText);
516                    m_visual.setStatic();
517                    EventObject ne;
518                    if (e instanceof TrainingSetEvent) {
519                      ne = new TrainingSetEvent(weka.gui.beans.Filter.this, 
520                                                filteredData);
521                      ((TrainingSetEvent)ne).m_setNumber =
522                        ((TrainingSetEvent)e).m_setNumber;
523                      ((TrainingSetEvent)ne).m_maxSetNumber = 
524                        ((TrainingSetEvent)e).m_maxSetNumber;
525                    } else {
526                      ne = new DataSetEvent(weka.gui.beans.Filter.this,
527                                            filteredData);
528                    }
529
530                    notifyDataOrTrainingListeners(ne);
531                  }
532                } catch (Exception ex) {
533                  Filter.this.stop(); // stop all processing
534                  ex.printStackTrace();
535                  if (m_log != null) {
536                    m_log.logMessage("[Filter] " + statusMessagePrefix() 
537                        + ex.getMessage());
538                    m_log.statusMessage(statusMessagePrefix()
539                        + "ERROR (See log for details).");
540//                    m_log.statusMessage("Problem filtering: see log for details.");
541                  }
542                } finally {
543//                m_visual.setText(oldText);
544                  m_visual.setStatic();
545                  m_state = IDLE;
546                  if (isInterrupted()) {
547                    m_trainingSet = null;
548                    if (m_log != null) {
549                      m_log.logMessage("[Filter] " + statusMessagePrefix()
550                                       + " training set interrupted!");
551                      m_log.statusMessage(statusMessagePrefix()
552                          + "INTERRUPTED");
553                    }               
554                  } else {
555                    if (m_log != null) {
556                      m_log.statusMessage(statusMessagePrefix() + "Finished.");
557                    }
558                  }
559                  block(false);
560                }
561              }
562            };
563          m_filterThread.setPriority(Thread.MIN_PRIORITY);
564          m_filterThread.start();
565          block(true);
566          m_filterThread = null;
567          m_state = IDLE;
568        }
569      } catch (Exception ex) {
570        ex.printStackTrace();
571      }
572    }
573  }
574
575  /**
576   * Accept a test set
577   *
578   * @param e a <code>TestSetEvent</code> value
579   */
580  public void acceptTestSet(final TestSetEvent e) {
581      if(e.isStructureOnly())
582            notifyTestListeners(e);
583      if (m_trainingSet != null && 
584        m_trainingSet.equalHeaders(e.getTestSet()) && 
585        m_filterThread == null) {
586      try {
587        if (m_state == IDLE) {
588          m_state = FILTERING_TEST;
589        }
590        m_testingSet = e.getTestSet();
591        //      final String oldText = m_visual.getText();
592        m_filterThread = new Thread() {
593            public void run() {
594              try {
595                if (m_testingSet != null) {
596                  m_visual.setAnimated();
597                  //              m_visual.setText("Filtering test data...");
598                  if (m_log != null) {
599                    m_log.statusMessage(statusMessagePrefix() 
600                        + "Filtering test data ("
601                        + m_testingSet.relationName() + ")");
602                  }
603                  Instances filteredTest = 
604                    weka.filters.Filter.useFilter(m_testingSet, m_Filter);
605                  //              m_visual.setText(oldText);
606                  m_visual.setStatic();
607                  TestSetEvent ne =
608                    new TestSetEvent(weka.gui.beans.Filter.this,
609                                     filteredTest);
610                  ne.m_setNumber = e.m_setNumber;
611                  ne.m_maxSetNumber = e.m_maxSetNumber;
612                  notifyTestListeners(ne);
613                }
614              } catch (Exception ex) {
615                Filter.this.stop();
616                ex.printStackTrace();
617                if (m_log != null) {
618                  m_log.logMessage("[Filter] " + statusMessagePrefix() 
619                      + ex.getMessage());
620                  m_log.statusMessage(statusMessagePrefix() 
621                      + "ERROR (See log for details).");
622                }
623              } finally {
624                //              m_visual.setText(oldText);
625                m_visual.setStatic();
626                m_state = IDLE;
627                if (isInterrupted()) {
628                  m_trainingSet = null;
629                  if (m_log != null) {
630                      m_log.logMessage("[Filter] " + statusMessagePrefix()
631                                       + " test set interrupted!");
632                      m_log.statusMessage(statusMessagePrefix()
633                          + "INTERRUPTED");
634//                  m_log.statusMessage("OK");
635                  }
636                } else {
637                  if (m_log != null) {
638                    m_log.statusMessage(statusMessagePrefix() + "Finished.");
639                  }
640                }
641                block(false);
642              }
643            }
644          };
645        m_filterThread.setPriority(Thread.MIN_PRIORITY);
646        m_filterThread.start();
647        block(true);
648        m_filterThread = null;
649        m_state = IDLE;
650      } catch (Exception ex) {
651        ex.printStackTrace();
652      }
653    }
654  }
655
656  /**
657   * Accept a data set
658   *
659   * @param e a <code>DataSetEvent</code> value
660   */
661  public void acceptDataSet(DataSetEvent e) {
662    processTrainingOrDataSourceEvents(e);
663  }
664
665  /**
666   * Set the visual appearance of this bean
667   *
668   * @param newVisual a <code>BeanVisual</code> value
669   */
670  public void setVisual(BeanVisual newVisual) {
671    m_visual = newVisual;
672  }
673
674  /**
675   * Get the visual appearance of this bean
676   *
677   * @return a <code>BeanVisual</code> value
678   */
679  public BeanVisual getVisual() {
680    return m_visual;
681  }
682
683  /**
684   * Use the default visual appearance
685   */
686  public void useDefaultVisual() {
687    m_visual.loadIcons(BeanVisual.ICON_PATH+"DefaultFilter.gif",
688                       BeanVisual.ICON_PATH+"DefaultFilter_animated.gif");
689  }
690
691  /**
692   * Add a training set listener
693   *
694   * @param tsl a <code>TrainingSetListener</code> value
695   */
696  public synchronized void addTrainingSetListener(TrainingSetListener tsl) {
697    m_trainingListeners.addElement(tsl);
698  }
699 
700  /**
701   * Remove a training set listener
702   *
703   * @param tsl a <code>TrainingSetListener</code> value
704   */
705  public synchronized void removeTrainingSetListener(TrainingSetListener tsl) {
706     m_trainingListeners.removeElement(tsl);
707  }
708
709  /**
710   * Add a test set listener
711   *
712   * @param tsl a <code>TestSetListener</code> value
713   */
714  public synchronized void addTestSetListener(TestSetListener tsl) {
715    m_testListeners.addElement(tsl);
716  }
717 
718  /**
719   * Remove a test set listener
720   *
721   * @param tsl a <code>TestSetListener</code> value
722   */
723  public synchronized void removeTestSetListener(TestSetListener tsl) {
724    m_testListeners.removeElement(tsl);
725  }
726
727  /**
728   * Add a data source listener
729   *
730   * @param dsl a <code>DataSourceListener</code> value
731   */
732  public synchronized void addDataSourceListener(DataSourceListener dsl) {
733    m_dataListeners.addElement(dsl);
734  }
735
736  /**
737   * Remove a data source listener
738   *
739   * @param dsl a <code>DataSourceListener</code> value
740   */
741  public synchronized void removeDataSourceListener(DataSourceListener dsl) {
742    m_dataListeners.remove(dsl);
743  }
744
745  /**
746   * Add an instance listener
747   *
748   * @param tsl an <code>InstanceListener</code> value
749   */
750  public synchronized void addInstanceListener(InstanceListener tsl) {
751    m_instanceListeners.addElement(tsl);
752  }
753
754  /**
755   * Remove an instance listener
756   *
757   * @param tsl an <code>InstanceListener</code> value
758   */
759  public synchronized void removeInstanceListener(InstanceListener tsl) {
760    m_instanceListeners.removeElement(tsl);
761  }
762 
763  /**
764   * We don't have to keep track of configuration listeners (see the
765   * documentation for ConfigurationListener/ConfigurationEvent).
766   *
767   * @param cl a ConfigurationListener.
768   */
769  public synchronized void addConfigurationListener(ConfigurationListener cl) {
770   
771  }
772 
773  /**
774   * We don't have to keep track of configuration listeners (see the
775   * documentation for ConfigurationListener/ConfigurationEvent).
776   *
777   * @param cl a ConfigurationListener.
778   */
779  public synchronized void removeConfigurationListener(ConfigurationListener cl) {
780   
781  }
782
783  private void notifyDataOrTrainingListeners(EventObject ce) {
784    Vector l;
785    synchronized (this) {
786      l = (ce instanceof TrainingSetEvent)
787        ? (Vector)m_trainingListeners.clone()
788        : (Vector)m_dataListeners.clone();
789    }
790    if (l.size() > 0) {
791      for(int i = 0; i < l.size(); i++) {
792        if (ce instanceof TrainingSetEvent) {
793          ((TrainingSetListener)l.elementAt(i)).
794            acceptTrainingSet((TrainingSetEvent)ce);
795        } else {
796          ((DataSourceListener)l.elementAt(i)).acceptDataSet((DataSetEvent)ce);
797        }
798      }
799    }
800  }
801
802  private void notifyTestListeners(TestSetEvent ce) {
803    Vector l;
804    synchronized (this) {
805      l = (Vector)m_testListeners.clone();
806    }
807    if (l.size() > 0) {
808      for(int i = 0; i < l.size(); i++) {
809        ((TestSetListener)l.elementAt(i)).acceptTestSet(ce);
810      }
811    }
812  }
813
814  protected void notifyInstanceListeners(InstanceEvent tse) {
815    Vector l;
816    synchronized (this) {
817      l = (Vector)m_instanceListeners.clone();
818    }
819    if (l.size() > 0) {
820      for(int i = 0; i < l.size(); i++) {
821        //      System.err.println("Notifying instance listeners "
822        //                         +"(Filter)");
823        ((InstanceListener)l.elementAt(i)).acceptInstance(tse);
824      }
825    }
826  }
827 
828  /**
829   * Returns true if, at this time,
830   * the object will accept a connection with respect to the supplied
831   * event name
832   *
833   * @param eventName the event
834   * @return true if the object will accept a connection
835   */
836  public boolean connectionAllowed(String eventName) {
837
838    if (m_listenees.containsKey(eventName)) {
839      return false;
840    }
841
842    /* reject a test event if we don't have a training or data set event
843    if (eventName.compareTo("testSet") == 0) {
844      if (!m_listenees.containsKey("trainingSet") &&
845          !m_listenees.containsKey("dataSet")) {
846        return false;
847      }
848      } */
849   
850    // will need to reject train/test listener if we have a
851    // data source listener and vis versa
852    if (m_listenees.containsKey("dataSet") &&
853        (eventName.compareTo("trainingSet") == 0 ||
854         eventName.compareTo("testSet") == 0 ||
855        eventName.compareTo("instance") == 0)) {
856      return false;
857    }
858
859    if ((m_listenees.containsKey("trainingSet") ||
860         m_listenees.containsKey("testSet")) &&
861        (eventName.compareTo("dataSet") == 0 || 
862        eventName.compareTo("instance") == 0)) {
863      return false;
864    }
865
866    if (m_listenees.containsKey("instance") &&
867        (eventName.compareTo("trainingSet") == 0 ||
868         eventName.compareTo("testSet") == 0 ||
869         eventName.compareTo("dataSet") == 0)) {
870      return false;
871    }
872
873    // reject an instance event connection if our filter isn't
874    // streamable
875    if (eventName.compareTo("instance") == 0 &&
876        !(m_Filter instanceof StreamableFilter)) {
877      return false;
878    }
879    return true;
880  }
881
882  /**
883   * Returns true if, at this time,
884   * the object will accept a connection according to the supplied
885   * EventSetDescriptor
886   *
887   * @param esd the EventSetDescriptor
888   * @return true if the object will accept a connection
889   */
890  public boolean connectionAllowed(EventSetDescriptor esd) {
891    return connectionAllowed(esd.getName());
892  }
893
894  /**
895   * Notify this object that it has been registered as a listener with
896   * a source with respect to the supplied event name
897   *
898   * @param eventName
899   * @param source the source with which this object has been registered as
900   * a listener
901   */
902  public synchronized void connectionNotification(String eventName,
903                                                  Object source) {
904    if (connectionAllowed(eventName)) {
905      m_listenees.put(eventName, source);
906      if (m_Filter instanceof ConnectionNotificationConsumer) {
907        ((ConnectionNotificationConsumer) m_Filter).
908          connectionNotification(eventName, source);
909      }
910    }
911  }
912
913  /**
914   * Notify this object that it has been deregistered as a listener with
915   * a source with respect to the supplied event name
916   *
917   * @param eventName the event
918   * @param source the source with which this object has been registered as
919   * a listener
920   */
921  public synchronized void disconnectionNotification(String eventName,
922                                                     Object source) {
923    if (m_Filter instanceof ConnectionNotificationConsumer) {
924      ((ConnectionNotificationConsumer) m_Filter).
925        disconnectionNotification(eventName, source);
926    }
927    m_listenees.remove(eventName);
928  }
929
930  /**
931   * Function used to stop code that calls acceptTrainingSet, acceptTestSet,
932   * or acceptDataSet. This is
933   * needed as filtering is performed inside a separate
934   * thread of execution.
935   *
936   * @param tf a <code>boolean</code> value
937   */
938  private synchronized void block(boolean tf) {
939    if (tf) {
940      try {
941        // only block if thread is still doing something useful!
942        if (m_filterThread.isAlive() && m_state != IDLE) {
943          wait();
944        }
945      } catch (InterruptedException ex) {
946      }
947    } else {
948      notifyAll();
949    }
950  }
951
952  /**
953   * Stop all action if possible
954   */
955  public void stop() {
956    // tell all listenees (upstream beans) to stop
957    Enumeration en = m_listenees.keys();
958    while (en.hasMoreElements()) {
959      Object tempO = m_listenees.get(en.nextElement());
960      if (tempO instanceof BeanCommon) {
961        ((BeanCommon)tempO).stop();
962      }
963    }
964   
965    // stop the filter thread
966    if (m_filterThread != null) {
967      m_filterThread.interrupt();
968      m_filterThread.stop();
969      m_filterThread = null;
970      m_visual.setStatic();
971    }
972  }
973 
974  /**
975   * Returns true if. at this time, the bean is busy with some
976   * (i.e. perhaps a worker thread is performing some calculation).
977   *
978   * @return true if the bean is busy.
979   */
980  public boolean isBusy() {
981    return (m_filterThread != null);
982  }
983 
984  /**
985   * Set a logger
986   *
987   * @param logger a <code>Logger</code> value
988   */
989  public void setLog(Logger logger) {
990    m_log = logger;
991
992    if (m_Filter != null && m_Filter instanceof LogWriter) {
993      ((LogWriter) m_Filter).setLog(m_log);
994    }
995  }
996
997  /**
998   * Return an enumeration of user requests
999   *
1000   * @return an <code>Enumeration</code> value
1001   */
1002  public Enumeration enumerateRequests() {
1003    Vector newVector = new Vector(0);
1004    if (m_filterThread != null) {
1005      newVector.addElement("Stop");
1006    }
1007    return newVector.elements();
1008  }
1009
1010  /**
1011   * Perform the named request
1012   *
1013   * @param request a <code>String</code> value
1014   * @exception IllegalArgumentException if an error occurs
1015   */
1016  public void performRequest(String request) {
1017    if (request.compareTo("Stop") == 0) {
1018      stop();
1019    } else {
1020      throw new IllegalArgumentException(request
1021                                         + " not supported (Filter)");
1022    }
1023  }
1024
1025  /**
1026   * Returns true, if at the current time, the named event could
1027   * be generated. Assumes that supplied event names are names of
1028   * events that could be generated by this bean.
1029   *
1030   * @param eventName the name of the event in question
1031   * @return true if the named event could be generated at this point in
1032   * time
1033   */
1034  public boolean eventGeneratable(String eventName) {
1035   
1036    if (eventName.equals("configuration") && m_Filter != null) {
1037      return true;
1038    }
1039   
1040    // can't generate the named even if we are not receiving it as an
1041    // input!
1042    if (!m_listenees.containsKey(eventName)) {
1043      return false;
1044    }
1045    Object source = m_listenees.get(eventName);
1046    if (source instanceof EventConstraints) {
1047      if (!((EventConstraints)source).eventGeneratable(eventName)) {
1048        return false;
1049      }
1050    }
1051    if (eventName.compareTo("instance") == 0) {
1052      if (!(m_Filter instanceof StreamableFilter)) {
1053        return false;
1054      }
1055    }
1056    return true;
1057  }
1058 
1059  private String statusMessagePrefix() {
1060    return getCustomName() + "$" + hashCode() + "|"
1061    + ((m_Filter instanceof OptionHandler &&
1062        Utils.joinOptions(((OptionHandler)m_Filter).getOptions()).length() > 0) 
1063        ? Utils.joinOptions(((OptionHandler)m_Filter).getOptions()) + "|"
1064            : "");
1065  }
1066}
Note: See TracBrowser for help on using the repository browser.