source: src/main/java/weka/gui/beans/Loader.java @ 11

Last change on this file since 11 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 21.9 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 *    Loader.java
19 *    Copyright (C) 2002 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.beans;
24
25import weka.core.Environment;
26import weka.core.EnvironmentHandler;
27import weka.core.Instance;
28import weka.core.Instances;
29import weka.core.OptionHandler;
30import weka.core.Utils;
31import weka.core.converters.ArffLoader;
32import weka.core.converters.DatabaseLoader;
33import weka.core.converters.FileSourcedConverter;
34import weka.gui.Logger;
35
36import java.awt.BorderLayout;
37import java.awt.event.ActionEvent;
38import java.awt.event.ActionListener;
39import java.beans.EventSetDescriptor;
40import java.beans.beancontext.BeanContext;
41import java.io.File;
42import java.io.IOException;
43import java.io.ObjectInputStream;
44import java.io.ObjectStreamException;
45import java.util.Enumeration;
46import java.util.Vector;
47
48import javax.swing.JButton;
49
50/**
51 * Loads data sets using weka.core.converter classes
52 *
53 * @author <a href="mailto:mhall@cs.waikato.ac.nz">Mark Hall</a>
54 * @version $Revision: 5396 $
55 * @since 1.0
56 * @see AbstractDataSource
57 * @see UserRequestAcceptor
58 */
59public class Loader
60  extends AbstractDataSource
61  implements Startable, /*UserRequestAcceptor,*/ WekaWrapper,
62             EventConstraints, BeanCommon, EnvironmentHandler {
63
64  /** for serialization */
65  private static final long serialVersionUID = 1993738191961163027L;
66
67  /**
68   * Holds the instances loaded
69   */
70  private transient Instances m_dataSet;
71
72  /**
73   * Holds the format of the last loaded data set
74   */
75  private transient Instances m_dataFormat;
76
77  /**
78   * Global info for the wrapped loader (if it exists).
79   */
80  protected String m_globalInfo;
81
82  /**
83   * Thread for doing IO in
84   */
85  private LoadThread m_ioThread;
86
87  private static int IDLE = 0;
88  private static int BATCH_LOADING = 1;
89  private static int INCREMENTAL_LOADING = 2;
90  private int m_state = IDLE;
91
92  /**
93   * Loader
94   */
95  private weka.core.converters.Loader m_Loader = new ArffLoader();
96
97  private InstanceEvent m_ie = new InstanceEvent(this);
98
99  /**
100   * Keep track of how many listeners for different types of events there are.
101   */
102  private int m_instanceEventTargets = 0;
103  private int m_dataSetEventTargets = 0;
104 
105  /** Flag indicating that a database has already been configured*/
106  private boolean m_dbSet = false;
107 
108  /**
109   * Logging
110   */
111  protected transient Logger m_log;
112 
113  /**
114   * The environment variables.
115   */
116  protected transient Environment m_env;
117 
118  /**
119   * Asked to stop?
120   */
121  protected boolean m_stopped = false;
122 
123  private class LoadThread extends Thread {
124    private DataSource m_DP;
125
126    public LoadThread(DataSource dp) {
127      m_DP = dp;
128    }
129
130    public void run() {
131      try {
132        m_visual.setAnimated();
133//        m_visual.setText("Loading...");
134       
135        boolean instanceGeneration = true;
136        // determine if we are going to produce data set or instance events
137        /*      for (int i = 0; i < m_listeners.size(); i++) {
138          if (m_listeners.elementAt(i) instanceof DataSourceListener) {
139            instanceGeneration = false;
140            break;
141          }
142          } */
143        if (m_dataSetEventTargets > 0) {
144          instanceGeneration = false;
145          m_state = BATCH_LOADING;
146        }
147       
148        // Set environment variables
149        if (m_Loader instanceof EnvironmentHandler && m_env != null) {
150          ((EnvironmentHandler)m_Loader).setEnvironment(m_env);
151        }
152       
153        String msg = statusMessagePrefix();
154        if (m_Loader instanceof FileSourcedConverter) {
155          msg += "Loading " + ((FileSourcedConverter)m_Loader).retrieveFile().getName();
156        } else {
157          msg += "Loading...";
158        }
159        if (m_log != null) {
160          m_log.statusMessage(msg);
161        }
162
163        if (instanceGeneration) {
164          m_state = INCREMENTAL_LOADING;
165          //      boolean start = true;
166          Instance nextInstance = null;
167          // load and pass on the structure first
168          Instances structure = null;
169          try {
170            m_Loader.reset();
171            //      System.err.println("NOTIFYING STRUCTURE AVAIL");
172            structure = m_Loader.getStructure();
173            notifyStructureAvailable(structure);
174          } catch (IOException e) {
175            if (m_log != null) {
176              m_log.statusMessage(statusMessagePrefix()
177                  +"ERROR (See log for details");
178              m_log.logMessage("[Loader] " + statusMessagePrefix()
179                  + " " + e.getMessage());
180            }
181            e.printStackTrace();
182          }
183          try {
184            nextInstance = m_Loader.getNextInstance(structure);
185          } catch (IOException e) {
186            if (m_log != null) {
187              m_log.statusMessage(statusMessagePrefix()
188                  +"ERROR (See log for details");
189              m_log.logMessage("[Loader] " + statusMessagePrefix()
190                  + " " + e.getMessage());
191            }
192            e.printStackTrace();
193          }
194          int z = 0;
195          while (nextInstance != null) {
196            if (m_stopped) {
197              break;
198            }
199            nextInstance.setDataset(structure);
200            //      format.add(nextInstance);
201            /*      InstanceEvent ie = (start)
202              ? new InstanceEvent(m_DP, nextInstance,
203                                  InstanceEvent.FORMAT_AVAILABLE)
204                : new InstanceEvent(m_DP, nextInstance,
205                InstanceEvent.INSTANCE_AVAILABLE); */
206            //      if (start) {
207            //        m_ie.setStatus(InstanceEvent.FORMAT_AVAILABLE);
208              //            } else {
209            m_ie.setStatus(InstanceEvent.INSTANCE_AVAILABLE);
210              //            }
211            m_ie.setInstance(nextInstance);
212            //      start = false;
213            //      System.err.println(z);
214            nextInstance = m_Loader.getNextInstance(structure);
215            if (nextInstance == null) {
216              m_ie.setStatus(InstanceEvent.BATCH_FINISHED);
217            }
218            notifyInstanceLoaded(m_ie);
219            z++;
220            if (z % 10000 == 0) {
221//              m_visual.setText("" + z + " instances...");
222              if (m_log != null) {
223                m_log.statusMessage(statusMessagePrefix() 
224                    + "Loaded " + z + " instances");
225              }
226            }
227          }
228          m_visual.setStatic();
229//        m_visual.setText(structure.relationName());
230        } else {
231          m_Loader.reset();
232          m_dataSet = m_Loader.getDataSet();
233          m_visual.setStatic();
234          if (m_log != null) {
235            m_log.logMessage("[Loader] " + statusMessagePrefix() 
236                + " loaded " + m_dataSet.relationName());
237          }
238//        m_visual.setText(m_dataSet.relationName());
239          notifyDataSetLoaded(new DataSetEvent(m_DP, m_dataSet));
240        }
241      } catch (Exception ex) {
242        if (m_log != null) {
243          m_log.statusMessage(statusMessagePrefix()
244              +"ERROR (See log for details");
245          m_log.logMessage("[Loader] " + statusMessagePrefix()
246              + " " + ex.getMessage());
247        }
248        ex.printStackTrace();
249      } finally {
250        if (Thread.currentThread().isInterrupted()) {
251          if (m_log != null) {
252            m_log.logMessage("[Loader] " + statusMessagePrefix() 
253                + " loading interrupted!");
254          }
255        }
256        m_ioThread = null;
257        //      m_visual.setText("Finished");
258        //      m_visual.setIcon(m_inactive.getVisual());
259        m_visual.setStatic();
260        m_state = IDLE;
261        m_stopped = false;
262        if (m_log != null) {
263          m_log.statusMessage(statusMessagePrefix() + "Finished.");
264        }
265        block(false);
266      }
267    }
268  }
269
270  /**
271   * Global info (if it exists) for the wrapped loader
272   *
273   * @return the global info
274   */
275  public String globalInfo() {
276    return m_globalInfo;
277  }
278
279  public Loader() {
280    super();
281    setLoader(m_Loader);
282    appearanceFinal();
283  }
284 
285  public void setDB(boolean flag){
286 
287      m_dbSet = flag;
288  }
289
290  protected void appearanceFinal() {
291    removeAll();
292    setLayout(new BorderLayout());
293    JButton goButton = new JButton("Start...");
294    add(goButton, BorderLayout.CENTER);
295    goButton.addActionListener(new ActionListener() {
296        public void actionPerformed(ActionEvent e) {
297          startLoading();
298        }
299      });
300  }
301
302  protected void appearanceDesign() {
303    removeAll();
304    setLayout(new BorderLayout());
305    add(m_visual, BorderLayout.CENTER);
306  }
307
308  /**
309   * Set a bean context for this bean
310   *
311   * @param bc a <code>BeanContext</code> value
312   */
313  public void setBeanContext(BeanContext bc) {
314    super.setBeanContext(bc);
315    if (m_design) {
316      appearanceDesign();
317    } else {
318      appearanceFinal();
319    }
320  }
321
322  /**
323   * Set the loader to use
324   *
325   * @param loader a <code>weka.core.converters.Loader</code> value
326   */
327  public void setLoader(weka.core.converters.Loader loader) {
328    boolean loadImages = true;
329    if (loader.getClass().getName().
330        compareTo(m_Loader.getClass().getName()) == 0) {
331      loadImages = false;
332    }
333    m_Loader = loader;
334    String loaderName = loader.getClass().toString();
335    loaderName = loaderName.substring(loaderName.
336                                      lastIndexOf('.')+1, 
337                                      loaderName.length());
338    if (loadImages) {
339      if (m_Loader instanceof Visible) {
340        m_visual = ((Visible) m_Loader).getVisual();
341      } else {
342
343        if (!m_visual.loadIcons(BeanVisual.ICON_PATH+loaderName+".gif",
344                                BeanVisual.ICON_PATH+loaderName+"_animated.gif")) {
345          useDefaultVisual();
346        }
347      }
348    }
349    m_visual.setText(loaderName);
350   
351    // get global info
352    m_globalInfo = KnowledgeFlowApp.getGlobalInfo(m_Loader);
353  }
354 
355  protected void newFileSelected() {
356    if(! (m_Loader instanceof DatabaseLoader)) {
357      // try to load structure (if possible) and notify any listeners
358      try {
359        // Set environment variables
360        if (m_Loader instanceof EnvironmentHandler && m_env != null) {
361          ((EnvironmentHandler)m_Loader).setEnvironment(m_env);
362        }
363        m_dataFormat = m_Loader.getStructure();
364        //      System.err.println(m_dataFormat);
365        System.out.println("[Loader] Notifying listeners of instance structure avail.");
366        notifyStructureAvailable(m_dataFormat);
367      }catch (Exception ex) {
368      }
369    }
370  }
371
372  /**
373   * Get the loader
374   *
375   * @return a <code>weka.core.converters.Loader</code> value
376   */
377  public weka.core.converters.Loader getLoader() {
378    return m_Loader;
379  }
380
381  /**
382   * Set the loader
383   *
384   * @param algorithm a Loader
385   * @exception IllegalArgumentException if an error occurs
386   */
387  public void setWrappedAlgorithm(Object algorithm) 
388    {
389
390    if (!(algorithm instanceof weka.core.converters.Loader)) { 
391      throw new IllegalArgumentException(algorithm.getClass()+" : incorrect "
392                                         +"type of algorithm (Loader)");
393    }
394    setLoader((weka.core.converters.Loader)algorithm);
395  }
396
397  /**
398   * Get the loader
399   *
400   * @return a Loader
401   */
402  public Object getWrappedAlgorithm() {
403    return getLoader();
404  }
405
406  /**
407   * Notify all listeners that the structure of a data set
408   * is available.
409   *
410   * @param structure an <code>Instances</code> value
411   */
412  protected void notifyStructureAvailable(Instances structure) {
413    if (m_dataSetEventTargets > 0 && structure != null) {
414      DataSetEvent dse = new DataSetEvent(this, structure);
415      notifyDataSetLoaded(dse);
416    } else if (m_instanceEventTargets > 0 && structure != null) {
417      m_ie.setStructure(structure);
418      notifyInstanceLoaded(m_ie);
419    }
420  }
421
422  /**
423   * Notify all Data source listeners that a data set has been loaded
424   *
425   * @param e a <code>DataSetEvent</code> value
426   */
427  protected void notifyDataSetLoaded(DataSetEvent e) {
428    Vector l;
429    synchronized (this) {
430      l = (Vector)m_listeners.clone();
431    }
432   
433    if (l.size() > 0) {
434      for(int i = 0; i < l.size(); i++) {
435        ((DataSourceListener)l.elementAt(i)).acceptDataSet(e);
436      }
437      m_dataSet = null;
438    }
439  }
440
441  /**
442   * Notify all instance listeners that a new instance is available
443   *
444   * @param e an <code>InstanceEvent</code> value
445   */
446  protected void notifyInstanceLoaded(InstanceEvent e) {
447    Vector l;
448    synchronized (this) {
449      l = (Vector)m_listeners.clone();
450    }
451   
452    if (l.size() > 0) {
453      for(int i = 0; i < l.size(); i++) {
454        ((InstanceListener)l.elementAt(i)).acceptInstance(e);
455      }
456      m_dataSet = null;
457    }
458  }
459
460 
461  /**
462   * Start loading data
463   */
464  public void startLoading() {
465    if (m_ioThread == null) {
466      //      m_visual.setText(m_dataSetFile.getName());
467      m_state = BATCH_LOADING;
468      m_ioThread = new LoadThread(Loader.this);
469      m_ioThread.setPriority(Thread.MIN_PRIORITY);
470      m_ioThread.start();
471    } else {
472      m_ioThread = null;
473      m_state = IDLE;
474    }
475  }
476
477  /**
478   * Get a list of user requests
479   *
480   * @return an <code>Enumeration</code> value
481   */
482  /*public Enumeration enumerateRequests() {
483    Vector newVector = new Vector(0);
484    boolean ok = true;
485    if (m_ioThread == null) {
486      if (m_Loader instanceof FileSourcedConverter) {
487        String temp = ((FileSourcedConverter) m_Loader).retrieveFile().getPath();
488        Environment env = (m_env == null) ? Environment.getSystemWide() : m_env;
489        try {
490          temp = env.substitute(temp);
491        } catch (Exception ex) {}
492        File tempF = new File(temp);
493        if (!tempF.isFile()) {
494          ok = false;
495        }
496      }
497      String entry = "Start loading";
498      if (!ok) {
499        entry = "$"+entry;
500      }
501      newVector.addElement(entry);
502    }
503    return newVector.elements();
504  } */
505
506  /**
507   * Perform the named request
508   *
509   * @param request a <code>String</code> value
510   * @exception IllegalArgumentException if an error occurs
511   */
512  /*public void performRequest(String request) {
513    if (request.compareTo("Start loading") == 0) {
514      startLoading();
515    } else {
516      throw new IllegalArgumentException(request
517                                         + " not supported (Loader)");
518    }
519  } */
520
521  /**
522   * Start loading
523   *
524   * @exception Exception if something goes wrong
525   */
526  public void start() throws Exception {
527    startLoading();
528    block(true);
529  }
530 
531  /**
532   * Gets a string that describes the start action. The
533   * KnowledgeFlow uses this in the popup contextual menu
534   * for the component. The string can be proceeded by
535   * a '$' character to indicate that the component can't
536   * be started at present.
537   *
538   * @return a string describing the start action.
539   */
540  public String getStartMessage() {
541    boolean ok = true;
542    String entry = "Start loading";
543    if (m_ioThread == null) {
544      if (m_Loader instanceof FileSourcedConverter) {
545        String temp = ((FileSourcedConverter) m_Loader).retrieveFile().getPath();
546        Environment env = (m_env == null) ? Environment.getSystemWide() : m_env;
547        try {
548          temp = env.substitute(temp);
549        } catch (Exception ex) {}
550        File tempF = new File(temp);
551        if (!tempF.isFile()) {
552          ok = false;
553        }
554      }
555      if (!ok) {
556        entry = "$"+entry;
557      }
558    }
559   
560    return entry;
561  }
562 
563  /**
564   * Function used to stop code that calls acceptTrainingSet. This is
565   * needed as classifier construction is performed inside a separate
566   * thread of execution.
567   *
568   * @param tf a <code>boolean</code> value
569   */
570  private synchronized void block(boolean tf) {
571
572    if (tf) {
573      try {
574          // only block if thread is still doing something useful!
575        if (m_ioThread.isAlive() && m_state != IDLE) {
576          wait();
577        }
578      } catch (InterruptedException ex) {
579      }
580    } else {
581      notifyAll();
582    }
583  }
584
585  /**
586   * Returns true if the named event can be generated at this time
587   *
588   * @param eventName the event
589   * @return a <code>boolean</code> value
590   */
591  public boolean eventGeneratable(String eventName) {
592    if (eventName.compareTo("instance") == 0) {
593      if (!(m_Loader instanceof weka.core.converters.IncrementalConverter)) {
594        return false;
595      }
596      if (m_dataSetEventTargets > 0) {
597        return false;
598      }
599      /*      for (int i = 0; i < m_listeners.size(); i++) {
600        if (m_listeners.elementAt(i) instanceof DataSourceListener) {
601          return false;
602        }
603        } */
604    }
605
606    if (eventName.compareTo("dataSet") == 0) {
607      if (!(m_Loader instanceof weka.core.converters.BatchConverter)) {
608        return false;
609      }
610      if (m_instanceEventTargets > 0) {
611        return false;
612      }
613      /*      for (int i = 0; i < m_listeners.size(); i++) {
614        if (m_listeners.elementAt(i) instanceof InstanceListener) {
615          return false;
616        }
617        } */
618    }
619    return true;
620  }
621
622  /**
623   * Add a listener
624   *
625   * @param dsl a <code>DataSourceListener</code> value
626   */
627  public synchronized void addDataSourceListener(DataSourceListener dsl) {
628    super.addDataSourceListener(dsl);
629    m_dataSetEventTargets ++;
630    // pass on any current instance format
631    try{
632      if((m_Loader instanceof DatabaseLoader && m_dbSet && m_dataFormat == null) || 
633         (!(m_Loader instanceof DatabaseLoader) && m_dataFormat == null)) {
634        m_dataFormat = m_Loader.getStructure();
635        m_dbSet = false;
636      }
637    }catch(Exception ex){
638    }
639    notifyStructureAvailable(m_dataFormat);
640  }
641 
642  /**
643   * Remove a listener
644   *
645   * @param dsl a <code>DataSourceListener</code> value
646   */
647  public synchronized void removeDataSourceListener(DataSourceListener dsl) {
648    super.removeDataSourceListener(dsl);
649    m_dataSetEventTargets --;
650  }
651
652  /**
653   * Add an instance listener
654   *
655   * @param dsl a <code>InstanceListener</code> value
656   */
657  public synchronized void addInstanceListener(InstanceListener dsl) {
658    super.addInstanceListener(dsl);
659    m_instanceEventTargets ++;
660    try{
661      if((m_Loader instanceof DatabaseLoader && m_dbSet && m_dataFormat == null) || 
662         (!(m_Loader instanceof DatabaseLoader) && m_dataFormat == null)) {
663        m_dataFormat = m_Loader.getStructure();
664        m_dbSet = false;
665      }
666    }catch(Exception ex){
667    }
668    // pass on any current instance format     
669    notifyStructureAvailable(m_dataFormat);
670  }
671 
672  /**
673   * Remove an instance listener
674   *
675   * @param dsl a <code>InstanceListener</code> value
676   */
677  public synchronized void removeInstanceListener(InstanceListener dsl) {
678    super.removeInstanceListener(dsl);
679    m_instanceEventTargets --;
680  }
681 
682  public static void main(String [] args) {
683    try {
684      final javax.swing.JFrame jf = new javax.swing.JFrame();
685      jf.getContentPane().setLayout(new java.awt.BorderLayout());
686
687      final Loader tv = new Loader();
688
689      jf.getContentPane().add(tv, java.awt.BorderLayout.CENTER);
690      jf.addWindowListener(new java.awt.event.WindowAdapter() {
691        public void windowClosing(java.awt.event.WindowEvent e) {
692          jf.dispose();
693          System.exit(0);
694        }
695      });
696      jf.setSize(800,600);
697      jf.setVisible(true);
698    } catch (Exception ex) {
699      ex.printStackTrace();
700    }
701  }
702 
703  private Object readResolve() throws ObjectStreamException {
704    // try and reset the Loader
705    if (m_Loader != null) {
706      try {
707        m_Loader.reset();
708      } catch (Exception ex) {
709      }
710    }
711    return this;
712  }
713 
714  /**
715   * Set a custom (descriptive) name for this bean
716   *
717   * @param name the name to use
718   */
719  public void setCustomName(String name) {
720    m_visual.setText(name);
721  }
722 
723  /**
724   * Get the custom (descriptive) name for this bean (if one has been set)
725   *
726   * @return the custom name (or the default name)
727   */
728  public String getCustomName() {
729    return m_visual.getText();
730  }
731  /**
732   * Set a logger
733   *
734   * @param logger a <code>weka.gui.Logger</code> value
735   */
736  public void setLog(Logger logger) {
737    m_log = logger;
738  }
739 
740  /**
741   * Set environment variables to use.
742   *
743   * @param env the environment variables to
744   * use
745   */
746  public void setEnvironment(Environment env) {
747    m_env = env;
748  }
749 
750  /**
751   * Returns true if, at this time,
752   * the object will accept a connection via the supplied
753   * EventSetDescriptor. Always returns false for loader.
754   *
755   * @param esd the EventSetDescriptor
756   * @return true if the object will accept a connection
757   */
758  public boolean connectionAllowed(EventSetDescriptor esd) {
759    return false;
760  }
761 
762  /**
763   * Returns true if, at this time,
764   * the object will accept a connection via the named event
765   *
766   * @param eventName the name of the event
767   * @return true if the object will accept a connection
768   */
769  public boolean connectionAllowed(String eventName) {
770    return false;
771  }
772 
773  /**
774   * Notify this object that it has been registered as a listener with
775   * a source for receiving events described by the named event
776   * This object is responsible for recording this fact.
777   *
778   * @param eventName the event
779   * @param source the source with which this object has been registered as
780   * a listener
781   */
782  public void connectionNotification(String eventName, Object source) {
783    // this should never get called for us.
784  }
785 
786  /**
787   * Notify this object that it has been deregistered as a listener with
788   * a source for named event. This object is responsible
789   * for recording this fact.
790   *
791   * @param eventName the event
792   * @param source the source with which this object has been registered as
793   * a listener
794   */
795  public void disconnectionNotification(String eventName, Object source) {
796    // this should never get called for us.
797  }
798 
799  /**
800   * Stop any loading action.
801   */
802  public void stop() {
803    m_stopped = true;
804  }
805 
806  /**
807   * Returns true if. at this time, the bean is busy with some
808   * (i.e. perhaps a worker thread is performing some calculation).
809   *
810   * @return true if the bean is busy.
811   */
812  public boolean isBusy() {
813    return (m_ioThread != null);
814  }
815 
816  private String statusMessagePrefix() {
817    return getCustomName() + "$" + hashCode() + "|"
818    + ((m_Loader instanceof OptionHandler) 
819        ? Utils.joinOptions(((OptionHandler)m_Loader).getOptions()) + "|"
820            : "");
821  }
822 
823  // Custom de-serialization in order to set default
824  // environment variables on de-serialization
825  private void readObject(ObjectInputStream aStream) 
826    throws IOException, ClassNotFoundException {
827    aStream.defaultReadObject();
828   
829    // set a default environment to use
830    m_env = Environment.getSystemWide();
831  }
832}
833
Note: See TracBrowser for help on using the repository browser.