Proxy setting not working in Jersey ClientConfig - java

I'm trying to setup a proxy in my java code using Jersey client but the proxy is not getting set. I went through the Jersey documentation and have implemented the code in the described way. I'm new to Jersey so not sure where I'm going wrong.
Below is the code.
#Override
#CircuitBreaker(name = "documentServiceCreateDocument", ignore = { NullPointerException.class, ArrayIndexOutOfBoundsException.class })
public String createDocument(String name, DocumentType docType, List<SourceData> sourceDatas) {
ClientConfig clientConfig = new ClientConfig().register(MultiPartFeature.class)
.register(ClientTransactionIdFilter.class)
.property(ClientProperties.READ_TIMEOUT, "30000")
.property(ClientProperties.CONNECT_TIMEOUT, "30000")
.property(ClientProperties.PROXY_URI, properties.getProxyUrl);
Client client = ClientBuilder.newClient(clientConfig);
Builder builder = resourceTarget.request().header("Authorization", ***);
List<Cookie> iamCookies = ***
Response response = null;
try {
response = builder.post(body);
} catch (Exception e){
if(response != null) {
logger.info("Response code : " + response.getStatus());
logger.info("Response : " + response.toString());
}
e.printStackTrace();
throw new RuntimeException(e);
}
String docLocation = response.getLocation().toString();
logger.debug("Created Document Service document with location=" + docLocation);
return docLocation;
}

After a long duration, I finally figured out the fix. We need to use the ApacheConnectorProvider in order for the proxy to work.
Add the ApacheConnectorProvider to the ClientConfig as shown below:
ClientConfig clientConfig = new ClientConfig().register(MultiPartFeature.class)
.register(ClientTransactionIdFilter.class)
.property(ClientProperties.READ_TIMEOUT, "30000")
.property(ClientProperties.CONNECT_TIMEOUT, "30000")
.connectorProvider(new ApacheConnectorProvider())
.property(ClientProperties.PROXY_URI, properties.getProxyUrl);
Don't forget to add the jersey-apache-connector dependency to your pom file(if you are using maven). Refer to the below link for jersey-apache-connector dependency details:
https://mvnrepository.com/artifact/org.glassfish.jersey.connectors/jersey-apache-connector/2.6

Related

Passing authorities and user principal from rest client to server spring boot

I have to call one secured endpoint from rest client and at the controller side it require the authorities and user principal information to be sent from client.
String endpoint="http://localhost:8096/polygons/34";
// endpoint="https://dop-int.edosdp.ericsson.se/polygon-manager/polygons/34";
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("mahi", "ChangeM6");
headers.setConnection("keep-alive");
HttpEntity<String> httpEntity = new HttpEntity<String>(headers);
ResponseEntity<Long> exchange = restTemplate.exchange(endpoint,HttpMethod.GET, httpEntity, Long.class);
how can send at least one role(ADMIN or GUEST_USER) information from client .
IS there any way I can wrap up all user info in a dummy session and send it to the serer.
Thanks ,
Mahi
No! It's a bad idea for the client to modify any kind of session information including cookies. Only the server should be allowed to do that.
Since your requirement is to check for user role on a specific url, you can set a custom request header and check for it within the controller method itself:
Example code:
#GetMapping("/polygons")
public String getPolygons(HttpServletRequest request) {
String userRole = request.getHeader("user-role");
if(userRole != null && userRole.toLowerCase().equals("admin")) {
System.out.print("Role provided: " + userRole);
// ...
return "some-data";
}
System.out.print("Role not provided!");
return "error";
}
You could also set the user role in the request body for a post request.
public class RequestParams {
private String userRole;
// ...
}
#PostMapping("/polygons")
public String getPolygons(#RequestBody RequestParams requestParams) {
String userRole = requestParams.getUserRole();
if(userRole != null && userRole.toLowerCase().equals("admin")) {
System.out.print("Role provided: " + userRole);
// ...
return "some-data";
}
System.out.print("Role not provided!");
return "error";
}
If your requirement is to check for the user role on multiple urls then you should consider writing a servlet filter.
EDIT:
I think I too faced a similar situation in the past. I ended up using apache's httpclient library instead of resttemplate.
Here's some sample code:
private List<OrganizationDTO> getUserOrgUnits(String loggedInUserId, String token) {
List<OrganizationDTO> userList = new ArrayList<OrganizationDTO>();
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(getUserOrgUnitsApiURL());
try {
// Setting header
httpGet.setHeader("Authorization", "Bearer " + token);
httpGet.setHeader("Content-type", "application/json");
// Setting custom header
httpGet.setHeader(USERID_HEADER_NAME, loggedInUserId);
CloseableHttpResponse response = httpClient.execute(httpGet);
String result = EntityUtils.toString(response.getEntity());
JsonNode node = null;
ObjectMapper mapper = new ObjectMapper();
node = mapper.readTree(result);
Iterable<JsonNode> list = node.path("data");
for (JsonNode jsonNode : list) {
OrganizationDTO dto = mapper.treeToValue(jsonNode, OrganizationDTO.class);
userList.add(dto);
}
} catch (Exception e) {
log.error("getUserOrgUnits: Exception.");
e.printStackTrace();
}
return userList;
}

RestEasy Client giving could not find writer for content-type application/xml type

I am writing a test client for my endpoint, but it is not able to execute the connection giving
EXCEPTION : could not find writer for content-type application/xml type: com.gepower.gees.ifs.goet.porequest.model.CreatePOReq
in the line
ClientResponse<CreatePOResp> clientResponse = client.post(CreatePOResp.class);
From Postman, the endpoint is returning the result fine.
I have tried to add all the RestEasy jars in my project, but it is still giving the same error while
public static CreatePOResp createUpdateALFPO(CreatePOReq req) {
CreatePOResp response = new CreatePOResp();
String operation = "createUpdatePO";
try {
String xmlReq = "";
try {
xmlReq = XmlUtils.marshalXmlToString(req);
System.out.println(operation + " - XML SOAP REQUEST: " + xmlReq);
} catch (Exception xmlex) {
System.out.println(xmlex.getMessage());
}
ClientRequest client = new ClientRequest("http://localhost/ofsrestws/fs/porequest/addpo");
client.body(MediaType.APPLICATION_XML, req);
System.out.println("URI ====" + client.getUri());
ClientResponse<CreatePOResp> clientResponse = client.post(CreatePOResp.class);
ResteasyProviderFactory.getInstance().addBuiltInMessageBodyReader(new JAXBXmlTypeProvider());
if (clientResponse.getStatus() == 200) {
response = clientResponse.getEntity();
System.out.println("web service is OK");
return response;
} else {
System.out.println("an issue has occure during the call of the web service: "
+ clientResponse.getResponseStatus());
// Object resp = clientResponse.getResponseStatus();
return null;
}
} catch (NullPointerException e) {
System.out.println("EXCEPTION : " + e.getMessage());
return null;
} catch (Exception e) {
System.out.println("EXCEPTION : " + e.getMessage());
return null;
} finally {}
}
The stacktrace:
java.lang.RuntimeException: could not find writer for content-type application/xml type: com.gepower.gees.ifs.goet.porequest.model.CreatePOReq
at org.jboss.resteasy.client.ClientRequest.writeRequestBody(ClientRequest.java:409)
at org.jboss.resteasy.client.core.executors.ApacheHttpClientExecutor$ClientRequestEntity.<init>(ApacheHttpClientExecutor.java:117)
at org.jboss.resteasy.client.core.executors.ApacheHttpClientExecutor.loadHttpMethod(ApacheHttpClientExecutor.java:188)
at org.jboss.resteasy.client.core.executors.ApacheHttpClientExecutor.execute(ApacheHttpClientExecutor.java:56)
at org.jboss.resteasy.client.ClientRequest.execute(ClientRequest.java:378)
at org.jboss.resteasy.client.ClientRequest.httpMethod(ClientRequest.java:590)
at org.jboss.resteasy.client.ClientRequest.post(ClientRequest.java:496)
at org.jboss.resteasy.client.ClientRequest.post(ClientRequest.java:501)
at org.tcs.TestJava.createUpdateALFPO(TestJava.java:52)
at org.tcs.TestJava.main(TestJava.java:31)
Please find the list of dependencies
The only thing I can see is that you register the adapter after you make the post request:
ClientResponse<CreatePOResp> clientResponse = client.post(CreatePOResp.class);
ResteasyProviderFactory.getInstance().addBuiltInMessageBodyReader(new JAXBXmlTypeProvider());
Since the exception occurs in the post call, maybe you should try switching the order.
I notice that you are using the deprecated RestEasy client API. Note that the JAX-RS 2.0 client implementation will automatically load all available
Provider classes (through the service loader mechanism). Maybe you should consider using that API instead.

Sendgrid v3: "Substitutions may not be used with dynamic templating"

I am trying to update my API Code from Sendgrid v2, to the actual Sendgrid v3, so my code used to look like this:
public void sendCreatedUserEmail(User user) {
Email from = new Email(FROM);
from.setName(EMAIL_NAME);
String subject = "Hello" + user.getName();
Email to = new Email(user.getEmail());
Content content = new Content("text/html", "Something");
Mail mail = new Mail(from, subject, to, content);
mail.personalization.get(0).addSubstitution("{name1}", user.getName());
mail.personalization.get(0).addSubstitution("{name2}", user.getName());
mail.setTemplateId(USER_TEMPLATE_ID);
SendGrid sg = new SendGrid(SENDGRID_API_KEY);
Request request = new Request();
try {
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
Response response = sg.api(request);
} catch (IOException ex) {
logger.error(ex);
}
}
After some hours of research I changed for v3 to this:
(I separeted everthing for a cleaner view)
public void sendCreatedUserEmail(User user) {
Mail mail = new Mail();
Email from = new Email();
from.setName(EMAIL_NAME);
from.setEmail(FROM);
mail.setFrom(from);
String subject = "Hello, " + user.getName();
mail.setSubject(subject);
Personalization personalization = new Personalization();
Email to = new Email();
to.setEmail(user.getEmail());
to.setName(user.getName());
personalization.addTo(to);
personalization.setSubject(subject);
personalization.addSubstitution("{name2}",user.getName());
personalization.addSubstitution("{name1}",user.getName());
mail.addPersonalization(personalization);
Content content = new Content();
content.setType("text/html");
content.setValue("Something");
mail.addContent(content);
mail.setTemplateId(NEW_USER_TEMPLATE_ID);
SendGrid sg = new SendGrid(SENDGRID_API_KEY);
Request request = new Request();
try {
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
Response response = sg.api(request);
System.out.println(response.getStatusCode());
System.out.println(response.getBody());
System.out.println(response.getHeaders());
} catch (IOException ex) {
logger.error(ex);
}
}
I am getting the following error:
ERROR ROOT - java.io.IOException: Request returned status Code 400Body:{"errors":[{"message":"Substitutions may not be used with dynamic templating","field":"personalizations.0.substitutions","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#message.personalizations.substitutions"}]}
And I really don't know how to proceed! I've been reading the sendgrid documentation but I couldn't get it.
Some details that might help
- Java8 is the language
- MAVEN for dependencies
- IntelliJ for the IDE
Sorry for the possible mistakes, it's my first post and English is not my main language. Thank you!
V3 of the Sendgrid API uses Dynamic Template Data instead of substitutions.
Try this instead of using addSubstitution:
personalization.addDynamicTemplateData("{name2}",user.getName());
personalization.addDynamicTemplateData("{name1}",user.getName());
Sources:
https://github.com/sendgrid/sendgrid-java/blob/9bc569cbdb908dba609ed0d9d2691dff319ce155/src/main/java/com/sendgrid/helpers/mail/objects/Personalization.java
https://sendgrid.com/docs/ui/sending-email/how-to-send-an-email-with-dynamic-transactional-templates/
Try:
personalization.addDynamicTemplateData("name2",user.getName());
personalization.addDynamicTemplateData("name1",user.getName());

Spring web app javax.ws.rs.ProcessingException: HTTP 500 Internal Server Error

I'm having some issues running a web app which is basically a URL shortener.
The server have a functionality that allows to upload a CSV file with a list of URLs to short. The code bellow is a method that takes a CSV file from a queue, it reads the file and shorts the URLs in it. The problem comes when I try to send a post request to on of the controllers in my server. The exception that appears is the following:
javax.ws.rs.ProcessingException: HTTP 500 Internal Server Error
Here is the code of the method I mentioned:
while(true){
QueueObject qo = csvQueue.take();
copyFile(qo.getFile());
File f = new File("temp");
Scanner sc = new Scanner(f);
sc.useDelimiter(",|\\s");
Client client = ClientBuilder.newClient();
while(sc.hasNext()){
String url = sc.next();
ResponseEntity<ShortURL> res = shortener(url, null, null, null, null, null);
if(res!=null && ((res.getStatusCode()).toString()).equals("400")){
String stat = url + " : Failed";
UpdateMessage um = new UpdateMessage(stat, qo.getUser());
Response response = client.target("http://localhost:8080/urlUploads")
.request(MediaType.APPLICATION_JSON)
.post(Entity.entity(um, MediaType.APPLICATION_JSON));
}
else{
String stat = url + " : Success";
UpdateMessage um = new UpdateMessage(stat, qo.getUser());
Response response = client.target("http://localhost:8080/urlUploads")
.request(MediaType.APPLICATION_JSON)
.post(Entity.entity(um, MediaType.APPLICATION_JSON));
}
}
f.delete();
}
As I said, the problem is on this specific request (both are basically the same):
Response response = client.target("http://localhost:8080/urlUploads")
.request(MediaType.APPLICATION_JSON)
.post(Entity.entity(um, MediaType.APPLICATION_JSON));
The controller I'm trying to reach is this one:
#Controller
public class WebSocketController {
private SimpMessagingTemplate template;
private static final Logger logger = LoggerFactory.getLogger(WebSocketController.class);
#Autowired
public WebSocketController(SimpMessagingTemplate template) {
this.template = template;
}
#RequestMapping(value="/urlUploads", method=RequestMethod.POST)
public void greet(UpdateMessage update) {
this.template.convertAndSendToUser(update.getUser(), "/sockets/urlUploads", update.getStatus());
}
}

How to call a RESTful web service from Android?

I have written a REST web service in Netbean IDE using Jersey Framework and Java.
For every request the user needs to provide a username and a password, I know that this authentication is not a best practice (using a curl command like: curl -u username:password -X PUT http://localhsot:8080/user).
Now I want to call a REST web service from an Android Class.
How should I do it?
I have an Android Class which uses DefaultHttpClient and CredentialUsernameAndPassword, but when I run it in Eclipse, sometimes I get a runtime exception or SDK exception.
This is an sample restclient class
public class RestClient
{
public enum RequestMethod
{
GET,
POST
}
public int responseCode=0;
public String message;
public String response;
public void Execute(RequestMethod method,String url,ArrayList<NameValuePair> headers,ArrayList<NameValuePair> params) throws Exception
{
switch (method)
{
case GET:
{
// add parameters
String combinedParams = "";
if (params!=null)
{
combinedParams += "?";
for (NameValuePair p : params)
{
String paramString = p.getName() + "=" + URLEncoder.encode(p.getValue(),"UTF-8");
if (combinedParams.length() > 1)
combinedParams += "&" + paramString;
else
combinedParams += paramString;
}
}
HttpGet request = new HttpGet(url + combinedParams);
// add headers
if (headers!=null)
{
headers=addCommonHeaderField(headers);
for (NameValuePair h : headers)
request.addHeader(h.getName(), h.getValue());
}
executeRequest(request, url);
break;
}
case POST:
{
HttpPost request = new HttpPost(url);
// add headers
if (headers!=null)
{
headers=addCommonHeaderField(headers);
for (NameValuePair h : headers)
request.addHeader(h.getName(), h.getValue());
}
if (params!=null)
request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
executeRequest(request, url);
break;
}
}
}
private ArrayList<NameValuePair> addCommonHeaderField(ArrayList<NameValuePair> _header)
{
_header.add(new BasicNameValuePair("Content-Type","application/x-www-form-urlencoded"));
return _header;
}
private void executeRequest(HttpUriRequest request, String url)
{
HttpClient client = new DefaultHttpClient();
HttpResponse httpResponse;
try
{
httpResponse = client.execute(request);
responseCode = httpResponse.getStatusLine().getStatusCode();
message = httpResponse.getStatusLine().getReasonPhrase();
HttpEntity entity = httpResponse.getEntity();
if (entity != null)
{
InputStream instream = entity.getContent();
response = convertStreamToString(instream);
instream.close();
}
}
catch (Exception e)
{ }
}
private static String convertStreamToString(InputStream is)
{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try
{
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
is.close();
}
catch (IOException e)
{ }
return sb.toString();
}
}
Recently discovered that a third party library - Square Retrofit can do the job very well.
Defining REST endpoint
public interface GitHubService {
#GET("/users/{user}/repos")
List<Repo> listRepos(#Path("user") String user,Callback<List<User>> cb);
}
Getting the concrete service
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.build();
GitHubService service = restAdapter.create(GitHubService.class);
Calling the REST endpoint
List<Repo> repos = service.listRepos("octocat",new Callback<List<User>>() {
#Override
public void failure(final RetrofitError error) {
android.util.Log.i("example", "Error, body: " + error.getBody().toString());
}
#Override
public void success(List<User> users, Response response) {
// Do something with the List of Users object returned
// you may populate your adapter here
}
});
The library handles the json serialization and deserailization for you. You may customize the serialization and deserialization too.
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.registerTypeAdapter(Date.class, new DateTypeAdapter())
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.setConverter(new GsonConverter(gson))
.build();
Stop with whatever you were doing ! :)
Implement the RESTful client as a SERVICE and delegate the intensive network stuff to activity independent component: a SERVICE.
Watch this insightful video
http://www.youtube.com/watch?v=xHXn3Kg2IQE where Virgil Dobjanschi is explaining his approach(es) to this challenge...
Using Spring for Android with RestTemplate
https://spring.io/guides/gs/consuming-rest-android/
// The connection URL
String url = "https://ajax.googleapis.com/ajax/" +
"services/search/web?v=1.0&q={query}";
// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();
// Add the String message converter
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
// Make the HTTP GET request, marshaling the response to a String
String result = restTemplate.getForObject(url, String.class, "Android");
I used OkHttpClient to call restful web service. It's very simple.
OkHttpClient httpClient = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
Response response = httpClient.newCall(request).execute();
String body = response.body().string()
What back-end? If JAVA then you can use REST with Java (JAX-RS) using Jersey.
On the Android side you can use this simple RestClient to work with that REST service.
For JSON <--> Object mapping on both sides (Android, Java back-end) you can use GSON.
Perhaps am late or maybe you've already used it before but there is another one called ksoap and its pretty amazing.. It also includes timeouts and can parse any SOAP based webservice efficiently. I also made a few changes to suit my parsing.. Look it up
Follow the below steps to consume RestFul in android.
Step1
Create a android blank project.
Step2
Need internet access permission. write the below code in AndroidManifest.xml file.
<uses-permission android:name="android.permission.INTERNET">
</uses-permission>
Step3
Need RestFul url which is running in another server or same machine.
Step4
Make a RestFul Client which will extends AsyncTask. See RestFulPost.java.
Step5
Make DTO class for RestFull Request and Response.
RestFulPost.java
package javaant.com.consuming_restful.restclient;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import com.google.gson.Gson;
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;
import org.apache.http.util.EntityUtils;
import java.util.Map;
import javaant.com.consuming_restful.util.Util;
/**
* Created by Nirmal Dhara on 29-10-2015.
*/
public class RestFulPost extends AsyncTask<map, void,="" string=""> {
RestFulResult restFulResult = null;
ProgressDialog Asycdialog;
String msg;
String task;
public RestFulPost(RestFulResult restFulResult, Context context, String msg,String task) {
this.restFulResult = restFulResult;
this.task=task;
this.msg = msg;
Asycdialog = new ProgressDialog(context);
}
#Override
protected String doInBackground(Map... params) {
String responseStr = null;
Object dataMap = null;
HttpPost httpost = new HttpPost(params[0].get("url").toString());
try {
dataMap = (Object) params[0].get("data");
Gson gson = new Gson();
Log.d("data map", "data map------" + gson.toJson(dataMap));
httpost.setEntity(new StringEntity(gson.toJson(dataMap)));
httpost.setHeader("Accept", "application/json");
httpost.setHeader("Content-type", "application/json");
DefaultHttpClient httpclient= Util.getClient();
HttpResponse response = httpclient.execute(httpost);
int statusCode = response.getStatusLine().getStatusCode();
Log.d("resonse code", "----------------" + statusCode);
if (statusCode == 200)
responseStr = EntityUtils.toString(response.getEntity());
if (statusCode == 404) {
responseStr = "{\n" +
"\"status\":\"fail\",\n" +
" \"data\":{\n" +
"\"ValidUser\":\"Service not available\",\n" +
"\"code\":\"404\"\n" +
"}\n" +
"}";
}
} catch (Exception e) {
e.printStackTrace();
}
return responseStr;
}
#Override
protected void onPreExecute() {
Asycdialog.setMessage(msg);
//show dialog
Asycdialog.show();
super.onPreExecute();
}
#Override
protected void onPostExecute(String s) {
Asycdialog.dismiss();
restFulResult.onResfulResponse(s,task);
}
}
For more details and complete code please visit http://javaant.com/consume-a-restful-webservice-in-android/#.VwzbipN96Hs
Here is my Library That I have created for simple Webservice Calling,
You can use this by adding a one line gradle dependency -
compile 'com.scantity.ScHttpLibrary:ScHttpLibrary:1.0.0'
Here is the demonstration of using.
https://github.com/vishalchhodwani1992/httpLibrary

Categories