Use google volley to receive streaming data - android-volley

I am trying to use volley to receive streaming strings. The api works well with curl command or HttpURLConnection:
curl http://streamingurl.com // fake url
string-piece1 string-piece2 string-piece3...
After you make such a request, the server just keep feeding you string pieces about every second.
However when I try it with Volley it doesn't work:
queue = Volley.newRequestQueue(context);
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, "http://streamingurl.com",
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.e("Streaming", response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("Streaming", error.toString());
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
I expect to receive a string snippet every second in the console. However I didn't. I just receive a TimeoutError after several second. Is it possible to use Volley to receive the streaming strings?

Related

Spring Boot + grpc logging + correlation id?

I've got a Spring Boot app. Its a standard http rest api. I'm adding a grpc host inside of it to provide a parallel grpc experience. That part is all working fine. One of my requirements is request / response logging.
I've got a ServerInterceptor, a SimpleForwardingServerCall wrapper and a SimpleForwardingServerCallListener wrapper to trap all the places I need to log (success & failure calls).
I need to get the request body from onMessage and the status code from 2 places (one for fail, one for success) and then the elapsed time.
So long question short, I'm not sure how the threading model works in grpc, where can I store this information on a per request basis so by the time I get to onComplete() which has no params, I can access it?
I'm doing something like:
return new xxxServerCallListener<>(next.startCall(new xxxServerCall<>(call), headers), call);
So I assume a new xxxServerCallListener and xxxServerCall get created for each request and I can store stuff in there as it moves through the pipeline? Would that be the best place to store?
Yes, construct your own ServerCall.Listener per-RPC and store the information there.
#Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
final Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
// resp could be stored in the call class, but then it would need to be
// a named class which is more boilerplate. AtomicReference is
// convenient.
final AtomicReference<RespT> resp = new AtomicReference<>();
call = new SimpleForwardingServerCall<ReqT, RespT>(call) {
#Override public void sendMessage(RespT message) {
// We assume we're getting immutable protobufs or something similar
// that doesn't mutate. Otherwise we'd need to copy it here.
resp.set(message);
super.sendMessage(message);
}
};
return new SimpleForwardingServerCallListener<ReqT>(next.startCall(call, headers)) {
private ReqT req;
#Override public void onMessage(ReqT message) {
this.req = message;
super.onMessage(message);
}
#Override public void onCancel() {
// No point in using 'resp' as the client probably didn't use it.
// Note that sendMessage() has likely not been called so 'resp' is
// frequently null. If referencing 'resp' here, synchronizing (like
// that provided by AtomicReference) is necessary.
log(req);
super.onCancel();
}
#Override public void onComplete() {
// For properly-behaving callers (those that do not invoke
// call.sendMessage() after call.close()), this actually doesn't
// need to be synchronized as call.close() (and thus any
// sendMessage()) is guaranteed to have been called by this point.
log(req, resp.get());
super.onComplete();
}
};
}

Retrotif2 + RxJava sending POST request failed

I want to send POST request with Retrofit + RxJava, but it is failing and I don't know the reason. In one activity it's working, in another - don't want to work:
private void sendMerchantInfo() {
try {
String advertiserOriginalDeepLink = "https://mywebsite.com/main-1?param1=value1&param2=value2";
String urlGetParams = LinkParser.getUrlGETParams(advertiserOriginalDeepLink);
Map<Object, Object> merchantInfo = LinkParser.parseUrlGetParams(urlGetParams);
String merchantInfoJson = new Gson().toJson(merchantInfo); //{"param1":"value1","param2":"value2"}
String url = "https://api.endpoint.com/v1/system/merchant/process";
userService = this.serviceGenerator.createService(UserService.class, true);
final Observable observable = userService.sendUserInfo(
url, new RetrofitMapBody(merchantInfo))
.doOnNext(new Consumer<ResponseBody>() {
#Override
public void accept(ResponseBody responseBody) throws Exception {
//handle 200 OK.
}
})
.onErrorResumeNext((ObservableSource<? extends ResponseBody>) v ->
Crashlytics.log("Send user info attempt failed."))
.subscribeOn(Schedulers.from(threadExecutor))
.observeOn(postExecutionThread.getScheduler());
addDisposable(observable.subscribe());
}
} catch (Exception exception) {
Crashlytics.log("Send user info attempt failed. " + exception.getMessage());
}
}
I suspect that problem in this part, I am trying to send request in OnCreate() method:
.subscribeOn(Schedulers.from(threadExecutor))
.observeOn(postExecutionThread.getScheduler());
Tried to use this, but no effect:
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
What I am doing wrong? It always call onErrorResumeNext() It's probably something with threads because one time I got exception: networkonmainthreadexception. Please help.
Try using RxJava2 Adapter, it will save you a lot!
Step 1: Retrofit client setup
private Retrofit getRetrofitClient() {
return new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //option 1
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.newThread())) //option 2
.build();
}
Step 2: APIService interface (Example)
#GET("endpoint")
Single<ResponseModel> fetch();
Step 3: Usage
Single<ResponseModel> fetch() {
return getRetrofitClient()
.create(APIService.class)
.fetch();
}
Any non-2xx HTTP response will be wrapped in HttpException from which you can extract the status code, the status message and the full HTTP response.
Any connection errors will be wrapped in IOException
And that is all you need to do to wrap your network call in any RxJava stream.

Request response over HTTP with Spring and activemq

I am building a simple REST api which connects a web server to a back end service, which performs a simple check and sends a response.
So client (over HTTP) -> to Web Server (over ACTIVEMQ/CAMEL)-> to Checking-Service, and back again.
The endpoint for the GET request is "/{id}". I'm trying to make this send a message through queue:ws-out to queue:cs-in and map it all the way back again to the original GET request.
The Checking-Service (cs) code is fine, it simply changes a value in the CheckMessage object to true using jmslistener.
I've searched the web thoroughly for examples, but can't get anything to work. The closest one I found was the following.
This is what I have so far on the Web Server (ws).
RestController
import ...
#RestController
public class RESTController extends Exception{
#Autowired
CamelContext camelContext;
#Autowired
JmsTemplate jmsTemplate;
#GetMapping("/{id}")
public String testCamel(#PathVariable String id) {
//Object used to send out
CheckMessage outMsg = new CheckMessage(id);
//Object used to receive response
CheckMessage inMsg = new CheckMessage(id);
//Sending the message out (working)
jmsTemplate.convertAndSend("ws-out", outMsg);
//Returning the response to the client (need correlation to the out message"
return jmsTemplate.receiveSelectedAndConvert("ws-in", ??);
}
}
Listener on ws
#Service
public class WSListener {
//For receiving the response from Checking-Service
#JmsListener(destination = "ws-in")
public void receiveMessage(CheckMessage response) {
}
}
Thanks!
your receive messages from "ws-in" with 2 consumers jmsTemplate.receiveSelectedAndConvert and WSListener !! message from a queue is consumed by one of the 2.
you send messages to "ws-out" and consume from "ws-in" ?? last queue
is empty and not receive any message, you have to send messages to
it
you need a valid selector to retrieve the message with receiveSelectedAndConvert based on JMSCorrelationID as the example you mntioned or the id received from the rest request but you need to add this id to the message headers like below
this.jmsTemplate.convertAndSend("ws-out", id, new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
TextMessage tm = session.createTextMessage(new CheckMessage(id));
tm.setJMSCorrelationID(id);
return tm;
}
});
return jmsTemplate.receiveSelectedAndConvert("ws-in", "JMSCorrelationID='" + id+ "'");
forward messages from "ws-out" to "ws-in"
#Service
public class WSListener {
//For receiving the response from Checking-Service
#JmsListener(destination = "ws-out")
public void receiveMessage(CheckMessage response) {
jmsTemplate.convertAndSend("ws-in", response);
}
}

Volley doesn't cache post request

I fetch data from server with following method:
public void process(final String url){
this.url=url;
GsonRequest<T> request=new GsonRequest<>(url, responseType, requestData, new Response.Listener<T>() {
#Override
public void onResponse(T response) {
//handle response here
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//handle error here
}
});
request.setRetryPolicy(new DefaultRetryPolicy(
0,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
request.setShouldCache(true);
queue.add(request);
}
Some of the requests fetch signficant amount of data.I'd like Volley to cache data in some cases.However when I do one of these heavy request and then turn network off and then repeat my request Volley throws
java.net.UnknownHostException: Unable to resolve host "...": No address associated with hostname.
Is there something I can do to make Volley cache responses?
The problem was in server code - it didn't allow caching

Asynchronous variation of the service activator EIP?

We have the following Camel route in our application:
from(webServiceUri).routeId("webServiceRoute")
.unmarshal(jaxb)
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
final Message in = exchange.getIn();
final DataRequest body = in.getBody(DataRequest.class);
final DataRequest.Items items = body.getItems();
itemValidator.validate(items.getItem());
getContext().createProducerTemplate().sendBody(importUri, body);
DataResponse response = new DataResponse();
response.setReturnCode(ReturnCode.SUCCESS);
in.setBody(response);
}
})
.marshal(jaxb);
We want the "webServiceRoute" to return the response user as soon as the processor has validated the data and forwarded the message to the "importUri". But right now it seems like the response is not returned to the caller until the "importUri" exchange is completed. So my question is what is the "correct" way to asynchronously forward the received request to another queue? There will not be any reply from the "importUri" exchange (i.e. it should be InOnly).
You can replace .sendBody(importUri, body) by .asyncSendBody(importUri, body).
Nevertheless I find your route looks strange to me, why do you use a processor to forward your message. I would write something like:
DataResponse successResponse = new DataResponse();
response.setReturnCode(ReturnCode.SUCCESS);
from(webServiceUri).routeId("webServiceRoute")
.unmarshal(jaxb)
.bean(WebServiceRouteHelper.class,"validate")
.to(importUri)
.setBody(constant(sucessResponse))
.marshal(jaxb);
class WebServiceRouteHelper {
public DataRequest validate(DataRequest dataRequest) throws Exception {
final DataRequest.Items items = body.getItems();
itemValidator.validate(items.getItem());
return dataRequest;
}
}

Resources