Scenario - upload binary data in the body of a post, handle a response body containing JSON.
How to do the following using Volley?
curl -X POST -H "X-Application-Id: 3KxPB" -H "X-REST-API-Key: jkuI9" -H "Content-Type: audio/3gp" --data-binary '#test.3gp' https://host/1/files/audio
IMO - there is a gap in Volley handling binary POST body types that apache httpclient handles in subclasses of abstracthttpentity. If buffered binary data generated on the phone by camera, microphone, or other binary output sensors needs a mechanism to be wrapped and written to the body of a POST how to do it in volley?
I've looked at PoolingByteArrayOutputStream and would like to do something like fill the buffer and get the PBAOutStrm ,writing to PBAOutStrm from the buffer and then flipping OutStrm to InputStream and then wrap it in the body of a POST request as something like a ByteArrayEntity. I cant see how to do that in volley.
To send binary data you can do something like what I did in this answer How to send a “multipart/form-data” POST in Android with Volley .
I was able to solve this using a Volley GsonRequest:
public class MainActivity extends AppCompatActivity {
String url = "https://arcane-anchorage-34204.herokuapp.com/handleCode";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
JSONObject jsonBody = null;
try {
jsonBody = new JSONObject ("{\"code\":\"NZ4UBUB\"}");
} catch (JSONException e) {
Toast.makeText(getApplicationContext(), "Error e = " + e, Toast.LENGTH_SHORT).show();
}
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
RequestQueue queue = Volley.newRequestQueue(this);
GsonRequest<Routine[]> gsonRequest = new GsonRequest<Routine[]>(Request.Method.POST, url, Routine[].class, headers, new Response.Listener<Routine[]>() {
#Override
public void onResponse(Routine[] routineData) {
TextView serverData = (TextView)findViewById(R.id.serverData);
String complete = "";
String repeat = "";
String hold = "";
String perform = "";
String txtData = "";
for (int i = 0; i < routineData.length; i++) {
complete = (routineData[i].instructions.complete != null) ? "Complete: " + routineData[i].instructions.complete : "";
repeat = (routineData[i].instructions.repeat != null) ? "Repeat: " + routineData[i].instructions.repeat : "";
hold = (routineData[i].instructions.hold != null) ? "Hold: " + routineData[i].instructions.hold : "";
perform = (routineData[i].instructions.perform != null) ? "Perform: " + routineData[i].instructions.perform : "";
txtData += "DESCRIPTION: " + routineData[i].description[0] + ": " + routineData[i].description[1] + ", " + complete + ", " + repeat + ", " + hold + ", " + perform + " ";
}
serverData.setText("Response: " + txtData);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
TextView serverData = (TextView)findViewById(R.id.serverData);
serverData.setText("Response: " + volleyError.toString());
}
}, jsonBody);
queue.add(gsonRequest);
}
public class GsonRequest<T> extends Request<T> {
private final Gson gson = new Gson();
private final Class<T> clazz;
private final Map<String, String> headers;
private final Response.Listener<T> listener;
private JSONObject parameters = null;
/**
* Make a GET request and return a parsed object from JSON.
*
* #param url URL of the request to make
* #param clazz Relevant class object, for Gson's reflection
* #param headers Map of request headers
*/
public GsonRequest(int method, String url, Class<T> clazz, Map<String, String> headers,
Response.Listener<T> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.clazz = clazz;
this.headers = headers;
this.listener = listener;
}
public GsonRequest(int method, String url, Class<T> clazz, Map<String, String> headers,
Response.Listener<T> listener, Response.ErrorListener errorListener, JSONObject parameters) {
this(method, url, clazz, headers, listener, errorListener);
this.parameters = parameters;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
#Override
public String getBodyContentType() {
return "application/json";
}
#Override
public byte[] getBody() throws AuthFailureError {
try {
return parameters.toString().getBytes(getParamsEncoding());
} catch (UnsupportedEncodingException e) {
}
return null;
}
#Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(
response.data, HttpHeaderParser.parseCharset(response.headers));
Log.i("RESPONSE", json);
return Response.success(
gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
}
}
Related
I am trying to make a post request which is supposed to return a json, but for some reason it returns 500 something went wrong.
'''
public void templatRequestPayment(String token, String url, String key, String body)
throws RestClientException, URISyntaxException, IOException {
URI uri = new URI(url);
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", token);
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
headers.set("key", key);
HttpEntity<String> entity = new HttpEntity<String>(body, headers);
RestTemplate template = new RestTemplate(getConverter());
try {
ResponseEntity<JsonNode> res = template.exchange(uri, HttpMethod.POST, entity,
JsonNode.class);
String tok = res.getBody().toString();
System.out.println(tok);
} catch (HttpStatusCodeException e) {
ResponseEntity<String> st =
ResponseEntity.status(e.getStatusCode()).headers(e.getResponseHeaders())
.body(e.getResponseBodyAsString());
System.out.println(st.getHeaders() + "-- /n" + st.getBody());
}
}
protected List<HttpMessageConverter< ?>> getConverter() {
List<HttpMessageConverter< ?>> converters = Lists.newArrayList();
converters.add(new MappingJackson2HttpMessageConverter());
return converters;
}
'''
I have an android app which is making api requests to my server running Spring MVC. The RestController works fine when I make a request from the browser but it responds with 404 when I am making requests from android. Not sure why
Here is code snippet from Android app making requests
public class AsyncFetch extends AsyncTask<Pair<String, String>, String, String> {
public ProgressDialog pdLoading;
private HttpURLConnection conn;
private String urlStr;
private String requestMethod = "GET";
public AsyncFetch(String endpoint, Context ctx)
{
pdLoading = new ProgressDialog(ctx);
Properties reader = PropertiesReader.getInstance().getProperties(ctx, "app.properties");
String host = reader.getProperty("host", "10.0.2.2");
String port = reader.getProperty("port", "8080");
String protocol = reader.getProperty("protocol", "http");
String context = reader.getProperty("context", "");
this.urlStr = protocol+"://"+host+":"+port+context+endpoint;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method will be running on UI thread
pdLoading.setMessage("\tLoading...");
pdLoading.setCancelable(false);
pdLoading.show();
}
#Override
protected String doInBackground(Pair<String, String>... params) {
URL url;
try {
url = new URL(urlStr);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return e.toString();
}
try {
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(READ_TIMEOUT);
conn.setConnectTimeout(CONNECTION_TIMEOUT);
conn.setRequestMethod(requestMethod);
conn.setDoOutput(true);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return e1.toString();
}
try {
int response_code = conn.getResponseCode();
// Check if successful connection made`enter code here`
if (response_code == HttpURLConnection.HTTP_OK) {
// Read data sent from server
InputStream input = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
// Pass data to onPostExecute method
return (result.toString());
} else {
return ("unsuccessful");
}
} catch (IOException e) {
e.printStackTrace();
return e.toString();
} finally {
conn.disconnect();
}
}
Spring MVC Controller
#RestController
public class ApiController {
#RequestMapping(value = "homefeed", method=RequestMethod.GET)
public String homefeed(#RequestParam(value="userId", required = false) Integer id, #RequestParam(value="search", required = false) String search, #RequestParam(value="page", required = false, defaultValue = "0") Integer page) { ... }
}
localhost:8080/api/homefeed -- works
127.0.0.1:8080/api/homefeed -- works
My Public IP:8080/api/homefeed -- does not works
10.0.2.2:8080/api/homefeed -- android emulator to localhost -- does not work
10.0.2.2:8080/Some resource other than the api endpoint -- works
Any help is highly appreciable, have wasted quiet some time in debugging.
I want to get information from the text message received. Information like Body of text sender's phone number etc. I am trying to do it with the code below. I have permissions in the Manifest.
public void onReceive(Context context, Intent intent)
{
//---get the SMS message passed in---
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str = "";
if (bundle != null)
{
//---retrieve the SMS message received---
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for (int i=0; i<msgs.length; i++){
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
str += "SMS from " + msgs[i].getOriginatingAddress();
str += " :";
str += msgs[i].getMessageBody().toString();
str += "n";
}
//---display the new SMS message---
Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
}
}
It works. But not on Marshmallow 6.0.1 API:23. Also, SmsMessage, createFromPdu and getMessageBody all of them are deprecated. I can not find a way to do it in Marshmallow. Please, give me the solution.
BroadcastReceiver smsReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT < 19) {
if(Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())){
Bundle bundle = intent.getExtras(); //---get the SMS message passed in---
SmsMessage[] msgs;
String sender;
if (bundle != null){
//---retrieve the SMS message received---
try{
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for(int i=0; i<msgs.length; i++){
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
sender = msgs[i].getOriginatingAddress();
String messageBody = msgs[i].getMessageBody();
// do things here
}
}
}catch(Exception e){
Log.d("Exception caught",e.getMessage());
}
}
}
}
else{
if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())) {
for (SmsMessage smsMessage : Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
String messageBody = smsMessage.getMessageBody();
String sender = smsMessage.getOriginatingAddress();
// do things here
}
}
}
}
};
Dont forget to register receiver. OnCreate:
IntentFilter intentFilter = new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
intentFilter.setPriority(990);
registerReceiver(smsReceiver, intentFilter);
And also unregister.
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(smsReceiver);
threadTimer.interrupt();
}
How to redirect Glassfish server output into HttpServletResponse.out? I am making servlet in NetBeans.
here is a working example, just expose this as a servlet
public class ReadLogs extends HttpServlet {
private static final String CONTENT_TYPE = "text/html; charset=UTF-8";
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.append("<html>\n<head>\n\n");
out.append("<script>function toBottom()" + "{"
+ "window.scrollTo(0, document.body.scrollHeight);" + "}");
out.append("\n</script>");
out.append("\n</head>\n<body onload=\"toBottom();\">\n<pre>\n");
try {
File file = new File("C:\\pathToServerLogFile");
BufferedReader in = new BufferedReader(new FileReader(file));
StringBuilder sb = new StringBuilder();
while (in.ready()) {
String x = in.readLine();
sb.append(x).append("<br/>");
}
in.close();
out.append("\n</pre>\n</body>\n</html>");
out.close();
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
UPDATE
If you need to print only the last portion of the file use this after line "in.close();"
//print only 1MB Oof data
if(sb.length()>1000000){
out.append(sb.substring(sb.length()-1000000, sb.length()));
}else{
out.append(sb.toString());
}
So.. to print only lines which appeared after invoking script I've made such code:
BufferedReader reader = new BufferedReader(new FileReader("/path/to/server/log/server.log"));
int lines = 0;
while (reader.readLine() != null) {
lines++;
}
reader.close();
BufferedReader reader2 = new BufferedReader(new FileReader("/path/to/server/log/server.log"));
String strLine;
int i = 0;
while (i != lines) {
reader2.readLine();
i++;
}
while ((strLine = reader2.readLine()) != null) {
out.println(stringToHTMLString(strLine));
out.println("<br>");
}
reader2.close();
When servlet starts it counts lines in server log (saves it in variable i), then after clicking on action form it read lines which indexes are higher than i and displays it on html page. I've used function stringToHTMLString which I found somewhere on stackoverflow.
Greets.
I want to know about implementing a "push" chat server, which uses HTTP keepalive headers. I just came to know two technologies such chat servers use - long polling, and push - but I could not get any concepts regarding what happens behind the scenes.
Can anyone please help me ? Any client side / server side code would be appreciated a lot !!
Here is some comet code from the Tomcat Docs (hhttp://tomcat.apache.org/tomcat-7.0-doc/aio.html)
public class ChatServlet
extends HttpServlet implements CometProcessor {
protected ArrayList<HttpServletResponse> connections =
new ArrayList<HttpServletResponse>();
protected MessageSender messageSender = null;
public void init() throws ServletException {
messageSender = new MessageSender();
Thread messageSenderThread =
new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]");
messageSenderThread.setDaemon(true);
messageSenderThread.start();
}
public void destroy() {
connections.clear();
messageSender.stop();
messageSender = null;
}
/**
* Process the given Comet event.
*
* #param event The Comet event that will be processed
* #throws IOException
* #throws ServletException
*/
public void event(CometEvent event)
throws IOException, ServletException {
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
if (event.getEventType() == CometEvent.EventType.BEGIN) {
log("Begin for session: " + request.getSession(true).getId());
PrintWriter writer = response.getWriter();
writer.println("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">");
writer.println("<head><title>JSP Chat</title></head><body bgcolor=\"#FFFFFF\">");
writer.flush();
synchronized(connections) {
connections.add(response);
}
} else if (event.getEventType() == CometEvent.EventType.ERROR) {
log("Error for session: " + request.getSession(true).getId());
synchronized(connections) {
connections.remove(response);
}
event.close();
} else if (event.getEventType() == CometEvent.EventType.END) {
log("End for session: " + request.getSession(true).getId());
synchronized(connections) {
connections.remove(response);
}
PrintWriter writer = response.getWriter();
writer.println("</body></html>");
event.close();
} else if (event.getEventType() == CometEvent.EventType.READ) {
InputStream is = request.getInputStream();
byte[] buf = new byte[512];
do {
int n = is.read(buf); //can throw an IOException
if (n > 0) {
log("Read " + n + " bytes: " + new String(buf, 0, n)
+ " for session: " + request.getSession(true).getId());
} else if (n < 0) {
error(event, request, response);
return;
}
} while (is.available() > 0);
}
}
public class MessageSender implements Runnable {
protected boolean running = true;
protected ArrayList<String> messages = new ArrayList<String>();
public MessageSender() {
}
public void stop() {
running = false;
}
/**
* Add message for sending.
*/
public void send(String user, String message) {
synchronized (messages) {
messages.add("[" + user + "]: " + message);
messages.notify();
}
}
public void run() {
while (running) {
if (messages.size() == 0) {
try {
synchronized (messages) {
messages.wait();
}
} catch (InterruptedException e) {
// Ignore
}
}
synchronized (connections) {
String[] pendingMessages = null;
synchronized (messages) {
pendingMessages = messages.toArray(new String[0]);
messages.clear();
}
// Send any pending message on all the open connections
for (int i = 0; i < connections.size(); i++) {
try {
PrintWriter writer = connections.get(i).getWriter();
for (int j = 0; j < pendingMessages.length; j++) {
writer.println(pendingMessages[j] + "<br>");
}
writer.flush();
} catch (IOException e) {
log("IOExeption sending message", e);
}
}
}
}
}
}
}
There are many specific techniques, generally now known under the name Comet. The Wikipedia article linked there is a pretty good intro.
Also see The Long Polling Technique.