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.GenericFileEndpoint; 022 import org.apache.camel.component.file.GenericFileExclusiveReadLockStrategy; 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. Will wait until the lock is granted. 030 * After granting the read lock it is released, we just want to make sure that when we start 031 * consuming the file its not currently in progress of being written by third party. 032 */ 033 public class GenericFileRenameExclusiveReadLockStrategy<T> implements GenericFileExclusiveReadLockStrategy<T> { 034 private static final transient Logger LOG = LoggerFactory.getLogger(GenericFileRenameExclusiveReadLockStrategy.class); 035 private long timeout; 036 private long checkInterval; 037 038 public void prepareOnStartup(GenericFileOperations<T> operations, GenericFileEndpoint<T> endpoint) throws Exception { 039 // noop 040 } 041 042 public boolean acquireExclusiveReadLock(GenericFileOperations<T> operations, GenericFile<T> file, 043 Exchange exchange) throws Exception { 044 LOG.trace("Waiting for exclusive read lock to file: {}", file); 045 046 // the trick is to try to rename the file, if we can rename then we have exclusive read 047 // since its a Generic file we cannot use java.nio to get a RW lock 048 String newName = file.getFileName() + ".camelExclusiveReadLock"; 049 050 // make a copy as result and change its file name 051 GenericFile<T> newFile = file.copyFrom(file); 052 newFile.changeFileName(newName); 053 StopWatch watch = new StopWatch(); 054 055 boolean exclusive = false; 056 while (!exclusive) { 057 // timeout check 058 if (timeout > 0) { 059 long delta = watch.taken(); 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 exclusive = operations.renameFile(file.getAbsoluteFilePath(), newFile.getAbsoluteFilePath()); 068 if (exclusive) { 069 LOG.trace("Acquired exclusive read lock to file: {}", file); 070 // rename it back so we can read it 071 operations.renameFile(newFile.getAbsoluteFilePath(), file.getAbsoluteFilePath()); 072 } else { 073 boolean interrupted = sleep(); 074 if (interrupted) { 075 // we were interrupted while sleeping, we are likely being shutdown so return false 076 return false; 077 } 078 } 079 } 080 081 return true; 082 } 083 084 public void releaseExclusiveReadLock(GenericFileOperations<T> operations, GenericFile<T> file, 085 Exchange exchange) throws Exception { 086 // noop 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 void setCheckInterval(long checkInterval) { 109 this.checkInterval = checkInterval; 110 } 111 }