Whenever I am calling the API with endPoint /user/block using retrofit, The retrofit calling the API with root Url of the BASE_URL instead of full BASE_URL.
Like if my BASE_URL is.
BASE_URL = "http://111.111.111.11/SocialApi/public/";
Then the API call should be go on BASE_URL+endPoint, But the Api call is going on root of base Url,
http://111.111.111.11/user/block
So getting 404 Not Found response.
What actually I am doing wrong here?
My singleton class, ApiClient.java.
package com.socialcodia.famblah.api;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.socialcodia.famblah.SocialCodia;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ApiClient {
private static final String BASE_URL = "http://111.111.111.11/SocialApiFriendsSystemVideoThumb/public/";
public static final String HEADER_CACHE_CONTROL = "Cache-Control";
public static final String HEADER_PRAGMA = "Pragma";
private static final String TAG = "ServiceGenerator";
private static ApiClient mInstance;
private Retrofit retrofit;
public static final long CACHE_SIZE = 5 * 1024 * 1024;
private ApiClient()
{
Gson gson = new GsonBuilder()
.setLenient()
.create();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
private static OkHttpClient okHttpClient(){
return new OkHttpClient.Builder()
.cache(cache())
.addInterceptor(httpLoggingInterceptor())
.addNetworkInterceptor(networkInterceptor())
.addInterceptor(offlineInterceptor())
.build();
}
private static Cache cache()
{
return new Cache(new File(SocialCodia.getInstance().getCacheDir(),"socialcodia"),CACHE_SIZE);
}
private static HttpLoggingInterceptor httpLoggingInterceptor()
{
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
#Override
public void log(String message) {
Log.d("mufazmi",message);
}
});
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return httpLoggingInterceptor;
}
private static Interceptor networkInterceptor()
{
return new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response response =chain.proceed(chain.request());
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(20, TimeUnit.SECONDS)
.build();
return response.newBuilder()
.removeHeader(HEADER_PRAGMA)
.removeHeader(HEADER_CACHE_CONTROL)
.header(HEADER_CACHE_CONTROL,cacheControl.toString())
.build();
}
};
}
public static Interceptor offlineInterceptor()
{
return new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!SocialCodia.isNetworkOk())
{
CacheControl cacheControl = new CacheControl.Builder()
.maxStale(7,TimeUnit.DAYS)
.build();
request = request.newBuilder()
.removeHeader(HEADER_PRAGMA)
.removeHeader(HEADER_CACHE_CONTROL)
.cacheControl(cacheControl)
.build();
}
return chain.proceed(request);
}
};
}
public static synchronized ApiClient getInstance()
{
if (mInstance == null)
{
mInstance = new ApiClient();
}
return mInstance;
}
public Api getApi()
{
return retrofit.create(Api.class);
}
}
My API interface.
package com.socialcodia.famblah.api;
import com.socialcodia.famblah.pojo.ResponseDefault;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.Header;
import retrofit2.http.POST;
import static com.socialcodia.famblah.storage.Constants.USER_TOKEN;
import static com.socialcodia.famblah.storage.Constants.USER_ID;
public interface Api
{
#FormUrlEncoded
#POST("/user/block")
Call<ResponseDefault> doBlock(
#Header(USER_TOKEN) String token,
#Field(USER_ID) int userId
);
#FormUrlEncoded
#POST("acceptFriendRequest")
Call<ResponseDefault> acceptFriendRequest(
#Header(USER_TOKEN) String token,
#Field(USER_ID) int userId
);
}
Method to call api from ProfileActivity
private void doBlock()
{
Call<ResponseDefault> call = ApiClient.getInstance().getApi().doBlock(token,hisUserId);
call.enqueue(new Callback<ResponseDefault>() {
#Override
public void onResponse(Call<ResponseDefault> call, Response<ResponseDefault> response) {
if (response.isSuccessful())
{
ResponseDefault responseDefault = response.body();
Toast.makeText(ProfileActivity.this, responseDefault.getMessage(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ResponseDefault> call, Throwable t) {
Toast.makeText(ProfileActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
t.printStackTrace();
}
});
}
But when I am calling the acceptFriendRequest() method it's working. means it calling the API.
Method to accept friend request.
private void acceptFriendRequest()
{
if (Utils.isNetworkAvailable(getApplicationContext()))
{
btnAcceptFriendRequest.setEnabled(false);
Call<ResponseDefault> call = ApiClient.getInstance().getApi().acceptFriendRequest(token,hisUserId);
call.enqueue(new Callback<ResponseDefault>() {
#Override
public void onResponse(Call<ResponseDefault> call, Response<ResponseDefault> response) {
if (response.isSuccessful())
{
ResponseDefault responseDefault = response.body();
if (!responseDefault.getError())
{
btnAcceptFriendRequest.setEnabled(true);
btnRejectFriendRequest.setVisibility(View.GONE);
btnAcceptFriendRequest.setVisibility(View.GONE);
btnUnFriend.setVisibility(View.VISIBLE);
}
else
{
btnAcceptFriendRequest.setEnabled(true);
Toast.makeText(ProfileActivity.this, responseDefault.getMessage(), Toast.LENGTH_SHORT).show();
}
}
else
{
btnAcceptFriendRequest.setEnabled(true);
Toast.makeText(ProfileActivity.this, R.string.SNR, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ResponseDefault> call, Throwable t) {
btnAcceptFriendRequest.setEnabled(true);
t.printStackTrace();
}
});
}
}
I have solve this by removing the slash from endPoint /user/block
#FormUrlEncoded
#POST("user/block")
Call<ResponseDefault> doBlock(
#Header(USER_TOKEN) String token,
#Field(USER_ID) int userId
);
Related
I'm using msl4j to interact with microsoft products, e.g. emails, calendars. When I call the user informations (without parameters) this will works fine. But, when I try to read messages from the inbox, the call ended with error 404 ("code":"ResourceNotFound","message":"Resource could not be discovered."). I don't know why. The API Permissions seems correct.
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import com.microsoft.aad.msal4j.ClientCredentialFactory;
import com.microsoft.aad.msal4j.ClientCredentialParameters;
import com.microsoft.aad.msal4j.ConfidentialClientApplication;
import com.microsoft.aad.msal4j.DeviceCode;
import com.microsoft.aad.msal4j.DeviceCodeFlowParameters;
import com.microsoft.aad.msal4j.IAccount;
import com.microsoft.aad.msal4j.IAuthenticationResult;
import com.microsoft.aad.msal4j.IClientCredential;
import com.microsoft.aad.msal4j.MsalException;
import com.microsoft.aad.msal4j.OnBehalfOfParameters;
import com.microsoft.aad.msal4j.PublicClientApplication;
import com.microsoft.aad.msal4j.SilentParameters;
import com.microsoft.aad.msal4j.UserAssertion;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class AppMSAL4J {
private static String userId;
private static String authority;
private static String clientId;
private static String clientSecret;
private static String tenantId;
private static Set<String> scopes;
public static void main(String args[]) throws Exception {
setUpSampleData();
try {
IAuthenticationResult result = acquireToken();
OkHttpClient client = new OkHttpClient().newBuilder().build();
MediaType mediaType = MediaType.parse("application/json");
String bodyString = "";
RequestBody body = RequestBody.create(bodyString, mediaType);
String baseUrl = "https://graph.microsoft.com/v1.0/users/" + userId;
String parameters = "";
// parameters = "/mailfolders('Inbox')/messages";
// parameters = "/messages";
Request request = new Request.Builder()
.url(baseUrl + parameters)
.method("GET", null)
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + result.accessToken())
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static IAuthenticationResult acquireToken() throws Exception {
IClientCredential credential = ClientCredentialFactory.createFromSecret(clientSecret);
ConfidentialClientApplication cca = ConfidentialClientApplication
.builder(clientId, credential)
.authority(authority)
.build();
ClientCredentialParameters parameters = ClientCredentialParameters
.builder(scopes)
.build();
return cca.acquireToken(parameters).join();
}
private static void setUpSampleData() {
userId = "b0f***";
tenantId = "fc2***";
authority = "https://login.microsoftonline.com/" + tenantId;
clientId = "b1a***";
clientSecret = "KJ***";
scopes = Collections.singleton("https://graph.microsoft.com/.default");
}
}
I try to make a second request in the HttpAsyncClient callback. But the second request is on wait state.
Example code:
package com.example.http;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.util.EntityUtils;
import java.util.concurrent.Future;
public class AsyncClientHttpExample {
public static void main(String[] args) {
CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
httpClient.start();
final HttpGet request1 = new HttpGet("http://httpbin.org/ip");
httpClient.execute(request1, new FutureCallback<HttpResponse>() {
#Override
public void completed(HttpResponse result) {
try {
System.out.println(EntityUtils.toString(result.getEntity()));
final HttpGet anotherRequest = new HttpGet("http://httpbin.org/headers");
Future<HttpResponse> future1 = httpClient.execute(anotherRequest, null);
HttpResponse anotherResponse = future1.get(); //the code get hand up here.
System.out.println("response 1 " + anotherResponse);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Override
public void failed(Exception ex) {
System.out.println(ex);
}
#Override
public void cancelled() {
}
});
}
}
I don't quite understand why the second request got hand up in the anotherResponse. I thought the second request is waiting for some lock that has already captured by request 1. But I haven't figure that out.
I face a problem to get Json data into my application. On get action. I have solve the problem for POST. We have a ssl certificate but seems for get and post the way is little different. I can't figure out. So if people can give me an help here. I will appreciate.
package com.example.administrator.superclass.Utils;
import android.app.ProgressDialog;
import android.content.Context;
import android.net.ConnectivityManager;
import android.os.Looper;
import android.util.Log;
import com.example.administrator.superclass.MyApp;
import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class Okhttp_Util {
public static String Ok_Get(Context context,String url, HashMap<String, String> hashMap) {
String data = "";
// OkHttpClient okHttpClient = new OkHttpClient.Builder()
// .connectTimeout(10, TimeUnit.SECONDS)
// .readTimeout(10,TimeUnit.SECONDS)
// .build();
OkHttpClient okHttpClient= MyApp.handleSSLHandshake();
FormBody.Builder builder = new FormBody.Builder();
for (String key : hashMap.keySet()) {
builder.add(key, hashMap.get(key));
}
builder.build();
RequestBody requestBody = builder.build();
Request request = new Request.Builder().url(url).build();
try {
Response response = okHttpClient.newCall(request).execute();
data = response.body().string();
} catch (IOException e) {
if(e instanceof SocketTimeoutException){//判断超时异常
Looper.prepare();
if (ProgressDialog_Util.isshow){
ProgressDialog_Util.Dialog_dismiss();
}
Toast_util.Toast_show(context,"连接超时!请更换网络后重试!");
Log.e("geterr1: ",e.toString() );
Looper.loop();
}
if(e instanceof ConnectException){//判断连接异常,我这里是报Failed to connect to 10.7.5.144
Looper.prepare();
if (ProgressDialog_Util.isshow){
ProgressDialog_Util.Dialog_dismiss();
}
Toast_util.Toast_show(context,e.toString());
Log.e( "geterr2: ",e.toString() );
Looper.loop();
}
}
return data;
}
public static String Ok_Post(Context context,String url, HashMap<String, String> hashMap) {
String data = "";
// OkHttpClient okHttpClient = new OkHttpClient.Builder()
// .connectTimeout(10, TimeUnit.SECONDS)
// .readTimeout(10,TimeUnit.SECONDS)
// .build();
OkHttpClient okHttpClient= MyApp.handleSSLHandshake();
FormBody.Builder builder = new FormBody.Builder();
for (String key : hashMap.keySet()) {
builder.add(key, hashMap.get(key));
}
builder.build();
RequestBody requestBody = builder.build();
Request request = new Request.Builder().post(requestBody).url(url).build();
try {
Response response = okHttpClient.newCall(request).execute();
data = response.body().string();
} catch (IOException e) {
if(e instanceof SocketTimeoutException){//判断超时异常
Looper.prepare();
if (ProgressDialog_Util.isshow){
ProgressDialog_Util.Dialog_dismiss();
}
Toast_util.Toast_show(context,"连接超时!");
Log.e("posterr1: ",e.toString() );
Looper.loop();
}
if(e instanceof ConnectException){//判断连接异常,我这里是报Failed to connect to 10.7.5.144
Looper.prepare();
if (ProgressDialog_Util.isshow){
ProgressDialog_Util.Dialog_dismiss();
}
Toast_util.Toast_show(context,e.toString());
Log.e( "posterr2: ",e.toString() );
Looper.loop();
}
}
return data;
}
}
From the compilation i get an error :
enter image description here
The error indicates that you are calling your get request without passing a HashMap.
My suggestion would be to either pass an empty HashMap if you have some URLs that require a body. Else remove it entirely:
public static String Ok_Get(Context context,String url) {
String data = "";
OkHttpClient okHttpClient= MyApp.handleSSLHandshake();
FormBody.Builder builder = new FormBody.Builder();
builder.build();
Request request = new Request.Builder().url(url).build();
If you still need it, when you call it make sure you include the HashMap:
Ok_Get(context, "your/url/string/here", Collections.<String, String>emptyMap())
I'm trying to write an Http Server using Apache Mina.
According to Mina's architecture, there should be 2 filters for this task, one for Http Request Passing and another for processing the request and generating the response. So using the Mina example codes, I came up with the following code, that has an acceptor, logging filter, Http filter, and a filter for processing request.
Initiation of the server runs correctly, but the request does not come to DummyHttpSever filter. I tried to debug, but could not find the issue. What is going wrong here?
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.api.AbstractIoFilter;
import org.apache.mina.api.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filterchain.ReadFilterChainController;
import org.apache.mina.http.DateUtil;
import org.apache.mina.http.HttpDecoderState;
import org.apache.mina.http.HttpServerDecoder;
import org.apache.mina.http.HttpServerEncoder;
import org.apache.mina.http.api.DefaultHttpResponse;
import org.apache.mina.http.api.HttpContentChunk;
import org.apache.mina.http.api.HttpEndOfContent;
import org.apache.mina.http.api.HttpMethod;
import org.apache.mina.http.api.HttpPdu;
import org.apache.mina.http.api.HttpRequest;
import org.apache.mina.http.api.HttpStatus;
import org.apache.mina.http.api.HttpVersion;
import org.apache.mina.transport.nio.NioTcpServer;
public class HttpTest {
public static void main(String[] args) throws Exception {
NioTcpServer httpServer = new NioTcpServer();
httpServer.setReuseAddress(true);
httpServer.setFilters(new ProtocolCodecFilter<HttpPdu, ByteBuffer, Void, HttpDecoderState>(new HttpServerEncoder(),
new HttpServerDecoder()), new LoggingFilter("DECODED"), new DummyHttpSever());
httpServer.getSessionConfig().setTcpNoDelay(true);
httpServer.bind(new InetSocketAddress(8080));
// run for 20 seconds
Thread.sleep(2000000000);
httpServer.unbind();
}
private static class DummyHttpSever extends AbstractIoFilter {
private HttpRequest incomingRequest;
private List<ByteBuffer> body;
#Override
public void messageReceived(IoSession session, Object message, ReadFilterChainController controller) {
if (message instanceof HttpRequest) {
System.out.println("This shit is working");
incomingRequest = (HttpRequest) message;
body = new ArrayList<ByteBuffer>();
// check if this request is going to be followed by and HTTP body or not
if (incomingRequest.getMethod() != HttpMethod.POST && incomingRequest.getMethod() != HttpMethod.PUT) {
sendResponse(session, incomingRequest);
} else {
}
} else if (message instanceof ByteBuffer) {
body.add((ByteBuffer) message);
} else if (message instanceof HttpEndOfContent) {
// we received all the post content, send the crap back
sendResponse(session, incomingRequest);
}
}
public void sendResponse(IoSession session, HttpRequest request) {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Server", "Apache MINA Dummy test server/0.0.");
headers.put("Date", DateUtil.getCurrentAsString());
headers.put("Connection", "Close");
String strContent = "Hello ! we reply to request !";
ByteBuffer content = ByteBuffer.wrap(strContent.getBytes());
// compute content len
headers.put("Content-Length", String.valueOf(content.remaining()));
session.write(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SUCCESS_OK, headers));
session.write(new HttpContentChunk(content));
session.write(new HttpEndOfContent());
session.close(false);
}
}
}
Also, following are dependencies I am using.
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-http</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-coap</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>LATEST</version>
</dependency>
This is a simple Http web server, which you can modify according to your need. This example is a modification to the example lightweight component of Apache Mina examples.
Main.java
import java.net.InetSocketAddress;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.asyncweb.common.codec.HttpCodecFactory;
import org.apache.asyncweb.examples.lightweight.HttpProtocolHandler;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class Main {
public static void main(String[] args) throws Exception {
SocketAcceptor acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new HttpCodecFactory()));
acceptor.setReuseAddress(true);
acceptor.getSessionConfig().setReuseAddress(true);
acceptor.getSessionConfig().setReceiveBufferSize(1024);
acceptor.getSessionConfig().setSendBufferSize(1024);
acceptor.getSessionConfig().setTcpNoDelay(true);
acceptor.getSessionConfig().setSoLinger(-1);
acceptor.setBacklog(10240);
acceptor.setHandler(new HttpProtocolHandler());
acceptor.bind(new InetSocketAddress(9012));
}
}
HttpProtocalHandler.java
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.future.WriteFuture;
import org.apache.asyncweb.common.HttpRequest;
import org.apache.asyncweb.common.HttpResponseStatus;
import org.apache.asyncweb.common.MutableHttpResponse;
import org.apache.asyncweb.common.DefaultHttpResponse;
import org.apache.asyncweb.common.HttpHeaderConstants;
public class HttpProtocolHandler implements IoHandler {
private static final int CONTENT_PADDING = 0; // 101
private final Map<Integer, IoBuffer> buffers = new ConcurrentHashMap<Integer, IoBuffer>();
private final Timer timer;
public HttpProtocolHandler() {
timer = new Timer(true);
}
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
if (!(cause instanceof IOException)) {
cause.printStackTrace();
}
session.close();
}
public Dictionary extractParameters(Map hashParameters){
Dictionary parameters = new Hashtable();
Iterator it = hashParameters.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
parameters.put(pair.getKey(), ((ArrayList) pair.getValue()).get(0) );
// it.remove(); // avoids a ConcurrentModificationException
}
return parameters;
}
public void messageReceived(IoSession session, Object message)
throws Exception {
HttpRequest req = (HttpRequest) message;
String path = req.getRequestUri().getPath(); //path: /echo
String end_point = path;
Dictionary parameters = this.extractParameters(req.getParameters());
String response = "";
/* switch (end_point) {
case "/io":
response= new IOHandler().handleRequest(parameters);
break;
case "/cpu":
response= new CPUHandler().handleRequest(parameters);
break;
case "/db":
response= new DBHandler().handleRequest(parameters);
break;
case "/memory":
response= new MemoryHandler().handleRequest(parameters);
break;
default:
response = "No end point found";
} */
response = "No end point found";
MutableHttpResponse res;
// if (path.startsWith("/size/")) {
// doDataResponse(session, req);
// } else if (path.startsWith("/delay/")) {
// doAsynchronousDelayedResponse(session, req);
// } else if (path.startsWith("/adelay/")) {
// doAsynchronousDelayedResponse(session, req);
// } else {
res = new DefaultHttpResponse();
IoBuffer bb = IoBuffer.allocate(1024);
bb.setAutoExpand(true);
bb.putString(response.toString(), Charset.forName("UTF-8").newEncoder());
bb.flip();
res.setContent(bb);
// res.setHeader("Pragma", "no-cache");
// res.setHeader("Cache-Control", "no-cache");
res.setStatus(HttpResponseStatus.OK);
WriteFuture future = session.write(res);
if (!HttpHeaderConstants.VALUE_KEEP_ALIVE.equalsIgnoreCase(
res.getHeader( HttpHeaderConstants.KEY_CONNECTION))) {
future.addListener(IoFutureListener.CLOSE);
}
}
private void writeResponse(IoSession session, HttpRequest req,
MutableHttpResponse res) {
res.normalize(req);
WriteFuture future = session.write(res);
if (!HttpHeaderConstants.VALUE_KEEP_ALIVE.equalsIgnoreCase(
res.getHeader( HttpHeaderConstants.KEY_CONNECTION))) {
future.addListener(IoFutureListener.CLOSE);
}
}
private void doDataResponse(IoSession session, HttpRequest req) {
String path = req.getRequestUri().getPath();
int size = Integer.parseInt(path.substring(path.lastIndexOf('/') + 1))
+ CONTENT_PADDING;
MutableHttpResponse res = new DefaultHttpResponse();
res.setStatus(HttpResponseStatus.OK);
res.setHeader("ETag", "W/\"" + size + "-1164091960000\"");
res.setHeader("Last-Modified", "Tue, 31 Nov 2006 06:52:40 GMT");
IoBuffer buf = buffers.get(size);
if (buf == null) {
buf = IoBuffer.allocate(size);
buffers.put(size, buf);
}
res.setContent(buf.duplicate());
writeResponse(session, req, res);
}
private void doAsynchronousDelayedResponse(final IoSession session,
final HttpRequest req) {
String path = req.getRequestUri().getPath();
int delay = Integer.parseInt(path.substring(path.lastIndexOf('/') + 1));
final MutableHttpResponse res = new DefaultHttpResponse();
res.setStatus(HttpResponseStatus.OK);
res.setHeader("ETag", "W/\"0-1164091960000\"");
res.setHeader("Last-Modified", "Tue, 31 Nov 2006 06:52:40 GMT");
timer.schedule(new TimerTask() {
#Override
public void run() {
writeResponse(session, req, res);
}
}, delay);
}
public void messageSent(IoSession session, Object message) throws Exception {
}
public void sessionClosed(IoSession session) throws Exception {
}
public void sessionCreated(IoSession session) throws Exception {
}
public void sessionIdle(IoSession session, IdleStatus status)
throws Exception {
session.close();
}
public void sessionOpened(IoSession session) throws Exception {
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
}
}
We have JAX RS implementation which needs to send back JSON output. But the response size is huge. And the client expects the same synchronously.
Hence I tried to use StreamingOutput... but the client is not really getting the data in chunks.
Below is sample snippet:
Server Side
streamingOutput = new StreamingOutput() {
#Override
public void write(OutputStream out) throws IOException, WebApplicationException {
JsonGenerator jsonGenerator = mapper.getFactory().createGenerator(out);
jsonGenerator.writeStartArray();
for(int i=0; i < 10; i++) {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("Response_State", "Response State - " + i);
jsonGenerator.writeStringField("Response_Report", "Response Report - " + i);
jsonGenerator.writeStringField("Error_details", "Error Details - " + i);
jsonGenerator.writeEndObject();;
jsonGenerator.flush();
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
jsonGenerator.writeEndArray();
jsonGenerator.close();
}
};
return Response.status(200).entity(streamingOutput).build();
Client
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost("http://localhost:8080/AccessData/FetchReport");
post.setHeader("Content-type", "application/json");
ResponseHandler<HttpResponse> responseHandler = new BasicResponseHandler();
StringEntity entity = new StringEntity(jsonRequest); //jsonRequest is request string
post.setEntity(entity);
HttpResponse response = client.execute(post);
BufferedReader buffReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
JsonParser jsonParser = new JsonFactory().createParser(buffReader);
while(jsonParser.nextToken() != JsonToken.END_OBJECT) {
System.out.println(jsonParser.getCurrentName() + ":" + jsonParser.getCurrentValue());
}
String output;
while((output = buffReader.readLine()) != null) {
System.out.println(output);
}
In the server side code, I am putting sleep call just to simulate a gap between chunks of data. What I need is that the client should receive chunks of data as and when it is thrown back by the server.
But here the client gets the response in entirety always.
Any possible solution?
Thanks in advance.
It looks like the client side is not implemented correctly: reading the array of the objects using the parser.
Also, I would like to recommend reading and writing a data transfer object instead of low level field-by-field reading and writing.
For the sake of completeness, here is a complete draft example that uses: Jersey 2.25.1, Jetty 9.2.14.v20151106.
Common
ResponseData class
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ResponseData {
private final String responseState;
private final String responseReport;
private final String errorDetails;
#JsonCreator
public ResponseData(
#JsonProperty("Response_State") final String responseState,
#JsonProperty("Response_Report") final String responseReport,
#JsonProperty("Error_details") final String errorDetails) {
this.responseState = responseState;
this.responseReport = responseReport;
this.errorDetails = errorDetails;
}
public String getResponseState() {
return this.responseState;
}
public String getResponseReport() {
return this.responseReport;
}
public String getErrorDetails() {
return this.errorDetails;
}
#Override
public String toString() {
return String.format(
"ResponseData: responseState: %s; responseReport: %s; errorDetails: %s",
this.responseState,
this.responseReport,
this.errorDetails
);
}
}
Service
ServerProgram class
import java.net.URI;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
public class ServerProgram {
public static void main(final String[] args) {
final URI uri = URI.create("http://localhost:8080/");
final ResourceConfig resourceConfig = new ResourceConfig(TestResource.class);
resourceConfig.register(JacksonFeature.class);
JettyHttpContainerFactory.createServer(uri, resourceConfig);
}
}
TestResource class
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.OutputStream;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
#Path("/")
public class TestResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getData() {
final StreamingOutput streamingOutput = new JsonStreamingOutput();
return Response.status(200).entity(streamingOutput).build();
}
private static class JsonStreamingOutput implements StreamingOutput {
#Override
public void write(final OutputStream outputStream) throws IOException, WebApplicationException {
final ObjectMapper objectMapper = new ObjectMapper();
final JsonFactory jsonFactory = objectMapper.getFactory();
try (final JsonGenerator jsonGenerator = jsonFactory.createGenerator(outputStream)) {
jsonGenerator.writeStartArray();
for (int i = 0; i < 10; i++) {
final ResponseData responseData = new ResponseData(
"Response State - " + i,
"Response Report - " + i,
"Error Details - " + i
);
jsonGenerator.writeObject(responseData);
jsonGenerator.flush();
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
jsonGenerator.writeEndArray();
}
}
}
}
Client
ClientProgram class
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import org.glassfish.jersey.client.ClientProperties;
public class ClientProgram {
public static void main(final String[] args) throws IOException {
Client client = null;
try {
client = ClientBuilder.newClient();
client.property(ClientProperties.READ_TIMEOUT, 10000);
try (final InputStream inputStream = client
.target("http://localhost:8080/")
.request(MediaType.APPLICATION_JSON)
.get(InputStream.class);
final BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {
processStream(bufferedInputStream);
}
} finally {
if (client != null) {
client.close();
}
}
}
private static void processStream(final InputStream inputStream) throws IOException {
final ObjectMapper objectMapper = new ObjectMapper();
final JsonFactory jsonFactory = objectMapper.getFactory();
try (final JsonParser jsonParser = jsonFactory.createParser(inputStream)) {
final JsonToken arrayToken = jsonParser.nextToken();
if (arrayToken == null) {
// TODO: Return or throw exception.
return;
}
if (!JsonToken.START_ARRAY.equals(arrayToken)) {
// TODO: Return or throw exception.
return;
}
// Iterate through the objects of the array.
while (JsonToken.START_OBJECT.equals(jsonParser.nextToken())) {
final ResponseData responseData = jsonParser.readValueAs(ResponseData.class);
System.out.println(responseData);
}
}
}
}
Hope this helps.