View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.xnap.transfer;
21  
22  import java.io.File;
23  
24  import javax.swing.Icon;
25  
26  import org.apache.log4j.Logger;
27  import org.xnap.event.StateListener;
28  import org.xnap.event.StateSupport;
29  
30  public abstract class AbstractTransfer implements Transfer {
31  
32      //--- Constant(s) ---
33  
34      public static final int RECALC_INTERVAL = 5000;
35  
36      /***
37       * Wait 50 milli seconds before calculating rate for the first time.
38       * Otherwise we will get fantastically high ones.
39       */
40      public static final int MIN_RECALC_INTERVAL = 50;
41  
42      /***
43       * The recommended default socket timeout.
44       */
45      public static final int SOCKET_TIMEOUT = 30 * 1000;
46  
47      //--- Data field(s) ---
48  
49      protected static Logger logger = Logger.getLogger("xnap.net.transfer");
50  
51      /***
52       *
53       */
54      private long lastBytesTransferred = 0;
55      private long lastElapsedTime = 0;
56      private long lastRate = 0;
57  
58      private long transferStartTime = -1;
59      private long totalRate = -1;
60  
61      private StateSupport listeners = new StateSupport(this);
62  
63      //--- Constructor(s) ---
64  
65      public AbstractTransfer()
66      {
67      }
68  
69      //--- Method(s) ---
70  
71      public void addStateListener(StateListener listener) 
72      {
73          listeners.addStateListener(listener);
74      }
75  
76  	/***
77  	 * Does nothing.
78  	 */
79  	public void cleared()
80  	{
81  	}
82  
83      /***
84       * Returns the average transfer rate.
85       */
86      public long getAverageRate()
87      {
88  		if (totalRate != -1) {
89  			return totalRate;
90  		}
91  		else if (transferStartTime == -1) {
92  			return -1;
93  		}
94  
95  		long elapsedTime = getElapsedTime();
96  		if (elapsedTime > 0) {
97  			return (getBytesTransferred() * 1000) / elapsedTime;
98  		}
99  		else {
100 			return getBytesTransferred();
101 		}
102     }
103 
104     /***
105      * Returns how many bytes have been transferred since the transfer
106      * was started.
107      * 
108      * @return number of transferred bytes
109      * @see #getCurrentRate()
110      */
111     protected abstract long getBytesTransferred();
112 
113     /***
114      * Returns the current download rate. Take at least a
115      * RECALC_INTERVAL into account to avoid jumping values all the
116      * time.
117      *
118      * @return byte / s 
119 	 */
120     public long getCurrentRate() 
121     {
122 		if (transferStartTime == -1) {
123 			return -1;
124 		}
125 
126 		long deltaTime = System.currentTimeMillis() - lastElapsedTime;
127 		if (deltaTime > MIN_RECALC_INTERVAL) {
128 			long deltaBytes = getBytesTransferred() - lastBytesTransferred;
129 			if (getElapsedTime() < RECALC_INTERVAL) {
130 				lastRate = (deltaBytes * 1000) / deltaTime;
131 			}
132 			else {
133 				lastBytesTransferred += deltaBytes;
134 				lastElapsedTime += deltaTime;
135 
136 				long t = RECALC_INTERVAL - deltaTime;
137 				if (t > 0) {
138 					// approximate how many bytes were transfered in the 
139 					// last RECALC_INTERVAL
140 					deltaBytes += (t * lastRate) / 1000;
141 					deltaTime = RECALC_INTERVAL;
142 				}
143 				lastRate = (deltaBytes * 1000) / deltaTime;
144 			}
145 		}
146 
147 		return lastRate;
148     }
149 
150     /***
151      * Returns null.
152      */
153     public String getDescription()
154 	{
155     	return null;
156     }
157     
158     /***
159      * Returns the number of milli seconds that have passed since the 
160      * transfer has been started.
161      */
162     public long getElapsedTime() 
163     {
164         return System.currentTimeMillis() - transferStartTime;
165     }
166 
167     public String getFilename()
168     {
169 		File f = getFile();
170 		return (f != null) ? f.getName() : "";
171     }
172 
173     public long getFilesize()
174     {
175 		File f = getFile();
176 		return (f != null) ? f.length() : 0;
177     }
178 
179     /***
180      * Returns null.
181      */
182     public Icon getIcon()
183     {
184 		return null;
185     }
186 
187 	/***
188 	 * Returns -1.
189 	 */
190 	public int getQueuePosition()
191 	{
192 		return -1;
193 	}
194 
195     public int getRemainingTime()
196     {
197 		long rate = getAverageRate();
198 		return (rate <= 0) ? -1 : 
199 			(int)((getFilesize() - getBytesTransferred()) / rate);
200     }
201 
202     public void removeStateListener(StateListener listener) 
203     {
204         listeners.removeStateListener(listener);
205     }
206 
207     /***
208      * Notifies all StateListeners that the state has changed.
209      */
210     protected void stateChanged()
211     {
212 		listeners.fireStateChanged();
213     }
214 
215     public String toString()
216     {
217 		return getFilename() + ", " + getFilesize();
218     }
219 
220     public Segment[] getSegments()
221     {
222 		return null;
223     }
224 
225 	/***
226 	 * Sub classes should invoke this method when the transfer has started.
227 	 */
228 	protected void transferStarted()
229 	{
230 		transferStartTime = System.currentTimeMillis();
231 		lastElapsedTime = System.currentTimeMillis();
232 		totalRate = -1;
233 	}
234 
235 	/***
236 	 * Sub classes should invoke this method when the transfer has stopped.
237 	 */
238 	protected void transferStopped()
239 	{
240 		if (getBytesTransferred() > 0) {
241 		    long rate = getAverageRate();
242 		    totalRate = (rate != -1) ? rate : getBytesTransferred();
243 		}
244 		transferStartTime = -1;
245 	}
246 
247 }