1 package fr.ifremer.tutti.ichtyometer;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import com.google.common.base.Preconditions;
28 import com.google.common.collect.Maps;
29 import com.google.common.collect.Sets;
30 import com.intel.bluetooth.BlueCoveImpl;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33
34 import javax.bluetooth.BluetoothStateException;
35 import javax.bluetooth.LocalDevice;
36 import javax.bluetooth.RemoteDevice;
37 import javax.bluetooth.ServiceRecord;
38 import javax.microedition.io.Connector;
39 import javax.microedition.io.StreamConnection;
40 import java.io.Closeable;
41 import java.io.IOException;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Set;
45
46
47
48
49
50
51
52
53
54 public class IchtyometerClient implements Closeable {
55
56
57 private static final Log log = LogFactory.getLog(IchtyometerClient.class);
58
59
60
61
62 protected static Map<String, RemoteDevice> REMOTE_DEVICE_CACHE;
63
64
65
66
67
68 protected static Map<String, String> REMOTE_CONNECTION_URL_CACHE;
69
70 private final int maximumNumberOfTryToConnect;
71
72 public IchtyometerClient(int maximumNumberOfTryToConnect) {
73 this.maximumNumberOfTryToConnect = maximumNumberOfTryToConnect;
74 }
75
76 public static void clearRemoteDeviceCaches() {
77 REMOTE_DEVICE_CACHE = null;
78 REMOTE_CONNECTION_URL_CACHE = null;
79 }
80
81
82
83
84 protected LocalDevice localDevice;
85
86
87
88
89 protected final Set<StreamConnection> connections = Sets.newHashSet();
90
91
92
93
94 protected RemoteDevice remoteDevice;
95
96
97
98
99 protected String connectionUrl;
100
101
102
103
104 protected boolean open;
105
106
107
108
109 protected String name;
110
111 public void open(RemoteDeviceChooser remoteDeviceChooser, boolean forceCompleteScan) throws IOException {
112
113 Preconditions.checkState(!open, "Client is already opened");
114
115 try {
116 localDevice = LocalDevice.getLocalDevice();
117 } catch (BluetoothStateException e) {
118 throw new LocalDeviceNotFoundException();
119 }
120
121 if (forceCompleteScan || REMOTE_DEVICE_CACHE == null) {
122
123
124
125 REMOTE_DEVICE_CACHE = discoverRemoteDevices();
126
127 }
128
129 if (REMOTE_DEVICE_CACHE.isEmpty()) {
130 throw new RemoteDeviceNotFoundException("No remote device found");
131 }
132
133
134 name = remoteDeviceChooser.chooseRemoteDevice(REMOTE_DEVICE_CACHE.keySet());
135
136 if (name == null) {
137 throw new RemoteDeviceNotFoundException("User did not choose a remote device");
138 }
139
140 remoteDevice = REMOTE_DEVICE_CACHE.get(name);
141
142 if (remoteDevice == null) {
143 throw new RemoteDeviceNotFoundException(
144 "Could not find remote device with name '" + name + "'");
145 }
146
147 if (forceCompleteScan || REMOTE_CONNECTION_URL_CACHE == null) {
148 REMOTE_CONNECTION_URL_CACHE = Maps.newTreeMap();
149 }
150
151 if (!REMOTE_CONNECTION_URL_CACHE.containsKey(name)) {
152
153 int serviceIndex = 3;
154
155 List<ServiceRecord> serviceRecords = discoverServiceRecords(serviceIndex);
156
157 if (log.isInfoEnabled()) {
158 log.info("Found some services for index: " + serviceIndex);
159 }
160
161
162 ServiceRecord serviceRecord = serviceRecords.get(0);
163
164
165 String url = serviceRecord.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, true);
166
167 if (log.isInfoEnabled()) {
168 log.info("Found service(" + serviceIndex + "): " + url + ", name: " + name);
169 }
170 REMOTE_CONNECTION_URL_CACHE.put(name, url);
171
172 }
173
174
175 connectionUrl = REMOTE_CONNECTION_URL_CACHE.get(name);
176
177 open = true;
178 }
179
180 @Override
181 public void close() throws IOException {
182
183 if (!open) {
184 return;
185 }
186 try {
187 for (StreamConnection connection : Sets.newHashSet(connections)) {
188 closeConnection(connection);
189 }
190 } finally {
191
192 BlueCoveImpl.shutdown();
193 }
194 }
195
196 public StreamConnection openConnection() throws IOException {
197
198 checkIsOpened();
199
200 StreamConnection connection = (StreamConnection) Connector.open(connectionUrl, 2);
201 connections.add(connection);
202 return connection;
203 }
204
205 public void closeConnection(StreamConnection connection) throws IOException {
206 checkIsOpened();
207 boolean remove = connections.remove(connection);
208 if (!remove) {
209 throw new IllegalArgumentException("Connection is not coming from this client, won't close it!");
210 }
211 connection.close();
212 }
213
214 public boolean isOpen() {
215 return open;
216 }
217
218 public String getName() {
219 checkIsOpened();
220 return name;
221 }
222
223 protected void checkIsOpened() {
224 if (!open) {
225 throw new IllegalStateException("Client is not opened!");
226 }
227 }
228
229 protected Map<String, RemoteDevice> discoverRemoteDevices() throws RemoteDeviceNotFoundException {
230
231 RemoteDevicesFinder remoteDevicesFinder = new RemoteDevicesFinder(maximumNumberOfTryToConnect, this);
232
233 Map<String, RemoteDevice> devices;
234 try {
235 devices = remoteDevicesFinder.findDevices(localDevice);
236
237 } catch (Exception e) {
238 throw new RemoteDeviceNotFoundException("Could not detected devices", e);
239 }
240
241 return devices;
242
243 }
244
245 protected List<ServiceRecord> discoverServiceRecords(int serviceIndex) throws RemoteDeviceNotFoundException, RemoteDeviceServiceNotFoundException {
246
247 ServiceRecordsFinder serviceRecordsFinder = new ServiceRecordsFinder(maximumNumberOfTryToConnect, this);
248 List<ServiceRecord> serviceRecords;
249 try {
250 serviceRecords = serviceRecordsFinder.findServices(localDevice, remoteDevice, serviceIndex);
251 } catch (Exception e) {
252 throw new RemoteDeviceNotFoundException("Could not read remote device services", e);
253 }
254
255 if (serviceRecords.isEmpty()) {
256 throw new RemoteDeviceServiceNotFoundException("No services detected.");
257 }
258
259 return serviceRecords;
260
261 }
262
263
264 }