001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.camel.component.file.strategy; 018 019 import org.apache.camel.Exchange; 020 import org.apache.camel.component.file.GenericFile; 021 import org.apache.camel.component.file.GenericFileExclusiveReadLockStrategy; 022 import org.apache.camel.component.file.GenericFileOperations; 023 import org.apache.commons.logging.Log; 024 import org.apache.commons.logging.LogFactory; 025 026 /** 027 * Acquires exclusive read lock to the given file. Will wait until the lock is granted. 028 * After granting the read lock it is realeased, we just want to make sure that when we start 029 * consuming the file its not currently in progress of being written by third party. 030 */ 031 public class GenericFileRenameExclusiveReadLockStrategy<T> implements GenericFileExclusiveReadLockStrategy<T> { 032 private static final transient Log LOG = LogFactory.getLog(GenericFileRenameExclusiveReadLockStrategy.class); 033 private long timeout; 034 035 public boolean acquireExclusiveReadLock(GenericFileOperations<T> operations, GenericFile<T> file, 036 Exchange exchange) throws Exception { 037 if (LOG.isTraceEnabled()) { 038 LOG.trace("Waiting for exclusive read lock to file: " + file); 039 } 040 041 // the trick is to try to rename the file, if we can rename then we have exclusive read 042 // since its a Generic file we cannot use java.nio to get a RW lock 043 String newName = file.getFileName() + ".camelExclusiveReadLock"; 044 045 // clone and change the name 046 GenericFile<T> newFile = file.clone(); 047 newFile.changeFileName(newName); 048 049 long start = System.currentTimeMillis(); 050 051 boolean exclusive = false; 052 while (!exclusive) { 053 // timeout check 054 if (timeout > 0) { 055 long delta = System.currentTimeMillis() - start; 056 if (delta > timeout) { 057 LOG.debug("Cannot acquire read lock within " + timeout + " millis. Will skip the file: " + file); 058 // we could not get the lock within the timeout period, so return false 059 return false; 060 } 061 } 062 063 exclusive = operations.renameFile(file.getAbsoluteFilePath(), newFile.getAbsoluteFilePath()); 064 if (exclusive) { 065 if (LOG.isTraceEnabled()) { 066 LOG.trace("Acquired exclusive read lock to file: " + file); 067 } 068 // rename it back so we can read it 069 operations.renameFile(newFile.getAbsoluteFilePath(), file.getAbsoluteFilePath()); 070 } else { 071 boolean interrupted = sleep(); 072 if (interrupted) { 073 // we were interrupted while sleeping, we are likely being shutdown so return false 074 return false; 075 } 076 } 077 } 078 079 return true; 080 } 081 082 public void releaseExclusiveReadLock(GenericFileOperations<T> operations, GenericFile<T> file, 083 Exchange exchange) throws Exception { 084 // noop 085 } 086 087 private boolean sleep() { 088 LOG.trace("Exclusive read lock not granted. Sleeping for 1000 millis."); 089 try { 090 Thread.sleep(1000); 091 return false; 092 } catch (InterruptedException e) { 093 LOG.debug("Sleep interrupted while waiting for exclusive read lock, so breaking out"); 094 return true; 095 } 096 } 097 098 public long getTimeout() { 099 return timeout; 100 } 101 102 /** 103 * Sets an optional timeout period. 104 * <p/> 105 * If the readlock could not be granted within the timeperiod then the wait is stopped and the 106 * <tt>acquireExclusiveReadLock</tt> returns <tt>false</tt>. 107 * 108 * @param timeout period in millis 109 */ 110 public void setTimeout(long timeout) { 111 this.timeout = timeout; 112 } 113 }