/** * Aptana Studio * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). * Please see the license.html included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.filesystem.s3; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.filesystem.provider.FileInfo; import org.eclipse.core.filesystem.provider.FileTree; import com.amazon.s3.ListEntry; /** * A more efficient way of accessing/querying the S3 file tree. Since when we query root for it's children we end up * with entire hierarchy below it (not just direct descendants), just store all the sub-tree entries and generate * IFileInfo and IFileStore's from it. * * @author cwilliams */ class S3FileTree extends FileTree { private static final String SEPARATOR = "/"; //$NON-NLS-1$ private List<ListEntry> entries; protected S3FileTree(IFileStore treeRoot, List<ListEntry> entries) { super(treeRoot); this.entries = entries; } @Override public IFileInfo[] getChildInfos(IFileStore store) // NO_UCD { if (!(store instanceof S3FileStore)) { return null; } List<ListEntry> matches = getChildEntries(store); List<IFileInfo> infos = new ArrayList<IFileInfo>(); for (ListEntry match : matches) { FileInfo fileInfo = generateFileInfo(match); // TODO these will always be files. What about "parent directories" that these keys imply? infos.add(fileInfo); } return infos.toArray(new IFileInfo[infos.size()]); } private FileInfo generateFileInfo(ListEntry match) { String name = match.key; int lastSlash = name.lastIndexOf(SEPARATOR); boolean isDirectory = (match instanceof PsuedoDirEntry); if (lastSlash != -1) { if (lastSlash == (name.length() - 1)) { name = name.substring(0, lastSlash); isDirectory = true; lastSlash = name.lastIndexOf(SEPARATOR); if (lastSlash != -1) { name = name.substring(lastSlash + 1); } } else { name = name.substring(lastSlash); if (name.startsWith(SEPARATOR)) { name = name.substring(1); } } } FileInfo fileInfo = new FileInfo(name); fileInfo.setExists(true); fileInfo.setLastModified(match.lastModified.getTime()); fileInfo.setLength(match.size); fileInfo.setDirectory(isDirectory); return fileInfo; } private List<ListEntry> getChildEntries(IFileStore store) { S3FileStore s3Store = (S3FileStore) store; String key = s3Store.getKey(); if (key.startsWith(SEPARATOR)) { key = key.substring(1); } // FIXME This isn't including the subdirs! Set<String> pseudoDirs = new HashSet<String>(); // Find all the entries that have the key as prefix List<ListEntry> matches = new ArrayList<ListEntry>(); for (ListEntry entry : entries) { String relative = entry.key; if (relative.startsWith(SEPARATOR)) { relative = relative.substring(1); } if (!(key.length() == 0 || relative.startsWith(key + SEPARATOR))) { continue; } // Only limit to direct children! relative = relative.substring(key.length()); if (relative.startsWith(SEPARATOR)) { relative = relative.substring(1); } if (relative.endsWith(SEPARATOR)) { relative = relative.substring(0, relative.length() - 1); } if (relative.length() == 0) { continue; } int index = relative.indexOf(SEPARATOR); if (index != -1) { String dirName = relative.substring(0, index); if (!pseudoDirs.contains(dirName)) { ListEntry dirEntry = new PsuedoDirEntry(dirName); pseudoDirs.add(dirEntry.key); matches.add(dirEntry); } } else { matches.add(entry); } } return matches; } private class PsuedoDirEntry extends ListEntry { public PsuedoDirEntry(String dirName) { super(); size = 0; lastModified = new Date(); key = dirName; } } @Override public IFileStore[] getChildStores(IFileStore store) // NO_UCD { if (!(store instanceof S3FileStore)) { return null; } S3FileStore s3Store = (S3FileStore) store; List<ListEntry> matches = getChildEntries(s3Store); List<IFileStore> childrenStores = new ArrayList<IFileStore>(); for (ListEntry match : matches) { String childName = match.key; if (childName.endsWith(SEPARATOR)) { childName = childName.substring(0, childName.length() - 1); } childrenStores.add(s3Store.getChild(childName)); } return childrenStores.toArray(new IFileStore[childrenStores.size()]); } @Override public IFileInfo getFileInfo(IFileStore store) { if (!(store instanceof S3FileStore)) { return null; } S3FileStore s3Store = (S3FileStore) store; String key = s3Store.getKey(); // generate an info from a ListEntry if we have a match! for (ListEntry entry : entries) { String entryKey = entry.key; if (entryKey.startsWith(SEPARATOR)) { entryKey = entryKey.substring(1); } if (entryKey.endsWith(SEPARATOR)) { entryKey = entryKey.substring(0, entryKey.length() - 1); } if (entryKey.equals(key)) { return generateFileInfo(entry); } } return s3Store.fetchInfo(); } }