From 70ffe3eade155b3db658a153187fed069cb2db02 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 2 Oct 2009 03:29:50 +0000 Subject: [PATCH] added null check in FileChannelCache --- .../file/locking/FileChannelCache.java | 28 ++++++++++----- .../integration/file/locking/FileLocker.java | 9 ++--- .../file/locking/LockFileFileListFilter.java | 34 +++++++++++-------- .../file/locking/NioFileLocker.java | 14 +++++--- 4 files changed, 54 insertions(+), 31 deletions(-) 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 38c1cfc525..acacba9394 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.file.locking; import java.io.File; @@ -26,17 +27,18 @@ import java.util.concurrent.ConcurrentMap; /** * @author Iwein Fuld + * @since 2.0 */ - final class FileChannelCache { + private static ConcurrentMap channelCache = new ConcurrentHashMap(); /** * 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 aquired this method will return null. + * VM. If the lock could not be acquired this method will return null. *

- * Locks aquired 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 leak. *

* Thread safe. */ @@ -45,13 +47,14 @@ final class FileChannelCache { if (channel == null) { FileChannel newChannel = new RandomAccessFile(fileToLock, "rw").getChannel(); FileChannel original = channelCache.putIfAbsent(fileToLock, newChannel); - channel = original != null ? original : newChannel; + channel = (original != null) ? original : newChannel; } FileLock lock = null; if (channel != null) { try { lock = channel.tryLock(); - } catch (OverlappingFileLockException e) { + } + catch (OverlappingFileLockException e) { // File is already locked in this thread or virtual machine } } @@ -63,11 +66,20 @@ final class FileChannelCache { *

* Thread safe. */ - public static void closeChannelFor(File fileToUnlock) throws IOException { - channelCache.remove(fileToUnlock).close(); + public static void closeChannelFor(File fileToUnlock) { + FileChannel fileChannel = channelCache.remove(fileToUnlock); + if (fileChannel != null) { + try { + fileChannel.close(); + } + catch (IOException e) { + // ignore + } + } } public static boolean isLocked(File file) { return channelCache.containsKey(file); } + } diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/FileLocker.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/FileLocker.java index 94b839c2de..1ed88f9a38 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/FileLocker.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/locking/FileLocker.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * 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. @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.file.locking; import java.io.File; -import java.io.IOException; /** * A FileLocker is a strategy that can ensure that files are only processed a single time. - * - * Implementations are free implement any relation between locking and unlocking (e.g. the Noop + * Implementations are free to implement any relation between locking and unlocking. * * @author Iwein Fuld + * @since 2.0 */ public interface FileLocker { @@ -36,4 +36,5 @@ public interface FileLocker { * Unlocks the given file. */ void unlock(File fileToUnlock); + } 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 index 8e42535519..b07c3cbf2d 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * 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. @@ -13,6 +13,7 @@ * 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; @@ -25,36 +26,39 @@ 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 addition precautions need to be taken to avoid treating - * the lock files as normal input. + * 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 directy must not be null."); - Assert.isTrue(workdir.isDirectory(),"Work directy must be a directory."); - Assert.isTrue(workdir.canWrite(), "Work directy must be write accessible."); + 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()){ + 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); + return !name.endsWith(LOCK_SUFFIX) && !name.endsWith(PRELOCK_SUFFIX); } /** @@ -71,12 +75,13 @@ public class LockFileFileListFilter extends AbstractFileListFilter implements Fi } try { preLockFile.createNewFile(); - } catch (IOException e) { + } + 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)) { + // 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; } @@ -91,8 +96,9 @@ public class LockFileFileListFilter extends AbstractFileListFilter implements Fi 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()) { + 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 889fee3898..22a8c43774 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * 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. @@ -13,16 +13,15 @@ * 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.FileListFilter; import org.springframework.integration.file.AbstractFileListFilter; import org.springframework.integration.core.MessagingException; import java.io.File; import java.io.IOException; import java.nio.channels.FileLock; -import java.util.List; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; @@ -32,8 +31,10 @@ import java.util.concurrent.ConcurrentHashMap; * * @author Iwein Fuld * @author Mark Fisher + * @since 2.0 */ public class NioFileLocker extends AbstractFileListFilter implements FileLocker { + private final ConcurrentMap lockCache = new ConcurrentHashMap(); public boolean lock(File fileToLock) { @@ -42,7 +43,8 @@ public class NioFileLocker extends AbstractFileListFilter implements FileLocker FileLock newLock = null; try { newLock = FileChannelCache.tryLockFor(fileToLock); - } catch (IOException e) { + } + catch (IOException e) { throw new MessagingException("Failed to lock file: " + fileToLock, e); } if (newLock != null) { @@ -60,7 +62,8 @@ public class NioFileLocker extends AbstractFileListFilter implements FileLocker fileLock.release(); } FileChannelCache.closeChannelFor(fileToUnlock); - } catch (IOException e) { + } + catch (IOException e) { throw new MessagingException("Failed to unlock file: " + fileToUnlock, e); } } @@ -68,4 +71,5 @@ public class NioFileLocker extends AbstractFileListFilter implements FileLocker protected boolean accept(File file) { return this.lock(file); } + }