Java tutorial
package ch.cyberduck.core.local; /* * Copyright (c) 2012 David Kocher. All rights reserved. * http://cyberduck.ch/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Bug fixes, suggestions and comments should be sent to: * dkocher@cyberduck.ch */ import ch.cyberduck.binding.foundation.NSArray; import ch.cyberduck.binding.foundation.NSEnumerator; import ch.cyberduck.binding.foundation.NSFileManager; import ch.cyberduck.binding.foundation.NSObject; import ch.cyberduck.binding.foundation.NSURL; import ch.cyberduck.core.AttributedList; import ch.cyberduck.core.Local; import ch.cyberduck.core.exception.AccessDeniedException; import ch.cyberduck.core.exception.LocalAccessDeniedException; import ch.cyberduck.core.exception.LocalNotfoundException; import ch.cyberduck.core.exception.NotfoundException; import ch.cyberduck.core.io.LocalRepeatableFileInputStream; import ch.cyberduck.core.library.Native; import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.serializer.Serializer; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.input.ProxyInputStream; import org.apache.commons.io.output.ProxyOutputStream; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.rococoa.Foundation; import org.rococoa.ObjCObjectByReference; import org.rococoa.cocoa.foundation.NSError; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class FinderLocal extends Local { private static final Logger log = Logger.getLogger(FinderLocal.class); static { Native.load("core"); } private static final NSFileManager manager = NSFileManager.defaultManager(); private static final FilesystemBookmarkResolver<NSURL> resolver = FilesystemBookmarkResolverFactory.get(); /** * Application scoped bookmark to access outside of sandbox */ private String bookmark; private final FinderLocalAttributes attributes = new FinderLocalAttributes(this); public FinderLocal(final Local parent, final String name) throws LocalAccessDeniedException { super(parent, name); } public FinderLocal(final String parent, final String name) throws LocalAccessDeniedException { super(parent, name); } public FinderLocal(final String path) throws LocalAccessDeniedException { super(resolveAlias(new TildeExpander().expand(path))); } @Override public <T> T serialize(final Serializer dict) { dict.setStringForKey(this.getAbbreviatedPath(), "Path"); // Get or create application scope bookmark final String bookmark = this.getBookmark(); if (StringUtils.isNotBlank(bookmark)) { dict.setStringForKey(bookmark, "Bookmark"); } return dict.getSerialized(); } /** * @return Name of the file as displayed in the Finder. E.g. a ':' is replaced with '/'. */ @Override public String getDisplayName() { return manager.displayNameAtPath(this.getName()); } /** * @return Path relative to the home directory denoted with a tilde. */ @Override public String getAbbreviatedPath() { return new TildeExpander().abbreviate(this.getAbsolute()); } @Override public Local getVolume() { for (Local parent = this.getParent(); !parent.isRoot(); parent = parent.getParent()) { final Local directory = parent.getParent(); if (null == directory) { return super.getVolume(); } if ("/Volumes".equals(directory.getAbsolute())) { return parent; } } return super.getVolume(); } @Override public boolean isSymbolicLink() { return attributes.isSymbolicLink(); } @Override public String getBookmark() { if (StringUtils.isBlank(bookmark)) { try { bookmark = resolver.create(this); } catch (AccessDeniedException e) { log.warn(String.format("Failure resolving bookmark for %s. %s", this, e.getDetail())); } } return bookmark; } @Override public void setBookmark(final String data) { this.bookmark = data; } @Override public OutputStream getOutputStream(boolean append) throws AccessDeniedException { final NSURL resolved; try { resolved = this.lock(false); } catch (LocalAccessDeniedException e) { return super.getOutputStream(append); } try { return new ProxyOutputStream(new FileOutputStream(new File(resolved.path()), append)) { @Override public void close() throws IOException { try { super.close(); } finally { release(resolved); } } }; } catch (FileNotFoundException e) { throw new LocalAccessDeniedException(e.getMessage(), e); } } /** * @param interactive Prompt to resolve bookmark of file outside of sandbox with choose panel */ @Override public NSURL lock(final boolean interactive) throws AccessDeniedException { final NSURL resolved = resolver.resolve(this, interactive); if (resolved.respondsToSelector(Foundation.selector("startAccessingSecurityScopedResource"))) { if (!resolved.startAccessingSecurityScopedResource()) { throw new LocalAccessDeniedException( String.format("Failure accessing security scoped resource for %s", this)); } } return resolved; } @Override public void release(final Object lock) { if (null == lock) { return; } final NSURL resolved = (NSURL) lock; if (resolved.respondsToSelector(Foundation.selector("stopAccessingSecurityScopedResource"))) { resolved.stopAccessingSecurityScopedResource(); } } @Override public InputStream getInputStream() throws AccessDeniedException { final NSURL resolved; try { resolved = this.lock(false); } catch (AccessDeniedException e) { return super.getInputStream(); } try { return new ProxyInputStream(new LocalRepeatableFileInputStream(new File(resolved.path()))) { @Override public void close() throws IOException { try { super.close(); } finally { release(resolved); } } }; } catch (FileNotFoundException e) { throw new LocalAccessDeniedException(e.getMessage(), e); } } @Override public AttributedList<Local> list() throws AccessDeniedException { if (PreferencesFactory.get().getBoolean("local.list.native")) { final AttributedList<Local> children = new AttributedList<Local>(); final ObjCObjectByReference error = new ObjCObjectByReference(); final NSArray files = manager.contentsOfDirectoryAtPath_error(this.getAbsolute(), error); if (null == files) { final NSError f = error.getValueAs(NSError.class); if (null == f) { throw new LocalAccessDeniedException(this.getAbsolute()); } throw new LocalAccessDeniedException(String.format("%s", f.localizedDescription())); } final NSEnumerator i = files.objectEnumerator(); NSObject next; while ((next = i.nextObject()) != null) { children.add(new FinderLocal(this, next.toString())); } return children; } else { return super.list(); } } /** * @param absolute The absolute path of the alias file. * @return The absolute path this alias is pointing to. */ private static native String resolveAlias(String absolute); @Override public FinderLocalAttributes attributes() { return attributes; } @Override public Local getSymlinkTarget() throws NotfoundException, LocalAccessDeniedException { final ObjCObjectByReference error = new ObjCObjectByReference(); final String destination = manager.destinationOfSymbolicLinkAtPath_error(this.getAbsolute(), error); if (null == destination) { final NSError f = error.getValueAs(NSError.class); if (null == f) { throw new LocalNotfoundException(this.getAbsolute()); } throw new LocalNotfoundException(String.format("%s", f.localizedDescription())); } if (FilenameUtils.getPrefixLength(destination) != 0) { // Absolute path return new FinderLocal(destination); } // Relative path return new FinderLocal(this.getParent(), destination); } }