View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2006-2008 Vlad Skarzhevskyy
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: BluetoothConnectionNotifierBase.java 2171 2008-05-06 15:27:15Z skarzhevskyy $
20   */
21  package com.intel.bluetooth;
22  
23  import java.io.IOException;
24  import java.util.Enumeration;
25  import java.util.Hashtable;
26  import java.util.Vector;
27  
28  import javax.bluetooth.BluetoothStateException;
29  import javax.bluetooth.DataElement;
30  import javax.bluetooth.ServiceRecord;
31  import javax.bluetooth.ServiceRegistrationException;
32  import javax.microedition.io.Connection;
33  
34  /**
35   * @author vlads
36   * 
37   */
38  abstract class BluetoothConnectionNotifierBase implements Connection, BluetoothConnectionNotifierServiceRecordAccess {
39  
40  	private static Hashtable stackConnections = new Hashtable();
41  
42  	protected BluetoothStack bluetoothStack;
43  
44  	protected volatile long handle;
45  
46  	protected ServiceRecordImpl serviceRecord;
47  
48  	protected boolean closed;
49  
50  	protected int securityOpt;
51  
52  	static void shutdownConnections(BluetoothStack bluetoothStack) {
53  		Vector connections;
54  		synchronized (stackConnections) {
55  			connections = (Vector) stackConnections.get(bluetoothStack);
56  		}
57  		if (connections == null) {
58  			return;
59  		}
60  		Vector c2shutdown = new Vector();
61  		c2shutdown = Utils.clone(connections.elements());
62  		for (Enumeration en = c2shutdown.elements(); en.hasMoreElements();) {
63  			BluetoothConnectionNotifierBase c = (BluetoothConnectionNotifierBase) en.nextElement();
64  			try {
65  				c.shutdown();
66  			} catch (IOException e) {
67  				DebugLog.debug("connection shutdown", e);
68  			}
69  		}
70  	}
71  
72  	protected BluetoothConnectionNotifierBase(BluetoothStack bluetoothStack, BluetoothConnectionNotifierParams params)
73  			throws BluetoothStateException, Error {
74  		this.bluetoothStack = bluetoothStack;
75  		this.closed = false;
76  		if (params.name == null) {
77  			throw new NullPointerException("Service name is null");
78  		}
79  		/*
80  		 * create service record to be later updated by BluetoothStack
81  		 */
82  		this.serviceRecord = new ServiceRecordImpl(this.bluetoothStack, null, 0);
83  	}
84  
85  	protected void connectionCreated() {
86  		Vector connections;
87  		synchronized (stackConnections) {
88  			connections = (Vector) stackConnections.get(this.bluetoothStack);
89  			if (connections == null) {
90  				connections = new Vector();
91  				stackConnections.put(this.bluetoothStack, connections);
92  			}
93  		}
94  		connections.addElement(this);
95  	}
96  
97  	protected abstract void stackServerClose(long handle) throws IOException;
98  
99  	/*
100 	 * Close the connection. When a connection has been closed, access to any of
101 	 * its methods except this close() will cause an an IOException to be
102 	 * thrown. Closing an already closed connection has no effect. Streams
103 	 * derived from the connection may be open when method is called. Any open
104 	 * streams will cause the connection to be held open until they themselves
105 	 * are closed. In this latter case access to the open streams is permitted,
106 	 * but access to the connection is not.
107 	 */
108 
109 	/*
110 	 * (non-Javadoc)
111 	 * 
112 	 * @see javax.microedition.io.Connection#close()
113 	 */
114 	public void close() throws IOException {
115 		if (!closed) {
116 			shutdown();
117 		}
118 	}
119 
120 	public void shutdown() throws IOException {
121 		closed = true;
122 		if (handle != 0) {
123 			DebugLog.debug("closing ConnectionNotifier", handle);
124 			Vector connections;
125 			synchronized (stackConnections) {
126 				connections = (Vector) stackConnections.get(this.bluetoothStack);
127 			}
128 			connections.removeElement(this);
129 			long synchronizedHandle;
130 			synchronized (this) {
131 				synchronizedHandle = handle;
132 				handle = 0;
133 			}
134 			if (synchronizedHandle != 0) {
135 
136 				ServiceRecordsRegistry.unregister(serviceRecord);
137 
138 				if ((serviceRecord.deviceServiceClasses != 0)
139 						&& ((bluetoothStack.getFeatureSet() & BluetoothStack.FEATURE_SET_DEVICE_SERVICE_CLASSES) != 0)) {
140 					bluetoothStack.setLocalDeviceServiceClasses(ServiceRecordsRegistry.getDeviceServiceClasses());
141 				}
142 
143 				stackServerClose(synchronizedHandle);
144 			}
145 		}
146 	}
147 
148 	/*
149 	 * (non-Javadoc)
150 	 * 
151 	 * @see com.intel.bluetooth.BluetoothConnectionNotifierServiceRecordAccess#getServiceRecord()
152 	 */
153 	public ServiceRecord getServiceRecord() {
154 		if (closed) {
155 			throw new IllegalArgumentException("ConnectionNotifier is closed");
156 		}
157 		ServiceRecordsRegistry.register(this, serviceRecord);
158 		return serviceRecord;
159 	}
160 
161 	protected void validateServiceRecord(ServiceRecord srvRecord) {
162 		DataElement protocolDescriptor = srvRecord.getAttributeValue(BluetoothConsts.ProtocolDescriptorList);
163 		if ((protocolDescriptor == null) || (protocolDescriptor.getDataType() != DataElement.DATSEQ)) {
164 			throw new IllegalArgumentException("ProtocolDescriptorList is mandatory");
165 		}
166 
167 		DataElement serviceClassIDList = srvRecord.getAttributeValue(BluetoothConsts.ServiceClassIDList);
168 		if ((serviceClassIDList == null) || (serviceClassIDList.getDataType() != DataElement.DATSEQ)
169 				|| serviceClassIDList.getSize() == 0) {
170 			throw new IllegalArgumentException("ServiceClassIDList is mandatory");
171 		}
172 
173 		boolean isL2CAPpresent = false;
174 		for (Enumeration protocolsSeqEnum = (Enumeration) protocolDescriptor.getValue(); protocolsSeqEnum
175 				.hasMoreElements();) {
176 			DataElement elementSeq = (DataElement) protocolsSeqEnum.nextElement();
177 			if (elementSeq.getDataType() == DataElement.DATSEQ) {
178 				Enumeration elementSeqEnum = (Enumeration) elementSeq.getValue();
179 				if (elementSeqEnum.hasMoreElements()) {
180 					DataElement protocolElement = (DataElement) elementSeqEnum.nextElement();
181 					if ((protocolElement.getDataType() == DataElement.UUID)
182 							&& (BluetoothConsts.L2CAP_PROTOCOL_UUID.equals(protocolElement.getValue()))) {
183 						isL2CAPpresent = true;
184 						break;
185 					}
186 				}
187 			}
188 		}
189 		if (!isL2CAPpresent) {
190 			throw new IllegalArgumentException("L2CAP UUID is mandatory in ProtocolDescriptorList");
191 		}
192 	}
193 
194 	protected abstract void updateStackServiceRecord(ServiceRecordImpl serviceRecord, boolean acceptAndOpen)
195 			throws ServiceRegistrationException;
196 
197 	/*
198 	 * (non-Javadoc)
199 	 * 
200 	 * @see com.intel.bluetooth.BluetoothConnectionNotifierServiceRecordAccess#updateServiceRecord(boolean)
201 	 */
202 	public void updateServiceRecord(boolean acceptAndOpen) throws ServiceRegistrationException {
203 		if (serviceRecord.attributeUpdated || (!acceptAndOpen)) {
204 			try {
205 				validateServiceRecord(this.serviceRecord);
206 			} catch (IllegalArgumentException e) {
207 				if (acceptAndOpen) {
208 					throw new ServiceRegistrationException(e.getMessage());
209 				} else {
210 					throw e;
211 				}
212 			}
213 			try {
214 				updateStackServiceRecord(serviceRecord, acceptAndOpen);
215 			} finally {
216 				serviceRecord.attributeUpdated = false;
217 			}
218 		}
219 		if ((serviceRecord.deviceServiceClasses != serviceRecord.deviceServiceClassesRegistered)
220 				&& ((bluetoothStack.getFeatureSet() & BluetoothStack.FEATURE_SET_DEVICE_SERVICE_CLASSES) != 0)) {
221 
222 			bluetoothStack.setLocalDeviceServiceClasses(ServiceRecordsRegistry.getDeviceServiceClasses());
223 
224 			serviceRecord.deviceServiceClassesRegistered = serviceRecord.deviceServiceClasses;
225 		}
226 	}
227 }