diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java index 88f1e4b437..b1d2a12086 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java @@ -16,8 +16,6 @@ package org.springframework.integration.file.config; -import org.w3c.dom.Element; - import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; @@ -25,53 +23,76 @@ import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; /** * Parser for the <inbound-channel-adapter> element of the 'file' namespace. - * + * * @author Iwein Fuld * @author Mark Fisher */ public class FileInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser { - private static final String PACKAGE_NAME = "org.springframework.integration.file"; + private static final String PACKAGE_NAME = "org.springframework.integration.file"; - @Override - protected String parseSource(Element element, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( - PACKAGE_NAME + ".config.FileReadingMessageSourceFactoryBean"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "comparator"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "scanner"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "directory"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-create-directory"); - String filterBeanName = this.registerFileListFilter(element, parserContext); - builder.addPropertyReference("filter", filterBeanName); - return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry()); - } + @Override + protected String parseSource(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( + PACKAGE_NAME + ".config.FileReadingMessageSourceFactoryBean"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "comparator"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "scanner"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "directory"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-create-directory"); + String filterBeanName = this.registerFilter(element, parserContext); + String lockerBeanName = registerLocker(element, parserContext); + if (lockerBeanName != null) { + builder.addPropertyReference("locker", lockerBeanName); + } + builder.addPropertyReference("filter", filterBeanName); + return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry()); + } - private String registerFileListFilter(Element element, ParserContext parserContext) { - BeanDefinitionBuilder factoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition( - PACKAGE_NAME + ".config.FileListFilterFactoryBean"); - factoryBeanBuilder.setRole(BeanDefinition.ROLE_SUPPORT); - String filter = element.getAttribute("filter"); - if (StringUtils.hasText(filter)) { - factoryBeanBuilder.addPropertyReference("filterReference", filter); - } - String filenamePattern = element.getAttribute("filename-pattern"); - if (StringUtils.hasText(filenamePattern)) { - if (StringUtils.hasText(filter)) { - parserContext.getReaderContext().error( - "At most one of 'filter' and 'filename-pattern' may be provided.", element); - } - factoryBeanBuilder.addPropertyValue("filenamePattern", filenamePattern); - } - String preventDuplicates = element.getAttribute("prevent-duplicates"); - if (StringUtils.hasText(preventDuplicates)) { - factoryBeanBuilder.addPropertyValue("preventDuplicates", preventDuplicates); - } - return BeanDefinitionReaderUtils.registerWithGeneratedName( - factoryBeanBuilder.getBeanDefinition(), parserContext.getRegistry()); - } + private String registerLocker(Element element, ParserContext parserContext) { + String lockerBeanName = null; + Element nioLocker = DomUtils.getChildElementByTagName(element, "nio-locker"); + if (nioLocker != null) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder + .genericBeanDefinition(PACKAGE_NAME + ".locking.NioFileLocker"); + lockerBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), + parserContext.getRegistry()); + } else { + Element locker = DomUtils.getChildElementByTagName(element, "locker"); + if (locker != null) { + lockerBeanName = locker.getAttribute("ref"); + } + } + return lockerBeanName; + } + + private String registerFilter(Element element, ParserContext parserContext) { + BeanDefinitionBuilder factoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition( + PACKAGE_NAME + ".config.FileListFilterFactoryBean"); + factoryBeanBuilder.setRole(BeanDefinition.ROLE_SUPPORT); + String filter = element.getAttribute("filter"); + if (StringUtils.hasText(filter)) { + factoryBeanBuilder.addPropertyReference("filterReference", filter); + } + String filenamePattern = element.getAttribute("filename-pattern"); + if (StringUtils.hasText(filenamePattern)) { + if (StringUtils.hasText(filter)) { + parserContext.getReaderContext().error( + "At most one of 'filter' and 'filename-pattern' may be provided.", element); + } + factoryBeanBuilder.addPropertyValue("filenamePattern", filenamePattern); + } + String preventDuplicates = element.getAttribute("prevent-duplicates"); + if (StringUtils.hasText(preventDuplicates)) { + factoryBeanBuilder.addPropertyValue("preventDuplicates", preventDuplicates); + } + return BeanDefinitionReaderUtils.registerWithGeneratedName( + factoryBeanBuilder.getBeanDefinition(), parserContext.getRegistry()); + } } diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileReadingMessageSourceFactoryBean.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileReadingMessageSourceFactoryBean.java index 0ec6668ba1..6504d3cf63 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileReadingMessageSourceFactoryBean.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileReadingMessageSourceFactoryBean.java @@ -17,11 +17,11 @@ package org.springframework.integration.file.config; import org.springframework.beans.factory.FactoryBean; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.core.io.ResourceLoader; +import org.springframework.integration.file.CompositeFileListFilter; import org.springframework.integration.file.DirectoryScanner; import org.springframework.integration.file.FileListFilter; import org.springframework.integration.file.FileReadingMessageSource; +import org.springframework.integration.file.locking.BaseLockingFilter; import java.io.File; import java.util.Comparator; @@ -31,92 +31,96 @@ import java.util.Comparator; * @author Iwein Fuld * @since 1.0.3 */ -public class FileReadingMessageSourceFactoryBean implements FactoryBean, ResourceLoaderAware { +public class FileReadingMessageSourceFactoryBean implements FactoryBean { - private volatile FileReadingMessageSource source; + private volatile FileReadingMessageSource source; - private volatile ResourceLoader resourceLoader; + private volatile File directory; - private volatile File directory; + private volatile FileListFilter filter; - private volatile FileListFilter filter; + private volatile BaseLockingFilter locker; - private volatile Comparator comparator; + private volatile Comparator comparator; private volatile DirectoryScanner scanner; - private volatile Boolean scanEachPoll; + private volatile Boolean scanEachPoll; - private volatile Boolean autoCreateDirectory; + private volatile Boolean autoCreateDirectory; - private final Object initializationMonitor = new Object(); + private final Object initializationMonitor = new Object(); + public void setDirectory(File directory) { + this.directory = directory; + } - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - public void setDirectory(File directory) { - this.directory = directory; - } - - public void setComparator(Comparator comparator) { - this.comparator = comparator; - } + public void setComparator(Comparator comparator) { + this.comparator = comparator; + } public void setScanner(DirectoryScanner scanner) { this.scanner = scanner; } public void setFilter(FileListFilter filter) { - this.filter = filter; - } + this.filter = filter; + } - public void setScanEachPoll(Boolean scanEachPoll) { - this.scanEachPoll = scanEachPoll; - } + public void setScanEachPoll(Boolean scanEachPoll) { + this.scanEachPoll = scanEachPoll; + } - public void setAutoCreateDirectory(Boolean autoCreateDirectory) { - this.autoCreateDirectory = autoCreateDirectory; - } + public void setAutoCreateDirectory(Boolean autoCreateDirectory) { + this.autoCreateDirectory = autoCreateDirectory; + } - public Object getObject() throws Exception { - if (this.source == null) { - initSource(); - } - return this.source; - } + public void setLocker(BaseLockingFilter locker) { + this.locker = locker; + } - public Class getObjectType() { - return FileReadingMessageSource.class; - } + public Object getObject() throws Exception { + if (this.source == null) { + initSource(); + } + return this.source; + } - public boolean isSingleton() { - return true; - } + public Class getObjectType() { + return FileReadingMessageSource.class; + } - private void initSource() { - synchronized (this.initializationMonitor) { - if (this.source != null) { - return; - } - this.source = (this.comparator != null) ? - new FileReadingMessageSource(this.comparator) : new FileReadingMessageSource(); - this.source.setDirectory(this.directory); - if (this.filter != null) { - this.source.setFilter(this.filter); - } - if (this.scanEachPoll != null) { - this.source.setScanEachPoll(this.scanEachPoll); - } - if (this.autoCreateDirectory != null) { - this.source.setAutoCreateDirectory(this.autoCreateDirectory); - } + public boolean isSingleton() { + return true; + } + + private void initSource() { + synchronized (this.initializationMonitor) { + if (this.source != null) { + return; + } + this.source = (this.comparator != null) ? + new FileReadingMessageSource(this.comparator) : new FileReadingMessageSource(); + this.source.setDirectory(this.directory); + if (this.filter != null) { + if (this.locker == null) { + this.source.setFilter(this.filter); + } else { + this.source.setFilter(new CompositeFileListFilter(this.filter, this.locker)); + this.source.setLocker(locker); + } + } + if (this.scanEachPoll != null) { + this.source.setScanEachPoll(this.scanEachPoll); + } + if (this.autoCreateDirectory != null) { + this.source.setAutoCreateDirectory(this.autoCreateDirectory); + } if (this.scanner != null) { this.source.setScanner(this.scanner); } - this.source.afterPropertiesSet(); - } - } + this.source.afterPropertiesSet(); + } + } } diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/BaseLockingFilter.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/BaseLockingFilter.java new file mode 100644 index 0000000000..efcb72039f --- /dev/null +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/BaseLockingFilter.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed 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.springframework.integration.file.locking; + +import org.springframework.integration.file.AbstractFileListFilter; + +import java.io.File; + +/** + * Convenience base class for implementing FileLockers that acquires a lock upon accepting a file. This is required + * when used in combination with a FileReadingMessageSource. + * + * @author Iwein Fuld + * @since 2.0 + * + */ +public abstract class BaseLockingFilter extends AbstractFileListFilter implements FileLocker { + + protected final boolean accept(File file) { + return lock(file); + } +} \ No newline at end of file diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/FileChannelCache.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/FileChannelCache.java index acacba9394..5aa7be4a95 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/FileChannelCache.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/FileChannelCache.java @@ -26,6 +26,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** + * Static cache of FileLocks that can be used to ensure that only a single lock is used inside this ClassLoader. + * * @author Iwein Fuld * @since 2.0 */ @@ -38,7 +40,7 @@ final class FileChannelCache { * Try to get a lock for this file while guaranteeing that the same channel will be used for all file locks in this * VM. If the lock could not be acquired this method will return null. *

- * Locks acquired through this method should be passed back to #closeChannelFor to prevent memory leak. + * Locks acquired through this method should be passed back to #closeChannelFor to prevent memory leaks. *

* Thread safe. */ diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/LockFileFileListFilter.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/LockFileFileListFilter.java deleted file mode 100644 index b07c3cbf2d..0000000000 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/LockFileFileListFilter.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed 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.springframework.integration.file.locking; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.integration.file.AbstractFileListFilter; -import org.springframework.util.Assert; - -import java.io.File; -import java.io.IOException; - -/** - * LockFileFileListFilter keeps track of the files it should pick up by adding lock files in a directory. If this - * directory is the same as the directory of the original files additional precautions need to be taken to avoid - * treating the lock files as normal input. - * - * If different LockFileFileListFilters share their lock directory they are unlikely to pass the same file. - * - * @author Iwein Fuld - * @since 2.0 - */ -public class LockFileFileListFilter extends AbstractFileListFilter implements FileLocker{ - - private static final Log logger = LogFactory.getLog(LockFileFileListFilter.class); - - private static final String LOCK_SUFFIX = ".lock"; - - private static final String PRELOCK_SUFFIX = ".prelock"; - - private File workdir; - - public LockFileFileListFilter(File workdir) { - Assert.notNull(workdir, "Work directory must not be null."); - Assert.isTrue(workdir.isDirectory(), "Work directory must be a directory."); - Assert.isTrue(workdir.canWrite(), "Work directory must be write accessible."); - this.workdir = workdir; - } - - protected boolean accept(File file) { - File lockFile = new File(workdir, file.getName() + LOCK_SUFFIX); - File preLockFile = new File(workdir, file.getName() + PRELOCK_SUFFIX); - if (lockFile.exists() || preLockFile.exists()) { - return false; - } - String name = file.getName(); - return !name.endsWith(LOCK_SUFFIX) && !name.endsWith(PRELOCK_SUFFIX); - } - - /** - * Makes a best effort attempt at locking the file atomically. - * - * The locking mechanism will create a prelock file and move it to a lock - * file location. - */ - public boolean lock(File fileToLock) { - File lockFile = new File(workdir, fileToLock.getName() + LOCK_SUFFIX); - File preLockFile = new File(workdir, fileToLock.getName() + PRELOCK_SUFFIX); - if (lockFile.exists() || preLockFile.exists()) { - return false; - } - try { - preLockFile.createNewFile(); - } - catch (IOException e) { - logger.warn("Failed to lock file", e); - return false; - } - // there is still a small chance that the next line will be done concurrently and the file will be picked up twice - if (!lockFile.exists() && preLockFile.renameTo(lockFile)) { - lockFile.deleteOnExit(); - return true; - } - preLockFile.delete(); - logger.warn("Failed to lock file [" + fileToLock + "]"); - return false; - } - - /** - * Deletes the lockFile for this file. - */ - public void unlock(File fileToUnlock) { - File lockFile = new File(workdir, fileToUnlock.getName() + LOCK_SUFFIX); - File preLockFile = new File(workdir, fileToUnlock.getName() + PRELOCK_SUFFIX); - if (!preLockFile.exists()) { - lockFile.delete(); - } - } - -} diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/NioFileLocker.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/NioFileLocker.java index 4d0f591d0a..f874578de7 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/NioFileLocker.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/NioFileLocker.java @@ -16,15 +16,14 @@ package org.springframework.integration.file.locking; -import org.springframework.integration.file.AbstractFileListFilter; -import org.springframework.integration.file.FileReadingMessageSource; import org.springframework.integration.core.MessagingException; +import org.springframework.integration.file.FileReadingMessageSource; import java.io.File; import java.io.IOException; import java.nio.channels.FileLock; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** * File locking strategy that uses java.nio. The locks taken by FileChannel are @@ -41,11 +40,11 @@ import java.util.concurrent.ConcurrentHashMap; * @author Mark Fisher * @since 2.0 */ -public class NioFileLocker extends AbstractFileListFilter implements FileLocker { +public class NioFileLocker extends BaseLockingFilter { private final ConcurrentMap lockCache = new ConcurrentHashMap(); - /** + /** * {@inheritDoc} * */ @@ -79,9 +78,4 @@ public class NioFileLocker extends AbstractFileListFilter implements FileLocker + fileToUnlock, e); } } - - protected boolean accept(File file) { - return this.lock(file); - } - } diff --git a/org.springframework.integration.file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-2.0.xsd b/org.springframework.integration.file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-2.0.xsd index f2d65bcb35..ca74e70772 100644 --- a/org.springframework.integration.file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-2.0.xsd +++ b/org.springframework.integration.file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-2.0.xsd @@ -26,9 +26,13 @@ - + - + + + + + @@ -249,4 +253,20 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/FileOutboundGatewayIntegrationTests-context.xml b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/FileOutboundGatewayIntegrationTests-context.xml index 71a235c46c..ba6d8f44f9 100644 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/FileOutboundGatewayIntegrationTests-context.xml +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/FileOutboundGatewayIntegrationTests-context.xml @@ -5,13 +5,13 @@ xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-2.5.xsd + http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context-2.5.xsd + http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/integration - http://www.springframework.org/schema/integration/spring-integration-1.0.xsd + http://www.springframework.org/schema/integration/spring-integration.xsd http://www.springframework.org/schema/integration/file - http://www.springframework.org/schema/integration/file/spring-integration-file-1.0.xsd"> + http://www.springframework.org/schema/integration/file/spring-integration-file.xsd"> @@ -32,6 +32,7 @@ directory="${java.io.tmpdir}/anyDir" delete-source-files="true"/> - + + diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileListFilterFactoryBeanTests.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileListFilterFactoryBeanTests.java index 491c609e86..c67a6b0b2b 100644 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileListFilterFactoryBeanTests.java +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileListFilterFactoryBeanTests.java @@ -16,23 +16,16 @@ package org.springframework.integration.file.config; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.integration.file.*; import java.io.File; import java.util.Collection; import java.util.Iterator; import java.util.regex.Pattern; -import org.junit.Test; - -import org.springframework.beans.DirectFieldAccessor; -import org.springframework.integration.file.AbstractFileListFilter; -import org.springframework.integration.file.AcceptOnceFileListFilter; -import org.springframework.integration.file.CompositeFileListFilter; -import org.springframework.integration.file.FileListFilter; -import org.springframework.integration.file.PatternMatchingFileListFilter; +import static org.junit.Assert.*; /** * @author Mark Fisher diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingNamespaceTests-context.xml b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingNamespaceTests-context.xml new file mode 100644 index 0000000000..657d110538 --- /dev/null +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingNamespaceTests-context.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingNamespaceTests.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingNamespaceTests.java new file mode 100644 index 0000000000..1abbfc6b84 --- /dev/null +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingNamespaceTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed 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.springframework.integration.file.locking; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.integration.endpoint.SourcePollingChannelAdapter; +import org.springframework.integration.file.CompositeFileListFilter; +import org.springframework.integration.file.FileReadingMessageSource; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.io.File; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * @author Iwein Fuld + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class FileLockingNamespaceTests { + + @Autowired + @Qualifier("nioLockingAdapter.adapter") + SourcePollingChannelAdapter nioAdapter; + + FileReadingMessageSource nioLockingSource; + + @Autowired + @Qualifier("customLockingAdapter.adapter") + SourcePollingChannelAdapter customAdapter; + + FileReadingMessageSource customLockingSource; + + @Before public void extractSources() { + nioLockingSource = (FileReadingMessageSource) new DirectFieldAccessor( nioAdapter).getPropertyValue("source"); + customLockingSource = (FileReadingMessageSource) new DirectFieldAccessor( customAdapter).getPropertyValue("source"); + } + + @Test + public void shouldLoadConfig() { + //verify Spring can load the configuration + } + + @Test + public void shouldSetCustomLockerProperly() { + DirectFieldAccessor accessor = new DirectFieldAccessor(customLockingSource); + assertThat(accessor.getPropertyValue("locker"), is(StubLocker.class)); + assertThat(accessor.getPropertyValue("filter"), is(CompositeFileListFilter.class)); + } + + @Test + public void shouldSetNioLockerProperly() { + DirectFieldAccessor accessor = new DirectFieldAccessor(nioLockingSource); + assertThat(accessor.getPropertyValue("locker"), is(NioFileLocker.class)); + assertThat(accessor.getPropertyValue("filter"), is(CompositeFileListFilter.class)); + } + + public static class StubLocker extends BaseLockingFilter { + public boolean lock(File fileToLock) { + return true; + } + + public void unlock(File fileToUnlock) { + // + } + } +} diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingWithMultipleSourcesIntegrationTests-context.xml b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingWithMultipleSourcesIntegrationTests-context.xml index ff98e8a726..0a36dc2775 100644 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingWithMultipleSourcesIntegrationTests-context.xml +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingWithMultipleSourcesIntegrationTests-context.xml @@ -8,15 +8,18 @@ + p:filter-ref="filter1"/> + + p:filter-ref="filter2"/> - - - - + + + + diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingWithMultipleSourcesIntegrationTests.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingWithMultipleSourcesIntegrationTests.java index f9e4c2ed19..04230bd16e 100644 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingWithMultipleSourcesIntegrationTests.java +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/FileLockingWithMultipleSourcesIntegrationTests.java @@ -15,8 +15,6 @@ */ package org.springframework.integration.file.locking; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertThat; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -24,12 +22,15 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.integration.file.FileReadingMessageSource; -import static org.springframework.integration.test.matcher.PayloadMatcher.hasPayload; import org.springframework.test.context.ContextConfiguration; import java.io.File; import java.io.IOException; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.springframework.integration.test.matcher.PayloadMatcher.hasPayload; + /** * @author Iwein Fuld */ @@ -50,10 +51,15 @@ public class FileLockingWithMultipleSourcesIntegrationTests { @Autowired @Qualifier("fileSource1") private FileReadingMessageSource fileSource1; + @Autowired @Qualifier("fileSource2") private FileReadingMessageSource fileSource2; + @Autowired + @Qualifier("fileSource2") + private FileReadingMessageSource fileSource3; + @Before public void cleanoutWorkDir() { for (File file : workdir.listFiles()) { @@ -62,10 +68,20 @@ public class FileLockingWithMultipleSourcesIntegrationTests { } @Test - public void filePickedUpOnlyOnce() throws IOException { + public void filePickedUpOnceWithDistinctFilters() throws IOException { File testFile = new File(workdir, "test"); testFile.createNewFile(); assertThat(fileSource1.receive(), hasPayload(testFile)); assertThat(fileSource2.receive(), nullValue()); + FileChannelCache.closeChannelFor(testFile); + } + + @Test + public void filePickedUpTwiceWithSharedFilter() throws Exception { + File testFile = new File(workdir, "test"); + testFile.createNewFile(); + assertThat(fileSource1.receive(), hasPayload(testFile)); + assertThat(fileSource3.receive(), hasPayload(testFile)); + FileChannelCache.closeChannelFor(testFile); } } diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/LockFileFileListFilterTests.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/LockFileFileListFilterTests.java deleted file mode 100644 index ef81817e04..0000000000 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/locking/LockFileFileListFilterTests.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2002-2008 the original author or authors. - * - * Licensed 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.springframework.integration.file.locking; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import org.junit.Before; -import org.junit.Test; -import org.junit.BeforeClass; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Iwein Fuld - */ -public class LockFileFileListFilterTests { - - private static File workdir = new File(new File(System.getProperty("java.io.tmpdir")), LockFileFileListFilterTests.class.getSimpleName()); - - @BeforeClass - public static void setupWorkDir() { - workdir.mkdir(); - } - - private FileLocker locker = new LockFileFileListFilter(workdir); - - @Before - public void cleanDirectory() { - File[] files = workdir.listFiles(); - for (File file : files) { - file.delete(); - } - } - - @Test - public void fileListedOnlyWhenNotLocked() throws IOException { - LockFileFileListFilter filter = new LockFileFileListFilter(workdir); - File testFile = new File(workdir, "test0"); - testFile.createNewFile(); - assertThat(filter.filterFiles(workdir.listFiles()).get(0), is(testFile)); - locker.lock(testFile); - assertThat(filter.filterFiles(workdir.listFiles()), is((List)new ArrayList())); - } - - @Test - public void fileListedByOneFilterOnly() throws IOException { - LockFileFileListFilter filter1 = new LockFileFileListFilter(workdir); - LockFileFileListFilter filter2 = new LockFileFileListFilter(workdir); - File testFile = new File(workdir, "test1"); - testFile.createNewFile(); - assertThat(filter1.filterFiles(workdir.listFiles()).get(0), is(testFile)); - locker.lock(testFile); - assertThat(filter2.filterFiles(workdir.listFiles()), is((List)new ArrayList())); - } - -} diff --git a/org.springframework.integration.file/src/test/resources/log4j.properties b/org.springframework.integration.file/src/test/resources/log4j.properties new file mode 100644 index 0000000000..c916dc5d9a --- /dev/null +++ b/org.springframework.integration.file/src/test/resources/log4j.properties @@ -0,0 +1,8 @@ +log4j.rootCategory=WARN, stdout + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%c{1}: %m%n + +log4j.category.org.springframework.integration=INFO +log4j.category.org.springframework.integration.file=DEBUG \ No newline at end of file diff --git a/org.springframework.integration.file/template.mf b/org.springframework.integration.file/template.mf index 6042cd5926..8a4ea705bb 100644 --- a/org.springframework.integration.file/template.mf +++ b/org.springframework.integration.file/template.mf @@ -9,4 +9,5 @@ Import-Template: org.springframework.context;version="[3.0.0, 4.0.0)", org.springframework.core.*;version="[3.0.0, 4.0.0)", org.springframework.util;version="[3.0.0, 4.0.0)", + org.springframework.util.xml;version="[3.0.0, 4.0.0)", org.w3c.dom.*;version="0" diff --git a/org.springframework.integration.osgi/.classpath b/org.springframework.integration.osgi/.classpath index c3aaf861ae..eaf8ea23cd 100644 --- a/org.springframework.integration.osgi/.classpath +++ b/org.springframework.integration.osgi/.classpath @@ -16,12 +16,12 @@ - - - + + + - - + + diff --git a/org.springframework.integration.ws/.classpath b/org.springframework.integration.ws/.classpath index 96f40f5b8a..0fd4d8541a 100644 --- a/org.springframework.integration.ws/.classpath +++ b/org.springframework.integration.ws/.classpath @@ -17,10 +17,10 @@ - + - + diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/channel/MixedDispatcherConfigurationScenarioTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/channel/MixedDispatcherConfigurationScenarioTests.java index 00a3c46057..41dd5cfa68 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/channel/MixedDispatcherConfigurationScenarioTests.java +++ b/org.springframework.integration/src/test/java/org/springframework/integration/channel/MixedDispatcherConfigurationScenarioTests.java @@ -16,29 +16,14 @@ package org.springframework.integration.channel; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; -import org.mockito.runners.MockitoJUnit44Runner; +import org.mockito.runners.MockitoJUnitRunner; import org.mockito.stubbing.Answer; - import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.task.SimpleAsyncTaskExecutor; @@ -50,19 +35,28 @@ import org.springframework.integration.message.MessageRejectedException; import org.springframework.integration.message.StringMessage; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.*; + /** * @author Oleg Zhurakousky */ -@RunWith(MockitoJUnit44Runner.class) +@RunWith(MockitoJUnitRunner.class) public class MixedDispatcherConfigurationScenarioTests { private static final int TOTAL_EXECUTIONS = 40; private ThreadPoolTaskExecutor scheduler = new ThreadPoolTaskExecutor(); - private CountDownLatch allDone; - private CountDownLatch start; - private AtomicBoolean failed; + private CountDownLatch allDone; + private CountDownLatch start; + private AtomicBoolean failed; @Mock private List exceptionRegistry; @@ -83,7 +77,8 @@ public class MixedDispatcherConfigurationScenarioTests { @Before public void initialize() throws Exception { - ac = new ClassPathXmlApplicationContext("MixedDispatcherConfigurationScenarioTests-context.xml",MixedDispatcherConfigurationScenarioTests.class); + ac = new ClassPathXmlApplicationContext("MixedDispatcherConfigurationScenarioTests-context.xml", + MixedDispatcherConfigurationScenarioTests.class); allDone = new CountDownLatch(TOTAL_EXECUTIONS); start = new CountDownLatch(1); failed = new AtomicBoolean(false); diff --git a/org.springframework.integration/src/test/resources/log4j.properties b/org.springframework.integration/src/test/resources/log4j.properties index c916dc5d9a..c5000b932a 100644 --- a/org.springframework.integration/src/test/resources/log4j.properties +++ b/org.springframework.integration/src/test/resources/log4j.properties @@ -4,5 +4,4 @@ log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%c{1}: %m%n -log4j.category.org.springframework.integration=INFO -log4j.category.org.springframework.integration.file=DEBUG \ No newline at end of file +log4j.category.org.springframework.integration=INFO \ No newline at end of file