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 <IVY>
+ * elements
+ *
+ * @param creoleXML
+ * the URL of the creole.xml file to process
+ * @return a list of the <IVY> 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 <IVY>
+ * elements
+ *
+ * @param doc
+ * the XML document to process
+ * @return a list of the <IVY> 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 <IVY> XML element into a File instance by resolving
relative
+ * to the creole.xml file.
+ *
+ * @param element
+ * the <IVY> 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 <IVY> 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 <extrafiles> 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 <JAR> elements contained in
- * the referenced creole.xml file.
+ * Extract the text values from any <JAR> elements contained in the
+ * referenced creole.xml file.
*
- * @return a set with one element for each unique <JAR> entry in
- * the given creole.xml.
+ * @return a set with one element for each unique <JAR> 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