View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.transport.sftp;
8   
9   import org.apache.commons.logging.Log;
10  import org.apache.commons.logging.LogFactory;
11  import org.mule.api.endpoint.ImmutableEndpoint;
12  
13  import java.io.BufferedInputStream;
14  import java.io.IOException;
15  import java.io.InputStream;
16  
17  /**
18   * <code>SftpInputStream</code> wraps an sftp InputStream.
19   */
20  
21  public class SftpInputStream extends BufferedInputStream implements ErrorOccurredDecorator
22  {
23      private final Log logger = LogFactory.getLog(getClass());
24  
25      private SftpClient client;
26      private boolean autoDelete = true;
27      private String fileName;
28  
29      public String getFileName()
30      {
31          return fileName;
32      }
33  
34      public void setFileName(String fileName)
35      {
36          this.fileName = fileName;
37      }
38  
39      private boolean errorOccured = false;
40      private ImmutableEndpoint endpoint;
41  
42      // Log every 10 000 000 bytes read at debug-level
43      // Good if really large files are transferred and you tend to get nervous by not
44      // seeing any progress in the logfile...
45      private static final int LOG_BYTE_INTERVAL = 10000000;
46      private long bytesRead = 0;
47      private long nextLevelToLogBytesRead = LOG_BYTE_INTERVAL;
48  
49      /**
50       * A special sftp InputStream. The constructor creates the InputStream by calling
51       * <code>SftpClient.retrieveFile(fileName)</code>. The client passed in is
52       * destroyed when the stream is closed.
53       * 
54       * @param client The SftpClient instance. Will be destroyed when stream closed.
55       * @param is The stream that should be used
56       * @param fileName name of the file to be retrieved
57       * @param autoDelete whether the file specified by fileName should be deleted
58       * @param endpoint the endpoint associated to a specific client (connector) pool.
59       * @throws Exception if failing to retrieve internal input stream.
60       */
61      public SftpInputStream(SftpClient client,
62                             InputStream is,
63                             String fileName,
64                             boolean autoDelete,
65                             ImmutableEndpoint endpoint) throws Exception
66      {
67          super(is);
68  
69          this.client = client;
70          this.fileName = fileName;
71          this.autoDelete = autoDelete;
72          this.endpoint = endpoint;
73      }
74  
75      @Override
76      public synchronized int read() throws IOException
77      {
78          logReadBytes(1);
79          return super.read();
80      }
81  
82      @Override
83      public synchronized int read(byte[] b, int off, int len) throws IOException
84      {
85          logReadBytes(len);
86          return super.read(b, off, len);
87      }
88  
89      @Override
90      public int read(byte[] b) throws IOException
91      {
92          logReadBytes(b.length);
93          return super.read(b);
94      }
95  
96      public void close() throws IOException
97      {
98          if (logger.isDebugEnabled())
99          {
100             logger.debug("Closing the stream for the file " + fileName);
101         }
102         try
103         {
104             super.close();
105 
106             if (autoDelete && !errorOccured)
107             {
108                 client.deleteFile(fileName);
109             }
110         }
111         catch (IOException e)
112         {
113             logger.error("Error occured while closing file " + fileName, e);
114             throw e;
115         }
116         finally
117         {
118             // We should release the connection from the pool even if some error
119             // occurs here
120             try
121             {
122                 ((SftpConnector) endpoint.getConnector()).releaseClient(endpoint, client);
123             }
124             catch (Exception e)
125             {
126                 logger.error(e.getMessage(), e);
127             }
128         }
129     }
130 
131     public void setErrorOccurred()
132     {
133         if (logger.isDebugEnabled()) logger.debug("setErrorOccurred() called");
134         this.errorOccured = true;
135     }
136 
137     @Override
138     public String toString()
139     {
140         return "SftpInputStream{" + "fileName='" + fileName + '\'' + " from endpoint="
141                + endpoint.getEndpointURI() + '}';
142     }
143 
144     private void logReadBytes(int newBytesRead)
145     {
146         if (!logger.isDebugEnabled()) return;
147 
148         this.bytesRead += newBytesRead;
149         if (this.bytesRead >= nextLevelToLogBytesRead)
150         {
151             logger.debug("Read " + this.bytesRead + " bytes and couting...");
152             nextLevelToLogBytesRead += LOG_BYTE_INTERVAL;
153         }
154     }
155 
156 }