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 */ 017package org.apache.camel.component.file.strategy; 018 019import java.io.File; 020import java.util.Date; 021 022import org.apache.camel.Exchange; 023import org.apache.camel.LoggingLevel; 024import org.apache.camel.component.file.GenericFile; 025import org.apache.camel.component.file.GenericFileOperations; 026import org.apache.camel.util.CamelLogger; 027import org.apache.camel.util.StopWatch; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031/** 032 * Acquires exclusive read lock to the given file by checking whether the file is being 033 * changed by scanning the file at different intervals (to detect changes). 034 * <p/> 035 * Setting the option {@link #setMarkerFiler(boolean)} to <tt>false</tt> allows to turn off using marker files. 036 */ 037public class FileChangedExclusiveReadLockStrategy extends MarkerFileExclusiveReadLockStrategy { 038 private static final Logger LOG = LoggerFactory.getLogger(FileChangedExclusiveReadLockStrategy.class); 039 private long timeout; 040 private long checkInterval = 1000; 041 private long minLength = 1; 042 private long minAge; 043 private LoggingLevel readLockLoggingLevel = LoggingLevel.DEBUG; 044 045 @Override 046 public boolean acquireExclusiveReadLock(GenericFileOperations<File> operations, GenericFile<File> file, Exchange exchange) throws Exception { 047 // must call super 048 if (!super.acquireExclusiveReadLock(operations, file, exchange)) { 049 return false; 050 } 051 052 File target = new File(file.getAbsoluteFilePath()); 053 boolean exclusive = false; 054 055 LOG.trace("Waiting for exclusive read lock to file: {}", file); 056 057 long lastModified = Long.MIN_VALUE; 058 long length = Long.MIN_VALUE; 059 StopWatch watch = new StopWatch(); 060 long startTime = (new Date()).getTime(); 061 062 while (!exclusive) { 063 // timeout check 064 if (timeout > 0) { 065 long delta = watch.taken(); 066 if (delta > timeout) { 067 CamelLogger.log(LOG, readLockLoggingLevel, 068 "Cannot acquire read lock within " + timeout + " millis. Will skip the file: " + file); 069 // we could not get the lock within the timeout period, so return false 070 return false; 071 } 072 } 073 074 long newLastModified = target.lastModified(); 075 long newLength = target.length(); 076 long newOlderThan = startTime + watch.taken() - minAge; 077 078 LOG.trace("Previous last modified: {}, new last modified: {}", lastModified, newLastModified); 079 LOG.trace("Previous length: {}, new length: {}", length, newLength); 080 LOG.trace("New older than threshold: {}", newOlderThan); 081 082 if (newLength >= minLength && ((minAge == 0 && newLastModified == lastModified && newLength == length) || (minAge != 0 && newLastModified < newOlderThan))) { 083 LOG.trace("Read lock acquired."); 084 exclusive = true; 085 } else { 086 // set new base file change information 087 lastModified = newLastModified; 088 length = newLength; 089 090 boolean interrupted = sleep(); 091 if (interrupted) { 092 // we were interrupted while sleeping, we are likely being shutdown so return false 093 return false; 094 } 095 } 096 } 097 098 return exclusive; 099 } 100 101 private boolean sleep() { 102 LOG.trace("Exclusive read lock not granted. Sleeping for {} millis.", checkInterval); 103 try { 104 Thread.sleep(checkInterval); 105 return false; 106 } catch (InterruptedException e) { 107 LOG.debug("Sleep interrupted while waiting for exclusive read lock, so breaking out"); 108 return true; 109 } 110 } 111 112 public long getTimeout() { 113 return timeout; 114 } 115 116 @Override 117 public void setTimeout(long timeout) { 118 this.timeout = timeout; 119 } 120 121 public long getCheckInterval() { 122 return checkInterval; 123 } 124 125 @Override 126 public void setCheckInterval(long checkInterval) { 127 this.checkInterval = checkInterval; 128 } 129 130 @Override 131 public void setReadLockLoggingLevel(LoggingLevel readLockLoggingLevel) { 132 this.readLockLoggingLevel = readLockLoggingLevel; 133 } 134 135 public long getMinLength() { 136 return minLength; 137 } 138 139 public void setMinLength(long minLength) { 140 this.minLength = minLength; 141 } 142 143 public long getMinAge() { 144 return minAge; 145 } 146 147 public void setMinAge(long minAge) { 148 this.minAge = minAge; 149 } 150}