Revision: 19985
          http://sourceforge.net/p/gate/code/19985
Author:   markagreenwood
Date:     2017-01-25 14:20:13 +0000 (Wed, 25 Jan 2017)
Log Message:
-----------
moved gate.Plugin to gate.creole.Plugin which is a much more sensible place for 
the class to live

Modified Paths:
--------------
    
gate/branches/sawdust2/Test-Utils/src/main/java/gate/test/GATEPluginTestCase.java
    gate/branches/sawdust2/gate-core/src/main/java/gate/CreoleRegister.java
    gate/branches/sawdust2/gate-core/src/main/java/gate/Factory.java
    gate/branches/sawdust2/gate-core/src/main/java/gate/Gate.java
    gate/branches/sawdust2/gate-core/src/main/java/gate/Main.java
    gate/branches/sawdust2/gate-core/src/main/java/gate/Utils.java
    
gate/branches/sawdust2/gate-core/src/main/java/gate/creole/CreoleAnnotationHandler.java
    
gate/branches/sawdust2/gate-core/src/main/java/gate/creole/CreoleRegisterImpl.java
    gate/branches/sawdust2/gate-core/src/main/java/gate/gui/MainFrame.java
    
gate/branches/sawdust2/gate-core/src/main/java/gate/gui/creole/manager/AvailablePlugins.java
    
gate/branches/sawdust2/gate-core/src/main/java/gate/gui/creole/manager/PluginUpdateManager.java
    
gate/branches/sawdust2/gate-core/src/main/java/gate/util/GateClassLoader.java
    
gate/branches/sawdust2/gate-core/src/main/java/gate/util/ant/ExpandCreoleXmls.java
    
gate/branches/sawdust2/gate-core/src/main/java/gate/util/persistence/PersistenceManager.java
    gate/branches/sawdust2/gate-core/src/test/java/gate/config/TestConfig.java
    
gate/branches/sawdust2/gate-core/src/test/java/gate/creole/DynamicRegistrationTest.java
    gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestCreole.java
    
gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestCreoleAnnotationHandler.java
    
gate/branches/sawdust2/gate-maven-plugin/src/main/java/uk/ac/gate/maven/DumpCreoleToXML.java
    gate/branches/sawdust2/notes.txt
    gate/branches/sawdust2/pom.xml

Added Paths:
-----------
    gate/branches/sawdust2/gate-core/src/main/java/gate/creole/Plugin.java

Removed Paths:
-------------
    gate/branches/sawdust2/gate-core/src/main/java/gate/Plugin.java

Modified: 
gate/branches/sawdust2/Test-Utils/src/main/java/gate/test/GATEPluginTestCase.java
===================================================================
--- 
gate/branches/sawdust2/Test-Utils/src/main/java/gate/test/GATEPluginTestCase.java
   2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/Test-Utils/src/main/java/gate/test/GATEPluginTestCase.java
   2017-01-25 14:20:13 UTC (rev 19985)
@@ -15,7 +15,7 @@
 package gate.test;
 
 import gate.Gate;
-import gate.Plugin;
+import gate.creole.Plugin;
 import gate.Gate.ResourceInfo;
 import gate.util.Files;
 import gate.util.asm.ClassReader;

Modified: 
gate/branches/sawdust2/gate-core/src/main/java/gate/CreoleRegister.java
===================================================================
--- gate/branches/sawdust2/gate-core/src/main/java/gate/CreoleRegister.java     
2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/gate-core/src/main/java/gate/CreoleRegister.java     
2017-01-25 14:20:13 UTC (rev 19985)
@@ -16,6 +16,7 @@
 
 package gate;
 
+import gate.creole.Plugin;
 import gate.creole.ResourceData;
 import gate.creole.metadata.CreoleResource;
 import gate.event.CreoleListener;

Modified: gate/branches/sawdust2/gate-core/src/main/java/gate/Factory.java
===================================================================
--- gate/branches/sawdust2/gate-core/src/main/java/gate/Factory.java    
2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/gate-core/src/main/java/gate/Factory.java    
2017-01-25 14:20:13 UTC (rev 19985)
@@ -24,6 +24,7 @@
 import gate.creole.CustomDuplication;
 import gate.creole.ParameterException;
 import gate.creole.ParameterList;
+import gate.creole.Plugin;
 import gate.creole.ResourceData;
 import gate.creole.ResourceInstantiationException;
 import gate.event.CreoleEvent;

Modified: gate/branches/sawdust2/gate-core/src/main/java/gate/Gate.java
===================================================================
--- gate/branches/sawdust2/gate-core/src/main/java/gate/Gate.java       
2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/gate-core/src/main/java/gate/Gate.java       
2017-01-25 14:20:13 UTC (rev 19985)
@@ -18,6 +18,7 @@
 
 import gate.config.ConfigDataProcessor;
 import gate.creole.CreoleRegisterImpl;
+import gate.creole.Plugin;
 import gate.creole.ResourceData;
 import gate.event.CreoleListener;
 import gate.gui.creole.manager.PluginUpdateManager;
@@ -1289,6 +1290,10 @@
     public String getResourceComment() {
       return resourceComment;
     }
+    
+    public void setResourceComment(String resourceComment) {
+       this.resourceComment = resourceComment;
+    }
 
     /**
      * @return Returns the resourceName.
@@ -1296,6 +1301,10 @@
     public String getResourceName() {
       return resourceName;
     }
+    
+    public void setResourceName(String resourceName) {
+       this.resourceName = resourceName;
+    }
 
     /**
      * The class for the resource.

Modified: gate/branches/sawdust2/gate-core/src/main/java/gate/Main.java
===================================================================
--- gate/branches/sawdust2/gate-core/src/main/java/gate/Main.java       
2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/gate-core/src/main/java/gate/Main.java       
2017-01-25 14:20:13 UTC (rev 19985)
@@ -16,6 +16,7 @@
 
 package gate;
 
+import gate.creole.Plugin;
 import gate.gui.MainFrame;
 import gate.gui.OptionsDialog;
 import gate.util.BomStrippingInputStreamReader;

Deleted: gate/branches/sawdust2/gate-core/src/main/java/gate/Plugin.java
===================================================================
--- gate/branches/sawdust2/gate-core/src/main/java/gate/Plugin.java     
2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/gate-core/src/main/java/gate/Plugin.java     
2017-01-25 14:20:13 UTC (rev 19985)
@@ -1,751 +0,0 @@
-/*
- *  Plugin.java
- *
- *  Copyright (c) 2016, 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 3, June 2007 (in the distribution as file licence.html,
- *  and also available at http://gate.ac.uk/gate/licence.html).
- *
- *  Mark A. Greenwood, 3rd April 2016
- */
-
-package gate;
-
-import static gate.util.maven.Utils.getRepositoryList;
-import static gate.util.maven.Utils.getRepositorySession;
-import static gate.util.maven.Utils.getRepositorySystem;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
-import java.lang.reflect.Field;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.net.URLStreamHandler;
-import java.net.URLStreamHandlerFactory;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
-
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.building.DefaultModelBuilderFactory;
-import org.apache.maven.model.building.DefaultModelBuildingRequest;
-import org.apache.maven.model.building.ModelBuilder;
-import org.apache.maven.model.building.ModelBuildingRequest;
-import org.eclipse.aether.RepositorySystem;
-import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.artifact.DefaultArtifact;
-import org.eclipse.aether.collection.CollectRequest;
-import org.eclipse.aether.graph.Dependency;
-import org.eclipse.aether.graph.DependencyNode;
-import org.eclipse.aether.repository.RemoteRepository;
-import org.eclipse.aether.repository.WorkspaceReader;
-import org.eclipse.aether.resolution.ArtifactRequest;
-import org.eclipse.aether.resolution.ArtifactResult;
-import org.eclipse.aether.resolution.DependencyRequest;
-import org.eclipse.aether.resolution.DependencyResult;
-import org.eclipse.aether.util.artifact.SubArtifact;
-import org.jdom.Attribute;
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.JDOMException;
-import org.jdom.input.SAXBuilder;
-
-import gate.Gate.ResourceInfo;
-import gate.creole.metadata.CreoleResource;
-import gate.util.asm.AnnotationVisitor;
-import gate.util.asm.ClassReader;
-import gate.util.asm.ClassVisitor;
-import gate.util.asm.Opcodes;
-import gate.util.asm.Type;
-import gate.util.asm.commons.EmptyVisitor;
-import gate.util.maven.SimpleModelResolver;
-
-public abstract class Plugin {
-  
-  protected static final Logger log = Logger.getLogger(Plugin.class);
-  
-  /**
-   * Is the plugin valid (i.e. is the location reachable and the
-   * creole.xml file parsable).
-   */
-  protected transient boolean valid = true;
-  
-  /**
-   * This is the URL against which all relative URLs in the CREOLE
-   * metadata are resolved
-   */
-  protected transient URI baseURL;
-  
-  protected transient String name;
-
-  /**
-   * The list of {@link Gate.ResourceInfo} objects within this plugin
-   */
-  protected transient List<ResourceInfo> resourceInfoList = null;
-  
-  /**
-   * The set of other plugins that must be loaded prior to the loading
-   * of this plugin
-   */
-  protected transient Set<Plugin> requiredPlugins = null;
-
-  public abstract org.jdom.Document getCreoleXML() throws Exception;
-  
-  public abstract String getName();
-  
-  public Set<Plugin> getRequiredPlugins() {
-    if (requiredPlugins == null) parseCreole();
-    
-    return requiredPlugins;
-  }   
-    
-  @Override
-  public int hashCode() {
-    final int prime = 31;
-    int result = 1;
-    result = prime * result + ((baseURL == null) ? 0 : baseURL.hashCode());
-    return result;
-  }
-  
-  @Override
-  public String toString() {
-    return getName();
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    if(this == obj) return true;
-    if(obj == null) return false;
-    if(getClass() != obj.getClass()) return false;
-    Plugin other = (Plugin)obj;
-    if(baseURL == null) {
-      if(other.baseURL != null) return false;
-    } else if(!baseURL.equals(other.baseURL)) return false;
-    return true;
-  }
-
-  public List<ResourceInfo> getResourceInfoList() {
-    if (resourceInfoList == null) parseCreole();
-    
-    return resourceInfoList;
-  }
-  
-  public URL getBaseURL() {
-    try {
-      return baseURL.toURL();
-    } catch(MalformedURLException e) {
-      // this should be impossible because of the way we have got hold of the
-      // URI
-      throw new RuntimeException(e);
-    }
-  }
-  
-  public boolean isValid() {
-    return valid;
-  }
-  
-  public void copyResources(File dir) throws IOException, URISyntaxException {
-    throw new UnsupportedOperationException("This plugin does not contain any 
resources that can be copied");
-  }
-  
-  public boolean hasResources() {
-    return false;
-  }
-  
-  protected void parseCreole() {
-    
-    valid = true;
-
-    resourceInfoList = new ArrayList<ResourceInfo>();
-    requiredPlugins = new LinkedHashSet<Plugin>();
-    
-    String relativePathMarker = "$relpath$";
-    String gatehomePathMarker = "$gatehome$";
-    String gatepluginsPathMarker = "$gateplugins$";
-    
-    try {
-      org.jdom.Document creoleDoc = getCreoleXML();
-      
-      final Map<String, ResourceInfo> resInfos = new LinkedHashMap<String, 
ResourceInfo>();
-      List<Element> jobsList = new ArrayList<Element>();
-      List<String> jarsToScan = new ArrayList<String>();
-      List<String> allJars = new ArrayList<String>();
-      jobsList.add(creoleDoc.getRootElement());
-      while(!jobsList.isEmpty()) {
-        Element currentElem = jobsList.remove(0);
-        if(currentElem.getName().equalsIgnoreCase("JAR")) {
-          @SuppressWarnings("unchecked")
-          List<Attribute> attrs = currentElem.getAttributes();
-          Iterator<Attribute> attrsIt = attrs.iterator();
-          while(attrsIt.hasNext()) {
-            Attribute attr = attrsIt.next();
-            if(attr.getName().equalsIgnoreCase("SCAN") && 
attr.getBooleanValue()) {
-              jarsToScan.add(currentElem.getTextTrim());
-              break;
-            }
-          }
-          allJars.add(currentElem.getTextTrim());
-        }
-        else if(currentElem.getName().equalsIgnoreCase("RESOURCE")) {
-          // we don't go deeper than resources so no recursion here
-          String resName = currentElem.getChildTextTrim("NAME");
-          String resClass = currentElem.getChildTextTrim("CLASS");
-          String resComment = currentElem.getChildTextTrim("COMMENT");
-          if(!resInfos.containsKey(resClass)) {
-            // create the handler
-            ResourceInfo rHandler =
-              new ResourceInfo(resName, resClass, resComment);
-            resInfos.put(resClass, rHandler);
-          }
-        }
-        else if(currentElem.getName().equalsIgnoreCase("REQUIRES")) {
-                    
-          if (currentElem.getAttribute("GROUP") != null) {
-            //TODO probably need more error checking here
-            requiredPlugins.add(new Plugin.Maven(currentElem
-                    .getAttributeValue("GROUP"), currentElem
-                    .getAttributeValue("ARTIFACT"), currentElem
-                    .getAttributeValue("VERSION")));
-          }
-          else {        
-            URL url = null;
-            String urlString = currentElem.getTextTrim();
-            if(urlString.startsWith(relativePathMarker)) {
-              url =
-                  new URL(getBaseURL(), urlString.substring(relativePathMarker
-                      .length()));
-            } else if(urlString.startsWith(gatehomePathMarker)) {
-              URL gatehome = Gate.getGateHome().toURI().toURL();
-              url =
-                  new URL(gatehome,
-                      urlString.substring(gatehomePathMarker.length()));
-            } else if(urlString.startsWith(gatepluginsPathMarker)) {
-              URL gateplugins = Gate.getPluginsHome().toURI().toURL();
-              url =
-                  new URL(gateplugins, 
urlString.substring(gatepluginsPathMarker
-                      .length()));
-            } else {
-              url = new URL(getBaseURL(), urlString);
-            }
-  
-            requiredPlugins.add(new Plugin.Directory(url));
-            
-            Utils.logOnce(log, Level.WARN, "Dependencies on other plugins via 
URL is deprecated ("+getName()+" plugin)");
-          }
-        }
-        else {
-          // this is some higher level element -> simulate recursion
-          // we want Depth-first-search so we need to add at the beginning
-          @SuppressWarnings("unchecked")
-          List<Element> newJobsList = new 
ArrayList<Element>(currentElem.getChildren());
-          newJobsList.addAll(jobsList);
-          jobsList = newJobsList;
-        }
-      }
-
-      // now process the jar files with SCAN="true", looking for any extra
-      // CreoleResource annotated classes.
-      for(String jarFile : jarsToScan) {
-        URL jarUrl = new URL(getBaseURL(), jarFile);
-        scanJar(jarUrl, resInfos);
-      }
-
-      // see whether any of the ResourceInfo objects are still incomplete
-      // (don't have a name)
-      List<ResourceInfo> incompleteResInfos = new ArrayList<ResourceInfo>();
-      for(ResourceInfo ri : resInfos.values()) {
-        if(ri.getResourceName() == null) {
-          incompleteResInfos.add(ri);
-        }
-      }
-
-      if(!incompleteResInfos.isEmpty()) {
-        fillInResInfos(incompleteResInfos, allJars);
-      }
-
-      // if any of the resource infos still don't have a name, take it from
-      // the class name.
-      for(ResourceInfo ri : incompleteResInfos) {
-        if(ri.getResourceName() == null) {
-          ri.resourceName = ri.resourceClassName.substring(
-                  ri.resourceClassName.lastIndexOf('.') + 1);
-        }
-      }
-
-      // finally, we have the complete list of ResourceInfos
-      resourceInfoList.addAll(resInfos.values());
-    }
-    catch(IOException ioe) {
-      valid = false;
-      log.error("Problem while parsing plugin " + toString() + "!\n"
-        + ioe.toString() + "\nPlugin not available!");
-    }
-    catch(JDOMException jde) {
-      valid = false;
-      log.error("Problem while parsing plugin " + toString() + "!\n"
-        + jde.toString() + "\nPlugin not available!");
-    }
-    catch(Exception e) {
-      valid = false;
-      log.error("Problem while parsing plugin " + toString() + "!\n"
-        + e.toString() + "\nPlugin not available!");
-    }
-  }
-
-  protected void scanJar(URL jarUrl, Map<String, ResourceInfo> resInfos) 
throws IOException {
-    JarInputStream jarInput = new JarInputStream(jarUrl.openStream(), false);
-    JarEntry entry = null;
-    while((entry = jarInput.getNextJarEntry()) != null) {
-      String entryName = entry.getName();
-      if(entryName != null && entryName.endsWith(".class")) {
-        final String className = entryName.substring(0,
-                 entryName.length() - 6).replace('/', '.');
-        if(!resInfos.containsKey(className)) {
-          ClassReader classReader = new ClassReader(jarInput);
-          ResourceInfo resInfo = new ResourceInfo(null, className, null);
-          ResourceInfoVisitor visitor = new ResourceInfoVisitor(resInfo);
-
-          classReader.accept(visitor, ClassReader.SKIP_CODE |
-              ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
-          if(visitor.isCreoleResource()) {
-            resInfos.put(className, resInfo);
-          }
-        }
-      }
-    }
-
-    jarInput.close();
-  }
-
-  protected void fillInResInfos(List<ResourceInfo> incompleteResInfos,
-          List<String> allJars) throws IOException {
-    // now create a temporary class loader with all the JARs (scanned or
-    // not), so we can look up all the referenced classes in the normal
-    // way and read their CreoleResource annotations (if any).
-    URL[] jarUrls = new URL[allJars.size()];
-    for(int i = 0; i < jarUrls.length; i++) {
-      jarUrls[i] = new URL(getBaseURL(), allJars.get(i));
-    }
-
-    // TODO shouldn't we use a proper temp gate class loader which we
-    // can then throw away?
-    try(URLClassLoader tempClassLoader =
-            new URLClassLoader(jarUrls, Gate.class.getClassLoader());) {
-      for(ResourceInfo ri : incompleteResInfos) {
-        String classFile =
-                ri.getResourceClassName().replace('.', '/') + ".class";
-        InputStream classStream =
-                tempClassLoader.getResourceAsStream(classFile);
-        if(classStream != null) {
-          ClassReader classReader = new ClassReader(classStream);
-          ClassVisitor visitor = new ResourceInfoVisitor(ri);
-          classReader.accept(visitor, ClassReader.SKIP_CODE
-                  | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
-          classStream.close();
-        }
-      }
-    }
-  }
-
-  public static class Directory extends Plugin {
-
-    public Directory(URL directoryURL) {
-      try {
-        baseURL = Gate.normaliseCreoleUrl(directoryURL).toURI();
-      } catch(URISyntaxException e) {
-        //this should never happen but....
-        throw new RuntimeException(e);
-      }
-    }    
-
-    @Override
-    public Document getCreoleXML() throws Exception {
-      SAXBuilder builder = new SAXBuilder(false);
-      URL creoleFileURL = new URL(getBaseURL(), "creole.xml");
-      return builder.build(creoleFileURL);
-    }
-
-    @Override
-    public String getName() {
-      if(name != null) return name;
-
-      // url.getPath() works for jar URLs; url.toURI().getPath() doesn't
-      // because jars aren't considered "hierarchical"
-      name = getBaseURL().getPath();
-      if(name.endsWith("/")) {
-        name = name.substring(0, name.length() - 1);
-      }
-      int lastSlash = name.lastIndexOf("/");
-      if(lastSlash != -1) {
-        name = name.substring(lastSlash + 1);
-      }
-      try {
-        // convert to (relative) URI and extract path.  This will
-        // decode any %20 escapes in the name.
-        name = new URI(name).getPath();
-      } catch(URISyntaxException ex) {
-        // ignore, this should have been checked when adding the URL!
-      }
-      return name;
-    }
-  }
-
-  public static class Maven extends Plugin implements Serializable {
-
-    private static final long serialVersionUID = -6944695755723023537L;
-    
-    private String group, artifact, version;
-    
-    private transient URL artifactURL;
-    
-    private WorkspaceReader workspace = null;//new SimpleMavenCache(new 
File("cache"));
-
-    public Maven(String group, String artifact, String version) {
-      this.group = group;
-      this.artifact = artifact;
-      this.version = version;
-      
-      name = group+":"+artifact+":"+version;
-    }    
-
-    @Override
-    public int hashCode() {
-      final int prime = 31;
-      int result = 1;
-      result = prime * result + ((artifact == null) ? 0 : artifact.hashCode());
-      result = prime * result + ((group == null) ? 0 : group.hashCode());
-      result = prime * result + ((version == null) ? 0 : version.hashCode());
-      return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-            
-      if(this == obj) return true;
-      if (obj == null) return false;
-      
-      if(getClass() != obj.getClass()) return false;
-      Maven other = (Maven)obj;
-      if(artifact == null) {
-        if(other.artifact != null) return false;
-      } else if(!artifact.equals(other.artifact)) return false;
-      if(group == null) {
-        if(other.group != null) return false;
-      } else if(!group.equals(other.group)) return false;
-      if(version == null) {
-        if(other.version != null) return false;
-      } else if(!version.equals(other.version)) return false;
-      return true;
-    }
-
-    @Override
-    public void copyResources(File dir) throws URISyntaxException, IOException 
{
-      
-      if (!hasResources())
-        throw new UnsupportedOperationException(
-            "this plugin doesn't have any resources you can copy as you would 
know had you called hasResources first :P");
-      
-      try (FileSystem zipFs =
-          FileSystems.newFileSystem(artifactURL.toURI(), new HashMap<>());) {
-
-        Path target = Paths.get(dir.toURI());
-        Path pathInZip = zipFs.getPath("/resources");
-
-        Files.walkFileTree(pathInZip, new SimpleFileVisitor<Path>() {
-          @Override
-          public FileVisitResult visitFile(Path filePath,
-              BasicFileAttributes attrs) throws IOException {
-            // Make sure that we conserve the hierachy of files and folders
-            // inside the zip
-            Path relativePathInZip = pathInZip.relativize(filePath);
-            Path targetPath = target.resolve(relativePathInZip.toString());
-            Files.createDirectories(targetPath.getParent());
-
-            // And extract the file
-            Files.copy(filePath, targetPath, 
StandardCopyOption.REPLACE_EXISTING);
-
-            return FileVisitResult.CONTINUE;
-          }
-        });
-      }
-    }
-    
-    @Override
-    public boolean hasResources() {   
-      try (FileSystem zipFs = FileSystems.newFileSystem(artifactURL.toURI(), 
new HashMap<>());) {        
-        Path pathInZip = zipFs.getPath("/resources");
-        return Files.isDirectory(pathInZip);
-      }
-      catch (URISyntaxException | IOException e) {
-        return false;
-      }
-    }    
-    
-    public URL getArtifactURL() throws Exception {
-      if (artifactURL == null) {
-        getCreoleXML();
-      }
-      
-      return artifactURL;
-    }
-
-    @Override
-    public Document getCreoleXML() throws Exception {
-      Artifact artifactObj =
-              new DefaultArtifact(group, artifact, "jar", version);
-
-      Dependency dependency = new Dependency(artifactObj, "runtime");
-
-      List<RemoteRepository> repos = getRepositoryList();
-      
-      ArtifactRequest artifactRequest = new ArtifactRequest(artifactObj, 
repos, null);
-            
-      RepositorySystem repoSystem = getRepositorySystem();
-      RepositorySystemSession repoSession = getRepositorySession(repoSystem, 
workspace);     
-      
-
-      ArtifactResult artifactResult =
-          repoSystem.resolveArtifact(repoSession,
-                      artifactRequest);
-      
-      //baseURL = new URI("creole://"+group+";"+artifact+";"+version+"/");
-            
-      artifactURL =
-              new URL("jar:"
-                      + artifactResult.getArtifact().getFile().toURI().toURL()
-                      + "!/");
-      
-      baseURL = artifactURL.toURI();
-
-      // check it has a creole.xml at the root
-      URL directoryXmlFileUrl = new URL(artifactURL, "creole.xml");
-
-      InputStream creoleStream = null;
-
-      try {
-        creoleStream = directoryXmlFileUrl.openStream();
-      } catch(IOException ioe) {
-        throw new IOException(getBaseURL().toExternalForm()
-                + " does not exist so this artifact is not a GATE plugin");
-      }
-
-      CollectRequest collectRequest = new CollectRequest(dependency,repos);
-      
-      DependencyNode node =
-              repoSystem.collectDependencies(repoSession,
-                      collectRequest).getRoot();
-
-      DependencyRequest dependencyRequest = new DependencyRequest();
-      dependencyRequest.setRoot(node);
-      
-      DependencyResult result =
-              repoSystem.resolveDependencies(repoSession,
-                      dependencyRequest);
-
-      // get the creole.xml out of the jar and add jar elements for this
-      // jar (marked for scanning) and the dependencies
-      SAXBuilder builder = new SAXBuilder(false);
-      Document jdomDoc =
-              builder.build(creoleStream, getBaseURL().toExternalForm());
-
-      Element creoleRoot = jdomDoc.getRootElement();
-
-      for(ArtifactResult ar : result.getArtifactResults()) {        
-        
-        Element jarElement = new Element("JAR");
-        jarElement.setText(ar.getArtifact().getFile().toURI().toURL()
-                .toExternalForm());
-
-        if(ar.getArtifact().equals(artifactResult.getArtifact())) {
-          jarElement.setAttribute("SCAN", "true");
-        }
-
-        creoleRoot.addContent(jarElement);
-      }
-      
-      artifactObj =
-          new SubArtifact(artifactObj,"", "pom");
-      
-      artifactRequest.setArtifact(artifactObj);
-      artifactResult =
-          repoSystem.resolveArtifact(repoSession,
-                  artifactRequest);
-      
-      ModelBuildingRequest req = new DefaultModelBuildingRequest(); 
-      req.setProcessPlugins(false); 
-      req.setPomFile(artifactResult.getArtifact().getFile()); 
-      req.setModelResolver(new SimpleModelResolver(repoSystem,  
-              repoSession, new ArrayList<RemoteRepository>())); 
-      req.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL); 
-       
-      ModelBuilder modelBuilder = new 
DefaultModelBuilderFactory().newInstance(); 
-      Model model = modelBuilder.build(req).getEffectiveModel(); 
-      
-      
-      if (model.getName() != null && !model.getName().trim().equals("")) name 
= model.getName();
-      
-      /*System.out.println(model.getOrganization().getName());
-      for (org.apache.maven.model.Repository r : model.getRepositories()) {
-        System.out.println(r.getName());
-      }
-      for (License l : model.getLicenses()) {
-        System.out.println(l.getName());
-      }*/
-      
-      return jdomDoc;
-    }
-
-    @Override
-    public String getName() {
-      return name;
-    }
-  }
-  
-  /**
-   * ClassVisitor that uses information from a CreoleResource annotation on the
-   * visited class (if such exists) to fill in the name and comment in the
-   * corresponding ResourceInfo.
-   */
-  protected static class ResourceInfoVisitor extends EmptyVisitor {
-    private ResourceInfo resInfo;
-
-    private boolean foundCreoleResource = false;
-
-    private boolean isAbstract = false;
-
-    public ResourceInfoVisitor(ResourceInfo resInfo) {
-      this.resInfo = resInfo;
-    }
-
-    public boolean isCreoleResource() {
-      return foundCreoleResource && !isAbstract;
-    }
-
-    /**
-     * Type descriptor for the CreoleResource annotation type.
-     */
-    private static final String CREOLE_RESOURCE_DESC =
-            Type.getDescriptor(CreoleResource.class);
-
-    /**
-     * Visit the class header, checking whether this is an abstract class or
-     * interface and setting the isAbstract flag appropriately.
-     */
-    @Override
-    public void visit(int version, int access, String name, String signature,
-            String superName, String[] interfaces) {
-      isAbstract = ((access &
-            (Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)) != 0);
-    }
-
-    /**
-     * Visit an annotation on the class.
-     */
-    @Override
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-      // we've found a CreoleResource annotation on this class
-      if(desc.equals(CREOLE_RESOURCE_DESC)) {
-        foundCreoleResource = true;
-        return new AnnotationVisitor(Opcodes.ASM5) {
-          @Override
-          public void visit(String name, Object value) {
-            if(name.equals("name") && resInfo.resourceName == null) {
-              resInfo.resourceName = (String)value;
-            }
-            else if(name.equals("comment") && resInfo.resourceComment == null) 
{
-              resInfo.resourceComment = (String)value;
-            }
-          }
-
-          @Override
-          public AnnotationVisitor visitAnnotation(String name,
-                    String desc) {
-            // don't want to recurse into AutoInstance annotations
-            return this;
-          }
-        };
-      }
-      else {
-        return super.visitAnnotation(desc, visible);
-      }
-    }
-  }
-  
-  public static class Component extends Plugin {
-
-    private Class<? extends Resource> resourceClass;
-    
-    public Component(Class<? extends Resource> resourceClass) throws 
MalformedURLException {
-      this.resourceClass = resourceClass;
-      try {
-        baseURL = (new 
URL(resourceClass.getResource("/gate/creole/CreoleRegisterImpl.class"), 
".")).toURI();
-      } catch(URISyntaxException e) {
-        //this should never happen
-        throw new RuntimeException(e);
-      }
-    }
-    
-    @Override
-    public Document getCreoleXML() throws Exception, JDOMException {
-      Document doc = new Document();
-      Element element;
-      doc.addContent(element = new Element("CREOLE-DIRECTORY"));
-      element.addContent(element = new Element("CREOLE"));
-      element.addContent(element = new Element("RESOURCE"));
-      Element classElement  = new Element("CLASS");
-      classElement.setText(resourceClass.getName());
-      element.addContent(classElement);
-      
-      return doc;
-    }
-
-    @Override
-    public String getName() {
-      return resourceClass.getName();
-    }
-    
-  }
-  
-  public static void main(String args[]) throws Exception {
-    Gate.runInSandbox(true);
-    Gate.init();
-     
-    Plugin annieMaven = new Plugin.Maven("uk.ac.gate.plugins", "annie", 
"9.0-SNAPSHOT");
-    
-    Gate.getCreoleRegister().registerPlugin(annieMaven);
-    
-    System.out.println(annieMaven.getName());
-    
-    File r = new File("testResources");
-    System.out.println(annieMaven.hasResources());
-    annieMaven.copyResources(r);
-
-  }
-}

Modified: gate/branches/sawdust2/gate-core/src/main/java/gate/Utils.java
===================================================================
--- gate/branches/sawdust2/gate-core/src/main/java/gate/Utils.java      
2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/gate-core/src/main/java/gate/Utils.java      
2017-01-25 14:20:13 UTC (rev 19985)
@@ -18,6 +18,7 @@
 import gate.annotation.AnnotationSetImpl;
 import gate.annotation.ImmutableAnnotationSetImpl;
 import gate.creole.ConditionalSerialController;
+import gate.creole.Plugin;
 import gate.creole.RunningStrategy;
 import gate.util.FeatureBearer;
 import gate.util.GateRuntimeException;

Modified: 
gate/branches/sawdust2/gate-core/src/main/java/gate/creole/CreoleAnnotationHandler.java
===================================================================
--- 
gate/branches/sawdust2/gate-core/src/main/java/gate/creole/CreoleAnnotationHandler.java
     2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/gate-core/src/main/java/gate/creole/CreoleAnnotationHandler.java
     2017-01-25 14:20:13 UTC (rev 19985)
@@ -18,7 +18,6 @@
 
 import gate.Gate;
 import gate.Gate.ResourceInfo;
-import gate.Plugin;
 import gate.Resource;
 import gate.creole.metadata.AutoInstance;
 import gate.creole.metadata.AutoInstanceParam;

Modified: 
gate/branches/sawdust2/gate-core/src/main/java/gate/creole/CreoleRegisterImpl.java
===================================================================
--- 
gate/branches/sawdust2/gate-core/src/main/java/gate/creole/CreoleRegisterImpl.java
  2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/gate-core/src/main/java/gate/creole/CreoleRegisterImpl.java
  2017-01-25 14:20:13 UTC (rev 19985)
@@ -22,7 +22,6 @@
 import gate.Gate;
 import gate.Gate.ResourceInfo;
 import gate.LanguageResource;
-import gate.Plugin;
 import gate.ProcessingResource;
 import gate.Resource;
 import gate.VisualResource;

Copied: gate/branches/sawdust2/gate-core/src/main/java/gate/creole/Plugin.java 
(from rev 19984, 
gate/branches/sawdust2/gate-core/src/main/java/gate/Plugin.java)
===================================================================
--- gate/branches/sawdust2/gate-core/src/main/java/gate/creole/Plugin.java      
                        (rev 0)
+++ gate/branches/sawdust2/gate-core/src/main/java/gate/creole/Plugin.java      
2017-01-25 14:20:13 UTC (rev 19985)
@@ -0,0 +1,754 @@
+/*
+ *  Plugin.java
+ *
+ *  Copyright (c) 2016, 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 3, June 2007 (in the distribution as file licence.html,
+ *  and also available at http://gate.ac.uk/gate/licence.html).
+ *
+ *  Mark A. Greenwood, 3rd April 2016
+ */
+
+package gate.creole;
+
+import static gate.util.maven.Utils.getRepositoryList;
+import static gate.util.maven.Utils.getRepositorySession;
+import static gate.util.maven.Utils.getRepositorySystem;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.DefaultModelBuilderFactory;
+import org.apache.maven.model.building.DefaultModelBuildingRequest;
+import org.apache.maven.model.building.ModelBuilder;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.repository.WorkspaceReader;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.resolution.DependencyRequest;
+import org.eclipse.aether.resolution.DependencyResult;
+import org.eclipse.aether.util.artifact.SubArtifact;
+import org.jdom.Attribute;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+
+import gate.Gate;
+import gate.Resource;
+import gate.Utils;
+import gate.Gate.ResourceInfo;
+import gate.creole.metadata.CreoleResource;
+import gate.util.asm.AnnotationVisitor;
+import gate.util.asm.ClassReader;
+import gate.util.asm.ClassVisitor;
+import gate.util.asm.Opcodes;
+import gate.util.asm.Type;
+import gate.util.asm.commons.EmptyVisitor;
+import gate.util.maven.SimpleModelResolver;
+
+public abstract class Plugin {
+  
+  protected static final Logger log = Logger.getLogger(Plugin.class);
+  
+  /**
+   * Is the plugin valid (i.e. is the location reachable and the
+   * creole.xml file parsable).
+   */
+  protected transient boolean valid = true;
+  
+  /**
+   * This is the URL against which all relative URLs in the CREOLE
+   * metadata are resolved
+   */
+  protected transient URI baseURL;
+  
+  protected transient String name;
+
+  /**
+   * The list of {@link Gate.ResourceInfo} objects within this plugin
+   */
+  protected transient List<ResourceInfo> resourceInfoList = null;
+  
+  /**
+   * The set of other plugins that must be loaded prior to the loading
+   * of this plugin
+   */
+  protected transient Set<Plugin> requiredPlugins = null;
+
+  public abstract org.jdom.Document getCreoleXML() throws Exception;
+  
+  public abstract String getName();
+  
+  public Set<Plugin> getRequiredPlugins() {
+    if (requiredPlugins == null) parseCreole();
+    
+    return requiredPlugins;
+  }   
+    
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((baseURL == null) ? 0 : baseURL.hashCode());
+    return result;
+  }
+  
+  @Override
+  public String toString() {
+    return getName();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if(this == obj) return true;
+    if(obj == null) return false;
+    if(getClass() != obj.getClass()) return false;
+    Plugin other = (Plugin)obj;
+    if(baseURL == null) {
+      if(other.baseURL != null) return false;
+    } else if(!baseURL.equals(other.baseURL)) return false;
+    return true;
+  }
+
+  public List<ResourceInfo> getResourceInfoList() {
+    if (resourceInfoList == null) parseCreole();
+    
+    return resourceInfoList;
+  }
+  
+  public URL getBaseURL() {
+    try {
+      return baseURL.toURL();
+    } catch(MalformedURLException e) {
+      // this should be impossible because of the way we have got hold of the
+      // URI
+      throw new RuntimeException(e);
+    }
+  }
+  
+  public boolean isValid() {
+    return valid;
+  }
+  
+  public void copyResources(File dir) throws IOException, URISyntaxException {
+    throw new UnsupportedOperationException("This plugin does not contain any 
resources that can be copied");
+  }
+  
+  public boolean hasResources() {
+    return false;
+  }
+  
+  protected void parseCreole() {
+    
+    valid = true;
+
+    resourceInfoList = new ArrayList<ResourceInfo>();
+    requiredPlugins = new LinkedHashSet<Plugin>();
+    
+    String relativePathMarker = "$relpath$";
+    String gatehomePathMarker = "$gatehome$";
+    String gatepluginsPathMarker = "$gateplugins$";
+    
+    try {
+      org.jdom.Document creoleDoc = getCreoleXML();
+      
+      final Map<String, ResourceInfo> resInfos = new LinkedHashMap<String, 
ResourceInfo>();
+      List<Element> jobsList = new ArrayList<Element>();
+      List<String> jarsToScan = new ArrayList<String>();
+      List<String> allJars = new ArrayList<String>();
+      jobsList.add(creoleDoc.getRootElement());
+      while(!jobsList.isEmpty()) {
+        Element currentElem = jobsList.remove(0);
+        if(currentElem.getName().equalsIgnoreCase("JAR")) {
+          @SuppressWarnings("unchecked")
+          List<Attribute> attrs = currentElem.getAttributes();
+          Iterator<Attribute> attrsIt = attrs.iterator();
+          while(attrsIt.hasNext()) {
+            Attribute attr = attrsIt.next();
+            if(attr.getName().equalsIgnoreCase("SCAN") && 
attr.getBooleanValue()) {
+              jarsToScan.add(currentElem.getTextTrim());
+              break;
+            }
+          }
+          allJars.add(currentElem.getTextTrim());
+        }
+        else if(currentElem.getName().equalsIgnoreCase("RESOURCE")) {
+          // we don't go deeper than resources so no recursion here
+          String resName = currentElem.getChildTextTrim("NAME");
+          String resClass = currentElem.getChildTextTrim("CLASS");
+          String resComment = currentElem.getChildTextTrim("COMMENT");
+          if(!resInfos.containsKey(resClass)) {
+            // create the handler
+            ResourceInfo rHandler =
+              new ResourceInfo(resName, resClass, resComment);
+            resInfos.put(resClass, rHandler);
+          }
+        }
+        else if(currentElem.getName().equalsIgnoreCase("REQUIRES")) {
+                    
+          if (currentElem.getAttribute("GROUP") != null) {
+            //TODO probably need more error checking here
+            requiredPlugins.add(new Plugin.Maven(currentElem
+                    .getAttributeValue("GROUP"), currentElem
+                    .getAttributeValue("ARTIFACT"), currentElem
+                    .getAttributeValue("VERSION")));
+          }
+          else {        
+            URL url = null;
+            String urlString = currentElem.getTextTrim();
+            if(urlString.startsWith(relativePathMarker)) {
+              url =
+                  new URL(getBaseURL(), urlString.substring(relativePathMarker
+                      .length()));
+            } else if(urlString.startsWith(gatehomePathMarker)) {
+              URL gatehome = Gate.getGateHome().toURI().toURL();
+              url =
+                  new URL(gatehome,
+                      urlString.substring(gatehomePathMarker.length()));
+            } else if(urlString.startsWith(gatepluginsPathMarker)) {
+              URL gateplugins = Gate.getPluginsHome().toURI().toURL();
+              url =
+                  new URL(gateplugins, 
urlString.substring(gatepluginsPathMarker
+                      .length()));
+            } else {
+              url = new URL(getBaseURL(), urlString);
+            }
+  
+            requiredPlugins.add(new Plugin.Directory(url));
+            
+            Utils.logOnce(log, Level.WARN, "Dependencies on other plugins via 
URL is deprecated ("+getName()+" plugin)");
+          }
+        }
+        else {
+          // this is some higher level element -> simulate recursion
+          // we want Depth-first-search so we need to add at the beginning
+          @SuppressWarnings("unchecked")
+          List<Element> newJobsList = new 
ArrayList<Element>(currentElem.getChildren());
+          newJobsList.addAll(jobsList);
+          jobsList = newJobsList;
+        }
+      }
+
+      // now process the jar files with SCAN="true", looking for any extra
+      // CreoleResource annotated classes.
+      for(String jarFile : jarsToScan) {
+        URL jarUrl = new URL(getBaseURL(), jarFile);
+        scanJar(jarUrl, resInfos);
+      }
+
+      // see whether any of the ResourceInfo objects are still incomplete
+      // (don't have a name)
+      List<ResourceInfo> incompleteResInfos = new ArrayList<ResourceInfo>();
+      for(ResourceInfo ri : resInfos.values()) {
+        if(ri.getResourceName() == null) {
+          incompleteResInfos.add(ri);
+        }
+      }
+
+      if(!incompleteResInfos.isEmpty()) {
+        fillInResInfos(incompleteResInfos, allJars);
+      }
+
+      // if any of the resource infos still don't have a name, take it from
+      // the class name.
+      for(ResourceInfo ri : incompleteResInfos) {
+        if(ri.getResourceName() == null) {
+          ri.setResourceName(ri.getResourceClassName().substring(
+                  ri.getResourceClassName().lastIndexOf('.') + 1));
+        }
+      }
+
+      // finally, we have the complete list of ResourceInfos
+      resourceInfoList.addAll(resInfos.values());
+    }
+    catch(IOException ioe) {
+      valid = false;
+      log.error("Problem while parsing plugin " + toString() + "!\n"
+        + ioe.toString() + "\nPlugin not available!");
+    }
+    catch(JDOMException jde) {
+      valid = false;
+      log.error("Problem while parsing plugin " + toString() + "!\n"
+        + jde.toString() + "\nPlugin not available!");
+    }
+    catch(Exception e) {
+      valid = false;
+      log.error("Problem while parsing plugin " + toString() + "!\n"
+        + e.toString() + "\nPlugin not available!");
+    }
+  }
+
+  protected void scanJar(URL jarUrl, Map<String, ResourceInfo> resInfos) 
throws IOException {
+    JarInputStream jarInput = new JarInputStream(jarUrl.openStream(), false);
+    JarEntry entry = null;
+    while((entry = jarInput.getNextJarEntry()) != null) {
+      String entryName = entry.getName();
+      if(entryName != null && entryName.endsWith(".class")) {
+        final String className = entryName.substring(0,
+                 entryName.length() - 6).replace('/', '.');
+        if(!resInfos.containsKey(className)) {
+          ClassReader classReader = new ClassReader(jarInput);
+          ResourceInfo resInfo = new ResourceInfo(null, className, null);
+          ResourceInfoVisitor visitor = new ResourceInfoVisitor(resInfo);
+
+          classReader.accept(visitor, ClassReader.SKIP_CODE |
+              ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+          if(visitor.isCreoleResource()) {
+            resInfos.put(className, resInfo);
+          }
+        }
+      }
+    }
+
+    jarInput.close();
+  }
+
+  protected void fillInResInfos(List<ResourceInfo> incompleteResInfos,
+          List<String> allJars) throws IOException {
+    // now create a temporary class loader with all the JARs (scanned or
+    // not), so we can look up all the referenced classes in the normal
+    // way and read their CreoleResource annotations (if any).
+    URL[] jarUrls = new URL[allJars.size()];
+    for(int i = 0; i < jarUrls.length; i++) {
+      jarUrls[i] = new URL(getBaseURL(), allJars.get(i));
+    }
+
+    // TODO shouldn't we use a proper temp gate class loader which we
+    // can then throw away?
+    try(URLClassLoader tempClassLoader =
+            new URLClassLoader(jarUrls, Gate.class.getClassLoader());) {
+      for(ResourceInfo ri : incompleteResInfos) {
+        String classFile =
+                ri.getResourceClassName().replace('.', '/') + ".class";
+        InputStream classStream =
+                tempClassLoader.getResourceAsStream(classFile);
+        if(classStream != null) {
+          ClassReader classReader = new ClassReader(classStream);
+          ClassVisitor visitor = new ResourceInfoVisitor(ri);
+          classReader.accept(visitor, ClassReader.SKIP_CODE
+                  | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+          classStream.close();
+        }
+      }
+    }
+  }
+
+  public static class Directory extends Plugin {
+
+    public Directory(URL directoryURL) {
+      try {
+        baseURL = Gate.normaliseCreoleUrl(directoryURL).toURI();
+      } catch(URISyntaxException e) {
+        //this should never happen but....
+        throw new RuntimeException(e);
+      }
+    }    
+
+    @Override
+    public Document getCreoleXML() throws Exception {
+      SAXBuilder builder = new SAXBuilder(false);
+      URL creoleFileURL = new URL(getBaseURL(), "creole.xml");
+      return builder.build(creoleFileURL);
+    }
+
+    @Override
+    public String getName() {
+      if(name != null) return name;
+
+      // url.getPath() works for jar URLs; url.toURI().getPath() doesn't
+      // because jars aren't considered "hierarchical"
+      name = getBaseURL().getPath();
+      if(name.endsWith("/")) {
+        name = name.substring(0, name.length() - 1);
+      }
+      int lastSlash = name.lastIndexOf("/");
+      if(lastSlash != -1) {
+        name = name.substring(lastSlash + 1);
+      }
+      try {
+        // convert to (relative) URI and extract path.  This will
+        // decode any %20 escapes in the name.
+        name = new URI(name).getPath();
+      } catch(URISyntaxException ex) {
+        // ignore, this should have been checked when adding the URL!
+      }
+      return name;
+    }
+  }
+
+  public static class Maven extends Plugin implements Serializable {
+
+    private static final long serialVersionUID = -6944695755723023537L;
+    
+    private String group, artifact, version;
+    
+    private transient URL artifactURL;
+    
+    private WorkspaceReader workspace = null;//new SimpleMavenCache(new 
File("cache"));
+
+    public Maven(String group, String artifact, String version) {
+      this.group = group;
+      this.artifact = artifact;
+      this.version = version;
+      
+      name = group+":"+artifact+":"+version;
+    }    
+
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + ((artifact == null) ? 0 : artifact.hashCode());
+      result = prime * result + ((group == null) ? 0 : group.hashCode());
+      result = prime * result + ((version == null) ? 0 : version.hashCode());
+      return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+            
+      if(this == obj) return true;
+      if (obj == null) return false;
+      
+      if(getClass() != obj.getClass()) return false;
+      Maven other = (Maven)obj;
+      if(artifact == null) {
+        if(other.artifact != null) return false;
+      } else if(!artifact.equals(other.artifact)) return false;
+      if(group == null) {
+        if(other.group != null) return false;
+      } else if(!group.equals(other.group)) return false;
+      if(version == null) {
+        if(other.version != null) return false;
+      } else if(!version.equals(other.version)) return false;
+      return true;
+    }
+
+    @Override
+    public void copyResources(File dir) throws URISyntaxException, IOException 
{
+      
+      if (!hasResources())
+        throw new UnsupportedOperationException(
+            "this plugin doesn't have any resources you can copy as you would 
know had you called hasResources first :P");
+      
+      try (FileSystem zipFs =
+          FileSystems.newFileSystem(artifactURL.toURI(), new HashMap<>());) {
+
+        Path target = Paths.get(dir.toURI());
+        Path pathInZip = zipFs.getPath("/resources");
+
+        Files.walkFileTree(pathInZip, new SimpleFileVisitor<Path>() {
+          @Override
+          public FileVisitResult visitFile(Path filePath,
+              BasicFileAttributes attrs) throws IOException {
+            // Make sure that we conserve the hierachy of files and folders
+            // inside the zip
+            Path relativePathInZip = pathInZip.relativize(filePath);
+            Path targetPath = target.resolve(relativePathInZip.toString());
+            Files.createDirectories(targetPath.getParent());
+
+            // And extract the file
+            Files.copy(filePath, targetPath, 
StandardCopyOption.REPLACE_EXISTING);
+
+            return FileVisitResult.CONTINUE;
+          }
+        });
+      }
+    }
+    
+    @Override
+    public boolean hasResources() {   
+      try (FileSystem zipFs = FileSystems.newFileSystem(artifactURL.toURI(), 
new HashMap<>());) {        
+        Path pathInZip = zipFs.getPath("/resources");
+        return Files.isDirectory(pathInZip);
+      }
+      catch (URISyntaxException | IOException e) {
+        return false;
+      }
+    }    
+    
+    public URL getArtifactURL() throws Exception {
+      if (artifactURL == null) {
+        getCreoleXML();
+      }
+      
+      return artifactURL;
+    }
+
+    @Override
+    public Document getCreoleXML() throws Exception {
+      Artifact artifactObj =
+              new DefaultArtifact(group, artifact, "jar", version);
+
+      Dependency dependency = new Dependency(artifactObj, "runtime");
+
+      List<RemoteRepository> repos = getRepositoryList();
+      
+      ArtifactRequest artifactRequest = new ArtifactRequest(artifactObj, 
repos, null);
+            
+      RepositorySystem repoSystem = getRepositorySystem();
+      RepositorySystemSession repoSession = getRepositorySession(repoSystem, 
workspace);     
+      
+
+      ArtifactResult artifactResult =
+          repoSystem.resolveArtifact(repoSession,
+                      artifactRequest);
+      
+      //baseURL = new URI("creole://"+group+";"+artifact+";"+version+"/");
+            
+      artifactURL =
+              new URL("jar:"
+                      + artifactResult.getArtifact().getFile().toURI().toURL()
+                      + "!/");
+      
+      baseURL = artifactURL.toURI();
+
+      // check it has a creole.xml at the root
+      URL directoryXmlFileUrl = new URL(artifactURL, "creole.xml");
+
+      InputStream creoleStream = null;
+
+      try {
+        creoleStream = directoryXmlFileUrl.openStream();
+      } catch(IOException ioe) {
+        throw new IOException(getBaseURL().toExternalForm()
+                + " does not exist so this artifact is not a GATE plugin");
+      }
+
+      CollectRequest collectRequest = new CollectRequest(dependency,repos);
+      
+      DependencyNode node =
+              repoSystem.collectDependencies(repoSession,
+                      collectRequest).getRoot();
+
+      DependencyRequest dependencyRequest = new DependencyRequest();
+      dependencyRequest.setRoot(node);
+      
+      DependencyResult result =
+              repoSystem.resolveDependencies(repoSession,
+                      dependencyRequest);
+
+      // get the creole.xml out of the jar and add jar elements for this
+      // jar (marked for scanning) and the dependencies
+      SAXBuilder builder = new SAXBuilder(false);
+      Document jdomDoc =
+              builder.build(creoleStream, getBaseURL().toExternalForm());
+
+      Element creoleRoot = jdomDoc.getRootElement();
+
+      for(ArtifactResult ar : result.getArtifactResults()) {        
+        
+        Element jarElement = new Element("JAR");
+        jarElement.setText(ar.getArtifact().getFile().toURI().toURL()
+                .toExternalForm());
+
+        if(ar.getArtifact().equals(artifactResult.getArtifact())) {
+          jarElement.setAttribute("SCAN", "true");
+        }
+
+        creoleRoot.addContent(jarElement);
+      }
+      
+      artifactObj =
+          new SubArtifact(artifactObj,"", "pom");
+      
+      artifactRequest.setArtifact(artifactObj);
+      artifactResult =
+          repoSystem.resolveArtifact(repoSession,
+                  artifactRequest);
+      
+      ModelBuildingRequest req = new DefaultModelBuildingRequest(); 
+      req.setProcessPlugins(false); 
+      req.setPomFile(artifactResult.getArtifact().getFile()); 
+      req.setModelResolver(new SimpleModelResolver(repoSystem,  
+              repoSession, new ArrayList<RemoteRepository>())); 
+      req.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL); 
+       
+      ModelBuilder modelBuilder = new 
DefaultModelBuilderFactory().newInstance(); 
+      Model model = modelBuilder.build(req).getEffectiveModel(); 
+      
+      
+      if (model.getName() != null && !model.getName().trim().equals("")) name 
= model.getName();
+      
+      /*System.out.println(model.getOrganization().getName());
+      for (org.apache.maven.model.Repository r : model.getRepositories()) {
+        System.out.println(r.getName());
+      }
+      for (License l : model.getLicenses()) {
+        System.out.println(l.getName());
+      }*/
+      
+      return jdomDoc;
+    }
+
+    @Override
+    public String getName() {
+      return name;
+    }
+  }
+  
+  /**
+   * ClassVisitor that uses information from a CreoleResource annotation on the
+   * visited class (if such exists) to fill in the name and comment in the
+   * corresponding ResourceInfo.
+   */
+  protected static class ResourceInfoVisitor extends EmptyVisitor {
+    private ResourceInfo resInfo;
+
+    private boolean foundCreoleResource = false;
+
+    private boolean isAbstract = false;
+
+    public ResourceInfoVisitor(ResourceInfo resInfo) {
+      this.resInfo = resInfo;
+    }
+
+    public boolean isCreoleResource() {
+      return foundCreoleResource && !isAbstract;
+    }
+
+    /**
+     * Type descriptor for the CreoleResource annotation type.
+     */
+    private static final String CREOLE_RESOURCE_DESC =
+            Type.getDescriptor(CreoleResource.class);
+
+    /**
+     * Visit the class header, checking whether this is an abstract class or
+     * interface and setting the isAbstract flag appropriately.
+     */
+    @Override
+    public void visit(int version, int access, String name, String signature,
+            String superName, String[] interfaces) {
+      isAbstract = ((access &
+            (Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)) != 0);
+    }
+
+    /**
+     * Visit an annotation on the class.
+     */
+    @Override
+    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+      // we've found a CreoleResource annotation on this class
+      if(desc.equals(CREOLE_RESOURCE_DESC)) {
+        foundCreoleResource = true;
+        return new AnnotationVisitor(Opcodes.ASM5) {
+          @Override
+          public void visit(String name, Object value) {
+            if(name.equals("name") && resInfo.getResourceName() == null) {
+              resInfo.setResourceName((String)value);
+            }
+            else if(name.equals("comment") && resInfo.getResourceComment() == 
null) {
+              resInfo.setResourceComment((String)value);
+            }
+          }
+
+          @Override
+          public AnnotationVisitor visitAnnotation(String name,
+                    String desc) {
+            // don't want to recurse into AutoInstance annotations
+            return this;
+          }
+        };
+      }
+      else {
+        return super.visitAnnotation(desc, visible);
+      }
+    }
+  }
+  
+  public static class Component extends Plugin {
+
+    private Class<? extends Resource> resourceClass;
+    
+    public Component(Class<? extends Resource> resourceClass) throws 
MalformedURLException {
+      this.resourceClass = resourceClass;
+      try {
+        baseURL = (new 
URL(resourceClass.getResource("/gate/creole/CreoleRegisterImpl.class"), 
".")).toURI();
+      } catch(URISyntaxException e) {
+        //this should never happen
+        throw new RuntimeException(e);
+      }
+    }
+    
+    @Override
+    public Document getCreoleXML() throws Exception, JDOMException {
+      Document doc = new Document();
+      Element element;
+      doc.addContent(element = new Element("CREOLE-DIRECTORY"));
+      element.addContent(element = new Element("CREOLE"));
+      element.addContent(element = new Element("RESOURCE"));
+      Element classElement  = new Element("CLASS");
+      classElement.setText(resourceClass.getName());
+      element.addContent(classElement);
+      
+      return doc;
+    }
+
+    @Override
+    public String getName() {
+      return resourceClass.getName();
+    }
+    
+  }
+  
+  public static void main(String args[]) throws Exception {
+    Gate.runInSandbox(true);
+    Gate.init();
+     
+    Plugin annieMaven = new Plugin.Maven("uk.ac.gate.plugins", "annie", 
"9.0-SNAPSHOT");
+    
+    Gate.getCreoleRegister().registerPlugin(annieMaven);
+    
+    System.out.println(annieMaven.getName());
+    
+    File r = new File("testResources");
+    System.out.println(annieMaven.hasResources());
+    annieMaven.copyResources(r);
+
+  }
+}

Modified: gate/branches/sawdust2/gate-core/src/main/java/gate/gui/MainFrame.java
===================================================================
--- gate/branches/sawdust2/gate-core/src/main/java/gate/gui/MainFrame.java      
2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/gate-core/src/main/java/gate/gui/MainFrame.java      
2017-01-25 14:20:13 UTC (rev 19985)
@@ -155,13 +155,13 @@
 import gate.GateConstants;
 import gate.LanguageResource;
 import gate.Main;
-import gate.Plugin;
 import gate.ProcessingResource;
 import gate.Resource;
 import gate.VisualResource;
 import gate.creole.ANNIEConstants;
 import gate.creole.ConditionalSerialAnalyserController;
 import gate.creole.PackagedController;
+import gate.creole.Plugin;
 import gate.creole.ResourceData;
 import gate.creole.ResourceInstantiationException;
 import gate.creole.annic.Constants;

Modified: 
gate/branches/sawdust2/gate-core/src/main/java/gate/gui/creole/manager/AvailablePlugins.java
===================================================================
--- 
gate/branches/sawdust2/gate-core/src/main/java/gate/gui/creole/manager/AvailablePlugins.java
        2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/gate-core/src/main/java/gate/gui/creole/manager/AvailablePlugins.java
        2017-01-25 14:20:13 UTC (rev 19985)
@@ -19,8 +19,8 @@
 
 import gate.Gate;
 import gate.Gate.ResourceInfo;
-import gate.Plugin;
 import gate.creole.CreoleRegisterImpl;
+import gate.creole.Plugin;
 import gate.gui.MainFrame;
 import gate.resources.img.svg.AddIcon;
 import gate.resources.img.svg.AvailableIcon;

Modified: 
gate/branches/sawdust2/gate-core/src/main/java/gate/gui/creole/manager/PluginUpdateManager.java
===================================================================
--- 
gate/branches/sawdust2/gate-core/src/main/java/gate/gui/creole/manager/PluginUpdateManager.java
     2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/gate-core/src/main/java/gate/gui/creole/manager/PluginUpdateManager.java
     2017-01-25 14:20:13 UTC (rev 19985)
@@ -15,7 +15,7 @@
 package gate.gui.creole.manager;
 
 import gate.Gate;
-import gate.Plugin;
+import gate.creole.Plugin;
 import gate.gui.MainFrame;
 import gate.resources.img.svg.AddIcon;
 import gate.resources.img.svg.AdvancedIcon;

Modified: 
gate/branches/sawdust2/gate-core/src/main/java/gate/util/GateClassLoader.java
===================================================================
--- 
gate/branches/sawdust2/gate-core/src/main/java/gate/util/GateClassLoader.java   
    2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/gate-core/src/main/java/gate/util/GateClassLoader.java   
    2017-01-25 14:20:13 UTC (rev 19985)
@@ -39,9 +39,9 @@
 
 import gate.Gate;
 import gate.Gate.ResourceInfo;
-import gate.Plugin;
 import gate.Resource;
 import gate.creole.AbstractResource;
+import gate.creole.Plugin;
 
 /**
  * GATE's class loader, which allows loading of classes over the net. A

Modified: 
gate/branches/sawdust2/gate-core/src/main/java/gate/util/ant/ExpandCreoleXmls.java
===================================================================
--- 
gate/branches/sawdust2/gate-core/src/main/java/gate/util/ant/ExpandCreoleXmls.java
  2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/gate-core/src/main/java/gate/util/ant/ExpandCreoleXmls.java
  2017-01-25 14:20:13 UTC (rev 19985)
@@ -1,8 +1,8 @@
 package gate.util.ant;
 
 import gate.Gate;
-import gate.Plugin;
 import gate.creole.CreoleAnnotationHandler;
+import gate.creole.Plugin;
 import gate.creole.metadata.CreoleResource;
 import gate.util.CreoleXmlUpperCaseFilter;
 import gate.util.GateException;

Modified: 
gate/branches/sawdust2/gate-core/src/main/java/gate/util/persistence/PersistenceManager.java
===================================================================
--- 
gate/branches/sawdust2/gate-core/src/main/java/gate/util/persistence/PersistenceManager.java
        2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/gate-core/src/main/java/gate/util/persistence/PersistenceManager.java
        2017-01-25 14:20:13 UTC (rev 19985)
@@ -70,11 +70,11 @@
 import gate.Gate;
 import gate.LanguageAnalyser;
 import gate.LanguageResource;
-import gate.Plugin;
 import gate.ProcessingResource;
 import gate.VisualResource;
 import gate.creole.ConditionalController;
 import gate.creole.ConditionalSerialAnalyserController;
+import gate.creole.Plugin;
 import gate.creole.ResourceInstantiationException;
 import gate.creole.SerialAnalyserController;
 import gate.event.ProgressListener;

Modified: 
gate/branches/sawdust2/gate-core/src/test/java/gate/config/TestConfig.java
===================================================================
--- gate/branches/sawdust2/gate-core/src/test/java/gate/config/TestConfig.java  
2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/gate-core/src/test/java/gate/config/TestConfig.java  
2017-01-25 14:20:13 UTC (rev 19985)
@@ -26,8 +26,8 @@
 import gate.CreoleRegister;
 import gate.Gate;
 import gate.GateConstants;
-import gate.Plugin;
 import gate.corpora.TestDocument;
+import gate.creole.Plugin;
 import gate.util.Files;
 import gate.util.GateException;
 import gate.util.OptionsMap;

Modified: 
gate/branches/sawdust2/gate-core/src/test/java/gate/creole/DynamicRegistrationTest.java
===================================================================
--- 
gate/branches/sawdust2/gate-core/src/test/java/gate/creole/DynamicRegistrationTest.java
     2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/gate-core/src/test/java/gate/creole/DynamicRegistrationTest.java
     2017-01-25 14:20:13 UTC (rev 19985)
@@ -17,7 +17,6 @@
 import gate.Document;
 import gate.Factory;
 import gate.Gate;
-import gate.Plugin;
 import gate.ProcessingResource;
 import gate.creole.metadata.CreoleResource;
 import junit.framework.TestCase;

Modified: 
gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestCreole.java
===================================================================
--- gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestCreole.java  
2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestCreole.java  
2017-01-25 14:20:13 UTC (rev 19985)
@@ -32,7 +32,6 @@
 import gate.FeatureMap;
 import gate.Gate;
 import gate.LanguageResource;
-import gate.Plugin;
 import gate.ProcessingResource;
 import gate.Resource;
 import gate.corpora.TestDocument;

Modified: 
gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestCreoleAnnotationHandler.java
===================================================================
--- 
gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestCreoleAnnotationHandler.java
 2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestCreoleAnnotationHandler.java
 2017-01-25 14:20:13 UTC (rev 19985)
@@ -31,7 +31,6 @@
 import org.w3c.dom.Node;
 
 import gate.Gate;
-import gate.Plugin;
 import gate.corpora.TestDocument;
 import gate.util.GateException;
 import junit.framework.Test;

Modified: 
gate/branches/sawdust2/gate-maven-plugin/src/main/java/uk/ac/gate/maven/DumpCreoleToXML.java
===================================================================
--- 
gate/branches/sawdust2/gate-maven-plugin/src/main/java/uk/ac/gate/maven/DumpCreoleToXML.java
        2017-01-25 13:51:29 UTC (rev 19984)
+++ 
gate/branches/sawdust2/gate-maven-plugin/src/main/java/uk/ac/gate/maven/DumpCreoleToXML.java
        2017-01-25 14:20:13 UTC (rev 19985)
@@ -38,7 +38,7 @@
 
 import gate.Gate;
 import gate.Gate.ResourceInfo;
-import gate.Plugin;
+import gate.creole.Plugin;
 import gate.creole.CreoleAnnotationHandler;
 import gate.util.GateClassLoader;
 import gate.util.asm.ClassReader;

Modified: gate/branches/sawdust2/notes.txt
===================================================================
--- gate/branches/sawdust2/notes.txt    2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/notes.txt    2017-01-25 14:20:13 UTC (rev 19985)
@@ -41,12 +41,8 @@
 gate.swing.VerticalTextIcon
 gate.swing.WaitDialog
 
-gate.util.Coordinates
-gate.util.CorpusSaver
 gate.util.DocumentProcessor
 gate.util.LanguageAnalyserDocumentProcessor
-gate.util.HtmlLinksExtractor
-gate.util.JarFiles
 gate.util.LaxErrorHandler
 gate.util.TemplateLaxErrorHandler
 gate.util.LuckyException -- replace with RuntimeException
@@ -54,9 +50,7 @@
 gate.util.ObjectWriter
 gate.util.OrderByRestriction
 gate.util.Pair
-gate.util.ProgressPrinter
 gate.util.RawEditorKit
-gate.util.Restriction
 
 to move into plugins
 ====================
@@ -66,7 +60,9 @@
 =========================
 log.error() calls in MainFrame.loadApplicationAction just disappear so I've
 added a printStackTrace as well but it would be nice if we could fix the 
logging
+Plugin.getCreoleXml() doesn't cache the result which could be a real 
performance issue
 
 Things still to do
 ==================
 alignment plugin has metadata in creole.xml not as annotations
+

Modified: gate/branches/sawdust2/pom.xml
===================================================================
--- gate/branches/sawdust2/pom.xml      2017-01-25 13:51:29 UTC (rev 19984)
+++ gate/branches/sawdust2/pom.xml      2017-01-25 14:20:13 UTC (rev 19985)
@@ -1,6 +1,5 @@
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
-       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
        
        <modelVersion>4.0.0</modelVersion>
        <!-- this is the description of this plugin -->
@@ -41,5 +40,6 @@
                <module>Test-Utils</module>
                <module>Plugin_Base</module>
                <module>plugins</module>
-       </modules>
-</project>
+    <module>benchmarking</module>
+  </modules>
+</project>
\ No newline at end of file

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


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
GATE-cvs mailing list
GATE-cvs@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/gate-cvs

Reply via email to