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 import java.io.IOException;
021
022 import org.apache.camel.Exchange;
023 import org.apache.camel.component.file.GenericFile;
024 import org.apache.camel.component.file.GenericFileEndpoint;
025 import org.apache.camel.component.file.GenericFileOperations;
026 import org.apache.commons.logging.Log;
027 import org.apache.commons.logging.LogFactory;
028
029 /**
030 * Acquires exclusive read lock to the given file by checking whether the file is being
031 * changed by scanning the file at different intervals (to detec changes).
032 */
033 public class FileChangedExclusiveReadLockStrategy extends MarkerFileExclusiveReadLockStrategy {
034 private static final transient Log LOG = LogFactory.getLog(FileChangedExclusiveReadLockStrategy.class);
035 private long timeout;
036
037 @Override
038 public void prepareOnStartup(GenericFileOperations<File> operations, GenericFileEndpoint<File> endpoint) {
039 // noop
040 }
041
042 public boolean acquireExclusiveReadLock(GenericFileOperations<File> operations, GenericFile<File> file, Exchange exchange) throws Exception {
043 File target = new File(file.getAbsoluteFilePath());
044 boolean exclusive = false;
045
046 if (LOG.isTraceEnabled()) {
047 LOG.trace("Waiting for exclusive read lock to file: " + file);
048 }
049
050 try {
051 long lastModified = Long.MIN_VALUE;
052 long length = Long.MIN_VALUE;
053
054 long start = System.currentTimeMillis();
055
056 while (!exclusive) {
057 // timeout check
058 if (timeout > 0) {
059 long delta = System.currentTimeMillis() - start;
060 if (delta > timeout) {
061 LOG.warn("Cannot acquire read lock within " + timeout + " millis. Will skip the file: " + file);
062 // we could not get the lock within the timeout period, so return false
063 return false;
064 }
065 }
066
067 long newLastModified = target.lastModified();
068 long newLength = target.length();
069
070 if (LOG.isTraceEnabled()) {
071 LOG.trace("Previous last modified: " + lastModified + ", new last modified: " + newLastModified);
072 LOG.trace("Previous length: " + length + ", new length: " + newLength);
073 }
074
075 if (newLastModified == lastModified && newLength == length) {
076 // let super handle the last part of acquiring the lock now the file is not
077 // currently being in progress of being copied as file length and modified
078 // are stable
079 exclusive = super.acquireExclusiveReadLock(operations, file, exchange);
080 } else {
081 // set new base file change information
082 lastModified = newLastModified;
083 length = newLength;
084
085 boolean interrupted = sleep();
086 if (interrupted) {
087 // we were interrupted while sleeping, we are likely being shutdown so return false
088 return false;
089 }
090 }
091 }
092 } catch (IOException e) {
093 // must handle IOException as some apps on Windows etc. will still somehow hold a lock to a file
094 // such as AntiVirus or MS Office that has special locks for it's supported files
095 if (timeout == 0) {
096 // if not using timeout, then we cant retry, so rethrow
097 throw e;
098 }
099 if (LOG.isDebugEnabled()) {
100 LOG.debug("Cannot acquire read lock. Will try again.", e);
101 }
102 boolean interrupted = sleep();
103 if (interrupted) {
104 // we were interrupted while sleeping, we are likely being shutdown so return false
105 return false;
106 }
107 }
108
109 return exclusive;
110 }
111
112 private boolean sleep() {
113 if (LOG.isTraceEnabled()) {
114 LOG.trace("Exclusive read lock not granted. Sleeping for 1000 millis.");
115 }
116 try {
117 Thread.sleep(1000);
118 return false;
119 } catch (InterruptedException e) {
120 if (LOG.isDebugEnabled()) {
121 LOG.debug("Sleep interrupted while waiting for exclusive read lock, so breaking out");
122 }
123 return true;
124 }
125 }
126
127 public long getTimeout() {
128 return timeout;
129 }
130
131 public void setTimeout(long timeout) {
132 this.timeout = timeout;
133 }
134
135 }