View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2004 Intel Corporation
4    * 
5    *  This library is free software; you can redistribute it and/or
6    *  modify it under the terms of the GNU Lesser General Public
7    *  License as published by the Free Software Foundation; either
8    *  version 2.1 of the License, or (at your option) any later version.
9    *
10   *  This library 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 GNU
13   *  Lesser General Public License for more details.
14   *
15   *  You should have received a copy of the GNU Lesser General Public
16   *  License along with this library; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   *
19   *  @version $Id: BluetoothRFCommConnection.java 2164 2008-05-04 19:31:39Z skarzhevskyy $
20   */
21  package com.intel.bluetooth;
22  
23  import java.io.DataInputStream;
24  import java.io.DataOutputStream;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.OutputStream;
28  
29  import javax.bluetooth.RemoteDevice;
30  import javax.bluetooth.ServiceRecord;
31  import javax.microedition.io.StreamConnection;
32  
33  /**
34   * All StreamConnections have one underlying InputStream and one OutputStream.
35   * Opening a DataInputStream counts as opening an InputStream and opening a
36   * DataOutputStream counts as opening an OutputStream. Trying to open another
37   * InputStream or OutputStream causes an IOException. Trying to open the
38   * InputStream or OutputStream after they have been closed causes an
39   * IOException.
40   * <p>
41   * The methods of StreamConnection are not synchronized. The only stream method
42   * that can be called safely in another thread is close.
43   * 
44   * 
45   */
46  abstract class BluetoothRFCommConnection implements StreamConnection, BluetoothConnectionAccess {
47  
48  	protected BluetoothStack bluetoothStack;
49  
50  	protected volatile long handle;
51  
52  	private BluetoothRFCommInputStream in;
53  
54  	private BluetoothRFCommOutputStream out;
55  
56  	private boolean isClosed;
57  
58  	protected int securityOpt;
59  
60  	RemoteDevice remoteDevice;
61  
62  	protected BluetoothRFCommConnection(BluetoothStack bluetoothStack, long handle) {
63  		this.bluetoothStack = bluetoothStack;
64  		this.handle = handle;
65  		this.isClosed = false;
66  	}
67  
68  	abstract void closeConnectionHandle(long handle) throws IOException;
69  
70  	/**
71  	 * Close the connection.
72  	 * <p>
73  	 * Streams derived from the connection may be open when close() method is
74  	 * called. Any open streams will cause the connection to be held open until
75  	 * they themselves are closed. In this latter case access to the open
76  	 * streams is permitted, but access to the connection is not.
77  	 * 
78  	 * @throws IOException
79  	 *             If an I/O error occurs
80  	 */
81  	void streamClosed() throws IOException {
82  		// Closing streams does not close connection
83  		if (!isClosed) {
84  			return;
85  		}
86  
87  		// Any open streams will cause the connection to be held open
88  		if ((in != null) && (!in.isClosed())) {
89  			return;
90  		}
91  
92  		if ((out != null) && (!out.isClosed())) {
93  			return;
94  		}
95  
96  		shutdown();
97  	}
98  
99  	/*
100 	 * (non-Javadoc)
101 	 * 
102 	 * @see com.intel.bluetooth.BluetoothConnectionAccess#shutdown()
103 	 */
104 	public void shutdown() throws IOException {
105 		if (handle != 0) {
106 			DebugLog.debug("closing RFCOMM Connection", handle);
107 			// close() can be called safely in another thread
108 			long synchronizedHandle;
109 			synchronized (this) {
110 				synchronizedHandle = handle;
111 				handle = 0;
112 			}
113 			if (synchronizedHandle != 0) {
114 				closeConnectionHandle(synchronizedHandle);
115 			}
116 		}
117 	}
118 
119 	/**
120 	 * Open and return an input stream for a connection.
121 	 * <p>
122 	 * Trying to open another InputStream or OutputStream causes an IOException.
123 	 * <p>
124 	 * Trying to open the InputStream or OutputStream after they have been
125 	 * closed causes an IOException.
126 	 * 
127 	 * @return An input stream
128 	 * 
129 	 * @throws IOException
130 	 *             If an I/O error occurs
131 	 */
132 	public InputStream openInputStream() throws IOException {
133 		if (isClosed) {
134 			throw new IOException("RFCOMM Connection is already closed");
135 		} else {
136 			if (in == null) {
137 				in = new BluetoothRFCommInputStream(this);
138 				return in;
139 			} else if (in.isClosed()) {
140 				throw new IOException("Stream cannot be reopened");
141 			} else {
142 				throw new IOException("Another InputStream already opened");
143 			}
144 		}
145 	}
146 
147 	/**
148 	 * Open and return an data input stream for a connection.
149 	 * <p>
150 	 * Opening a DataInputStream counts as opening an InputStream
151 	 * <p>
152 	 * Trying to open another InputStream or OutputStream causes an IOException.
153 	 * <p>
154 	 * Trying to open the InputStream or OutputStream after they have been
155 	 * closed causes an IOException.
156 	 * 
157 	 * @return An input stream
158 	 * 
159 	 * @throws IOException
160 	 *             If an I/O error occurs
161 	 */
162 	public DataInputStream openDataInputStream() throws IOException {
163 		return new DataInputStream(openInputStream());
164 	}
165 
166 	/**
167 	 * Open and return an output stream for a connection.
168 	 * <p>
169 	 * Trying to open another InputStream or OutputStream causes an IOException.
170 	 * <p>
171 	 * Trying to open the InputStream or OutputStream after they have been
172 	 * closed causes an IOException.
173 	 * 
174 	 * @return An output stream
175 	 * 
176 	 * @throws IOException
177 	 *             If an I/O error occurs
178 	 */
179 	public OutputStream openOutputStream() throws IOException {
180 		if (isClosed) {
181 			throw new IOException("RFCOMM Connection is already closed");
182 		} else {
183 			if (out == null) {
184 				out = new BluetoothRFCommOutputStream(this);
185 				return out;
186 			} else if (out.isClosed()) {
187 				throw new IOException("Stream cannot be reopened");
188 			} else {
189 				throw new IOException("Another OutputStream already opened");
190 			}
191 		}
192 	}
193 
194 	/**
195 	 * Open and return an data output stream for a connection.
196 	 * <p>
197 	 * Opening a DataOutputStream counts as opening an OutputStream
198 	 * <p>
199 	 * Trying to open another InputStream or OutputStream causes an IOException.
200 	 * <p>
201 	 * Trying to open the InputStream or OutputStream after they have been
202 	 * closed causes an IOException.
203 	 * 
204 	 * @return An output stream
205 	 * 
206 	 * @throws IOException
207 	 *             If an I/O error occurs
208 	 */
209 	public DataOutputStream openDataOutputStream() throws IOException {
210 		return new DataOutputStream(openOutputStream());
211 	}
212 
213 	/**
214 	 * Close the connection.
215 	 * <p>
216 	 * When a connection has been closed, access to any of its methods except
217 	 * this close() will cause an an IOException to be thrown. Closing an
218 	 * already closed connection has no effect. Streams derived from the
219 	 * connection may be open when method is called. Any open streams will cause
220 	 * the connection to be held open until they themselves are closed. In this
221 	 * latter case access to the open streams is permitted, but access to the
222 	 * connection is not.
223 	 * 
224 	 * @throws IOException
225 	 *             If an I/O error occurs
226 	 */
227 	public void close() throws IOException {
228 		if (isClosed) {
229 			return;
230 		}
231 		isClosed = true;
232 		streamClosed();
233 	}
234 
235 	protected void finalize() {
236 		try {
237 			close();
238 		} catch (IOException e) {
239 		}
240 	}
241 
242 	/*
243 	 * (non-Javadoc)
244 	 * 
245 	 * @see com.intel.bluetooth.BluetoothConnectionAccess#isClosed()
246 	 */
247 	public boolean isClosed() {
248 		return isClosed;
249 	}
250 
251 	/*
252 	 * (non-Javadoc)
253 	 * 
254 	 * @see com.intel.bluetooth.BluetoothConnectionAccess#markAuthenticated()
255 	 */
256 	public void markAuthenticated() {
257 		if (this.securityOpt == ServiceRecord.NOAUTHENTICATE_NOENCRYPT) {
258 			this.securityOpt = ServiceRecord.AUTHENTICATE_NOENCRYPT;
259 		}
260 	}
261 
262 	/*
263 	 * (non-Javadoc)
264 	 * 
265 	 * @see com.intel.bluetooth.BluetoothConnectionAccess#getSecurityOpt()
266 	 */
267 	public int getSecurityOpt() {
268 		try {
269 			this.securityOpt = bluetoothStack.rfGetSecurityOpt(this.handle, this.securityOpt);
270 		} catch (IOException notChanged) {
271 		}
272 		return this.securityOpt;
273 	}
274 
275 	/*
276 	 * (non-Javadoc)
277 	 * 
278 	 * @see com.intel.bluetooth.BluetoothConnectionAccess#encrypt(boolean)
279 	 */
280 	public boolean encrypt(long address, boolean on) throws IOException {
281 		if (isClosed) {
282 			throw new IOException("RFCOMM Connection is already closed");
283 		}
284 		boolean changed = bluetoothStack.rfEncrypt(address, this.handle, on);
285 		if (changed) {
286 			if (on) {
287 				this.securityOpt = ServiceRecord.AUTHENTICATE_ENCRYPT;
288 			} else {
289 				this.securityOpt = ServiceRecord.AUTHENTICATE_NOENCRYPT;
290 			}
291 		}
292 		return changed;
293 	}
294 
295 	/*
296 	 * (non-Javadoc)
297 	 * 
298 	 * @see com.intel.bluetooth.BluetoothConnectionAccess#getRemoteAddress()
299 	 */
300 	public long getRemoteAddress() throws IOException {
301 		if (isClosed) {
302 			throw new IOException("Connection closed");
303 		}
304 		return bluetoothStack.getConnectionRfRemoteAddress(handle);
305 	}
306 
307 	/*
308 	 * (non-Javadoc)
309 	 * 
310 	 * @see com.intel.bluetooth.BluetoothConnectionAccess#getRemoteDevice()
311 	 */
312 	public RemoteDevice getRemoteDevice() {
313 		return this.remoteDevice;
314 	}
315 
316 	/*
317 	 * (non-Javadoc)
318 	 * 
319 	 * @see com.intel.bluetooth.BluetoothConnectionAccess#setRemoteDevice(javax.bluetooth.RemoteDevice)
320 	 */
321 	public void setRemoteDevice(RemoteDevice remoteDevice) {
322 		this.remoteDevice = remoteDevice;
323 	}
324 
325 	/*
326 	 * (non-Javadoc)
327 	 * 
328 	 * @see com.intel.bluetooth.BluetoothConnectionAccess#getBluetoothStack()
329 	 */
330 	public BluetoothStack getBluetoothStack() {
331 		return bluetoothStack;
332 	}
333 }