[Swift-commit] cog r3750

swift at ci.uchicago.edu swift at ci.uchicago.edu
Mon Jul 29 00:30:03 CDT 2013


------------------------------------------------------------------------
r3750 | hategan | 2013-07-29 00:27:54 -0500 (Mon, 29 Jul 2013) | 1 line

merged r3749 from trunk
------------------------------------------------------------------------
Index: modules/provider-local/src/org/globus/cog/abstraction/impl/execution/local/JobSubmissionTaskHandler.java
===================================================================
--- modules/provider-local/src/org/globus/cog/abstraction/impl/execution/local/JobSubmissionTaskHandler.java	(revision 3749)
+++ modules/provider-local/src/org/globus/cog/abstraction/impl/execution/local/JobSubmissionTaskHandler.java	(working copy)
@@ -13,7 +13,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.EnumSet;
@@ -41,6 +40,7 @@
 import org.globus.cog.abstraction.interfaces.FileLocation;
 import org.globus.cog.abstraction.interfaces.FileResource;
 import org.globus.cog.abstraction.interfaces.JobSpecification;
+import org.globus.cog.abstraction.interfaces.RemoteFile;
 import org.globus.cog.abstraction.interfaces.Service;
 import org.globus.cog.abstraction.interfaces.ServiceContact;
 import org.globus.cog.abstraction.interfaces.Specification;
@@ -341,19 +341,19 @@
 
     private void copy(String src, String dest, File dir, EnumSet<Mode> mode, boolean jobSucceeded) throws Exception {
         src = dropCDMPrefix(src);
-        URI suri = new URI(src);
-        URI duri = new URI(dest);
+        RemoteFile srf = new RemoteFile(src);
+        RemoteFile drf = new RemoteFile(dest);
 
-        String srcScheme = defaultToLocal(suri.getScheme());
-        String dstScheme = defaultToLocal(duri.getScheme());
+        String srcScheme = defaultToLocal(srf.getProtocol());
+        String dstScheme = defaultToLocal(drf.getProtocol());
 
-        Service ss = new ServiceImpl(srcScheme, getServiceContact(suri), null);
-        Service ds = new ServiceImpl(dstScheme, getServiceContact(duri), null);
+        Service ss = new ServiceImpl(srcScheme, getServiceContact(srf), null);
+        Service ds = new ServiceImpl(dstScheme, getServiceContact(drf), null);
         
         FileResource sres = FileResourceCache.getDefault().getResource(ss);
         FileResource dres = FileResourceCache.getDefault().getResource(ds);
                 
-        String srcPath = getPath(suri, dir);
+        String srcPath = getPath(srf, dir);
         
         if (mode.contains(Mode.IF_PRESENT) && !sres.exists(srcPath)) {
             return;
@@ -366,7 +366,7 @@
         }
 
         InputStream is = sres.openInputStream(srcPath);
-        OutputStream os = dres.openOutputStream(getPath(duri, dir));
+        OutputStream os = dres.openOutputStream(getPath(drf, dir));
         byte[] buffer = new byte[BUFFER_SIZE];
 
         int len = is.read(buffer);
@@ -379,22 +379,22 @@
         FileResourceCache.getDefault().releaseResource(dres);
     }
 
-    private String getPath(URI uri, File dir) {
-        if (uri.getScheme() == null && !uri.getPath().startsWith("//")) {
-            return new File(dir, uri.getPath()).getAbsolutePath();
+    private String getPath(RemoteFile rf, File dir) {
+        if (rf.getProtocol() == null && !rf.isAbsolute()) {
+            return new File(dir, rf.getPath()).getAbsolutePath();
         }
         else {
-            return uri.getPath().substring(1);
+            return rf.getPath();
         }
     }
 
-    protected ServiceContact getServiceContact(URI uri) {
+    protected ServiceContact getServiceContact(RemoteFile rf) {
         ServiceContact sc = new ServiceContactImpl();
-        if (uri.getHost() != null) {
-            sc.setHost(uri.getHost());
+        if (rf.getHost() != null) {
+            sc.setHost(rf.getHost());
         }
-        if (uri.getPort() != -1) {
-            sc.setPort(uri.getPort());
+        if (rf.getPort() != -1) {
+            sc.setPort(rf.getPort());
         }
         return sc;
     }
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/CoasterFileRequestHandler.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/CoasterFileRequestHandler.java	(revision 3749)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/CoasterFileRequestHandler.java	(working copy)
@@ -12,6 +12,7 @@
 import java.io.File;
 
 import org.globus.cog.abstraction.impl.execution.coaster.NotificationManager;
+import org.globus.cog.abstraction.interfaces.RemoteFile;
 import org.globus.cog.karajan.workflow.service.ProtocolException;
 import org.globus.cog.karajan.workflow.service.handlers.RequestHandler;
 
@@ -19,14 +20,12 @@
     // private static final String HOME = System.getProperty("user.home");
     private static final String CWD = new File(".").getAbsolutePath();
 
-    public static File normalize(String name) {
-        File f = new File(name);
-
-        if (f.isAbsolute()) {
-            return f;
+    public static File normalize(RemoteFile rf) {
+        if (rf.isAbsolute()) {
+            return new File(rf.getPath());
         }
         else {
-            return new File(CWD, name);
+            return new File(CWD, rf.getPath());
         }
     }
 
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/ProxyIOProvider.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/ProxyIOProvider.java	(revision 3749)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/ProxyIOProvider.java	(working copy)
@@ -11,8 +11,6 @@
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -30,6 +28,7 @@
 import org.globus.cog.abstraction.impl.file.coaster.commands.PutFileCommand;
 import org.globus.cog.abstraction.impl.file.coaster.handlers.GetFileHandler;
 import org.globus.cog.abstraction.impl.file.coaster.handlers.PutFileHandler;
+import org.globus.cog.abstraction.interfaces.RemoteFile;
 import org.globus.cog.karajan.workflow.service.ProtocolException;
 import org.globus.cog.karajan.workflow.service.channels.ChannelException;
 import org.globus.cog.karajan.workflow.service.channels.ChannelManager;
@@ -93,8 +92,8 @@
 
         public void setLength(long len) throws IOException {
             try {
-                URI uri = new URI(dst);
-                cmd = new CustomPutFileCmd(src, "file://localhost/" + uri.getPath().substring(1), len, this);
+                RemoteFile uri = new RemoteFile(dst);
+                cmd = new CustomPutFileCmd(src, "file://localhost/" + uri.getPath(), len, this);
                 channel = ChannelManager.getManager().reserveChannel("id://" + uri.getHost(), null);
                 cmd.executeAsync(channel, this);
                 cb.info(String.valueOf(cmd.getId()));
@@ -264,8 +263,8 @@
             }
             this.cb = cb;
             this.src = src;
-            URI uri = newURI(src);
-            cmd = new CustomGetFileCmd("file://localhost/" + uri.getPath().substring(1), dst, this);
+            RemoteFile uri = newRemoteFile(src);
+            cmd = new CustomGetFileCmd("file://localhost/" + uri.getPath(), dst, this);
             try {
                 channel = ChannelManager.getManager().reserveChannel("id://" + uri.getHost(), null);
             }
@@ -291,12 +290,12 @@
             }
         }
 
-        private URI newURI(String src) throws IOException {
+        private RemoteFile newRemoteFile(String src) throws IOException {
             try {
-                return new URI(src);
+                return new RemoteFile(src);
             }
-            catch (URISyntaxException e) {
-                throw new IOException("Malformed URI: " + e.getMessage());
+            catch (Exception e) {
+                throw new IOException("Invalid file name: " + e.getMessage());
             }
         }
 
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalCopyIOProvider.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalCopyIOProvider.java	(revision 3749)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalCopyIOProvider.java	(working copy)
@@ -15,6 +15,7 @@
 import java.net.URISyntaxException;
 
 import org.apache.log4j.Logger;
+import org.globus.cog.abstraction.interfaces.RemoteFile;
 
 /**
  * Sample indirect provider
@@ -65,10 +66,10 @@
 
         protected static String getPath(String suri) throws IOException {
             try {
-                URI uri = new URI(suri);
-                return uri.getPath().substring(1);
+                RemoteFile rf = new RemoteFile(suri);
+                return rf.getPath();
             }
-            catch (URISyntaxException e) {
+            catch (Exception e) {
                 throw new IOException(e.toString());
             }
         }
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalIOProvider.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalIOProvider.java	(revision 3749)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalIOProvider.java	(working copy)
@@ -27,6 +27,7 @@
 import org.globus.cog.abstraction.impl.file.coaster.buffers.WriteBuffer;
 import org.globus.cog.abstraction.impl.file.coaster.buffers.WriteBufferCallback;
 import org.globus.cog.abstraction.impl.file.coaster.handlers.CoasterFileRequestHandler;
+import org.globus.cog.abstraction.interfaces.RemoteFile;
 
 public class LocalIOProvider implements IOProvider {
     public static final Logger logger = Logger.getLogger(LocalIOProvider.class); 
@@ -49,12 +50,12 @@
         return true;
     }
     
-    private static URI newURI(String src) throws IOException {
+    private static RemoteFile newRemoteFile(String src) throws IOException {
         try {
-            return new URI(src);
+            return new RemoteFile(src);
         }
-        catch (URISyntaxException e) {
-            throw new IOException("Malformed URI: " + e.getMessage());
+        catch (Exception e) {
+            throw new IOException("Invalid name: " + e.getMessage());
         }
     }
 
@@ -68,8 +69,8 @@
 
         public Writer(String dest, WriteIOCallback cb) throws IOException {
             this.cb = cb;
-            URI destURI = newURI(dest);
-            f = CoasterFileRequestHandler.normalize(destURI.getPath().substring(1));
+            RemoteFile destURI = newRemoteFile(dest);
+            f = CoasterFileRequestHandler.normalize(destURI);
         }
         
         public String toString() {
@@ -155,8 +156,8 @@
             if (logger.isDebugEnabled()) {
                 logger.debug("LocalIOProvider.Reader " + src);
             }
-            URI srcURI = newURI(src);
-            f = CoasterFileRequestHandler.normalize(srcURI.getPath().substring(1));
+            RemoteFile srcURI = newRemoteFile(src);
+            f = CoasterFileRequestHandler.normalize(srcURI);
             this.cb = cb;
             fc = new FileInputStream(f).getChannel();
         }
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/SubmitJobCommand.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/SubmitJobCommand.java	(revision 3749)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/SubmitJobCommand.java	(working copy)
@@ -12,8 +12,8 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.nio.charset.Charset;
 import java.util.HashSet;
 import java.util.Set;
@@ -178,16 +178,16 @@
 
     private String absolutize(String file) throws IOException {
         try {            
-            URI u = new URI(file);
-            if (ABSOLUTIZE.contains(u.getScheme())) {
-                return u.getScheme() + "://" + u.getHost() + 
+            URL u = new URL(file);
+            if (ABSOLUTIZE.contains(u.getProtocol())) {
+                return u.getProtocol() + "://" + u.getHost() + 
                     (u.getPort() != -1 ? ":" + u.getPort() : "") + "/" + new File(u.getPath().substring(1)).getAbsolutePath(); 
             }
             else {
                 return file;
             }
         }
-        catch (URISyntaxException e) {
+        catch (MalformedURLException e) {
             throw new IOException("Invalid file specification: " + file);
         }
     }
@@ -235,4 +235,17 @@
     public void setSimple(boolean simple) {
         this.simple = simple;
     }
+    
+    public static void main(String[] args) {
+        try {
+            URL u = new URL("/some path");
+            System.out.println(u.getProtocol());
+            System.out.println(u.getHost());
+            System.out.println(u.getPort());
+            System.out.println(u.getPath());
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
 }
Index: modules/abstraction-common/src/org/globus/cog/abstraction/tools/transfer/FileTransfer.java
===================================================================
--- modules/abstraction-common/src/org/globus/cog/abstraction/tools/transfer/FileTransfer.java	(revision 3749)
+++ modules/abstraction-common/src/org/globus/cog/abstraction/tools/transfer/FileTransfer.java	(working copy)
@@ -6,8 +6,6 @@
 
 package org.globus.cog.abstraction.tools.transfer;
 
-import java.net.URI;
-
 import org.apache.log4j.Logger;
 import org.globus.cog.abstraction.impl.common.AbstractionFactory;
 import org.globus.cog.abstraction.impl.common.StatusEvent;
@@ -21,6 +19,7 @@
 import org.globus.cog.abstraction.impl.common.task.ServiceImpl;
 import org.globus.cog.abstraction.impl.common.task.TaskSubmissionException;
 import org.globus.cog.abstraction.interfaces.FileTransferSpecification;
+import org.globus.cog.abstraction.interfaces.RemoteFile;
 import org.globus.cog.abstraction.interfaces.SecurityContext;
 import org.globus.cog.abstraction.interfaces.Service;
 import org.globus.cog.abstraction.interfaces.ServiceContact;
@@ -39,25 +38,25 @@
     static Logger logger = Logger.getLogger(FileTransfer.class);
 
     private Task task = null;
-    private URI sourceURI = null;
-    private URI destinationURI = null;
+    private RemoteFile sourceURI = null;
+    private RemoteFile destinationURI = null;
     private boolean commandLine = false;
     private boolean thirdparty = false;
 
     public FileTransfer(String name, String sourceURI, String destinationURI)
             throws Exception {
-        this.sourceURI = new URI(sourceURI);
-        this.destinationURI = new URI(destinationURI);
+        this.sourceURI = new RemoteFile(sourceURI);
+        this.destinationURI = new RemoteFile(destinationURI);
         this.task = new FileTransferTask(name);
         logger.debug("Task Identity: " + this.task.getIdentity().toString());
     }
 
     public void setSourceURI(String sourceURI) throws Exception {
-        this.sourceURI = new URI(sourceURI);
+        this.sourceURI = new RemoteFile(sourceURI);
     }
 
     public void setDestinationURI(String destinationURI) throws Exception {
-        this.destinationURI = new URI(destinationURI);
+        this.destinationURI = new RemoteFile(destinationURI);
     }
 
     public String getSourceURI() {
@@ -97,9 +96,9 @@
         sourceServiceContact.setPort(sourceURI.getPort());
         
         SecurityContext sourceSecurityContext = 
-            AbstractionFactory.getSecurityContext(sourceURI.getScheme(), sourceServiceContact);
+            AbstractionFactory.getSecurityContext(sourceURI.getProtocol(), sourceServiceContact);
 
-        Service sourceService = new ServiceImpl(sourceURI.getScheme(),
+        Service sourceService = new ServiceImpl(sourceURI.getProtocol(),
                 Service.FILE_TRANSFER, sourceServiceContact,
                 sourceSecurityContext);
 
@@ -108,10 +107,10 @@
         destinationServiceContact.setPort(destinationURI.getPort());
         
         SecurityContext destinationSecurityContext = 
-            AbstractionFactory.getSecurityContext(destinationURI.getScheme(), destinationServiceContact);
+            AbstractionFactory.getSecurityContext(destinationURI.getProtocol(), destinationServiceContact);
 
         Service destinationService = new ServiceImpl(
-                destinationURI.getScheme(), Service.FILE_TRANSFER,
+                destinationURI.getProtocol(), Service.FILE_TRANSFER,
                 destinationServiceContact, destinationSecurityContext);
 
         // add the source service at index 0
Index: modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/task/FileTransferSpecificationImpl.java
===================================================================
--- modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/task/FileTransferSpecificationImpl.java	(revision 3749)
+++ modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/task/FileTransferSpecificationImpl.java	(working copy)
@@ -54,7 +54,9 @@
 	}
 
 	public void setSourceDirectory(String directory) {
-		this.sourceDirectory = directory.trim();
+	    if (directory != null) {
+	        this.sourceDirectory = directory.trim();
+	    }
 	}
 
 	public String getSourceDirectory() {
Index: modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/util/FileTransfer.java
===================================================================
--- modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/util/FileTransfer.java	(revision 3749)
+++ modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/util/FileTransfer.java	(working copy)
@@ -11,6 +11,7 @@
 import org.globus.cog.abstraction.impl.common.task.ServiceContactImpl;
 import org.globus.cog.abstraction.impl.common.task.ServiceImpl;
 import org.globus.cog.abstraction.impl.common.task.TaskImpl;
+import org.globus.cog.abstraction.interfaces.RemoteFile;
 import org.globus.cog.abstraction.interfaces.SecurityContext;
 import org.globus.cog.abstraction.interfaces.Service;
 import org.globus.cog.abstraction.interfaces.Status;
@@ -71,15 +72,18 @@
 
 		Service sourceService = new ServiceImpl();
 		Service destService = new ServiceImpl();
+		
+		RemoteFile src = new RemoteFile(sourceUri);
+		RemoteFile dst = new RemoteFile(destUri);
 
-		configureService(sourceService, sourceUri, sourceCredentials);
-		configureService(destService, destUri, destCredentials);
+		configureService(sourceService, src, sourceCredentials);
+		configureService(destService, dst, destCredentials);
 
-		spec.setSourceDirectory(getDirectory(sourceUri));
-		spec.setSourceFile(getFile(sourceUri));
+		spec.setSourceDirectory(src.getDirectory());
+		spec.setSourceFile(src.getName());
 
-		spec.setDestinationDirectory(getDirectory(destUri));
-		spec.setDestinationFile(getFile(destUri));
+		spec.setDestinationDirectory(dst.getDirectory());
+		spec.setDestinationFile(dst.getName());
 
 		Task task = getTask(spec, sourceService, destService);
 
@@ -112,10 +116,9 @@
 		return task;
 	}
 
-	void configureService(Service service, String uri, Object credentials) throws Exception {
+	void configureService(Service service, RemoteFile rf, Object credentials) throws Exception {
 		SecurityContext securityContext = null;
-		URI u = new URI(uri);
-		String protocol = u.getScheme();
+		String protocol = rf.getProtocol();
 		if (protocol.equals("file")) {
 			service.setProvider("local");
 		}
@@ -134,22 +137,13 @@
 			securityContext.setCredentials(credentials);
 			service.setSecurityContext(securityContext);
 		}
-		String host = u.getHost();
+		String host = rf.getHost();
 		if (host == null) {
 			host = "localhost";
 		}
 		service.setServiceContact(new ServiceContactImpl(host));
 	}
 
-	String getDirectory(String uri) throws Exception {
-		String parent = (new File((new URI(uri)).getPath().substring(1))).getParent();
-		return (parent == null) ? "" : parent;
-	}
-
-	String getFile(String uri) throws Exception {
-		return (new File((new URI(uri)).getPath().substring(1))).getName();
-	}
-
 	synchronized void setIsComplete(boolean ic) {
 		isComplete = ic;
 		notifyAll();
Index: modules/abstraction-common/src/org/globus/cog/abstraction/interfaces/RemoteFile.java
===================================================================
--- modules/abstraction-common/src/org/globus/cog/abstraction/interfaces/RemoteFile.java	(revision 0)
+++ modules/abstraction-common/src/org/globus/cog/abstraction/interfaces/RemoteFile.java	(revision 3751)
@@ -0,0 +1,323 @@
+//----------------------------------------------------------------------
+//This code is developed as part of the Java CoG Kit project
+//The terms of the license can be found at http://www.cogkit.org/license
+//This message may not be removed or altered.
+//----------------------------------------------------------------------
+
+/*
+ * Created on Jul 27, 2013
+ */
+package org.globus.cog.abstraction.interfaces;
+
+
+/**
+ * Something to fill the gap between a URI and URL. URIs cannot seem to 
+ * allow spaces in the name and URLs cannot be a path-only.
+ * 
+ * The accepted syntax is:
+ * [protocol://host[:port]/]path
+ *
+ */
+public class RemoteFile {
+    private String protocol;
+    private String host;
+    private String dir, name;
+    private int port;
+    
+    public RemoteFile(String protocol, String host, int port, String dir, String name) {
+        this.protocol = protocol;
+        this.host = host;
+        this.port = port;
+        this.dir = dir;
+        this.name = name;
+    }
+    
+    public RemoteFile(String protocol, String host, int port, String path) {
+        this.protocol = protocol;
+        this.host = host;
+        this.port = port;
+        this.parseDirAndName(path, 0);
+    }
+    
+    public RemoteFile(String protocol, String host, String path) {
+        this.protocol = protocol;
+        this.host = host;
+        this.port = -1;
+        this.parseDirAndName(path, 0);
+    }
+    
+    public RemoteFile(String s) {
+        port = -1;
+        parse(s);
+    }
+    
+    protected void parse(String str) {
+        int pp = 0, sp = 0, state = 0;
+        /*
+         * state: 
+         *  0000 - nothing found yet; next is either protocol or path
+         *         scan for:
+         *            "://" -> 1000, protocol = str(pp:sp)
+         *            EOL   -> path = str
+         *  1000 - host[:port] part; scan for:
+         *            ":"   -> 2000, host = str(pp:sp)
+         *            "/"   -> host = str(pp:sp), path = str(sp:)
+         *            EOL   -> error (missing host) 
+         *  2000 - port part; scan for:
+         *            "/"   -> port = str(pp:sp), path = str(sp + 1:)
+         *            EOL   -> error (missing path)
+         *  3000 - STOP
+         */
+        int len = str.length();
+        outer:
+        while (sp < len) {
+            char c = str.charAt(sp);
+            if (c > 255) {
+                throw new IllegalArgumentException("Illegal character '" + c + "' in path at column " + sp + ": '" + str + "'");
+            }
+            int ms = state + c;
+            switch (ms) {
+                case ':':
+                    if (match(str, "//", sp + 1)) {
+                        state = 1000;
+                        protocol = str.substring(pp, sp);
+                        pp = sp + 3;
+                        sp = pp;
+                    }
+                    break;
+                case 1000 + ':':
+                    host = str.substring(pp, sp);
+                    pp = sp + 1;
+                    state = 2000;
+                    break;
+                case 1000 + '/':
+                    port = -1;
+                    host = str.substring(pp, sp);
+                    parseDirAndName(str, sp + 1);
+                    state = 3000;
+                    break outer;
+                case 2000 + '/':
+                    try {
+                        port = Integer.parseInt(str.substring(pp, sp));
+                    }
+                    catch (NumberFormatException e) {
+                        throw new IllegalArgumentException("Invalid port: '" + str.substring(pp, sp) + "'");
+                    }
+                    parseDirAndName(str, sp + 1);
+                    state = 3000;
+                    break outer;
+            }
+            
+            sp++;
+        }
+        // EOL
+        switch (state) {
+            case 0000:
+                protocol = null;
+                host = null;
+                parseDirAndName(str, 0);
+                port = -1;
+                break;
+            case 1000:
+                throw new IllegalArgumentException("Host not found while scanning '" + str + "'");
+            case 2000:
+                throw new IllegalArgumentException("Path not found while scanning '" + str + "'");
+            default:
+                // STOP
+        }
+    }
+    
+    private void parseDirAndName(String str, int pos) {
+        int lastSep = str.lastIndexOf('/');
+        if (lastSep < pos) {
+            dir = null;
+            name = str.substring(pos);
+        }
+        else if (lastSep == pos) {
+            dir = "/";
+            name = str.substring(pos + 1);
+        }
+        else {
+            dir = normalize(str, pos, lastSep);
+            name = str.substring(lastSep + 1);
+        }
+    }
+
+    private boolean match(String str, String sub, int pos) {
+        if (sub.length() + pos > str.length()) {
+            return false;
+        }
+        for (int i = 0; i < sub.length(); i++) {
+            if (str.charAt(pos + i) != sub.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    private String normalize(String path, int start, int end) {
+        // there is a slight performance penalty here, but it makes things
+        // cleaner
+        StringBuilder sb = new StringBuilder();
+        while (start < end) {
+            char c = path.charAt(start);
+            if (c == '/') {
+                if (start + 2 < end && match(path, "./", start + 1)) {
+                    start += 2;
+                }
+                else if (start + 2 == end && path.charAt(start + 1) == '.') {
+                    break;
+                }
+                else if (start + 1 < end && path.charAt(start + 1) == '/') {
+                    start += 1;
+                }
+            }
+            sb.append(c);
+            
+            start++;
+        }
+        return sb.toString();
+    }
+    
+    public String getName() {
+        return name;
+    }
+
+    public String getDirectory() {
+        return dir;
+    }
+    
+    protected void setDirectory(String dir) {
+        this.dir = dir;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+    
+    protected void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public String getHost() {
+        return host;
+    }
+    
+    protected void setHost(String host) {
+        this.host = host;
+    }
+    
+    public int getPort() {
+        return port;
+    }
+
+    public String getPath() {
+        if (dir == null) {
+            return name;
+        }
+        else {
+            return dir + '/' + name;
+        }
+    }
+    
+    public boolean isAbsolute() {
+        return dir != null && dir.startsWith("/");
+    }
+        
+    public String getURIAsString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(protocol);
+        sb.append("://");
+        sb.append(host);
+        if (port != -1) {
+            sb.append(':');
+            sb.append(port);
+        }
+        sb.append('/');
+        if (dir != null) {
+            // special case when the dir is just a slash
+            // (indicating a file in the root dir): there
+            // is no explicit separator
+            if (dir.equals("/")) {
+                sb.append(dir);
+            }
+            else {
+                sb.append(dir);
+                sb.append('/');
+            }
+            sb.append(name);
+        }
+        else {
+            sb.append(name);
+        }
+        return sb.toString();
+    }
+    
+    public String toString() {
+        return getURIAsString();
+    }
+    
+    public String toDebugString() {
+        return "RemoteFile[protocol: '" + protocol + "', host: '" + host + 
+            "', port: " + port + ", dir: " + (dir == null ? "null" : "'" + dir + "'") + ", name: '" + name + "']"; 
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof RemoteFile) {
+            RemoteFile a = (RemoteFile) obj;
+            return name.equals(a.name) && (dir == null ? a.dir == null : dir.equals(a.dir)) && 
+                host.equals(a.host) && port == a.port && protocol.equals(a.protocol);
+        }
+        else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return protocol.hashCode() + host.hashCode() + port + (dir == null ? 0 : dir.hashCode()) + name.hashCode();
+    }
+    
+    public static void main(String[] args) {
+        test("http://ll.com/name", "http://ll.com/name", false);
+        test("http://ll.com:30/name", "http://ll.com:30/name", false);
+        test("http://ll.com:/name", "http://ll.com:/name", true);
+        test("http://www.example.com/dir/name", "http://www.example.com/dir/name", false);
+        test("http://ll.com//name", "http://ll.com//name", false);
+        test("http://ll.com/dir/./name", "http://ll.com/dir/name", false);
+        test("http://ll.com/dir1/./dir2/name", "http://ll.com/dir1/dir2/name", false);
+    }
+
+    private static void test(String s, String e, boolean err) {
+        RemoteFile rf;
+        if (err) {
+            try {
+                rf = new RemoteFile(s);
+                System.err.println("Missing error: " + s + " -> " + rf.toDebugString());
+            }
+            catch (Exception ex) {
+                System.out.println(s);
+                System.out.println("\tError: " + ex.getMessage());
+                return;
+            }
+        }
+        else {
+            try {
+                rf = new RemoteFile(s);
+            }
+            catch (Exception ex) {
+                System.err.println(s);
+                System.err.println("\tError");
+                return;
+            }
+        }
+        if (!rf.toString().equals(e)) {
+            System.out.println("Error: " + e + " -> " + rf.toString() + " -> " + rf.toDebugString());
+        }
+        else {
+            System.out.println(s);
+            System.out.println("\t" + rf.toDebugString());
+        }
+    }
+}



More information about the Swift-commit mailing list