Why OutputStreamWriter doesn't write data? - java

I'm very new to android programming and I have a problem with OutputStreamWriter. Now i'm working on simple test appication to send a POST requests to a server. There is a PHP application on the server side, which is designed to write data in a txt file.
When i run my android app it goes through the code and the commands in the "finally" block are performed. The server really writes in the txt file, but it puts empty data.
I've tried also with GET method and tried to check REQUEST array. But no data are sent.
If i delete from my code OutputStreamWriter I obtain the same picture, so it doesn't work at all.
I also tried with using encoding, the same result.
I have done through similar questions:
OutputStreamWriter not writing -
writing to file and problem was with its creating;
Android, Java: HTTP POST Request
- here and a few other questions is used httpClient which is depricated now.
HttpUrlConnection getOutputStream have plroblem, HttpUrlConnection getOutputStream have plroblem - here networking at main thread, but mine is run on the another one;
Android POST request not working, Java HttpURLConnection OutputStreamWriter is empty - is proposed to use reader to receive input stream. I've tried this solution, but the result was the same (no data sent)
My android version 6.0.1.
What is the problem may be in?
package com.victoria.requester;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.io.*;
import java.net.*;
import android.widget.TextView;
import java.io.IOException;
import java.net.URL;
import java.net.HttpURLConnection;
public class MainActivity extends AppCompatActivity {
public final static String EXTRA_MESSAGE = "EXTRA_MESSAGE";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
thread.start();
}
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
String url = "http://192.168.56.226:90/wfile.php";
String f_name = "123";
HttpURLConnection httpCon = null;
TextView textView = findViewById(R.id.textView);
textView.setText("OK1!");
try {
textView.setText("OK2!");
URL urlObj = new URL(url);
httpCon = (HttpURLConnection) urlObj.openConnection();
httpCon.setDoInput(true);
httpCon.setDoOutput(true);
//httpCon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
httpCon.setRequestProperty("Content-Type", "text/html");
httpCon.setRequestMethod("POST");
String parameters = "f_name"+f_name;
//String parameters = URLEncoder.encode("f_name", "UTF-8") + "=" + URLEncoder.encode("123", "UTF-8");
httpCon.getResponseCode();
OutputStreamWriter writer = new OutputStreamWriter(httpCon.getOutputStream());
writer.write(parameters);
writer.close();
} catch (MalformedURLException e) {
textView.setText("bad URL!");
} catch (IOException e) {
textView.setText("network error!");
} finally {
httpCon.disconnect();
textView.setText("All done");
}
}
});
}

So, I've finally solved my problem, which actually was complex.
First of all, thank you, #Stephen C.
When I moved getResponseCode AFTER getOutputStream() my server begun to receive requests.
It's important that without calling getResponseCode the data weren't sent.
But the second trouble was with string:
String parameters = "f_name" + f_name;
As I lost "=" the name of the element in the POST array was 'f_name123' and value was empty))) That's why i couldn't pick the data up from $_POST["f_name"].
Also I'd like to notice that textview doesn't work only if accessing within the connection. After disconnected you can use textview.
Thank to all for help.
The next code works for me now:
package com.victoria.requester;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.io.*;
import java.net.*;
import android.widget.TextView;
import java.io.IOException;
import java.net.URL;
import java.net.HttpURLConnection;
public class MainActivity extends AppCompatActivity {
public final static String EXTRA_MESSAGE = "EXTRA_MESSAGE";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
thread.start();
}
Thread thread;
{
thread = new Thread(new Runnable() {
#Override
public void run() {
String url = "http://192.168.56.226:90/wfile.php";
String f_name = "123";
HttpURLConnection httpCon = null;
TextView textView = findViewById(R.id.textView);
try {
URL urlObj = new URL(url);
httpCon = (HttpURLConnection) urlObj.openConnection();
httpCon.setDoOutput(true);
httpCon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
httpCon.setRequestMethod("POST");
String parameters = "f_name=" + f_name;
OutputStreamWriter writer = new
OutputStreamWriter(httpCon.getOutputStream());
writer.write(parameters);
writer.flush();
writer.close();
httpCon.getResponseCode();
} catch (MalformedURLException e) {
textView.setText("bad URL!");
} catch (IOException e) {
textView.setText("network error!");
} finally {
httpCon.disconnect();
textView.setText("All done");
}
}
});
}
}

The problem is that you are calling httpCon.getOutputStream() and writing the request data after you have called httpCon.getResponseCode().
The correct order is:
Call getConnection() to get the connection object for the URL
In any order:
Set the request method
Set any request properties
Call setDoOutput(true) since you intend to use the output stream.
Call getOutputStream()
Write the data.
Close the stream.
Get the response code.
What you are currently doing will throw an exception when you call getOutputStream. The remote server can only send you a response after it has read the request data. When you call getResponseCode() this tells the client-side stack to indicate to the server that there is no more request data.
In addition, you should not call setDoInput(true) if you don't intend to read data from the connection in some circumstances. At the very least it is redundant.

Related

Java - Using HttpURLConnection to make POST request and send image to server

I'm working on a team software project that involves designing a client for a server-based AI called SeeFood. You can send it a picture, and it will tell you whether or not the picture has food in it. We currently have a python script deployed to the server that accepts Http POST requests and calls the AI with an image that it is given. You can access that at 34.236.92.140.
The challenge I'm facing right now is getting my Java client to be able to send an image to the server, have it analyzed, and get a response back. I've been trying different things, including the Apache HttpComponents library, but I'm constantly getting this response code from the server when I run the code:
400 BAD REQUEST
Server: Apache/2.4.27 (Amazon) PHP/5.6.30 mod_wsgi/3.5 Python/2.7.12
Connection: close
Content-Length: 192
Date: Fri, 17 Nov 2017 16:11:28 GMT
Content-Type: text/html; charset=UTF-8
Judging by research done on HTTP code 400, the server doesn't like how I've formatted the POST request. Does anyone have experience with HTTP servers and sending images via POST? Again, you can try out the server side application at 34.236.92.140. I'll also include the Java client and Python server code.
Java Client (relevant code under the exportImages and readResultsToString methods):
package javaapplication12;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.*;
import static javafx.application.Application.launch;
import javafx.event.*;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.*;
public class UserInterface extends Application {
private List<File> _images;
/**
* #param args the command line arguments
*/
public static void main (String[] args) {
System.setProperty("java.net.preferIPv4Stack" , "true");
launch (args);
}
#Override
public void start (Stage primaryStage) {
final FileChooser fc=new FileChooser ();
primaryStage.setTitle ("SeeFood AI User Interface");
Button imageButton=new Button ("Import Images");
Button exportButton=new Button ("Send Images to SeeFood");
//When image button is pressed, a FileChooser should load up and add all selected images to a list
imageButton.setOnAction ((ActionEvent event) -> {
_images=fc.showOpenMultipleDialog (primaryStage);
if (_images!=null) {
int i=0;
//loop to verify that all selected images are added
for (File file:_images) {
System.out.println ("image "+i);
i++;
}
}
});
exportButton.setOnAction ((ActionEvent event) -> {
try {
exportImages();
} catch (IOException ex) {
Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
}
});
final GridPane inputGridPane=new GridPane ();
GridPane.setConstraints (imageButton,0,0);
GridPane.setConstraints (exportButton,0,1);
inputGridPane.setHgap (6);
inputGridPane.setVgap (6);
inputGridPane.getChildren ().addAll (imageButton, exportButton);
final Pane rootGroup=new VBox (12);
rootGroup.getChildren ().addAll (inputGridPane);
rootGroup.setPadding (new Insets (12,12,12,12));
primaryStage.setScene (new Scene (rootGroup));
primaryStage.show ();
}
/**
* Sends one or more images to SeeFood via HTTP POST.
* #throws MalformedURLException
* #throws IOException
*/
private void exportImages() throws MalformedURLException, IOException{
//InetAddress host=InetAddress.getByName(_ip);
// System.out.println(InetAddress.getByName(_ip));
URL url=new URL("http://34.236.92.140");
HttpURLConnection con=(HttpURLConnection) url.openConnection();
String output;
con.setRequestMethod("POST");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setRequestProperty("Content-Type", "multipart/form-data");
FileChannel in;
WritableByteChannel out;
con.setDoOutput(true); //this must be set to true in order to work
con.setDoInput(true);
for(File file:_images){
in=new FileInputStream(file).getChannel();
out=Channels.newChannel(con.getOutputStream());
in.transferTo(0, file.length(), out);
StringBuilder builder = new StringBuilder();
builder.append(con.getResponseCode())
.append(" ")
.append(con.getResponseMessage())
.append("\n");
Map<String, List<String>> map = con.getHeaderFields();
for (Map.Entry<String, List<String>> entry : map.entrySet()){
if (entry.getKey() == null)
continue;
builder.append( entry.getKey())
.append(": ");
List<String> headerValues = entry.getValue();
Iterator<String> it = headerValues.iterator();
if (it.hasNext()) {
builder.append(it.next());
while (it.hasNext()) {
builder.append(", ")
.append(it.next());
}
}
builder.append("\n");
}
System.out.println(builder);
//Output the result from SeeFood
//Later on, this result should be stored for each image
output=readResultsToString(con);
if(output!=null){
System.out.println(output);
} else {
System.out.println("There was an error in the connection.");
}
in.close();
out.close();
}
con.disconnect();
}
/**
* Helper method to exportImages(). Should get response from server
* and append contents to string.
* #param con - the active http connection
* #return response from the server
*/
private String readResultsToString(HttpURLConnection con){
String result = null;
StringBuffer sb = new StringBuffer();
InputStream is = null;
try {
is=new BufferedInputStream(con.getInputStream());
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String inputLine="";
while((inputLine=br.readLine())!=null){
sb.append(inputLine);
}
result=sb.toString();
} catch (IOException ex) {
Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if(is!=null){
try {
is.close();
} catch (IOException ex) {
Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
return result;
}
}
Python server:
from flask import Flask, send_from_directory, request
from werkzeug.utils import secure_filename
import argparse
import numpy as np
import tensorflow as tf
from PIL import Image
import sys
app = Flask(__name__)
'''
method for uploading files to the server
via http POST request
'''
#app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
f.save(secure_filename(f.filename))
print f.filename
score = ai_call(f.filename)
#save file in location based on score
return score
return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
'''
'''
method for returning files from the server based on filename
'''
#app.route('/download/<file_name>')
def get_file(file_name):
return app.send_static_file(file_name)
'''
index page
needs to be motifed to return default images
'''
#app.route('/')
def index():
find_food
return 'Hello World'
"""
A script to ask SeeFood if it sees food in the image at
path specified by the command line argument.
"""
def ai_call(system_arg):
#parser = argparse.ArgumentParser(description="Ask SeeFood if there is
food in the image provided.")
#parser.add_argument('image_path', help="The full path to an image file stored on disk.")
#args = parser.parse_args()
# The script assumes the args are perfect, this will crash and burn otherwise.
###### Initialization code - we only need to run this once and keep in memory.
sess = tf.Session()
saver = tf.train.import_meta_graph('saved_model/model_epoch5.ckpt.meta')
saver.restore(sess, tf.train.latest_checkpoint('saved_model/'))
graph = tf.get_default_graph()
x_input = graph.get_tensor_by_name('Input_xn/Placeholder:0')
keep_prob = graph.get_tensor_by_name('Placeholder:0')
class_scores = graph.get_tensor_by_name("fc8/fc8:0")
######
# Work in RGBA space (A=alpha) since png's come in as RGBA, jpeg come in as RGB
# so convert everything to RGBA and then to RGB.
#image_path = args.image_path
image_path = system_arg
image = Image.open(image_path).convert('RGB')
image = image.resize((227, 227), Image.BILINEAR)
img_tensor = [np.asarray(image, dtype=np.float32)]
print 'looking for food in '+ image_path
#Run the image in the model.
scores = sess.run(class_scores, {x_input: img_tensor, keep_prob: 1.})
print scores
# if np.argmax = 0; then the first class_score was higher, e.g., the model sees food.
# if np.argmax = 1; then the second class_score was higher, e.g., the model does not see food.
if np.argmax(scores) == 1:
print "No food here... :disappointed: "
else:
print "Oh yes... I see food! :D"
return str(scores)
if __name__ == '__main__':
app.debug = True
app.run()
Any help you can offer is appreciated. Thank you in advance.
I had a similar problem. I fixed it by -
String url = "http://127.0.0.1:8080/";
// 2. create obj for the URL class
URL obj = new URL(url);
// 3. open connection on the url
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type","image/jpeg");
con.setDoInput(true);
con.setDoOutput(true);
OutputStream out = con.getOutputStream();
DataOutputStream image = new DataOutputStream(out);
Path path = Paths.get("jpeg.jpg");
byte[] fileContents = Files.readAllBytes(path);
image.write(fileContents, 0, fileContents.length);

Azure Web Job Upload using java client

History for context:
I am trying to run a web job from an HTTP Client. The file is a ZIP file . and contains a java class and bat file to run that java class. This runs okay when i do from POSTMAN. But when i use HTTP client, i get the following error always " '---i-NPsGbTVUpaP0CeJxMQVrHoDHvaxo3' is not recognized as an internal or external command" - Please help – Jagaran yesterday
#Jagaran if it only happen from some clients, it is likely unrelated. Please ask a new question – David Ebbo 21 hours ago
No any HTTP Client i am using in java, it is the same. it works in CURL or loading from web console. My sample code below – Jagaran 2 hours ago
No any HTTP Client i am using in java, it is the same. it works in CURL or loading from web console.
Do you have any sample Java based HTTP Client where I can publish Azure Web Job? I have tried all Java REST clients.
May be i am doing something wrong. The error I get in Azure console is '---i-NPsGbTVUpaP0CeJxMQVrHoDHvaxo3' is not recognized as an internal or external command, [08/25/2017 09:30:22 > e7f683: ERR ] operable program or batch file.o
I feel Content type = applciation /zip is not happening correctly when using java. Please help us.
Sample Code:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.http.entity.ContentType;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
/**
* #author jagaran.das
*
*/
public class AIPHTTPClient {
/**
* #param args
* #throws IOException
*/
#SuppressWarnings({ "unused", "rawtypes" })
public static void main(String[] args) throws IOException {
try {
URI uri = new AIPHTTPClient().getURI();
HttpResponse<InputStream> jsonResponse = Unirest.put("https://<URL>/api/triggeredwebjobs/TestJOb")
.basicAuth("$AzureWebJobTestBRMS", "XXXXX")
.header("content-disposition","attachement; filename=acvbgth.bat")
.field("file", new FileInputStream(new File(uri))
,ContentType.create("content-type: application/zip"),"AzureWebJob.zip").asBinary();
System.out.println(jsonResponse.getStatusText());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public InputStream readZip() {
ZipFile zipFile = null;
ZipEntry zipEntry = zipFile.getEntry("run.bat");
InputStream stream = null;
/* try {
zipFile = new ZipFile("/Users/jagaran.das/Documents/work/AIP/AzureWebJob.zip");
java.util.Enumeration<? extends ZipEntry> entries = zipFile.entries();
while(entries.hasMoreElements()){
ZipEntry entry = entries.nextElement();
stream = zipFile.getInputStream(entry);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} */
try {
stream = zipFile.getInputStream(zipEntry);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stream;
}
public URI getURI() throws MalformedURLException {
File file = new File("/Users/jagaran.das/Documents/work/AIP/azure-poc/AzureWebJob.zip");
URI fileUri = file.toURI();
System.out.println("URI:" + fileUri);
URL fileUrl = file.toURI().toURL();
System.out.println("URL:" + fileUrl);
URL fileUrlWithoutSpecialCharacterHandling = file.toURL();
System.out.println("URL (no special character handling):" + fileUrlWithoutSpecialCharacterHandling);
return fileUri;
}
}
I've been a little too harsh in my answer before really trying stuff out. Apologies. I've now tried out your snippet and looks like you're hitting an issue with Unirest - probably this one.
My advice would be to just move to Apache's HTTP library.
Here's a working sample:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import java.io.File;
public class App
{
public static void main( String[] args )
{
File sourceZipFile = new File("webjob.zip");
String kuduApiUrl = "https://yoursitename.scm.azurewebsites.net/api/zip/site/wwwroot/app_data/jobs/triggered/job988/";
HttpEntity httpEntity = EntityBuilder.create()
.setFile(sourceZipFile)
.build();
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
"$yoursitename", "SiteLevelPasSw0rD"
);
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create()
.setDefaultCredentialsProvider(provider)
.build();
HttpPut putRequest = new HttpPut(kuduApiUrl);
putRequest.setEntity(httpEntity);
// Kudu's Zip API expects application/zip
putRequest.setHeader("Content-type", "application/zip");
try {
HttpResponse response = client.execute(putRequest);
int statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
String resBody = EntityUtils.toString(entity, "UTF-8");
System.out.println(statusCode);
System.out.println(resBody);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
That's sending Content-Type: application/zip and the raw zip contents in the body (no multipart horse manure). I've probably over-engineered the sample.. but it is what it is.
The upload is successful and the WebJob published:
Glad for you that you have solved the issue and I try to provide a workaround for your reference.
Deploy WebJob to azure , in addition to using REST API, you can also use the FTP way. Of course, the premise is that you need to know the directory uploaded by webjob via KUDU.
I offer you the snippet of code below via FTP4J libiary:
import java.io.File;
import it.sauronsoftware.ftp4j.FTPClient;
public class UploadFileByFTP {
private static String hostName = <your host name>;
private static String userName = <user name>;
private static String password = <password>;
public static void main(String[] args) {
try {
// create client
FTPClient client = new FTPClient();
// connect host
client.connect(hostName);
// log in
client.login(userName, password);
// print address
System.out.println(client);
// change directory
client.changeDirectory("/site/wwwroot/App_Data/jobs/continuous");
// current directory
String dir = client.currentDirectory();
System.out.println(dir);
File file = new File("D:/test.zip");
client.upload(file);
} catch (Exception e) {
e.printStackTrace();
}
}
}
You can follow this tutorial to configure your parameters.

POST parameter not present

I'm a bit new to using API's and I've been trying to use a few for a while now but for some reason I always received a connect error with every implementation I used. I finally found a working POST here but I keep getting {"success":false,"error":"Required POST parameter 'value1' not present."}
Here's the code that I have:
package org.apache.http.examples;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
public class APINew7 {
public static void main(String[] args) {
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(
"https://website.com");
StringEntity input = new StringEntity("{\"value1\":\"123\",\"value2\":\"456\"}");
input.setContentType("application/json");
postRequest.setEntity(input);
HttpResponse response = httpClient.execute(postRequest);
BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
httpClient.getConnectionManager().shutdown();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I'm fairly sure the problem lies here however I'm not sure what's wrong with it:
StringEntity input = new StringEntity("{\"value1\":\"123\",\"value2\":\"456\"}");
I've seen a few different methods of passing the data through but this implementation is the only one that's successfully run. So to sum it up, this does actually run but the parameters are not being spotted.
I appreciate any help, thank you.
Edit:
I may have found what the problem is, but I don't really know a way around it. One of the parameters being sent through is a semi colon. I have to send this through, no way around it. How would I go about sending a semi colon through? Example: "abc;123"
Well I managed to figure it out. Sending a semicolon with the method I used wasn't working but for whoever might have the same problem, using LinkedHashMap to create an object and just using variable.put("parameter", "value") works out.
Thanks for the suggestion #cody123

Android Application that connects to remote server

I am trying to build an Android App on Platform 2.2 Froyo. The app is supposed to connect to a remote server, fetch data from it and display to user in a different language.
So my question - What technologies I need to learn so that I can
build the above app.
Note - I have already installed the Android platform and have built simple apps like Hello, world. I know Java. Also I am using Eclipse.
Thank you for your answers. No rude comment please...
//--------------Code for connecting to web using HTTP protocol-----------------//
package in.androidbook.Networking;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends Activity
{
ImageView img;
/* This is for making asynchronous calls to ensure that connection to server will not return until data is received */
private class BackgroundTask extends AsyncTask<String, Void, Bitmap>
{
protected Bitmap doInBackground(String...url)
{
Bitmap bitmap = DownloadImage(url[0]);
return bitmap;
}
protected void onPostExecute(Bitmap bitmap)
{
ImageView img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(bitmap);
}
}
// Code for making HTTP connection
private InputStream OpenHttpConnection(String urlString) throws IOException
{
InputStream in = null;
int response = -1;
URL url = new URL(urlString);//We take an object of class URL
URLConnection conn = url.openConnection(); //Create a connection object and open the connection
if(!(conn instanceof HttpURLConnection)) throw new IOException("Not an Http connection");
try
{
HttpURLConnection httpConn = (HttpURLConnection) conn; //httpConn object is assigned the value of conn. Typecasting is done to avoid conflict.
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if(response == HttpURLConnection.HTTP_OK)
in = httpConn.getInputStream();
}
catch (Exception ex)
{
throw new IOException("Error connecting");
}
return in;
}
//------------------------------------------ OpenHttpConnection method completed----------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------------------------------------------------------------//
//-------------------------------Method to download an image--------------------------------------------------------------------------------------//
private Bitmap DownloadImage(String URL)
{
Bitmap bitmap = null;
InputStream in = null;
try
{
in = OpenHttpConnection(URL);
bitmap = BitmapFactory.decodeStream(in);
in.close();
}
catch(IOException e1)
{
Toast.makeText(this, e1.getLocalizedMessage(), Toast.LENGTH_LONG).show();
//Toast displays a short msg to user. this refers to current object.
e1.printStackTrace();
}
return bitmap;
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Bitmap bitmap = DownloadImage("http://i.zdnet.com/blogs/3-29-androids.jpg");
img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(bitmap);
}
}
UPDATED (based on comment) : As we are talking about the client side, I confirm my answer. If the site is not yours, the first thing you need to do if check how/if it allows for some kind of communication via API, and in what kind of format (XML and JSON being the most used). With this information, it should be pretty easy. Take a look of the Android example using the Google Map or Twitter, you should find some.
Well, it depends what do you mean exactly : are you asking for the skills needed on the client side (the app) - in the idea that the server is already built, or will be by someone else, or the skills needed for the server ?
In the former case, I would advice to communicate with REST API and JSON. Take a look at apache HTTPGet, HTTPClient and HTTPResponse class and org.json (all are included in Android). If you want to test with them, use some public APIs (so you do not have to worry about the server), such as Google Map API (which is simple and free to use under some limits).
In the latter case, I'm with ColWinters : if you know java, use it there also, with Tomcat as a server and a basic Servlet. You'll find examples aplenty on the Internet.
Look up these technologies,
Apache Tomcat - Java Server Pages (server processing)
MySQL (storage of data)
and thats it. Also make sure to do the request in a seperate thread like an Async Task from an activity.
If you know java, I would suggest servlet as service hosted on server which reads data from mysql or anydatabase and contructs as json. in your android app make http using in buit httpclient to remote servlet and parse json response. So. Servlets,Httpclient,Json covers most if your app is native to phone app.

Why does this HTTP servlet behave inconsistently?

An intranet site has a search form which uses AJAX to call a servlet on a different domain for search suggestions.
This works in Internet Explorer with the intranet domain being a "trusted site" and with cross-domain requests enabled for trusted sites, but doesn't work in Firefox.
I have tried to work around the problem by creating a servlet on the intranet server, so there's a JS call to my servlet on the same domain, then my servlet calls the suggestions servlet on the other domain. The cross-domain call is server-side, so it should work regardless of browser settings.
The AJAX call and my servlet's call to the other servlet both use a HTTP POST request with arguments in the URL and empty request-content.
The reason I'm sticking with POST requests is that the JS code is all in files on the search server, which I can't modify, and that code uses POST requests.
I've tried calling the customer's existing suggestions servlet with a GET request, and it produces a 404 error.
The problem is that the result is inconsistent.
I've used System.out.println calls to show the full URL and size of the result on the server log.
The output first seemed to change depending on the calling browser and/or website, but now seems to change even between sessions of the same browser.
E.g. entering "g" in the search box, I got this output from the first few tries on the Development environment using Firefox:
Search suggestion URL: http://searchdev.companyname.com.au/suggest?q=g&max=10&site=All&client=ie&access=p&format=rich
Search suggestion result length: 64
Initial tries with Firefox on the Test environment (different intranet server but same search server) produced a result length of 0 for the same search URL.
Initial tries with Internet Explorer produced a result length of 0 in both environments.
Then I tried searching for different letters, and found that "t" produced a result in IE when "g" hadn't.
After closing the browsers and leaving it for a while, I tried again and got different results.
E.g. Using Firefox and trying "g" in the Development environment now produces no result when it was previously producing one.
The inconsistency makes me think something is wrong with my servlet code, which is shown below. What could be causing the problem?
I think the search suggestions are being provided by a Google Search Appliance, and the JS files on the search server all seem to have come from Google.
The actual AJAX call is this line in one file:
XH_XmlHttpPOST(xmlhttp, url, '', handler);
The XH_XmlHttpPOST function is as follows in another file:
function XH_XmlHttpPOST(xmlHttp, url, data, handler) {
xmlHttp.open("POST", url, true);
xmlHttp.onreadystatechange = handler;
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("Content-Length",
/** #type {string} */ (data.length));
XH_XmlHttpSend(xmlHttp, data);
}
Here is my servlet code:
package com.companyname.theme;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class suggest extends HttpServlet {
Properties props=null;
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String result = "";
String args = req.getQueryString();
String baseURL = props.getProperty("searchFormBaseURL");
String urlStr = baseURL + "/suggest?" + args;
System.out.println("Search suggestion URL: " + urlStr);
try {
int avail, rCount;
int totalCount = 0;
byte[] ba = null;
byte[] bCopy;
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write("".getBytes());
os.close();
InputStream is = conn.getInputStream();
while ((avail = is.available()) > 0) {
if (ba == null) ba = new byte[avail];
else if (totalCount + avail > ba.length) {
// Resize ba if there's more data available.
bCopy = new byte[totalCount + avail];
System.arraycopy(ba, 0, bCopy, 0, totalCount);
ba = bCopy;
bCopy = null;
}
rCount = is.read(ba, totalCount, avail);
if (rCount < 0) break;
totalCount += rCount;
}
is.close();
conn.disconnect();
result = (ba == null ? "" : new String(ba));
System.out.println("Search suggestion result length: " + Integer.toString(result.length()));
} catch(MalformedURLException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
PrintWriter pw = resp.getWriter();
pw.print(result);
}
#Override
public void init() throws ServletException {
super.init();
InputStream stream = this.getClass().getResourceAsStream("/WEB-INF/lib/endeavour.properties");
props = new Properties();
try {
props.load(stream);
stream.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
Solution: don't rely on InputStream.available().
The JavaDoc for that method says it always returns 0.
HttpURLConnection.getInputStream() actually returns a HttpInputStream, in which available() seems to work but apparently sometimes returns 0 when there is more data.
I changed my read loop to not use available() at all, and now it consistently returns the expected results.
The working servlet is below.
package com.integral.ie.theme;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class suggest extends HttpServlet implements
javax.servlet.Servlet {
Properties props=null;
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//super.doPost(req, resp);
final int maxRead=200;
String result="";
String args=req.getQueryString();
String baseURL=props.getProperty("searchFormBaseURL");
String urlStr=baseURL+"/suggest?"+args;
//System.out.println("Search suggestion URL: "+urlStr);
try {
int rCount=0;
int totalCount=0;
int baLen=maxRead;
byte[] ba=null;
byte[] bCopy;
URL url=new URL(urlStr);
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
// Setting these properties may be unnecessary - just did it
// because the GSA javascript does it.
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length","0");
InputStream is=conn.getInputStream();
ba=new byte[baLen];
while (rCount>=0) {
try {
rCount=is.read(ba,totalCount,baLen-totalCount);
if (rCount>0) {
totalCount+=rCount;
if (totalCount>=baLen) {
baLen+=maxRead;
bCopy=new byte[baLen];
System.arraycopy(ba,0,bCopy,0,totalCount);
ba=bCopy;
bCopy=null;
}
}
} catch(IOException e) {
// IOException while reading - allow the method to return
// anything we've read so far.
}
}
is.close();
conn.disconnect();
result=(totalCount==0?"":new String(ba,0,totalCount));
//System.out.println("Search suggestion result length: "
//+Integer.toString(result.length()));
} catch(MalformedURLException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
PrintWriter pw=resp.getWriter();
pw.print(result);
}
#Override
public void init() throws ServletException {
super.init();
InputStream stream=this.getClass().getResourceAsStream("/WEB-INF/lib/endeavour.properties");
props=new Properties();
try {
props.load(stream);
stream.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
Start with a unit test. Servlets are pretty straightforward to unit test and HttpUnit has worked for us.
Debugging Servlet code in a browser and with println calls will cost more time in the long run and it's difficult for someone on SO to digest all of that information to help you.
Also, consider using a JavaScript framework such as JQuery for your AJAX calls. In my opinion there's little reason to touch an xmlHttp object directly now that frameworks will hide that for you.

Categories

Resources