# IGNITE-661: Removed FTP scanner and abstracted scanners into separate 
configurable entity.


Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/0391d27c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/0391d27c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/0391d27c

Branch: refs/heads/gg-10046
Commit: 0391d27c51b7590c3cc501b9a8d512fbb6cc4d7b
Parents: ac779fa
Author: vozerov-gridgain <voze...@gridgain.com>
Authored: Thu Apr 9 17:48:20 2015 +0300
Committer: vozerov-gridgain <voze...@gridgain.com>
Committed: Thu Apr 9 17:48:20 2015 +0300

----------------------------------------------------------------------
 modules/urideploy/README.txt                    |   2 +-
 modules/urideploy/licenses/edtftp-license.pdf   | Bin 58355 -> 0 bytes
 modules/urideploy/licenses/jtidy-license.txt    |  50 --
 .../urideploy/licenses/jtidy-mit-license.txt    |  50 ++
 modules/urideploy/pom.xml                       |   6 -
 .../spi/deployment/uri/UriDeploymentSpi.java    | 182 +++----
 .../uri/scanners/GridUriDeploymentScanner.java  | 286 -----------
 .../GridUriDeploymentScannerListener.java       |   2 +-
 .../uri/scanners/UriDeploymentScanner.java      |  47 ++
 .../scanners/UriDeploymentScannerContext.java   |  92 ++++
 .../scanners/UriDeploymentScannerManager.java   | 221 +++++++++
 .../file/GridUriDeploymentFileScanner.java      | 311 ------------
 .../scanners/file/UriDeploymentFileScanner.java | 327 +++++++++++++
 .../ftp/GridUriDeploymentFtpClient.java         | 199 --------
 .../ftp/GridUriDeploymentFtpConfiguration.java  | 115 -----
 .../ftp/GridUriDeploymentFtpException.java      |  43 --
 .../scanners/ftp/GridUriDeploymentFtpFile.java  | 119 -----
 .../ftp/GridUriDeploymentFtpScanner.java        | 234 ---------
 .../uri/scanners/ftp/package-info.java          |  22 -
 .../http/GridUriDeploymentHttpScanner.java      | 423 ----------------
 .../scanners/http/UriDeploymentHttpScanner.java | 478 +++++++++++++++++++
 ...loymentMultiScannersErrorThrottlingTest.java |   3 -
 .../GridUriDeploymentMultiScannersSelfTest.java |   3 +-
 .../GridFileDeploymentUndeploySelfTest.java     |   4 +-
 .../uri/scanners/ftp/GridFtpDeploymentTest.java |  46 --
 .../uri/scanners/ftp/package-info.java          |  22 -
 26 files changed, 1277 insertions(+), 2010 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/README.txt
----------------------------------------------------------------------
diff --git a/modules/urideploy/README.txt b/modules/urideploy/README.txt
index a2cdb62..dc3defd 100644
--- a/modules/urideploy/README.txt
+++ b/modules/urideploy/README.txt
@@ -2,7 +2,7 @@ Apache Ignite URI Deploy Module
 -------------------------------
 
 Apache Ignite URI Deploy module provides capabilities to deploy tasks from 
different sources like
-File System, HTTP, FTP, or even Email.
+File System, HTTP, or even Email.
 
 To enable URI Deploy module when starting a standalone node, move 
'optional/ignite-urideploy' folder to
 'libs' folder before running 'ignite.{sh|bat}' script. The content of the 
module folder will

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/licenses/edtftp-license.pdf
----------------------------------------------------------------------
diff --git a/modules/urideploy/licenses/edtftp-license.pdf 
b/modules/urideploy/licenses/edtftp-license.pdf
deleted file mode 100644
index 606d7cd..0000000
Binary files a/modules/urideploy/licenses/edtftp-license.pdf and /dev/null 
differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/licenses/jtidy-license.txt
----------------------------------------------------------------------
diff --git a/modules/urideploy/licenses/jtidy-license.txt 
b/modules/urideploy/licenses/jtidy-license.txt
deleted file mode 100644
index 3f5714a..0000000
--- a/modules/urideploy/licenses/jtidy-license.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-Java HTML Tidy - JTidy
-HTML parser and pretty printer
-
-Copyright (c) 1998-2000 World Wide Web Consortium (Massachusetts
-Institute of Technology, Institut National de Recherche en
-Informatique et en Automatique, Keio University). All Rights
-Reserved.
-
-Contributing Author(s):
-
-   Dave Raggett <d...@w3.org>
-   Andy Quick <ac.qu...@sympatico.ca> (translation to Java)
-   Gary L Peskin <ga...@firstech.com> (Java development)
-   Sami Lempinen <s...@lempinen.net> (release management)
-   Fabrizio Giustina <fgiust at users.sourceforge.net>
-
-The contributing author(s) would like to thank all those who
-helped with testing, bug fixes, and patience.  This wouldn't
-have been possible without all of you.
-
-COPYRIGHT NOTICE:
-
-This software and documentation is provided "as is," and
-the copyright holders and contributing author(s) make no
-representations or warranties, express or implied, including
-but not limited to, warranties of merchantability or fitness
-for any particular purpose or that the use of the software or
-documentation will not infringe any third party patents,
-copyrights, trademarks or other rights.
-
-The copyright holders and contributing author(s) will not be
-liable for any direct, indirect, special or consequential damages
-arising out of any use of the software or documentation, even if
-advised of the possibility of such damage.
-
-Permission is hereby granted to use, copy, modify, and distribute
-this source code, or portions hereof, documentation and executables,
-for any purpose, without fee, subject to the following restrictions:
-
-1. The origin of this source code must not be misrepresented.
-2. Altered versions must be plainly marked as such and must
-   not be misrepresented as being the original source.
-3. This Copyright notice may not be removed or altered from any
-   source or altered source distribution.
-
-The copyright holders and contributing author(s) specifically
-permit, without fee, and encourage the use of this source code
-as a component for supporting the Hypertext Markup Language in
-commercial products. If you use this source code in a product,
-acknowledgment is not required but would be appreciated.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/licenses/jtidy-mit-license.txt
----------------------------------------------------------------------
diff --git a/modules/urideploy/licenses/jtidy-mit-license.txt 
b/modules/urideploy/licenses/jtidy-mit-license.txt
new file mode 100644
index 0000000..3f5714a
--- /dev/null
+++ b/modules/urideploy/licenses/jtidy-mit-license.txt
@@ -0,0 +1,50 @@
+Java HTML Tidy - JTidy
+HTML parser and pretty printer
+
+Copyright (c) 1998-2000 World Wide Web Consortium (Massachusetts
+Institute of Technology, Institut National de Recherche en
+Informatique et en Automatique, Keio University). All Rights
+Reserved.
+
+Contributing Author(s):
+
+   Dave Raggett <d...@w3.org>
+   Andy Quick <ac.qu...@sympatico.ca> (translation to Java)
+   Gary L Peskin <ga...@firstech.com> (Java development)
+   Sami Lempinen <s...@lempinen.net> (release management)
+   Fabrizio Giustina <fgiust at users.sourceforge.net>
+
+The contributing author(s) would like to thank all those who
+helped with testing, bug fixes, and patience.  This wouldn't
+have been possible without all of you.
+
+COPYRIGHT NOTICE:
+
+This software and documentation is provided "as is," and
+the copyright holders and contributing author(s) make no
+representations or warranties, express or implied, including
+but not limited to, warranties of merchantability or fitness
+for any particular purpose or that the use of the software or
+documentation will not infringe any third party patents,
+copyrights, trademarks or other rights.
+
+The copyright holders and contributing author(s) will not be
+liable for any direct, indirect, special or consequential damages
+arising out of any use of the software or documentation, even if
+advised of the possibility of such damage.
+
+Permission is hereby granted to use, copy, modify, and distribute
+this source code, or portions hereof, documentation and executables,
+for any purpose, without fee, subject to the following restrictions:
+
+1. The origin of this source code must not be misrepresented.
+2. Altered versions must be plainly marked as such and must
+   not be misrepresented as being the original source.
+3. This Copyright notice may not be removed or altered from any
+   source or altered source distribution.
+
+The copyright holders and contributing author(s) specifically
+permit, without fee, and encourage the use of this source code
+as a component for supporting the Hypertext Markup Language in
+commercial products. If you use this source code in a product,
+acknowledgment is not required but would be appreciated.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/pom.xml
----------------------------------------------------------------------
diff --git a/modules/urideploy/pom.xml b/modules/urideploy/pom.xml
index d8a9aa1..29b00b7 100644
--- a/modules/urideploy/pom.xml
+++ b/modules/urideploy/pom.xml
@@ -77,12 +77,6 @@
         </dependency>
 
         <dependency>
-            <groupId>com.enterprisedt</groupId>
-            <artifactId>edtFTPj</artifactId>
-            <version>1.5.3</version>
-        </dependency>
-
-        <dependency>
             <groupId>net.sf.jtidy</groupId>
             <artifactId>jtidy</artifactId>
             <version>r938</version>

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/UriDeploymentSpi.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/UriDeploymentSpi.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/UriDeploymentSpi.java
index da9b42e..cb089c3 100644
--- 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/UriDeploymentSpi.java
+++ 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/UriDeploymentSpi.java
@@ -28,7 +28,6 @@ import org.apache.ignite.spi.*;
 import org.apache.ignite.spi.deployment.*;
 import org.apache.ignite.spi.deployment.uri.scanners.*;
 import org.apache.ignite.spi.deployment.uri.scanners.file.*;
-import org.apache.ignite.spi.deployment.uri.scanners.ftp.*;
 import org.apache.ignite.spi.deployment.uri.scanners.http.*;
 import org.jetbrains.annotations.*;
 
@@ -39,7 +38,7 @@ import java.util.Map.*;
 
 /**
  * Implementation of {@link org.apache.ignite.spi.deployment.DeploymentSpi} 
which can deploy tasks from
- * different sources like file system folders, FTP, email and HTTP.
+ * different sources like file system folders, email and HTTP.
  * There are different ways to deploy tasks in grid and every deploy method
  * depends on selected source protocol. This SPI is configured to work
  * with a list of URI's. Every URI contains all data about protocol/transport
@@ -140,7 +139,6 @@ import java.util.Map.*;
  * <ul>
  * <li><a href="#file">file://</a> - File protocol</li>
  * <li><a href="#classes">classes://</a> - Custom File protocol.</li>
- * <li><a href="#ftp">ftp://</a> - File transfer protocol</li>
  * <li><a href="#http">http://</a> - HTTP protocol</li>
  * <li><a href="#http">https://</a> - Secure HTTP protocol</li>
  * </ul>
@@ -163,12 +161,6 @@ import java.util.Map.*;
  *      <th>Optional</th>
  *      <th>Default</th>
  *  </tr>
- *  <tr>
- *      <td>freq</td>
- *      <td>File directory scan frequency in milliseconds.</td>
- *      <td>Yes</td>
- *      <td>{@code 5000} ms specified in {@link #DFLT_DISK_SCAN_FREQUENCY 
DFLT_DISK_SCAN_FREQUENCY}.</td>
- *  </tr>
  * </table>
  * <h2 class="header">File URI Example</h2>
  * The following example will scan {@code 'c:/Program files/ignite/deployment'}
@@ -194,12 +186,6 @@ import java.util.Map.*;
  *      <th>Optional</th>
  *      <th>Default</th>
  *  </tr>
- *  <tr>
- *      <td>freq</td>
- *      <td>File directory scan frequency in milliseconds.</td>
- *      <td>Yes</td>
- *      <td>{@code 5000} ms specified in {@link #DFLT_DISK_SCAN_FREQUENCY 
DFLT_DISK_SCAN_FREQUENCY}.</td>
- *  </tr>
  * </table>
  * <h2 class="header">Classes URI Example</h2>
  * The following example will scan {@code 'c:/Program files/ignite/deployment'}
@@ -209,42 +195,7 @@ import java.util.Map.*;
  * <blockquote class="snippet">
  * {@code classes://freq=5000@localhost/c:/Program files/ignite/deployment}
  * </blockquote>
- * <a name="ftp"></a>
- * <h1 class="header">FTP</h1>
- * For FTP protocol SPI will scan and download only GAR files from source
- * directory defined in URI. SPI doesn't scan FTP folders recursively.
- * The following parameters are supported for FTP protocol:
- * <table class="doctable">
- *  <tr>
- *      <th>Parameter</th>
- *      <th>Description</th>
- *      <th>Optional</th>
- *      <th>Default</th>
- *  </tr>
- *  <tr>
- *      <td>freq</td>
- *      <td>FTP location scan frequency in milliseconds.</td>
- *      <td>Yes</td>
- *      <td>{@code 300000} ms specified in {@link #DFLT_FTP_SCAN_FREQUENCY 
DFLT_FTP_SCAN_FREQUENCY}.</td>
- *  </tr>
- *  <tr>
- *      <td>username:password</td>
- *      <td>
- *          FTP username and password specified in standard URI server-based
- *          authority format.
- *      </td>
- *      <td>No</td>
- *      <td>---</td>
- *  </tr>
- * </table>
- * <h2 class="header">FTP URI Example</h2>
- * Here is an example of an FTP URI that connects identified as
- * {@code username:password} to {@code 'localhost'} on port {@code '21'},
- * with initial path set to {@code 'ignite/deployment'}
- * <blockquote class="snippet">
- * ftp://username:password;freq=10000@localhost:21/ignite/deployment
- * </blockquote>
- * <p>
+ * <a name="http"></a>
  * <h2 class="header">HTTP URI Example</h2>
  * The following example will scan {@code 'ignite/deployment'} folder with
  * on site {@code 'www.mysite.com'} using authentication
@@ -262,7 +213,6 @@ import java.util.Map.*;
  * List&lt;String&gt; uris = new ArrayList&lt;String&gt;(5);
  *
  * uris.add("http://www.site.com/tasks";);
- * 
uris.add("ftp://ftpuser:password;freq=10000@localhost:21/gg-test/deployment";);
  * uris.add("file://freq=20000@localhost/c:/Program files/gg-deployment");
  * uris.add("classes:///c:/Java_Projects/myproject/out");
  *
@@ -290,7 +240,6 @@ import java.util.Map.*;
  *                 &lt;property name="uriList"&gt;
  *                     &lt;list&gt;
  *                         &lt;value&gt;http://www.site.com/tasks&lt;/value&gt;
- *                         
&lt;value&gt;ftp://ftpuser:password;freq=10000@localhost:21/gg-test/deployment&lt;/value&gt;
  *                         &lt;value&gt;file://freq=20000@localhost/c:/Program 
files/gg-deployment&lt;/value&gt;
  *                         
&lt;value&gt;classes:///c:/Java_Projects/myproject/out&lt;/value&gt;
  *                     &lt;/list&gt;
@@ -319,15 +268,6 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
      */
     public static final String DFLT_DEPLOY_DIR = "deployment/file";
 
-    /** Default scan frequency for {@code file://} and {@code classes://} 
protocols (value is {@code 5000}). */
-    public static final int DFLT_DISK_SCAN_FREQUENCY = 5000;
-
-    /** Default scan frequency for {@code ftp://} protocol (value is {@code 
300000}). */
-    public static final int DFLT_FTP_SCAN_FREQUENCY = 300000;
-
-    /** Default scan frequency for {@code http://} protocol (value is {@code 
300000}). */
-    public static final int DFLT_HTTP_SCAN_FREQUENCY = 300000;
-
     /** Default task description file path and name (value is {@code 
META-INF/ignite.xml}). */
     public static final String XML_DESCRIPTOR_PATH = "META-INF/ignite.xml";
 
@@ -354,15 +294,14 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
 
     /** */
     @SuppressWarnings({"CollectionDeclaredAsConcreteClass"})
-    private final LinkedList<GridUriDeploymentUnitDescriptor> unitLoaders =
-        new LinkedList<>();
+    private final LinkedList<GridUriDeploymentUnitDescriptor> unitLoaders = 
new LinkedList<>();
 
     /** */
     @SuppressWarnings({"TypeMayBeWeakened"})
     private final LastTimeUnitDescriptorComparator unitComp = new 
LastTimeUnitDescriptorComparator();
 
-    /** List of scanners. Every URI has it's own scanner. */
-    private final Collection<GridUriDeploymentScanner> scanners = new 
ArrayList<>();
+    /** List of scanner managers. Every URI has it's own manager. */
+    private final Collection<UriDeploymentScannerManager> mgrs = new 
ArrayList<>();
 
     /** Whether URIs should be encoded or not. */
     private boolean encodeUri = true;
@@ -384,6 +323,9 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
     @SuppressWarnings("UnusedDeclaration")
     private boolean delayOnNewOrUpdatedFile;
 
+    /** Configured scanners. */
+    private UriDeploymentScanner[] scanners;
+
     /**
      * Sets absolute path to temporary directory which will be used by
      * deployment SPI to keep all deployed classes in.
@@ -463,17 +405,36 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
         this.lsnr = lsnr;
     }
 
+    /**
+     * Gets scanners.
+     *
+     * @return Scanners.
+     */
+    public UriDeploymentScanner[] getScanners() {
+        return scanners;
+    }
+
+    /**
+     * Sets scanners.
+     *
+     * @param scanners Scanners.
+     */
+    @IgniteSpiConfiguration(optional = true)
+    public void setScanners(UriDeploymentScanner... scanners) {
+        this.scanners = scanners;
+    }
+
     /** {@inheritDoc} */
     @Override public void spiStop() throws IgniteSpiException {
-        for (GridUriDeploymentScanner scanner : scanners)
-            scanner.cancel();
+        for (UriDeploymentScannerManager mgr : mgrs)
+            mgr.cancel();
 
-        for (GridUriDeploymentScanner scanner : scanners)
-            scanner.join();
+        for (UriDeploymentScannerManager mgr : mgrs)
+            mgr.join();
 
         // Clear inner collections.
         uriEncodedList.clear();
-        scanners.clear();
+        mgrs.clear();
 
         List<ClassLoader> tmpClsLdrs;
 
@@ -587,9 +548,15 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
             }
         };
 
-        for (URI uri : uriEncodedList) {
-            String proto = uri.getScheme();
+        // Set default scanners if none are configured.
+        if (scanners == null) {
+            scanners = new UriDeploymentScanner[2];
+
+            scanners[0] = new UriDeploymentFileScanner();
+            scanners[1] = new UriDeploymentHttpScanner();
+        }
 
+        for (URI uri : uriEncodedList) {
             File file = new File(deployTmpDirPath);
 
             long freq = -1;
@@ -601,34 +568,23 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
                 U.error(log, "Error parsing parameter value for frequency.", 
e);
             }
 
-            assert proto != null;
-
-            GridUriDeploymentScanner scanner;
+            UriDeploymentScannerManager mgr = null;
 
-            switch (proto) {
-                case "file":
-                    scanner = new GridUriDeploymentFileScanner(gridName, uri, 
file, freq > 0 ? freq :
-                        DFLT_DISK_SCAN_FREQUENCY, filter, lsnr, log);
-                    break;
+            for (UriDeploymentScanner scanner : scanners) {
+                if (scanner.acceptsURI(uri)) {
+                    mgr = new UriDeploymentScannerManager(gridName, uri, file, 
freq > 0 ? freq :
+                        scanner.getDefaultScanFrequency(), filter, lsnr, log, 
scanner);
 
-                case "http":
-                case "https":
-                    scanner = new GridUriDeploymentHttpScanner(gridName, uri, 
file, freq > 0 ? freq :
-                        DFLT_HTTP_SCAN_FREQUENCY, filter, lsnr, log);
                     break;
-
-                case "ftp":
-                    scanner = new GridUriDeploymentFtpScanner(gridName, uri, 
file, freq > 0 ? freq :
-                        DFLT_FTP_SCAN_FREQUENCY, filter, lsnr, log);
-                    break;
-
-                default:
-                    throw new IgniteSpiException("Unsupported protocol: " + 
proto);
+                }
             }
 
-            scanners.add(scanner);
+            if (mgr == null)
+                throw new IgniteSpiException("Unsupported URI (please 
configure appropriate scanner): " + uri);
 
-            scanner.start();
+            mgrs.add(mgr);
+
+            mgr.start();
         }
 
         // Ack parameters.
@@ -636,7 +592,7 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
             log.debug(configInfo("tmpDirPath", tmpDirPath));
             log.debug(configInfo("uriList", uriList));
             log.debug(configInfo("encodeUri", encodeUri));
-            log.debug(configInfo("scanners", scanners));
+            log.debug(configInfo("scanners", mgrs));
         }
 
         // Ack ok start.
@@ -662,7 +618,7 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
         if (userInfo != null) {
             String[] arr = userInfo.split(";");
 
-            if (arr != null && arr.length > 0)
+            if (arr.length > 0)
                 for (String el : arr)
                     if (el.startsWith("freq="))
                         return Long.parseLong(el.substring(5));
@@ -676,7 +632,7 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
     @Override public DeploymentResource findResource(String rsrcName) {
         assert rsrcName != null;
 
-        // Wait until all scanners finish their first scanning.
+        // Wait until all scanner managers finish their first scanning.
         try {
             synchronized (mux) {
                 while (!isFirstScanFinished(firstScanCntr))
@@ -684,7 +640,7 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
             }
         }
         catch (InterruptedException e) {
-            U.error(log, "Failed to wait while all scanners finish their first 
scanning.", e);
+            U.error(log, "Failed to wait while all scanner managers finish 
their first scanning.", e);
 
             Thread.currentThread().interrupt();
 
@@ -946,28 +902,6 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
     }
 
     /**
-     * Gets resource name for a given class name.
-     *
-     * @param clsName Class name.
-     * @param rsrcs Map of resources.
-     * @return Resource name.
-     */
-    private String getResourceName(String clsName, Map<String, String> rsrcs) {
-        assert Thread.holdsLock(mux);
-
-        String rsrcName = clsName;
-
-        for (Entry<String, String> e : rsrcs.entrySet())
-            if (e.getValue().equals(clsName) && !e.getKey().equals(clsName)) {
-                rsrcName = e.getKey();
-
-                break;
-            }
-
-        return rsrcName;
-    }
-
-    /**
      * Check is class can be reached.
      *
      * @param ldr Class loader.
@@ -1014,8 +948,6 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
         for (String uri : uriList) {
             assertParameter(uri != null, "uriList.get(X) != null");
 
-            assert uri != null;
-
             String encUri = encodeUri(uri.replaceAll("\\\\", "/"));
 
             URI uriObj;
@@ -1038,7 +970,7 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
     }
 
     /**
-     * Add configuration for file scanner {@link GridUriDeploymentFileScanner}.
+     * Add configuration for file scanner.
      *
      * @throws org.apache.ignite.spi.IgniteSpiException Thrown if default URI 
syntax is incorrect.
      */
@@ -1144,7 +1076,7 @@ public class UriDeploymentSpi extends IgniteSpiAdapter 
implements DeploymentSpi,
                 GridUriDeploymentUnitDescriptor desc = iter.next();
 
                 assert !newDesc.getClassLoader().equals(desc.getClassLoader()) 
:
-                    "Uri scanners always create new class loader for every GAR 
file: " + newDesc;
+                    "URI scanners always create new class loader for every GAR 
file: " + newDesc;
 
                 // Only for GAR files. Undeploy all for overwritten GAR files.
                 if (desc.getType() == 
GridUriDeploymentUnitDescriptor.Type.FILE &&

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/GridUriDeploymentScanner.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/GridUriDeploymentScanner.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/GridUriDeploymentScanner.java
deleted file mode 100644
index e20d156..0000000
--- 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/GridUriDeploymentScanner.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.spi.deployment.uri.scanners;
-
-import org.apache.ignite.*;
-import org.apache.ignite.internal.util.tostring.*;
-import org.apache.ignite.internal.util.typedef.internal.*;
-import org.apache.ignite.spi.*;
-
-import java.io.*;
-import java.net.*;
-
-/**
- * Base deployment scanner implementation. It simplifies scanner implementation
- * by providing loggers, executors and file names parsing methods.
- */
-public abstract class GridUriDeploymentScanner {
-    /** Grid name. */
-    private final String gridName;
-
-    /** URI that scanner should looks after. */
-    @GridToStringExclude
-    private final URI uri;
-
-    /** Temporary deployment directory. */
-    private final File deployDir;
-
-    /** Scan frequency. */
-    private final long freq;
-
-    /** Found files filter. */
-    private final FilenameFilter filter;
-
-    /** Scanner listener which should be notified about changes. */
-    private final GridUriDeploymentScannerListener lsnr;
-
-    /** Logger. */
-    private final IgniteLogger log;
-
-    /** Scanner implementation. */
-    private IgniteSpiThread scanner;
-
-    /** Whether first scan completed or not. */
-    private boolean firstScan = true;
-
-    /**
-     * Scans URI for new, updated or deleted files.
-     */
-    protected abstract void process();
-
-    /**
-     * Creates new scanner.
-     *
-     * @param gridName Grid name.
-     * @param uri URI which scanner should looks after.
-     * @param deployDir Temporary deployment directory.
-     * @param freq Scan frequency.
-     * @param filter Found files filter.
-     * @param lsnr Scanner listener which should be notifier about changes.
-     * @param log Logger.
-     */
-    protected GridUriDeploymentScanner(
-        String gridName,
-        URI uri,
-        File deployDir,
-        long freq,
-        FilenameFilter filter,
-        GridUriDeploymentScannerListener lsnr,
-        IgniteLogger log) {
-        assert uri != null;
-        assert freq > 0;
-        assert deployDir != null;
-        assert filter != null;
-        assert log != null;
-        assert lsnr != null;
-
-        this.gridName = gridName;
-        this.uri = uri;
-        this.deployDir = deployDir;
-        this.freq = freq;
-        this.filter = filter;
-        this.log = log.getLogger(getClass());
-        this.lsnr = lsnr;
-    }
-
-    /**
-     * Starts scanner.
-     */
-    public void start() {
-        scanner = new IgniteSpiThread(gridName, "grid-uri-scanner", log) {
-            /** {@inheritDoc} */
-            @SuppressWarnings({"BusyWait"})
-            @Override protected void body() throws InterruptedException  {
-                try {
-                    while (!isInterrupted()) {
-                        try {
-                            process();
-                        }
-                        finally {
-                            // Do it in finally to avoid any hanging.
-                            if (firstScan) {
-                                firstScan = false;
-
-                                lsnr.onFirstScanFinished();
-                            }
-                        }
-
-                        Thread.sleep(freq);
-                    }
-                }
-                finally {
-                    // Double check. If we were cancelled before anything has 
been scanned.
-                    if (firstScan) {
-                        firstScan = false;
-
-                        lsnr.onFirstScanFinished();
-                    }
-                }
-            }
-        };
-
-        scanner.start();
-
-        if (log.isDebugEnabled())
-            log.debug("Grid URI deployment scanner started: " + this);
-    }
-
-    /**
-     * Cancels scanner execution.
-     */
-    public void cancel() {
-        U.interrupt(scanner);
-    }
-
-    /**
-     * Joins scanner thread.
-     */
-    public void join() {
-        U.join(scanner, log);
-
-        if (log.isDebugEnabled())
-            log.debug("Grid URI deployment scanner stopped: " + this);
-    }
-
-    /**
-     * Tests whether scanner was cancelled before or not.
-     *
-     * @return {@code true} if scanner was cancelled and {@code false}
-     *      otherwise.
-     */
-    protected boolean isCancelled() {
-        assert scanner != null;
-
-        return scanner.isInterrupted();
-    }
-
-    /**
-     * Creates temp file in temp directory.
-     *
-     * @param fileName File name.
-     * @param tmpDir dir to creating file.
-     * @return created file.
-     * @throws IOException if error occur.
-     */
-    protected File createTempFile(String fileName, File tmpDir) throws 
IOException {
-        assert fileName != null;
-
-        int idx = fileName.lastIndexOf('.');
-
-        if (idx == -1)
-            idx = fileName.length();
-
-        String prefix = fileName.substring(0, idx);
-        if (idx < 3) { // Prefix must be at least 3 characters long. See 
File.createTempFile(...).
-            prefix += "___";
-        }
-
-        String suffix = fileName.substring(idx);
-
-        return File.createTempFile(prefix, suffix, tmpDir);
-    }
-
-    /**
-     * Gets file URI for the given file name. It extends any given name with 
{@link #uri}.
-     *
-     * @param name File name.
-     * @return URI for the given file name.
-     */
-    protected String getFileUri(String name) {
-        assert name != null;
-
-        String fileUri = uri.toString();
-
-        fileUri = fileUri.length() > 0 && fileUri.charAt(fileUri.length() - 1) 
== '/' ? fileUri + name :
-            fileUri + '/' + name;
-
-        return fileUri;
-    }
-
-    /**
-     * Tests whether first scan completed or not.
-     *
-     * @return {@code true} if first scan has been already completed and
-     *      {@code false} otherwise.
-     */
-    protected boolean isFirstScan() {
-        return firstScan;
-    }
-
-    /**
-     * Gets deployment URI.
-     *
-     * @return Deployment URI.
-     */
-    protected final URI getUri() {
-        return uri;
-    }
-
-    /**
-     * Gets deployment frequency.
-     *
-     * @return Deployment frequency.
-     */
-    protected final long getFrequency() {
-        return freq;
-    }
-
-    /**
-     * Gets temporary deployment directory.
-     *
-     * @return Temporary deployment directory.
-     */
-    protected final File getDeployDirectory() {
-        return deployDir;
-    }
-
-    /**
-     * Gets filter for found files. Before {@link #lsnr} is notified about
-     * changes with certain file last should be accepted by filter.
-     *
-     * @return New, updated or deleted file filter.
-     */
-    protected final FilenameFilter getFilter() {
-        return filter;
-    }
-
-    /**
-     * Gets deployment listener.
-     *
-     * @return Listener which should be notified about all deployment events
-     *      by scanner.
-     */
-    protected final GridUriDeploymentScannerListener getListener() {
-        return lsnr;
-    }
-
-    /**
-     * Gets scanner logger.
-     *
-     * @return Logger.
-     */
-    protected final IgniteLogger getLogger() {
-        return log;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return S.toString(GridUriDeploymentScanner.class, this,
-            "uri", uri != null ? U.hidePassword(uri.toString()) : null);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/GridUriDeploymentScannerListener.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/GridUriDeploymentScannerListener.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/GridUriDeploymentScannerListener.java
index ff33bd5..905e944 100644
--- 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/GridUriDeploymentScannerListener.java
+++ 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/GridUriDeploymentScannerListener.java
@@ -22,7 +22,7 @@ import java.util.*;
 
 /**
  * Scanner listener interface. Whatever deployment scanner is used
- * (ftp, http, file and so on) following events happens:
+ * (http, file and so on) following events happens:
  * <ul>
  * <li>{@code onNewOrUpdatedFile} - happens when new file has been found or 
updated.</li>
  * <li>{@code onDeletedFiles} - happens when file(s) has been removed.</li>

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScanner.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScanner.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScanner.java
new file mode 100644
index 0000000..e33351c
--- /dev/null
+++ 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScanner.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.spi.deployment.uri.scanners;
+
+import java.net.*;
+
+/**
+ * URI deployment scanner.
+ */
+public interface UriDeploymentScanner {
+    /**
+     * Check whether scanner is able to process the given URI.
+     *
+     * @param uri URI.
+     * @return {@code true} if scanner is able to process the URI.
+     */
+    boolean acceptsURI(URI uri);
+
+    /**
+     * Scan the given URI.
+     *
+     * @param scanCtx Scan context.
+     */
+    void scan(UriDeploymentScannerContext scanCtx);
+
+    /**
+     * Gets default scan frequency in milliseconds.
+     *
+     * @return Default scan frequency.
+     */
+    long getDefaultScanFrequency();
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScannerContext.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScannerContext.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScannerContext.java
new file mode 100644
index 0000000..9867f0f
--- /dev/null
+++ 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScannerContext.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.spi.deployment.uri.scanners;
+
+import org.apache.ignite.*;
+import org.apache.ignite.spi.deployment.uri.scanners.*;
+
+import java.io.*;
+import java.net.*;
+
+/**
+ * Deployment scanner context.
+ */
+public interface UriDeploymentScannerContext {
+    /**
+     * Creates temp file in temp directory.
+     *
+     * @param fileName File name.
+     * @param tmpDir dir to creating file.
+     * @return created file.
+     * @throws IOException if error occur.
+     */
+    File createTempFile(String fileName, File tmpDir) throws IOException;
+
+    /**
+     * Gets temporary deployment directory.
+     *
+     * @return Temporary deployment directory.
+     */
+    File getDeployDirectory();
+
+    /**
+     * Gets filter for found files. Before listener is notified about
+     * changes with certain file last should be accepted by filter.
+     *
+     * @return New, updated or deleted file filter.
+     */
+    FilenameFilter getFilter();
+
+    /**
+     * Gets deployment listener.
+     *
+     * @return Listener which should be notified about all deployment events
+     *      by scanner.
+     */
+    GridUriDeploymentScannerListener getListener();
+
+    /**
+     * Gets scanner logger.
+     *
+     * @return Logger.
+     */
+    IgniteLogger getLogger();
+
+    /**
+     * Gets deployment URI.
+     *
+     * @return Deployment URI.
+     */
+    URI getUri();
+
+    /**
+     * Tests whether scanner was cancelled before or not.
+     *
+     * @return {@code true} if scanner was cancelled and {@code false}
+     *      otherwise.
+     */
+    boolean isCancelled();
+
+    /**
+     * Tests whether first scan completed or not.
+     *
+     * @return {@code true} if first scan has been already completed and
+     *      {@code false} otherwise.
+     */
+    boolean isFirstScan();
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScannerManager.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScannerManager.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScannerManager.java
new file mode 100644
index 0000000..0d959d9
--- /dev/null
+++ 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/UriDeploymentScannerManager.java
@@ -0,0 +1,221 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.spi.deployment.uri.scanners;
+
+import org.apache.ignite.*;
+import org.apache.ignite.internal.util.tostring.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.spi.*;
+
+import java.io.*;
+import java.net.*;
+
+/**
+ * URI deployment scanner manager.
+ */
+public class UriDeploymentScannerManager implements 
UriDeploymentScannerContext {
+    /** Grid name. */
+    private final String gridName;
+
+    /** URI that scanner should looks after. */
+    @GridToStringExclude
+    private final URI uri;
+
+    /** Temporary deployment directory. */
+    private final File deployDir;
+
+    /** Scan frequency. */
+    private final long freq;
+
+    /** Found files filter. */
+    private final FilenameFilter filter;
+
+    /** Scanner listener which should be notified about changes. */
+    private final GridUriDeploymentScannerListener lsnr;
+
+    /** Logger. */
+    private final IgniteLogger log;
+
+    /** Underlying scanner. */
+    private final UriDeploymentScanner scanner;
+
+    /** Scanner implementation. */
+    private IgniteSpiThread scannerThread;
+
+    /** Whether first scan completed or not. */
+    private boolean firstScan = true;
+
+    /**
+     * Creates new scanner.
+     *
+     * @param gridName Grid name.
+     * @param uri URI which scanner should looks after.
+     * @param deployDir Temporary deployment directory.
+     * @param freq Scan frequency.
+     * @param filter Found files filter.
+     * @param lsnr Scanner listener which should be notifier about changes.
+     * @param log Logger.
+     * @param scanner Scanner.
+     */
+    public UriDeploymentScannerManager(
+        String gridName,
+        URI uri,
+        File deployDir,
+        long freq,
+        FilenameFilter filter,
+        GridUriDeploymentScannerListener lsnr,
+        IgniteLogger log,
+        UriDeploymentScanner scanner) {
+        assert uri != null;
+        assert freq > 0;
+        assert deployDir != null;
+        assert filter != null;
+        assert log != null;
+        assert lsnr != null;
+        assert scanner != null;
+
+        this.gridName = gridName;
+        this.uri = uri;
+        this.deployDir = deployDir;
+        this.freq = freq;
+        this.filter = filter;
+        this.log = log.getLogger(getClass());
+        this.lsnr = lsnr;
+        this.scanner = scanner;
+    }
+
+    /**
+     * Starts scanner.
+     */
+    public void start() {
+        scannerThread = new IgniteSpiThread(gridName, "grid-uri-scanner", log) 
{
+            /** {@inheritDoc} */
+            @SuppressWarnings({"BusyWait"})
+            @Override protected void body() throws InterruptedException  {
+                try {
+                    while (!isInterrupted()) {
+                        try {
+                            scanner.scan(UriDeploymentScannerManager.this);
+                        }
+                        finally {
+                            // Do it in finally to avoid any hanging.
+                            if (firstScan) {
+                                firstScan = false;
+
+                                lsnr.onFirstScanFinished();
+                            }
+                        }
+
+                        Thread.sleep(freq);
+                    }
+                }
+                finally {
+                    // Double check. If we were cancelled before anything has 
been scanned.
+                    if (firstScan) {
+                        firstScan = false;
+
+                        lsnr.onFirstScanFinished();
+                    }
+                }
+            }
+        };
+
+        scannerThread.start();
+
+        if (log.isDebugEnabled())
+            log.debug("Grid URI deployment scanner started: " + this);
+    }
+
+    /**
+     * Cancels scanner execution.
+     */
+    public void cancel() {
+        U.interrupt(scannerThread);
+    }
+
+    /**
+     * Joins scanner thread.
+     */
+    public void join() {
+        U.join(scannerThread, log);
+
+        if (log.isDebugEnabled())
+            log.debug("Grid URI deployment scanner stopped: " + this);
+    }
+
+    /** {@inheritDoc} */
+    public boolean isCancelled() {
+        assert scannerThread != null;
+
+        return scannerThread.isInterrupted();
+    }
+
+    /** {@inheritDoc} */
+    public File createTempFile(String fileName, File tmpDir) throws 
IOException {
+        assert fileName != null;
+
+        int idx = fileName.lastIndexOf('.');
+
+        if (idx == -1)
+            idx = fileName.length();
+
+        String prefix = fileName.substring(0, idx);
+        if (idx < 3) { // Prefix must be at least 3 characters long. See 
File.createTempFile(...).
+            prefix += "___";
+        }
+
+        String suffix = fileName.substring(idx);
+
+        return File.createTempFile(prefix, suffix, tmpDir);
+    }
+
+    /** {@inheritDoc} */
+    public boolean isFirstScan() {
+        return firstScan;
+    }
+
+    /** {@inheritDoc} */
+    public URI getUri() {
+        return uri;
+    }
+
+    /** {@inheritDoc} */
+    public File getDeployDirectory() {
+        return deployDir;
+    }
+
+    /** {@inheritDoc} */
+    public FilenameFilter getFilter() {
+        return filter;
+    }
+
+    /** {@inheritDoc} */
+    public GridUriDeploymentScannerListener getListener() {
+        return lsnr;
+    }
+
+    /** {@inheritDoc} */
+    public IgniteLogger getLogger() {
+        return log;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(UriDeploymentScannerManager.class, this, "uri", 
U.hidePassword(uri.toString()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/file/GridUriDeploymentFileScanner.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/file/GridUriDeploymentFileScanner.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/file/GridUriDeploymentFileScanner.java
deleted file mode 100644
index fc81c13..0000000
--- 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/file/GridUriDeploymentFileScanner.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.spi.deployment.uri.scanners.file;
-
-import org.apache.ignite.*;
-import org.apache.ignite.internal.util.lang.*;
-import org.apache.ignite.internal.util.typedef.*;
-import org.apache.ignite.internal.util.typedef.internal.*;
-import org.apache.ignite.spi.*;
-import org.apache.ignite.spi.deployment.uri.scanners.*;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-
-/**
- * Scanner that processes all URIs with "file" scheme. Usually URI point to
- * certain directory or file and scanner is in charge of watching all changes
- * (file deletion, creation and so on) and sending notification to the listener
- * about every change.
- */
-public class GridUriDeploymentFileScanner extends GridUriDeploymentScanner {
-    /** Scanning directory or file. */
-    private File scanDir;
-
-    /** Cache of found GAR-files or GAR-directories to check if any of it has 
been updated. */
-    private Map<File, Long> tstampCache = new HashMap<>();
-
-    /** Cache of found files in GAR-folder to check if any of it has been 
updated. */
-    private Map<File, Map<File, Long>> garDirFilesTstampCache = new 
HashMap<>();
-
-    /** */
-    private FileFilter garFilter;
-
-    /** */
-    private FileFilter garDirFilesFilter;
-
-    /**
-     * Creates new instance of scanner with given name.
-     *
-     * @param gridName Grid name.
-     * @param uri URI which scanner should look after.
-     * @param deployDir Temporary deployment directory.
-     * @param freq Scan frequency.
-     * @param filter Found files filter.
-     * @param lsnr Scanner listener which should be notifier about changes.
-     * @param log Logger.
-     * @throws org.apache.ignite.spi.IgniteSpiException Thrown if URI is 
{@code null} or is not a
-     *      directory.
-     */
-    public GridUriDeploymentFileScanner(
-        String gridName,
-        URI uri,
-        File deployDir,
-        long freq,
-        FilenameFilter filter,
-        GridUriDeploymentScannerListener lsnr,
-        IgniteLogger log) throws IgniteSpiException {
-        super(gridName, uri, deployDir, freq, filter, lsnr, log);
-
-        initialize(uri);
-    }
-
-    /**
-     * Initializes scanner by parsing given URI and extracting scanning
-     * directory path and creating file filters.
-     *
-     * @param uri Scanning URI with "file" scheme.
-     * @throws org.apache.ignite.spi.IgniteSpiException Thrown if URI is 
{@code null} or is not a
-     *      directory.
-     */
-    private void initialize(URI uri) throws IgniteSpiException {
-        assert "file".equals(getUri().getScheme());
-
-        String scanDirPath = uri.getPath();
-
-        if (scanDirPath != null)
-            scanDir = new File(scanDirPath);
-
-        if (scanDir == null || !scanDir.isDirectory()) {
-            scanDir = null;
-
-            throw new IgniteSpiException("URI is either not provided or is not 
a directory: " +
-                U.hidePassword(uri.toString()));
-        }
-
-        garFilter = new FileFilter() {
-            /** {@inheritDoc} */
-            @Override public boolean accept(File pathname) {
-                return getFilter().accept(null, pathname.getName());
-            }
-        };
-
-        garDirFilesFilter = new FileFilter() {
-            /** {@inheritDoc} */
-            @Override public boolean accept(File pathname) {
-                // Allow all files in GAR-directory.
-                return pathname.isFile();
-            }
-        };
-    }
-
-    /**
-     * Handles changes in scanning directory by tracking files modification 
date.
-     * Checks files modification date against those one that was collected 
before
-     * and notifies listener about every changed or deleted file.
-     */
-    @Override protected void process() {
-        final Set<File> foundFiles = isFirstScan() ? new HashSet<File>() : 
U.<File>newHashSet(tstampCache.size());
-
-        GridDeploymentFileHandler hnd = new GridDeploymentFileHandler() {
-            /** {@inheritDoc} */
-            @Override public void handle(File file) {
-                foundFiles.add(file);
-
-                handleFile(file);
-            }
-        };
-
-        // Scan directory for deploy units.
-        GridDeploymentFolderScannerHelper.scanFolder(scanDir, garFilter, hnd);
-
-        // Print warning if no GAR-units found first time.
-        if (isFirstScan() && foundFiles.isEmpty())
-            U.warn(getLogger(), "No GAR-units found in: " + 
U.hidePassword(getUri().toString()));
-
-        if (!isFirstScan()) {
-            Collection<File> deletedFiles = new 
HashSet<>(tstampCache.keySet());
-
-            deletedFiles.removeAll(foundFiles);
-
-            if (!deletedFiles.isEmpty()) {
-                List<String> uris = new ArrayList<>();
-
-                for (File file : deletedFiles) {
-                    uris.add(getFileUri(file.getAbsolutePath()));
-                }
-
-                // Clear cache.
-                tstampCache.keySet().removeAll(deletedFiles);
-
-                garDirFilesTstampCache.keySet().removeAll(deletedFiles);
-
-                getListener().onDeletedFiles(uris);
-            }
-        }
-    }
-
-    /**
-     * Tests whether given directory or file was changed since last check and 
if so
-     * copies all directory sub-folders and files or file itself to the 
deployment
-     * directory and than notifies listener about new or updated files.
-     *
-     * @param file Scanning directory or file.
-     */
-    private void handleFile(File file) {
-        boolean changed;
-
-        Long lastMod;
-
-        if (file.isDirectory()) {
-            GridTuple<Long> dirLastModified = F.t(file.lastModified());
-
-            changed = checkGarDirectoryChanged(file, dirLastModified);
-
-            lastMod = dirLastModified.get();
-        }
-        else {
-            lastMod = tstampCache.get(file);
-
-            changed = lastMod == null || lastMod != file.lastModified();
-
-            lastMod = file.lastModified();
-        }
-
-        // If file is new or has been modified.
-        if (changed) {
-            tstampCache.put(file, lastMod);
-
-            if (getLogger().isDebugEnabled())
-                getLogger().debug("Discovered deployment file or directory: " 
+ file);
-
-            String fileName = file.getName();
-
-            try {
-                File cpFile = createTempFile(fileName, getDeployDirectory());
-
-                // Delete file when JVM stopped.
-                cpFile.deleteOnExit();
-
-                if (file.isDirectory()) {
-                    cpFile = new File(cpFile.getParent(), "dir_" + 
cpFile.getName());
-
-                    // Delete directory when JVM stopped.
-                    cpFile.deleteOnExit();
-                }
-
-                // Copy file to deploy directory.
-                U.copy(file, cpFile, true);
-
-                String fileUri = getFileUri(file.getAbsolutePath());
-
-                getListener().onNewOrUpdatedFile(cpFile, fileUri, lastMod);
-            }
-            catch (IOException e) {
-                U.error(getLogger(), "Error saving file: " + fileName, e);
-            }
-        }
-    }
-
-    /**
-     * Tests whether certain directory was changed since given modification 
date.
-     * It scans all directory files one by one and compares their modification
-     * dates with those ones that was collected before.
-     * <p>
-     * If at least one file was changed (has modification date after given one)
-     * whole directory is considered as modified.
-     *
-     * @param dir Scanning directory.
-     * @param lastModified Last calculated Directory modification date.
-     * @return {@code true} if directory was changed since last check and
-     *      {@code false} otherwise.
-     */
-    private boolean checkGarDirectoryChanged(File dir, final GridTuple<Long> 
lastModified) {
-        final Map<File, Long> clssTstampCache;
-
-        boolean firstScan = false;
-
-        if (!garDirFilesTstampCache.containsKey(dir)) {
-            firstScan = true;
-
-            garDirFilesTstampCache.put(dir, clssTstampCache = new HashMap<>());
-        }
-        else
-            clssTstampCache = garDirFilesTstampCache.get(dir);
-
-        assert clssTstampCache != null;
-
-        final GridTuple<Boolean> changed = F.t(false);
-
-        final Set<File> foundFiles = firstScan ? new HashSet<File>() : 
U.<File>newHashSet(clssTstampCache.size());
-
-        GridDeploymentFileHandler hnd = new GridDeploymentFileHandler() {
-            @Override public void handle(File file) {
-                foundFiles.add(file);
-
-                Long fileLastModified = clssTstampCache.get(file);
-
-                if (fileLastModified == null || fileLastModified != 
file.lastModified()) {
-                    clssTstampCache.put(file, fileLastModified = 
file.lastModified());
-
-                    changed.set(true);
-                }
-
-                // Calculate last modified file in folder.
-                if (fileLastModified > lastModified.get())
-                    lastModified.set(fileLastModified);
-            }
-        };
-
-        // Scan GAR-directory for changes.
-        GridDeploymentFolderScannerHelper.scanFolder(dir, garDirFilesFilter, 
hnd);
-
-        // Clear cache for deleted files.
-        if (!firstScan && clssTstampCache.keySet().retainAll(foundFiles))
-            changed.set(true);
-
-        return changed.get();
-    }
-
-    /**
-     * Converts given file name to the URI with "file" scheme.
-     *
-     * @param name File name to be converted.
-     * @return File name with "file://" prefix.
-     */
-    @Override protected String getFileUri(String name) {
-        assert name != null;
-
-        name = name.replace("\\","/");
-
-        return "file://" + (name.charAt(0) == '/' ? "" : '/') + name;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        StringBuilder buf = new StringBuilder();
-
-        buf.append(getClass().getName()).append(" [");
-        buf.append("scanDir=").append(scanDir);
-        buf.append(']');
-
-        return buf.toString();
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/file/UriDeploymentFileScanner.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/file/UriDeploymentFileScanner.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/file/UriDeploymentFileScanner.java
new file mode 100644
index 0000000..2cbe38b
--- /dev/null
+++ 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/file/UriDeploymentFileScanner.java
@@ -0,0 +1,327 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.spi.deployment.uri.scanners.file;
+
+import org.apache.ignite.internal.util.lang.*;
+import org.apache.ignite.internal.util.typedef.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.spi.*;
+import org.apache.ignite.spi.deployment.uri.scanners.*;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * URI deployment file scanner.
+ */
+public class UriDeploymentFileScanner implements UriDeploymentScanner {
+    /** Default scan frequency. */
+    public static final int DFLT_SCAN_FREQ = 5000;
+
+    /** Per-URI contexts. */
+    private final ConcurrentHashMap<URI, URIContext> uriCtxs = new 
ConcurrentHashMap<>();
+
+    /** {@inheritDoc} */
+    @Override public boolean acceptsURI(URI uri) {
+        String proto = uri.getScheme().toLowerCase();
+
+        return "file".equals(proto);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void scan(UriDeploymentScannerContext scanCtx) {
+        URI uri = scanCtx.getUri();
+
+        URIContext uriCtx = uriCtxs.get(uri);
+
+        if (uriCtx == null) {
+            uriCtx = createUriContext(uri, scanCtx);
+
+            URIContext oldUriCtx = uriCtxs.putIfAbsent(uri, uriCtx);
+
+            if (oldUriCtx != null)
+                uriCtx = oldUriCtx;
+        }
+
+        uriCtx.scan(scanCtx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getDefaultScanFrequency() {
+        return DFLT_SCAN_FREQ;
+    }
+
+    /**
+     * Create context for the given URI.
+     *
+     * @param uri URI.
+     * @param scanCtx Scanner context.
+     * @return URI context.
+     */
+    private URIContext createUriContext(URI uri, final 
UriDeploymentScannerContext scanCtx) {
+        String scanDirPath = uri.getPath();
+
+        File scanDir = null;
+
+        if (scanDirPath != null)
+            scanDir = new File(scanDirPath);
+
+        if (scanDir == null || !scanDir.isDirectory())
+            throw new IgniteSpiException("URI is either not provided or is not 
a directory: " +
+                U.hidePassword(uri.toString()));
+
+        FileFilter garFilter = new FileFilter() {
+            /** {@inheritDoc} */
+            @Override public boolean accept(File pathname) {
+                return scanCtx.getFilter().accept(null, pathname.getName());
+            }
+        };
+
+        FileFilter garDirFilesFilter = new FileFilter() {
+            /** {@inheritDoc} */
+            @Override public boolean accept(File pathname) {
+                // Allow all files in GAR-directory.
+                return pathname.isFile();
+            }
+        };
+
+        return new URIContext(scanDir, garFilter, garDirFilesFilter);
+    }
+
+    /**
+     * Converts given file name to the URI with "file" scheme.
+     *
+     * @param name File name to be converted.
+     * @return File name with "file://" prefix.
+     */
+    private static String getFileUri(String name) {
+        assert name != null;
+
+        name = name.replace("\\","/");
+
+        return "file://" + (name.charAt(0) == '/' ? "" : '/') + name;
+    }
+
+    /**
+     * Context for the given URI.
+     */
+    private static class URIContext {
+        /** Scanning directory or file. */
+        private final File scanDir;
+
+        /** GAR filter. */
+        private final FileFilter garFilter;
+
+        /** GAR directory files filter. */
+        private final FileFilter garDirFilesFilter;
+
+        /** Cache of found GAR-files or GAR-directories to check if any of it 
has been updated. */
+        private final Map<File, Long> tstampCache = new HashMap<>();
+
+        /** Cache of found files in GAR-folder to check if any of it has been 
updated. */
+        private final Map<File, Map<File, Long>> garDirFilesTstampCache = new 
HashMap<>();
+
+        /**
+         * Constructor.
+         *
+         * @param scanDir Scan directory.
+         * @param garFilter Gar filter.
+         * @param garDirFilesFilter GAR directory files filter.
+         */
+        private URIContext(File scanDir, FileFilter garFilter, FileFilter 
garDirFilesFilter) {
+            this.scanDir = scanDir;
+            this.garFilter = garFilter;
+            this.garDirFilesFilter = garDirFilesFilter;
+        }
+
+        /**
+         * Perform scan.
+         *
+         * @param scanCtx Scan context.
+         */
+        private void scan(final UriDeploymentScannerContext scanCtx) {
+            final Set<File> foundFiles = scanCtx.isFirstScan() ?
+                new HashSet<File>() : U.<File>newHashSet(tstampCache.size());
+
+            GridDeploymentFileHandler hnd = new GridDeploymentFileHandler() {
+                /** {@inheritDoc} */
+                @Override public void handle(File file) {
+                    foundFiles.add(file);
+
+                    handleFile(file, scanCtx);
+                }
+            };
+
+            // Scan directory for deploy units.
+            GridDeploymentFolderScannerHelper.scanFolder(scanDir, garFilter, 
hnd);
+
+            // Print warning if no GAR-units found first time.
+            if (scanCtx.isFirstScan() && foundFiles.isEmpty())
+                U.warn(scanCtx.getLogger(), "No GAR-units found in: " + 
U.hidePassword(scanCtx.getUri().toString()));
+
+            if (!scanCtx.isFirstScan()) {
+                Collection<File> deletedFiles = new 
HashSet<>(tstampCache.keySet());
+
+                deletedFiles.removeAll(foundFiles);
+
+                if (!deletedFiles.isEmpty()) {
+                    List<String> uris = new ArrayList<>();
+
+                    for (File file : deletedFiles) {
+                        uris.add(getFileUri(file.getAbsolutePath()));
+                    }
+
+                    // Clear cache.
+                    tstampCache.keySet().removeAll(deletedFiles);
+
+                    garDirFilesTstampCache.keySet().removeAll(deletedFiles);
+
+                    scanCtx.getListener().onDeletedFiles(uris);
+                }
+            }
+        }
+
+        /**
+         * Tests whether given directory or file was changed since last check 
and if so
+         * copies all directory sub-folders and files or file itself to the 
deployment
+         * directory and than notifies listener about new or updated files.
+         *
+         * @param file Scanning directory or file.
+         * @param ctx Scanner context.
+         */
+        private void handleFile(File file, UriDeploymentScannerContext ctx) {
+            boolean changed;
+
+            Long lastMod;
+
+            if (file.isDirectory()) {
+                GridTuple<Long> dirLastModified = F.t(file.lastModified());
+
+                changed = checkGarDirectoryChanged(file, dirLastModified);
+
+                lastMod = dirLastModified.get();
+            }
+            else {
+                lastMod = tstampCache.get(file);
+
+                changed = lastMod == null || lastMod != file.lastModified();
+
+                lastMod = file.lastModified();
+            }
+
+            // If file is new or has been modified.
+            if (changed) {
+                tstampCache.put(file, lastMod);
+
+                if (ctx.getLogger().isDebugEnabled())
+                    ctx.getLogger().debug("Discovered deployment file or 
directory: " + file);
+
+                String fileName = file.getName();
+
+                try {
+                    File cpFile = ctx.createTempFile(fileName, 
ctx.getDeployDirectory());
+
+                    // Delete file when JVM stopped.
+                    cpFile.deleteOnExit();
+
+                    if (file.isDirectory()) {
+                        cpFile = new File(cpFile.getParent(), "dir_" + 
cpFile.getName());
+
+                        // Delete directory when JVM stopped.
+                        cpFile.deleteOnExit();
+                    }
+
+                    // Copy file to deploy directory.
+                    U.copy(file, cpFile, true);
+
+                    String fileUri = getFileUri(file.getAbsolutePath());
+
+                    assert lastMod != null;
+
+                    ctx.getListener().onNewOrUpdatedFile(cpFile, fileUri, 
lastMod);
+                }
+                catch (IOException e) {
+                    U.error(ctx.getLogger(), "Error saving file: " + fileName, 
e);
+                }
+            }
+        }
+
+        /**
+         * Tests whether certain directory was changed since given 
modification date.
+         * It scans all directory files one by one and compares their 
modification
+         * dates with those ones that was collected before.
+         * <p>
+         * If at least one file was changed (has modification date after given 
one)
+         * whole directory is considered as modified.
+         *
+         * @param dir Scanning directory.
+         * @param lastModified Last calculated Directory modification date.
+         * @return {@code true} if directory was changed since last check and
+         *      {@code false} otherwise.
+         */
+        @SuppressWarnings("ConstantConditions")
+        private boolean checkGarDirectoryChanged(File dir, final 
GridTuple<Long> lastModified) {
+            final Map<File, Long> clssTstampCache;
+
+            boolean firstScan = false;
+
+            if (!garDirFilesTstampCache.containsKey(dir)) {
+                firstScan = true;
+
+                garDirFilesTstampCache.put(dir, clssTstampCache = new 
HashMap<>());
+            }
+            else
+                clssTstampCache = garDirFilesTstampCache.get(dir);
+
+            assert clssTstampCache != null;
+
+            final GridTuple<Boolean> changed = F.t(false);
+
+            final Set<File> foundFiles = firstScan ? new HashSet<File>() : 
U.<File>newHashSet(clssTstampCache.size());
+
+            GridDeploymentFileHandler hnd = new GridDeploymentFileHandler() {
+                @Override public void handle(File file) {
+                    foundFiles.add(file);
+
+                    Long fileLastModified = clssTstampCache.get(file);
+
+                    if (fileLastModified == null || fileLastModified != 
file.lastModified()) {
+                        clssTstampCache.put(file, fileLastModified = 
file.lastModified());
+
+                        changed.set(true);
+                    }
+
+                    // Calculate last modified file in folder.
+                    if (fileLastModified > lastModified.get())
+                        lastModified.set(fileLastModified);
+                }
+            };
+
+            // Scan GAR-directory for changes.
+            GridDeploymentFolderScannerHelper.scanFolder(dir, 
garDirFilesFilter, hnd);
+
+            // Clear cache for deleted files.
+            if (!firstScan && clssTstampCache.keySet().retainAll(foundFiles))
+                changed.set(true);
+
+            return changed.get();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpClient.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpClient.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpClient.java
deleted file mode 100644
index e85082e..0000000
--- 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpClient.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.spi.deployment.uri.scanners.ftp;
-
-import com.enterprisedt.net.ftp.*;
-import org.apache.ignite.*;
-import org.apache.ignite.internal.util.typedef.internal.*;
-
-import java.io.*;
-import java.text.*;
-import java.util.*;
-
-/**
- * URI FTP deployment client.
- */
-class GridUriDeploymentFtpClient {
-    /** Timeout in milliseconds on the underlying socket. */
-    private static final int TIMEOUT = 60000;
-
-    /** */
-    private final GridUriDeploymentFtpConfiguration cfg;
-
-    /** */
-    private final IgniteLogger log;
-
-    /** */
-    private FTPClient ftp;
-
-    /** */
-    private boolean isConnected;
-
-    /**
-     * @param cfg FTP configuration.
-     * @param log Logger to use.
-     */
-    GridUriDeploymentFtpClient(GridUriDeploymentFtpConfiguration cfg, 
IgniteLogger log) {
-        assert cfg != null;
-        assert log != null;
-
-        this.cfg = cfg;
-        this.log = log;
-    }
-
-
-    /**
-     * @param rmtFile Remote file.
-     * @param localFile Local file.
-     * @throws GridUriDeploymentFtpException Thrown in case of any error.
-     */
-    void downloadToFile(GridUriDeploymentFtpFile rmtFile, File localFile) 
throws GridUriDeploymentFtpException {
-        assert ftp != null;
-        assert rmtFile != null;
-        assert localFile != null;
-
-        String dirName = rmtFile.getParentDirectory();
-
-        if (dirName.length() == 0 || '/' != dirName.charAt(dirName.length() - 
1))
-            dirName += '/';
-
-        String srcPath = dirName + rmtFile.getName();
-
-        try {
-            BufferedOutputStream out = null;
-
-            try {
-                out = new BufferedOutputStream(new 
FileOutputStream(localFile));
-
-                ftp.get(out, srcPath);
-            }
-            finally {
-                U.close(out, log);
-            }
-        }
-        catch (IOException | FTPException e) {
-            throw new GridUriDeploymentFtpException("Failed to download file 
[rmtFile=" + srcPath + ", localFile=" +
-                localFile + ']', e);
-        }
-    }
-
-    /**
-     * @throws GridUriDeploymentFtpException Thrown in case of any error.
-     */
-    void connect() throws GridUriDeploymentFtpException {
-        ftp = new FTPClient();
-
-        try {
-            ftp.setRemoteHost(cfg.getHost());
-            ftp.setRemotePort(cfg.getPort());
-
-            // Set socket timeout to avoid an infinite timeout.
-            ftp.setTimeout(TIMEOUT);
-
-            ftp.connect();
-
-            ftp.login(cfg.getUsername(), cfg.getPassword());
-
-            // Set up passive binary transfers.
-            ftp.setConnectMode(FTPConnectMode.PASV);
-            ftp.setType(FTPTransferType.BINARY);
-
-            if (!ftp.connected()) {
-                ftp.quit();
-
-                throw new GridUriDeploymentFtpException("FTP server refused 
connection [host=" + cfg.getHost() +
-                    ", port=" + cfg.getPort() + ", username=" + 
cfg.getUsername() + ']');
-            }
-        }
-        catch (IOException | FTPException e) {
-            throw new GridUriDeploymentFtpException("Failed to connect to host 
[host=" + cfg.getHost() +
-                ", port=" + cfg.getPort() + ']', e);
-        }
-
-        isConnected = true;
-    }
-
-    /**
-     * @throws GridUriDeploymentFtpException Thrown in case of any error.
-     */
-    void close() throws GridUriDeploymentFtpException {
-        if (!isConnected)
-            return;
-
-        assert ftp != null;
-
-        Exception e = null;
-
-        try {
-            ftp.quit();
-        }
-        catch (IOException e1) {
-            e = e1;
-        }
-        catch (FTPException e1) {
-            e = e1;
-        }
-        finally{
-            if (ftp.connected()) {
-                try {
-                    ftp.quit();
-                }
-                catch (IOException | FTPException e1) {
-                    // Don't loose the initial exception.
-                    if (e == null)
-                        e = e1;
-                }
-            }
-        }
-
-        ftp = null;
-
-        isConnected = false;
-
-        if (e != null)
-            throw new GridUriDeploymentFtpException("Failed to close FTP 
client.", e);
-    }
-
-    /**
-     * @return List of files.
-     * @throws GridUriDeploymentFtpException Thrown in case of any error.
-     */
-    List<GridUriDeploymentFtpFile> getFiles() throws 
GridUriDeploymentFtpException {
-        try {
-            assert cfg.getDirectory() != null;
-
-            List<GridUriDeploymentFtpFile> clientFiles = new ArrayList<>();
-
-            FTPFile[] files = ftp.dirDetails(cfg.getDirectory());
-
-            for (FTPFile file : files) {
-                clientFiles.add(new 
GridUriDeploymentFtpFile(cfg.getDirectory(), file));
-            }
-
-            return clientFiles;
-        }
-        catch (IOException | ParseException | FTPException e) {
-            throw new GridUriDeploymentFtpException("Failed to get files in 
directory: " + cfg.getDirectory(), e);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return S.toString(GridUriDeploymentFtpClient.class, this);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpConfiguration.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpConfiguration.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpConfiguration.java
deleted file mode 100644
index 5d5b62a..0000000
--- 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpConfiguration.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.spi.deployment.uri.scanners.ftp;
-
-import org.apache.ignite.internal.util.tostring.*;
-import org.apache.ignite.internal.util.typedef.internal.*;
-
-/**
- * URI FTP deployment configuration.
- */
-class GridUriDeploymentFtpConfiguration {
-    /** */
-    private static final String DFLT_DIR = "/";
-
-    /** */
-    private String host;
-
-    /** */
-    private int port = 21;
-
-    /** */
-    private String username;
-
-    /** */
-    @GridToStringExclude private String pswd;
-
-    /** */
-    private String dir = DFLT_DIR;
-
-    /**
-     * @return Host.
-     */
-    String getHost() { return host; }
-
-    /**
-     * @param host FTP host.
-     */
-    void setHost(String host) {
-        assert host != null;
-
-        this.host = host;
-    }
-
-    /**
-     * @return Port.
-     */
-    int getPort() { return port; }
-
-    /**
-     * @param port FTP port.
-     */
-    void setPort(int port) {
-        assert port > 0;
-
-        this.port = port;
-    }
-
-    /**
-     * @return Username.
-     */
-    String getUsername() { return username; }
-
-    /**
-     * @param username FTP username.
-     */
-    void setUsername(String username) {
-        assert username != null;
-
-        this.username = username;
-    }
-
-    /**
-     * @return Password.
-     */
-    String getPassword() { return pswd; }
-
-    /**
-     * @param pswd FTP password.
-     */
-    void setPassword(String pswd) {
-        assert pswd != null;
-
-        this.pswd = pswd;
-    }
-
-    /**
-     * @return Directory.
-     */
-    String getDirectory() { return dir; }
-
-    /**
-     * @param dir FTP remote directory.
-     */
-    void setDirectory(String dir) { this.dir = dir == null ? DFLT_DIR : dir; }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return S.toString(GridUriDeploymentFtpConfiguration.class, this);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpException.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpException.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpException.java
deleted file mode 100644
index cc046a8..0000000
--- 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.spi.deployment.uri.scanners.ftp;
-
-import org.apache.ignite.*;
-
-/**
- * An exception occurred during URI FTP deployment.
- */
-class GridUriDeploymentFtpException extends IgniteCheckedException {
-    /** */
-    private static final long serialVersionUID = 0L;
-
-    /**
-     * Creates new grid exception with given error message.
-     *
-     * @param msg Error message.
-     */
-    GridUriDeploymentFtpException(String msg) { super(msg); }
-
-    /**
-     * Creates new grid ftp client exception with given error message and 
optional nested exception.
-     *
-     * @param msg Error message.
-     * @param cause Optional nested exception (can be {@code null}).
-     */
-    GridUriDeploymentFtpException(String msg, Throwable cause) { super(msg, 
cause); }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/0391d27c/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpFile.java
----------------------------------------------------------------------
diff --git 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpFile.java
 
b/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpFile.java
deleted file mode 100644
index 90e941f..0000000
--- 
a/modules/urideploy/src/main/java/org/apache/ignite/spi/deployment/uri/scanners/ftp/GridUriDeploymentFtpFile.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.spi.deployment.uri.scanners.ftp;
-
-import com.enterprisedt.net.ftp.*;
-import org.apache.ignite.internal.util.typedef.internal.*;
-
-import java.util.*;
-
-/**
- * Value object which encapsulates {@link FTPFile} and corresponding directory.
- */
-class GridUriDeploymentFtpFile {
-    /** */
-    private final String dir;
-
-    /** */
-    private final FTPFile file;
-
-    /**
-     * @param dir Remote FTP directory.
-     * @param file FTP file.
-     */
-    GridUriDeploymentFtpFile(String dir, FTPFile file) {
-        assert dir != null;
-        assert file != null;
-        assert file.getName() != null;
-
-        this.dir = dir;
-        this.file = file;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-
-        if (!(obj instanceof GridUriDeploymentFtpFile))
-            return false;
-
-        GridUriDeploymentFtpFile other = (GridUriDeploymentFtpFile)obj;
-
-        return dir.equals(other.dir) && 
file.getName().equals(other.file.getName());
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        int res = dir.hashCode();
-
-        res = 29 * res + file.getName().hashCode();
-
-        return res;
-    }
-
-    /**
-     * @return File name.
-     */
-    String getName() {
-        return file.getName();
-    }
-
-    /**
-     * @return Last modification date as calendar.
-     */
-    Calendar getTimestamp() {
-        Date date = file.lastModified();
-
-        Calendar cal = null;
-
-        if (date != null) {
-            cal = Calendar.getInstance();
-
-            cal.setTime(date);
-        }
-
-        return cal;
-    }
-
-    /**
-     * @return {@code True} in case provided file is a directory.
-     */
-    boolean isDirectory() {
-        return file.isDir();
-    }
-
-    /**
-     * @return {@code True} in case provided file is not a directory or link.
-     */
-    boolean isFile() {
-        return !file.isDir() && !file.isLink();
-    }
-
-    /**
-     * @return File parent directory.
-     */
-    String getParentDirectory() {
-        return dir;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return S.toString(GridUriDeploymentFtpFile.class, this);
-    }
-}

Reply via email to