I am building my first Java application using GWT which must read in data from a very large XML file. I am having issues when I try sending a request for the information in the file, and I'm not quite sure if it has to do with the size of the file, or my semantics. In my program I have the following:
static final String xmlurl = "filename.xml";
String xmlData;
...
public void onModuleLoad() {
requestData(xmlurl);
if(xmlData.equals("Error")){
// display error message
return;
} else {
// display the xml
}
void requestData(String url){
final int STATUS_CODE = 200;
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
builder.setTimeoutMillis(2000);
builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
xmlData = "Error"
}
public void onResponseReceived(Request request, Response response) {
if (STATUS_CODE == response.getStatusCode()){
xmlData = response.getText();
} else {
xmlData = "Error";
}
}
}
} catch (RequestException e) {
xmlData = "Error";
}
}
I rewrote the code, so I might have made some typos, but for the actual application it compiles and runs. The issue is that I get a nullpointer exception when I try to display the XML and xmlData is never assigned to anything. I tried putting a while loop that waited for it to store either "Error" or the XML text, but the variable was never assigned to. I have the XML file saved in the war directory of my project, and it seems to be able to find the file. I've searched online for similar examples, but everything seemed to be a bit more complicated than what I'm trying to do, and I'm not sure if I need a servlet or a configuration change for this, or if the file is just too big to read into a String. Any help is appreciated. Thanks.
Parsing xml at client-side (in browser) is quite slow, and should be avoided; delegating this to server-side is usually faster and therefore more user friendly (big files will cause your browser stop responding for a long time).
However the decision is yours ;) Here is what I use for reading files:
Define this helper method:
public static void httpGetFile(final String url, final AsyncCallback<String> callback) {
final RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, url);
rb.setCallback(new RequestCallback() {
public void onResponseReceived(Request request, Response response) {
try {
final int responseCode = response.getStatusCode() / 100;
if (url.startsWith("file:/") || (responseCode == 2)) {
callback.onSuccess(response.getText());
} else {
callback.onFailure(new IllegalStateException("HttpError#" + response.getStatusCode() + " - " + response.getStatusText()));
}
} catch (Throwable e) {
callback.onFailure(e);
}
}
public void onError(Request request, Throwable exception) {
callback.onFailure(exception);
}
});
try {
rb.send();
} catch (RequestException e) {
callback.onFailure(e);
}
}
In your code, it might look like this:
...
httpGetFile(url, new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
xmlData = "Error";
}
public void onSuccess(String xmlText) {
xmlData = xmlText;
}
}
....
Related
The task is simple, but I want to do it in the right way and I would love to hear your expert advice because I am novice in android developing.
First the application is just for me so I really don't care about security and stuff.
So my objective is like this:
I have a large amount of data that I want to transfer to my MYSQL database, the easiest way for me is to use HTTP POST method, but I am concerned about the part that the application may get stuck or some data won't pass because of the many POST requests that are gonna be.
So how exactly should I pass the data using POST request with insuring that all of the requests will be sent one by one without skipping any or losing data ?
Just the logic behind this would be enough I don't really need the code part.
Hopefully I was clear enough.
Retrofit FTW. Makes networking easy on Android (RESTful) and it include Gson.
Speaking of Gson... You mention you might be making many POSTs? If so, you should probably convert your data to JSON instead, and send it over the network that way. Google's Gson is a fantastic way to easily convert a Java object to JSON.
http://square.github.io/retrofit/
https://github.com/google/gson
Before reading: this is my way for implementing posts and gets, this is not the best way ever, but just the best way for my needs, feel free to edit/not use/implement it yourself
I personally prefer OkHTTP library, it is easy to use and easy to implement.
Implementation is really easy, just add this row in your Gradle app-level
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
Then I created an helper class for get and post calls (I don't need many configurations, so a static one for me was enough, if you need more stuff you can easily implement. Also the timeouts are set for my needs and you can chenge them freely)
private String ConsumeGetRequest(String path) {
int tries = 0;
boolean isMyException = true;
while (tries <= 3 && isMyException) {
try {
isMyException = false;
tries++;
Response response = executeRequestBody(path, null);
if (response != null && response.body() != null)
return response.body().string();
else
return "";
} catch (ConnectException e) {
e.printStackTrace();
if (e.getMessage().contains("Failed to connect to") && tries <= 3) {
isMyException = true;
}
} catch (Exception ex) {
ex.printStackTrace();
return "";
}
}
return "";
}
private Pair<Boolean, String> ConsumePostRequest(String path, String postData) {
int tries = 0;
String errorMsg = null;
boolean isMyException = true;
//you can ignore this while, it was for our internal reasons and it's just a check.
while (tries <= 3 && isMyException) {
try {
isMyException = false;
tries++;
Response response = executeRequestBody(path, postData);
if (response != null && response.body() != null)
return new Pair<>(response.isSuccessful(), response.body().string());
else
return new Pair<>(false, null);
} catch (ConnectException e) {
errorMsg = e.getMessage();
if (e.getMessage().contains("Failed to connect to") && tries <= 3) {
isMyException = true;
}
} catch (Exception ex) {
errorMsg = ex.getMessage();
}
}
return new Pair<>(false, errorMsg);
}
private Response executeRequestBody(String path, String postData) throws IOException {
String url = String.format("%s%s/", RuntimeHelper._baseWebServiceIP, path);
if (okHttpClient == null) {
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.build();
}
Request.Builder builder = new Request.Builder().url(url);
if (postData != null && !postData.isEmpty()) {
RequestBody body = RequestBody.create(RuntimeHelper._okHttpTypeJson, postData);
builder = builder.post(body);
}
Request request = builder.build();
return okHttpClient.newCall(request).execute();
}
with those two methods (a couple of examples) I create my path and I call the proper method for my needs.
//Post
public boolean setAlerts(String postData) {
String path = String.format("api/wfm/v1/set-alerts/%s/%s", authToken, resourceId);
return ConsumePostRequest(path, postData).first;
}
//Post
public String isAlertUpdated(String lastDownloadDate) {
String path = String.format("api/wfm/v1/is-alert-updated/%s/%s", authToken, lastDownloadDate);
return ConsumeGetRequest(path);
}
Then with an AsyncTask you can perform the operation without blocking UI
public class NewAlertAsyncTask extends AsyncTask<String, String, Boolean> {
Context context;
private WebApiMethodsController webApiMethodsController;
AuthenticatedUser authenticatedUser;
public NewAlertAsyncTask(Context ctx) {
this.context = ctx;
authenticatedUser = AuthenticatedUser.getIstance(context);
webApiMethodsController = new WebApiMethodsController(authenticatedUser.getAuthenticationTokenID().toString(), authenticatedUser.getResourceID().toString(), context);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values) {
}
#Override
protected Boolean doInBackground(String... datas) {
Boolean result;
try {
result = webApiMethodsController.setAlerts(datas[0]);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return result;
}
#Override
protected void onPostExecute(Boolean s) {
if(s){
//manage succes, I use this
mCallback.onNewAlertCreated();
}
else{
//manage error
}
}
}
mine is a really simple structure, you can implement it with callbacks, status progress, deeper return status check, ...
You can simply call the asynctask with this
NewAlertAsyncTask newAlertAsyncTask = new NewAlertAsyncTask(getActivity());
newAlertAsyncTask.execute(gson.toJson(alertList));
I'm currently in a project where I have to do multiple, concurrent http requests to a rest service which returns a JSON response. This is a batch operation and the number of requests at any time could range from several hunderd to several thousend.
That's why I thought it would be a good idea to have an async http client so I could have concurrent requests, which dramatically could speed up the process. I first tried ning's async-http-client. Maybe I was doing something wrong, because it was kind of slow for me. About 10 seconds for 1000 requests.
After which I tried Apache's implementation which was much faster at about 4 seconds for 1000 requests. But I can't seem to get the requests to get stable. Most of the time I will get a List with a 1000 responses (like I expect), but sometimes I am just missing a few responses, like 1 or 2.
This is currently my code:
public class AsyncServiceTest {
public AsyncServiceTest(String serviceURI) {
this.httpClient = HttpAsyncClients.custom().setMaxConnPerRoute(100).setMaxConnTotal(20)
.setDefaultRequestConfig(RequestConfig.custom().build()).build();
this.objectMapper = new ObjectMapper();
this.serviceURI = serviceURI;
}
private List<Object> getResults(List<String> queryStrings) throws Exception {
try {
httpClient.start();
final List<HttpGet> requests = new ArrayList<>(addresses.size());
for (String str : queryStrings) {
requests.add(new HttpGet(buildUri(str))); // In this method we build the absolute request uri.
}
final CountDownLatch latch = new CountDownLatch(requests.size());
final List<Object> responses = new ArrayList<>(requests.size());
final List<String> stringResponses = new ArrayList<>(requests.size());
for (final HttpGet request : requests) {
httpClient.execute(request, new FutureCallback<HttpResponse>() {
#Override
public void completed(HttpResponse response) {
try {
stringResponses.add(IOUtils.toString(response.getEntity().getContent(), "UTF-8"));
latch.countDown();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void failed(Exception e) {
latch.countDown();
}
#Override
public void cancelled() {
latch.countDown();
}
});
}
latch.await();
for (String r : stringResponses) {
responses.add(mapToLocation(r)); // Mapping some Strings to JSON in this method.
}
return responses;
} finally {
httpClient.close();
}
}
}
So, in essence, I am wondering if there is something wrong with my code (probably) or is it just because of the way the library works? Because the CountDownLatch is at zero all the time. Or does anyone have a pointer in the right direction (maybe with another library)?
It seemed to be a concurrency problem (thanks to #vanOekel) in my code. The answer is to replace the ArrayList<E> with a Vector<E>, which is in fact thread-safe. Example code:
public class AsyncServiceTest {
public AsyncServiceTest(String serviceURI) {
this.httpClient = HttpAsyncClients.custom().setMaxConnPerRoute(100).setMaxConnTotal(20)
.setDefaultRequestConfig(RequestConfig.custom().build()).build();
this.objectMapper = new ObjectMapper();
this.serviceURI = serviceURI;
}
private List<Object> getResults(List<String> queryStrings) throws Exception {
try {
httpClient.start();
final CountDownLatch latch = new CountDownLatch(queryStrings.size());
final Vector<Object> responses = new Vector<>(queryStrings.size());
for (String str : queryStrings) {
// buildUri: In this method we build the absolute request uri.
httpClient.execute(new HttpGet(buildUri(str)), new FutureCallback<HttpResponse>() {
#Override
public void completed(HttpResponse response) {
try {
// mapToLocation: Mapping some Strings to JSON in this method.
responses.add(mapToLocation(IOUtils.toString(response.getEntity().getContent(), "UTF-8")));
latch.countDown();
} catch (IOException e) {
failed(e);
}
}
#Override
public void failed(Exception e) {
logger.error(e.getLocalizedMessage(), e);
latch.countDown();
}
#Override
public void cancelled() {
logger.error("Request cancelled.");
latch.countDown();
}
});
}
latch.await();
return responses;
} finally {
httpClient.close();
}
}
}
Thanks for all the helpful responses. If anyone has any suggestions regarding optimization of the above code, I will be glad to hear so.
I have the following piece of code to work with but I just did not understand how this works, to start off refer the following link
http://developer.android.com/reference/android/os/Message.html#sendToTarget%28%29
It clearly states that sendToTarget() sends message to the specified Handler by getTarget() or it throws a NPE. In the following code, I dont see an implementation of getTarget() but its working fine, please explain how this works, look for queueThumbnail() function here..specified in comments exactly where Im not understanding how it works
public class ThumbnailDownloader<Token> extends HandlerThread {
private static final String TAG = "ThumbNailDownloader";
private static final int MESSAGE_DOWNLOAD = 0;
Handler mHandler;
Map <Token, String> requestMap = Collections.synchronizedMap(new HashMap<Token,String>());
public ThumbnailDownloader(Handler responseHandler)
{
super(TAG);
}
#SuppressLint("HandlerLeak")
#Override
protected void onLooperPrepared()
{
mHandler = new Handler(){
#Override
public void handleMessage(Message msg)
{
if(msg.what==MESSAGE_DOWNLOAD)
{
#SuppressWarnings("unchecked")
Token token = (Token)msg.obj;
Log.i(TAG, "Got a request for Url:"+requestMap.get(token));
handleRequest(token);
}
}
};
}
public void handleRequest(final Token token)
{
try
{
final String url = requestMap.get(token);
if(url == null) return;
byte[] bitmapBytes = new FlickrFetchr().getUrlBytes(url);
final Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);
Log.i(TAG, "Bitmap Created");
mResponseHandler.post(new Runnable(){
public void run()
{
if(requestMap.get(token)!=url) return;
requestMap.remove(token);
mListener.onThumbnailDownloaded(token, bitmap);
}
});
}
catch(IOException ioe)
{
Log.e(TAG, "Error Downloading Image"+ioe);
}
}
public void queueThumbnail(Token token, String url)
{
Log.i(TAG, "Got an URL: "+url);
requestMap.put(token, url);
mHandler.obtainMessage(MESSAGE_DOWNLOAD, token).sendToTarget();
//some other class calls this function
//here the target is not set, but I see the request is handled well
//how is this possible? getTarget() is not set anywhere is here
}
just look at here https://android.googlesource.com/platform/frameworks/base.git/+/6083d81ce4d67ec632962270fda64ebb9db0d5b1/core/java/android/os/Message.java, and you will know everything, btw if you are extending HandlerThread you are probably on the wrong path
I'm trying implement server code of Server-Sent Events in a generic way that any Object of my application could send a message to client, so I've decided implement a specific Servlet just for SSE. The initial test codes worked like a charm, but wasn't flexible enought to send messages from different parts of my application. So I've rewrite the code in a way that all objects that has a reference to Servlet object could send a message to the clients:
public class PushServlet extends HttpServlet {
private Thread threadServlet;
private boolean processando=true;
private MensagemSSEBean mensagem;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
threadServlet=Thread.currentThread();
response.setContentType("text/event-stream; charset=utf-8");
while (processando){
if(!pausarThread())
break;
enviarMensagemParaOCliente(response.getWriter());
}
enviarMensagemDeFechamento(response.getWriter());
}
private void enviarMensagemParaOCliente(PrintWriter saida) {
ConversorMensagemSSE conversor = new ConversorMensagemSSE();
saida.print(conversor.converter(mensagem));
saida.flush();
}
private synchronized void enviarMensagemDeFechamento(PrintWriter saida) {
mensagem.setMensagem("#FECHAR_CONEXAO#");
enviarMensagemParaOCliente(saida);
saida.close();
}
public synchronized void enviarMensagem(MensagemSSEBean mensagem) throws IOException {
this.mensagem=mensagem;
threadServlet.notifyAll();
}
public synchronized void finalizar(){
processando=false;
}
private boolean pausarThread() {
try {
threadServlet.wait();
return true;
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
}
As you can see, I pause the Servlet Thread until something call "enviarMensagem". I didn't tested this code, basically cause I don't know how I can get this Servlet object. Could someone explain me how could I get this Servlet object from any Object?? Another important question, is this the ideal approach for this kind of problem??
Finally I implemented it in a generic way. The servlet class now send keep-alive every ten seconds or the messages in a shared queue:
public class PushServlet extends HttpServlet {
private boolean processing = true;
private HttpServletResponse response;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.response = response;
configureAndStart();
while (processing) {
try {
sendMessages();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void configureAndStart() throws IOException {
processing = true;
response.setContentType("text/event-stream; charset=utf-8");
sendMessage(new SSEMessageBean(SSEEventType.START));
}
private void sendMessages() throws IOException, InterruptedException {
SSEMessageBean message = MessageQueueController.getInstance().getNextMessage();
while (message != null) {
sendMessage(message);
message = MessageQueueController.getInstance().getNextMessage();
if (message.getEventType() != SSEEventType.END)
return;
}
Thread.sleep(10000);
sendMessage(new SSEMessageBean(SSEEventType.KEEP_ALIVE));
}
public void sendMessage(SSEMessageBean message) throws IOException {
SSEMessageConverter converter = new SSEMessageConverter();
PrintWriter out = response.getWriter();
out.print(converter.convert(message));
out.flush();
if (message.getEventType() == SSEEventType.END) {
processing = false;
out.close();
}
}
}
The objects that want send events to clients simply write in shared queue.
How can I retrieve a file from the following method:
public void getJson(String pathToFile) {
String userUrl = DOMAIN_URL+pathToFile;
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(userUrl));
JSONArray outerJsonArray;
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
try {
JSONValue jsonValue = JSONParser.parse(response.getText());
JSONArray jsonArray = jsonValue.isArray();
if (jsonArray != null) {
} else {
throw new JSONException();
}
} catch (JSONException e) {
}
} else {
}
}
});
} catch (RequestException e) {
}
}
Now it is just void. I should retriwe the jsonArray variable
You simply can't.
The request is asynchronous, so your method has to be asynchronous (non-blocking) too. You can pass something like an AsyncCallback (to reuse an existing interface) to your getJson method, and have your RequestCallback call it... back, with the JSONArray.
Technically speaking, that would be possible, but that's a design choice in GWT to not allowing blocking AJAX requests.
Embrace asynchrony!
Just change the declaration to
public JSONArray getJson(String pathToFile) {
After the line
JSONArray jsonArray = jsonValue.isArray();
you can add
return jsonArray;
Now you have to be careful. Obviously, you have some error checking conditions in case the array is null or an error occurs during reading. It is up to you to design how to handle them: if the array is null, should you throw an exception or return the null value? If there is an error reading, should you throw an exception, print an error, or return a null value? These are considerations that your external interface will dictate.