Direct-BT v3.3.0-1-gc2d430c
Direct-BT - Direct Bluetooth Programming.
BTDeviceRegistry.java
Go to the documentation of this file.
1/**
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2020 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26package org.direct_bt;
27
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.Collection;
31import java.util.Collections;
32import java.util.HashSet;
33import java.util.Iterator;
34import java.util.List;
35
36import org.jau.net.EUI48;
37import org.jau.net.EUI48Sub;
38
39/**
40 * Application toolkit providing BT device registration of processed and awaited devices.
41 * The latter on a pattern matching basis, i.e. EUI48Sub or name-sub.
42 */
43public class BTDeviceRegistry {
44 /**
45 * Specifies devices queries to act upon.
46 */
47 public static class DeviceQuery {
48 /**
49 * {@link DeviceQuery} type, i.e. {@link EUI48Sub} or a {@link String} name.
50 */
51 public static enum Type {
52 /** {@link DeviceQuery} type, using a sensor device {@link EUI48Sub}. */
54 /** {@link DeviceQuery} type, using a sensor device {@link String} name. */
55 NAME
56 }
57
58 public final Type type;
59 public final EUI48Sub addressSub;
60 public final String nameSub;
61
62 public DeviceQuery(final EUI48Sub as) {
64 addressSub = as;
65 nameSub = new String();
66 }
67 public DeviceQuery(final String ns) {
68 type = Type.NAME;
69 addressSub = EUI48Sub.ANY_DEVICE;
70 nameSub = ns;
71 }
72
73 public final boolean isEUI48Sub() { return Type.EUI48SUB == type; }
74
75 @Override
76 public String toString() {
77 if( Type.EUI48SUB == type ) {
78 return "[a: "+addressSub.toString()+"]";
79 } else {
80 return "[n: '"+nameSub+"']";
81 }
82 }
83 };
84 private static List<DeviceQuery> waitForDevices = new ArrayList<DeviceQuery>();
85
86 /**
87 * Specifies unique device identities,
88 * using {@link BDAddressAndType} as key.
89 */
90 public static class DeviceID {
92 public final String name;
93 public DeviceID(final BDAddressAndType a, final String n) {
95 name = n;
96 }
97
98 /**
99 * {@inheritDoc}
100 * <p>
101 * Implementation simply tests the {@link BDAddressAndType} fields for equality,
102 * `name` is ignored.
103 * </p>
104 */
105 @Override
106 public final boolean equals(final Object obj) {
107 if(this == obj) {
108 return true;
109 }
110 if (obj == null || !(obj instanceof DeviceID)) {
111 return false;
112 }
114 }
115
116 /**
117 * {@inheritDoc}
118 * <p>
119 * Implementation simply returns the {@link BDAddressAndType} hash code,
120 * `name` is ignored.
121 * </p>
122 */
123 @Override
124 public final int hashCode() {
125 return addressAndType.hashCode();
126 }
127
128 @Override
129 public String toString() {
130 return "["+addressAndType+", "+name+"]";
131 }
132 };
133 private static Collection<DeviceID> devicesProcessed = Collections.synchronizedCollection(new HashSet<DeviceID>());
134
135 public static void addToWaitForDevices(final String addrOrNameSub) {
136 final EUI48Sub addr1 = new EUI48Sub();
137 final StringBuilder errmsg = new StringBuilder();
138 if( EUI48Sub.scanEUI48Sub(addrOrNameSub, addr1, errmsg) ) {
139 waitForDevices.add( new DeviceQuery( addr1 ) );
140 } else {
141 addr1.clear();
142 waitForDevices.add( new DeviceQuery( addrOrNameSub ) );
143 }
144 }
145 public static boolean isWaitingForAnyDevice() {
146 return waitForDevices.size()==0;
147 }
148 public static int getWaitForDevicesCount() {
149 return waitForDevices.size();
150 }
151 public static String getWaitForDevicesString() {
152 return Arrays.toString(waitForDevices.toArray());
153 }
154 /**
155 * Returns the reference of the current list of {@link DeviceQuery}, not a copy.
156 */
157 public static List<DeviceQuery> getWaitForDevices() {
158 return waitForDevices;
159 }
160 /**
161 * Clears internal list
162 */
163 public static void clearWaitForDevices() {
164 waitForDevices.clear();
165 }
166
167 public static void addToProcessedDevices(final BDAddressAndType a, final String n) {
168 devicesProcessed.add( new DeviceID(a, n) );
169 }
170 public static boolean isDeviceProcessed(final BDAddressAndType a) {
171 return devicesProcessed.contains( new DeviceID(a, null) );
172 }
173 public static int getProcessedDeviceCount() {
174 return devicesProcessed.size();
175 }
176 public static String getProcessedDevicesString() {
177 return Arrays.toString(devicesProcessed.toArray());
178 }
179 /**
180 * Returns a copy of the current collection of processed {@link DeviceID}.
181 */
182 public static List<DeviceID> getProcessedDevices() {
183 return new ArrayList<DeviceID>(devicesProcessed);
184 }
185 /**
186 * Clears internal list
187 */
188 public static void clearProcessedDevices() {
189 devicesProcessed.clear();
190 }
191
192 /**
193 * Interface for user defined {@link DeviceQuery} matching criteria and algorithm.
194 */
195 public static interface DeviceQueryMatch {
196 /**
197 * Return {@code true} if the given {@code address} and/or {@code name} matches
198 * with the {@link DeviceQuery}'s {@link DeviceQuery#addressSub addressSub} and/or
199 * {@link DeviceQuery#nameSub nameSub}.
200 * <p>
201 * Example (lambda):
202 * <pre>
203 * (final EUI48 a, final String n, final DeviceQuery q) -> {
204 * return q.isEUI48Sub() ? a.contains(q.addressSub) : n.indexOf(q.nameSub) >= 0;
205 * }
206 * </pre>
207 * </p>
208 */
209 public boolean match(final EUI48 address, final String name, final DeviceQuery q);
210 }
211
212 /**
213 * Returns {@code true} if the given {@code address} and/or {@code name}
214 * {@link DeviceQueryMatch#match(EUI48, String, DeviceQuery) matches}
215 * any of the {@link #addToWaitForDevices(String) awaited devices}.
216 * <p>
217 * Matching criteria and algorithm is defined by the given {@link DeviceQueryMatch}.
218 * </p>
219 * @see #isWaitingForDevice(EUI48, String)
220 */
221 public static boolean isWaitingForDevice(final EUI48 address, final String name,
222 final DeviceQueryMatch m) {
223 for(final Iterator<DeviceQuery> it=waitForDevices.iterator(); it.hasNext(); ) {
224 final DeviceQuery q = it.next();
225 if( m.match(address, name, q) ) {
226 return true;
227 }
228 }
229 return false;
230 }
231 /**
232 * Returns {@code true} if the given {@code address} and/or {@code name}
233 * {@link DeviceQueryMatch#match(EUI48, String, DeviceQuery) matches}
234 * any of the {@link #addToWaitForDevices(String) awaited devices}.
235 * <p>
236 * Matching criteria is either the awaited device's {@link DeviceQuery#addressSub}
237 * or {@link DeviceQuery#nameSub}, whichever is set.
238 * </p>
239 * <p>
240 * Matching algorithm is a simple {@code contains} pattern match,
241 * i.e. the given {@code address} or {@code name} contains the corresponding {@link DeviceQuery} element.
242 * </p>
243 * @see #isWaitingForDevice(EUI48, String, DeviceQueryMatch)
244 */
245 public static boolean isWaitingForDevice(final EUI48 address, final String name) {
246 return isWaitingForDevice( address, name,
247 (final EUI48 a, final String n, final DeviceQuery q) -> {
248 return q.isEUI48Sub() ? a.contains(q.addressSub) : n.indexOf(q.nameSub) >= 0;
249 });
250 }
251
252 /**
253 * Returns {@code true} if all {@link #addToWaitForDevices(String) awaited devices}
254 * have been {@link #addToProcessedDevices(BDAddressAndType, String) processed}.
255 * <p>
256 * Matching criteria and algorithm is defined by the given {@link DeviceQueryMatch}.
257 * </p>
258 * @see #areAllDevicesProcessed()
259 */
260 public static boolean areAllDevicesProcessed(final DeviceQueryMatch m) {
261 for(final Iterator<DeviceQuery> it1=waitForDevices.iterator(); it1.hasNext(); ) {
262 final DeviceQuery q = it1.next();
263 final Iterator<DeviceID> it2=devicesProcessed.iterator();
264 while( it2.hasNext() ) {
265 final DeviceID id = it2.next();
266 if( m.match(id.addressAndType.address, id.name, q) ) {
267 break;
268 }
269 }
270 if( !it2.hasNext() ) {
271 return false;
272 }
273 }
274 return true;
275 }
276 /**
277 * Returns {@code true} if all {@link #addToWaitForDevices(String) awaited devices}
278 * have been {@link #addToProcessedDevices(BDAddressAndType, String) processed}.
279 * <p>
280 * Matching criteria is either the awaited device's {@link DeviceQuery#addressSub}
281 * or {@link DeviceQuery#nameSub}, whichever is set.
282 * </p>
283 * <p>
284 * Matching algorithm is a simple {@code contains} pattern match,
285 * i.e. the processed {@link DeviceID} contains one element of {@link DeviceQuery}.
286 * </p>
287 * @see #areAllDevicesProcessed(DeviceQueryMatch)
288 */
289 public static boolean areAllDevicesProcessed() {
290 return areAllDevicesProcessed( (final EUI48 a, final String n, final DeviceQuery q) -> {
291 return q.isEUI48Sub() ? a.contains(q.addressSub) : n.indexOf(q.nameSub) >= 0;
292 });
293 }
294}
Unique Bluetooth EUI48 address and BDAddressType tuple.
final boolean equals(final Object obj)
If both types are of BDAddressAndType, it compares their EUI48 address and BDAddressType.
Specifies unique device identities, using BDAddressAndType as key.
final boolean equals(final Object obj)
DeviceID(final BDAddressAndType a, final String n)
Specifies devices queries to act upon.
Application toolkit providing BT device registration of processed and awaited devices.
static List< DeviceQuery > getWaitForDevices()
Returns the reference of the current list of DeviceQuery, not a copy.
static List< DeviceID > getProcessedDevices()
Returns a copy of the current collection of processed DeviceID.
static void addToProcessedDevices(final BDAddressAndType a, final String n)
static boolean isDeviceProcessed(final BDAddressAndType a)
static boolean isWaitingForDevice(final EUI48 address, final String name, final DeviceQueryMatch m)
Returns true if the given address and/or name matches any of the awaited devices.
static boolean areAllDevicesProcessed()
Returns true if all awaited devices have been processed.
static void clearWaitForDevices()
Clears internal list.
static boolean isWaitingForDevice(final EUI48 address, final String name)
Returns true if the given address and/or name matches any of the awaited devices.
static boolean areAllDevicesProcessed(final DeviceQueryMatch m)
Returns true if all awaited devices have been processed.
static void clearProcessedDevices()
Clears internal list.
static void addToWaitForDevices(final String addrOrNameSub)
NAME
DeviceQuery type, using a sensor device String name.
EUI48SUB
DeviceQuery type, using a sensor device EUI48Sub.
Interface for user defined DeviceQuery matching criteria and algorithm.
boolean match(final EUI48 address, final String name, final DeviceQuery q)
Return true if the given address and/or name matches with the DeviceQuery's addressSub and/or nameSub...