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 java.io.File;
020
021 import org.apache.camel.Exchange;
022 import org.apache.camel.component.file.GenericFile;
023 import org.apache.camel.component.file.GenericFileOperations;
024 import org.apache.camel.util.StopWatch;
025 import org.slf4j.Logger;
026 import org.slf4j.LoggerFactory;
027
028 /**
029 * Acquires exclusive read lock to the given file by checking whether the file is being
030 * changed by scanning the file at different intervals (to detect changes).
031 */
032 public class FileChangedExclusiveReadLockStrategy extends MarkerFileExclusiveReadLockStrategy {
033 private static final transient Logger LOG = LoggerFactory.getLogger(FileChangedExclusiveReadLockStrategy.class);
034 private long timeout;
035 private long checkInterval = 1000;
036 private long minLength = 1;
037
038 public boolean acquireExclusiveReadLock(GenericFileOperations<File> operations, GenericFile<File> file, Exchange exchange) throws Exception {
039 // must call super
040 if (!super.acquireExclusiveReadLock(operations, file, exchange)) {
041 return false;
042 }
043
044 File target = new File(file.getAbsoluteFilePath());
045 boolean exclusive = false;
046
047 LOG.trace("Waiting for exclusive read lock to file: {}", file);
048
049 long lastModified = Long.MIN_VALUE;
050 long length = Long.MIN_VALUE;
051 StopWatch watch = new StopWatch();
052
053 while (!exclusive) {
054 // timeout check
055 if (timeout > 0) {
056 long delta = watch.taken();
057 if (delta > timeout) {
058 LOG.warn("Cannot acquire read lock within " + timeout + " millis. Will skip the file: " + file);
059 // we could not get the lock within the timeout period, so return false
060 return false;
061 }
062 }
063
064 long newLastModified = target.lastModified();
065 long newLength = target.length();
066
067 LOG.trace("Previous last modified: {}, new last modified: {}", lastModified, newLastModified);
068 LOG.trace("Previous length: {}, new length: {}", length, newLength);
069
070 if (length >= minLength && (newLastModified == lastModified && newLength == length)) {
071 LOG.trace("Read lock acquired.");
072 exclusive = true;
073 } else {
074 // set new base file change information
075 lastModified = newLastModified;
076 length = newLength;
077
078 boolean interrupted = sleep();
079 if (interrupted) {
080 // we were interrupted while sleeping, we are likely being shutdown so return false
081 return false;
082 }
083 }
084 }
085
086 return exclusive;
087 }
088
089 private boolean sleep() {
090 LOG.trace("Exclusive read lock not granted. Sleeping for {} millis.", checkInterval);
091 try {
092 Thread.sleep(checkInterval);
093 return false;
094 } catch (InterruptedException e) {
095 LOG.debug("Sleep interrupted while waiting for exclusive read lock, so breaking out");
096 return true;
097 }
098 }
099
100 public long getTimeout() {
101 return timeout;
102 }
103
104 public void setTimeout(long timeout) {
105 this.timeout = timeout;
106 }
107
108 public long getCheckInterval() {
109 return checkInterval;
110 }
111
112 public void setCheckInterval(long checkInterval) {
113 this.checkInterval = checkInterval;
114 }
115
116 public long getMinLength() {
117 return minLength;
118 }
119
120 public void setMinLength(long minLength) {
121 this.minLength = minLength;
122 }
123 }