Java tutorial
/* * This file is part of Awake FILE. * Awake file: Easy file upload & download over HTTP with Java. * Copyright (C) 2015, KawanSoft SAS * (http://www.kawansoft.com). All rights reserved. * * Awake FILE is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * Awake FILE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * * Any modifications to this file must keep this entire header * intact. */ package org.kawanfw.file.api.client; import java.io.File; import java.io.FileFilter; import java.io.FilenameFilter; import java.io.IOException; import java.util.logging.Level; import org.apache.commons.lang3.StringUtils; import org.kawanfw.commons.api.client.InvalidLoginException; import org.kawanfw.commons.api.client.RemoteException; import org.kawanfw.commons.util.ClientLogger; import org.kawanfw.commons.util.FrameworkDebug; import org.kawanfw.file.api.server.FileConfigurator; import org.kawanfw.file.api.util.client.CallerFinder; import org.kawanfw.file.api.util.client.RemoteFileUtil; /** * An abstract representation of file and directory pathnames <i>on a remote * host</i>. * <p> * Methods have the same names, signatures and behaviors as {@link java.io.File} * methods: <br> * a {@code RemoteFile} method is a {@code File} method that is executed on the * remote host. * <p> * For the sake of clarity, we have thus kept unchanged the {@code File} Javadoc * of each described method, the few differences are detailed in this header. * <p> * The few differences with {@code java.io.File} are: * <ul> * <li>There is only one constructor that takes as parameter a * {@link RemoteSession} and a {@code pathname}. The {@code pathname} is defined * with a "/" separator on all platforms and must be absolute.</li> * <li>{@code File.compareTo(File)} and {@code File.renameTo(File)} methods * take a {@code RemoteFile} parameter in this class.</li> * <li>{@code File} methods that return {@code File} instance(s) return * {@code RemoteFile} instance(s) in this class.</li> * <li>The {@code File.toURI()} and {@code File.toURL()} methods are meaningless * in this context and are thus not ported.</li> * <li>The static {@code File.listRoots()} and {@code File.createTempFile()} are * not ported.</li> * <li>The Java 7+ {@code File.toPath()} method is not ported as this Awake FILE * version does not support remote {@code Path} objects.</li> * </ul> * <p> * Note that the <i>real</i> pathname used on host for {@code File} method * execution depends on the Awake FILE configuration of * {@link FileConfigurator#getServerRoot()} and * {@link FileConfigurator#useOneRootPerUsername()}. This follow the same * principle of FTP server mechanisms. * <p> * Example: * <p> * If {@code FileConfigurator.getServerRoot()} returns {@code /home/} and * {@code FileConfigurator.useOneRootPerUsername()} returns {@code true} and * client username is {@code "mike"} : <br> * * {@code new RemoteFile(remoteSession, "/myfile.txt").exists()} <br> * will return the result of the execution on remote host of: <br> * * {@code new File("/home/mike/myfile.txt").exists()}. * <p> * See User Documentation for more info. * <p> * When using {@code FilenameFilter} and {@code FileFilter} filters, the filter * implementation must follow these rules: * <ul> * <li>The filter must implement {@code Serializable}.</li> * <li>Thus, the filter class must already exist on the server side.</li> * <li>When using anonymous inner class for {@code FilenameFilter} and * {@code FileFilter}: it must be public static.</li> * </ul> * <p> * Note that <a href="http://commons.apache.org/proper/commons-io/">Apache * Commons IO 2.4</a> are included in this software and the <a href= * "http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/filefilter/package-summary.html" * >org.apache.commons.io.filefilter package</a> contains many built-in classes * to be used directly. See code example below. * <p> * {@code RemoteFile} methods throw following Exceptions that are wrapped by a * {@code RuntimeException}: * <ul> * <li>{@code InvalidLoginException}: the session has been closed by a * {@code RemoteSession.logoff()}.</li> * <li>{@code UnknownHostException}: if host URL (http://www.acme.org) does not * exists or no Internet connection.</li> * <li>{@code ConnectException}: if the Host is correct but the ServerFileManager * Servlet is not reachable (http://www.acme.org/ServerFileManager) and access * failed with a status != OK (200). (If the host is incorrect, or is impossible * to connect to - Tomcat down - the {@code ConnectException} will be the sub * exception {@code HttpHostConnectException}.)</li> * <li>{@code SocketException}: if network failure during transmission.</li> * <li>{@link RemoteException}: an exception has been thrown on the server side.</li> * </ul> * <br> * Note: the user rights are the rights of * the servlet container when accessing remote files. * <h3>Example of RemoteFile usage</h3> * <blockquote> * * <pre> * // Define URL of the path to the ServerFileManager servlet * String url = "https://www.acme.org/ServerFileManager"; * * // The login info for strong authentication on server side * String username = "myUsername"; * char[] password = { 'm', 'y', 'P', 'a', 's', 's', 'w', 'o', 'r', 'd' }; * * // Establish a session with the remote server * RemoteSession remoteSession = new RemoteSession(url, username, password); * * // Create a new RemoteFile that maps a file on remote server * RemoteFile remoteFile = new RemoteFile(remoteSession, "/Koala.jpg"); * * // We can use all the familiar java.io.File methods on our RemoteFile * if (remoteFile.exists()) { * System.out.println(remoteFile.getName() + " length : " * + remoteFile.length()); * System.out.println(remoteFile.getName() + " canWrite: " * + remoteFile.canWrite()); * } * * // List files on our remote root directory * remoteFile = new RemoteFile(remoteSession, "/"); * * RemoteFile[] files = remoteFile.listFiles(); * for (RemoteFile file : files) { * System.out.println("Remote file: " + file); * } * * // List all text files in out root directory * // using an Apache Commons IO 2.4 FileFiter * FileFilter fileFilter = new SuffixFileFilter(".txt"); * * files = remoteFile.listFiles(fileFilter); * for (RemoteFile file : files) { * System.out.println("Remote text file: " + file); * } * * // Etc. * </pre> * * </blockquote> * * @see org.kawanfw.file.api.client.RemoteInputStream * @see org.kawanfw.file.api.client.RemoteOutputStream * * @author Nicolas de Pomereu * @since 3.0 */ public class RemoteFile { private static boolean DEBUG = FrameworkDebug.isSet(RemoteFile.class); private RemoteSession remoteSession = null; private String pathname = null; /** Delegate to execute all methods */ private RemoteFileListExecutor remoteFileExecutor = null; /** * Constructor * * @param remoteSession * the remote session * @param pathname * the pathname on host with "/" as file separator. Must be * absolute. * * @throws InvalidLoginException * if sessions is closed */ public RemoteFile(RemoteSession remoteSession, String pathname) throws InvalidLoginException { if (remoteSession == null) { throw new IllegalArgumentException("remoteSession is null!"); } if (remoteSession.getUsername() == null || remoteSession.getAuthenticationToken() == null) { throw new InvalidLoginException(RemoteSession.REMOTE_SESSION_IS_CLOSED); } if (pathname == null) { throw new IllegalArgumentException("pathname is null!"); } if (!pathname.startsWith("/")) { throw new IllegalArgumentException("pathname must be asbsolute and start with \"/\""); } // Remove last unecessary / if (pathname.length() > 1 && pathname.endsWith("/")) { pathname = StringUtils.substringBeforeLast(pathname, "/"); } debug("pathname: " + pathname); this.remoteSession = remoteSession; this.pathname = pathname; this.remoteFileExecutor = new RemoteFileListExecutor(this); } /** * Returns the {@code RemoteSession} of this {@code RemoteFile} * * @return the {@code RemoteSession} of this {@code RemoteFile} */ public RemoteSession getRemoteSession() { return remoteSession; } private void debug(String s) { if (DEBUG) { ClientLogger.getLogger().log(Level.WARNING, s); } } /** * Tests whether the application can execute the file denoted by this * abstract pathname. * * @return <code>true</code> if and only if the abstract pathname exists * <em>and</em> the application is allowed to execute the file * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkExec(java.lang.String)}</code> * method denies execute access to the file */ public boolean canExecute() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "canExecute"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Tests whether the application can read the file denoted by this abstract * pathname. * * @return <code>true</code> if and only if the file specified by this * abstract pathname exists <em>and</em> can be read by the * application; <code>false</code> otherwise * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file */ public boolean canRead() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "canRead"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Tests whether the application can modify the file denoted by this * abstract pathname. * * @return <code>true</code> if and only if the file system actually * contains a file denoted by this abstract pathname <em>and</em> * the application is allowed to write to the file; * <code>false</code> otherwise. * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkWrite(java.lang.String)}</code> * method denies write access to the file */ public boolean canWrite() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "canWrite"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Compares two abstract pathnames lexicographically. The ordering defined * by this method depends upon the underlying system. On UNIX systems, * alphabetic case is significant in comparing pathnames; on Microsoft * Windows systems it is not. * * @param pathname * The abstract pathname to be compared to this abstract pathname * @return Zero if the argument is equal to this abstract pathname, a value * less than zero if this abstract pathname is lexicographically * less than the argument, or a value greater than zero if this * abstract pathname is lexicographically greater than the argument */ public int compareTo(RemoteFile pathname) { try { if (pathname == null) { throw new NullPointerException(); } // TestReload if we have the same RemoteSession parameters (aka same // host and username) if (!this.remoteSession.equals(pathname.getRemoteSession())) { throw new IllegalArgumentException( "Remote files must have identical RemoteSession (url, username) parameters."); } // We will transport a File because server does know what is a // RemoteFile //File file = new File(pathname.toString()); String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "compareTo", pathname); return new Integer(result).intValue(); } catch (SecurityException e) { throw e; } catch (NullPointerException e) { throw e; } catch (IllegalArgumentException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Atomically creates a new, empty file named by this abstract pathname if * and only if a file with this name does not yet exist. The check for the * existence of the file and the creation of the file if it does not exist * are a single operation that is atomic with respect to all other * filesystem activities that might affect the file. * <P> * Note: this method should <i>not</i> be used for file-locking, as the * resulting protocol cannot be made to work reliably. The * {@link java.nio.channels.FileLock FileLock} facility should be used * instead. * * @return <code>true</code> if the named file does not exist and was * successfully created; <code>false</code> if the named file * already exists * @throws IOException * If an I/O error occurred * @throws SecurityException * If a security manager exists and its <code> * {@link java.lang.SecurityManager#checkWrite(java.lang.String)} * </code> method denies write access to the file */ public boolean createNewFile() throws IOException { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "createNewFile"); return new Boolean(result).booleanValue(); } catch (RemoteException remoteexception) { Throwable cause = remoteexception.getCause(); if (cause != null && cause instanceof IOException) { throw new IOException(remoteexception.getMessage()); } else { throw remoteexception; } } catch (IOException e) { throw e; } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Deletes the file or directory denoted by this abstract pathname. If this * pathname denotes a directory, then the directory must be empty in order * to be deleted. * * @return <code>true</code> if and only if the file or directory is * successfully deleted; <code>false</code> otherwise * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkDelete}</code> * method denies delete access to the file */ public boolean delete() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "delete"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Requests that the file or directory denoted by this abstract pathname be * deleted when the virtual machine terminates. Files (or directories) are * deleted in the reverse order that they are registered. Invoking this * method to delete a file or directory that is already registered for * deletion has no effect. Deletion will be attempted only for normal * termination of the virtual machine, as defined by the Java Language * Specification. * * <p> * Once deletion has been requested, it is not possible to cancel the * request. This method should therefore be used with care. * * <P> * Note: this method should <i>not</i> be used for file-locking, as the * resulting protocol cannot be made to work reliably. The * {@link java.nio.channels.FileLock FileLock} facility should be used * instead. * * @throws SecurityException * If a security manager exists and its <code> * {@link java.lang.SecurityManager#checkDelete}</code> method * denies delete access to the file */ public void deleteOnExit() { try { remoteFileExecutor.fileMethodOneReturn(this.pathname, "deleteOnExit"); return; } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Tests this abstract pathname for equality with the given object. Returns * <code>true</code> if and only if the argument is not <code>null</code> * and is an abstract pathname that denotes the same file or directory as * this abstract pathname. Whether or not two abstract pathnames are equal * depends upon the underlying system. On UNIX systems, alphabetic case is * significant in comparing pathnames; on Microsoft Windows systems it is * not. * * @param obj * The object to be compared with this abstract pathname * @return <code>true</code> if and only if the objects are the same; * <code>false</code> otherwise */ public boolean equals(Object obj) { try { if (obj == null) { return false; } String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "equals", obj); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Tests whether the file or directory denoted by this abstract pathname * exists. * * @return <code>true</code> if and only if the file or directory denoted by * this abstract pathname exists; <code>false</code> otherwise * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file or directory */ public boolean exists() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "exists"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the absolute form of this abstract pathname. Equivalent to * <code>new File(this.{@link #getAbsolutePath})</code>. * * @return The absolute abstract pathname denoting the same file or * directory as this abstract pathname * @throws SecurityException * If a required system property value cannot be accessed. */ public RemoteFile getAbsoluteFile() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "getAbsoluteFile"); return new RemoteFile(remoteSession, result); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the absolute pathname string of this abstract pathname. * * <p> * If this abstract pathname is already absolute, then the pathname string * is simply returned as if by the <code>{@link #getPath}</code> method. If * this abstract pathname is the empty abstract pathname then the pathname * string of the current user directory, which is named by the system * property <code>user.dir</code>, is returned. Otherwise this pathname is * resolved in a system-dependent way. On UNIX systems, a relative pathname * is made absolute by resolving it against the current user directory. On * Microsoft Windows systems, a relative pathname is made absolute by * resolving it against the current directory of the drive named by the * pathname, if any; if not, it is resolved against the current user * directory. * * @return The absolute pathname string denoting the same file or directory * as this abstract pathname * @throws SecurityException * If a required system property value cannot be accessed. */ public String getAbsolutePath() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "getAbsolutePath"); return result; } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the canonical form of this abstract pathname. Equivalent to * <code>new File(this.{@link #getCanonicalPath})</code>. * * @return The canonical pathname string denoting the same file or directory * as this abstract pathname * @throws IOException * If an I/O error occurs, which is possible because the * construction of the canonical pathname may require filesystem * queries * @throws SecurityException * If a required system property value cannot be accessed, or if * a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead}</code> * method denies read access to the file */ public RemoteFile getCanonicalFile() throws IOException { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "getCanonicalFile"); return new RemoteFile(remoteSession, result); } catch (RemoteException remoteexception) { Throwable cause = remoteexception.getCause(); if (cause != null && cause instanceof IOException) { throw new IOException(remoteexception.getMessage()); } else { throw remoteexception; } } catch (IOException e) { throw e; } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the canonical pathname string of this abstract pathname. * * <p> * A canonical pathname is both absolute and unique. The precise definition * of canonical form is system-dependent. This method first converts this * pathname to absolute form if necessary, as if by invoking the * {@link #getAbsolutePath} method, and then maps it to its unique form in a * system-dependent way. This typically involves removing redundant names * such as <tt>"."</tt> and <tt>".."</tt> from the pathname, resolving * symbolic links (on UNIX platforms), and converting drive letters to a * standard case (on Microsoft Windows platforms). * * <p> * Every pathname that denotes an existing file or directory has a unique * canonical form. Every pathname that denotes a nonexistent file or * directory also has a unique canonical form. The canonical form of the * pathname of a nonexistent file or directory may be different from the * canonical form of the same pathname after the file or directory is * created. Similarly, the canonical form of the pathname of an existing * file or directory may be different from the canonical form of the same * pathname after the file or directory is deleted. * * @return The canonical pathname string denoting the same file or directory * as this abstract pathname * @throws IOException * If an I/O error occurs, which is possible because the * construction of the canonical pathname may require filesystem * queries * @throws SecurityException * If a required system property value cannot be accessed, or if * a security manager exists and its <code> * {@link java.lang.SecurityManager#checkRead}</code> method * denies read access to the file */ public String getCanonicalPath() throws IOException { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "getCanonicalPath"); return result; } catch (RemoteException remoteexception) { Throwable cause = remoteexception.getCause(); if (cause != null && cause instanceof IOException) { throw new IOException(remoteexception.getMessage()); } else { throw remoteexception; } } catch (IOException e) { throw e; } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the number of unallocated bytes in the partition <a * href="#partName">named</a> by this abstract path name. * * <p> * The returned number of unallocated bytes is a hint, but not a guarantee, * that it is possible to use most or any of these bytes. The number of * unallocated bytes is most likely to be accurate immediately after this * call. It is likely to be made inaccurate by any external I/O operations * including those made on the system outside of this virtual machine. This * method makes no guarantee that write operations to this file system will * succeed. * * @return The number of unallocated bytes on the partition <tt>0L</tt> if * the abstract pathname does not name a partition. This value will * be less than or equal to the total file system size returned by * {@link #getTotalSpace}. * @throws SecurityException * If a security manager has been installed and it denies * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt> * or its {@link SecurityManager#checkRead(String)} method * denies read access to the file named by this abstract * pathname */ public long getFreeSpace() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "getFreeSpace"); return new Long(result).longValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the name of the file or directory denoted by this abstract * pathname. This is just the last name in the pathname's name sequence. If * the pathname's name sequence is empty, then the empty string is returned. * * @return The name of the file or directory denoted by this abstract * pathname, or the empty string if this pathname's name sequence is * empty */ public String getName() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "getName"); return result; } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the pathname string of this abstract pathname's parent, or * <code>null</code> if this pathname does not name a parent directory. * * <p> * The <em>parent</em> of an abstract pathname consists of the pathname's * prefix, if any, and each name in the pathname's name sequence except for * the last. If the name sequence is empty then the pathname does not name a * parent directory. * * @return The pathname string of the parent directory named by this * abstract pathname, or <code>null</code> if this pathname does not * name a parent */ public String getParent() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "getParent"); return result; } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the abstract pathname of this abstract pathname's parent, or * <code>null</code> if this pathname does not name a parent directory. * * <p> * The <em>parent</em> of an abstract pathname consists of the pathname's * prefix, if any, and each name in the pathname's name sequence except for * the last. If the name sequence is empty then the pathname does not name a * parent directory. * * @return The abstract pathname of the parent directory named by this * abstract pathname, or <code>null</code> if this pathname does not * name a parent */ public RemoteFile getParentFile() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "getParentFile"); if (result == null) { return null; } else { return new RemoteFile(remoteSession, result); } } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Converts this abstract pathname into a pathname string. The resulting * string uses the {@link File#separator default name-separator character} to * separate the names in the name sequence. * * @return The string form of this abstract pathname */ public String getPath() { return pathname; } /** * Returns the size of the partition <a href="#partName">named</a> by this * abstract pathname. * * @return The size, in bytes, of the partition or <tt>0L</tt> if this * abstract pathname does not name a partition * @throws SecurityException * If a security manager has been installed and it denies * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt> * or its {@link SecurityManager#checkRead(String)} method * denies read access to the file named by this abstract * pathname */ public long getTotalSpace() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "getTotalSpace"); return new Long(result).longValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the number of bytes available to this virtual machine on the * partition <a href="#partName">named</a> by this abstract pathname. When * possible, this method checks for write permissions and other operating * system restrictions and will therefore usually provide a more accurate * estimate of how much new data can actually be written than * {@link #getFreeSpace}. * * <p> * The returned number of available bytes is a hint, but not a guarantee, * that it is possible to use most or any of these bytes. The number of * unallocated bytes is most likely to be accurate immediately after this * call. It is likely to be made inaccurate by any external I/O operations * including those made on the system outside of this virtual machine. This * method makes no guarantee that write operations to this file system will * succeed. * * @return The number of available bytes on the partition or <tt>0L</tt> if * the abstract pathname does not name a partition. On systems where * this information is not available, this method will be equivalent * to a call to {@link #getFreeSpace}. * @throws SecurityException * If a security manager has been installed and it denies * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt> * or its {@link SecurityManager#checkRead(String)} method * denies read access to the file named by this abstract * pathname */ public long getUsableSpace() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "getUsableSpace"); return new Long(result).longValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Computes a hash code for this abstract pathname. Because equality of * abstract pathnames is inherently system-dependent, so is the computation * of their hash codes. On UNIX systems, the hash code of an abstract * pathname is equal to the exclusive <em>or</em> of the hash code of its * pathname string and the decimal value <code>1234321</code>. On Microsoft * Windows systems, the hash code is equal to the exclusive <em>or</em> of * the hash code of its pathname string converted to lower case and the * decimal value <code>1234321</code>. Locale is not taken into account on * lowercasing the pathname string. * * @return A hash code for this abstract pathname */ public int hashCode() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "hashCode"); return new Integer(result).intValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Tests whether this abstract pathname is absolute. The definition of * absolute pathname is system dependent. On UNIX systems, a pathname is * absolute if its prefix is <code>"/"</code>. On Microsoft Windows systems, * a pathname is absolute if its prefix is a drive specifier followed by * <code>"\\"</code>, or if its prefix is <code>"\\\\"</code>. * * @return <code>true</code> if this abstract pathname is absolute, * <code>false</code> otherwise */ public boolean isAbsolute() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "isAbsolute"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Tests whether the file denoted by this abstract pathname is a directory. * * @return <code>true</code> if and only if the file denoted by this * abstract pathname exists <em>and</em> is a directory; * <code>false</code> otherwise * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file */ public boolean isDirectory() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "isDirectory"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Tests whether the file denoted by this abstract pathname is a normal * file. A file is <em>normal</em> if it is not a directory and, in * addition, satisfies other system-dependent criteria. Any non-directory * file created by a Java application is guaranteed to be a normal file. * * @return <code>true</code> if and only if the file denoted by this * abstract pathname exists <em>and</em> is a normal file; * <code>false</code> otherwise * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file */ public boolean isFile() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "isFile"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Tests whether the file named by this abstract pathname is a hidden file. * The exact definition of <em>hidden</em> is system-dependent. On UNIX * systems, a file is considered to be hidden if its name begins with a * period character (<code>'.'</code>). On Microsoft Windows systems, a file * is considered to be hidden if it has been marked as such in the * filesystem. * * @return <code>true</code> if and only if the file denoted by this * abstract pathname is hidden according to the conventions of the * underlying platform * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file */ public boolean isHidden() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "isHidden"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the time that the file denoted by this abstract pathname was last * modified. * * @return A <code>long</code> value representing the time the file was last * modified, measured in milliseconds since the epoch (00:00:00 GMT, * January 1, 1970), or <code>0L</code> if the file does not exist * or if an I/O error occurs * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file */ public long lastModified() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "lastModified"); return new Long(result).longValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the length of the file denoted by this abstract pathname. The * return value is unspecified if this pathname denotes a directory. * * @return The length, in bytes, of the file denoted by this abstract * pathname, or <code>0L</code> if the file does not exist. Some * operating systems may return <code>0L</code> for pathnames * denoting system-dependent entities such as devices or pipes. * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the file */ public long length() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "length"); return new Long(result).longValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns an array of strings naming the files and directories in the * directory denoted by this abstract pathname. * * <p> * If this abstract pathname does not denote a directory, then this method * returns <code>null</code>. Otherwise an array of strings is returned, one * for each file or directory in the directory. Names denoting the directory * itself and the directory's parent directory are not included in the * result. Each string is a file name rather than a complete path. * * <p> * There is no guarantee that the name strings in the resulting array will * appear in any specific order; they are not, in particular, guaranteed to * appear in alphabetical order. * * @return An array of strings naming the files and directories in the * directory denoted by this abstract pathname. The array will be * empty if the directory is empty. Returns <code>null</code> if * this abstract pathname does not denote a directory, or if an I/O * error occurs. * @throws SecurityException * If a security manager exists and its <code> * {@link java.lang.SecurityManager#checkRead(java.lang.String)} * </code> method denies read access to the directory */ public String[] list() { try { String[] filenames = remoteFileExecutor.list(this.pathname, null, null); return filenames; } catch (SecurityException e) { throw e; } catch (Exception e) { if (e instanceof RemoteException) { Throwable cause = e.getCause(); throw new RuntimeException(cause); } throw new RuntimeException(e); } } /** * Returns an array of strings naming the files and directories in the * directory denoted by this abstract pathname that satisfy the specified * filter. The behavior of this method is the same as that of the * <code>{@link #list()}</code> method, except that the strings in the * returned array must satisfy the filter. If the given <code>filter</code> * is <code>null</code> then all names are accepted. Otherwise, a name * satisfies the filter if and only if the value <code>true</code> results * when the <code>{@link FilenameFilter#accept}</code> method of the filter is invoked on * this abstract pathname and the name of a file or directory in the * directory that it denotes. * * @param filter * A filename filter * @return An array of strings naming the files and directories in the * directory denoted by this abstract pathname that were accepted by * the given <code>filter</code>. The array will be empty if the * directory is empty or if no names were accepted by the filter. * Returns <code>null</code> if this abstract pathname does not * denote a directory, or if an I/O error occurs. * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the directory */ public String[] list(FilenameFilter filter) { String[] filenames = null; try { String callerClassName = CallerFinder.getCallerCallerClassName(); filenames = remoteFileExecutor.list(this.pathname, filter, callerClassName); } catch (SecurityException e) { throw e; } catch (Throwable e) { RemoteFileUtil.decodeTrowableForFilterUsage(e); } return filenames; } /** * Returns an array of abstract pathnames denoting the files in the * directory denoted by this abstract pathname. * * <p> * If this abstract pathname does not denote a directory, then this method * returns <code>null</code>. Otherwise an array of <code>File</code> * objects is returned, one for each file or directory in the directory. * Pathnames denoting the directory itself and the directory's parent * directory are not included in the result. Each resulting abstract * pathname is constructed from this abstract pathname using the * <code>{@link File#File(java.io.File, java.lang.String) File(File, String)}</code> constructor. Therefore if this pathname * is absolute then each resulting pathname is absolute; if this pathname is * relative then each resulting pathname will be relative to the same * directory. * * <p> * There is no guarantee that the name strings in the resulting array will * appear in any specific order; they are not, in particular, guaranteed to * appear in alphabetical order. * * @return An array of abstract pathnames denoting the files and directories * in the directory denoted by this abstract pathname. The array * will be empty if the directory is empty. Returns * <code>null</code> if this abstract pathname does not denote a * directory, or if an I/O error occurs. * @throws SecurityException * If a security manager exists and its <code> * {@link java.lang.SecurityManager#checkRead(java.lang.String)} * </code> method denies read access to the directory */ public RemoteFile[] listFiles() { try { RemoteFile[] remoteFiles = remoteFileExecutor.listFiles(this.pathname, null, null, null); return remoteFiles; } catch (SecurityException e) { throw e; } catch (Exception e) { if (e instanceof RemoteException) { Throwable cause = e.getCause(); throw new RuntimeException(cause); } throw new RuntimeException(e); } } /** * Returns an array of abstract pathnames denoting the files and directories * in the directory denoted by this abstract pathname that satisfy the * specified filter. The behavior of this method is the same as that of the * <code>{@link #listFiles()}</code> method, except that the pathnames in * the returned array must satisfy the filter. If the given * <code>filter</code> is <code>null</code> then all pathnames are accepted. * Otherwise, a pathname satisfies the filter if and only if the value * <code>true</code> results when the * <code>{@link FileFilter#accept(java.io.File)}</code> method of the filter * is invoked on the pathname. * * @param filter * A file filter * @return An array of abstract pathnames denoting the files and directories * in the directory denoted by this abstract pathname. The array * will be empty if the directory is empty. Returns * <code>null</code> if this abstract pathname does not denote a * directory, or if an I/O error occurs. * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the directory */ public RemoteFile[] listFiles(FilenameFilter filter) { RemoteFile[] remoteFiles = null; try { String callerClassName = CallerFinder.getCallerCallerClassName(); remoteFiles = remoteFileExecutor.listFiles(this.pathname, filter, null, callerClassName); } catch (SecurityException e) { throw e; } catch (Throwable e) { RemoteFileUtil.decodeTrowableForFilterUsage(e); } return remoteFiles; } /** * Returns an array of abstract pathnames denoting the files and directories * in the directory denoted by this abstract pathname that satisfy the * specified filter. The behavior of this method is the same as that of the * <code>{@link #listFiles()}</code> method, except that the pathnames in * the returned array must satisfy the filter. If the given * <code>filter</code> is <code>null</code> then all pathnames are accepted. * Otherwise, a pathname satisfies the filter if and only if the value * <code>true</code> results when the * <code>{@link FileFilter#accept(java.io.File)}</code> method of the filter * is invoked on the pathname. * * @param filter * A file filter * @return An array of abstract pathnames denoting the files and directories * in the directory denoted by this abstract pathname. The array * will be empty if the directory is empty. Returns * <code>null</code> if this abstract pathname does not denote a * directory, or if an I/O error occurs. * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method denies read access to the directory */ public RemoteFile[] listFiles(FileFilter filter) { RemoteFile[] remoteFiles = null; try { String callerClassName = CallerFinder.getCallerCallerClassName(); remoteFiles = remoteFileExecutor.listFiles(this.pathname, null, filter, callerClassName); } catch (SecurityException e) { throw e; } catch (Throwable e) { RemoteFileUtil.decodeTrowableForFilterUsage(e); } return remoteFiles; } /** * Creates the directory named by this abstract pathname. * * @return <code>true</code> if and only if the directory was created; * <code>false</code> otherwise * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkWrite(java.lang.String)}</code> * method does not permit the named directory to be created */ public boolean mkdir() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "mkdir"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Creates the directory named by this abstract pathname, including any * necessary but nonexistent parent directories. Note that if this operation * fails it may have succeeded in creating some of the necessary parent * directories. * * @return <code>true</code> if and only if the directory was created, along * with all necessary parent directories; <code>false</code> * otherwise * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkRead(java.lang.String)}</code> * method does not permit verification of the existence of the * named directory and all necessary parent directories; or if * the <code>{@link java.lang.SecurityManager#checkWrite(java.lang.String)}</code> * method does not permit the named directory and all necessary * parent directories to be created */ public boolean mkdirs() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "mkdirs"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Renames the file denoted by this abstract pathname. * * <p> * Many aspects of the behavior of this method are inherently * platform-dependent: The rename operation might not be able to move a file * from one filesystem to another, it might not be atomic, and it might not * succeed if a file with the destination abstract pathname already exists. * The return value should always be checked to make sure that the rename * operation was successful. * * @param dest * The new abstract pathname for the named file * @return <code>true</code> if and only if the renaming succeeded; * <code>false</code> otherwise * @throws SecurityException * If a security manager exists and its <code> * {@link java.lang.SecurityManager#checkWrite(java.lang.String)} * </code> method denies write access to either the old or new * pathnames * @throws NullPointerException * If parameter <code>dest</code> is <code>null</code> */ public boolean renameTo(RemoteFile dest) { try { if (dest == null) { throw new NullPointerException(); } // TestReload if we have the same RemoteSession parameters (aka same // host and username) if (!this.remoteSession.equals(dest.getRemoteSession())) { throw new IllegalArgumentException( "Remote files must have identical RemoteSession (url, username) parameters."); } // We will transport a File because server does know what is a // RemoteFile //File file = new File(dest.toString()); String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "renameTo", dest); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (NullPointerException e) { throw e; } catch (IllegalArgumentException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * A convenience method to set the owner's execute permission for this * abstract pathname. * * <p> * An invocation of this method of the form <tt>file.setExcutable(arg)</tt> * behaves in exactly the same way as the invocation * * <blockquote><pre> * file.setExecutable(arg, true) * </pre></blockquote> * * @param executable * If <code>true</code>, sets the access permission to allow * execute operations; if <code>false</code> to disallow execute * operations * @return <code>true</code> if and only if the operation succeeded. The * operation will fail if the user does not have permission to * change the access permissions of this abstract pathname. If * <code>executable</code> is <code>false</code> and the underlying * file system does not implement an excute permission, then the * operation will fail. * @throws SecurityException * If a security manager exists and its <code> * {@link java.lang.SecurityManager#checkWrite(java.lang.String)} * </code> method denies write access to the file */ public boolean setExecutable(boolean executable) { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "setExecutable", executable); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Sets the owner's or everybody's execute permission for this abstract * pathname. * * @param executable * If <code>true</code>, sets the access permission to allow * execute operations; if <code>false</code> to disallow execute * operations * @param ownerOnly * If <code>true</code>, the execute permission applies only to * the owner's execute permission; otherwise, it applies to * everybody. If the underlying file system can not distinguish * the owner's execute permission from that of others, then the * permission will apply to everybody, regardless of this value. * @return <code>true</code> if and only if the operation succeeded. The * operation will fail if the user does not have permission to * change the access permissions of this abstract pathname. If * <code>executable</code> is <code>false</code> and the underlying * file system does not implement an execute permission, then the * operation will fail. * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkWrite(java.lang.String)}</code> * method denies write access to the file */ public boolean setExecutable(boolean executable, boolean ownerOnly) { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "setExecutable", executable, ownerOnly); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Sets the last-modified time of the file or directory named by this * abstract pathname. * * <p> * All platforms support file-modification times to the nearest second, but * some provide more precision. The argument will be truncated to fit the * supported precision. If the operation succeeds and no intervening * operations on the file take place, then the next invocation of the * <code>{@link #lastModified}</code> method will return the (possibly * truncated) <code>time</code> argument that was passed to this method. * * @param time * The new last-modified time, measured in milliseconds since the * epoch (00:00:00 GMT, January 1, 1970) * @return <code>true</code> if and only if the operation succeeded; * <code>false</code> otherwise * @throws IllegalArgumentException * If the argument is negative * @throws SecurityException * If a security manager exists and its <code> * {@link java.lang.SecurityManager#checkWrite(java.lang.String)} * </code> method denies write access to the named file */ public boolean setLastModified(long time) { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "setLastModified", time); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Marks the file or directory named by this abstract pathname so that only * read operations are allowed. After invoking this method the file or * directory is guaranteed not to change until it is either deleted or * marked to allow write access. Whether or not a read-only file or * directory may be deleted depends upon the underlying system. * * @return <code>true</code> if and only if the operation succeeded; * <code>false</code> otherwise * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkWrite(java.lang.String)}</code> * method denies write access to the named file */ public boolean setReadOnly() { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "setReadOnly"); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * A convenience method to set the owner's read permission for this abstract * pathname. * * <p> * An invocation of this method of the form <tt>file.setReadable(arg)</tt> * behaves in exactly the same way as the invocation * * <blockquote><pre> * file.setReadable(arg, true) * </pre></blockquote> * * @param readable * If <code>true</code>, sets the access permission to allow read * operations; if <code>false</code> to disallow read operations * @return <code>true</code> if and only if the operation succeeded. The * operation will fail if the user does not have permission to * change the access permissions of this abstract pathname. If * <code>readable</code> is <code>false</code> and the underlying * file system does not implement a read permission, then the * operation will fail. * @throws SecurityException * If a security manager exists and its <code> * {@link java.lang.SecurityManager#checkWrite(java.lang.String)} * </code> method denies write access to the file */ public boolean setReadable(boolean readable) { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "setReadable", readable); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Sets the owner's or everybody's read permission for this abstract * pathname. * * @param readable * If <code>true</code>, sets the access permission to allow read * operations; if <code>false</code> to disallow read operations * @param ownerOnly * If <code>true</code>, the read permission applies only to the * owner's read permission; otherwise, it applies to everybody. * If the underlying file system can not distinguish the owner's * read permission from that of others, then the permission will * apply to everybody, regardless of this value. * @return <code>true</code> if and only if the operation succeeded. The * operation will fail if the user does not have permission to * change the access permissions of this abstract pathname. If * <code>readable</code> is <code>false</code> and the underlying * file system does not implement a read permission, then the * operation will fail. * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkWrite(java.lang.String)}</code> * method denies write access to the file */ public boolean setReadable(boolean readable, boolean ownerOnly) { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "setReadable", readable, ownerOnly); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * A convenience method to set the owner's write permission for this * abstract pathname. * * <p> * An invocation of this method of the form <tt>file.setWritable(arg)</tt> * behaves in exactly the same way as the invocation * * <blockquote><pre> * file.setWritable(arg, true) * </pre></blockquote> * * @param writable * If <code>true</code>, sets the access permission to allow * write operations; if <code>false</code> to disallow write * operations * @return <code>true</code> if and only if the operation succeeded. The * operation will fail if the user does not have permission to * change the access permissions of this abstract pathname. * @throws SecurityException * If a security manager exists and its <code> * {@link java.lang.SecurityManager#checkWrite(java.lang.String)} * </code> method denies write access to the file */ public boolean setWritable(boolean writable) { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "setWritable", writable); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Sets the owner's or everybody's write permission for this abstract * pathname. * * @param writable * If <code>true</code>, sets the access permission to allow * write operations; if <code>false</code> to disallow write * operations * @param ownerOnly * If <code>true</code>, the write permission applies only to the * owner's write permission; otherwise, it applies to everybody. * If the underlying file system can not distinguish the owner's * write permission from that of others, then the permission will * apply to everybody, regardless of this value. * @return <code>true</code> if and only if the operation succeeded. The * operation will fail if the user does not have permission to * change the access permissions of this abstract pathname. * @throws SecurityException * If a security manager exists and its <code>{@link java.lang.SecurityManager#checkWrite(java.lang.String)}</code> * method denies write access to the named file */ public boolean setWritable(boolean writable, boolean ownerOnly) { try { String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, "setWritable", writable, ownerOnly); return new Boolean(result).booleanValue(); } catch (SecurityException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns the pathname string of this abstract pathname. This is just the * string returned by the <code>{@link #getPath}</code> method. * * @return The string form of this abstract pathname */ public String toString() { return getPath(); } // /** // * Constructs a <tt>file:</tt> URI that represents this abstract pathname. // * // * <p> // * The exact form of the URI is system-dependent. If it can be determined // * that the file denoted by this abstract pathname is a directory, then // the // * resulting URI will end with a slash. // * // * <p> // * For a given abstract pathname <i>f</i>, it is guaranteed that // * // * <tt> // new {@link #File(java.net.URI) File}(</tt><i> f</i> // * <tt>.toURI()).equals(</tt><i> f</i> // * <tt>.{@link #getAbsoluteFile() getAbsoluteFile}()) // </tt> // * // * so long as the original abstract pathname, the URI, and the new // abstract // * pathname are all created in (possibly different invocations of) the // same // * Java virtual machine. Due to the system-dependent nature of abstract // * pathnames, however, this relationship typically does not hold when a // * <tt>file:</tt> URI that is created in a virtual machine on one // operating // * system is converted into an abstract pathname in a virtual machine on a // * different operating system. // * // * @return An absolute, hierarchical URI with a scheme equal to // * <tt>"file"</tt>, a path representing this abstract pathname, and // * undefined authority, query, and fragment components // * @throws SecurityException // * If a required system property value cannot be accessed. // */ // public URI toURI() { // throw new UnsupportedOperationException(Tag.PRODUCT // + "Method not implemented."); // // try { // // String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, // // "toURI"); // // return new URI(result); // // // // } catch (SecurityException e) { // // throw e; // // } catch (Exception e) { // // throw new RuntimeException(e); // // } // } // // /** // * Converts this abstract pathname into a <code>file:</code> URL. The // exact // * form of the URL is system-dependent. If it can be determined that the // * file denoted by this abstract pathname is a directory, then the // resulting // * URL will end with a slash. // * // * @return A URL object representing the equivalent file URL // * @throws MalformedURLException // * If the path cannot be parsed as a URL // */ // public URL toURL() throws MalformedURLException { // throw new UnsupportedOperationException(Tag.PRODUCT // + "Method not implemented."); // // try { // // String result = remoteFileExecutor.fileMethodOneReturn(this.pathname, // // "toURL"); // // return new URL(result); // // } catch (MalformedURLException malformedurlexception) { // // throw malformedurlexception; // // } catch (SecurityException e) { // // throw e; // // } catch (Exception e) { // // throw new RuntimeException(e); // // } // } }