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.remote; 018 019 import java.io.IOException; 020 021 import org.apache.camel.Exchange; 022 import org.apache.camel.ServicePoolAware; 023 import org.apache.camel.component.file.GenericFileOperationFailedException; 024 import org.apache.camel.component.file.GenericFileProducer; 025 import org.apache.camel.util.ExchangeHelper; 026 027 /** 028 * Remote file producer. Handles connecting and disconnecting if we are not. 029 * Generic type F is the remote system implementation of a file. 030 */ 031 public class RemoteFileProducer<T> extends GenericFileProducer<T> implements ServicePoolAware { 032 033 private boolean loggedIn; 034 035 protected RemoteFileProducer(RemoteFileEndpoint<T> endpoint, RemoteFileOperations<T> operations) { 036 super(endpoint, operations); 037 } 038 039 @Override 040 protected String getFileSeparator() { 041 return "/"; 042 } 043 044 @Override 045 protected String normalizePath(String name) { 046 return name; 047 } 048 049 @SuppressWarnings("unchecked") 050 public void process(Exchange exchange) throws Exception { 051 Exchange remoteExchange = getEndpoint().createExchange(exchange); 052 processExchange(remoteExchange); 053 ExchangeHelper.copyResults(exchange, remoteExchange); 054 } 055 056 protected RemoteFileOperations getOperations() { 057 return (RemoteFileOperations) operations; 058 } 059 060 /** 061 * The file could not be written. We need to disconnect from the remote server. 062 */ 063 protected void handleFailedWrite(Exchange exchange, Exception exception) throws Exception { 064 loggedIn = false; 065 if (isStopping() || isStopped()) { 066 // if we are stopping then ignore any exception during a poll 067 log.debug("Exception occurred during stopping: " + exception.getMessage()); 068 } else { 069 log.warn("Writing file failed with: " + exception.getMessage()); 070 try { 071 disconnect(); 072 } catch (Exception e) { 073 // ignore exception 074 log.debug("Ignored exception during disconnect: " + e.getMessage()); 075 } 076 // rethrow the original exception*/ 077 throw exception; 078 } 079 } 080 081 public void disconnect() throws IOException { 082 loggedIn = false; 083 if (getOperations().isConnected()) { 084 if (log.isDebugEnabled()) { 085 log.debug("Disconnecting from: " + getEndpoint()); 086 } 087 getOperations().disconnect(); 088 } 089 } 090 091 @Override 092 protected void preWriteCheck() throws Exception { 093 // before writing send a noop to see if the connection is alive and works 094 boolean noop = false; 095 try { 096 connectIfNecessary(); 097 if (loggedIn) { 098 noop = getOperations().sendNoop(); 099 } 100 } catch (Exception e) { 101 // ignore as we will try to recover connection 102 noop = false; 103 } 104 if (log.isDebugEnabled()) { 105 log.debug("preWriteCheck send noop success: " + noop); 106 } 107 108 // if not alive then force a disconnect so we reconnect again 109 if (!noop) { 110 try { 111 if (log.isDebugEnabled()) { 112 log.debug("preWriteCheck forcing a disconnect as noop failed"); 113 } 114 disconnect(); 115 } catch (Exception e) { 116 // ignore for now as we will reconnect below 117 } 118 } 119 120 connectIfNecessary(); 121 if (!loggedIn) { 122 // must be logged in to be able to upload the file 123 String message = "Cannot connect/login to: " + ((RemoteFileEndpoint) getEndpoint()).remoteServerInformation(); 124 throw new GenericFileOperationFailedException(message); 125 } 126 } 127 128 @Override 129 protected void doStart() throws Exception { 130 log.debug("Starting"); 131 // do not connect when component starts, just wait until we process as we will 132 // connect at that time if needed 133 super.doStart(); 134 } 135 136 @Override 137 protected void doStop() throws Exception { 138 try { 139 disconnect(); 140 } catch (Exception e) { 141 log.debug("Exception occurred during disconnecting from: " + getEndpoint() + " " + e.getMessage()); 142 } 143 super.doStop(); 144 } 145 146 protected void connectIfNecessary() throws IOException { 147 if (!loggedIn) { 148 if (log.isDebugEnabled()) { 149 log.debug("Not already connected/logged in. Connecting to: " + getEndpoint()); 150 } 151 RemoteFileEndpoint rfe = (RemoteFileEndpoint) getEndpoint(); 152 RemoteFileConfiguration conf = (RemoteFileConfiguration) rfe.getConfiguration(); 153 loggedIn = getOperations().connect(conf); 154 if (!loggedIn) { 155 return; 156 } 157 log.info("Connected and logged in to: " + getEndpoint()); 158 } 159 } 160 161 public boolean isSingleton() { 162 // this producer is stateful because the remote file operations is not thread safe 163 return false; 164 } 165 }