Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: recoinx/clef/CLEFClient.java


1   
2   package recoinx.clef;
3   
4   import javax.swing.*;
5   
6   import org.apache.log4j.Logger;
7   import org.dom4j.Document;
8   import org.dom4j.DocumentException;
9   import org.dom4j.Element;
10  import org.dom4j.io.OutputFormat;
11  import org.dom4j.io.SAXReader;
12  import org.dom4j.io.XMLWriter;
13  
14  import java.util.Iterator;
15  import java.util.Vector;
16  import java.util.Enumeration;
17  import java.awt.Dimension;
18  import java.awt.GridBagConstraints;
19  import java.awt.GridBagLayout;
20  import java.awt.Insets;
21  import java.awt.event.ActionEvent;
22  import java.awt.event.ActionListener;
23  import java.awt.event.WindowListener;
24  import java.awt.BorderLayout;
25  import java.io.BufferedReader;
26  import java.io.BufferedWriter;
27  import java.io.File;
28  import java.io.FileWriter;
29  import java.io.IOException;
30  import java.io.Reader;
31  import java.io.StringReader;
32  import java.io.Writer;
33  import java.rmi.RemoteException;
34  import java.rmi.RMISecurityManager;
35  import java.rmi.Naming;
36  import java.rmi.server.UnicastRemoteObject;
37  
38  import recoin.container.Result;
39  import recoin.container.ResultList;
40  
41  /**
42   * The CLEFClient represents an application that offers graphical means to
43   * enter all parameters needed to execute the retrieval process, send them and 
44   * process the results upon completion.
45   * @author Jan H. Scheufen
46   * @version 0.2.9
47   */
48  public class CLEFClient implements ActionListener, WindowListener 
49  {
50    /**
51     * The logger for this class.
52     */
53    static Logger logger;
54    /**
55     * A SAXReader to read XML files.
56     */
57    private SAXReader xmlReader;
58    /**
59     * A SAXWriter to write XML files.
60     */
61    private XMLWriter xmlWriter;
62    /**
63     * A TRECFormatWriter to create the official TREC format for results.
64     */
65    private TRECFormatWriter formatWriter;
66    /**
67     * The file with the topics.
68     */
69    private File topicFile = null;
70    /**
71     * The URL of the CLEF RMI service.
72     */
73    private String serverURL = "rmi://localhost/RMICLEFService";
74    /**
75     * The RemoteCLEFConnector.
76     */
77    private RemoteCLEFConnector remoteConnector;
78    /**
79     * A JFrame for this CLEFClient.
80     */
81    private JFrame appletFrame;
82    /**
83     * The JTextFields.
84     */
85    private JTextField tfCutOff, tfTopicNumber, tfTopicPath, tfSavePath;
86    /**
87     * The JLabels.
88     */
89    private JLabel lTopic, lSave, lMessage;
90    /**
91     * The JButtons.
92     */
93    private JButton bBrowseTopic, bBrowseSave, bSubmit;
94    /**
95     * A RMI service that receives the answer from the RemoteCLEFConnector.
96     */
97    private CLEFClient.RMIClient client;
98    /**
99     * A CLEFFileChooser to select the topic file from the file system.
100    */
101   private CLEFFileChooser topicChooser;
102   /**
103    * A CLEFFileChooser to select the directory to save results to from the file system.
104    */
105   private CLEFFileChooser saveChooser;
106   
107   /**
108    * Creates a new CLEFClient.
109    */
110   public CLEFClient() 
111   {
112     super();
113 
114     logger = Logger.getLogger( CLEFClient.class.getName() );
115 
116     xmlReader = new SAXReader();
117 
118     try
119     {
120       client = new RMIClient();
121     }
122     catch( RemoteException e )
123     {
124       logger.error("Couldn't initiate RemoteClient.", e);
125     }
126     
127     remoteConnector = lookupConnector( serverURL );
128     
129     initiateComponents();
130     
131     // create the CLEFFileChoosers
132     topicChooser = new CLEFFileChooser( System.getProperty("user.dir") , "Select the XML topic file." );
133     saveChooser = new CLEFFileChooser( System.getProperty("user.dir") , "Select a directory to save to." );
134     saveChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY );
135     
136     appletFrame.setLocation(100,100);
137     appletFrame.pack();
138     appletFrame.setVisible(true);
139     logger.debug("CLEFClient created.");
140   }
141   
142   /**
143    * Looks up the RemoteCLEFConnector service in the rmiregistry using the specified URL.
144    * @param connectorURL the URL of the RMI service
145    * @return a RemotePublicConnector
146    */
147   public RemoteCLEFConnector lookupConnector(String connectorURL) 
148   {
149     RemoteCLEFConnector rcc = null;
150     try
151     {
152       // Overwriting security methods.
153       System.setSecurityManager (new RMISecurityManager() {
154         public void checkConnect (String host, int port) {}
155         public void checkConnect (String host, int port, Object context) {}
156         public void checkAccept (String host, int port) {}
157         public void checkRead (String file) {}
158         public void checkWrite (String file) {}
159         // allow access to system properties
160         public void checkPropertyAccess(String key) {}
161       });
162 
163       rcc = (RemoteCLEFConnector) Naming.lookup( connectorURL );
164     }
165     catch( Exception e )
166     {
167         logger.error("Error lookupConnector()", e);
168     }
169 
170     return rcc;    
171   }
172   
173   /**
174    * Handles ActionEvents from the buttons of this CLEFClient and triggers the
175    * submit mechanism or opens the CLEFFileChooser, for example.
176    * @param e the ActionEvent
177    * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
178    */
179   public void actionPerformed(ActionEvent event)
180   {
181     try
182     {
183       JButton button = (JButton)event.getSource();
184       //######### BROWSE TOPIC ###########
185       if( button.equals( bBrowseTopic ) )
186       {
187         int value = topicChooser.showOpenDialog( appletFrame );
188         if( value == JFileChooser.APPROVE_OPTION )
189         {
190           String filePath = topicChooser.getSelectedFile().getAbsolutePath();
191           tfTopicPath.setText( filePath );
192         }
193       }
194       //######### BROWSE SAVEPATH ###########
195       else if( button.equals( bBrowseSave ) )
196       {
197         int value = saveChooser.showOpenDialog( appletFrame );
198         if( value == JFileChooser.APPROVE_OPTION )
199         {
200           String filePath = saveChooser.getSelectedFile().getAbsolutePath();
201           tfSavePath.setText( filePath );
202         }
203       }
204       //######### SUBMIT ###########
205       else if( button.equals( bSubmit ) )
206       {
207         Document topicDoc = null;
208         if( tfTopicPath.getText().equals("") )
209         {
210           //logger.error("Topic file not specified in CLEFClient!");
211           printMessage("ERROR: You must specify a topic file!");
212           return;
213         }
214         else if( tfSavePath.getText().equals("") )
215         {
216           //logger.error("Topic file not specified in CLEFClient!");
217           printMessage("ERROR: You must specify a directory to save to!");
218           return;
219         }
220         else
221         {
222           // TODO no verfification if specified files/dirs exist!
223           topicDoc = createDocument( new File( tfTopicPath.getText() ) );
224           client.setSavePath( tfSavePath.getText() );
225         }
226         
227         CLEFQuery query = null;
228         
229         int cutOff = 0;
230         try
231         {
232           cutOff = Integer.parseInt(tfCutOff.getText());
233         }
234         catch( NumberFormatException e )
235         {
236           printMessage("ERROR: The value in the Cut Off field is not numerical!");
237           return;
238         }
239         
240         // if topicNumber is specified process particular topic
241         String topicNumber = tfTopicNumber.getText();
242         if( !topicNumber.equals("") )
243         {
244           Iterator topicIter = getTopicIterator( topicDoc );
245           while( topicIter.hasNext() )
246           {
247             Element topic = (Element)topicIter.next();
248             // find topic with specified topicNumber
249             if( topic.element("num").getTextTrim().equals( topicNumber ) )
250             {
251               // create a new query for this topic
252               query = new CLEFQuery( topicNumber );
253               if( cutOff > 0 )
254                 query.setCutOff( cutOff );
255               query.addTopic( topic.elementTextTrim("EN-desc"), CLEFConstants.ENGLISH );
256               break;
257             }
258           }
259           // Send to RMI service
260           remoteConnector.acceptQuery( client, query );
261         }
262         // otherwise process all topics
263         else
264         {
265           // Get an iterator over the topics
266           Iterator topicIter = getTopicIterator( topicDoc );
267           while( topicIter.hasNext() )
268           {
269             Element topic = (Element)topicIter.next();
270             // create a new query for this topic
271             query = new CLEFQuery( topicNumber );
272             if( cutOff > 0 )
273               query.setCutOff( cutOff );
274             query.addTopic( topic.elementTextTrim("EN-desc"), CLEFConstants.ENGLISH );
275             // Send to RMI service
276             remoteConnector.acceptQuery( client, query );
277             logger.debug("Query abgeschickt.");    
278           }
279         }
280       }
281     }
282     catch( RemoteException e )
283     {
284       logger.error("RemoteException beim Senden des CLEFQuery.", e);  
285     }
286     catch (DocumentException e)
287     {
288       logger.error("Unable to create topic document.", e);
289     }
290   }
291   
292   /**
293    * Outputs the specified message to the user.
294    * @param msg the message
295    */
296   private void printMessage(String msg)
297   {
298     this.lMessage.setText( msg );    
299   }
300 
301   /**
302    * Main-method of this CLEFClient that starts the client.
303    * @param args
304    */
305   public static void main(String[] args) 
306   {
307     new CLEFClient();    
308   }
309   
310   /**
311    * Exits this CLEFClient.
312    * @param windowEvent
313    * @see java.awt.event.WindowListener#windowClosing(java.awt.event.WindowEvent)
314    */
315   public void windowClosing(java.awt.event.WindowEvent windowEvent) 
316   {
317     System.exit(0);    
318   }
319   
320   /**
321    * Empty implementation of WindowListener method.
322    * @param e the WindowEvent
323    * @see java.awt.event.WindowListener#windowActivated(java.awt.event.WindowEvent)
324    */
325   public void windowActivated(java.awt.event.WindowEvent windowEvent) 
326   {
327     
328   }
329   
330   /**
331    * Empty implementation of WindowListener method.
332    * @param e the WindowEvent
333    * @see java.awt.event.WindowListener#windowDeiconified(java.awt.event.WindowEvent)
334    */
335   public void windowDeiconified(java.awt.event.WindowEvent windowEvent) 
336   {
337     
338   }
339   
340   /**
341    * Empty implementation of WindowListener method.
342    * @param e the WindowEvent
343    * @see java.awt.event.WindowListener#windowDeactivated(java.awt.event.WindowEvent)
344    */
345   public void windowDeactivated(java.awt.event.WindowEvent windowEvent) 
346   {
347     
348   }
349   
350   /**
351    * Empty implementation of WindowListener method.
352    * @param e the WindowEvent
353    * @see java.awt.event.WindowListener#windowIconified(java.awt.event.WindowEvent)
354    */
355   public void windowIconified(java.awt.event.WindowEvent windowEvent) 
356   {
357     
358   }
359   
360   /**
361    * Empty implementation of WindowListener method.
362    * @param e the WindowEvent
363    * @see java.awt.event.WindowListener#windowClosed(java.awt.event.WindowEvent)
364    */
365   public void windowClosed(java.awt.event.WindowEvent windowEvent) 
366   {
367     
368   }
369   
370   /**
371    * Empty implementation of WindowListener method.
372    * @param e the WindowEvent
373    * @see java.awt.event.WindowListener#windowOpened(java.awt.event.WindowEvent)
374    */
375   public void windowOpened(java.awt.event.WindowEvent windowEvent) 
376   {
377     
378   }
379   
380   /**
381    * Initiates the GUI components of this CLEFClient.
382    */
383   private void initiateComponents()
384   {
385     // GUI zusammenbauen
386     appletFrame = new JFrame("CLEF Client");
387     //appletFrame.setSize(500,350);
388     appletFrame.addWindowListener(this);
389     // the content pane already has an implicit BorderLayout by default
390     
391     GridBagConstraints constraints = new GridBagConstraints();
392 
393     // create main panel with GridBagLayout
394     JPanel mainPanel = new JPanel();
395     mainPanel.setLayout( new GridBagLayout() );
396 
397     // Topic Label
398     lTopic = new JLabel("Topic File:");
399     constraints.gridx = 0;
400     constraints.gridy = 0;
401     constraints.insets = new Insets(5, 10, 2, 5);
402     constraints.anchor = GridBagConstraints.WEST;
403     constraints.gridwidth = 2;
404     mainPanel.add(lTopic, constraints);
405 
406     // TopicPath Textfield
407     tfTopicPath = new JTextField(30);
408     constraints.gridx = 0;
409     constraints.gridy = 1;
410     constraints.insets = new Insets(2, 10, 5, 5);
411     constraints.anchor = GridBagConstraints.WEST;
412     mainPanel.add(tfTopicPath, constraints);
413 
414     // Topic Browse Button
415     bBrowseTopic = new JButton("Browse");
416     bBrowseTopic.addActionListener( this );
417     constraints.gridx = 2;
418     constraints.gridy = 1;
419     constraints.insets = new Insets(2, 5, 5, 10);
420     constraints.anchor = GridBagConstraints.EAST;
421     constraints.gridwidth = 1;
422     mainPanel.add(bBrowseTopic, constraints);
423 
424     // SaveAs Label
425     lSave = new JLabel("Save Results to");
426     constraints.gridx = 0;
427     constraints.gridy = 2;
428     constraints.insets = new Insets(5, 10, 2, 5);
429     constraints.anchor = GridBagConstraints.WEST;
430     constraints.gridwidth = 2;
431     mainPanel.add(lSave, constraints);
432     
433     // SavePath Textfield
434     tfSavePath = new JTextField(30);
435     constraints.gridx = 0;
436     constraints.gridy = 3;
437     constraints.insets = new Insets(2, 10, 5, 5);
438     constraints.anchor = GridBagConstraints.WEST;
439     mainPanel.add(tfSavePath, constraints);
440 
441     // SavePath Browse Button
442     bBrowseSave = new JButton("Browse");
443     bBrowseSave.addActionListener( this );
444     constraints.gridx = 2;
445     constraints.gridy = 3;
446     constraints.insets = new Insets(2, 5, 5, 10);
447     constraints.anchor = GridBagConstraints.EAST;
448     constraints.gridwidth = 1;
449     mainPanel.add(bBrowseSave, constraints);
450     
451     // Topic Number Label
452     JLabel lTopicNo = new JLabel("Topic Number:");
453     constraints.gridx = 0;
454     constraints.gridy = 4;
455     constraints.insets = new Insets(5, 10, 5, 5);
456     constraints.anchor = GridBagConstraints.WEST;
457     mainPanel.add(lTopicNo, constraints);
458     
459     // Topic Number Textfield
460     tfTopicNumber = new JTextField( 5 );
461     tfTopicNumber.setEditable(true);
462     constraints.gridx = 1;
463     constraints.gridy = 4;
464     //constraints.gridwidth = GridBagConstraints.REMAINDER;
465     constraints.insets = new Insets(5, 5, 5, 5);
466     mainPanel.add(tfTopicNumber, constraints);
467 
468     // Cut Off Label
469     JLabel lCutOff = new JLabel("Cut Off:");
470     constraints.gridx = 0;
471     constraints.gridy = 5;
472     constraints.insets = new Insets(5, 10, 5, 5);
473     mainPanel.add(lCutOff, constraints);
474     
475     // Cut Off Textfield
476     tfCutOff = new JTextField( 5 );
477     tfCutOff.setEditable(true);
478     constraints.gridx = 1;
479     constraints.gridy = 5;
480     constraints.insets = new Insets(5, 5, 5, 5);
481     mainPanel.add(tfCutOff, constraints);
482 
483     // Submit Button
484     bSubmit = new JButton("Submit");
485     bSubmit.addActionListener( this );
486     constraints.gridx = 0;
487     constraints.gridy = 6;
488     constraints.gridwidth = 3;
489     constraints.insets = new Insets(15, 5, 15, 5);
490     constraints.anchor = GridBagConstraints.CENTER;
491     constraints.gridwidth = 3;
492     mainPanel.add(bSubmit, constraints);
493     
494     // Message Label
495     lMessage = new JLabel();
496 
497     appletFrame.getContentPane().add( mainPanel, BorderLayout.CENTER );
498     appletFrame.getContentPane().add( lMessage, BorderLayout.SOUTH );
499 
500   }
501 
502   /**
503    * Returns a org.dom4j.Document that represents the specified file.
504    * @param file the File to parse.
505    * @return the Document representation.
506    * @throws org.dom4j.DocumentException
507    */
508   private Document createDocument(File file) throws DocumentException 
509   {
510     Document document = null;
511     try
512     {
513         document = xmlReader.read(file);
514     }
515     catch( java.net.MalformedURLException e )
516     {
517       logger.error("MalformedURLException in createDocument(File).");
518     }
519     return document;    
520   }
521   
522   /**
523    * Returns a org.dom4j.Document that is created using the specified Reader.
524    * @param reader a Reader to read the input from
525    * @return the document representation.
526    * @throws org.dom4j.DocumentException
527    */
528   private Document createDocument( Reader reader ) throws DocumentException 
529   {
530     Document document = null;
531     document = xmlReader.read( reader );
532     return document;    
533   }
534   
535   /**
536    * Returns an Iterator ocer the topic elements in the specified Document.
537    * @param doc the Document
538    * @return the topic Iterator
539    */
540   private Iterator getTopicIterator( Document doc )
541   {
542     Element root = doc.getRootElement();
543     return root.elementIterator("top");
544   }
545     
546   /**
547    * Writes the specified Document using the specified XMLWriter
548    * @param writer a XMLWriter
549    * @param doc the Document
550    */
551   private void writeDoc( XMLWriter writer, Document doc )
552   {
553     try
554     {
555       writer.write( doc );
556       writer.flush();
557     }
558     catch (IOException e)
559     {
560       logger.debug("IOException in writeDoc. ", e);
561     }
562   }
563   
564   /**
565    * Inner class that implements an RMI service to receive the results from the
566    * RemoteCLEFConnector.
567    */
568   protected class RMIClient extends UnicastRemoteObject implements RemoteCLEFClient 
569   {
570     /**
571      * The path where to save any results. 
572      */
573     private String savePath = "";
574 
575     /**
576      * Creates a new RMIClient.
577      * @throws RemoteException
578      */
579     public RMIClient() throws RemoteException 
580     {
581     }
582     
583     /**
584      * The remote method that is called by the RemoteCLEFConnector to return any results.
585      * @param v a Vector of ResultList objects
586      */
587     public void receiveResults(Vector results) 
588     {
589       try
590       {
591         logger.debug("Receiving "+results.size()+" results.");
592         BufferedWriter writer = null;
593         Document doc = null;
594         // iterate through ResultLists
595         for( Enumeration listEnum = results.elements(); listEnum.hasMoreElements(); )
596         {
597           ResultList list = (ResultList)listEnum.nextElement();
598           String filePath = "";
599           String formatPath = "";
600           String content = "";
601           String ps = File.separator;
602           if( list instanceof CLEFResultList )
603           {
604             CLEFResultList clefList = (CLEFResultList)list;
605             filePath = savePath+ps+clefList.getTopicNumber()+"_"+clefList.getTopic().getLanguage()+"_"+list.getChainID()+".xml";
606             formatPath = savePath+ps+clefList.getTopicNumber()+"_"+clefList.getTopic().getLanguage()+"_"+list.getChainID()+"_trec.txt";
607             content = clefList.toXML();
608           }
609           else if( list instanceof CLEFMergedResultList )
610           {
611             CLEFMergedResultList mergedList = (CLEFMergedResultList)list;
612             int i=1;
613             String marker = mergedList.getLanguage() != -1 ? CLEFConstants.getLanguageName(mergedList.getLanguage())+"_merged" : "merged_"+(i++);
614             filePath = savePath+ps+mergedList.getTopicNumber()+"_"+marker+"_"+list.getChainID()+".xml";
615             formatPath = savePath+ps+mergedList.getTopicNumber()+"_"+marker+"_"+list.getChainID()+"_trec.txt";
616             content = mergedList.toXML();
617           }
618 
619           try
620           {
621             logger.debug("Writing file '"+filePath+"'.");
622             // create BufferedWriter and XMLWriter
623             writer = new BufferedWriter( new FileWriter( filePath ) );
624             OutputFormat format = OutputFormat.createPrettyPrint();
625             // Suppress XML declaration since no root element is added!
626             //format.setSuppressDeclaration(true);
627             xmlWriter = new XMLWriter( writer, format );
628             formatWriter = new TRECFormatWriter( new FileWriter(formatPath) );
629 
630             doc = createDocument( new BufferedReader( new StringReader( content ) ) );
631             // write the XML file
632             writeDoc( xmlWriter, doc );
633             // write the official format file
634             formatWriter.writeFormattedDoc( "runid", doc );
635             formatWriter.close();
636           }
637           catch (IOException e)
638           {
639             logger.error("Couldn't write to file: "+filePath, e);
640           }
641         }
642       }
643       catch( DocumentException de )
644       {
645         logger.error("Unable to create XML Document.", de);
646       }
647       catch (Exception e)
648       {
649         logger.error("Exception while receiving results.", e);
650       }
651       
652       logger.debug("Results stored. Query finished.");
653 
654       /*
655        if( results.size() == 0 )
656         JOptionPane.showMessageDialog(null, "Es wurden keine ResultLists zur�ckgegeben!", "Suche erfolglos", JOptionPane.INFORMATION_MESSAGE);
657       else
658         JOptionPane.showMessageDialog(null, "Es wurden "+results.size()+" ResultLists zur�ckgegeben!", "Suche erfolgreich", JOptionPane.INFORMATION_MESSAGE);
659       */
660 
661       /* Remove comments if you want to display the ResultLists in individual frames.
662     
663       Vector frames = new Vector();
664       
665       int coordinate = 30;
666       for( Enumeration enum = results.elements(); enum.hasMoreElements(); )
667       {
668         ResultList rl = (ResultList)enum.nextElement();
669         ResultFrame rf = new ResultFrame(rl);
670         frames.add(rf);
671         rf.setLocation(coordinate, coordinate);
672         rf.pack();
673         rf.show();
674         coordinate += 15;
675       }
676       */
677     }
678     
679     /**
680      * Returns the path where results are saved.
681      * @return the path
682      */
683     public String getSavePath()
684     {
685       return savePath;
686     }
687 
688     /**
689      * Sets the path where results are saved to the specified path.
690      * @param path the path
691      */
692     public void setSavePath(String path)
693     {
694       savePath = path;
695     }
696 
697   }
698   
699   /**
700    * Inner class that represents a single JFrame to display the results.
701    */
702   private class ResultFrame extends JFrame 
703   {
704     /**
705      * The ResultList that is displayed.
706      */
707     private ResultList resultList;
708     /**
709      * A JTextArea to render the ResultList.
710      */
711     private JTextArea textArea;
712     
713     /**
714      * Creates a new ResultFrame with the specified ResultList.
715      * @param list the ResultList
716      */
717     public ResultFrame(ResultList list) 
718     {
719       resultList = list;
720       init();
721       renderResultList();
722     }
723     
724     /**
725      * Initiates the GUI components of this ResultFrame.
726      */
727     private void init() 
728     {
729       setTitle( resultList.getName() );
730       textArea = new JTextArea(60,80);
731       textArea.setEditable(false);
732       JScrollPane scrollPane = new JScrollPane(textArea);
733       scrollPane.setPreferredSize(new Dimension(700, 500));
734       getContentPane().setLayout( new BorderLayout() );
735       getContentPane().add(scrollPane, BorderLayout.CENTER);
736     }
737     
738     /**
739      * Renders the results in a formatted form.
740      */
741     private void renderResultList() 
742     {
743       String nl = System.getProperty("line.separator");
744       Result result = null;
745       Enumeration resultEnum = resultList.getResults().elements();
746       while( resultEnum.hasMoreElements() )
747       {
748         result = (Result) resultEnum.nextElement();
749         textArea.append( result.toXML() + nl );
750       }
751     }
752   }
753   
754   /**
755    * The CLEFFileChooser class represents a JFileChooser to select a file or a folder
756    * from the file system.
757    */
758   private class CLEFFileChooser extends JFileChooser 
759   {
760     /**
761      * Creates a new CLEFFileChooser with the specified path that is used to set
762      * a path to start from.
763      * @param path a path to start from
764      * @param title the dialog's title
765      */
766     CLEFFileChooser( String path, String title )
767     {
768       super( path );
769       setDialogTitle( title );
770     }    
771   }
772 
773   /**
774    * The TRECFormatWriter class extends the BufferedWriter to print to a File.
775    * It provides methods that format retrieval results to the official TREC
776    * format and print them.
777    * @author Jan H. Scheufen
778    * @version 0.2.9
779    */
780   private class TRECFormatWriter extends BufferedWriter
781   {
782     /**
783      * Creates a new TRECFormatWriter with the specified Writer.
784      * @param out a Writer
785      */
786     public TRECFormatWriter(Writer out)
787     {
788       super(out);
789     }
790     
791     /**
792      * Writes the specified Document if the root element discovered equals
793      * CLEFRESULTLIST or CLEFMERGEDRESULTLIST.<br>
794      * The inidividual results are transformed into the official TREC result
795      * format using the specified String as run ID.
796      * @param runID the run ID to print
797      * @param doc the Document with the results
798      * @throws IOException
799      */
800     public void writeFormattedDoc( String runID, Document doc ) throws IOException
801     {
802       Element root = doc.getRootElement();
803       Iterator iter = null;
804       if( root.getName().equals("CLEFRESULTLIST") )
805       {
806         logger.debug("Getting Iterator over CLEFRESULT elements.");
807         iter = root.elementIterator("CLEFRESULT");
808       }
809       else if( root.getName().equals("CLEFMERGEDRESULTLIST") )
810       {
811         logger.debug("Getting Iterator over MERGEDRESULT elements.");
812         iter = root.elementIterator("MERGEDRESULT");
813       }
814       
815       if( iter != null )
816       {
817         String topic = root.element("TOPIC").getTextTrim();
818         // remove letters from start if present
819         if( !topic.equals("") )
820         {
821           boolean ok = false;
822           do
823           {
824             // try to parse first char
825             try
826             {
827               Integer.valueOf( String.valueOf(topic.charAt(0)) );
828               ok = true;
829             }
830             catch (NumberFormatException e)
831             {
832               // shorten topic
833               topic = topic.substring(1);
834             }
835           }
836           while( !ok && topic.length() > 0 );
837         }
838               
839         Element result;
840         int i = 0;
841         String nl = System.getProperty("line.separator");
842         String prefix = topic+" Q0 ";
843         String resultString = "";
844         logger.debug("Writing TREC format file for topic '"+topic+"'.");
845         try
846         {
847           while( iter.hasNext() )
848           {
849             result = (Element)iter.next();
850             resultString = prefix;
851             resultString += result.element("DOCNO").getTextTrim()+" "+(++i)+" ";
852             resultString += result.element("SCORE").getTextTrim()+" "+runID+nl;
853             write( resultString );
854             flush();
855           }
856         }
857         catch (IOException e)
858         {
859           logger.error("Unable to write resultString '"+resultString+"'.", e);
860           //throw e;
861         }
862       }
863       else
864       {
865         logger.error("Couldn't create Iterator over results in Document "+doc);
866       }
867     }
868 
869   }
870 
871 }