I have an application which is a RESTful API consumer, and I wish to have a timeout on my connection with the API.
As I've searched, and also tested, the HttpURLConnection.setReadTimeout() method doesn't work, so the solution I found was to use an AsyncTask which will try to connect to the server and then pass the timeout to the AsyncTask.get().
It works, partially. The problem is when I do the following:
Enter the application with the WiFi turned on. I click "Login" button and get "Invalid/User password". Ok.
Turn off the WiFi, click "Login" button. The application tries to connect but after 5 seconds (the timeout I chose) it shows me the notification dialog saying I'm not connected. Ok, everything as expected.
Turn on back the WiFi, click "Login" button. It stills working as if I was not connected, always showing the dialog. I can wait many seconds but the behaviour is the same as If I was disconnected.
I debugged all my code, step by step using Eclipse and there's nothing wrong with the logic.
My HttpURLConnection is always a new object, so I'm not trying to use the same connection object to connect after the WiFi is turned on back...
Also I'm using the Scribe library, for OAuth, but I checked the source code and everything seems ok, except that I changed the method which creates a connection to always use a new instance.
I'm starting to think that Android is "caching" my connection object or the AsyncTask object...
Below some code of my RequestManager class:
public class RequestManager {
private static RequestManager self = new RequestManager();
private Request currentRequest;
private static final long TIMEOUT = 5000;
public static RequestManager getInstance() {
return self;
}
public void startRequest(Request request) {
if (currentRequest != null) return;
currentRequest = request;
}
public String getResponse() throws ConnectionErrorException {
RequestThreat rt = new RequestThread();
rt.execute(currentRequest);
try {
return (String) rt.get(TIMEOUT, TimeUnit.MILISECONDS);
} catch (InterruptedException e) {
} catch (ExecutionException e) {
} catch (TimeoutException e) {
throw new ConnectionErrorException();
} finally {
endRequest();
}
return null;
}
public void endRequest() {
currentRequest = null;
}
private class RequestThread extends AsyncTask<Request, Integer, String> {
#Override
protected String doInBackground(Request... requestParams) {
return requestParams[0].send().getBody();
}
}
}
Also in the method I call getResponse() I'm calling endRequest() after.
Any thoughts?
You should check to see if a network connection is available before trying to access the network. Have a look at this quesion:
How to respect network use settings
Specifically:
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isAvailable() && networkInfo.isConnected()) {
Related
i have written a large scale http server using , but im getting this error when number of concurrent requests increases
WARNING: Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 8458 ms, time limit is 1000
io.vertx.core.VertxException: Thread blocked
here is my full code :
public class MyVertxServer {
public Vertx vertx = Vertx.vertx(new VertxOptions().setWorkerPoolSize(100));
private HttpServer server = vertx.createHttpServer();
private Router router = Router.router(vertx);
public void bind(int port){
server.requestHandler(router::accept).listen(port);
}
public void createContext(String path,MyHttpHandler handler){
if(!path.endsWith("/")){
path += "/";
}
path+="*";
router.route(path).handler(new Handler<RoutingContext>() {
#Override
public void handle(RoutingContext ctx) {
String[] handlerID = ctx.request().uri().split(ctx.currentRoute().getPath());
String suffix = handlerID.length > 1 ? handlerID[1] : null;
handler.Handle(ctx, new VertxUtils(), suffix);
}
});
}
}
and how i call it :
ver.createContext("/getRegisterManager",new ProfilesManager.RegisterHandler());
ver.createContext("/getLoginManager", new ProfilesManager.LoginHandler());
ver.createContext("/getMapcomCreator",new ItemsManager.MapcomCreator());
ver.createContext("/getImagesManager", new ItemsManager.ImagesHandler());
ver.bind(PORT);
how ever i dont find eventbus() useful for http servers that process send/receive files , because u need to send the RoutingContext in the message with is not possible.
could you please point me to the right direction? thanks
added a little bit of handler's code:
class ProfileGetter implements MyHttpHandler{
#Override
public void Handle(RoutingContext ctx, VertxUtils utils, String suffix) {
String username = utils.Decode(ctx.request().headers().get("username"));
String lang = utils.Decode(ctx.request().headers().get("lang"));
display("profile requested : "+username);
Profile profile = ProfileManager.FindProfile(username,lang);
if(profile == null){
ctx.request().response().putHeader("available","false");
utils.sendResponseAndEnd(ctx.response(),400);
return;
}else{
ctx.request().response().putHeader("available","true");
utils.writeStringAndEnd(ctx, new Gson().toJson(profile));
}
}
}
here ProfileManager.FindProfile(username,lang) does a long running database job on the same thread
...
basically all of my processes are happening on the main thread , because if i use executor i will get strange exceptions and nullpointers in Vertx , making me feel like the request proccessors in Vertx are parallel
Given the small amount of code in the question lets agree that the problem is on the line:
Profile profile = ProfileManager.FindProfile(username,lang);
Assuming that this is internally doing some blocking JDBC call which is a anti-pattern in Vert.x you can solve this in several ways.
Say that you can totally refactor the ProfileManager class which IMO is the best then you can update it to be reactive, so your code would be like:
ProfileManager.FindProfile(username,lang, res -> {
if (res.failed()) {
// handle error, sent 500 back, etc...
} else {
Profile profile = res.result();
if(profile == null){
ctx.request().response().putHeader("available","false");
utils.sendResponseAndEnd(ctx.response(),400);
return;
}else{
ctx.request().response().putHeader("available","true");
utils.writeStringAndEnd(ctx, new Gson().toJson(profile));
}
}
});
Now what would be hapening behind the scenes is that your JDBC call would not block (which is tricky because JDBC is blocking by nature). So to fix this and you're lucky enough to use MySQL or Postgres then you could code your JDBC against the async-client if you're stuck with other RDBMS servers then you need to use the jdbc-client which in turn will use a thread pool to offload the work from the event loop thread.
Now say that you cannot change the ProfileManager code then you can still off load it to the thread pool by wrapping the code in a executeBlocking block:
vertx.executeBlocking(future -> {
Profile profile = ProfileManager.FindProfile(username,lang);
future.complete(profile);
}, false, res -> {
if (res.failed()) {
// handle error, sent 500 back, etc...
} else {
Profile profile = res.result();
if(profile == null){
ctx.request().response().putHeader("available","false");
utils.sendResponseAndEnd(ctx.response(),400);
return;
}else{
ctx.request().response().putHeader("available","true");
utils.writeStringAndEnd(ctx, new Gson().toJson(profile));
}
}
});
I'm writing a Spring web application and I'm mapping the "/do" URL path to the following Controller's method
#Controller
public class MyController
{
#RequestMapping(value="/do", method=RequestMethod.GET)
public String do()
{
File f = new File("otherMethodEnded.tmp");
while (!f.exists())
{
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
}
// ok, let's continue
}
}
The otherMethodEnded.tmp file is written by one another Controller's method, so when the client calls the second URL I expect the first method to exit the while loop.
Everything works, except when the client calls the "/do" URL and then closes the connection before the response was received. The problem is that the server remains in the while (!f.exists()) loop even though the client is down and cannot call the second URL to unlock the while loop.
I would try to retrieve the connection status of the "/do" URL and exit the loop when the connection is closed by the client, but I cannot find any way to do so.
I tried with the HttpServletRequest.getSession(false) method but the returned HttpSession object is always not null, so the HttpServletRequest object is not updated in case of connection close of the client.
How can I check whether the client is still waiting for the risponse or not?
The simplest way to verify something is not right is to define a timeout value and then during your loop test if your time spent waiting has exceeded the timeout.
something like:
#Controller
public class MyController
{
private static final long MAX_LOOP_TIME = 1000 * 60 * 5; // 5 minutes? choose a value
#RequestMapping(value="/do", method=RequestMethod.GET)
public String do()
{
File f = new File("otherMethodEnded.tmp");
long startedAt = System.currentTimeMillis()
boolean forcedExit = false;
while (!forcedExit && !f.exists())
{
try {
Thread.sleep(5000);
if (System.currentTimeMillis() - startedAt > MAX_LOOP_TIME) {
forcedExit = true;
}
} catch (InterruptedException e) {
forcedExit = true;
}
}
// ok, let's continue
// if forcedExit , handle error scenario?
}
}
Additionally: InterruptedException is not something to blindly catch and ignore. see this discussion
In your case I would really exit the while loop if you're interrupted.
You only know if the client is no longer waiting on your connection when you notice the output stream you write to (response.outputstream) is closed. But there isn't a way to detect it.
(see this question for details)
Seeing as you've indicated your client does occasional callbacks, you could on the clientside poll if the other call has been completed. If this other call has completed, do the operation, otherwise return directly and have the client do the call again. (assuming you are sending json, but adapt as you require)
something like
public class MyController
{
#RequestMapping(value="/do", method=RequestMethod.GET)
public String do()
{
File f = new File("otherMethodEnded.tmp");
if (f.exists()) {
// do what you set out to do
// ok, let's continue
// and return with a response that indicates the call did what it did
// view that returns json { "result" : "success" }
return "viewThatSIgnalsToClientThatOperationSucceeded";
} else {
// view that returns json: { "result" : "retry" }
return "viewThatSignalsToClientToRetryIn5Seconds";
}
}
}
Then the clientside would run something like: (pseudojavascript as it's been a while)
val callinterval = setInterval(function() { checkServer() }, 5000);
function checkServer() {
$.ajax({
// ...
success: successFunction
});
}
function successFunction(response) {
// connection succeeded
var json = $.parseJSON(response);
if (json.result === "retry") {
// interval will call this again
} else {
clearInterval(callinterval);
if (json.result === "success") {
// do the good stuff
} else if (json.result === "failure") {
// report that the server reported an error
}
}
}
Ofcourse this is just semi-serious code but it's roughly how i'd try it if I were to have the dependency. If this is regarding afile upload, keep in mind that this file may not contain all of the bytes yet. file exists != file = completely uploaded, unless you use move it. cp / scp / etc. is not atomic.
How to check if server is online or offline, and if is offline start connecting until server is on. I have tried with this:
connectBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Thread(rConnection).start();
}
});
public Runnable rConnection = new Runnable() {
#Override
public void run() {
boolean status = connect();
while (!status)
{
System.out.println("Connection Status: " + status);
status = Connect();
}
}
};
public boolean Connect() {
boolean status = false;
try {
s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT);
System.out.println("Socket: " + s.toString());
if (s.toString() != "")
{
status = true;
}
} catch (UnknownHostException e) {
e.printStackTrace();
status = false;
s=null;
} catch (IOException e) {
e.printStackTrace();
status = false;
s=null;
} catch (NullPointerException e)
{
e.printStackTrace();
status = false;
s=null;
}
return status;
}
If server is running before staring app it connects successfully but if server is off or disconnects after some time I don't get any error message and it won't start reconnecting again. How to solve this?
Basically you may split this:
s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT);
into
s = new Socket();
s.connect(remoteAddr,timeout)
And then control if connect returns on timeout or on successfull connection.
Look at this thread for a solution and keywords: How can I monitor the network connection status in Android? . Also, consider retrying requests on a new connection if the underlying connection is lost (or times out).
How to check if server is online or offline, and if is offline start connecting until server is on
Try to connect to it when you need to connect to it, and handle the failures that result. At present you seem to be trying to maintain an eternal connection, which is never going to work. The best way to detect whether a resource is available is to try to use it at the time that you need to use it. Anything is subject to numerous sources of error such as timing window problems, testing the wrong thing, testing the right thing at the wrong time, and at best to overuse of scarce resources. Rethink your requirement.
I am working to add Bluetooth capabilities to my app and ultimately the device that I want to use is a headset/earpiece. I have begun assembling the code and I partial functionality with it. When I got to the code for setting up a bluetooth connection by server, I got errors when adding the code. I have tried solving the problems through the hover over the error and autocorrect but every time I fix one problem a different on arises. This leads me to believe that I am missing something that autocorrect doesn't know about. I need some help fixing the errors. Useful suggestions for setting a bluetooth codin for the first time would also be appreciated. Errors are surrounded with ||#| xxx |||. Error 1:cannot be resolved. Error 2:cannot be resolved to a variable. Error 3:undefined for the type AcceptSocket.
import java.io.IOException;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
public class AcceptSocket extends Thread {
private static final String MY_UUID = null;
BluetoothServerSocket mmServerSocket;
public void AcceptThread() {
// Use a temporary object that is later asssigned to mmServerSocket,
// because mmServerSocket is final
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = ||1|mBluetoothAdapter|||.listenUsingRfcommWithServiceRecord(||2|NAME|||,
MY_UUID);
} catch (IOException e) {
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
// Do work to manage the connection (in a separate thread)
||3|manageConnectedSocket|||(socket);
mmServerSocket.close();
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) {
}
}
}
Error 1,2: There is no constant called NAME anywhere in the class.
Error 3: There is no method called manageConnectedSocket() in the class.
You can't just copy and paste something from the developer's page and expect it to work. It leads you in the correct direction and you have to fill in the missing pieces.
Using JXTA 2.6 from http://jxse.kenai.com/ I want to create application that can run multiple peers on one or more hosts. The peers should be able to find each other in a group and send direct messages as well as propagate messages.
What would a simple hello world type of application look like that meet these requirements?
I created this question with the intention of supplying a tutorial like answer, an answer I tried very hard to find two months ago when starting to look at JXTA for a uni project. Feel free to add your own answers or improve on mine. I will wait a few days and accept the best one.
Introduction to JXTA 2.6 Peer discovery and pipe messaging
The guide I wish I had 2 months ago =)
After spending a lot of time during a university course building
a JXTA p2p application I feel a lot of the frustrations and
confusion I went through could have been avoided with a good
starting point.
The jar files you will need can be found here:
https://oss.sonatype.org/content/repositories/comkenaijxse-057/com/kenai/jxse/jxse/2.6/jxse-2.6.jar
http://sourceforge.net/projects/practicaljxta/files/lib-dependencies-2.6.zip/download
Throw them into Yourproject/lib, open up eclipse, create a new project "Yourproject" and it should sort out
importing the libraries for you.
You will soon come to realize that almost any information on the web is out dated, very out dated.
You will also run into a lot of very confusing error messages and most of them can be avoided by
going through this check list.
Is your firewall turned off or at least open for the ports you use?
You can disable iptables using "sudo service iptables stop" under Fedora.
Check spelling! Many times when joining groups or trying to send messages spelling the group name wrong or not using the
exact same advertisement when looking for peers and services or opening pipes will cause very confusing messages.
Was trying to figure out why my pipe connections timed out when I spotted the group names being "Net info" and "Net_info".
Are you using a JXTA home directory? One per each peer you run on the same computer?
Do you really use a unique peer id? The seed provided to IDFactory need to be long enough or else you will get duplicates.
Turn off SELinux. I have had SELinux turned off during the development but can imagine it causing errors.
While it is common to group all fields together I introduce them as I go to show where they are needed.
Note: This will not work in 2.7. Some issue with PSE membership I think.
public class Hello implements DiscoveryListener, PipeMsgListener {
// When developing you should handle these exceptions, I don't to lessen the clutter of start()
public static void main(String[] args) throws PeerGroupException, IOException {
// JXTA logs a lot, you can configure it setting level here
Logger.getLogger("net.jxta").setLevel(Level.ALL);
// Randomize a port to use with a number over 1000 (for non root on unix)
// JXTA uses TCP for incoming connections which will conflict if more than
// one Hello runs at the same time on one computer.
int port = 9000 + new Random().nextInt(100);
Hello hello = new Hello(port);
hello.start();
hello.fetch_advertisements();
}
private String peer_name;
private PeerID peer_id;
private File conf;
private NetworkManager manager;
public Hello(int port) {
// Add a random number to make it easier to identify by name, will also make sure the ID is unique
peer_name = "Peer " + new Random().nextInt(1000000);
// This is what you will be looking for in Wireshark instead of an IP, hint: filter by "jxta"
peer_id = IDFactory.newPeerID(PeerGroupID.defaultNetPeerGroupID, peer_name.getBytes());
// Here the local peer cache will be saved, if you have multiple peers this must be unique
conf = new File("." + System.getProperty("file.separator") + peer_name);
// Most documentation you will find use a deprecated network manager setup, use this one instead
// ADHOC is usually a good starting point, other alternatives include Edge and Rendezvous
try {
manager = new NetworkManager(
NetworkManager.ConfigMode.ADHOC,
peer_name, conf.toURI());
}
catch (IOException e) {
// Will be thrown if you specify an invalid directory in conf
e.printStackTrace();
}
NetworkConfigurator configurator;
try {
// Settings Configuration
configurator = manager.getConfigurator();
configurator.setTcpPort(port);
configurator.setTcpEnabled(true);
configurator.setTcpIncoming(true);
configurator.setTcpOutgoing(true);
configurator.setUseMulticast(true);
configurator.setPeerID(peer_id);
}
catch (IOException e) {
// Never caught this one but let me know if you do =)
e.printStackTrace();
}
}
private static final String subgroup_name = "Make sure this is spelled the same everywhere";
private static final String subgroup_desc = "...";
private static final PeerGroupID subgroup_id = IDFactory.newPeerGroupID(PeerGroupID.defaultNetPeerGroupID, subgroup_name.getBytes());
private static final String unicast_name = "This must be spelled the same too";
private static final String multicast_name = "Or else you will get the wrong PipeID";
private static final String service_name = "And dont forget it like i did a million times";
private PeerGroup subgroup;
private PipeService pipe_service;
private PipeID unicast_id;
private PipeID multicast_id;
private PipeID service_id;
private DiscoveryService discovery;
private ModuleSpecAdvertisement mdadv;
public void start() throws PeerGroupException, IOException {
// Launch the missiles, if you have logging on and see no exceptions
// after this is ran, then you probably have at least the jars setup correctly.
PeerGroup net_group = manager.startNetwork();
// Connect to our subgroup (all groups are subgroups of Netgroup)
// If the group does not exist, it will be automatically created
// Note this is suggested deprecated, not sure what the better way is
ModuleImplAdvertisement mAdv = null;
try {
mAdv = net_group.getAllPurposePeerGroupImplAdvertisement();
} catch (Exception ex) {
System.err.println(ex.toString());
}
subgroup = net_group.newGroup(subgroup_id, mAdv, subgroup_name, subgroup_desc);
// A simple check to see if connecting to the group worked
if (Module.START_OK != subgroup.startApp(new String[0]))
System.err.println("Cannot start child peergroup");
// We will spice things up to a more interesting level by sending unicast and multicast messages
// In order to be able to do that we will create to listeners that will listen for
// unicast and multicast advertisements respectively. All messages will be handled by Hello in the
// pipeMsgEvent method.
unicast_id = IDFactory.newPipeID(subgroup.getPeerGroupID(), unicast_name.getBytes());
multicast_id = IDFactory.newPipeID(subgroup.getPeerGroupID(), multicast_name.getBytes());
pipe_service = subgroup.getPipeService();
pipe_service.createInputPipe(get_advertisement(unicast_id, false), this);
pipe_service.createInputPipe(get_advertisement(multicast_id, true), this);
// In order to for other peers to find this one (and say hello) we will
// advertise a Hello Service.
discovery = subgroup.getDiscoveryService();
discovery.addDiscoveryListener(this);
ModuleClassAdvertisement mcadv = (ModuleClassAdvertisement)
AdvertisementFactory.newAdvertisement(ModuleClassAdvertisement.getAdvertisementType());
mcadv.setName("STACK-OVERFLOW:HELLO");
mcadv.setDescription("Tutorial example to use JXTA module advertisement Framework");
ModuleClassID mcID = IDFactory.newModuleClassID();
mcadv.setModuleClassID(mcID);
// Let the group know of this service "module" / collection
discovery.publish(mcadv);
discovery.remotePublish(mcadv);
mdadv = (ModuleSpecAdvertisement)
AdvertisementFactory.newAdvertisement(ModuleSpecAdvertisement.getAdvertisementType());
mdadv.setName("STACK-OVERFLOW:HELLO");
mdadv.setVersion("Version 1.0");
mdadv.setCreator("sun.com");
mdadv.setModuleSpecID(IDFactory.newModuleSpecID(mcID));
mdadv.setSpecURI("http://www.jxta.org/Ex1");
service_id = IDFactory.newPipeID(subgroup.getPeerGroupID(), service_name.getBytes());
PipeAdvertisement pipeadv = get_advertisement(service_id, false);
mdadv.setPipeAdvertisement(pipeadv);
// Let the group know of the service
discovery.publish(mdadv);
discovery.remotePublish(mdadv);
// Start listening for discovery events, received by the discoveryEvent method
pipe_service.createInputPipe(pipeadv, this);
}
private static PipeAdvertisement get_advertisement(PipeID id, boolean is_multicast) {
PipeAdvertisement adv = (PipeAdvertisement )AdvertisementFactory.
newAdvertisement(PipeAdvertisement.getAdvertisementType());
adv.setPipeID(id);
if (is_multicast)
adv.setType(PipeService.PropagateType);
else
adv.setType(PipeService.UnicastType);
adv.setName("This however");
adv.setDescription("does not really matter");
return adv;
}
#Override public void discoveryEvent(DiscoveryEvent event) {
// Found another peer! Let's say hello shall we!
// Reformatting to create a real peer id string
String found_peer_id = "urn:jxta:" + event.getSource().toString().substring(7);
send_to_peer("Hello", found_peer_id);
}
private void send_to_peer(String message, String found_peer_id) {
// This is where having the same ID is important or else we wont be
// able to open a pipe and send messages
PipeAdvertisement adv = get_advertisement(unicast_id, false);
// Send message to all peers in "ps", just one in our case
Set<PeerID> ps = new HashSet<PeerID>();
try {
ps.add((PeerID)IDFactory.fromURI(new URI(found_peer_id)));
}
catch (URISyntaxException e) {
// The JXTA peer ids need to be formatted as proper urns
e.printStackTrace();
}
// A pipe we can use to send messages with
OutputPipe sender = null;
try {
sender = pipe_service.createOutputPipe(adv, ps, 10000);
}
catch (IOException e) {
// Thrown if there was an error opening the connection, check firewall settings
e.printStackTrace();
}
Message msg = new Message();
MessageElement fromElem = null;
MessageElement msgElem = null;
try {
fromElem = new ByteArrayMessageElement("From", null, peer_id.toString().getBytes("ISO-8859-1"), null);
msgElem = new ByteArrayMessageElement("Msg", null, message.getBytes("ISO-8859-1"), null);
} catch (UnsupportedEncodingException e) {
// Yepp, you want to spell ISO-8859-1 correctly
e.printStackTrace();
}
msg.addMessageElement(fromElem);
msg.addMessageElement(msgElem);
try {
sender.send(msg);
} catch (IOException e) {
// Check, firewall, settings.
e.printStackTrace();
}
}
#Override public void pipeMsgEvent(PipeMsgEvent event) {
// Someone is sending us a message!
try {
Message msg = event.getMessage();
byte[] msgBytes = msg.getMessageElement("Msg").getBytes(true);
byte[] fromBytes = msg.getMessageElement("From").getBytes(true);
String from = new String(fromBytes);
String message = new String(msgBytes);
System.out.println(message + " says " + from);
}
catch (Exception e) {
// You will notice that JXTA is not very specific with exceptions...
e.printStackTrace();
}
}
/**
* We will not find anyone if we are not regularly looking
*/
private void fetch_advertisements() {
new Thread("fetch advertisements thread") {
public void run() {
while(true) {
discovery.getRemoteAdvertisements(null, DiscoveryService.ADV, "Name", "STACK-OVERFLOW:HELLO", 1, null);
try {
sleep(10000);
}
catch(InterruptedException e) {}
}
}
}.start();
}
}