Revision: 15033
          http://gate.svn.sourceforge.net/gate/?rev=15033&view=rev
Author:   markagreenwood
Date:     2012-01-13 15:46:53 +0000 (Fri, 13 Jan 2012)
Log Message:
-----------
support for using ivy to resolve dependencies in creole plugins

Modified Paths:
--------------
    gate/trunk/.classpath
    gate/trunk/.settings/org.eclipse.jdt.core.prefs
    gate/trunk/build/deploy/maven/gate-core.pom.template
    gate/trunk/src/gate/creole/CreoleAnnotationHandler.java
    gate/trunk/src/gate/creole/CreoleXmlHandler.java
    gate/trunk/src/gate/gui/NameBearerHandle.java
    gate/trunk/src/gate/util/ant/antlib.xml
    gate/trunk/src/gate/util/ant/packager/PackageGappTask.java

Added Paths:
-----------
    gate/trunk/lib/commons-httpclient-3.0.jar
    gate/trunk/lib/commons-vfs-1.0.jar
    gate/trunk/lib/ivy-2.2.0.jar
    gate/trunk/lib/jsch-0.1.31.jar
    gate/trunk/src/gate/util/ant/ExpandIvy.java

Modified: gate/trunk/.classpath
===================================================================
--- gate/trunk/.classpath       2012-01-13 15:35:53 UTC (rev 15032)
+++ gate/trunk/.classpath       2012-01-13 15:46:53 UTC (rev 15033)
@@ -125,5 +125,9 @@
        <classpathentry kind="lib" 
path="plugins/Ontology/lib/owlim-lite-4.3.jar"/>
        <classpathentry kind="lib" path="lib/tika-core-1.0.jar"/>
        <classpathentry kind="lib" path="lib/tika-parsers-1.0.jar"/>
+       <classpathentry kind="lib" path="lib/commons-httpclient-3.0.jar"/>
+       <classpathentry kind="lib" path="lib/commons-vfs-1.0.jar"/>
+       <classpathentry kind="lib" path="lib/ivy-2.2.0.jar"/>
+       <classpathentry kind="lib" path="lib/jsch-0.1.31.jar"/>
        <classpathentry kind="output" path="classes"/>
 </classpath>

Modified: gate/trunk/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- gate/trunk/.settings/org.eclipse.jdt.core.prefs     2012-01-13 15:35:53 UTC 
(rev 15032)
+++ gate/trunk/.settings/org.eclipse.jdt.core.prefs     2012-01-13 15:46:53 UTC 
(rev 15033)
@@ -270,7 +270,7 @@
 
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
 org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
 
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
 org.eclipse.jdt.core.formatter.tabulation.char=space
 org.eclipse.jdt.core.formatter.tabulation.size=2

Modified: gate/trunk/build/deploy/maven/gate-core.pom.template
===================================================================
--- gate/trunk/build/deploy/maven/gate-core.pom.template        2012-01-13 
15:35:53 UTC (rev 15032)
+++ gate/trunk/build/deploy/maven/gate-core.pom.template        2012-01-13 
15:46:53 UTC (rev 15033)
@@ -30,11 +30,6 @@
             <version>1.2.16</version>
         </dependency>
         <dependency>
-            <groupId>commons-lang</groupId>
-            <artifactId>commons-lang</artifactId>
-            <version>2.5</version>
-        </dependency>
-        <dependency>
             <groupId>jdom</groupId>
             <artifactId>jdom</artifactId>
             <version>1.0</version>
@@ -81,7 +76,42 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.apache.ivy</groupId>
+            <artifactId>ivy</artifactId>
+            <version>2.2.0</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>ant</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
 
+        <!-- Apache Ant.  Required by the GATE Ant tasks and also by the
+             developer GUI as Ant classes are referenced by NameBearerHandle to
+             implement the "export for GATECloud.net" function. -->
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+            <version>${ant.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant-launcher</artifactId>
+            <version>${ant.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant-junit</artifactId>
+            <version>${ant.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant-nodeps</artifactId>
+            <version>${ant.version}</version>
+        </dependency>
+
         <!-- Optional dependencies -->
         <!-- You need to expicitly add the below dependencies in your project, 
if you
          intend to use parts of GATE that rely on them. -->
@@ -121,34 +151,6 @@
             <optional>true</optional>
         </dependency>
 
-        <!-- Apache Ant.  Required by the GATE Ant tasks and also by the
-             developer GUI as Ant classes are referenced by NameBearerHandle to
-             implement the "export for GATECloud.net" function. -->
-        <dependency>
-            <groupId>org.apache.ant</groupId>
-            <artifactId>ant</artifactId>
-            <version>${ant.version}</version>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.ant</groupId>
-            <artifactId>ant-launcher</artifactId>
-            <version>${ant.version}</version>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.ant</groupId>
-            <artifactId>ant-junit</artifactId>
-            <version>${ant.version}</version>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.ant</groupId>
-            <artifactId>ant-nodeps</artifactId>
-            <version>${ant.version}</version>
-            <optional>true</optional>
-        </dependency>
-
         <!-- Required for Spring Framework support in GATE -->
         <dependency>
             <groupId>org.springframework</groupId>

Added: gate/trunk/lib/commons-httpclient-3.0.jar
===================================================================
(Binary files differ)


Property changes on: gate/trunk/lib/commons-httpclient-3.0.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: gate/trunk/lib/commons-vfs-1.0.jar
===================================================================
(Binary files differ)


Property changes on: gate/trunk/lib/commons-vfs-1.0.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: gate/trunk/lib/ivy-2.2.0.jar
===================================================================
(Binary files differ)


Property changes on: gate/trunk/lib/ivy-2.2.0.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: gate/trunk/lib/jsch-0.1.31.jar
===================================================================
(Binary files differ)


Property changes on: gate/trunk/lib/jsch-0.1.31.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Modified: gate/trunk/src/gate/creole/CreoleAnnotationHandler.java
===================================================================
--- gate/trunk/src/gate/creole/CreoleAnnotationHandler.java     2012-01-13 
15:35:53 UTC (rev 15032)
+++ gate/trunk/src/gate/creole/CreoleAnnotationHandler.java     2012-01-13 
15:46:53 UTC (rev 15033)
@@ -28,21 +28,28 @@
 import gate.creole.metadata.HiddenCreoleParameter;
 import gate.creole.metadata.Optional;
 import gate.creole.metadata.RunTime;
+import gate.util.Err;
 import gate.util.GateException;
-import gate.util.Err;
+import gate.util.ant.ExpandIvy;
 
+import java.io.IOException;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.io.IOException;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.ivy.Ivy;
+import org.apache.ivy.core.LogOptions;
+import org.apache.ivy.core.report.ArtifactDownloadReport;
+import org.apache.ivy.core.report.ResolveReport;
+import org.apache.ivy.core.resolve.ResolveOptions;
+import org.apache.ivy.util.filter.FilterHelper;
 import org.jdom.Document;
 import org.jdom.Element;
 
@@ -71,16 +78,58 @@
    * @param jdomDoc JDOM document representing a parsed creole.xml file.
    */
   public void addJarsToClassLoader(Document jdomDoc)
-          throws MalformedURLException {
+          throws IOException {
     addJarsToClassLoader(jdomDoc.getRootElement());
+    addIvyDependencies(jdomDoc);
   }
+  
+  /**
+   * Extract all the IVY elements from the given JDOM document and then add all
+   * the jars resulting from ivy's dependency resolution to the 
GateClassLoader.
+   * 
+   * @param creoleDoc
+   *          JDOM document representing a parsed creole.xml file.
+   */
+  private void addIvyDependencies(Document creoleDoc) throws IOException {
 
+    try {
+      List<Element> ivyElts = ExpandIvy.getIvyElements(creoleDoc);
+
+      if(ivyElts.size() > 0) {
+
+        Ivy ivy = ExpandIvy.getIvy(ExpandIvy.getSettingsURL());
+
+        ResolveOptions resolveOptions = new ResolveOptions();
+        resolveOptions.setArtifactFilter(FilterHelper
+            .getArtifactTypeFilter(new String[]{"jar"}));
+        resolveOptions.setLog(LogOptions.LOG_QUIET);
+
+        for(Element e : ivyElts) {
+          URL url = new URL(creoleFileUrl, ExpandIvy.getIvyPath(e));
+
+          ResolveReport report = ivy.resolve(url, resolveOptions);
+          if(report.getAllProblemMessages().size() > 0)
+            throw new Exception("Unable to resolve all IVY dependencies");
+
+          for(ArtifactDownloadReport dlReport : 
report.getAllArtifactsReports()) {
+            Gate.getClassLoader().addURL(
+                dlReport.getLocalFile().toURI().toURL());
+          }
+
+        }
+      }
+    } catch(Exception ex) {
+      throw new IOException("Error using Ivy to add required dependencies", 
ex);
+    }
+  }
+
   /**
    * Recursively search the given element for JAR entries and add these
    * jars to the GateClassLoader
    *
    * @param jdomElt JDOM element representing a creole.xml file
    */
+  @SuppressWarnings("unchecked")
   private void addJarsToClassLoader(Element jdomElt)
           throws MalformedURLException {
     if("JAR".equals(jdomElt.getName())) {
@@ -133,6 +182,7 @@
 
   }
 
+  @SuppressWarnings("unchecked")
   private void findResourceElements(Map<String, Element> map, Element elt) {
     if(elt.getName().equals("RESOURCE")) {
       String className = elt.getChildTextTrim("CLASS");
@@ -165,6 +215,7 @@
    *
    * @param element the element to process.
    */
+  @SuppressWarnings("unchecked")
   private void processAnnotations(Element element) throws GateException {
     if("RESOURCE".equals(element.getName())) {
       processAnnotationsForResource(element);

Modified: gate/trunk/src/gate/creole/CreoleXmlHandler.java
===================================================================
--- gate/trunk/src/gate/creole/CreoleXmlHandler.java    2012-01-13 15:35:53 UTC 
(rev 15032)
+++ gate/trunk/src/gate/creole/CreoleXmlHandler.java    2012-01-13 15:46:53 UTC 
(rev 15033)
@@ -16,19 +16,34 @@
 
 package gate.creole;
 
+import gate.CreoleRegister;
+import gate.Factory;
+import gate.FeatureMap;
+import gate.Gate;
+import gate.GateConstants;
+import gate.util.GateRuntimeException;
+import gate.util.GateSaxException;
+import gate.util.Out;
+import gate.util.Strings;
+import gate.xml.SimpleErrorHandler;
+
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.Stack;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
 
-import javax.swing.text.html.HTMLDocument.HTMLReader.HiddenAction;
-
-import org.xml.sax.*;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
 import org.xml.sax.helpers.DefaultHandler;
 
-import gate.*;
-import gate.util.*;
-import gate.xml.SimpleErrorHandler;
-
 /** This is a SAX handler for processing <CODE>creole.xml</CODE> files.
   * It would have been better to write it using DOM or JDOM but....
   * Resource data objects are created and added to the CREOLE register.
@@ -41,7 +56,7 @@
    *  onto it. Probably. Ok, so I should check, but a) it works, b)
    *  I'm bald already and c) life is short.)
    */
-  private Stack contentStack = new Stack();
+  private Stack<String> contentStack = new Stack<String>();
 
   /** The current resource data object */
   private ResourceData resourceData;
@@ -95,7 +110,7 @@
   /** This field holds autoinstanceParams describing the resource that
     * needs to be instantiated
     */
-  private List currentAutoinstances = null;
+  private List<FeatureMap> currentAutoinstances = null;
 
 
   /** This is used to capture all data within two tags before calling the 
actual characters method */
@@ -171,7 +186,7 @@
     if(elementName.toUpperCase().equals("RESOURCE")) {
       resourceData = new ResourceData();
       resourceData.setFeatures(Factory.newFeatureMap());
-      currentAutoinstances = new ArrayList();
+      currentAutoinstances = new ArrayList<FeatureMap>();
     }// End if RESOURCE
 
     // record the attributes of this element
@@ -234,9 +249,9 @@
                                 currentAttributes.getValue("ITEM_CLASS_NAME");
       // read the suffixes and transform them to a Set of Strings
       String suffixes = currentAttributes.getValue("SUFFIXES");
-      Set suffiexesSet = null;
+      Set<String> suffiexesSet = null;
       if (suffixes != null){
-        suffiexesSet = new HashSet();
+        suffiexesSet = new HashSet<String>();
         StringTokenizer strTokenizer = new StringTokenizer(suffixes,";");
         while(strTokenizer.hasMoreTokens()){
            suffiexesSet.add(strTokenizer.nextToken());
@@ -302,7 +317,8 @@
       // if the resource is auto-loading, try and load it
       if(resourceData.isAutoLoading())
         try {
-          Class resClass = resourceData.getResourceClass();
+          @SuppressWarnings("unused")
+          Class<?> resClass = resourceData.getResourceClass();
 //          Resource res = Factory.createResource(
 //              resourceData.getClassName(), Factory.newFeatureMap()
 //          );
@@ -337,9 +353,9 @@
       if(DEBUG) Out.println("added: " + resourceData);
       // Iterate through autoinstances and try to instanciate them
       if ( currentAutoinstances != null && !currentAutoinstances.isEmpty()){
-        Iterator iter = currentAutoinstances.iterator();
+        Iterator<FeatureMap> iter = currentAutoinstances.iterator();
         while (iter.hasNext()){
-          FeatureMap autoinstanceParams = (FeatureMap) iter.next();
+          FeatureMap autoinstanceParams = iter.next();
           iter.remove();
           FeatureMap autoinstanceFeatures = null;
           //if the hidden attribute was set in the parameters, create a 
feature 
@@ -384,6 +400,10 @@
       resourceData.setName((String) contentStack.pop());
     // End NAME processing
     //////////////////////////////////////////////////////////////////
+    } else if (elementName.toUpperCase().equals("IVY")) {
+      if (!contentStack.isEmpty()) contentStack.pop();
+    // End IVY processing
+    //////////////////////////////////////////////////////////////////
     } else if(elementName.toUpperCase().equals("JAR")) {
       checkStack("endElement", "JAR");
 
@@ -492,9 +512,9 @@
       checkStack("endElement", "RESOURCE_DISPLAYED");
       String resourceDisplayed = (String) contentStack.pop();
       resourceData.setResourceDisplayed(resourceDisplayed);
-      Class resourceDisplayedClass = null;
       try{
-        resourceDisplayedClass = Gate.getClassLoader().
+        @SuppressWarnings("unused")
+        Class<?> resourceDisplayedClass = Gate.getClassLoader().
                                  loadClass(resourceDisplayed);
       } catch (ClassNotFoundException ex){
         throw new GateRuntimeException(

Modified: gate/trunk/src/gate/gui/NameBearerHandle.java
===================================================================
--- gate/trunk/src/gate/gui/NameBearerHandle.java       2012-01-13 15:35:53 UTC 
(rev 15032)
+++ gate/trunk/src/gate/gui/NameBearerHandle.java       2012-01-13 15:46:53 UTC 
(rev 15033)
@@ -1290,6 +1290,7 @@
               task.setDestFile(targetGapp);
               // sensible default settings
               task.setCopyPlugins(true);
+              task.setExpandIvy(true);
               task.setCopyResourceDirs(true);
               task.setOnUnresolved(PackageGappTask.UnresolvedAction.recover);
               task.init();
@@ -2032,20 +2033,20 @@
 
   protected void fireProgressChanged(int e) {
     if(progressListeners != null) {
-      Vector listeners = progressListeners;
+      Vector<ProgressListener> listeners = progressListeners;
       int count = listeners.size();
       for(int i = 0; i < count; i++) {
-        ((ProgressListener)listeners.elementAt(i)).progressChanged(e);
+        listeners.elementAt(i).progressChanged(e);
       }
     }
   }// protected void fireProgressChanged(int e)
 
   protected void fireProcessFinished() {
     if(progressListeners != null) {
-      Vector listeners = progressListeners;
+      Vector<ProgressListener> listeners = progressListeners;
       int count = listeners.size();
       for(int i = 0; i < count; i++) {
-        ((ProgressListener)listeners.elementAt(i)).processFinished();
+        listeners.elementAt(i).processFinished();
       }
     }
   }// protected void fireProcessFinished()
@@ -2073,10 +2074,10 @@
 
   protected void fireStatusChanged(String e) {
     if(statusListeners != null) {
-      Vector listeners = statusListeners;
+      Vector<StatusListener> listeners = statusListeners;
       int count = listeners.size();
       for(int i = 0; i < count; i++) {
-        ((StatusListener)listeners.elementAt(i)).statusChanged(e);
+        listeners.elementAt(i).statusChanged(e);
       }
     }
   }

Added: gate/trunk/src/gate/util/ant/ExpandIvy.java
===================================================================
--- gate/trunk/src/gate/util/ant/ExpandIvy.java                         (rev 0)
+++ gate/trunk/src/gate/util/ant/ExpandIvy.java 2012-01-13 15:46:53 UTC (rev 
15033)
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 1995-2012, 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, 12/01/2012
+ * 
+ * $Id$
+ */
+
+package gate.util.ant;
+
+import gate.util.persistence.PersistenceManager;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.URL;
+import java.text.ParseException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ivy.Ivy;
+import org.apache.ivy.core.LogOptions;
+import org.apache.ivy.core.report.ArtifactDownloadReport;
+import org.apache.ivy.core.report.ResolveReport;
+import org.apache.ivy.core.resolve.ResolveOptions;
+import org.apache.ivy.core.retrieve.RetrieveOptions;
+import org.apache.ivy.core.settings.IvySettings;
+import org.apache.ivy.util.DefaultMessageLogger;
+import org.apache.ivy.util.Message;
+import org.apache.ivy.util.filter.Filter;
+import org.apache.ivy.util.filter.FilterHelper;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Copy;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+import org.jdom.xpath.XPath;
+
+/**
+ * An ANT task that takes a CREOLE plugin and adds local copies of Ivy managed
+ * dependencies. This involves copying JAR files into the plugin directory as
+ * well as updating the creole.xml to substitute the IVY elements with
+ * appropriate JAR elements.
+ */
+public class ExpandIvy extends Task {
+
+  private XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
+
+  private File dir, settings;
+
+  private boolean verbose = false;
+
+  private boolean fully = false;
+
+  /**
+   * Get the CREOLE plugin directory being processed.
+   * 
+   * @return the CREOLE plugin directory being processed.
+   */
+  public File getDir() {
+    return dir;
+  }
+
+  /**
+   * Set the CREOLE plugin directory to be processed.
+   * 
+   * @param dir
+   *          the CREOLE plugin directory to be processed.
+   */
+  public void setDir(File dir) {
+    this.dir = dir;
+  }
+
+  /**
+   * Get the Ivy settings file used to control dependency resolution.
+   * 
+   * @return the Ivy settings file used to control dependency resolution, or
+   *         null if the default settings are being used.
+   */
+  public File getSettings() {
+    return dir;
+  }
+
+  /**
+   * Specifies the settings file used to control dependency resolution.
+   * 
+   * @param settings
+   *          the settings file used to control dependency resolution, or null
+   *          to use the default settings.
+   */
+  public void setSettings(File settings) {
+    this.settings = settings;
+  }
+
+  /**
+   * If true then Ivy will spit out lots of messages while resolving
+   * dependencies.
+   * 
+   * @return if true then Ivy will spit out lots of messages while resolving
+   *         dependencies.
+   */
+  public boolean getVerbose() {
+    return verbose;
+  }
+
+  /**
+   * Controls the log level of Ivy.
+   * 
+   * @param verbose
+   *          if true then Ivy will spit out lots of messages while resolving
+   *          dependencies.
+   */
+  public void setVerbose(boolean verbose) {
+    this.verbose = verbose;
+  }
+
+  /**
+   * Should we fully remove the link to Ivy by removing the dependency XML
+   * files.
+   * 
+   * @return if true Ivy files referenced in creole.xml will be removed after
+   *         they have been processed.
+   */
+  public boolean getFully() {
+    return fully;
+  }
+
+  /**
+   * If true Ivy files referenced in creole.xml will be removed after they have
+   * been processed.
+   * 
+   * @param fully
+   *          if true Ivy files referenced in creole.xml will be removed after
+   *          they have been processed.
+   */
+  public void setFully(boolean fully) {
+    this.fully = fully;
+  }
+
+  @Override
+  public void execute() throws BuildException {
+    if(dir == null)
+      throw new BuildException("Please specify a directory", getLocation());
+
+    if(!dir.exists() || !dir.isDirectory())
+      throw new BuildException("Specified directory doesn't exist",
+          getLocation());
+
+    File creoleXml = new File(dir, "creole.xml");
+
+    if(!creoleXml.exists())
+      throw new BuildException("Supplied directory isn't a CREOLE plugin");
+
+    try {
+      // load the creole.xml into a JDOM structure
+      SAXBuilder builder = new SAXBuilder();
+      Document creoleDoc = builder.build(creoleXml);
+
+      // get the IVY elements from the creole XML file
+      List<Element> ivyElts = getIvyElements(creoleDoc);
+
+      if(ivyElts.size() > 0) {
+        // if there are some elements to process then we have work to do...
+
+        // get a configured Ivy instance
+        Ivy ivy =
+            getIvy(settings != null
+                ? settings.toURI().toURL()
+                : getSettingsURL(), dir);
+
+        // we only want the binary jars so create a filter for them
+        Filter filter = FilterHelper.getArtifactTypeFilter(new 
String[]{"jar"});
+
+        // set up the options for doing a resolve
+        ResolveOptions resolveOptions = new ResolveOptions();
+        resolveOptions.setArtifactFilter(filter);
+        if(!verbose) resolveOptions.setLog(LogOptions.LOG_QUIET);
+
+        // set up the options for doing a retrieve
+        RetrieveOptions retrieveOptions = new RetrieveOptions();
+        retrieveOptions.setArtifactFilter(filter);
+        if(!verbose) retrieveOptions.setLog(LogOptions.LOG_QUIET);
+
+        // an ANT task to handle all the copying
+        Copy copyTask;
+
+        for(Element e : ivyElts) {
+          // for each IVY element in the creole.xml file....
+
+          // get the location of the ivy file (assume ivy.xml if not specified)
+          File ivyFile = getIvyFile(e, creoleXml);
+
+          if(!ivyFile.exists())
+            throw new BuildException("Referenced ivy file does not exist: "
+                + ivyFile, getLocation());
+
+          // remove the IVY element from the XML
+          Element parent = e.getParentElement();
+          parent.removeContent(e);
+
+          // get ivy to resolve the dependencies and generate a report
+          ResolveReport report =
+              ivy.resolve(ivyFile.toURI().toURL(), resolveOptions);
+
+          if(report.getAllProblemMessages().size() > 0)
+            throw new BuildException("Unable to resolve all IVY dependencies",
+                getLocation());
+
+          // don't do a retrieve but find out what it would actually do.
+          // NOTE: we need to do this as a retrieve just returns the number of
+          // jar files copied and not what they were which we need to update 
the
+          // creole.xml file
+          @SuppressWarnings("unchecked")
+          Map<ArtifactDownloadReport, Set<String>> toCopy =
+              ivy.getRetrieveEngine().determineArtifactsToCopy(
+                  report.getModuleDescriptor().getModuleRevisionId(),
+                  ivy.getSettings().substitute(
+                      ivy.getSettings().getVariable("ivy.retrieve.pattern")),
+                  retrieveOptions);
+
+          for(Map.Entry<ArtifactDownloadReport, Set<String>> entry : toCopy
+              .entrySet()) {
+            // for each artifact a retrieve would copy....
+            ArtifactDownloadReport dlReport =
+                (ArtifactDownloadReport)entry.getKey();
+
+            for(String destPath : entry.getValue()) {
+              // find out where it should end up
+              File destFile = new File(destPath);
+
+              // make sure the dir actually exists
+              destFile.getParentFile().mkdirs();
+
+              // set up ANT ready to copy from the cache into the plugin dir
+              copyTask = new Copy();
+              copyTask.setProject(getProject());
+              copyTask.setLocation(getLocation());
+              copyTask.setTaskName(getTaskName());
+              copyTask.setFile(dlReport.getLocalFile());
+              copyTask.setTofile(destFile);
+              copyTask.init();
+
+              // do the actual copy
+              copyTask.perform();
+
+              // add a new JAR element to creole.xml pointing at the newly 
added
+              // jar
+              Element jarElement =
+                  new Element("JAR").setText(PersistenceManager
+                      .getRelativePath(dir.toURI().toURL(), destFile.toURI()
+                          .toURL()));
+              parent.addContent(jarElement);
+            }
+
+            if(fully && !ivyFile.delete()) ivyFile.deleteOnExit();
+          }
+        }
+
+        // now we have finished write the new XML back to creole.xml
+        outputter.output(creoleDoc, new FileWriter(creoleXml));
+      }
+    } catch(Exception e) {
+      // if anything goes wrong just re-throw the exception
+      throw new BuildException(e);
+    }
+  }
+
+  /**
+   * Processes the specified creole.xml file to extract all the &lt;IVY&gt;
+   * elements
+   * 
+   * @param creoleXML
+   *          the URL of the creole.xml file to process
+   * @return a list of the &lt;IVY&gt; XML elements
+   */
+  public static List<Element> getIvyElements(URL creoleXML)
+      throws JDOMException, IOException {
+    // load the creole.xml into a JDOM structure
+    SAXBuilder builder = new SAXBuilder();
+    Document doc = builder.build(creoleXML);
+    return getIvyElements(doc);
+  }
+
+  /**
+   * Processes the specified XML document file to extract all the &lt;IVY&gt;
+   * elements
+   * 
+   * @param doc
+   *          the XML document to process
+   * @return a list of the &lt;IVY&gt; XML elements
+   */
+  @SuppressWarnings("unchecked")
+  public static List<Element> getIvyElements(Document doc) throws 
JDOMException {
+    // use XPath to find all the IVY elements
+    XPath jarXPath =
+        XPath.newInstance("//*[translate(local-name(), 'ivy', 'IVY') = 
'IVY']");
+    return jarXPath.selectNodes(doc);
+  }
+
+  /**
+   * Turns an &lt;IVY&gt; XML element into a File instance by resolving 
relative
+   * to the creole.xml file.
+   * 
+   * @param element
+   *          the &lt;IVY&gt; element to convert
+   * @param creoleXML
+   *          the creole.xml file to resolve relative to
+   * @return a File instance pointing to the Ivy file specified by the XML
+   *         element
+   */
+  public static File getIvyFile(Element element, File creoleXML) {
+    return new File(creoleXML.getParentFile(), getIvyPath(element));
+  }
+
+  /**
+   * Retrieve the path to the Ivy file as specified in the XML element. If no
+   * path is given use the default of 'ivy.xml'.
+   * 
+   * @param element
+   *          the &lt;IVY&gt; XML element to process
+   * @return the path to the Ivy file as specified in the XML element, defaults
+   *         to 'ivy.xml'.
+   */
+  public static String getIvyPath(Element element) {
+    String ivyText = element.getTextTrim();
+    if(ivyText == null || ivyText.equals("")) ivyText = "ivy.xml";
+    return ivyText;
+  }
+
+  public static Ivy getIvy() throws ParseException, IOException {
+    return getIvy(null, null);
+  }
+
+  public static Ivy getIvy(File dir) throws ParseException, IOException {
+    return getIvy(null, dir);
+  }
+
+  public static Ivy getIvy(URL settings) throws ParseException, IOException {
+    return getIvy(settings, null);
+  }
+
+  public static Ivy getIvy(URL settings, File dir) throws ParseException,
+      IOException {
+    IvySettings ivySettings = new IvySettings();
+
+    if(settings != null)
+      ivySettings.load(settings);
+    else ivySettings.loadDefault();
+
+    if(dir != null) ivySettings.setBaseDir(dir);
+
+    // get an instance of ivy
+    return Ivy.newInstance(ivySettings);
+  }
+
+  /**
+   * Attempts to find a custom Ivy settings file to use instead of the default
+   * configuration. This looks first for a system property
+   * <code>ivy.settings.file</code> and then <code>ivy.settings.url</code>. If
+   * neither exist or can be converted to a valid URL then the method returns
+   * null.
+   * 
+   * @return the URL of the settings file to use or null if one was not
+   *         specified or could not be correctly converted.
+   */
+  public static URL getSettingsURL() {
+
+    String val = System.getProperty("ivy.settings.file");
+    if(val != null) {
+      try {
+        File file = new File(val);
+        if(file.exists() && file.isFile() && file.canRead())
+          return file.toURI().toURL();
+      } catch(Exception e) {
+        // ignore this and try the URL
+        System.err.println("Ivalid ivy.settings.file will be ignored: " + val);
+      }
+    }
+
+    val = System.getProperty("ivy.settings.url");
+    if(val != null) {
+      try {
+        return new URL(val);
+      } catch(Exception e) {
+        // ignore this
+        System.err.println("Ivalid ivy.settings.url will be ignored: " + val);
+      }
+    }
+
+    // neither of the system properties were helpful so return null
+    return null;
+  }
+
+  static {
+    // this seems to be the only way to suppress the loading settings message
+    Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_ERR));
+  }
+}
\ No newline at end of file

Modified: gate/trunk/src/gate/util/ant/antlib.xml
===================================================================
--- gate/trunk/src/gate/util/ant/antlib.xml     2012-01-13 15:35:53 UTC (rev 
15032)
+++ gate/trunk/src/gate/util/ant/antlib.xml     2012-01-13 15:46:53 UTC (rev 
15033)
@@ -3,6 +3,9 @@
 <antlib>
   <!-- Expand creole.xml (used to regenerate the plugins.html page) -->
   <taskdef name="expandcreoles" classname="gate.util.ant.ExpandCreoleXmls" />
+  
+  <!-- Expand CREOLE plugins to include local copies of Ivy dependencies -->
+  <taskdef name="expandivy" classname="gate.util.ant.ExpandIvy" />
 
   <!-- GAPP file packager -->
   <taskdef name="packagegapp" 
classname="gate.util.ant.packager.PackageGappTask" />

Modified: gate/trunk/src/gate/util/ant/packager/PackageGappTask.java
===================================================================
--- gate/trunk/src/gate/util/ant/packager/PackageGappTask.java  2012-01-13 
15:35:53 UTC (rev 15032)
+++ gate/trunk/src/gate/util/ant/packager/PackageGappTask.java  2012-01-13 
15:46:53 UTC (rev 15033)
@@ -14,6 +14,7 @@
 package gate.util.ant.packager;
 
 import gate.util.Files;
+import gate.util.ant.ExpandIvy;
 import gate.util.persistence.PersistenceManager;
 
 import java.io.File;
@@ -100,6 +101,12 @@
    * declared in an &lt;extrafiles&gt; sub-element.
    */
   private boolean copyPlugins = true;
+  
+  /**
+   * Should we expand any Ivy based dependencies to create a standalone
+   * application. If true then local copies of each dependency will be
+   */
+  private boolean expandIvy = false;
 
   /**
    * Should we copy the complete contents of the parent directories of
@@ -214,6 +221,14 @@
   public void setCopyPlugins(boolean copyPlugins) {
     this.copyPlugins = copyPlugins;
   }
+  
+  public void setExpandIvy(boolean expandIvy) {
+    this.expandIvy = expandIvy;
+  }
+  
+  public boolean getExpandIvy() {
+    return expandIvy;
+  }
 
   /**
    * Will the task copy the complete contents of directories containing
@@ -607,14 +622,32 @@
       if(copyPlugins) {
         log("Also copying complete plugin contents", Project.MSG_VERBOSE);
       }
+      copyDirectories(pluginCopyMap, !copyPlugins);
+
+      if(expandIvy) {
+        ExpandIvy ivyExpander = new ExpandIvy();
+        ivyExpander.setProject(getProject());
+        ivyExpander.setLocation(getLocation());
+        ivyExpander.setTaskName(getTaskName());
+        ivyExpander.setFully(!copyPlugins);
+
+        for(URL url : pluginCopyMap.values()) {
+          File dir = Files.fileFromURL(url);
+          if(dir.exists()) {
+            ivyExpander.setDir(dir);
+            ivyExpander.init();
+            ivyExpander.perform();
+          }
+        }
+      }
     }
-    copyDirectories(pluginCopyMap, !copyPlugins);
-
+    
     // handle extra directories
     if(dirCopyMap.size() > 0) {
-      log("Copying " + dirCopyMap.size() + " resource directories");
+      log("Copying " + dirCopyMap.size() + " resource directories");      
+      copyDirectories(dirCopyMap, false);
     }
-    copyDirectories(dirCopyMap, false);
+    
   }
 
   /**
@@ -648,9 +681,7 @@
   private void copyDirectories(Map<URL, URL> copyMap, boolean minimalPlugin) {
     for(Map.Entry<URL, URL> copyEntry : copyMap.entrySet()) {
       File source = Files.fileFromURL(copyEntry.getKey());
-      if(!source.exists()) {
-        return;
-      }
+      if(!source.exists()) { return; }
       File dest = Files.fileFromURL(copyEntry.getValue());
       // set up a copy task to do the copying
       Copy copyTask = new Copy();
@@ -670,17 +701,29 @@
         URL creoleXml;
         try {
           creoleXml =
-                  new URL(copyEntry.getKey().toExternalForm() + "/creole.xml");
-        }
-        catch(MalformedURLException e) {
+              new URL(copyEntry.getKey().toExternalForm() + "/creole.xml");
+        } catch(MalformedURLException e) {
           throw new BuildException(
-                  "Error creating URL for creole.xml in plugin "
-                          + copyEntry.getKey());
+              "Error creating URL for creole.xml in plugin "
+                  + copyEntry.getKey());
         }
+
         for(String jarString : getJars(creoleXml)) {
           NameEntry jarInclude = fileSet.createInclude();
           jarInclude.setName(jarString);
         }
+
+        // copy the ivy files as either they will be needed to load the plugin
+        // or they will be needed when the expand task is run
+        try {
+          for(Element e : ExpandIvy.getIvyElements(creoleXml)) {
+            NameEntry ivyInclude = fileSet.createInclude();
+            ivyInclude.setName(ExpandIvy.getIvyPath(e));
+          }
+        } catch(Exception e) {
+          throw new BuildException("Error processing IVY includes", e,
+              getLocation());
+        }
       }
 
       // do the copying
@@ -690,11 +733,11 @@
   }
 
   /**
-   * Extract the text values from any &lt;JAR&gt; elements contained in
-   * the referenced creole.xml file.
+   * Extract the text values from any &lt;JAR&gt; elements contained in the
+   * referenced creole.xml file.
    * 
-   * @return a set with one element for each unique &lt;JAR&gt; entry in
-   *         the given creole.xml.
+   * @return a set with one element for each unique &lt;JAR&gt; entry in the
+   *         given creole.xml.
    */
   private Set<String> getJars(URL creoleXml) {
     try {
@@ -702,29 +745,28 @@
       // the XPath is a bit ugly, but needed to match the element name
       // case-insensitively.
       XPath jarXPath =
-              XPath
-                      .newInstance("//*[translate(local-name(), 'jar', 'JAR') 
= 'JAR']");
+          XPath
+              .newInstance("//*[translate(local-name(), 'jar', 'JAR') = 
'JAR']");
       SAXBuilder builder = new SAXBuilder();
       Document creoleDoc = builder.build(creoleXml);
       // technically unsafe, but we know that the above XPath expression
       // can only match elements.
+      @SuppressWarnings("unchecked")
       List<Element> jarElts = jarXPath.selectNodes(creoleDoc);
       for(Element e : jarElts) {
         jars.add(e.getTextTrim());
       }
 
       return jars;
-    }
-    catch(JDOMException e) {
+    } catch(JDOMException e) {
       throw new BuildException("Error extracting JAR elements from "
-              + creoleXml, e, getLocation());
-    }
-    catch(IOException e) {
+          + creoleXml, e, getLocation());
+    } catch(IOException e) {
       throw new BuildException("Error loading " + creoleXml
-              + " to extract JARs", e, getLocation());
+          + " to extract JARs", e, getLocation());
     }
   }
-
+  
   /**
    * Get a URL for a directory to which the given (unresolved) resource
    * directory should be mapped.

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


------------------------------------------------------------------------------
RSA(R) Conference 2012
Mar 27 - Feb 2
Save $400 by Jan. 27
Register now!
http://p.sf.net/sfu/rsa-sfdev2dev2
_______________________________________________
GATE-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gate-cvs

Reply via email to