KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > update > internal > core > connection > ConnectionThreadManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.update.internal.core.connection;
12
13
14 import java.io.IOException JavaDoc;
15 import java.io.InputStream JavaDoc;
16 import java.net.HttpURLConnection JavaDoc;
17 import java.net.URL JavaDoc;
18 import java.net.URLConnection JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.List JavaDoc;
21
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.MultiStatus;
25 import org.eclipse.core.runtime.Status;
26 import org.eclipse.osgi.util.NLS;
27 import org.eclipse.update.internal.core.Messages;
28 import org.eclipse.update.internal.core.UpdateCore;
29
30 /**
31  * This class manages threads that are dispatched to
32  * obtained a valid input stream from an HTTP connection.
33  * Since obtaining an input stream is an I/O operation
34  * that may block for a long time, it is performed
35  * on a separate thread to keep the UI responsive.
36  * <p>
37  * In case that a connection blocks and does not
38  * terminate with an IOException after a timeout,
39  * active threads may accumulate. The manager will
40  * refuse to create more than MAX_COUNT threads and
41  * instead will throw a CoreException with a child
42  * status object for each connection that is still pending.
43  * <p>
44  * If the connection is responsive but slow, the user
45  * may cancel it. In that case, the manager will
46  * close the stream to avoid resource leak.
47  */

48 public class ConnectionThreadManager {
49     
50     // set connection timeout to 1 minute
51
private static final String JavaDoc CONNECT_TIMEOUT = "60000"; //$NON-NLS-1$
52
// set read timeout to 1 minute
53
private static final String JavaDoc READ_TIMEOUT = "60000"; //$NON-NLS-1$
54
// max number of active threads
55
private static final int MAX_COUNT = 9;
56     private List JavaDoc threads = new ArrayList JavaDoc(MAX_COUNT);
57     
58     
59
60     public static class StreamRunnable implements Runnable JavaDoc {
61         
62         private URLConnection JavaDoc urlConnection;
63         private IOException JavaDoc ioException;
64         private Exception JavaDoc exception;
65         private InputStream JavaDoc is;
66         private boolean disconnected;
67
68         public StreamRunnable(URLConnection JavaDoc urlConnection) {
69             this.urlConnection = urlConnection;
70         }
71
72         public InputStream JavaDoc getInputStream() {
73             return is;
74         }
75
76         public URL JavaDoc getURL() {
77             return urlConnection.getURL();
78         }
79
80         public IOException JavaDoc getIOException() {
81             return ioException;
82         }
83         
84         public Exception JavaDoc getException() {
85             return exception;
86         }
87
88         public void disconnect() {
89             if (urlConnection instanceof HttpURLConnection JavaDoc)
90                 ((HttpURLConnection JavaDoc)urlConnection).disconnect();
91             disconnected = true;
92         }
93
94         public void run() {
95             try {
96                 is = urlConnection.getInputStream();
97                 if (disconnected) {
98                     // The connection was slow, but returned
99
// a valid input stream. However,
100
// the user canceled the connection
101
// so we must close to avoid
102
// resource leak.
103
if (is != null) {
104                         try {
105                             is.close();
106                         } catch (IOException JavaDoc ex) {
107                             // at this point, we don't care
108
} finally {
109                             is = null;
110                         }
111                     }
112                 }
113             } catch (IOException JavaDoc e) {
114                 ioException = e;
115             } catch (Exception JavaDoc e) {
116                 exception = e;
117             } finally {
118                 //threads.
119
}
120         }
121     }
122
123     
124     class ConnectionThread extends Thread JavaDoc {
125         
126         private StreamRunnable runnable;
127         
128         public ConnectionThread(StreamRunnable runnable) {
129             super(runnable, "update-connection"); //$NON-NLS-1$
130
this.runnable = runnable;
131         }
132
133         public StreamRunnable getRunnable() {
134             return runnable;
135         }
136     }
137
138     public ConnectionThreadManager() {
139         // In case we are running Sun's code.
140
setIfNotDefaultProperty("sun.net.client.defaultConnectTimeout", CONNECT_TIMEOUT); //$NON-NLS-1$
141
setIfNotDefaultProperty("sun.net.client.defaultReadTimeout", READ_TIMEOUT); //$NON-NLS-1$
142
}
143     
144     private void setIfNotDefaultProperty(String JavaDoc key, String JavaDoc value) {
145         String JavaDoc oldValue = System.getProperty(key);
146         if (oldValue==null || oldValue.equals("-1")) //$NON-NLS-1$
147
System.setProperty(key, value);
148     }
149
150     public Thread JavaDoc getConnectionThread(StreamRunnable runnable) throws CoreException {
151         
152         validateExistingThreads();
153     
154         //if (threads == null)
155
// threads = new Vector();
156
Thread JavaDoc t = new Thread JavaDoc(runnable);
157         t.setDaemon(true);
158         threads.add(t);
159         return t;
160     }
161
162     /*
163      * Removes threads that are not alive any more from the
164      * list and ensures that there are at most MAX_COUNT threads
165      * still working.
166      */

167     private void validateExistingThreads() throws CoreException {
168         
169         if ((threads == null) || (threads.size() == 0))
170             return;
171         
172         int aliveCount = purgeTerminatedThreads();
173
174         if (aliveCount > MAX_COUNT) {
175             ArrayList JavaDoc children = new ArrayList JavaDoc();
176             String JavaDoc pluginId =
177                 UpdateCore.getPlugin().getBundle().getSymbolicName();
178             for (int i = 0; i < threads.size(); i++) {
179                 ConnectionThread t = (ConnectionThread) threads.get(i);
180                 String JavaDoc url = t.getRunnable().getURL().toString();
181                 IStatus status =
182                     new Status(
183                         IStatus.ERROR,
184                         pluginId,
185                         IStatus.OK,
186                         NLS.bind(Messages.ConnectionThreadManager_unresponsiveURL, (new String JavaDoc[] { url })),
187                         null);
188                 children.add(status);
189             }
190             MultiStatus parentStatus =
191                 new MultiStatus(
192                     pluginId,
193                     IStatus.OK,
194                     (IStatus[]) children.toArray(new IStatus[children.size()]),
195                     Messages.ConnectionThreadManager_tooManyConnections,
196                     null);
197             throw new CoreException(parentStatus);
198         }
199     }
200     
201     /*
202      * Removes terminated threads from the list and returns
203      * the number of those still active.
204      */

205     
206     private int purgeTerminatedThreads() {
207         
208         if (threads.size() == 0) {
209             return 0;
210         }
211         
212         int aliveCount = 0;
213
214         Object JavaDoc[] array = threads.toArray();
215         for (int i = 0; i < array.length; i++) {
216             Thread JavaDoc t = (Thread JavaDoc) array[i];
217             if (!t.isAlive())
218                 threads.remove(t);
219             else
220                 aliveCount++;
221         }
222         return aliveCount;
223     }
224
225     public void shutdown() {
226         // We might want to kill the active threads but
227
// this is not really necessary since they are all
228
// daemons and will not prevent JVM to terminate.
229
threads.clear();
230     }
231 }
232
Popular Tags