Revision: 16765
          http://sourceforge.net/p/gate/code/16765
Author:   markagreenwood
Date:     2013-08-04 13:30:14 +0000 (Sun, 04 Aug 2013)
Log Message:
-----------
the new Fast Infoset document format plugin -- including support for saving 
GATE docs in this format to allow for full round-tripping

Added Paths:
-----------
    gate/trunk/plugins/Format_FastInfoset/
    gate/trunk/plugins/Format_FastInfoset/build.xml
    gate/trunk/plugins/Format_FastInfoset/creole.xml
    gate/trunk/plugins/Format_FastInfoset/lib/
    gate/trunk/plugins/Format_FastInfoset/lib/FastInfoset-1.2.13.jar
    gate/trunk/plugins/Format_FastInfoset/src/
    gate/trunk/plugins/Format_FastInfoset/src/gate/
    gate/trunk/plugins/Format_FastInfoset/src/gate/corpora/
    
gate/trunk/plugins/Format_FastInfoset/src/gate/corpora/FastInfosetDocumentFormat.java
    
gate/trunk/plugins/Format_FastInfoset/src/gate/corpora/FastInfosetExporter.java

Added: gate/trunk/plugins/Format_FastInfoset/build.xml
===================================================================
--- gate/trunk/plugins/Format_FastInfoset/build.xml                             
(rev 0)
+++ gate/trunk/plugins/Format_FastInfoset/build.xml     2013-08-04 13:30:14 UTC 
(rev 16765)
@@ -0,0 +1,85 @@
+<project name="Format_FastInfoset" basedir="." default="build">
+  <!-- Prevent Ant from warning about includeantruntime not being set -->
+  <property name="build.sysclasspath" value="ignore" />
+  
+       <property file="build.properties" />
+
+       <property name="gate.home" location="../.." />
+       <property name="gate.lib" location="${gate.home}/lib" />
+       <property name="gate.jar" location="${gate.home}/bin/gate.jar" />
+       <property name="src.dir" location="src" />
+       <property name="classes.dir" location="classes" />
+       <property name="jar.location" location="format-fastinfoset.jar" />
+       <property name="lib" location="lib" />
+       <property name="doc.dir" location="doc" />
+       <property name="javadoc.dir" location="${doc.dir}/javadoc" />
+
+       <!-- Path to compile - includes gate.jar and GATE/lib/*.jar -->
+       <path id="compile.classpath">
+               <fileset dir="lib">
+                       <include name="**/*.jar" />
+               </fileset>
+               <pathelement location="${gate.jar}" />
+               <fileset dir="${gate.lib}">
+                       <include name="**/*.jar" />
+                       <include name="**/*.zip" />
+               </fileset>
+       </path>
+
+       <!-- create build directory structure -->
+       <target name="prepare">
+               <mkdir dir="${classes.dir}" />
+       </target>
+
+       <target name="resources" depends="prepare">
+               <!-- <copy todir="${classes.dir}/gate/resources" 
includeEmptyDirs="true">
+                       <fileset dir="${src.dir}/gate/resources" />
+               </copy> -->
+       </target>
+
+       <!-- compile the source -->
+       <target name="compile" depends="prepare, resources">
+               <javac classpathref="compile.classpath" srcdir="${src.dir}" 
destdir="${classes.dir}" debug="true" debuglevel="lines,source" source="1.5" 
target="1.5">
+               </javac>
+       </target>
+
+       <!-- create the JAR file -->
+       <target name="jar" depends="compile">
+               <jar destfile="${jar.location}" update="false" 
basedir="${classes.dir}" />
+       </target>
+
+       <!-- remove the generated .class files -->
+       <target name="clean.classes">
+               <delete dir="${classes.dir}" />
+       </target>
+
+       <!-- Clean up - remove .class and .jar files -->
+       <target name="clean" depends="clean.classes">
+               <delete file="${jar.location}" />
+       </target>
+
+       <!-- Build JavaDoc documentation -->
+       <target name="doc.prepare">
+               <mkdir dir="${javadoc.dir}" />
+       </target>
+
+       <target name="javadoc" depends="jar, doc.prepare">
+               <javadoc destdir="${javadoc.dir}" packagenames="*" 
classpathref="compile.classpath" encoding="UTF-8" windowtitle="Fast Infoset 
Document Format JavaDoc" source="1.6">
+                       <sourcepath>
+                               <pathelement location="${src.dir}" />
+                       </sourcepath>
+                       <link href="http://docs.oracle.com/javase/6/docs/api/"; 
/>
+                       <link href="http://gate.ac.uk/gate/doc/javadoc/"; />
+               </javadoc>
+       </target>
+
+       <!-- Targets used by the main GATE build file:
+         build: build the plugin - just calls "jar" target
+         test : run the unit tests - there aren't any
+         distro.prepare: remove intermediate files that shouldn't be in the
+                         distribution
+  -->
+       <target name="build" depends="jar" />
+       <target name="test" />
+       <target name="distro.prepare" depends="clean.classes" />
+</project>

Added: gate/trunk/plugins/Format_FastInfoset/creole.xml
===================================================================
--- gate/trunk/plugins/Format_FastInfoset/creole.xml                            
(rev 0)
+++ gate/trunk/plugins/Format_FastInfoset/creole.xml    2013-08-04 13:30:14 UTC 
(rev 16765)
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<CREOLE-DIRECTORY>
+  <JAR SCAN="true">format-fastinfoset.jar</JAR>
+  <JAR>lib/FastInfoset-1.2.13.jar</JAR>
+</CREOLE-DIRECTORY>

Added: gate/trunk/plugins/Format_FastInfoset/lib/FastInfoset-1.2.13.jar
===================================================================
(Binary files differ)

Index: gate/trunk/plugins/Format_FastInfoset/lib/FastInfoset-1.2.13.jar
===================================================================
--- gate/trunk/plugins/Format_FastInfoset/lib/FastInfoset-1.2.13.jar    
2013-08-03 11:44:38 UTC (rev 16764)
+++ gate/trunk/plugins/Format_FastInfoset/lib/FastInfoset-1.2.13.jar    
2013-08-04 13:30:14 UTC (rev 16765)

Property changes on: 
gate/trunk/plugins/Format_FastInfoset/lib/FastInfoset-1.2.13.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: 
gate/trunk/plugins/Format_FastInfoset/src/gate/corpora/FastInfosetDocumentFormat.java
===================================================================
--- 
gate/trunk/plugins/Format_FastInfoset/src/gate/corpora/FastInfosetDocumentFormat.java
                               (rev 0)
+++ 
gate/trunk/plugins/Format_FastInfoset/src/gate/corpora/FastInfosetDocumentFormat.java
       2013-08-04 13:30:14 UTC (rev 16765)
@@ -0,0 +1,333 @@
+/*
+ * FastInfosetDocumentFormat.java
+ * 
+ * Copyright (c) 1995-2013, The University of Sheffield. See the file
+ * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
+ * 
+ * This file is part of GATE (see http://gate.ac.uk/), and is free software,
+ * licenced under the GNU Library General Public License, Version 2, June 1991
+ * (in the distribution as file licence.html, and also available at
+ * http://gate.ac.uk/gate/licence.html).
+ * 
+ * Mark A. Greenwood, 01/08/2013
+ */
+
+package gate.corpora;
+
+import gate.Document;
+import gate.GateConstants;
+import gate.Resource;
+import gate.TextualDocument;
+import gate.creole.ResourceInstantiationException;
+import gate.creole.metadata.AutoInstance;
+import gate.creole.metadata.CreoleResource;
+import gate.event.StatusListener;
+import gate.util.DocumentFormatException;
+import gate.util.Out;
+import gate.xml.XmlDocumentHandler;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.commons.io.IOUtils;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import com.sun.xml.fastinfoset.sax.SAXDocumentParser;
+import com.sun.xml.fastinfoset.stax.StAXDocumentParser;
+import com.sun.xml.fastinfoset.stax.StAXManager;
+
+@CreoleResource(name = "Fast Infoset Document Format", isPrivate = true, 
autoinstances = {@AutoInstance(hidden = true)})
+public class FastInfosetDocumentFormat extends TextualDocumentFormat {
+
+  private static StAXManager staxManager;
+
+  /** Default construction */
+  public FastInfosetDocumentFormat() {
+    super();
+  }
+
+  /** We could collect repositioning information during XML parsing */
+  @Override
+  public Boolean supportsRepositioning() {
+    return new Boolean(true);
+  }
+
+  /** Old style of unpackMarkup (without collecting of RepositioningInfo) */
+  @Override
+  public void unpackMarkup(Document doc) throws DocumentFormatException {
+    unpackMarkup(doc, (RepositioningInfo)null, (RepositioningInfo)null);
+  }
+
+  /**
+   * Unpack the markup in the document. This converts markup from the native
+   * format (e.g. XML) into annotations in GATE format. Uses the
+   * markupElementsMap to determine which elements to convert, and what
+   * annotation type names to use. If the document was created from a String,
+   * then is recommended to set the doc's sourceUrl to <b>null</b>. So, if the
+   * document has a valid URL, then the parser will try to parse the XML
+   * document pointed by the URL.If the URL is not valid, or is null, then the
+   * doc's content will be parsed. If the doc's content is not a valid XML then
+   * the parser might crash.
+   * 
+   * @param doc
+   *          The gate document you want to parse. If
+   *          <code>doc.getSourceUrl()</code> returns <b>null</b> then the
+   *          content of doc will be parsed. Using a URL is recommended because
+   *          the parser will report errors correctly if the XML document is 
not
+   *          well formed.
+   */
+  @Override
+  public void unpackMarkup(Document doc, RepositioningInfo repInfo,
+      RepositioningInfo ampCodingInfo) throws DocumentFormatException {
+    if((doc == null)
+        || (doc.getSourceUrl() == null && doc.getContent() == null)) {
+
+    throw new DocumentFormatException(
+        "GATE document is null or no content found. Nothing to parse!"); }// 
End
+                                                                          // if
+
+    // Create a status listener
+    StatusListener statusListener = new StatusListener() {
+      @Override
+      public void statusChanged(String text) {
+        // This is implemented in DocumentFormat.java and inherited here
+        fireStatusChanged(text);
+      }
+    };
+
+    // determine whether we have a GATE format document or not
+    String content = doc.getContent().toString();
+    if(content.length() > 2048) {
+      content = content.substring(0, 2048);
+    }
+    boolean gateFormat = isGateFIFormat(content);
+
+    if(gateFormat) {
+      unpackGateFormatMarkup(doc, statusListener);
+    } else {
+      unpackGeneralXmlMarkup(doc, repInfo, ampCodingInfo, statusListener);
+    }
+  }
+
+  /**
+   * Unpacks markup in the GATE-specific standoff XML markup format.
+   * 
+   * @param doc
+   *          the document to process
+   * @param statusListener
+   *          optional status listener to receive status messages
+   * @throws DocumentFormatException
+   *           if a fatal error occurs during parsing
+   */
+  private void unpackGateFormatMarkup(Document doc,
+      StatusListener statusListener) throws DocumentFormatException {
+    boolean docHasContentButNoValidURL = hasContentButNoValidUrl(doc);
+
+    try {
+      Reader inputReader = null;
+      InputStream inputStream = null;
+      XMLStreamReader xsr = null;
+      String encoding = ((TextualDocument)doc).getEncoding();
+      if(docHasContentButNoValidURL) {
+        xsr =
+            new StAXDocumentParser(IOUtils.toInputStream(doc.getContent()
+                .toString(), encoding), getStAXManager());
+      } else {
+        inputStream = doc.getSourceUrl().openStream();
+        xsr = new StAXDocumentParser(inputStream, getStAXManager());
+      }
+
+      // find the opening GateDocument tag
+      xsr.nextTag();
+
+      // parse the document
+      try {
+        DocumentStaxUtils.readGateXmlDocument(xsr, doc, statusListener);
+      } finally {
+        xsr.close();
+        if(inputStream != null) {
+          inputStream.close();
+        }
+        if(inputReader != null) {
+          inputReader.close();
+        }
+      }
+    } catch(XMLStreamException e) {
+      doc.getFeatures().put("parsingError", Boolean.TRUE);
+
+      Boolean bThrow =
+          (Boolean)doc.getFeatures().get(
+              GateConstants.THROWEX_FORMAT_PROPERTY_NAME);
+
+      if(bThrow != null && bThrow.booleanValue()) {
+        // the next line is commented to avoid Document creation fail on
+        // error
+        throw new DocumentFormatException(e);
+      } else {
+        Out.println("Warning: Document remains unparsed. \n"
+            + "\n  Stack Dump: ");
+        e.printStackTrace(Out.getPrintWriter());
+      } // if
+    } catch(IOException ioe) {
+      throw new DocumentFormatException("I/O exception for "
+          + doc.getSourceUrl().toString(), ioe);
+    }
+  }
+
+  /**
+   * Returns the StAX manager, creating one if it is currently null.
+   * 
+   * @return <code>staxFactory</code>
+   * @throws XMLStreamException
+   */
+  private static StAXManager getStAXManager() throws XMLStreamException {
+    if(staxManager == null) {
+      staxManager = new StAXManager(StAXManager.CONTEXT_READER);
+    }
+    return staxManager;
+  }
+
+  /**
+   * Unpack markup from any XML format. The XML elements are translated to
+   * annotations on the Original markups annotation set.
+   * 
+   * @param doc
+   *          the document to process
+   * @throws DocumentFormatException
+   */
+  private void unpackGeneralXmlMarkup(Document doc, RepositioningInfo repInfo,
+      RepositioningInfo ampCodingInfo, StatusListener statusListener)
+      throws DocumentFormatException {
+    boolean docHasContentButNoValidURL = hasContentButNoValidUrl(doc);
+
+    XmlDocumentHandler xmlDocHandler = null;
+    try {
+
+      // Create a new Xml document handler
+      xmlDocHandler =
+          new XmlDocumentHandler(doc, this.markupElementsMap,
+              this.element2StringMap);
+
+      // Register a status listener with it
+      xmlDocHandler.addStatusListener(statusListener);
+
+      // set repositioning object
+      xmlDocHandler.setRepositioningInfo(repInfo);
+
+      // set the object with ampersand coding positions
+      xmlDocHandler.setAmpCodingInfo(ampCodingInfo);
+
+      // create the parser
+      SAXDocumentParser newxmlParser = new SAXDocumentParser();
+
+      // Set up the factory to create the appropriate type of parser
+      // Fast Infoset doesn't support validating which is good as we would want
+      // it off any way, but we do want it to be namesapace aware
+      newxmlParser.setFeature("http://xml.org/sax/features/namespaces";, true);
+      newxmlParser.setFeature("http://xml.org/sax/features/namespace-prefixes";,
+          true);
+      newxmlParser.setContentHandler(xmlDocHandler);
+      newxmlParser.setErrorHandler(xmlDocHandler);
+      newxmlParser.setDTDHandler(xmlDocHandler);
+      newxmlParser.setEntityResolver(xmlDocHandler);
+
+      // Parse the XML Document with the appropriate encoding
+      Reader docReader = null;
+      try {
+        InputSource is;
+        if(docHasContentButNoValidURL) {
+          // no URL, so parse from string
+          is = new InputSource(new StringReader(doc.getContent().toString()));
+        } else if(doc instanceof TextualDocument) {
+          // textual document - load with user specified encoding
+          String docEncoding = ((TextualDocument)doc).getEncoding();
+          // don't strip BOM on XML.
+          docReader =
+              new InputStreamReader(doc.getSourceUrl().openStream(),
+                  docEncoding);
+          is = new InputSource(docReader);
+          // must set system ID to allow relative URLs (e.g. to a DTD) to
+          // work
+          is.setSystemId(doc.getSourceUrl().toString());
+        } else {
+          // let the parser decide the encoding
+          is = new InputSource(doc.getSourceUrl().toString());
+        }
+        newxmlParser.parse(is);
+      } finally {
+        // make sure the open streams are closed
+        if(docReader != null) docReader.close();
+      }
+
+      ((DocumentImpl)doc).setNextAnnotationId(xmlDocHandler
+          .getCustomObjectsId());
+    } catch(SAXException e) {
+      doc.getFeatures().put("parsingError", Boolean.TRUE);
+
+      Boolean bThrow =
+          (Boolean)doc.getFeatures().get(
+              GateConstants.THROWEX_FORMAT_PROPERTY_NAME);
+
+      if(bThrow != null && bThrow.booleanValue()) {
+        throw new DocumentFormatException(e);
+      } else {
+        Out.println("Warning: Document remains unparsed. \n"
+            + "\n  Stack Dump: ");
+        e.printStackTrace(Out.getPrintWriter());
+      }
+
+    } catch(IOException e) {
+      throw new DocumentFormatException("I/O exception for "
+          + doc.getSourceUrl(), e);
+    } finally {
+      if(xmlDocHandler != null)
+        xmlDocHandler.removeStatusListener(statusListener);
+    }
+  }
+
+  /**
+   * Determine whether the given document content string represents a GATE
+   * custom format XML document.
+   */
+  private static boolean isGateFIFormat(String content) {
+    return (content.indexOf("GateDocument") != -1);
+  }
+
+  /** Initialise this resource, and return it. */
+  @Override
+  public Resource init() throws ResourceInstantiationException {
+
+    // based on info from
+    // http://www.iana.org/assignments/media-types/application/fastinfoset
+
+    // Register XML mime type
+    MimeType mime = new MimeType("application", "fastinfoset");
+
+    // Register the class handler for this mime type
+    mimeString2ClassHandlerMap.put(mime.getType() + "/" + mime.getSubtype(),
+        this);
+
+    // Register the mime type with mine string
+    mimeString2mimeTypeMap.put(mime.getType() + "/" + mime.getSubtype(), mime);
+
+    // Register file sufixes for this mime type
+    suffixes2mimeTypeMap.put("finf", mime);
+
+    // Register magic numbers for this mime type
+    // this should be E0 00 00 01
+    // but I can't seem to get it to work
+
+    // Set the mimeType for this language resource
+    setMimeType(mime);
+
+    return this;
+  }
+
+}
\ No newline at end of file

Added: 
gate/trunk/plugins/Format_FastInfoset/src/gate/corpora/FastInfosetExporter.java
===================================================================
--- 
gate/trunk/plugins/Format_FastInfoset/src/gate/corpora/FastInfosetExporter.java 
                            (rev 0)
+++ 
gate/trunk/plugins/Format_FastInfoset/src/gate/corpora/FastInfosetExporter.java 
    2013-08-04 13:30:14 UTC (rev 16765)
@@ -0,0 +1,344 @@
+/*
+ * FastInfosetExporter.java
+ * 
+ * Copyright (c) 2012-2013, The University of Sheffield. See the file
+ * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
+ * 
+ * This file is part of GATE (see http://gate.ac.uk/), and is free software,
+ * licenced under the GNU Library General Public License, Version 2, June 1991
+ * (in the distribution as file licence.html, and also available at
+ * http://gate.ac.uk/gate/licence.html).
+ * 
+ * Mark A. Greenwood, 01/08/2013
+ */
+
+package gate.corpora;
+
+import gate.Corpus;
+import gate.Document;
+import gate.Factory;
+import gate.creole.metadata.AutoInstance;
+import gate.creole.metadata.CreoleResource;
+import gate.gui.MainFrame;
+import gate.gui.NameBearerHandle;
+import gate.gui.ResourceHelper;
+import gate.swing.XJFileChooser;
+import gate.util.Err;
+import gate.util.ExtensionFileFilter;
+import gate.util.Files;
+import gate.util.InvalidOffsetException;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+
+import com.sun.xml.fastinfoset.stax.StAXDocumentSerializer;
+
+@CreoleResource(name = "Fast Infoset Exporter", tool = true, autoinstances = 
@AutoInstance)
+public class FastInfosetExporter extends ResourceHelper {
+
+  @Override
+  protected List<Action> buildActions(final NameBearerHandle handle) {
+    List<Action> actions = new ArrayList<Action>();
+
+    if(handle.getTarget() instanceof Document) {
+      actions.add(new AbstractAction("Save as Fast Infoset XML...") {
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+
+          Runnable runableAction = new Runnable() {
+            
+            @Override
+            public void run() {
+              XJFileChooser fileChooser = MainFrame.getFileChooser();
+              ExtensionFileFilter filter =
+                  new ExtensionFileFilter("Fast Infoset XML Files (*.finf)", 
"finf");
+              fileChooser.addChoosableFileFilter(filter);
+              fileChooser.setMultiSelectionEnabled(false);
+              fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+              fileChooser.setDialogTitle("Saving as Fast Infoset XML");
+
+              Document doc = (Document)handle.getTarget();
+              if(doc.getSourceUrl() != null) {
+                String fileName = "";
+                try {
+                  fileName = doc.getSourceUrl().toURI().getPath().trim();
+                } catch(URISyntaxException e) {
+                  fileName = doc.getSourceUrl().getPath().trim();
+                }
+                if(fileName.equals("") || fileName.equals("/")) {
+                  if(doc.getNamedAnnotationSets().containsKey(
+                      "Original markups")
+                      && !doc.getAnnotations("Original markups").get("title")
+                          .isEmpty()) {
+                    // use the title annotation if any
+                    try {
+                      fileName =
+                          doc.getContent()
+                              .getContent(
+                                  doc.getAnnotations("Original markups")
+                                      .get("title").firstNode().getOffset(),
+                                  doc.getAnnotations("Original markups")
+                                      .get("title").lastNode().getOffset())
+                              .toString();
+                    } catch(InvalidOffsetException e) {
+                      e.printStackTrace();
+                    }
+                  } else {
+                    fileName = doc.getSourceUrl().toString();
+                  }
+                  // cleans the file name
+                  fileName = fileName.replaceAll("/", "_");
+                } else {
+                  // replaces the extension with .finf
+                  fileName = fileName.replaceAll("\\.[a-zA-Z]{1,4}$", ".finf");
+                }
+                // cleans the file name
+                fileName = fileName.replaceAll("[^/a-zA-Z0-9._-]", "_");
+                fileName = fileName.replaceAll("__+", "_");
+                // adds a .finf extension if not present
+                if(!fileName.endsWith(".finf")) {
+                  fileName += ".finf";
+                }
+                File file = new File(fileName);
+                fileChooser.ensureFileIsVisible(file);
+                fileChooser.setSelectedFile(file);
+              }
+
+              if(fileChooser.showSaveDialog(MainFrame.getInstance()) != 
JFileChooser.APPROVE_OPTION)
+                return;
+
+              File selectedFile = fileChooser.getSelectedFile();
+              if(selectedFile == null) return;
+              long start = System.currentTimeMillis();
+              handle.statusChanged("Saving as Fast Infoset XML to "
+                  + selectedFile.toString() + "...");
+              try {
+                MainFrame.lockGUI("Exporting...");
+
+                export(doc, selectedFile);
+              } catch(Exception ex) {
+                MainFrame.unlockGUI();
+                JOptionPane.showMessageDialog(MainFrame.getInstance(),
+                    "Could not create write file:" + ex.toString(),
+                    "GATE", JOptionPane.ERROR_MESSAGE);
+                ex.printStackTrace(Err.getPrintWriter());
+                return;
+              } finally {
+                MainFrame.unlockGUI();
+              }
+              long time = System.currentTimeMillis() - start;
+              handle
+                  .statusChanged("Finished saving as Fast Infoset XML into "
+                      + " the file: " + selectedFile.toString() + " in "
+                      + ((double)time) / 1000 + " s");
+            }
+          };
+          Thread thread = new Thread(runableAction, "Fast Infoset Exporter");
+          thread.setPriority(Thread.MIN_PRIORITY);
+          thread.start();
+        }
+
+      });
+    } else if(handle.getTarget() instanceof Corpus) {
+      actions.add(new AbstractAction("Save as Fast Infoset XML...") {
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+          Runnable runnable = new Runnable() {
+            
+            @Override
+            public void run() {
+              try {
+                // we need a directory
+                XJFileChooser fileChooser = MainFrame.getFileChooser();
+                fileChooser
+                    .setDialogTitle("Select the directory that will contain 
the corpus");
+                
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+
+                if(fileChooser.showDialog(MainFrame.getInstance(), "Select") 
!= JFileChooser.APPROVE_OPTION)
+                  return;
+
+                File dir = fileChooser.getSelectedFile();
+                // create the top directory if needed
+                if(!dir.exists()) {
+                  if(!dir.mkdirs()) {
+                    JOptionPane.showMessageDialog(MainFrame.getInstance(),
+                        "Could not create top directory!", "GATE",
+                        JOptionPane.ERROR_MESSAGE);
+                    return;
+                  }
+                }
+
+                MainFrame.lockGUI("Saving...");
+
+                // iterate through all the docs and save each of them as
+                // finf
+                Corpus corpus = (Corpus)handle.getTarget();
+                Iterator<Document> docIter = corpus.iterator();
+                boolean overwriteAll = false;
+                int docCnt = corpus.size();
+                int currentDocIndex = 0;
+                Set<String> usedFileNames = new HashSet<String>();
+                while(docIter.hasNext()) {
+                  boolean docWasLoaded =
+                      corpus.isDocumentLoaded(currentDocIndex);
+                  Document currentDoc = (Document)docIter.next();
+                  URL sourceURL = currentDoc.getSourceUrl();
+                  String fileName = null;
+                  if(sourceURL != null) {
+                    fileName = sourceURL.getPath();
+                    fileName = Files.getLastPathComponent(fileName);
+                  }
+                  if(fileName == null || fileName.length() == 0) {
+                    fileName = currentDoc.getName();
+                  }
+                  // makes sure that the filename does not contain any
+                  // forbidden character
+                  fileName = fileName.replaceAll("[\\/:\\*\\?\"<>|]", "_");
+                  if(fileName.toLowerCase().endsWith(".finf")) {
+                    fileName = fileName.substring(0, fileName.length() - 5);
+                  }
+                  if(usedFileNames.contains(fileName)) {
+                    // name clash -> add unique ID
+                    String fileNameBase = fileName;
+                    int uniqId = 0;
+                    fileName = fileNameBase + "-" + uniqId++;
+                    while(usedFileNames.contains(fileName)) {
+                      fileName = fileNameBase + "-" + uniqId++;
+                    }
+                  }
+                  usedFileNames.add(fileName);
+                  if(!fileName.toLowerCase().endsWith(".finf"))
+                    fileName += ".finf";
+                  File docFile = null;
+                  boolean nameOK = false;
+                  do {
+                    docFile = new File(dir, fileName);
+                    if(docFile.exists() && !overwriteAll) {
+                      // ask the user if we can overwrite the file
+                      Object[] options =
+                          new Object[]{"Yes", "All", "No", "Cancel"};
+                      MainFrame.unlockGUI();
+                      int answer =
+                          JOptionPane.showOptionDialog(MainFrame.getInstance(),
+                              "File " + docFile.getName()
+                                  + " already exists!\n" + "Overwrite?",
+                              "GATE", JOptionPane.DEFAULT_OPTION,
+                              JOptionPane.WARNING_MESSAGE, null, options,
+                              options[2]);
+                      MainFrame.lockGUI("Saving...");
+                      switch(answer){
+                        case 0: {
+                          nameOK = true;
+                          break;
+                        }
+                        case 1: {
+                          nameOK = true;
+                          overwriteAll = true;
+                          break;
+                        }
+                        case 2: {
+                          // user said NO, allow them to provide an
+                          // alternative name;
+                          MainFrame.unlockGUI();
+                          fileName =
+                              (String)JOptionPane.showInputDialog(
+                                  MainFrame.getInstance(),
+                                  "Please provide an alternative file name",
+                                  "GATE", JOptionPane.QUESTION_MESSAGE, null,
+                                  null, fileName);
+                          if(fileName == null) {
+                            handle.processFinished();
+                            return;
+                          }
+                          MainFrame.lockGUI("Saving");
+                          break;
+                        }
+                        case 3: {
+                          // user gave up; return
+                          handle.processFinished();
+                          return;
+                        }
+                      }
+
+                    } else {
+                      nameOK = true;
+                    }
+                  } while(!nameOK);
+                  // save the file
+                  try {
+                    // do the actual exporting
+                    export(currentDoc, docFile);
+                  } catch(Exception ioe) {
+                    MainFrame.unlockGUI();
+                    JOptionPane.showMessageDialog(MainFrame.getInstance(),
+                        "Could not create write file:" + ioe.toString(),
+                        "GATE", JOptionPane.ERROR_MESSAGE);
+                    ioe.printStackTrace(Err.getPrintWriter());
+                    return;
+                  }
+
+                  handle.statusChanged(currentDoc.getName() + " saved");
+                  // close the doc if it wasn't already loaded
+                  if(!docWasLoaded) {
+                    corpus.unloadDocument(currentDoc);
+                    Factory.deleteResource(currentDoc);
+                  }
+
+                  handle.progressChanged(100 * currentDocIndex++ / docCnt);
+                }// while(docIter.hasNext())
+                handle.statusChanged("Corpus Saved");
+                handle.processFinished();
+
+              } finally {
+                MainFrame.unlockGUI();
+              }
+            }
+          };
+          Thread thread =
+              new Thread(Thread.currentThread().getThreadGroup(), runnable,
+                  "Corpus Fast Infoset XML dumper");
+          thread.setPriority(Thread.MIN_PRIORITY);
+          thread.start();
+
+        }
+
+      });
+    }
+
+    return actions;
+  }
+
+  /**
+   * A static utility method that exports the specified GATE document to a 
Fast Infoset file.
+   * @param doc the {@link gate.Document} instance to export
+   * @param file the {@link java.io.File}
+   * @throws Exception
+   */
+  public static void export(Document doc, File file) throws Exception {
+
+    StAXDocumentSerializer xsw =
+        new StAXDocumentSerializer(new FileOutputStream(file));
+
+    xsw.writeStartDocument("1.0");
+    DocumentStaxUtils.writeDocument(doc, xsw, "");
+    xsw.writeEndDocument();
+    xsw.flush();
+    xsw.close();
+
+  }
+}

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Get your SQL database under version control now!
Version control is standard for application code, but databases havent 
caught up. So what steps can you take to put your SQL databases under 
version control? Why should you start doing it? Read more to find out.
http://pubads.g.doubleclick.net/gampad/clk?id=49501711&iu=/4140/ostg.clktrk
_______________________________________________
GATE-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gate-cvs

Reply via email to