You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2008/09/13 23:08:39 UTC
svn commit: r695030 - in /activemq/camel/trunk/components/camel-ftp/src:
main/java/org/apache/camel/component/file/remote/
test/java/org/apache/camel/component/file/remote/ test/resources/
Author: davsclaus
Date: Sat Sep 13 14:08:39 2008
New Revision: 695030
URL: http://svn.apache.org/viewvc?rev=695030&view=rev
Log:
CAMEL-894: camel-ftp now throws FTPOperationFailedException, for failing operations. All operations should succeed before the consumer will process an Exchange.
Added:
activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpConsumerDeleteNoWritePermissionTest.java (with props)
activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpLoginTest.java
Modified:
activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpConsumer.java
activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperationFailedException.java
activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpProducer.java
activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpUtils.java
activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConsumer.java
activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpProducer.java
activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FromFtpToAsciiFileNoBodyConversionTest.java
activemq/camel/trunk/components/camel-ftp/src/test/resources/users.properties
Modified: activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpConsumer.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpConsumer.java?rev=695030&r1=695029&r2=695030&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpConsumer.java (original)
+++ activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpConsumer.java Sat Sep 13 14:08:39 2008
@@ -29,6 +29,7 @@
private FtpEndpoint endpoint;
private FTPClient client;
+ private boolean loggedIn;
public FtpConsumer(FtpEndpoint endpoint, Processor processor, FTPClient client) {
super(endpoint, processor);
@@ -55,23 +56,29 @@
disconnect();
} catch (Exception e) {
// ignore just log a warning
- log.warn("Exception occured during disconecting from " + remoteServer() + ". "
- + e.getClass().getCanonicalName() + " message: " + e.getMessage());
+ String message = "Could not disconnect from " + remoteServer()
+ + ". Reason: " + client.getReplyString() + ". Code: " + client.getReplyCode();
+ log.warn(message);
}
super.doStop();
}
protected void connectIfNecessary() throws IOException {
- if (!client.isConnected()) {
+ if (!client.isConnected() || !loggedIn) {
if (log.isDebugEnabled()) {
- log.debug("Not connected, connecting to " + remoteServer());
+ log.debug("Not connected/logged in, connecting to " + remoteServer());
+ }
+ loggedIn = FtpUtils.connect(client, endpoint.getConfiguration());
+ if (!loggedIn) {
+ return;
}
- FtpUtils.connect(client, endpoint.getConfiguration());
- log.info("Connected to " + remoteServer());
}
+
+ log.info("Connected and logged in to " + remoteServer());
}
protected void disconnect() throws IOException {
+ loggedIn = false;
log.debug("Disconnecting from " + remoteServer());
FtpUtils.disconnect(client);
}
@@ -80,10 +87,16 @@
if (log.isTraceEnabled()) {
log.trace("Polling " + endpoint.getConfiguration());
}
- connectIfNecessary();
- // If the attempt to connect isn't successful, then the thrown
- // exception will signify that we couldn't poll
+
try {
+ connectIfNecessary();
+
+ if (!loggedIn) {
+ String message = "Could not connect/login to " + endpoint.getConfiguration();
+ log.warn(message);
+ throw new FtpOperationFailedException(client.getReplyCode(), client.getReplyString(), message);
+ }
+
final String fileName = endpoint.getConfiguration().getFile();
if (endpoint.getConfiguration().isDirectory()) {
pollDirectory(fileName);
@@ -97,8 +110,11 @@
final FTPFile[] files = client.listFiles(fileName.substring(index + 1));
pollFile(files[0]);
}
+
lastPollTime = System.currentTimeMillis();
+
} catch (Exception e) {
+ loggedIn = false;
if (isStopping() || isStopped()) {
// if we are stopping then ignore any exception during a poll
log.warn("Consumer is stopping. Ignoring caught exception: "
@@ -187,8 +203,8 @@
}
boolean deleted = client.deleteFile(ftpFile.getName());
if (!deleted) {
- // ignore just log a warning
- log.warn("Can not delete file: " + ftpFile.getName() + " from: " + remoteServer());
+ String message = "Can not delete file: " + ftpFile.getName() + " from: " + remoteServer();
+ throw new FtpOperationFailedException(client.getReplyCode(), client.getReplyString(), message);
}
} else if (isMoveFile()) {
String fromName = ftpFile.getName();
@@ -214,10 +230,12 @@
// try to rename
boolean success = client.rename(fromName, toName);
if (!success) {
- log.warn("Can not move file: " + fromName + " to: " + toName);
+ String message = "Can not move file: " + fromName + " to: " + toName;
+ throw new FtpOperationFailedException(client.getReplyCode(), client.getReplyString(), message);
}
}
+ // all success so lets process it
getProcessor().process(exchange);
}
}
Modified: activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperationFailedException.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperationFailedException.java?rev=695030&r1=695029&r2=695030&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperationFailedException.java (original)
+++ activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperationFailedException.java Sat Sep 13 14:08:39 2008
@@ -19,28 +19,33 @@
import org.apache.camel.RuntimeCamelException;
/**
+ * Exception thrown in case of last FTP operation failed.
+ *
* @version $Revision$
- * @deprecated not used will be removed in Camel 2.0.
*/
public class FtpOperationFailedException extends RuntimeCamelException {
private final int code;
private final String reason;
public FtpOperationFailedException(int code, String reason) {
- super("Ftp operation failed: " + reason + " Code: " + code);
+ super("Ftp operation failed: " + reason + ". Code: " + code);
this.code = code;
this.reason = reason;
}
+ public FtpOperationFailedException(int code, String reason, String message) {
+ this(code, reason + " " + message);
+ }
+
/**
- * Return the failure code
+ * Return the FTP failure code
*/
public int getCode() {
return code;
}
/**
- * Return the failure reason
+ * Return the FTP failure reason
*/
public String getReason() {
return reason;
Modified: activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpProducer.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpProducer.java?rev=695030&r1=695029&r2=695030&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpProducer.java (original)
+++ activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpProducer.java Sat Sep 13 14:08:39 2008
@@ -20,13 +20,13 @@
import java.io.InputStream;
import org.apache.camel.Exchange;
-import org.apache.camel.RuntimeCamelException;
import org.apache.commons.net.ftp.FTPClient;
public class FtpProducer extends RemoteFileProducer<RemoteFileExchange> {
private FtpEndpoint endpoint;
private FTPClient client;
+ private boolean loggedIn;
public FtpProducer(FtpEndpoint endpoint, FTPClient client) {
super(endpoint);
@@ -38,12 +38,19 @@
if (log.isTraceEnabled()) {
log.trace("Processing " + endpoint.getConfiguration());
}
- connectIfNecessary();
- // If the attempt to connect isn't successful, then the thrown
- // exception will signify that we couldn't deliver
+
try {
+ connectIfNecessary();
+
+ if (!loggedIn) {
+ String message = "Could not connect/login to " + endpoint.getConfiguration();
+ log.warn(message);
+ throw new FtpOperationFailedException(client.getReplyCode(), client.getReplyString(), message);
+ }
+
process(endpoint.createExchange(exchange));
} catch (Exception e) {
+ loggedIn = false;
if (isStopping() || isStopped()) {
// if we are stopping then ignore any exception during a poll
log.warn("Producer is stopping. Ignoring caught exception: "
@@ -59,16 +66,21 @@
}
protected void connectIfNecessary() throws IOException {
- if (!client.isConnected()) {
+ if (!client.isConnected() || !loggedIn) {
if (log.isDebugEnabled()) {
- log.debug("Not connected, connecting to " + remoteServer());
+ log.debug("Not connected/logged in, connecting to " + remoteServer());
+ }
+ loggedIn = FtpUtils.connect(client, endpoint.getConfiguration());
+ if (!loggedIn) {
+ return;
}
- FtpUtils.connect(client, endpoint.getConfiguration());
- log.info("Connected to " + remoteServer());
}
+
+ log.info("Connected and logged in to " + remoteServer());
}
public void disconnect() throws IOException {
+ loggedIn = false;
if (log.isDebugEnabled()) {
log.debug("Disconnecting from " + remoteServer());
}
@@ -90,7 +102,8 @@
boolean success = client.storeFile(fileName, payload);
if (!success) {
- throw new RuntimeCamelException("Error sending file: " + fileName + " to: " + remoteServer());
+ String message = "Error sending file: " + fileName + " to: " + remoteServer();
+ throw new FtpOperationFailedException(client.getReplyCode(), client.getReplyString(), message);
}
log.info("Sent: " + fileName + " to: " + remoteServer());
Modified: activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpUtils.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpUtils.java?rev=695030&r1=695029&r2=695030&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpUtils.java (original)
+++ activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpUtils.java Sat Sep 13 14:08:39 2008
@@ -31,18 +31,28 @@
private FtpUtils() {
}
- public static void connect(FTPClient client, RemoteFileConfiguration config) throws IOException {
+ public static boolean connect(FTPClient client, RemoteFileConfiguration config) throws IOException {
String host = config.getHost();
int port = config.getPort();
String username = config.getUsername();
+ LOG.trace("Connecting to " + config);
client.connect(host, port);
+
+ boolean login;
+ LOG.trace("Attempting to login " + username);
if (username != null) {
- client.login(username, config.getPassword());
+ login = client.login(username, config.getPassword());
} else {
- client.login("anonymous", null);
+ login = client.login("anonymous", null);
+ }
+ LOG.trace("User " + username + " logged in: " + login);
+ if (!login) {
+ return false;
}
+
client.setFileType(config.isBinary() ? FTPClient.BINARY_FILE_TYPE : FTPClient.ASCII_FILE_TYPE);
+ return true;
}
public static void disconnect(FTPClient client) throws IOException {
@@ -63,8 +73,8 @@
// maybe the full directory already exsits
success = ftpClient.changeWorkingDirectory(dirName);
if (!success) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Trying to build remote directory: " + dirName);
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Trying to build remote directory: " + dirName);
}
success = ftpClient.makeDirectory(dirName);
if (!success) {
Modified: activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConsumer.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConsumer.java?rev=695030&r1=695029&r2=695030&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConsumer.java (original)
+++ activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConsumer.java Sat Sep 13 14:08:39 2008
@@ -68,11 +68,11 @@
protected void connectIfNecessary() throws JSchException {
if (channel == null || !channel.isConnected()) {
if (session == null || !session.isConnected()) {
- log.debug("Session isn't connected, trying to recreate and connect.");
+ log.trace("Session isn't connected, trying to recreate and connect.");
session = endpoint.createSession();
session.connect();
}
- log.debug("Channel isn't connected, trying to recreate and connect.");
+ log.trace("Channel isn't connected, trying to recreate and connect.");
channel = endpoint.createChannelSftp(session);
channel.connect();
log.info("Connected to " + remoteServer());
@@ -80,9 +80,7 @@
}
protected void disconnect() throws JSchException {
- if (log.isDebugEnabled()) {
- log.debug("Disconnecting from " + remoteServer());
- }
+ log.debug("Disconnecting from " + remoteServer());
if (session != null) {
session.disconnect();
}
Modified: activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpProducer.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpProducer.java?rev=695030&r1=695029&r2=695030&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpProducer.java (original)
+++ activemq/camel/trunk/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpProducer.java Sat Sep 13 14:08:39 2008
@@ -62,11 +62,11 @@
protected void connectIfNecessary() throws JSchException {
if (channel == null || !channel.isConnected()) {
if (session == null || !session.isConnected()) {
- log.debug("Session isn't connected, trying to recreate and connect.");
+ log.trace("Session isn't connected, trying to recreate and connect.");
session = endpoint.createSession();
session.connect();
}
- log.debug("Channel isn't connected, trying to recreate and connect.");
+ log.trace("Channel isn't connected, trying to recreate and connect.");
channel = endpoint.createChannelSftp(session);
channel.connect();
log.info("Connected to " + endpoint.getConfiguration().remoteServerInformation());
Modified: activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FromFtpToAsciiFileNoBodyConversionTest.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FromFtpToAsciiFileNoBodyConversionTest.java?rev=695030&r1=695029&r2=695030&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FromFtpToAsciiFileNoBodyConversionTest.java (original)
+++ activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FromFtpToAsciiFileNoBodyConversionTest.java Sat Sep 13 14:08:39 2008
@@ -33,7 +33,6 @@
private String ftpUrl = "ftp://admin@localhost:" + port + "/tmp5/camel?password=admin&binary=false";
public void testFromFtpToAsciiFileNoBodyConversion() throws Exception {
-
MockEndpoint resultEndpoint = getMockEndpoint("mock:result");
resultEndpoint.expectedMinimumMessageCount(1);
resultEndpoint.expectedBodiesReceived("Hello ASCII from FTPServer");
Added: activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpConsumerDeleteNoWritePermissionTest.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpConsumerDeleteNoWritePermissionTest.java?rev=695030&view=auto
==============================================================================
--- activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpConsumerDeleteNoWritePermissionTest.java (added)
+++ activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpConsumerDeleteNoWritePermissionTest.java Sat Sep 13 14:08:39 2008
@@ -0,0 +1,58 @@
+/**
+ * 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.camel.component.file.remote;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.PollingConsumer;
+import org.apache.camel.component.file.FileComponent;
+
+/**
+ * User does not have write permissions so can't deleted consumed file.
+ */
+public class FtpConsumerDeleteNoWritePermissionTest extends FtpServerTestSupport {
+
+ private int port = 20087;
+
+ private String ftpUrl = "ftp://dummy@localhost:" + port + "/deletenoperm?password=foo"
+ + "&consumer.deleteFile=true";
+
+ public void testExludePreAndPostfixes() throws Exception {
+ PollingConsumer consumer = context.getEndpoint(ftpUrl).createPollingConsumer();
+ consumer.start();
+ Exchange out = consumer.receive(3000);
+ assertNull("Should not get the file", out);
+ consumer.stop();
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ prepareFtpServer();
+ }
+
+ private void prepareFtpServer() throws Exception {
+ // prepares the FTP Server by creating files on the server that we want to unit
+ // test that we can pool and store as a local file
+ String ftpUrl = "ftp://admin@localhost:" + port + "/deletenoperm/?password=admin";
+ template.sendBodyAndHeader(ftpUrl, "Hello World", FileComponent.HEADER_FILE_NAME, "hello.txt");
+ }
+
+}
\ No newline at end of file
Propchange: activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpConsumerDeleteNoWritePermissionTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpConsumerDeleteNoWritePermissionTest.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpLoginTest.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpLoginTest.java?rev=695030&view=auto
==============================================================================
--- activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpLoginTest.java (added)
+++ activemq/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpLoginTest.java Sat Sep 13 14:08:39 2008
@@ -0,0 +1,95 @@
+/**
+ * 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.camel.component.file.remote;
+
+import java.io.File;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Producer;
+import org.apache.camel.component.file.FileComponent;
+
+/**
+ * Unit test for login failure due bad password and login with accepted password
+ */
+public class FtpLoginTest extends FtpServerTestSupport {
+
+ private int port = 20077;
+ private String ftpUrl = "ftp://dummy@localhost:" + port;
+
+ public int getPort() {
+ return port;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ deleteDirectory("./res/home/login");
+ }
+
+ public void testBadLogin() throws Exception {
+ try {
+ uploadFile("dummy", "cantremeber");
+ fail("Should have thrown a FtpOperationFailedException");
+ } catch (FtpOperationFailedException e) {
+ // expected
+ assertEquals(530, e.getCode());
+ }
+
+ // assert file NOT created
+ File file = new File("./res/home/login/report.txt");
+ file = file.getAbsoluteFile();
+ assertFalse("The file should NOT exists", file.exists());
+ }
+
+ public void testGoodLogin() throws Exception {
+ uploadFile("scott", "tiger");
+
+ // give time for producer
+ Thread.sleep(2000);
+
+ // assert file created
+ File file = new File("./res/home/login/report.txt");
+ file = file.getAbsoluteFile();
+ assertTrue("The file should exists", file.exists());
+ }
+
+ private void uploadFile(String username, String password) throws Exception {
+ RemoteFileConfiguration config = new RemoteFileConfiguration();
+ config.setBinary(false);
+ config.setUsername(username);
+ config.setPassword(password);
+ config.setDirectory(true);
+ config.setHost("localhost");
+ config.setPort(port);
+ config.setProtocol("ftp");
+ config.setFile("login");
+
+ RemoteFileComponent component = new RemoteFileComponent(context);
+ component.setConfiguration(config);
+
+ RemoteFileEndpoint endpoint = new FtpEndpoint(ftpUrl, component, config);
+
+ Exchange exchange = endpoint.createExchange();
+ exchange.getIn().setBody("Hello World from FTPServer");
+ exchange.getIn().setHeader(FileComponent.HEADER_FILE_NAME, "report.txt");
+ Producer producer = endpoint.createProducer();
+ producer.start();
+ producer.process(exchange);
+ producer.stop();
+ }
+
+}
Modified: activemq/camel/trunk/components/camel-ftp/src/test/resources/users.properties
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-ftp/src/test/resources/users.properties?rev=695030&r1=695029&r2=695030&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-ftp/src/test/resources/users.properties (original)
+++ activemq/camel/trunk/components/camel-ftp/src/test/resources/users.properties Sat Sep 13 14:08:39 2008
@@ -5,4 +5,8 @@
ftpserver.user.scott
ftpserver.user.scott.userpassword=tiger
ftpserver.user.scott.homedirectory=./res/home
-ftpserver.user.scott.writepermission=true
\ No newline at end of file
+ftpserver.user.scott.writepermission=true
+ftpserver.user.dummy
+ftpserver.user.dummy.userpassword=foo
+ftpserver.user.dummy.homedirectory=./res/home
+ftpserver.user.dummy.writepermission=false