KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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;
12
13 import java.io.*;
14 import java.net.*;
15 import java.util.*;
16
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.osgi.util.NLS;
19
20 /**
21  * This class manages threads that are dispatched to
22  * obtained a valid input stream from an HTTP connection.
23  * Since obtaining an input stream is an I/O operation
24  * that may block for a long time, it is performed
25  * on a separate thread to keep the UI responsive.
26  * <p>
27  * In case that a connection blocks and does not
28  * terminate with an IOException after a timeout,
29  * active threads may accumulate. The manager will
30  * refuse to create more than MAX_COUNT threads and
31  * instead will throw a CoreException with a child
32  * status object for each connection that is still pending.
33  * <p>
34  * If the connection is responsive but slow, the user
35  * may cancel it. In that case, the manager will
36  * close the stream to avoid resource leak.
37  */

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

139     private void validateExistingThreads() throws CoreException {
140         if (threads == null)
141             return;
142             
143         int aliveCount = purgeTerminatedThreads();
144
145         if (aliveCount > MAX_COUNT) {
146             ArrayList children = new ArrayList();
147             String JavaDoc pluginId =
148                 UpdateCore.getPlugin().getBundle().getSymbolicName();
149             for (int i = 0; i < threads.size(); i++) {
150                 ConnectionThread t = (ConnectionThread) threads.get(i);
151                 String JavaDoc url = t.getRunnable().getURL().toString();
152                 IStatus status =
153                     new Status(
154                         IStatus.ERROR,
155                         pluginId,
156                         IStatus.OK,
157                         NLS.bind(Messages.ConnectionThreadManager_unresponsiveURL, (new String JavaDoc[] { url })),
158                         null);
159                 children.add(status);
160             }
161             MultiStatus parentStatus =
162                 new MultiStatus(
163                     pluginId,
164                     IStatus.OK,
165                     (IStatus[]) children.toArray(new IStatus[children.size()]),
166                     Messages.ConnectionThreadManager_tooManyConnections,
167                     null);
168             throw new CoreException(parentStatus);
169         }
170     }
171     
172     /*
173      * Removes terminated threads from the list and returns
174      * the number of those still active.
175      */

176     
177     private int purgeTerminatedThreads() {
178         int aliveCount = 0;
179
180         Object JavaDoc[] array = threads.toArray();
181         for (int i = 0; i < array.length; i++) {
182             Thread JavaDoc t = (Thread JavaDoc) array[i];
183             if (!t.isAlive())
184                 threads.remove(t);
185             else
186                 aliveCount++;
187         }
188         return aliveCount;
189     }
190
191     public void shutdown() {
192         // We might want to kill the active threads but
193
// this is not really necessary since they are all
194
// daemons and will not prevent JVM to terminate.
195
threads.clear();
196     }
197 }
198
Popular Tags