📄 serverlookup.java
字号:
/* The Bluetooth Library for client-server communication Copyright (C) 2006 Martin Vysny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */package net.sf.btw.btlib;import java.util.Enumeration;import java.util.Vector;import javax.bluetooth.BluetoothStateException;import javax.bluetooth.DeviceClass;import javax.bluetooth.DiscoveryAgent;import javax.bluetooth.DiscoveryListener;import javax.bluetooth.RemoteDevice;import javax.bluetooth.ServiceRecord;import javax.bluetooth.UUID;import net.sf.btw.tools.ArrayUtils;import net.sf.btw.tools.Logger;/** * Looks for available servers. * * @author Martin Vysny */public final class ServerLookup extends Thread implements DiscoveryListener { /** * If <code>true</code> then the thread should terminate ASAP. */ private volatile boolean interrupted = false; /** * Constructs new instance of thread. You have to call * {@link #searchForServers()} to initiate the search. * * @param serverId * ID of the server to search for. * @param listener * the listener. Must not be <code>null</code>. */ public ServerLookup(final UUID serverId, final ILookupListener listener) { super(); if (listener == null) throw new IllegalArgumentException("listener must not be null"); //$NON-NLS-1$ this.listener = listener; this.serverId = serverId; discoveryAgent = Peer.getDevice().getDiscoveryAgent(); } private final static int STATE_NOT_STARTED = 0; private final static int STATE_INQUIRY = 1; private final static int STATE_SERVICE_SEARCH = 2; private final static int STATE_TERMINATED = 3; /** * The state of the thread. One of <code>STATE_</code> constants. */ private volatile int state = STATE_NOT_STARTED; /* * (non-Javadoc) * * @see java.lang.Thread#run() */ public void run() { // this ensures that no other service search/inquiry is in progress. synchronized (ServerInfo.DISCOVERY_LOCK) { clientSearchForServers(); } } /** * The listener instance. */ private final ILookupListener listener; /** * Server UUID. */ public final UUID serverId; private final DiscoveryAgent discoveryAgent; /** * Current active service transaction ID. */ private int serviceTransactionID = -1; /** * <p> * Searches for available servers. The method will not block. It will * gradually fill the {@link #servers} list. The method will do nothing if a * search is already in progress. This method may be called only once - if a * second scan is required then a new instance must be made. * </p> * <p> * If the {@link ServerInfo#connectToServer(UUID)} is in progress the lookup * will wait until the function finishes. * </p> */ public void searchForServers() { if (isSearching()) return; start(); } /** * Checks if the server search is in progress. * * @return <code>true</code> if the search did not end yet, * <code>false</code> otherwise. */ public boolean isSearching() { int s = state; return (s == STATE_INQUIRY) || (s == STATE_SERVICE_SEARCH); } /** * Servers found. Contains instances of {@link ServerInfo}. */ public final Vector servers = new Vector(); /** * Executes the search. */ private void clientSearchForServers() { remoteDevices.removeAllElements(); servers.removeAllElements(); try { discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this); state = STATE_INQUIRY; synchronized (remoteDevices) { remoteDevices.wait(); } for (final Enumeration e = remoteDevices.elements(); e .hasMoreElements();) { try { final RemoteDevice remoteDevice = (RemoteDevice) e .nextElement(); serviceTransactionID = discoveryAgent.searchServices(null, new UUID[] { serverId }, remoteDevice, this); state = STATE_SERVICE_SEARCH; synchronized (remoteDevices) { remoteDevices.wait(); } } catch (Exception ex) { Logger .error( "ServerLookup.clientSearchForServers():serviceSearch", //$NON-NLS-1$ ex); if (!interrupted) listener.serverScanError(ex); } } listener.serverScanFinished(servers, !interrupted); } catch (InterruptedException e) { // do nothing, the thread is interrupted and should end. listener.serverScanFinished(servers, false); } catch (Exception ex) { Logger.error("ServerLookup.searchForServers()", ex); //$NON-NLS-1$ listener.serverScanError(ex); } state = STATE_TERMINATED; } /** * {@link #searchForServers()} blocks on this object. Contains list of * {@link RemoteDevice}. */ private final Vector remoteDevices = new Vector(); /** * Not intended to be called by clients. */ public void deviceDiscovered(RemoteDevice arg0, DeviceClass arg1) { remoteDevices.addElement(arg0); if (Logger.CURRENT_LEVEL < Logger.LEVEL_DEBUG) return; Logger.debug("ServerLookup.deviceDiscovered(): " //$NON-NLS-1$ + Peer.getDeviceName(arg0, true), null); } /** * Not intended to be called by clients. */ public void inquiryCompleted(int discType) { final boolean forcefullyTerminated = (discType == INQUIRY_TERMINATED) && interrupted; final boolean error = (discType != INQUIRY_COMPLETED) && !forcefullyTerminated; Logger .log(error ? Logger.LEVEL_ERROR : Logger.LEVEL_INFO, "ServerLookup.inquiryCompleted(): " //$NON-NLS-1$ + getInqErrorCode(discType), null); if (error) { listener.serverScanError(new BluetoothStateException( "Inquiry error - is bluetooth enabled?")); //$NON-NLS-1$ } synchronized (remoteDevices) { remoteDevices.notify(); } } /** * Returns displayable value of given inquiry error code. * * @param discType * the inquiry error code issued by * {@link DiscoveryListener#inquiryCompleted(int)}. * @return displayable error code, never <code>null</code>. */ public static String getInqErrorCode(final int discType) { switch (discType) { case INQUIRY_COMPLETED: return "ICompleted"; //$NON-NLS-1$ case INQUIRY_ERROR: return "IError"; //$NON-NLS-1$ case INQUIRY_TERMINATED: return "ITerminated"; //$NON-NLS-1$ default: return "IUnknown(" + discType + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } } /** * Not intended to be called by clients. */ public void servicesDiscovered(int arg0, ServiceRecord[] arg1) { if ((arg1 == null) || arg1.length == 0) { Logger.debug("Discovered 0 services, ignoring", null); //$NON-NLS-1$ return; } final ServerInfo si = new ServerInfo(arg1[0].getHostDevice()); // check if this server has been found already final int serverIndex = ArrayUtils.indexOf(servers, si); if (serverIndex >= 0) { // discard newly created server info. Logger.debug("ServerLookup.servicesDiscovered(): Found " //$NON-NLS-1$ + arg1.length + " service(s) on existing server " + si, //$NON-NLS-1$ null); return; } // okay, service seems unique. register it Logger.debug("ServerLookup.servicesDiscovered(): Found " + arg1.length //$NON-NLS-1$ + " service(s) on new server" + si, null); //$NON-NLS-1$ servers.addElement(si); if (!interrupted) listener.serverFound(si); } /** * Not intended to be called by clients. */ public void serviceSearchCompleted(int arg0, int respCode) { final boolean forcefullyTerminated = (respCode == SERVICE_SEARCH_TERMINATED) && interrupted; final boolean error = (respCode != SERVICE_SEARCH_COMPLETED) && (respCode != SERVICE_SEARCH_NO_RECORDS) && !forcefullyTerminated; Logger.log(error ? Logger.LEVEL_ERROR : Logger.LEVEL_INFO, "ServerLookup.serviceSearchCompleted(): " //$NON-NLS-1$ + getServiceErrorCode(respCode), null); synchronized (remoteDevices) { remoteDevices.notify(); } } /** * Returns displayable value of given service search error code. * * @param respCode * the service search error code issued by * {@link DiscoveryListener#serviceSearchCompleted(int, int)}. * @return displayable error code, never <code>null</code>. */ public static String getServiceErrorCode(final int respCode) { switch (respCode) { case SERVICE_SEARCH_COMPLETED: return "SSCompleted"; //$NON-NLS-1$ case SERVICE_SEARCH_DEVICE_NOT_REACHABLE: return "SSDeviceNotReachable"; //$NON-NLS-1$ case SERVICE_SEARCH_ERROR: return "SSError"; //$NON-NLS-1$ case SERVICE_SEARCH_NO_RECORDS: return "SSNoRecords"; //$NON-NLS-1$ case SERVICE_SEARCH_TERMINATED: return "SSTerminated"; //$NON-NLS-1$ default: return "SSUnknown(" + respCode + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } } /** * Stops the server search. No further server discovery events will be * invoked on the listener, except the * {@link ILookupListener#serverScanFinished(Vector, boolean)}. */ public void interrupt() { interrupted = true; // super.interrupt(); switch (state) { case STATE_INQUIRY: discoveryAgent.cancelInquiry(this); break; case STATE_SERVICE_SEARCH: discoveryAgent.cancelServiceSearch(serviceTransactionID); break; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -