AbstractFakeFileSystem.java revision 38fab1fed5287011ab8fbc41b429c6bbf3b981e0
1334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair/* 2334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Copyright 2008 the original author or authors. 3334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 4334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Licensed under the Apache License, Version 2.0 (the "License"); 5334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * you may not use this file except in compliance with the License. 6334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * You may obtain a copy of the License at 7334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 8334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * http://www.apache.org/licenses/LICENSE-2.0 9334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 10334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Unless required by applicable law or agreed to in writing, software 11334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * distributed under the License is distributed on an "AS IS" BASIS, 12334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * See the License for the specific language governing permissions and 14334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * limitations under the License. 15334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 16334c6ebce811c954bf2a79ba4579589a4a3326bfchrismairpackage org.mockftpserver.fake.filesystem; 17334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 18334c6ebce811c954bf2a79ba4579589a4a3326bfchrismairimport org.apache.log4j.Logger; 19334c6ebce811c954bf2a79ba4579589a4a3326bfchrismairimport org.mockftpserver.core.util.Assert; 20334c6ebce811c954bf2a79ba4579589a4a3326bfchrismairimport org.mockftpserver.core.util.PatternUtil; 21e0bd1bd5786e7df8c65476d76dc2262c3a59f04cchrismairimport org.mockftpserver.core.util.StringUtil; 22334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 235e9566a04364b1cad5c33001a37d4638bc8a93e6chrismairimport java.util.ArrayList; 245e9566a04364b1cad5c33001a37d4638bc8a93e6chrismairimport java.util.Collections; 255e9566a04364b1cad5c33001a37d4638bc8a93e6chrismairimport java.util.Date; 265e9566a04364b1cad5c33001a37d4638bc8a93e6chrismairimport java.util.HashMap; 275e9566a04364b1cad5c33001a37d4638bc8a93e6chrismairimport java.util.Iterator; 285e9566a04364b1cad5c33001a37d4638bc8a93e6chrismairimport java.util.List; 295e9566a04364b1cad5c33001a37d4638bc8a93e6chrismairimport java.util.Map; 30334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 31334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair/** 32334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Abstract superclass for implementation of the FileSystem interface that manage the files 33334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * and directories in memory, simulating a real file system. 34334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * <p/> 35334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * If the <code>createParentDirectoriesAutomatically</code> property is set to <code>true</code>, 36334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * then creating a directory or file will automatically create any parent directories (recursively) 37334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * that do not already exist. If <code>false</code>, then creating a directory or file throws an 38334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * exception if its parent directory does not exist. This value defaults to <code>true</code>. 39334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * <p/> 40334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * The <code>directoryListingFormatter</code> property holds an instance of {@link DirectoryListingFormatter} , 41334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * used by the <code>formatDirectoryListing</code> method to format directory listings in a 42334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * filesystem-specific manner. This property must be initialized by concrete subclasses. 43334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 44334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @author Chris Mair 452a0a3f946dba517a01cc26278f905156857c9c91chrismair * @version $Revision$ - $Date$ 46334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 47334c6ebce811c954bf2a79ba4579589a4a3326bfchrismairpublic abstract class AbstractFakeFileSystem implements FileSystem { 48334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 49334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair private static final Logger LOG = Logger.getLogger(AbstractFakeFileSystem.class); 50334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 51334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 52334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * If <code>true</code>, creating a directory or file will automatically create 53334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * any parent directories (recursively) that do not already exist. If <code>false</code>, 54334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * then creating a directory or file throws an exception if its parent directory 55334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * does not exist. This value defaults to <code>true</code>. 56334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 57334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair private boolean createParentDirectoriesAutomatically = true; 58334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 59334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 60334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * The {@link DirectoryListingFormatter} used by the {@link #formatDirectoryListing(FileSystemEntry)} 61334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * method. This must be initialized by concrete subclasses. 62334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 63334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair private DirectoryListingFormatter directoryListingFormatter; 64334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 65334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair private Map entries = new HashMap(); 66334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 67334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair //------------------------------------------------------------------------- 68334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair // Public API 69334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair //------------------------------------------------------------------------- 70334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 71334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public boolean isCreateParentDirectoriesAutomatically() { 72334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return createParentDirectoriesAutomatically; 73334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 74334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 75334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public void setCreateParentDirectoriesAutomatically(boolean createParentDirectoriesAutomatically) { 76334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair this.createParentDirectoriesAutomatically = createParentDirectoriesAutomatically; 77334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 78334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 79334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public DirectoryListingFormatter getDirectoryListingFormatter() { 80334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return directoryListingFormatter; 81334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 82334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 83334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public void setDirectoryListingFormatter(DirectoryListingFormatter directoryListingFormatter) { 84334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair this.directoryListingFormatter = directoryListingFormatter; 85334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 86334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 87334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 88334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Add each of the entries in the specified List to this filesystem. Note that this does not affect 89334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * entries already existing within this filesystem. 90334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 91334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param entriesToAdd - the List of FileSystemEntry entries to add 92334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 93334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public void setEntries(List entriesToAdd) { 94334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair for (Iterator iter = entriesToAdd.iterator(); iter.hasNext();) { 95334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair FileSystemEntry entry = (FileSystemEntry) iter.next(); 96334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair add(entry); 97334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 98334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 99334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 100334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 101334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Add the specified file system entry (file or directory) to this file system 102334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 103334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param entry - the FileSystemEntry to add 104334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 105334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public void add(FileSystemEntry entry) { 106334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String path = entry.getPath(); 107334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair checkForInvalidFilename(path); 108334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (getEntry(path) != null) { 109334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair throw new FileSystemException(path, "filesystem.pathAlreadyExists"); 110334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 111334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 112334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (!parentDirectoryExists(path)) { 113334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String parent = getParent(path); 114334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (createParentDirectoriesAutomatically) { 115334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair add(new DirectoryEntry(parent)); 116334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } else { 117334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair throw new FileSystemException(parent, "filesystem.parentDirectoryDoesNotExist"); 118334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 119334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 120334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 121334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair // Set lastModified, if not already set 122334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (entry.getLastModified() == null) { 123334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair entry.setLastModified(new Date()); 124334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 125334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 126334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair entries.put(getFileSystemEntryKey(path), entry); 127334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair entry.lockPath(); 128334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 129334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 130334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 131334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Delete the file or directory specified by the path. Return true if the file is successfully 132334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * deleted, false otherwise. If the path refers to a directory, it must be empty. Return false 133334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * if the path does not refer to a valid file or directory or if it is a non-empty directory. 134334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 135334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path of the file or directory to delete 136334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return true if the file or directory is successfully deleted 137334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws org.mockftpserver.core.util.AssertFailedException 138334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * - if path is null 139334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @see org.mockftpserver.fake.filesystem.FileSystem#delete(java.lang.String) 140334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 141334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public boolean delete(String path) { 142334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.notNull(path, "path"); 143334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 144334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (getEntry(path) != null && !hasChildren(path)) { 145334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair removeEntry(path); 146334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return true; 147334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 148334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return false; 149334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 150334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 151334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 152334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return true if there exists a file or directory at the specified path 153334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 154334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 155334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return true if the file/directory exists 156334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws AssertionError - if path is null 157334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @see org.mockftpserver.fake.filesystem.FileSystem#exists(java.lang.String) 158334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 159334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public boolean exists(String path) { 160334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.notNull(path, "path"); 161334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return getEntry(path) != null; 162334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 163334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 164334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 165334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return true if the specified path designates an existing directory, false otherwise 166334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 167334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 168334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return true if path is a directory, false otherwise 169334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws AssertionError - if path is null 170334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @see org.mockftpserver.fake.filesystem.FileSystem#isDirectory(java.lang.String) 171334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 172334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public boolean isDirectory(String path) { 173334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.notNull(path, "path"); 174334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair FileSystemEntry entry = getEntry(path); 175334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return entry != null && entry.isDirectory(); 176334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 177334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 178334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 179334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return true if the specified path designates an existing file, false otherwise 180334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 181334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 182334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return true if path is a file, false otherwise 183334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws AssertionError - if path is null 184334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @see org.mockftpserver.fake.filesystem.FileSystem#isFile(java.lang.String) 185334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 186334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public boolean isFile(String path) { 187334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.notNull(path, "path"); 188334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair FileSystemEntry entry = getEntry(path); 189334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return entry != null && !entry.isDirectory(); 190334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 191334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 192334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 193334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return the List of FileSystemEntry objects for the files in the specified directory or group of 194334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * files. If the path specifies a single file, then return a list with a single FileSystemEntry 195334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * object representing that file. If the path does not refer to an existing directory or 196334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * group of files, then an empty List is returned. 197334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 198334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path specifying a directory or group of files; may contain wildcards (? or *) 199334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the List of FileSystemEntry objects for the specified directory or file; may be empty 200334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @see org.mockftpserver.fake.filesystem.FileSystem#listFiles(java.lang.String) 201334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 202334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public List listFiles(String path) { 203334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (isFile(path)) { 204334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return Collections.singletonList(getEntry(path)); 205334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 206334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 207334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair List entryList = new ArrayList(); 208334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair List children = children(path); 209334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Iterator iter = children.iterator(); 210334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair while (iter.hasNext()) { 211334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String childPath = (String) iter.next(); 212334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair FileSystemEntry fileSystemEntry = getEntry(childPath); 213334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair entryList.add(fileSystemEntry); 214334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 215334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return entryList; 216334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 217334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 218334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 219334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return the List of filenames in the specified directory path or file path. If the path specifies 220334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * a single file, then return that single filename. The returned filenames do not 221334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * include a path. If the path does not refer to a valid directory or file path, then an empty List 222334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * is returned. 223334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 224334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path specifying a directory or group of files; may contain wildcards (? or *) 225334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the List of filenames (not including paths) for all files in the specified directory 226334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * or file path; may be empty 227334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws AssertionError - if path is null 228334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @see org.mockftpserver.fake.filesystem.FileSystem#listNames(java.lang.String) 229334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 230334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public List listNames(String path) { 231334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (isFile(path)) { 232334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return Collections.singletonList(getName(path)); 233334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 234334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 235334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair List filenames = new ArrayList(); 236334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair List children = children(path); 237334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Iterator iter = children.iterator(); 238334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair while (iter.hasNext()) { 239334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String childPath = (String) iter.next(); 240334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair FileSystemEntry fileSystemEntry = getEntry(childPath); 241334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair filenames.add(fileSystemEntry.getName()); 242334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 243334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return filenames; 244334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 245334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 246334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 247334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Rename the file or directory. Specify the FROM path and the TO path. Throw an exception if the FROM path or 248334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * the parent directory of the TO path do not exist; or if the rename fails for another reason. 249334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 250334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param fromPath - the source (old) path + filename 251334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param toPath - the target (new) path + filename 252334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws AssertionError - if fromPath or toPath is null 253334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws FileSystemException - if the rename fails. 254334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 255334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public void rename(String fromPath, String toPath) { 256334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.notNull(toPath, "toPath"); 257334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.notNull(fromPath, "fromPath"); 258334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 259334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair FileSystemEntry entry = getRequiredEntry(fromPath); 260334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 261334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String normalizedFromPath = normalize(fromPath); 262334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String normalizedToPath = normalize(toPath); 263334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 264334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (!entry.isDirectory()) { 265334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair renamePath(entry, normalizedToPath); 266334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return; 267334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 268334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 269334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair // Create the TO directory entry first so that the destination path exists when you 270334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair // move the children. Remove the FROM path after all children have been moved 271334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair add(new DirectoryEntry(normalizedToPath)); 272334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 273334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair List children = descendents(fromPath); 274334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Iterator iter = children.iterator(); 275334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair while (iter.hasNext()) { 276334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String childPath = (String) iter.next(); 277334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair FileSystemEntry child = getRequiredEntry(childPath); 278334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String normalizedChildPath = normalize(child.getPath()); 279334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.isTrue(normalizedChildPath.startsWith(normalizedFromPath), "Starts with FROM path"); 280334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String childToPath = normalizedToPath + normalizedChildPath.substring(normalizedFromPath.length()); 281334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair renamePath(child, childToPath); 282334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 283334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.isTrue(children(normalizedFromPath).isEmpty(), "Must have no children: " + normalizedFromPath); 284334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair removeEntry(normalizedFromPath); 285334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 286334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 287334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 288334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @see java.lang.Object#toString() 289334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 290334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public String toString() { 291334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return this.getClass().getName() + entries; 292334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 293334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 294334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 295334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return the formatted directory listing entry for the file represented by the specified FileSystemEntry 296334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 297334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param fileSystemEntry - the FileSystemEntry representing the file or directory entry to be formatted 298334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the the formatted directory listing entry 299334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 300334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public String formatDirectoryListing(FileSystemEntry fileSystemEntry) { 301334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.notNull(directoryListingFormatter, "directoryListingFormatter"); 302334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.notNull(fileSystemEntry, "fileSystemEntry"); 303334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return directoryListingFormatter.format(fileSystemEntry); 304334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 305334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 306334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 307334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Build a path from the two path components. Concatenate path1 and path2. Insert the path 308334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * separator character in between if necessary (i.e., if both are non-empty and path1 does not already 309334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * end with a separator character AND path2 does not begin with one). 310334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 311334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path1 - the first path component may be null or empty 312334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path2 - the second path component may be null or empty 31338fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair * @return the normalized path resulting from concatenating path1 to path2 314334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 315334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public String path(String path1, String path2) { 316334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair StringBuffer buf = new StringBuffer(); 317334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (path1 != null && path1.length() > 0) { 318334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair buf.append(path1); 319334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 320334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (path2 != null && path2.length() > 0) { 321334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if ((path1 != null && path1.length() > 0) 322334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair && (!isSeparator(path1.charAt(path1.length() - 1))) 323334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair && (!isSeparator(path2.charAt(0)))) { 324334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair buf.append(this.getSeparator()); 325334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 326334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair buf.append(path2); 327334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 32838fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair return normalize(buf.toString()); 329334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 330334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 331334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 332334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return the parent path of the specified path. If <code>path</code> specifies a filename, 333334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * then this method returns the path of the directory containing that file. If <code>path</code> 334334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * specifies a directory, the this method returns its parent directory. If <code>path</code> is 335334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * empty or does not have a parent component, then return an empty string. 336334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * <p/> 337334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * All path separators in the returned path are converted to the system-dependent separator character. 338334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 339334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 340334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the parent of the specified path, or null if <code>path</code> has no parent 341334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws AssertionError - if path is null 342334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 343334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public String getParent(String path) { 344334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair List parts = normalizedComponents(path); 345334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (parts.size() < 2) { 346334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return null; 347334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 348334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair parts.remove(parts.size() - 1); 349334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return componentsToPath(parts); 350334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 351334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 352334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 353334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Returns the name of the file or directory denoted by this abstract 354334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * pathname. This is just the last name in the pathname's name 355334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * sequence. If the pathname's name sequence is empty, then the empty string is returned. 356334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 3575e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair * @param path - the path 358334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return The name of the file or directory denoted by this abstract pathname, or the 359334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * empty string if this pathname's name sequence is empty 360334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 361334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public String getName(String path) { 362334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.notNull(path, "path"); 363334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String normalized = normalize(path); 364334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair int separatorIndex = normalized.lastIndexOf(this.getSeparator()); 365334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return (separatorIndex == -1) ? normalized : normalized.substring(separatorIndex + 1); 366334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 367334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 368334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 369334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Returns the FileSystemEntry object representing the file system entry at the specified path, or null 370334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * if the path does not specify an existing file or directory within this file system. 371334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 372334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path of the file or directory within this file system 373334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the FileSystemEntry containing the information for the file or directory, or else null 374334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @see FileSystem#getEntry(String) 375334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 376334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public FileSystemEntry getEntry(String path) { 377334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return (FileSystemEntry) entries.get(getFileSystemEntryKey(path)); 378334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 379334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 380334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair //------------------------------------------------------------------------- 381334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair // Abstract Methods 382334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair //------------------------------------------------------------------------- 383334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 384334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 3855e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair * @param path - the path 386334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return true if the specified dir/file path name is valid according to the current filesystem. 387334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 388334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected abstract boolean isValidName(String path); 389334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 390334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 391334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the file system-specific file separator as a char 392334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 393334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected abstract char getSeparatorChar(); 394334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 395334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 3965e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair * @param pathComponent - the component (piece) of the path to check 397334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return true if the specified path component is a root for this filesystem 398334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 399334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected abstract boolean isRoot(String pathComponent); 400334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 401334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 402334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return true if the specified char is a separator character for this filesystem 403334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 404334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param c - the character to test 405334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return true if the specified char is a separator character 406334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 407334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected abstract boolean isSeparator(char c); 408334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 409334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair //------------------------------------------------------------------------- 410334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair // Internal Helper Methods 411334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair //------------------------------------------------------------------------- 412334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 413334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 414334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the file system-specific file separator as a String 415334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 416334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected String getSeparator() { 417334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return Character.toString(getSeparatorChar()); 418334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 419334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 420334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 421334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return the normalized and unique key used to access the file system entry 422334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 423334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 424334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the corresponding normalized key 425334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 426334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected String getFileSystemEntryKey(String path) { 427334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return normalize(path); 428334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 429334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 430334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 431334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return the standard, normalized form of the path. 432334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 433334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 434334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the path in a standard, unique, canonical form 435334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws AssertionError - if path is null 436334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 437334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected String normalize(String path) { 438334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return componentsToPath(normalizedComponents(path)); 439334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 440334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 441334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 442334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Throw an InvalidFilenameException if the specified path is not valid. 4435e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair * 4445e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair * @param path - the path 445334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 446334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected void checkForInvalidFilename(String path) { 447334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (!isValidName(path)) { 448334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair throw new InvalidFilenameException(path); 449334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 450334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 451334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 452334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 453334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Rename the file system entry to the specified path name 454334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 455334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param entry - the file system entry 456334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param toPath - the TO path (normalized) 457334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 458334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected void renamePath(FileSystemEntry entry, String toPath) { 459334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String normalizedFrom = normalize(entry.getPath()); 460334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String normalizedTo = normalize(toPath); 461334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair LOG.info("renaming from [" + normalizedFrom + "] to [" + normalizedTo + "]"); 462334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair FileSystemEntry newEntry = entry.cloneWithNewPath(normalizedTo); 463334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair add(newEntry); 464334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair // Do this at the end, in case the addEntry() failed 465334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair removeEntry(normalizedFrom); 466334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 467334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 468334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 469334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return the FileSystemEntry for the specified path. Throw FileSystemException if the 470334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * specified path does not exist. 471334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 472334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 473334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the FileSystemEntry 474334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws FileSystemException - if the specified path does not exist 475334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 476334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected FileSystemEntry getRequiredEntry(String path) { 477334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair FileSystemEntry entry = getEntry(path); 478334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (entry == null) { 479334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair LOG.error("Path does not exist: " + path); 480b698aacfd0744243d4ec776cfd4eb1d43856961cchrismair throw new FileSystemException(normalize(path), "filesystem.doesNotExist"); 481334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 482334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return entry; 483334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 484334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 485334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 486334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return the components of the specified path as a List. The components are normalized, and 487334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * the returned List does not include path separator characters. 4885e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair * 4895e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair * @param path - the path 4905e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair * @return the List of normalized components 491334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 492334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected List normalizedComponents(String path) { 493334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Assert.notNull(path, "path"); 494334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair char otherSeparator = this.getSeparatorChar() == '/' ? '\\' : '/'; 495334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String p = path.replace(otherSeparator, this.getSeparatorChar()); 496334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 497334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair // TODO better way to do this 498334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (p.equals(this.getSeparator())) { 499334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return Collections.singletonList(""); 500334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 501334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair List result = new ArrayList(); 50238fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair if (p.length() > 0) { 50338fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair String[] parts = p.split("\\" + this.getSeparator()); 50438fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair for (int i = 0; i < parts.length; i++) { 50538fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair String part = parts[i]; 50638fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair if (part.equals("..")) { 50738fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair result.remove(result.size() - 1); 50838fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair } else if (!part.equals(".")) { 50938fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair result.add(part); 51038fab1fed5287011ab8fbc41b429c6bbf3b981e0chrismair } 511334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 512334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 513334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return result; 514334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 515334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 516334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 517334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Build a path from the specified list of path components 518334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 519334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param components - the list of path components 520334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the resulting path 521334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 522334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair protected String componentsToPath(List components) { 523334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (components.size() == 1) { 524334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String first = (String) components.get(0); 525334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (first.length() == 0 || isRoot(first)) { 526334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return first + this.getSeparator(); 527334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 528334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 529e0bd1bd5786e7df8c65476d76dc2262c3a59f04cchrismair return StringUtil.join(components, this.getSeparator()); 530334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 531334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 532334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 533334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return true if the specified path designates an absolute file path. 534334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 535334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 536334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return true if path is absolute, false otherwise 537334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @throws AssertionError - if path is null 538334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 539334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair public boolean isAbsolute(String path) { 540334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return isValidName(path); 541334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 542334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 543334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 544334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return true if the specified path exists 545334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 546334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 547334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return true if the path exists 548334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 549334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair private boolean pathExists(String path) { 550334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return getEntry(path) != null; 551334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 552334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 553334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 554334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * If the specified path has a parent, then verify that the parent exists 555334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 556334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 5575e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair * @return true if the parent of the specified path exists 558334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 559334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair private boolean parentDirectoryExists(String path) { 560334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String parent = getParent(path); 5615e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair return parent == null || pathExists(parent); 562334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 563334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 564334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 565334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return true if the specified path represents a directory that contains one or more files or subdirectories 566334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 567334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 568334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return true if the path has child entries 569334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 570334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair private boolean hasChildren(String path) { 571334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (!isDirectory(path)) { 572334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return false; 573334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 574334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String key = getFileSystemEntryKey(path); 575334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Iterator iter = entries.keySet().iterator(); 576334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair while (iter.hasNext()) { 577334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String p = (String) iter.next(); 578334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (p.startsWith(key) && !key.equals(p)) { 579334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return true; 580334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 581334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 582334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return false; 583334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 584334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 585334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 586334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return the List of files or subdirectory paths that are descendents of the specified path 587334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 588334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 589334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the List of the paths for the files and subdirectories that are children, grandchildren, etc. 590334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 591334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair private List descendents(String path) { 592334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (isDirectory(path)) { 593334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String normalizedPath = getFileSystemEntryKey(path); 594334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String separator = (normalizedPath.endsWith(getSeparator())) ? "" : getSeparator(); 595334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String normalizedDirPrefix = normalizedPath + separator; 596334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair List descendents = new ArrayList(); 597334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Iterator iter = entries.keySet().iterator(); 598334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair while (iter.hasNext()) { 599334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String p = (String) iter.next(); 600334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair if (p.startsWith(normalizedDirPrefix) && !normalizedPath.equals(p)) { 601334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair descendents.add(p); 602334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 603334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 604334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return descendents; 605334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 606334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return Collections.EMPTY_LIST; 607334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 608334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 609334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair /** 610334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * Return the List of files or subdirectory paths that are children of the specified path 611334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * 612334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @param path - the path 613334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair * @return the List of the paths for the files and subdirectories that are children 614334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair */ 615334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair private List children(String path) { 616334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String lastComponent = getName(path); 617334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair boolean containsWildcards = PatternUtil.containsWildcards(lastComponent); 618334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String dir = containsWildcards ? getParent(path) : path; 619334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String pattern = containsWildcards ? PatternUtil.convertStringWithWildcardsToRegex(getName(path)) : null; 620334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair LOG.debug("path=" + path + " lastComponent=" + lastComponent + " containsWildcards=" + containsWildcards + " dir=" + dir + " pattern=" + pattern); 621334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 622334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair List descendents = descendents(dir); 623334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair List children = new ArrayList(); 624334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String normalizedDir = normalize(dir); 625334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair Iterator iter = descendents.iterator(); 626334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair while (iter.hasNext()) { 627334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair String descendentPath = (String) iter.next(); 628334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 629334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair boolean patternEmpty = pattern == null || pattern.length() == 0; 6305e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair if (normalizedDir.equals(getParent(descendentPath)) && 6315e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair (patternEmpty || (getName(descendentPath).matches(pattern)))) { 6325e9566a04364b1cad5c33001a37d4638bc8a93e6chrismair children.add(descendentPath); 633334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 634334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 635334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair return children; 636334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 637334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 638334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair private void removeEntry(String path) { 639334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair entries.remove(getFileSystemEntryKey(path)); 640334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair } 641334c6ebce811c954bf2a79ba4579589a4a3326bfchrismair 64247fb67a4e600f339064de4c08f10279accc95e92chrismair}