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