I have implemented a chat service and desktop client using Java, the program works pefectly but the client is consuming lots of CPU, the idea is :
Every client has an events queue in the server
different events are added to the queue during the program, for example a new user logs in so an event is added to refresh the users list, if a new message is sent another event is added ... etc
the client has a thread that is polling continually for events in its queue and responding to these events appropriately
The only problem is that the polling thread is consuming lots of CPU, i do not know if using Asynchronous web services will help ..
for example :
This is the class where the events are added to the queue
public class Session {
private String owner;
private int sessionID;
private BlockingQueue<Events> eventsQueue = new LinkedBlockingQueue<Events>();
public Session() {
}
public Session(String owner, int sessionID) {
this.owner = owner;
this.sessionID = sessionID;
}
public Events getEvent() {
try {
return eventsQueue.take();
} catch (InterruptedException ex) {
System.err.println("Error retreiving Events");
}
return null;
}
public void addEvent(Events ev) {
try {
eventsQueue.put(ev);
eventsQueue.put(ev);
System.out.println("New Event Created with ID : " + ev.getId());
System.out.println("Number Of Evenets in Queue " + getOwner() + " : " + eventsQueue.size());
} catch (InterruptedException ex) {
System.err.println("Error Creating New Event");
}
}
public int queueSize() {
return eventsQueue.size();
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public int getSessionID() {
return sessionID;
}
public void setSessionID(int sessionID) {
this.sessionID = sessionID;
}
}
And this is the polling thread
public class pollingThread implements Runnable {
public void run() {
while (true) {
if (checkQueue(Login.getUserName()) != null) {
final Events ev = (Events) ObjectSerialization.Deserialize(checkQueue(Login.getUserName()));
if (ev != null) {
switch (ev.getId()) {
case 1:
System.out.println("Event Retreived : " + ev.getEventType());
RefreshOnlineList RfEv = (RefreshOnlineList) ev;
if (RfEv.getLogEvent().equals("1") && !RfEv.getUname().equals(Login.getUserName())) {
Chatter.showTrayMessage(RfEv.getUname() + " Has Just logged In", MessageType.INFO);
} else if (!RfEv.getUname().equals(Login.getUserName())) {
Chatter.showTrayMessage(RfEv.getUname() + " Has Just logged Out", MessageType.INFO);
}
Chatter.updateUsersCounter();
Chatter.updateList();
break;
case 2:
System.out.println("Event Retreived : " + ev.getEventType());
final RegistrationEvent RegEv = (RegistrationEvent) ev;
Chatter.showTrayMessage(RegEv.getUser().getUser_name() + " Has Just Registered", MessageType.INFO);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Chatter.addNewUserPanel(RegEv.getUser());
}
});
break;
case 3:
System.out.println("Event Retreived : " + ev.getEventType());
final ChatRequestEvent ChEv = (ChatRequestEvent) ev;
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
int res = JOptionPane.showConfirmDialog(
null,
ChEv.getRequestingUser() + " Wishes to connect with you !! ",
"Incoming Request",
JOptionPane.YES_NO_OPTION);
if (res == 1) {
replyRequest(ChEv.getRequestingUser(), ChEv.getReceivingUser(), false, ChEv.getRequestID());
} else {
chatWindow s = new chatWindow(ChEv.getRequestID(), ChEv.getRequestingUser() + " - " + ChEv.getReceivingUser());
Chatter.addChatwindow(ChEv.getRequestID(), s);
Chatter.setUserIsChatting(ChEv.getRequestingUser(), true);
chatWindow.main(ChEv.getRequestID(), ChEv.getRequestingUser() + " - " + ChEv.getReceivingUser() + " Are Talking ...", s);
replyRequest(ChEv.getRequestingUser(), ChEv.getReceivingUser(), true, ChEv.getRequestID());
startChatSession(Login.getUserName(), ChEv.getRequestingUser(), ChEv.getRequestID(), Chatter.getDate());
}
}
});
break;
case 4:
System.out.println("Event Retreived : " + ev.getEventType());
final RequestResponseEvent ResponseEv = (RequestResponseEvent) ev;
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
if (ResponseEv.isResponse()) {
chatWindow s = new chatWindow(ResponseEv.getChatRequestID(), ResponseEv.getRequestinguser() + " - " + ResponseEv.getReceivingUser());
Chatter.addChatwindow(ResponseEv.getChatRequestID(), s);
Chatter.setUserIsChatting(ResponseEv.getReceivingUser(), true);
chatWindow.main(ResponseEv.getChatRequestID(), ResponseEv.getRequestinguser() + " - " + ResponseEv.getReceivingUser() + " Are Talking ...", s);
} else {
JOptionPane.showMessageDialog(null, ResponseEv.getReceivingUser() + " Ignored Your Request");
}
}
});
break;
case 5:
System.out.println("Event Retreived : " + ev.getEventType());
//Add Code to beautify the message not only the body
final SendMessageEvent MessageEv = (SendMessageEvent) ev;
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
Chatter.addMessage(MessageEv.getMessage(), MessageEv.getChatID());
}
});
break;
case 6:
System.out.println("Event Retreived : " + ev.getEventType());
final LeaveChatEvent LeaveEv = (LeaveChatEvent) ev;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println(LeaveEv.getUserName() + " has left the Chat with ID: " + LeaveEv.getChatID());
Chatter.addMessage(new shared.Message(LeaveEv.getUserName(), 1), LeaveEv.getChatID());
Chatter.setUserIsChatting(LeaveEv.getUserName(), false);
}
});
break;
case 7:
System.out.println("Event Retreived : " + ev.getEventType());
final GroupChatRequestEvent GroupChatEvent = (GroupChatRequestEvent) ev;
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
int res = JOptionPane.showConfirmDialog(
null,
GroupChatEvent.getRequestingUser() + " Wants to Join his Group Conference !! ",
"Incoming Request",
JOptionPane.YES_NO_OPTION);
if (res != 1) {
chatWindow s = new chatWindow(GroupChatEvent.getChatID(), "Conference - " + GroupChatEvent.getRequestingUser() + " - " + Login.getUserName());
Chatter.addChatwindow(GroupChatEvent.getChatID(), s);
Chatter.setUserIsChatting(GroupChatEvent.getRequestingUser(), true);
chatWindow.main(GroupChatEvent.getChatID(), "Conference - " + GroupChatEvent.getRequestingUser() + " - " + Login.getUserName() + " Are Talking ...", s);
joinChat(Login.getUserName(), GroupChatEvent.getChatID());
}
}
});
break;
case 8:
System.out.println("Event Retreived : " + ev.getEventType());
final LeaveChatEvent joinEv = (LeaveChatEvent) ev;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println(joinEv.getUserName() + " has Joined the Chat with ID: " + joinEv.getChatID());
Chatter.addMessage(new shared.Message(joinEv.getUserName(), 2), joinEv.getChatID());
Chatter.setUserIsChatting(joinEv.getUserName(), true);
}
});
break;
case 9:
System.out.println("Event Retreived : " + ev.getEventType());
final UpdateStatusEvent updateEv = (UpdateStatusEvent) ev;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println(updateEv.getUser() + " has updated his status to " + updateEv.getStatus());
Chatter.updateStatusList(updateEv.getUser(), updateEv.getStatus());
}
});
break;
case 10:
System.out.println("Event Retreived : " + ev.getEventType());
final RefreshDetailsEvent refEvenet = (RefreshDetailsEvent) ev;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println(refEvenet.getUser() + " has updated his Details ");
Chatter.updateDetails(refEvenet.getUser());
}
});
break;
case 11:
System.out.println("Event Retreived : " + ev.getEventType());
final BlockedEvent BlockedEv = (BlockedEvent) ev;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println(BlockedEv.getUserName() + " has Been Blocked ");
JOptionPane.showMessageDialog(null, "You have Been Blocked\nReason: " + BlockedEv.getReason());
Chatter.signOut();
}
});
break;
}
}
}
}
}
private static byte[] checkQueue(java.lang.String uname) {
db.Database service = new db.Database();
db.DatabasePortType port = service.getDatabaseHttpSoap12Endpoint();
return port.checkQueue(uname);
}
private static void replyRequest(java.lang.String requestingUser, java.lang.String receivingUser, java.lang.Boolean result, java.lang.Integer id) {
db.Database service = new db.Database();
db.DatabasePortType port = service.getDatabaseHttpSoap12Endpoint();
port.replyRequest(requestingUser, receivingUser, result, id);
}
private static void startChatSession(java.lang.String initiatingUser, java.lang.String receivingUser, java.lang.Integer id, java.lang.String sessionTime) {
db.Database service = new db.Database();
db.DatabasePortType port = service.getDatabaseHttpSoap12Endpoint();
port.startChatSession(initiatingUser, receivingUser, id, sessionTime);
}
private static void joinChat(java.lang.String uname, java.lang.Integer chatID) {
db.Database service = new db.Database();
db.DatabasePortType port = service.getDatabaseHttpSoap12Endpoint();
port.joinChat(uname, chatID);
}
}
And Queue checking
appreciate help
Instead of having the clients polling the main server, I would say use a push technology so the server will push changes to the appropriate client if any. However, this may require a lot of changes depending on your current architecture.
UPDATE:
The basic idea is:
Instead of having client poll the server to get updates if there is any, change your client code so that they are waiting to receive updates from server (another thread in the client side waiting to receive updates from server). The server will have a list of events with client information so it will send the correct data to correct client.
So at the client side, you will need at least 2 threads one for sending updates to the server and another that waits to receive updates from server (pushed by server).
Related
I'm getting familiar with BitcoinJ. So now there is a function for user that registers for the first time and there should be created address for him. But it doesn't work. It says there is already some money.
// USER HAS NEVER USED COIN_ATLAS ( IT IS THE FIRST TIME )
public void addUser()
{
DBObject dbUser;
WalletAppKit kit = new WalletAppKit(TestNet3Params.get(), new File("."), "forwarding-service-testnet");
params = TestNet3Params.get();
Debug.Log("Wait a bit...");
kit.startAsync();
kit.awaitRunning();
BlockChain chain = null;
my_wallet = kit.wallet(); // Wallet created for that user
try {
chain = new BlockChain(params, my_wallet,
new MemoryBlockStore(params));
} catch (BlockStoreException e) {
e.printStackTrace();
}
PeerGroup peerGroup = new PeerGroup(params, chain);
peerGroup.addPeerDiscovery(new DnsDiscovery(params));
peerGroup.addWallet(my_wallet);
peerGroup.startAsync();
Debug.Log("WALLET: " + my_wallet.currentReceiveAddress());
Debug.Log("WALLET BALANCE: " + my_wallet.getBalance().toFriendlyString());
my_wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
#Override
public void onCoinsReceived(Wallet wallet, Transaction transaction, Coin coin, Coin coin1) {
send("NEW TRANSACTION:");
sendWithMarkdown("FROM: " + wallet.currentReceiveAddress() + " : " + bold(coin1.toFriendlyString()));
Coin value = transaction.getValueSentToMe(wallet);
System.out.println("Received tx for " + value.toFriendlyString() + ": " + transaction);
Futures.addCallback(transaction.getConfidence().getDepthFuture(1), new FutureCallback<TransactionConfidence>() {
#Override
public void onSuccess(#Nullable TransactionConfidence transactionConfidence) {
send(bold("Transaction confirmed!"));
send(bold(value.toFriendlyString() + " is deposited!"));
}
#Override
public void onFailure(Throwable throwable) {
}
});
}
});
peerGroup.downloadBlockChain();
peerGroup.stopAsync();
dbUser = new BasicDBObject("_id", bot_user.getId())
.append("firstName", bot_user.getFirstName())
.append("password", bot_user.getPassword())
.append("address", my_wallet.currentReceiveAddress().toString())
.append("BTC", (double)my_wallet.getBalance().getValue());
collection.insert(dbUser);
}
There is what I get in output:
WALLET: mtrjbnpq5wDzoywrKqod63tpB7ZUFrr7q5
WALLET BALANCE: 1.21503904 BTC
But if I check this address in blockchain, it shows 0.
So how to create wallet the right way?
I am trying to avoid "while(true)" solution when i waiting until my spark apache job is done, but without success.
I have spark application which suppose to process some data and put a result to database, i do call it from my spring service and would like to wait until the job is done.
Example:
Launcher with method:
#Override
public void run(UUID docId, String query) throws Exception {
launcher.addAppArgs(docId.toString(), query);
SparkAppHandle sparkAppHandle = launcher.startApplication();
sparkAppHandle.addListener(new SparkAppHandle.Listener() {
#Override
public void stateChanged(SparkAppHandle handle) {
System.out.println(handle.getState() + " new state");
}
#Override
public void infoChanged(SparkAppHandle handle) {
System.out.println(handle.getState() + " new state");
}
});
System.out.println(sparkAppHandle.getState().toString());
}
How to wait properly until state of handler is "Finished".
I am also using SparkLauncher from a Spring application. Here is a summary of the approach that I took (by following examples in the JavaDoc).
The #Service used to launch the job also implements SparkHandle.Listener and passes a reference to itself via .startApplication e.g.
...
...
#Service
public class JobLauncher implements SparkAppHandle.Listener {
...
...
...
private SparkAppHandle launchJob(String mainClass, String[] args) throws Exception {
String appResource = getAppResourceName();
SparkAppHandle handle = new SparkLauncher()
.setAppResource(appResource).addAppArgs(args)
.setMainClass(mainClass)
.setMaster(sparkMaster)
.setDeployMode(sparkDeployMode)
.setSparkHome(sparkHome)
.setConf(SparkLauncher.DRIVER_MEMORY, "2g")
.startApplication(this);
LOG.info("Launched [" + mainClass + "] from [" + appResource + "] State [" + handle.getState() + "]");
return handle;
}
/**
* Callback method for changes to the Spark Job
*/
#Override
public void infoChanged(SparkAppHandle handle) {
LOG.info("Spark App Id [" + handle.getAppId() + "] Info Changed. State [" + handle.getState() + "]");
}
/**
* Callback method for changes to the Spark Job's state
*/
#Override
public void stateChanged(SparkAppHandle handle) {
LOG.info("Spark App Id [" + handle.getAppId() + "] State Changed. State [" + handle.getState() + "]");
}
Using this approach, one can take action when the state changes to "FAILED", "FINISHED" or "KILLED".
I hope this information is helpful to you.
I implemented using CountDownLatch, and it works as expected.
...
final CountDownLatch countDownLatch = new CountDownLatch(1);
SparkAppListener sparkAppListener = new SparkAppListener(countDownLatch);
SparkAppHandle appHandle = sparkLauncher.startApplication(sparkAppListener);
Thread sparkAppListenerThread = new Thread(sparkAppListener);
sparkAppListenerThread.start();
long timeout = 120;
countDownLatch.await(timeout, TimeUnit.SECONDS);
...
private static class SparkAppListener implements SparkAppHandle.Listener, Runnable {
private static final Log log = LogFactory.getLog(SparkAppListener.class);
private final CountDownLatch countDownLatch;
public SparkAppListener(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
#Override
public void stateChanged(SparkAppHandle handle) {
String sparkAppId = handle.getAppId();
State appState = handle.getState();
if (sparkAppId != null) {
log.info("Spark job with app id: " + sparkAppId + ",\t State changed to: " + appState + " - "
+ SPARK_STATE_MSG.get(appState));
} else {
log.info("Spark job's state changed to: " + appState + " - " + SPARK_STATE_MSG.get(appState));
}
if (appState != null && appState.isFinal()) {
countDownLatch.countDown();
}
}
#Override
public void infoChanged(SparkAppHandle handle) {}
#Override
public void run() {}
}
In my app I need to add string vallues to the file(.property file, if it is important). and user enter this values in gwt GUI. Here is it's important part:
final Button submit = new Button("Submit");
addButton(submit);
submit.addSelectionListener(new SelectionListener<ButtonEvent>() {
#Override
public void componentSelected(ButtonEvent ce) {
keyWord.selectAll();
regexp.selectAll();
if (keyWord.getValue() != null){
setKeyWord(customerId, keyWord.getValue());
keyWord.setValue("");
}
if (regexp.getValue() != null){
setRegExp(customerId, regexp.getValue());
regexp.setValue("");
}
}
});
}
private void setKeyWord(final String customerId, final String keyword){
final AsyncCallback<String> callbackItems = new AsyncCallback<String>() {
public void onFailure(final Throwable caught) {
Window.alert("unable to add " + caught.toString());
}
public void onSuccess(final String x) {
Window.alert(x);
}
};
serverManagementSvc.setKeyWords(customerId, keyword, callbackItems);
}
private void setRegExp(final String customerId, final String regexp){
final AsyncCallback<String> calbackItems = new AsyncCallback<String>() {
#Override
public void onFailure(Throwable throwable) {
Window.alert("unable to add " + throwable.toString());
}
#Override
public void onSuccess(String s) {
Window.alert(s);
}
};
serverManagementSvc.setRegExp(customerId, regexp, calbackItems);
}
So I need to use Asunccallback to call methods which are in the "server part".
here are these methods:
//adds a new keyword to customers properties
public String setKeyWords(String customer, String word){
try{
PropertiesConfiguration props = new PropertiesConfiguration("/home/mikhail/bzrrep/DLP/DLPServer/src/main/resources/rules.properties");
String newKeyWord = new String(props.getString("users." + customer + ".keywords" + "," + word));
props.setProperty("users." + customer + ".keywords", newKeyWord);
props.save();
}catch (ConfigurationException e){
e.printStackTrace();
}
return "keyword " + word + " added";
}
// adds a new regexp to customer properties
public String setRegExp(String customer, String regexp){
try {
PropertiesConfiguration props = new PropertiesConfiguration("/home/mikhail/bzrrep/DLP/DLPServer/src/main/resources/rules.properties");
String newRegValue = new String(props.getString("users." + customer + ".regexps" + "," + regexp));
props.setProperty("users." + customer + ".regexps", newRegValue);
props.save();
} catch (ConfigurationException e){
e.printStackTrace();
}
return "regexp " + regexp + " added to " + customer + "'s config";
}
all interfaces are present.
when I run my code And press "submit" button in gui I see that both asynccallback failured(Window.alert, as you can see, shows "null pointer exception" despite of the fact that values which I send to methods are not null). why can it be? can you suggest me something?
UPD here is error which is shown by firebug:
uncaught exception: java.lang.ClassCastException
function W8(){try{null.a()}catch(a){return a}}
the problem is solved: there were a simple mistake in the code. I've closed brackets at the wrong place:
//adds a new keyword to customers properties
public String setKeyWords(String customer, String word){
try{
PropertiesConfiguration props = new PropertiesConfiguration("/home/mikhail/bzrrep/DLP/DLPServer/src/main/resources/rules.properties");
String newKeyWord = new String(props.getString("users." + customer + ".keywords") + "," + word);
props.setProperty("users." + customer + ".keywords", newKeyWord);
props.save();
}catch (ConfigurationException e){
e.printStackTrace();
}
return "keyword " + word + " added";
}
// adds a new regexp to customer properties
public String setRegExp(String customer, String regexp){
try {
PropertiesConfiguration props = new PropertiesConfiguration("/home/mikhail/bzrrep/DLP/DLPServer/src/main/resources/rules.properties");
String newRegValue = new String(props.getString("users." + customer + ".regexps") + "," + regexp);
props.setProperty("users." + customer + ".regexps", newRegValue);
props.save();
} catch (ConfigurationException e){
e.printStackTrace();
}
return "regexp " + regexp + " added to " + customer + "'s config";
}
I recommend that you recompile the GWT code using
-style PRETTY
and then check that firebug output again; it may give you a better clue, compared to your updated uncaught exception.
Next, I suggest you run it in the eclipse debugger, and set breakpoints in both the client and server code, and then you can inspect the variables and step through the code.
i have created JmDNS example:
public class Service {
public static void main(String[] args) {
try {
JmDNS mdnsServer = null;
mdnsServer = JmDNS.create("localhost");
// Register a test service.
ServiceInfo testService = ServiceInfo.create("_myTest._tcp.local.", "Test-Service", 3, "test_service");
mdnsServer.registerService(testService);
} catch (IOException e) {
e.printStackTrace();
}
}
}
It runs for few seconds then it exits program, So i am wondering is it blocking or non blocking. I was thinking since it broadcast service over network so we need to exit application manually
Same is true for following ServiceDiscovery
public class ServiceDiscovery {
private static ServiceListenerClass listener;
private static int count = 0;
public static void main(String[] args) throws IOException {
JmDNS jmdns = null;
InetAddress address = null;
String type = "_myTest._tcp.local.";
Enumeration<NetworkInterface> ifc = NetworkInterface.getNetworkInterfaces();
while (ifc.hasMoreElements()) {
NetworkInterface anInterface = ifc.nextElement();
if (anInterface.isUp()) {
Enumeration<InetAddress> addr = anInterface.getInetAddresses();
while (addr.hasMoreElements()) {
if (!(address = addr.nextElement()).isLoopbackAddress())
break;
}
}
}
jmdns = JmDNS.create(address, type);
listener = new ServiceListenerClass();
jmdns.addServiceListener(type, listener);
}
public static class ServiceListenerClass implements ServiceListener {
public void serviceAdded(ServiceEvent event) {
event.getDNS().requestServiceInfo(event.getInfo().getServer(), event.getName(), true);
}
public void serviceRemoved(ServiceEvent event) {
System.out.println((count--) + " " + event.getInfo().getName());
}
public void serviceResolved(ServiceEvent event) {
System.out.println((count++) + " :Res: " + event.getInfo().getName() + " " + event.getInfo().getPort() + " " + event.getInfo().getApplication()
+ " " + event.getInfo().getDomain() + " " + event.getInfo().getKey());
for (InetAddress address : event.getInfo().getInetAddresses())
System.out.println(address.getHostAddress());
}
}
}
Without guarantee: JmDNS.create is non-blocking, the one which is blocking is the jmdns.registerService() method.
I try to connect to a custom Bluetooth device using BlueCove. I can pair the device, but when I try to search for services I always get SERVICE_SEARCH_DEVICE_NOT_REACHABLE in serviceSearchCompleted() and no services are discovered. If I try the same thing outside Java (in Windows), the PC bluetooth device discovers and can connect (using COM21, COM22, ...) to the SPP service on my device.
What am I doing wrong?
I also tried to do the service search after the device discovery is ended. Same issue.
Please find below my code.
Many thanks in advance for any idea on how to solve this,
Adrian.
public class Test {
private static Logger LOG = Logger.getLogger(Test.class.getName());
private static final String NAME = "XXXX";
private static final String PIN = "1234";
private static final UUID[] UUIDS = new UUID[] {new UUID(0x0003), new UUID(0x1101)};
private LocalDevice localDevice;
private DiscoveryAgent discoveryAgent;
private DiscoveryListener discoveryListener = new GDiscoveryListener();
private Map<Integer, RemoteDevice> searchForServices = new HashMap<Integer, RemoteDevice>();
private Collection<ServiceRecord> servicesDiscovered = new HashSet<ServiceRecord>();
private Object lock = new Object();
private CountDownLatch waitForDevices;
protected void connect() {
try {
localDevice = LocalDevice.getLocalDevice();
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
LOG.info("Local Device: " + localDevice.getFriendlyName()
+ "(" + localDevice.getBluetoothAddress() + ")");
discoveryAgent = localDevice.getDiscoveryAgent();
LOG.finest("Start discovering devices");
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, discoveryListener);
try {
synchronized(lock) {
lock.wait();
}
if (searchForServices.size() > 0) {
waitForDevices = new CountDownLatch(searchForServices.size());
waitForDevices.await();
}
}
catch (InterruptedException e) {
LOG.log(Level.WARNING, "Error waiting to terminate discovery", e);
}
LOG.finest(servicesDiscovered.size() + " services discovered");
LOG.finest("Device discovery completed");
} catch (BluetoothStateException e) {
LOG.log(Level.WARNING, "Error initializing Bluetooth", e);
}
}
private class GDiscoveryListener implements DiscoveryListener {
public void deviceDiscovered(RemoteDevice rd, DeviceClass dc) {
try {
String name = rd.getFriendlyName(false);
boolean isMine = NAME.equals(name);
LOG.info("Discovered: " + name + "(" + rd.getBluetoothAddress() + ")"
+ (isMine ? "" : " - ignoring"));
if (!isMine)
return;
if (!rd.isAuthenticated()) {
LOG.finest("Try to pair with " + name
+ " PIN: " + PIN);
boolean paired = RemoteDeviceHelper.authenticate(rd, PIN);
LOG.info("Pair with " + name + (paired ? " succesfull" : " failed"));
}
int transID = discoveryAgent.searchServices(null, UUIDS, rd, discoveryListener);
searchForServices.put(transID, rd);
LOG.finest("Searching for services for " + name + " with transaction " + transID);
} catch (BluetoothStateException e) {
LOG.log(Level.WARNING, "Cannot search services for "
+ rd.getBluetoothAddress(), e);
} catch (IOException e) {
LOG.log(Level.WARNING, "Error connecting ", e);
} catch (Throwable t) {
LOG.log(Level.WARNING, "Cannot search services for "
+ rd.getBluetoothAddress(), t);
}
}
public void inquiryCompleted(int respCode) {
synchronized(lock) {
lock.notify();
}
switch (respCode) {
case DiscoveryListener.INQUIRY_COMPLETED :
LOG.fine("INQUIRY_COMPLETED");
break;
case DiscoveryListener.INQUIRY_TERMINATED :
LOG.fine("INQUIRY_TERMINATED");
break;
case DiscoveryListener.INQUIRY_ERROR :
LOG.fine("INQUIRY_ERROR");
break;
default :
LOG.fine("Unknown Response Code - " + respCode);
break;
}
}
public void serviceSearchCompleted(int transID, int respCode) {
String rd = searchForServices.get(transID).getBluetoothAddress();
//searchForServices.remove(transID);
switch (respCode) {
case DiscoveryListener.SERVICE_SEARCH_COMPLETED:
LOG.fine(rd + ": The service search completed normally");
break;
case DiscoveryListener.SERVICE_SEARCH_TERMINATED:
LOG.fine(rd + ": The service search request was cancelled by a call to DiscoveryAgent.cancelServiceSearch(int)");
break;
case DiscoveryListener.SERVICE_SEARCH_ERROR:
LOG.warning(rd + ": An error occurred while processing the request");
break;
case DiscoveryListener.SERVICE_SEARCH_NO_RECORDS:
LOG.info(rd + ": No records were found during the service search");
break;
case DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE:
LOG.warning(rd + ": The device specified in the search request could not be reached or the local device could not establish a connection to the remote device");
break;
default:
LOG.warning(rd + ": Unknown Response Code - " + respCode);
break;
}
if (waitForDevices != null)
waitForDevices.countDown();
}
public void servicesDiscovered(int transID, ServiceRecord[] srs) {
LOG.info("Services discovered in transaction " + transID + " : " + srs.length);
for (ServiceRecord sr : srs) {
LOG.info(sr.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false));
servicesDiscovered.add(sr);
}
}
}
public static void main(String[] args) {
new Test().connect();
}
}
I had the same problem while connecting to a Bluetooth earpiece. Like you I was also searching for more than one service at a time and It always returned SERVICE_SEARCH_DEVICE_NOT_REACHABLE. So, I tried searching for only one service and it worked. So, try modifying your code as:
...
private static final UUID[] UUIDS = new UUID[] {new UUID(0x0003)}