View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2004 Intel Corporation
4    *  Copyright (C) 2006-2008 Vlad Skarzhevskyy
5    * 
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or (at your option) any later version.
10   *
11   *  This library is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   *
20   *  @version $Id: MicroeditionConnector.java 2046 2008-04-16 15:55:38Z skarzhevskyy $
21   */
22  package com.intel.bluetooth;
23  
24  import java.io.DataInputStream;
25  import java.io.DataOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.OutputStream;
29  import java.util.Enumeration;
30  import java.util.Hashtable;
31  
32  import javax.bluetooth.BluetoothConnectionException;
33  import javax.bluetooth.L2CAPConnection;
34  import javax.bluetooth.UUID;
35  import javax.microedition.io.Connection;
36  import javax.microedition.io.ConnectionNotFoundException;
37  import javax.microedition.io.Connector;
38  import javax.microedition.io.InputConnection;
39  import javax.microedition.io.OutputConnection;
40  
41  import com.intel.bluetooth.gcf.socket.ServerSocketConnection;
42  import com.intel.bluetooth.gcf.socket.SocketConnection;
43  import com.intel.bluetooth.obex.OBEXClientSessionImpl;
44  import com.intel.bluetooth.obex.OBEXConnectionParams;
45  import com.intel.bluetooth.obex.OBEXSessionNotifierImpl;
46  
47  /**
48   * 
49   * Implementation of javax.microedition.io.Connector
50   * <p>
51   * <b><u>Your application should not use this class directly.</u></b>
52   * <p>
53   * BlueCove specific JSR-82 extension <tt>bluecovepsm</tt> enables the use of
54   * specific PSM channel in L2CAP service.
55   * <tt>btl2cap://localhost;name=...;bluecovepsm=1007</tt>
56   */
57  public abstract class MicroeditionConnector {
58  	/*
59  	 * Access mode READ. The value 1 is assigned to READ.
60  	 */
61  
62  	public static final int READ = Connector.READ;
63  
64  	/*
65  	 * Access mode WRITE. The value 2 is assigned to WRITE.
66  	 */
67  
68  	public static final int WRITE = Connector.WRITE;
69  
70  	/*
71  	 * Access mode READ_WRITE. The value 3 is assigned to READ_WRITE.
72  	 */
73  
74  	public static final int READ_WRITE = Connector.READ_WRITE;
75  
76  	private static Hashtable/* <String, String> */suportScheme = new Hashtable();
77  
78  	private static Hashtable/* <String, String> */srvParams = new Hashtable();
79  
80  	private static Hashtable/* <String, String> */cliParams = new Hashtable();
81  
82  	private static Hashtable/* <String, String> */cliParamsL2CAP = new Hashtable();
83  
84  	private static Hashtable/* <String, String> */srvParamsL2CAP = new Hashtable();
85  
86  	private static final String AUTHENTICATE = "authenticate";
87  
88  	private static final String AUTHORIZE = "authorize";
89  
90  	private static final String ENCRYPT = "encrypt";
91  
92  	private static final String MASTER = "master";
93  
94  	private static final String NAME = "name";
95  
96  	private static final String RECEIVE_MTU = "receivemtu";
97  
98  	private static final String TRANSMIT_MTU = "transmitmtu";
99  
100 	private static final String EXT_BLUECOVE_L2CAP_PSM = "bluecovepsm";
101 
102 	static {
103 		// cliParams ::== master | encrypt | authenticate
104 		cliParams.put(AUTHENTICATE, AUTHENTICATE);
105 		cliParams.put(ENCRYPT, ENCRYPT);
106 		cliParams.put(MASTER, MASTER);
107 
108 		// srvParams ::== name | master | encrypt | authorize | authenticate
109 		copyAll(srvParams, cliParams);
110 		srvParams.put(AUTHORIZE, AUTHORIZE);
111 		srvParams.put(NAME, NAME);
112 
113 		copyAll(cliParamsL2CAP, cliParams);
114 
115 		cliParamsL2CAP.put(RECEIVE_MTU, RECEIVE_MTU);
116 		cliParamsL2CAP.put(TRANSMIT_MTU, TRANSMIT_MTU);
117 
118 		copyAll(srvParamsL2CAP, cliParamsL2CAP);
119 		srvParamsL2CAP.put(AUTHORIZE, AUTHORIZE);
120 		srvParamsL2CAP.put(NAME, NAME);
121 		srvParamsL2CAP.put(EXT_BLUECOVE_L2CAP_PSM, EXT_BLUECOVE_L2CAP_PSM);
122 
123 		// "socket://" host ":" port
124 		// no validation for socket, since this is internal connector
125 
126 		suportScheme.put(BluetoothConsts.PROTOCOL_SCHEME_RFCOMM, Boolean.TRUE);
127 		suportScheme.put(BluetoothConsts.PROTOCOL_SCHEME_BT_OBEX, Boolean.TRUE);
128 		suportScheme.put(BluetoothConsts.PROTOCOL_SCHEME_TCP_OBEX, Boolean.TRUE);
129 		suportScheme.put(BluetoothConsts.PROTOCOL_SCHEME_L2CAP, Boolean.TRUE);
130 		suportScheme.put("socket", Boolean.TRUE);
131 	}
132 
133 	private MicroeditionConnector() {
134 
135 	}
136 
137 	static void copyAll(Hashtable dest, Hashtable src) {
138 		for (Enumeration en = src.keys(); en.hasMoreElements();) {
139 			Object key = en.nextElement();
140 			dest.put(key, src.get(key));
141 		}
142 	}
143 
144 	static String validParamName(Hashtable map, String paramName) {
145 		String validName = (String) map.get(paramName.toLowerCase());
146 		if (validName != null) {
147 			return validName;
148 		}
149 		return null;
150 	}
151 
152 	/*
153 	 * Create and open a Connection. Parameters: name - The URL for the
154 	 * connection. Returns: A new Connection object. Throws:
155 	 * IllegalArgumentException - If a parameter is invalid.
156 	 * ConnectionNotFoundException - If the requested connection cannot be made,
157 	 * or the protocol type does not exist. java.io.IOException - If some other
158 	 * kind of I/O error occurs. SecurityException - If a requested protocol
159 	 * handler is not permitted.
160 	 */
161 
162 	public static Connection open(String name) throws IOException {
163 		return openImpl(name, READ_WRITE, false, true);
164 	}
165 
166 	private static Connection openImpl(String name, int mode, boolean timeouts, boolean allowServer) throws IOException {
167 
168 		DebugLog.debug("connecting", name);
169 
170 		/*
171 		 * parse URL
172 		 */
173 
174 		String host = null;
175 		String portORuuid = null;
176 
177 		Hashtable values = new Hashtable();
178 
179 		// scheme : // host : port [;param=val]
180 		int schemeEnd = name.indexOf("://");
181 		if (schemeEnd == -1) {
182 			throw new ConnectionNotFoundException(name);
183 		}
184 		String scheme = name.substring(0, schemeEnd);
185 		if (!suportScheme.containsKey(scheme)) {
186 			throw new ConnectionNotFoundException(scheme);
187 		}
188 		boolean schemeBluetooth = (scheme.equals(BluetoothConsts.PROTOCOL_SCHEME_RFCOMM))
189 				|| (scheme.equals(BluetoothConsts.PROTOCOL_SCHEME_BT_OBEX) || (scheme
190 						.equals(BluetoothConsts.PROTOCOL_SCHEME_L2CAP)));
191 		boolean isL2CAP = scheme.equals(BluetoothConsts.PROTOCOL_SCHEME_L2CAP);
192 		boolean isTCPOBEX = scheme.equals(BluetoothConsts.PROTOCOL_SCHEME_TCP_OBEX);
193 
194 		BluetoothStack bluetoothStack = null;
195 
196 		if (schemeBluetooth) {
197 			bluetoothStack = BlueCoveImpl.instance().getBluetoothStack();
198 		}
199 
200 		boolean isServer;
201 
202 		int hostEnd = name.indexOf(':', scheme.length() + 3);
203 
204 		if (hostEnd > -1) {
205 			host = name.substring(scheme.length() + 3, hostEnd);
206 			isServer = host.equals("localhost");
207 
208 			Hashtable params;
209 			if (isTCPOBEX) {
210 				params = new Hashtable();
211 				isServer = (host.length() == 0);
212 			} else if (isL2CAP) {
213 				if (isServer) {
214 					params = srvParamsL2CAP;
215 				} else {
216 					params = cliParamsL2CAP;
217 				}
218 			} else {
219 				if (isServer) {
220 					params = srvParams;
221 				} else {
222 					params = cliParams;
223 				}
224 			}
225 
226 			String paramsStr = name.substring(hostEnd + 1);
227 			UtilsStringTokenizer tok = new UtilsStringTokenizer(paramsStr, ";");
228 			if (tok.hasMoreTokens()) {
229 				portORuuid = tok.nextToken();
230 			} else {
231 				portORuuid = paramsStr;
232 			}
233 			while (tok.hasMoreTokens()) {
234 				String t = tok.nextToken();
235 				int equals = t.indexOf('=');
236 				if (equals > -1) {
237 					String param = t.substring(0, equals);
238 					String value = t.substring(equals + 1);
239 					String validName = validParamName(params, param);
240 					if (validName != null) {
241 						String hasValue = (String) values.get(validName);
242 						if ((hasValue != null) && (!hasValue.equals(value))) {
243 							throw new IllegalArgumentException("duplicate param [" + param + "] value [" + value + "]");
244 						}
245 						values.put(validName, value);
246 					} else {
247 						throw new IllegalArgumentException("invalid param [" + param + "] value [" + value + "]");
248 					}
249 				} else {
250 					throw new IllegalArgumentException("invalid param [" + t + "]");
251 				}
252 			}
253 		} else if (isTCPOBEX) {
254 			host = name.substring(scheme.length() + 3);
255 			isServer = (host.length() == 0);
256 		} else {
257 			throw new IllegalArgumentException(name.substring(scheme.length() + 3));
258 		}
259 
260 		if (isTCPOBEX) {
261 			if ((portORuuid == null) || (portORuuid.length() == 0)) {
262 				portORuuid = String.valueOf(BluetoothConsts.TCP_OBEX_DEFAULT_PORT);
263 			}
264 			// else {
265 			// try {
266 			// int port = Integer.parseInt(portORuuid);
267 			// if ((port < 1023) && (port !=
268 			// BluetoothConsts.TCP_OBEX_DEFAULT_PORT)) {
269 			// throw new IllegalArgumentException("Port " + portORuuid + " can't
270 			// be used; the 0-1023 range is reserved");
271 			// }
272 			// } catch (NumberFormatException e) {
273 			// throw new IllegalArgumentException("port " + portORuuid);
274 			// }
275 			// }
276 		}
277 
278 		if (host == null || portORuuid == null) {
279 			throw new IllegalArgumentException();
280 		}
281 
282 		BluetoothConnectionNotifierParams notifierParams = null;
283 
284 		BluetoothConnectionParams connectionParams = null;
285 
286 		int channel = 0;
287 		if (isServer) {
288 			if (!allowServer) {
289 				throw new IllegalArgumentException("Can't use server connection URL");
290 			}
291 			if (values.get(NAME) == null) {
292 				values.put(NAME, "BlueCove");
293 			} else if (schemeBluetooth) {
294 				validateBluetoothServiceName((String) values.get(NAME));
295 			}
296 			if (schemeBluetooth) {
297 				notifierParams = new BluetoothConnectionNotifierParams(new UUID(portORuuid, false), paramBoolean(
298 						values, AUTHENTICATE), paramBoolean(values, ENCRYPT), paramBoolean(values, AUTHORIZE),
299 						(String) values.get(NAME), paramBoolean(values, MASTER));
300 				notifierParams.timeouts = timeouts;
301 				if (notifierParams.encrypt && (!notifierParams.authenticate)) {
302 					if (values.get(AUTHENTICATE) == null) {
303 						notifierParams.authenticate = true;
304 					} else {
305 						throw new BluetoothConnectionException(BluetoothConnectionException.UNACCEPTABLE_PARAMS,
306 								"encryption requires authentication");
307 					}
308 				}
309 				if (notifierParams.authorize && (!notifierParams.authenticate)) {
310 					if (values.get(AUTHENTICATE) == null) {
311 						notifierParams.authenticate = true;
312 					} else {
313 						throw new BluetoothConnectionException(BluetoothConnectionException.UNACCEPTABLE_PARAMS,
314 								"authorization requires authentication");
315 					}
316 				}
317 				if (isL2CAP) {
318 					String bluecove_ext_psm = (String) values.get(EXT_BLUECOVE_L2CAP_PSM);
319 					if (bluecove_ext_psm != null) {
320 						int psm = Integer.parseInt(bluecove_ext_psm, 16);
321 						validateL2CAPPSM(psm, bluecove_ext_psm);
322 						notifierParams.bluecove_ext_psm = psm;
323 					}
324 				}
325 			}
326 		} else { // (!isServer)
327 			try {
328 				channel = Integer.parseInt(portORuuid, isL2CAP ? 16 : 10);
329 			} catch (NumberFormatException e) {
330 				throw new IllegalArgumentException("channel " + portORuuid);
331 			}
332 			if (channel < 0) {
333 				throw new IllegalArgumentException("channel " + portORuuid);
334 			}
335 			if (schemeBluetooth) {
336 				if (isL2CAP) {
337 					validateL2CAPPSM(channel, portORuuid);
338 				} else {
339 					if ((channel < BluetoothConsts.RFCOMM_CHANNEL_MIN)
340 							|| (channel > BluetoothConsts.RFCOMM_CHANNEL_MAX)) {
341 						throw new IllegalArgumentException("RFCOMM channel " + portORuuid);
342 					}
343 				}
344 
345 				connectionParams = new BluetoothConnectionParams(RemoteDeviceHelper.getAddress(host), channel,
346 						paramBoolean(values, AUTHENTICATE), paramBoolean(values, ENCRYPT));
347 				connectionParams.timeouts = timeouts;
348 				if (connectionParams.encrypt && (!connectionParams.authenticate)) {
349 					if (values.get(AUTHENTICATE) == null) {
350 						connectionParams.authenticate = true;
351 					} else {
352 						throw new BluetoothConnectionException(BluetoothConnectionException.UNACCEPTABLE_PARAMS,
353 								"encryption requires authentication");
354 					}
355 				}
356 				String timeout = BlueCoveImpl.getConfigProperty(BlueCoveConfigProperties.PROPERTY_CONNECT_TIMEOUT);
357 				if (timeout != null) {
358 					connectionParams.timeout = Integer.parseInt(timeout);
359 				}
360 			}
361 		}
362 		OBEXConnectionParams obexConnectionParams = null;
363 
364 		if (scheme.equals(BluetoothConsts.PROTOCOL_SCHEME_TCP_OBEX)
365 				|| scheme.equals(BluetoothConsts.PROTOCOL_SCHEME_BT_OBEX)) {
366 			obexConnectionParams = new OBEXConnectionParams();
367 			obexConnectionParams.timeouts = timeouts;
368 			String timeout = BlueCoveImpl.getConfigProperty(BlueCoveConfigProperties.PROPERTY_OBEX_TIMEOUT);
369 			if (timeout != null) {
370 				obexConnectionParams.timeout = Integer.parseInt(timeout);
371 			}
372 			String mtu = BlueCoveImpl.getConfigProperty(BlueCoveConfigProperties.PROPERTY_OBEX_MTU);
373 			if (mtu != null) {
374 				obexConnectionParams.mtu = Integer.parseInt(mtu);
375 			}
376 		}
377 
378 		/*
379 		 * create connection
380 		 */
381 		if (scheme.equals(BluetoothConsts.PROTOCOL_SCHEME_RFCOMM)) {
382 			if (isServer) {
383 				return new BluetoothRFCommConnectionNotifier(bluetoothStack, notifierParams);
384 			} else {
385 				return new BluetoothRFCommClientConnection(bluetoothStack, connectionParams);
386 			}
387 		} else if (scheme.equals(BluetoothConsts.PROTOCOL_SCHEME_BT_OBEX)) {
388 			if (isServer) {
389 				notifierParams.obex = true;
390 				return new OBEXSessionNotifierImpl(
391 						new BluetoothRFCommConnectionNotifier(bluetoothStack, notifierParams), obexConnectionParams);
392 			} else {
393 				return new OBEXClientSessionImpl(new BluetoothRFCommClientConnection(bluetoothStack, connectionParams),
394 						obexConnectionParams);
395 			}
396 		} else if (scheme.equals(BluetoothConsts.PROTOCOL_SCHEME_L2CAP)) {
397 			if (isServer) {
398 				return new BluetoothL2CAPConnectionNotifier(bluetoothStack, notifierParams, paramL2CAPMTU(values,
399 						RECEIVE_MTU), paramL2CAPMTU(values, TRANSMIT_MTU));
400 			} else {
401 				return new BluetoothL2CAPClientConnection(bluetoothStack, connectionParams, paramL2CAPMTU(values,
402 						RECEIVE_MTU), paramL2CAPMTU(values, TRANSMIT_MTU));
403 			}
404 		} else if (scheme.equals(BluetoothConsts.PROTOCOL_SCHEME_TCP_OBEX)) {
405 			if (isServer) {
406 				try {
407 					channel = Integer.parseInt(portORuuid);
408 				} catch (NumberFormatException e) {
409 					throw new IllegalArgumentException("port " + portORuuid);
410 				}
411 				return new OBEXSessionNotifierImpl(new ServerSocketConnection(channel), obexConnectionParams);
412 			} else {
413 				return new OBEXClientSessionImpl(new SocketConnection(host, channel), obexConnectionParams);
414 			}
415 		} else if (scheme.equals("socket")) {
416 			if (isServer) {
417 				try {
418 					channel = Integer.parseInt(portORuuid);
419 				} catch (NumberFormatException e) {
420 					throw new IllegalArgumentException("port " + portORuuid);
421 				}
422 				return new ServerSocketConnection(channel);
423 			} else {
424 				return new SocketConnection(host, channel);
425 			}
426 		} else {
427 			throw new ConnectionNotFoundException(scheme);
428 		}
429 	}
430 
431 	private static void validateL2CAPPSM(int channel, String channelAsString) throws IllegalArgumentException {
432 		// Valid PSM range: 0x0001-0x0019 (0x1001-0xFFFF dynamically
433 		// assigned, 0x0019-0x0100 reserved for future use).
434 		if ((channel < BluetoothConsts.L2CAP_PSM_MIN) || (channel > BluetoothConsts.L2CAP_PSM_MAX)) {
435 			// PSM 1 discovery, 3 RFCOMM
436 			throw new IllegalArgumentException("PCM " + channelAsString);
437 		}
438 		// has the 9th bit (0x100) set to zero
439 		if ((channel & 0x100) != 0) {
440 			throw new IllegalArgumentException("9th bit set in PCM " + channelAsString);
441 		}
442 		if ((channel % 2) == 0) {
443 			throw new IllegalArgumentException("PSM value " + channelAsString + " should be odd");
444 		}
445 	}
446 
447 	private static void validateBluetoothServiceName(String serviceName) {
448 		if (serviceName.length() == 0) {
449 			throw new IllegalArgumentException("zero length service name");
450 		}
451 		final String allowNameCharactes = " -_";
452 		for (int i = 0; i < serviceName.length(); i++) {
453 			char c = serviceName.charAt(i);
454 			if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')
455 					|| allowNameCharactes.indexOf(c) != -1) {
456 				continue;
457 			}
458 			throw new IllegalArgumentException("Illegal character '" + c + "' in service name");
459 		}
460 	}
461 
462 	private static boolean paramBoolean(Hashtable values, String name) {
463 		String v = (String) values.get(name);
464 		if (v == null) {
465 			return false;
466 		} else if ("true".equals(v)) {
467 			return true;
468 		} else if ("false".equals(v)) {
469 			return false;
470 		} else {
471 			throw new IllegalArgumentException("invalid param value " + name + "=" + v);
472 		}
473 	}
474 
475 	private static int paramL2CAPMTU(Hashtable values, String name) {
476 		String v = (String) values.get(name);
477 		if (v == null) {
478 			if (name.equals(TRANSMIT_MTU)) {
479 				// This will select RemoteMtu
480 				return -1;
481 			} else {
482 				return L2CAPConnection.DEFAULT_MTU;
483 			}
484 		}
485 		try {
486 			int mtu = Integer.parseInt(v);
487 			if (mtu >= L2CAPConnection.MINIMUM_MTU) {
488 				return mtu;
489 			}
490 			if ((mtu > 0) && (mtu < L2CAPConnection.MINIMUM_MTU) && (name.equals(TRANSMIT_MTU))) {
491 				return L2CAPConnection.MINIMUM_MTU;
492 			}
493 		} catch (NumberFormatException e) {
494 			throw new IllegalArgumentException("invalid MTU value " + v);
495 		}
496 		throw new IllegalArgumentException("invalid MTU param value " + name + "=" + v);
497 	}
498 
499 	/*
500 	 * Create and open a Connection. Parameters: name - The URL for the
501 	 * connection. mode - The access mode. Returns: A new Connection object.
502 	 * Throws: IllegalArgumentException - If a parameter is invalid.
503 	 * ConnectionNotFoundException - If the requested connection cannot be made,
504 	 * or the protocol type does not exist. java.io.IOException - If some other
505 	 * kind of I/O error occurs. SecurityException - If a requested protocol
506 	 * handler is not permitted.
507 	 */
508 
509 	public static Connection open(String name, int mode) throws IOException {
510 		return openImpl(name, mode, false, true);
511 	}
512 
513 	/*
514 	 * Create and open a Connection. Parameters: name - The URL for the
515 	 * connection mode - The access mode timeouts - A flag to indicate that the
516 	 * caller wants timeout exceptions Returns: A new Connection object Throws:
517 	 * IllegalArgumentException - If a parameter is invalid.
518 	 * ConnectionNotFoundException - if the requested connection cannot be made,
519 	 * or the protocol type does not exist. java.io.IOException - If some other
520 	 * kind of I/O error occurs. SecurityException - If a requested protocol
521 	 * handler is not permitted.
522 	 */
523 
524 	public static Connection open(String name, int mode, boolean timeouts) throws IOException {
525 		return openImpl(name, mode, timeouts, true);
526 	}
527 
528 	/*
529 	 * Create and open a connection input stream. Parameters: name - The URL for
530 	 * the connection. Returns: A DataInputStream. Throws:
531 	 * IllegalArgumentException - If a parameter is invalid.
532 	 * ConnectionNotFoundException - If the connection cannot be found.
533 	 * java.io.IOException - If some other kind of I/O error occurs.
534 	 * SecurityException - If access to the requested stream is not permitted.
535 	 */
536 
537 	public static DataInputStream openDataInputStream(String name) throws IOException {
538 		return new DataInputStream(openInputStream(name));
539 	}
540 
541 	/*
542 	 * Create and open a connection output stream. Parameters: name - The URL
543 	 * for the connection. Returns: A DataOutputStream. Throws:
544 	 * IllegalArgumentException - If a parameter is invalid.
545 	 * ConnectionNotFoundException - If the connection cannot be found.
546 	 * java.io.IOException - If some other kind of I/O error occurs.
547 	 * SecurityException - If access to the requested stream is not permitted.
548 	 */
549 
550 	public static DataOutputStream openDataOutputStream(String name) throws IOException {
551 		return new DataOutputStream(openOutputStream(name));
552 	}
553 
554 	/*
555 	 * Create and open a connection input stream. Parameters: name - The URL for
556 	 * the connection. Returns: An InputStream. Throws: IllegalArgumentException -
557 	 * If a parameter is invalid. ConnectionNotFoundException - If the
558 	 * connection cannot be found. java.io.IOException - If some other kind of
559 	 * I/O error occurs. SecurityException - If access to the requested stream
560 	 * is not permitted.
561 	 */
562 
563 	public static InputStream openInputStream(String name) throws IOException {
564 		InputConnection con = ((InputConnection) openImpl(name, READ, false, false));
565 		try {
566 			return con.openInputStream();
567 		} finally {
568 			con.close();
569 		}
570 	}
571 
572 	/*
573 	 * Create and open a connection output stream. Parameters: name - The URL
574 	 * for the connection. Returns: An OutputStream. Throws:
575 	 * IllegalArgumentException - If a parameter is invalid.
576 	 * ConnectionNotFoundException - If the connection cannot be found.
577 	 * java.io.IOException - If some other kind of I/O error occurs.
578 	 * SecurityException - If access to the requested stream is not permitted.
579 	 */
580 
581 	public static OutputStream openOutputStream(String name) throws IOException {
582 		OutputConnection con = ((OutputConnection) openImpl(name, WRITE, false, false));
583 		try {
584 			return con.openOutputStream();
585 		} finally {
586 			con.close();
587 		}
588 	}
589 
590 }