View Javadoc

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