# HG changeset patch # User Alexander Simon # Date 1309507788 -14400 # Node ID 0b3fb75bcecc4a4a7f2860bd0a93858c0c4a9a9e # Parent 57a7addcfff32969f6ddbaaff21e0b5c5557645b fixing Bug 199806 - Provide bridge between remote file system and VCS - initial module version diff --git a/dlight.nativeexecution/nbproject/project.xml b/dlight.nativeexecution/nbproject/project.xml --- a/dlight.nativeexecution/nbproject/project.xml +++ b/dlight.nativeexecution/nbproject/project.xml @@ -270,6 +270,7 @@ org.netbeans.modules.dlight.uncover org.netbeans.modules.dlight.util org.netbeans.modules.dlight.webstack + org.netbeans.modules.fsbridge org.netbeans.nativeexecution.terminal org.netbeans.modules.nativeexecution.api org.netbeans.modules.nativeexecution.api.execution diff --git a/dlight.remote.impl/nbproject/project.xml b/dlight.remote.impl/nbproject/project.xml --- a/dlight.remote.impl/nbproject/project.xml +++ b/dlight.remote.impl/nbproject/project.xml @@ -57,6 +57,23 @@ + org.netbeans.modules.fsbridge + + + + 1.0 + + + + org.netbeans.modules.masterfs + + + + 2 + 2.32.1 + + + org.openide.awt diff --git a/fsbridge/build.xml b/fsbridge/build.xml new file mode 100644 --- /dev/null +++ b/fsbridge/build.xml @@ -0,0 +1,5 @@ + + + Builds, tests, and runs the project org.netbeans.modules.fsbridge + + diff --git a/fsbridge/manifest.mf b/fsbridge/manifest.mf new file mode 100644 --- /dev/null +++ b/fsbridge/manifest.mf @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +OpenIDE-Module: org.netbeans.modules.fsbridge +OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/fsbridge/Bundle.properties +OpenIDE-Module-Specification-Version: 1.0 + diff --git a/fsbridge/nbproject/project.properties b/fsbridge/nbproject/project.properties new file mode 100644 --- /dev/null +++ b/fsbridge/nbproject/project.properties @@ -0,0 +1,2 @@ +javac.source=1.6 +javac.compilerargs=-Xlint -Xlint:-serial diff --git a/fsbridge/nbproject/project.xml b/fsbridge/nbproject/project.xml new file mode 100644 --- /dev/null +++ b/fsbridge/nbproject/project.xml @@ -0,0 +1,41 @@ + + + org.netbeans.modules.apisupport.project + + + org.netbeans.modules.fsbridge + + + org.netbeans.modules.dlight.nativeexecution + + + + 1.10.3 + + + + org.netbeans.modules.masterfs + + + + 2 + 2.32.1 + + + + org.openide.filesystems + + + + 7.47.1 + + + + + org.netbeans.modules.dlight.remote.impl + org.netbeans.modules.versioning + org.netbeans.modules.fsbridge.spi + + + + diff --git a/fsbridge/src/org/netbeans/modules/fsbridge/Bundle.properties b/fsbridge/src/org/netbeans/modules/fsbridge/Bundle.properties new file mode 100644 --- /dev/null +++ b/fsbridge/src/org/netbeans/modules/fsbridge/Bundle.properties @@ -0,0 +1,5 @@ +OpenIDE-Module-Display-Category=Infrastructure +OpenIDE-Module-Long-Description=\ + Remote File System Bridge +OpenIDE-Module-Name=Remote File System Bridge +OpenIDE-Module-Short-Description=Remote File System Bridge diff --git a/fsbridge/src/org/netbeans/modules/fsbridge/spi/Bridge.java b/fsbridge/src/org/netbeans/modules/fsbridge/spi/Bridge.java new file mode 100644 --- /dev/null +++ b/fsbridge/src/org/netbeans/modules/fsbridge/spi/Bridge.java @@ -0,0 +1,164 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2011 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2011 Sun Microsystems, Inc. + */ +package org.netbeans.modules.fsbridge.spi; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment; +import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileStateInvalidException; +import org.openide.filesystems.FileSystem; +import org.openide.filesystems.FileUtil; + +/** + * + * @author Alexander Simon + */ +public final class Bridge { + + private static FileSystem rootFileSystem; + + static { + File tmpFile = null; + try { + tmpFile = File.createTempFile("NetBeans", ".tmp"); //NOI18N + tmpFile = FileUtil.normalizeFile(tmpFile); + FileObject fo = FileUtil.toFileObject(tmpFile); + rootFileSystem = fo.getFileSystem(); + } catch (IOException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } finally { + if (tmpFile != null) { + tmpFile.delete(); + } + } + } + + private Bridge() { + } + + public static FileProxy toLocalFileProxy(File file) { + return new FileProxy(file.getAbsolutePath(), rootFileSystem, true); + } + + public static FileProxy toFileProxy(FileObject file) { + try { + FileSystem fileSystem = file.getFileSystem(); + return new FileProxy(file.getPath(), fileSystem, !isRemote(fileSystem)); + } catch (FileStateInvalidException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } + return new FileProxy(file.getPath(), rootFileSystem, true); + } + + public static FileProxy toFileProxy(FileSystem fs, String path) { + if (isRemote(fs)) { + try { + //TODO: provide SPI + Class cls = Class.forName("org.netbeans.modules.remote.spi.FileSystemProvider"); //NOI18N + if (cls != null) { + Method method = cls.getMethod("normalizeAbsolutePath", String.class, FileSystem.class); //NOI18N + if (method != null) { + path = (String) method.invoke(cls, path, fs); + } + } + } catch (IllegalAccessException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } catch (IllegalArgumentException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } catch (InvocationTargetException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } catch (NoSuchMethodException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotFoundException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } + + } else { + path = FileUtil.normalizePath(path); + } + return new FileProxy(path, fs, !isRemote(fs)); + } + + public static FileObject toFileObject(FileProxy path) { + return path.getFileSystem().findResource(path.getAbsolutePath()); + } + + public static ExecutionEnvironment getExecutionEnvironment(FileProxy path) { + FileSystem fs = path.getFileSystem(); + if (isRemote(fs)) { + //TODO: provide SPI + Class aClass = fs.getClass(); + try { + Method method = aClass.getMethod("getExecutionEnvironment"); //NOI18N + return (ExecutionEnvironment) method.invoke(fs); + } catch (IllegalArgumentException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } catch (InvocationTargetException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } catch (NoSuchMethodException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } catch (IllegalAccessException ex) { + Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex); + } + } + return ExecutionEnvironmentFactory.getLocal(); + } + + private static boolean isRemote(FileSystem fs) { + //TODO: provide SPI + Class aClass = fs.getClass(); + if ("org.netbeans.modules.remote.impl.fs.RemoteFileSystem".equals(aClass.getName())) { //NOI18N + return true; + } + return false; + } +} diff --git a/fsbridge/src/org/netbeans/modules/fsbridge/spi/FileProxy.java b/fsbridge/src/org/netbeans/modules/fsbridge/spi/FileProxy.java new file mode 100644 --- /dev/null +++ b/fsbridge/src/org/netbeans/modules/fsbridge/spi/FileProxy.java @@ -0,0 +1,183 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2011 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2011 Sun Microsystems, Inc. + */ +package org.netbeans.modules.fsbridge.spi; + +import java.io.File; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileSystem; + +/** + * Represents file on remote or local file system. + * + * @author Alexander Simon + */ +public final class FileProxy { + + private final String path; + private final FileSystem fs; + private final boolean isLocal; + + FileProxy(String path, FileSystem fs, boolean isLocal) { + this.path = path; + this.fs = fs; + this.isLocal = isLocal; + } + + /** + * + * @return File system (remote or local) + */ + FileSystem getFileSystem() { + return fs; + } + + /** + * + * @return Absolute path to file in file system. + */ + public String getAbsolutePath() { + return path; + } + + public String getName() { + if (isLocal) { + return new File(path).getName(); + } else { + int index = path.lastIndexOf('/'); + if (index >= 0) { + return path.substring(index + 1); + } else { + return ""; //NOI18N + } + } + } + + public boolean isDirectory() { + if (isLocal) { + return new File(path).isDirectory(); + } + FileObject fo = Bridge.toFileObject(this); + return fo == null ? false : fo.isFolder(); + } + + public boolean isFile() { + if (isLocal) { + return new File(path).isFile(); + } else { + FileObject fo = Bridge.toFileObject(this); + return fo == null ? false : fo.isData(); + } + } + + public boolean canWrite() { + if (isLocal) { + return new File(path).canWrite(); + } else { + FileObject fo = Bridge.toFileObject(this); + return fo == null ? false : fo.canWrite(); + } + } + + public FileProxy getParentFile() { + if (isLocal) { + String parent = new File(path).getParent(); + if (parent != null) { + return new FileProxy(parent, fs, isLocal); + } + } else { + int index = path.lastIndexOf('/'); + if (index >= 0) { + String parent = path.substring(0, index); + return new FileProxy(parent, fs, isLocal); + } + } + return null; + } + + public boolean exists() { + if (isLocal) { + return new File(path).exists(); + } else { + FileObject fo = Bridge.toFileObject(this); + return fo == null ? false : fo.isValid(); + } + } + + public FileProxy newFileProxy(String name) { + if (isLocal) { + return Bridge.toLocalFileProxy(new File(path,name)); + } else { + return Bridge.toFileProxy(fs, path+'/'+name); + } + } + + @Override + public String toString() { + return fs + " " + path; //NOI18N + } + + @Override + public int hashCode() { + int hash = 3; + hash = 59 * hash + (this.path != null ? this.path.hashCode() : 0); + hash = 59 * hash + (this.fs != null ? this.fs.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final FileProxy other = (FileProxy) obj; + if (this.fs != other.fs && (this.fs == null || !this.fs.equals(other.fs))) { + return false; + } + if ((this.path == null) ? (other.path != null) : !this.path.equals(other.path)) { + return false; + } + return true; + } +} diff --git a/fsbridge/src/org/netbeans/modules/fsbridge/spi/ProvidedExtensions2.java b/fsbridge/src/org/netbeans/modules/fsbridge/spi/ProvidedExtensions2.java new file mode 100644 --- /dev/null +++ b/fsbridge/src/org/netbeans/modules/fsbridge/spi/ProvidedExtensions2.java @@ -0,0 +1,207 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2011 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2011 Sun Microsystems, Inc. + */ +package org.netbeans.modules.fsbridge.spi; + +import java.util.List; +import org.netbeans.modules.masterfs.providers.ProvidedExtensions; +import org.openide.filesystems.FileObject; + +/** + * Extension of {@link ProvidedExtensions} to process remote file operations. + * + * The interface is intended to be implemented in remote file system and VCS + * when modules extend class ProvidedExtensions. + * + * @author Alexander Simon + */ +public interface ProvidedExtensions2 { + /** + * Return instance of {@link ProvidedExtensions.IOHandler} + * that is responsible for copying the file or null. + * + * Just the first non null instance of IOHandler is used by + * RemoteFileSystem + * + * @param from file to be copied + * @param to target to copy this file to + * @return instance of {@link ProvidedExtensions.IOHandler} + * that is responsible for copying the file or null + */ + ProvidedExtensions.IOHandler getCopyHandler(FileProxy from, FileProxy to); + + /** + * Return instance of {@link ProvidedExtensions.IOHandler} + * that is responsible for moving the file or null. + * + * Just the first non null instance of IOHandler is used by + * RemoteFileSystem + * + * @param from file to be moved + * @param to target to move this file to + * @return instance of {@link ProvidedExtensions.IOHandler} + * that is responsible for moving the file or null + */ + ProvidedExtensions.IOHandler getMoveHandler(FileProxy from, FileProxy to); + + /* + * Return instance of {@link ProvidedExtensions.IOHandler} + * that is responsible for renaming the file or null. + * + * Just the first non null instance of IOHandler is used by + * RemoteFileSystem + * + * @param from file to be renamed + * @param newName new name of file + * @return instance of {@link ProvidedExtensions.IOHandler} + * that is responsible for renaming the file or null + */ + ProvidedExtensions.IOHandler getRenameHandler(FileProxy from, String newName); + + /* + * Return instance of {@link ProvidedExtensions.DeleteHandler} + * that is responsible for deleting the file or null. + * + * Just the first non null instance of DeleteHandler is used by + * RemoteFileSystem + * + * @param f file or folder to be deleted + * @return instance of {@link ProvidedExtensions2.DeleteHandler2} + * that is responsible for deleting the file or null + */ + ProvidedExtensions2.DeleteHandler2 getDeleteHandler(FileProxy f); + + public interface DeleteHandler2 { + /** + * Deletes the file or directory denoted by this abstract pathname. If + * this pathname denotes a directory, then the directory must be empty in + * order to be deleted. + * + * @return true if and only if the file or directory is + * successfully deleted; false otherwise + */ + boolean delete(FileProxy file); + } + + /** + * Called by RemoteFileSystem before FileObject + * is copied + * @param from FileObject to be moved + * @param to FileProxy target to move this file to + */ + void beforeCopy(FileObject from, FileProxy to); + + /** + * Called by RemoteFileSystem after FileObject + * was successfully copied + * @param from FileObject to be moved + * @param to FileProxy target to move this file to + */ + void copySuccess(FileObject from, FileProxy to); + + /** + * Called by RemoteFileSystem after a FileObject + * copy failed + * @param from FileObject to be moved + * @param to FileProxy target to move this file to + */ + void copyFailure(FileObject from, FileProxy to); + + /** + * Called by RemoteFileSystem before FileObject + * is moved + * @param from FileObject to be moved + * @param to FileProxy target to move this file to + */ + void beforeMove(FileObject from, FileProxy to); + + /** + * Called by RemoteFileSystem after FileObject + * was successfully + * @param from FileObject to be moved + * @param to FileProxy target to move this file to + */ + void moveSuccess(FileObject from, FileProxy to); + + /** + * Called by RemoteFileSystem after a FileObject + * move failed + * @param from FileObject to be moved + * @param to FileProxy target to move this file to + */ + void moveFailure(FileObject from, FileProxy to); + + /** + * Called by RemoteFileSystem when FileObject is queried for writability with the + * canWrite() method. + * + * @param f a FileProxy to query + * @return true if the file can be written to, deleted or moved, false otherwise + */ + boolean canWrite(FileProxy f); + + /** + * Called by {@code RemoteFileSystem} when {@code FileObject} is + * queried for attribute and attribute's name starts with {@code ProvidedExtensions} + * prefix. + * @param attrName name of attribute + * @return value of attribute + */ + Object getAttribute(FileProxy file, String attrName); + + /** Allows versioning system to exclude some children from recursive + * listening check. Also notifies the versioning whenever a refresh + * is required and allows the versiniong to provide special timestamp + * for a directory. + *

+ * Default implementation of this method returns -1. + * + * @param dir the directory to check timestamp for + * @param lastTimeStamp the previously known timestamp or -1 + * @param children add subfiles that shall be interated into this array + * @return the timestamp that shall represent this directory, it will + * be compared with timestamps of all children and the newest + * one will be kept and next time passed as lastTimeStamp. Return + * 0 if the directory does not have any special timestamp. Return + * -1 if you are not providing any special implementation + */ + long refreshRecursively(FileProxy dir, long lastTimeStamp, List children); +} diff --git a/masterfs/nbproject/project.xml b/masterfs/nbproject/project.xml --- a/masterfs/nbproject/project.xml +++ b/masterfs/nbproject/project.xml @@ -135,6 +135,8 @@ + org.netbeans.modules.dlight.remote.impl + org.netbeans.modules.fsbridge org.netbeans.modules.javafx.source org.netbeans.modules.parsing.api org.netbeans.modules.parsing.lucene diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties --- a/nbbuild/cluster.properties +++ b/nbbuild/cluster.properties @@ -269,6 +269,7 @@ extbrowser,\ extexecution,\ extexecution.destroy,\ + fsbridge,\ glassfish.common,\ gototest,\ gsf.codecoverage,\ diff --git a/versioning/nbproject/project.xml b/versioning/nbproject/project.xml --- a/versioning/nbproject/project.xml +++ b/versioning/nbproject/project.xml @@ -94,6 +94,14 @@ + org.netbeans.modules.fsbridge + + + + 1.0 + + + org.netbeans.modules.masterfs