org.openide.awt
--- a/fsbridge/build.xml
+++ a/fsbridge/build.xml
@@ -0,0 +1,5 @@
+
+
+ Builds, tests, and runs the project org.netbeans.modules.fsbridge
+
+
--- a/fsbridge/manifest.mf
+++ a/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
+
--- a/fsbridge/nbproject/project.properties
+++ a/fsbridge/nbproject/project.properties
@@ -0,0 +1,2 @@
+javac.source=1.6
+javac.compilerargs=-Xlint -Xlint:-serial
--- a/fsbridge/nbproject/project.xml
+++ a/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
+
+
+
+
--- a/fsbridge/src/org/netbeans/modules/fsbridge/Bundle.properties
+++ a/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
--- a/fsbridge/src/org/netbeans/modules/fsbridge/spi/Bridge.java
+++ a/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 extends FileSystem> 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 extends FileSystem> aClass = fs.getClass();
+ if ("org.netbeans.modules.remote.impl.fs.RemoteFileSystem".equals(aClass.getName())) { //NOI18N
+ return true;
+ }
+ return false;
+ }
+}
--- a/fsbridge/src/org/netbeans/modules/fsbridge/spi/FileProxy.java
+++ a/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;
+ }
+}
--- a/fsbridge/src/org/netbeans/modules/fsbridge/spi/ProvidedExtensions2.java
+++ a/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 super FileProxy> children);
+}
--- a/masterfs/nbproject/project.xml
+++ a/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
--- a/nbbuild/cluster.properties
+++ a/nbbuild/cluster.properties
@@ -269,6 +269,7 @@
extbrowser,\
extexecution,\
extexecution.destroy,\
+ fsbridge,\
glassfish.common,\
gototest,\
gsf.codecoverage,\
--- a/versioning/nbproject/project.xml
+++ a/versioning/nbproject/project.xml
@@ -94,6 +94,14 @@