Author: davsclaus Date: Fri Dec 17 09:34:32 2010 New Revision: 1050327 URL: http://svn.apache.org/viewvc?rev=1050327&view=rev Log: CAMEL-3369: Added writing done file to file/ftp producer.
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FilerProducerDoneFileNameTest.java - copied, changed from r1050275, camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FilerProducerFileNamesTest.java camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerDoneFileNameTest.java Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java camel/trunk/camel-core/src/test/java/org/apache/camel/model/StartingRoutesErrorReportedTest.java Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java?rev=1050327&r1=1050326&r2=1050327&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java Fri Dec 17 09:34:32 2010 @@ -86,6 +86,7 @@ public abstract class GenericFileEndpoin protected long readLockTimeout = 10000; protected GenericFileExclusiveReadLockStrategy<T> exclusiveReadLockStrategy; protected boolean keepLastModified; + protected String doneFileName; public GenericFileEndpoint() { } @@ -278,6 +279,19 @@ public abstract class GenericFileEndpoin this.fileName = createFileLanguageExpression(fileLanguageExpression); } + public String getDoneFileName() { + return doneFileName; + } + + /** + * Sets the done file name. + * <p/> + * Only ${file.name} and ${file.name.noext} is supported as dynamic placeholders. + */ + public void setDoneFileName(String doneFileName) { + this.doneFileName = doneFileName; + } + public Boolean isIdempotent() { return idempotent != null ? idempotent : false; } Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java?rev=1050327&r1=1050326&r2=1050327&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java Fri Dec 17 09:34:32 2010 @@ -17,16 +17,16 @@ package org.apache.camel.component.file; import java.io.File; -import java.io.InputStream; import org.apache.camel.Exchange; import org.apache.camel.Expression; +import org.apache.camel.ExpressionIllegalSyntaxException; +import org.apache.camel.impl.DefaultExchange; import org.apache.camel.impl.DefaultProducer; import org.apache.camel.language.simple.SimpleLanguage; import org.apache.camel.spi.Language; import org.apache.camel.util.ExchangeHelper; import org.apache.camel.util.FileUtil; -import org.apache.camel.util.IOHelper; import org.apache.camel.util.ObjectHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -164,6 +164,27 @@ public class GenericFileProducer<T> exte } } + // any done file to write? + if (endpoint.getDoneFileName() != null) { + String doneFileName = createDoneName(target); + ObjectHelper.notEmpty(doneFileName, "doneFileName", endpoint); + + // create empty exchange with empty body to write as the done file + Exchange empty = new DefaultExchange(exchange); + empty.getIn().setBody(""); + + if (log.isTraceEnabled()) { + log.trace("Writing done file: [" + doneFileName + "]"); + } + // delete any existing done file + if (operations.existsFile(doneFileName)) { + if (!operations.deleteFile(doneFileName)) { + throw new GenericFileOperationFailedException("Cannot delete existing done file: " + doneFileName); + } + } + writeFile(empty, doneFileName); + } + // lets store the name we really used in the header, so end-users // can retrieve it exchange.getIn().setHeader(Exchange.FILE_NAME_PRODUCED, target); @@ -314,4 +335,28 @@ public class GenericFileProducer<T> exte } } + public String createDoneName(String fileName) { + String pattern = endpoint.getDoneFileName(); + ObjectHelper.notEmpty(pattern, "doneFileName", endpoint); + + // we only support ${file:name} or ${file:name.noext} as dynamic placeholders for done files + String path = FileUtil.onlyPath(fileName); + String onlyName = FileUtil.stripPath(fileName); + + pattern = pattern.replaceFirst("\\$\\{file:name\\}", onlyName); + pattern = pattern.replaceFirst("\\$\\{file:name.noext\\}", FileUtil.stripExt(onlyName)); + + // must be able to resolve all placeholders supported + if (SimpleLanguage.hasStartToken(pattern)) { + throw new ExpressionIllegalSyntaxException(fileName + ". Cannot resolve reminder: " + pattern); + } + + // done file must always be in same directory as the real file name + if (ObjectHelper.isNotEmpty(pattern)) { + return path + File.separator + pattern; + } else { + return pattern; + } + } + } Copied: camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FilerProducerDoneFileNameTest.java (from r1050275, camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FilerProducerFileNamesTest.java) URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FilerProducerDoneFileNameTest.java?p2=camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FilerProducerDoneFileNameTest.java&p1=camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FilerProducerFileNamesTest.java&r1=1050275&r2=1050327&rev=1050327&view=diff ============================================================================== --- camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FilerProducerFileNamesTest.java (original) +++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FilerProducerDoneFileNameTest.java Fri Dec 17 09:34:32 2010 @@ -18,46 +18,84 @@ package org.apache.camel.component.file; import java.io.File; +import org.apache.camel.CamelExecutionException; import org.apache.camel.ContextTestSupport; -import org.apache.camel.Endpoint; import org.apache.camel.Exchange; -import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.ExpressionIllegalSyntaxException; /** - * Unit test for the how FileProducer behaves a bit strangely when generating filenames + * Unit test for writing done files */ -public class FilerProducerFileNamesTest extends ContextTestSupport { +public class FilerProducerDoneFileNameTest extends ContextTestSupport { - // START SNIPPET: e1 - public void testProducerWithMessageIdAsFileName() throws Exception { - Endpoint endpoint = context.getEndpoint("direct:report"); - Exchange exchange = endpoint.createExchange(); - exchange.getIn().setBody("This is a good report"); + @Override + protected void setUp() throws Exception { + deleteDirectory("target/done"); + super.setUp(); + } + + public void testProducerConstantDoneFileName() throws Exception { + template.sendBodyAndHeader("file:target/done?doneFileName=done", "Hello World", Exchange.FILE_NAME, "hello.txt"); + + File file = new File("target/done/hello.txt").getAbsoluteFile(); + assertEquals("File should exists", true, file.exists()); + + File done = new File("target/done/done").getAbsoluteFile(); + assertEquals("Done file should exists", true, done.exists()); + } + + public void testProducerPrefixDoneFileName() throws Exception { + template.sendBodyAndHeader("file:target/done?doneFileName=done-${file:name}", "Hello World", Exchange.FILE_NAME, "hello.txt"); + + File file = new File("target/done/hello.txt").getAbsoluteFile(); + assertEquals("File should exists", true, file.exists()); - FileEndpoint fileEndpoint = resolveMandatoryEndpoint("file:target/reports/report.txt", FileEndpoint.class); - String id = fileEndpoint.getGeneratedFileName(exchange.getIn()); + File done = new File("target/done/done-hello.txt").getAbsoluteFile(); + assertEquals("Done file should exists", true, done.exists()); + } - template.send("direct:report", exchange); + public void testProducerExtDoneFileName() throws Exception { + template.sendBodyAndHeader("file:target/done?doneFileName=${file:name}.done", "Hello World", Exchange.FILE_NAME, "hello.txt"); - File file = new File("target/reports/" + id).getAbsoluteFile(); + File file = new File("target/done/hello.txt").getAbsoluteFile(); assertEquals("File should exists", true, file.exists()); + + File done = new File("target/done/hello.txt.done").getAbsoluteFile(); + assertEquals("Done file should exists", true, done.exists()); } - public void testProducerWithHeaderFileName() throws Exception { - template.sendBody("direct:report2", "This is super good report"); - File file = new File("target/report-super.txt").getAbsoluteFile(); + public void testProducerReplaceExtDoneFileName() throws Exception { + template.sendBodyAndHeader("file:target/done?doneFileName=${file:name.noext}.done", "Hello World", Exchange.FILE_NAME, "hello.txt"); + + File file = new File("target/done/hello.txt").getAbsoluteFile(); assertEquals("File should exists", true, file.exists()); + + File done = new File("target/done/hello.done").getAbsoluteFile(); + assertEquals("Done file should exists", true, done.exists()); + } + + public void testProducerInvalidDoneFileName() throws Exception { + try { + template.sendBodyAndHeader("file:target/done?doneFileName=${file:parent}/foo", "Hello World", Exchange.FILE_NAME, "hello.txt"); + fail("Should have thrown exception"); + } catch (CamelExecutionException e) { + ExpressionIllegalSyntaxException cause = assertIsInstanceOf(ExpressionIllegalSyntaxException.class, e.getCause()); + assertTrue(cause.getMessage(), cause.getMessage().endsWith("Cannot resolve reminder: ${file:parent}/foo")); + } } - protected RouteBuilder createRouteBuilder() throws Exception { - return new RouteBuilder() { - public void configure() throws Exception { - from("direct:report").to("file:target/reports/"); - - from("direct:report2").setHeader(Exchange.FILE_NAME, constant("report-super.txt")).to("file:target/"); - } - }; + public void testProducerEmptyDoneFileName() throws Exception { + try { + template.sendBodyAndHeader("file:target/done?doneFileName=", "Hello World", Exchange.FILE_NAME, "hello.txt"); + fail("Should have thrown exception"); + } catch (CamelExecutionException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertTrue(cause.getMessage(), cause.getMessage().startsWith("doneFileName must be specified and not empty")); + } } - // END SNIPPET: e1 + @Override + public boolean isUseRouteBuilder() { + return false; + } } Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/model/StartingRoutesErrorReportedTest.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/model/StartingRoutesErrorReportedTest.java?rev=1050327&r1=1050326&r2=1050327&view=diff ============================================================================== --- camel/trunk/camel-core/src/test/java/org/apache/camel/model/StartingRoutesErrorReportedTest.java (original) +++ camel/trunk/camel-core/src/test/java/org/apache/camel/model/StartingRoutesErrorReportedTest.java Fri Dec 17 09:34:32 2010 @@ -36,7 +36,7 @@ public class StartingRoutesErrorReported context.start(); fail(); } catch (FailedToCreateRouteException e) { - assertTrue(e.getMessage().startsWith("Failed to create route route1: Route[[From[direct:start?foo=bar]] -> [To[mock:result]]] because of")); + assertTrue(e.getMessage().startsWith("Failed to create route route1: Route[[From[direct:start?foo=bar]]")); } } @@ -51,7 +51,7 @@ public class StartingRoutesErrorReported context.start(); fail(); } catch (FailedToCreateRouteException e) { - assertTrue(e.getMessage(), e.getMessage().startsWith("Failed to create route route2 at: >>> To[mock:result?foo=bar] <<< in route: Route[[From[direct://start]] -> [To[mock:result?foo=bar]]] because of")); + assertTrue(e.getMessage(), e.getMessage().startsWith("Failed to create route route2 at: >>> To[mock:result?foo=bar]")); } } Added: camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerDoneFileNameTest.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerDoneFileNameTest.java?rev=1050327&view=auto ============================================================================== --- camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerDoneFileNameTest.java (added) +++ camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerDoneFileNameTest.java Fri Dec 17 09:34:32 2010 @@ -0,0 +1,105 @@ +/** + * 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.CamelExecutionException; +import org.apache.camel.Exchange; +import org.apache.camel.ExpressionIllegalSyntaxException; +import org.junit.Test; + +/** + * @version $Revision$ + */ +public class FtpProducerDoneFileNameTest extends FtpServerTestSupport { + + private String getFtpUrl() { + return "ftp://ad...@localhost:" + getPort() + "/done?password=admin"; + } + + @Test + public void testProducerConstantDoneFileName() throws Exception { + template.sendBodyAndHeader(getFtpUrl() + "&doneFileName=done", "Hello World", Exchange.FILE_NAME, "hello.txt"); + + File file = new File(FTP_ROOT_DIR + "done/hello.txt").getAbsoluteFile(); + assertEquals("File should exists", true, file.exists()); + + File done = new File(FTP_ROOT_DIR + "done/done").getAbsoluteFile(); + assertEquals("Done file should exists", true, done.exists()); + } + + @Test + public void testProducerPrefixDoneFileName() throws Exception { + template.sendBodyAndHeader(getFtpUrl() + "&doneFileName=done-${file:name}", "Hello World", Exchange.FILE_NAME, "hello.txt"); + + File file = new File(FTP_ROOT_DIR + "done/hello.txt").getAbsoluteFile(); + assertEquals("File should exists", true, file.exists()); + + File done = new File(FTP_ROOT_DIR + "done/done-hello.txt").getAbsoluteFile(); + assertEquals("Done file should exists", true, done.exists()); + } + + @Test + public void testProducerExtDoneFileName() throws Exception { + template.sendBodyAndHeader(getFtpUrl() + "&doneFileName=${file:name}.done", "Hello World", Exchange.FILE_NAME, "hello.txt"); + + File file = new File(FTP_ROOT_DIR + "done/hello.txt").getAbsoluteFile(); + assertEquals("File should exists", true, file.exists()); + + File done = new File(FTP_ROOT_DIR + "done/hello.txt.done").getAbsoluteFile(); + assertEquals("Done file should exists", true, done.exists()); + } + + @Test + public void testProducerReplaceExtDoneFileName() throws Exception { + template.sendBodyAndHeader(getFtpUrl() + "&doneFileName=${file:name.noext}.done", "Hello World", Exchange.FILE_NAME, "hello.txt"); + + File file = new File(FTP_ROOT_DIR + "done/hello.txt").getAbsoluteFile(); + assertEquals("File should exists", true, file.exists()); + + File done = new File(FTP_ROOT_DIR + "done/hello.done").getAbsoluteFile(); + assertEquals("Done file should exists", true, done.exists()); + } + + @Test + public void testProducerInvalidDoneFileName() throws Exception { + try { + template.sendBodyAndHeader(getFtpUrl() + "&doneFileName=${file:parent}/foo", "Hello World", Exchange.FILE_NAME, "hello.txt"); + fail("Should have thrown exception"); + } catch (CamelExecutionException e) { + ExpressionIllegalSyntaxException cause = assertIsInstanceOf(ExpressionIllegalSyntaxException.class, e.getCause()); + assertTrue(cause.getMessage(), cause.getMessage().endsWith("Cannot resolve reminder: ${file:parent}/foo")); + } + } + + @Test + public void testProducerEmptyDoneFileName() throws Exception { + try { + template.sendBodyAndHeader(getFtpUrl() + "&doneFileName=", "Hello World", Exchange.FILE_NAME, "hello.txt"); + fail("Should have thrown exception"); + } catch (CamelExecutionException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertTrue(cause.getMessage(), cause.getMessage().startsWith("doneFileName must be specified and not empty")); + } + } + @Override + public boolean isUseRouteBuilder() { + return false; + } + +}