Revision: 20014 http://sourceforge.net/p/gate/code/20014 Author: markagreenwood Date: 2017-01-30 11:28:58 +0000 (Mon, 30 Jan 2017) Log Message: ----------- ResourceReference params can now be persisted into xgapp files and any that refer to objects by file URL are handled in the same was as saving file: URLs already are so $ etc. works. Note that reading these back doesn't work yet
Modified Paths: -------------- gate/branches/sawdust2/gate-core/src/main/java/gate/creole/ResourceReference.java gate/branches/sawdust2/gate-core/src/main/java/gate/util/persistence/PersistenceManager.java gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestResourceReference.java Modified: gate/branches/sawdust2/gate-core/src/main/java/gate/creole/ResourceReference.java =================================================================== --- gate/branches/sawdust2/gate-core/src/main/java/gate/creole/ResourceReference.java 2017-01-30 02:23:19 UTC (rev 20013) +++ gate/branches/sawdust2/gate-core/src/main/java/gate/creole/ResourceReference.java 2017-01-30 11:28:58 UTC (rev 20014) @@ -16,6 +16,7 @@ import java.io.IOException; import java.io.InputStream; +import java.io.Serializable; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; @@ -24,8 +25,10 @@ import gate.Gate; -public class ResourceReference { +public class ResourceReference implements Serializable { + private static final long serialVersionUID = 2526144106607856721L; + private URI uri; public ResourceReference(URL url) throws URISyntaxException { 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-30 02:23:19 UTC (rev 20013) +++ gate/branches/sawdust2/gate-core/src/main/java/gate/util/persistence/PersistenceManager.java 2017-01-30 11:28:58 UTC (rev 20014) @@ -76,6 +76,7 @@ import gate.creole.ConditionalSerialAnalyserController; import gate.creole.Plugin; import gate.creole.ResourceInstantiationException; +import gate.creole.ResourceReference; import gate.creole.SerialAnalyserController; import gate.event.ProgressListener; import gate.event.StatusListener; @@ -159,7 +160,66 @@ static final long serialVersionUID = -8665414981783519937L; } + + public static class RRPersistence implements Persistence { + + String uriString; + + @Override + public String toString() { + return uriString; + } + @Override + public void extractDataFromSource(Object source) + throws PersistenceException { + + try { + URI uri = null; + + if (source instanceof ResourceReference) { + uri = ((ResourceReference)source).toURI(); + } + + if (uri == null) throw new UnsupportedOperationException("Whatever you are trying to persist isn't a URL"); + + if(uri.getScheme() != null && uri.getScheme().equals("file")) { + // url is what we want to convert to something that is relative to $relpath$, + // $resourceshome$ or $gatehome$ + + // The file in which the URL should get persisted, the directory this file is in + // is the location to which we want to make the URL relative, unless we want to + // use $gatehome$ or $resourceshome$ + File outFile = currentPersistenceFile(); + //File outFileReal = getCanonicalFileIfPossible(outFile); + + File urlFile = new File(uri);//Files.fileFromURL(url); + //File urlFileReal = getCanonicalFileIfPossible(urlFile); + + //logger.debug("Trying to persist "+uri+" for "+outFile); + + uriString = URLHolder.relativize(outFile, urlFile); + + } // if protocol is file + else { + // protocol was not file: + uriString = ((URI)source).toString(); + } + } + catch(ClassCastException | URISyntaxException e) { + throw new PersistenceException(e); + } + } + + @Override + public Object createObject() + throws PersistenceException, ResourceInstantiationException { + // TODO Auto-generated method stub + return null; + } + + } + /** * URLs get upset when serialised and deserialised so we need to * convert them to strings for storage. @@ -198,6 +258,152 @@ * from the original source object. */ static final Logger logger = Logger.getLogger(URLHolder.class); + + public static String relativize(File outFile, File urlFile) throws URISyntaxException { + + File outFileReal = getCanonicalFileIfPossible(outFile); + File urlFileReal = getCanonicalFileIfPossible(urlFile); + // Note: the outDir will be correct if the application file itself is not a link + // If the application file is a link than its parent is the parent of the real + // path. + File outDir = outFile.getParentFile(); + File outDirReal = getCanonicalFileIfPossible(outDir); + File outDirOfReal = getCanonicalFileIfPossible(outFileReal.getParentFile()); + + + logger.debug("urlFile="+urlFile+", urlFileReal"+urlFileReal); + logger.debug("outDir="+outDir+", outDirReal"+outDirReal); + + // by default, use just the relative path + String pathMarker = relativePathMarker; + + // - this returns the canonical path to GATE_HOME + File gateHomePathReal = getGateHomePath(); + + // get the canonical path of the resources home directory, if set, otherwise null + File resourceshomeDirReal = getResourceshomePath(); + + // Only if we actually *want* to consider GATE_HOME and other special directories, + // do all of this ... + // Note: the semantics of this has slightly changed to what it was before: we only + // do this is the use gatehome flag is set, not if it is not set but the warn flag + // is set (previsouly, the warn flag alone was sufficient too). + if(currentUseGateHome()) { + // First of all, check if we want to use GATE_HOME instead: this happens + // if the real location of the url is inside the real location of GATE_HOME + // and the location of the outfile is outside of GATE_HOME + + if (!isContainedWithin(outFileReal, gateHomePathReal) && + isContainedWithin(urlFileReal, gateHomePathReal)) { + logger.debug("Setting path marker to "+gatehomePathMarker); + if(currentWarnAboutGateHome()) { + if(!currentHaveWarnedAboutGateHome().getValue()) { + logger.warn( + "\nYour application is using some of the resources/plugins "+ + "distributed with GATE, and may not work as expected "+ + "with different versions of GATE. You should consider "+ + "making private local copies of the plug-ins, and "+ + "distributing those with your application."); + currentHaveWarnedAboutGateHome().setValue(true); + } + // the actual URL is shown every time + //logger.warn("GATE resource referenced: "+url); + } + if(currentUseGateHome()) { + pathMarker = gatehomePathMarker; + } + } else + // Otherwise, do the same check for the resources home path, but only if it + // is actuallys set + if(resourceshomeDirReal != null && + !isContainedWithin(outFileReal, resourceshomeDirReal) && + isContainedWithin(urlFileReal, resourceshomeDirReal)) { + if(currentWarnAboutGateHome()) { + if(!currentHaveWarnedAboutResourceshome().getValue()) { + logger.warn( + "\nYour application is using resources from your project "+ + "path at "+getResourceshomePath()+". Restoring the application "+ + "will only work if the same project path is set."); + currentHaveWarnedAboutResourceshome().setValue(true); + } + // the actual URL is shown every time + //logger.warn("Resource referenced: "+url); + } + if(currentUseGateHome()) { + pathMarker = resourceshomePathMarker; + } + + } + } + + String relPath = null; + + if(pathMarker.equals(relativePathMarker)) { + // In theory we should just relativize here using the original paths, without + // following any symbolic links. We do not want to follow symbolic links because + // somebody may want to use a symbolic link to a completely different location + // to include some resources into the project directory that contains the + // pipeline (and the link to the resource). + // However, if the project directory itself is within a linked location, then + // GATE will sometimes use the linked and sometimes the non-linked path + // (for some reason it uses the non-linked path in the plugin manager but it uses + // the linked path when the application file is choosen). This means that + // in those cases, there would be a large number of unwanted ../../../../some/dir/to/get/back + // If we solve this by using the canonical paths, it will do the wrong thing for + // links to resources. So we choose to make a compromise: if we can create a relative + // path that does not generate any ../ at the beginning of the relative part, then + // we use that, otherwise we use the real paths + + relPath = getRelativeFilePathString(outDir, urlFile); + logger.debug("First relative path string attempt got "+relPath); + if(relPath.startsWith("../")) { + // if we want to actually use the real path, we have to be careful which is the + // real parent of the out file: if outFile is a symbolic link then it is + // outDirOfReal otherwise it is outDirReal + logger.debug("upslength is "+upsLength(relPath)); + String tmpPath = relPath; + if(java.nio.file.Files.isSymbolicLink(outFile.toPath())) { + tmpPath = getRelativeFilePathString(outDirOfReal, urlFileReal); + logger.debug("trying outDirOfReal "+tmpPath); + logger.debug("upslength is "+upsLength(tmpPath)); + } else { + tmpPath = getRelativeFilePathString(outDirReal, urlFileReal); + logger.debug("trying outDirReal "+tmpPath); + logger.debug("upslength is "+upsLength(tmpPath)); + } + if(upsLength(tmpPath) < upsLength(relPath)) { + relPath = tmpPath; + } + logger.debug("Using tmpPath "+relPath); + } + // if we still get something that starts with ../ then our only remaining option is + // to find if a parent + } else if(pathMarker.equals(gatehomePathMarker)) { + relPath = getRelativeFilePathString(gateHomePathReal, urlFileReal); + } else if(pathMarker.equals(resourceshomePathMarker)) { + relPath = getRelativeFilePathString(resourceshomeDirReal, urlFileReal); + } else { + // this should really never happen! + throw new GateRuntimeException("Unexpected error when persisting URL "+urlFile); + } + + Path rel = Paths.get(relPath); + String uriPath = ""; + boolean first = true; + for(Path component : rel) { + if(!first) uriPath += "/"; + uriPath += component.toString(); + first = false; + } + if(urlFile.isDirectory()) { + // trailing slash + uriPath += "/"; + } + // construct the final properly encoded relative URI + URI finalRelUri = new URI(null, null, uriPath, null); + return pathMarker + finalRelUri.getRawPath(); + } + @Override public void extractDataFromSource(Object source) throws PersistenceException { @@ -221,149 +427,15 @@ // is the location to which we want to make the URL relative, unless we want to // use $gatehome$ or $resourceshome$ File outFile = currentPersistenceFile(); - File outFileReal = getCanonicalFileIfPossible(outFile); - // Note: the outDir will be correct if the application file itself is not a link - // If the application file is a link than its parent is the parent of the real - // path. - File outDir = outFile.getParentFile(); - File outDirReal = getCanonicalFileIfPossible(outDir); - File outDirOfReal = getCanonicalFileIfPossible(outFileReal.getParentFile()); + //File outFileReal = getCanonicalFileIfPossible(outFile); File urlFile = Files.fileFromURL(url); - File urlFileReal = getCanonicalFileIfPossible(urlFile); + //File urlFileReal = getCanonicalFileIfPossible(urlFile); logger.debug("Trying to persist "+url+" for "+outFile); - logger.debug("urlFile="+urlFile+", urlFileReal"+urlFileReal); - logger.debug("outDir="+outDir+", outDirReal"+outDirReal); - // by default, use just the relative path - String pathMarker = relativePathMarker; + urlString = relativize(outFile, urlFile); - // - this returns the canonical path to GATE_HOME - File gateHomePathReal = getGateHomePath(); - - // get the canonical path of the resources home directory, if set, otherwise null - File resourceshomeDirReal = getResourceshomePath(); - - // Only if we actually *want* to consider GATE_HOME and other special directories, - // do all of this ... - // Note: the semantics of this has slightly changed to what it was before: we only - // do this is the use gatehome flag is set, not if it is not set but the warn flag - // is set (previsouly, the warn flag alone was sufficient too). - if(currentUseGateHome()) { - // First of all, check if we want to use GATE_HOME instead: this happens - // if the real location of the url is inside the real location of GATE_HOME - // and the location of the outfile is outside of GATE_HOME - - if (!isContainedWithin(outFileReal, gateHomePathReal) && - isContainedWithin(urlFileReal, gateHomePathReal)) { - logger.debug("Setting path marker to "+gatehomePathMarker); - if(currentWarnAboutGateHome()) { - if(!currentHaveWarnedAboutGateHome().getValue()) { - logger.warn( - "\nYour application is using some of the resources/plugins "+ - "distributed with GATE, and may not work as expected "+ - "with different versions of GATE. You should consider "+ - "making private local copies of the plug-ins, and "+ - "distributing those with your application."); - currentHaveWarnedAboutGateHome().setValue(true); - } - // the actual URL is shown every time - logger.warn("GATE resource referenced: "+url); - } - if(currentUseGateHome()) { - pathMarker = gatehomePathMarker; - } - } else - // Otherwise, do the same check for the resources home path, but only if it - // is actuallys set - if(resourceshomeDirReal != null && - !isContainedWithin(outFileReal, resourceshomeDirReal) && - isContainedWithin(urlFileReal, resourceshomeDirReal)) { - if(currentWarnAboutGateHome()) { - if(!currentHaveWarnedAboutResourceshome().getValue()) { - logger.warn( - "\nYour application is using resources from your project "+ - "path at "+getResourceshomePath()+". Restoring the application "+ - "will only work if the same project path is set."); - currentHaveWarnedAboutResourceshome().setValue(true); - } - // the actual URL is shown every time - logger.warn("Resource referenced: "+url); - } - if(currentUseGateHome()) { - pathMarker = resourceshomePathMarker; - } - - } - } - - String relPath = null; - - if(pathMarker.equals(relativePathMarker)) { - // In theory we should just relativize here using the original paths, without - // following any symbolic links. We do not want to follow symbolic links because - // somebody may want to use a symbolic link to a completely different location - // to include some resources into the project directory that contains the - // pipeline (and the link to the resource). - // However, if the project directory itself is within a linked location, then - // GATE will sometimes use the linked and sometimes the non-linked path - // (for some reason it uses the non-linked path in the plugin manager but it uses - // the linked path when the application file is choosen). This means that - // in those cases, there would be a large number of unwanted ../../../../some/dir/to/get/back - // If we solve this by using the canonical paths, it will do the wrong thing for - // links to resources. So we choose to make a compromise: if we can create a relative - // path that does not generate any ../ at the beginning of the relative part, then - // we use that, otherwise we use the real paths - - relPath = getRelativeFilePathString(outDir, urlFile); - logger.debug("First relative path string attempt got "+relPath); - if(relPath.startsWith("../")) { - // if we want to actually use the real path, we have to be careful which is the - // real parent of the out file: if outFile is a symbolic link then it is - // outDirOfReal otherwise it is outDirReal - logger.debug("upslength is "+upsLength(relPath)); - String tmpPath = relPath; - if(java.nio.file.Files.isSymbolicLink(outFile.toPath())) { - tmpPath = getRelativeFilePathString(outDirOfReal, urlFileReal); - logger.debug("trying outDirOfReal "+tmpPath); - logger.debug("upslength is "+upsLength(tmpPath)); - } else { - tmpPath = getRelativeFilePathString(outDirReal, urlFileReal); - logger.debug("trying outDirReal "+tmpPath); - logger.debug("upslength is "+upsLength(tmpPath)); - } - if(upsLength(tmpPath) < upsLength(relPath)) { - relPath = tmpPath; - } - logger.debug("Using tmpPath "+relPath); - } - // if we still get something that starts with ../ then our only remaining option is - // to find if a parent - } else if(pathMarker.equals(gatehomePathMarker)) { - relPath = getRelativeFilePathString(gateHomePathReal, urlFileReal); - } else if(pathMarker.equals(resourceshomePathMarker)) { - relPath = getRelativeFilePathString(resourceshomeDirReal, urlFileReal); - } else { - // this should really never happen! - throw new GateRuntimeException("Unexpected error when persisting URL "+url); - } - - Path rel = Paths.get(relPath); - String uriPath = ""; - boolean first = true; - for(Path component : rel) { - if(!first) uriPath += "/"; - uriPath += component.toString(); - first = false; - } - if(urlFile.isDirectory()) { - // trailing slash - uriPath += "/"; - } - // construct the final properly encoded relative URI - URI finalRelUri = new URI(null, null, uriPath, null); - urlString = pathMarker + finalRelUri.getRawPath(); } // if protocol is file else { // protocol was not file: @@ -493,7 +565,7 @@ } - private File getGateHomePath() { + private static File getGateHomePath() { if(gatehomePath != null) { return gatehomePath; } else { @@ -502,7 +574,7 @@ } } - private File getResourceshomePath() { + private static File getResourceshomePath() { if(haveResourceshomePath == null) { String resourceshomeString = System.getProperty(resourceshomePropertyName); if(resourceshomeString == null) { @@ -521,7 +593,7 @@ } - private File getCanonicalFileIfPossible(File file) { + private static File getCanonicalFileIfPossible(File file) { if (file == null) return file; File tmp = file; try { @@ -544,7 +616,7 @@ * @param file the file we want to reference * @return the path appended to dir to get to file */ - private String getRelativeFilePathString(File dir, File file) { + private static String getRelativeFilePathString(File dir, File file) { Path dirPath = dir.toPath(); Path filePath = file.toPath(); try { @@ -561,7 +633,7 @@ return dirPath.relativize(filePath).toString(); } - private int upsLength(String path) { + private static int upsLength(String path) { Matcher m = goUpPattern.matcher(path); if(m.matches()) { return m.group(1).length(); @@ -1421,6 +1493,7 @@ registerPersistentEquivalent(VisualResource.class, SlashDevSlashNull.class); registerPersistentEquivalent(URL.class, URLHolder.class); + registerPersistentEquivalent(ResourceReference.class, RRPersistence.class); //for compatibility reasons we treat Plugins loaded from a directory URL as a URL registerPersistentEquivalent(Plugin.Directory.class, URLHolder.class); Modified: gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestResourceReference.java =================================================================== --- gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestResourceReference.java 2017-01-30 02:23:19 UTC (rev 20013) +++ gate/branches/sawdust2/gate-core/src/test/java/gate/creole/TestResourceReference.java 2017-01-30 11:28:58 UTC (rev 20014) @@ -1,20 +1,25 @@ package gate.creole; +import java.io.File; import java.io.InputStream; import java.net.URI; import java.net.URL; import org.apache.commons.io.IOUtils; +import org.jdom.Content; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; +import org.jdom.input.SAXBuilder; import gate.Factory; +import gate.FeatureMap; import gate.Gate; import gate.Resource; import gate.corpora.TestDocument; import gate.creole.metadata.CreoleParameter; import gate.creole.metadata.CreoleResource; +import gate.util.persistence.PersistenceManager; import junit.framework.TestCase; @SuppressWarnings("serial") @@ -23,7 +28,7 @@ private Plugin creolePlugin; @CreoleResource - public static class TestResource extends AbstractResource { + public static class TestResource extends AbstractProcessingResource { ResourceReference rr = null; @@ -189,7 +194,47 @@ } } - /*public void testPersistence() throws Exception { + public void testPersistence() throws Exception { - }*/ + Resource resource = null; + + File xgappFile = null; + File txtFile = null; + + try { + xgappFile = File.createTempFile("rr-test", ".xgapp"); + xgappFile.createNewFile(); + + txtFile = new File(xgappFile.getParentFile(),"test-file.txt"); + + FeatureMap params = Factory.newFeatureMap(); + params.put("param", new ResourceReference(txtFile.toURI())); + resource = Factory.createResource(TestResource.class.getName(),params); + + PersistenceManager.saveObjectToFile(resource, xgappFile); + + SAXBuilder builder = new SAXBuilder(); + Document doc = builder.build(xgappFile); + + Element entry = doc.getRootElement().getChild("application").getChild("initParams").getChild("localMap").getChild("entry"); + + assertEquals("couldn't find a param entry", "param",entry.getChildText("string")); + + Element value = entry.getChild("gate.util.persistence.PersistenceManager-RRPersistence"); + + assertNotNull("We couldn't find the RRPersistence wrapper",value); + + assertEquals("The URI was not as expected","$relpath$test-file.txt", value.getChildText("uriString")); + + } finally { + if (xgappFile != null) xgappFile.deleteOnExit(); + + if(resource != null) { + Factory.deleteResource(resource); + } + + + } + + } } \ 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