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;
018
019 import org.apache.camel.Exchange;
020 import org.apache.camel.impl.LoggingExceptionHandler;
021 import org.apache.camel.spi.ExceptionHandler;
022 import org.apache.camel.spi.Synchronization;
023 import org.apache.commons.logging.Log;
024 import org.apache.commons.logging.LogFactory;
025
026 /**
027 * On completion strategy that performs the required work after the {@link Exchange} has been processed.
028 * <p/>
029 * The work is for example to move the processed file into a backup folder, delete the file or
030 * in case of processing failure do a rollback.
031 *
032 * @version $Revision: 905637 $
033 */
034 public class GenericFileOnCompletion<T> implements Synchronization {
035
036 private final transient Log log = LogFactory.getLog(GenericFileOnCompletion.class);
037 private GenericFileEndpoint<T> endpoint;
038 private GenericFileOperations<T> operations;
039 private ExceptionHandler exceptionHandler;
040 private GenericFile<T> file;
041 private String originalFileName;
042
043 public GenericFileOnCompletion(GenericFileEndpoint<T> endpoint, GenericFileOperations<T> operations,
044 GenericFile<T> file, String originalFileName) {
045 this.endpoint = endpoint;
046 this.operations = operations;
047 this.file = file;
048 this.originalFileName = originalFileName;
049 }
050
051 public void onComplete(Exchange exchange) {
052 onCompletion(exchange);
053 }
054
055 public void onFailure(Exchange exchange) {
056 onCompletion(exchange);
057 }
058
059 public ExceptionHandler getExceptionHandler() {
060 if (exceptionHandler == null) {
061 exceptionHandler = new LoggingExceptionHandler(getClass());
062 }
063 return exceptionHandler;
064 }
065
066 public void setExceptionHandler(ExceptionHandler exceptionHandler) {
067 this.exceptionHandler = exceptionHandler;
068 }
069
070 protected void onCompletion(Exchange exchange) {
071 GenericFileProcessStrategy<T> processStrategy = endpoint.getGenericFileProcessStrategy();
072
073 if (log.isDebugEnabled()) {
074 log.debug("Done processing file: " + file + " using exchange: " + exchange);
075 }
076
077 // commit or rollback
078 boolean committed = false;
079 try {
080 boolean failed = exchange.isFailed();
081 if (!failed) {
082 // commit the file strategy if there was no failure or already handled by the DeadLetterChannel
083 processStrategyCommit(processStrategy, exchange, file);
084 committed = true;
085 } else {
086 if (exchange.getException() != null) {
087 // if the failure was an exception then handle it
088 handleException(exchange.getException());
089 }
090 }
091 } finally {
092 if (!committed) {
093 processStrategyRollback(processStrategy, exchange, file);
094 }
095
096 // remove file from the in progress list as its no longer in progress
097 // use the original file name that was used to add it to the repository
098 // as the name can be different when using preMove option
099 endpoint.getInProgressRepository().remove(originalFileName);
100 }
101 }
102
103 /**
104 * Strategy when the file was processed and a commit should be executed.
105 *
106 * @param processStrategy the strategy to perform the commit
107 * @param exchange the exchange
108 * @param file the file processed
109 */
110 protected void processStrategyCommit(GenericFileProcessStrategy<T> processStrategy,
111 Exchange exchange, GenericFile<T> file) {
112 if (endpoint.isIdempotent()) {
113 // only add to idempotent repository if we could process the file
114 // only use the filename as the key as the file could be moved into a done folder
115 endpoint.getIdempotentRepository().add(file.getFileName());
116 }
117
118 try {
119 if (log.isTraceEnabled()) {
120 log.trace("Commit file strategy: " + processStrategy + " for file: " + file);
121 }
122 processStrategy.commit(operations, endpoint, exchange, file);
123 } catch (Exception e) {
124 handleException(e);
125 }
126 }
127
128 /**
129 * Strategy when the file was not processed and a rollback should be executed.
130 *
131 * @param processStrategy the strategy to perform the commit
132 * @param exchange the exchange
133 * @param file the file processed
134 */
135 protected void processStrategyRollback(GenericFileProcessStrategy<T> processStrategy,
136 Exchange exchange, GenericFile<T> file) {
137
138 if (log.isWarnEnabled()) {
139 log.warn("Rollback file strategy: " + processStrategy + " for file: " + file);
140 }
141 try {
142 processStrategy.rollback(operations, endpoint, exchange, file);
143 } catch (Exception e) {
144 handleException(e);
145 }
146 }
147
148 protected void handleException(Throwable t) {
149 Throwable newt = (t == null) ? new IllegalArgumentException("Handling [null] exception") : t;
150 getExceptionHandler().handleException(newt);
151 }
152
153 @Override
154 public String toString() {
155 return "GenericFileOnCompletion";
156 }
157 }