added null check in FileChannelCache

This commit is contained in:
Mark Fisher
2009-10-02 03:29:50 +00:00
parent fe9160e1e7
commit 70ffe3eade
4 changed files with 54 additions and 31 deletions

View File

@@ -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<File, FileChannel> channelCache = new ConcurrentHashMap<File, FileChannel>();
/**
* 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 <code>null</code>.
* VM. If the lock could not be acquired this method will return <code>null</code>.
* <p/>
* 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.
* <p/>
* 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 {
* <p/>
* 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);
}
}

View File

@@ -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);
}

View File

@@ -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();
}
}
}

View File

@@ -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<File, FileLock> lockCache = new ConcurrentHashMap<File, FileLock>();
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);
}
}