Jax-RS and Xmlhttp Communication - java

I have a REST Server in Java JAX-RS and an HTML page.
I want to send a JSON array, a username, and an accountID from the HTML page through an xmlhttp POST request by making all of them a single big String so I can use the xmthttp.send() method.
The HTML sending code is:
function sendData() {
var req = createRequest();
var postUrl = "rest/hello/treeData";
var dsdata = $("#treeview").data("kendoTreeView").dataSource.data();
var accID = "onthespot";
var username = "alex";
req.open("post", postUrl, true);
req.setRequestHeader("Content-type","text/plain");
req.send("data=" + JSON.stringify(dsdata) + "&username=" + username + "&accID=" + accID);
req.onreadystatechange = function() {
if (req.readyState != 4) {
return;
}
if (req.status != 200) {
alert("Error: " + req.status);
return;
}
alert("Sent Data Status: " + req.responseText);
}
}
And the Server JAX-RS code is:
#Path("/treeData")
#POST
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.TEXT_PLAIN)
public String storeTreeData(
#QueryParam("data") String data,
#QueryParam("username") String username,
#QueryParam("accID") String accID) {
System.out.println("Data= " + data + "\nAccID= " + accID + "\nUsername= " + username);
return "Done";
}
The problem is that all the variables are printed as null..
the storeTreeData function should find the data , username , accID variables through #QueryParam and store them isn't that right?
Anyone know what's the problem here?
PS:The xmlhttp request is initiallized correctly and the connection is made but the parameters are not passed on the server.

What you try to do:
#QueryParam is used to get parameters from the query of the request:
http://example.com/some/path?id=foo&name=bar
In this example id and name can be accessed as #QueryParam.
But you are sending the parameters in the body of your request.
What you should do:
To get the parameters from the body, you should use #FormParam together with application/x-www-form-urlencoded:
#Path("/treeData")
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces(MediaType.TEXT_PLAIN)
public Response storeTreeData(
#FormParam("data") String data,
#FormParam("username") String username,
#FormParam("accID") String accID) {
// Build a text/plain response from the #FormParams.
StringBuilder sb = new StringBuilder();
sb.append("data=").append(data)
.append("; username=").append(username)
.append("; accId=").append(accID);
// Return 200 OK with text/plain response body.
return Response.ok(sb.toString()).build();
}
Edit:
You should also use
req.setRequestHeader("Content-type","application/x-www-form-urlencoded");
in your JavaScript code.

Related

How to get data from query string in Java Spring boot REST

We have a requirement to read data after '?' in service-url in Spring boot REST API.
For example, We exposed a service called sampleService and GET URL for this is
http://www.myservices.com/api/sampleServce
And clients will pass the data as http://www.myservices.com/api/sampleServce?dynamicdata
So we have to read that "dynamicdata" in my sample service and process.
Please let me know the possibilities.
GET: http://localhost:8080/api/foos?id=abc here the query string is id=abc . Now to extract the value of id, you can use the code something like this.
#GetMapping("/api/foos")
#ResponseBody
public String getFoos(#RequestParam String id) {
return "ID: " + id;
}
GET: http://www.myservices.com/api/sampleServce?dynamicdata is incorrect. Either it should be http://www.myservices.com/api/sampleServce/dynamicdata (PathVariable) or http://www.myservices.com/api/sampleServce?title=dynamicdata (RequestParam)
GET: http://www.myservices.com/api/sampleServce/dynamicdata to extract dynamicdata, you can use code something like
#GetMapping("/api/sampleServce/{id}")
#ResponseBody
public String getFooById(#PathVariable String id) {
return "ID: " + id; // here id = "dynamicdata"
}
GET: http://www.myservices.com/api/sampleServce?title=dynamicdata to extract title, you can use code something like
#GetMapping("/api/sampleServce")
#ResponseBody
public String getFoos(#RequestParam String title) {
return "title: " + title; // title="dynamicdata"
}
dynamicdata is path param, it cannot be placed after ?. It should be something like this:
http://www.myservices.com/api/dynamicdata/sampleServce
Check when and how to use query or path parameters
Accept dynamic data through request param:
#GetMapping("/api/sampleServce")
public void test(#RequestParam Map<String, String> dynamicdata) {
System.out.println(dynamicdata.keySet()); //http://localhost:9001/dag-backend/api/sampleServce?test&test11
Optional<String> data = dynamicdata.keySet().stream().findFirst();
String value = data.isPresent() ? data.get() : null;
System.out.println(value); //http://localhost:9001/dag-backend/api/sampleServce?test
}
URLs:
http://www.myservices.com/api/sampleServce?dynamicdata
http://www.myservices.com/api/sampleServce?dynamicdata&12344&1212
http://www.myservices.com/api/sampleServce?$999900&124434&234
You can add an HttpServletRequest object to your mapped method signature:
#RequestMapping("/api/sampleServce")
public Object sampleServce (HttpServletRequest request) {
//print everything after the question mark:
System.out.println("queryString: " + request.getQueryString());
//print key value pairs:
Enumeration<String> params = request.getParameterNames();
while(params.hasMoreElements()){
String paramName = params.nextElement();
String paramValue = request.getParameter(paramName);
System.out.println("name: " + paramName);
System.out.println("value: " + paramValue);
}
return request.getQueryString();
}

How to get the access_token first in Apex Restful service to call GET/POST methods from outside?

I am doing Salesforce trailhead from the link : https://trailhead.salesforce.com/modules/apex_integration_services/units/apex_integration_webservices.
In this tutorial they've use access_token to call the GET request. But they have not guided us how to get the access_token, which is an important steps to call the APEX Rest from outside.
I tied to do something like below its saying me the error:
https://ap5.salesforce.com/services/oauth2/token?client_id="3MVG9d8..z.hDcPJZPIzGJ5UZDuKCOqbH8CCGCPnmwQuRbwLZ_2f.thbqWMX82H7JRGx4
6VYyEkuwzQ9._ww5"&client_secret="1180508865211885204"&username="pXXXXXXXXXXXXXXX.com"&password="AgXXXXXXXX"&grant_type=password
I understood the concept now and thanks for sharing other links.
client_id, client_secret, username, password and grant_type should be sent in a HTTP POST body not in header.
HttpRequest req = new HttpRequest();
req.setMethod('POST');
req.setHeader('Content-Type','application/x-www-form-urlencoded');
req.setEndpoint('https://ap5.salesforce.com/services/oauth2/token');
String CLIENT_ID = 'XXXXXXXXXXXXXXXXXXXXXXXXX';
String CLIENT_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXX';
String USERNAME = 'XXXXXXXXXXXXXX';
String PASSWORD = 'XXXXXXXXXXXXXX';
req.setBody('grant_type=password' + '&client_id='+CLIENT_ID +
'&client_secret='+CLIENT_SECRET + '&username='+USERNAME + '&password='+PASSWORD);
Http http = new Http();
HTTPResponse response = http.send(req);
System.debug('Body ' + response.getBody());
System.debug('Status ' + response.getStatus());
System.debug('Status code ' + response.getStatusCode());
You might need to call api to get the access token.
Here's my code in C# to get the access token
async public static Task GetAccessTokenByUserNamePasswordAuthenticationFlowAsync(string username, string password, string token, string consumerKey, string consumerSecret)
{
HttpClient authClient = new HttpClient();
string sfdcConsumerKey = consumerKey;
string sfdcConsumerSecret = consumerSecret;
string sfdcUserName = username;
string sfdcPassword = password;
string sfdcToken = token;
string loginPassword = sfdcPassword + sfdcToken;
HttpContent content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{"grant_type","password"},
{"client_id",sfdcConsumerKey},
{"client_secret",sfdcConsumerSecret},
{"username",sfdcUserName},
{"password",loginPassword}
}
);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11; //tuanv2t: Salesforce has changed to use TLS 1.1 ->
//tuanv2t: Without, responseString will like this {"error":"unknown_error","error_description":"retry your request"}
HttpResponseMessage message = await authClient.PostAsync("https://login.salesforce.com/services/oauth2/token", content);
string responseString = await message.Content.ReadAsStringAsync();
//JObject obj = JObject.Parse(responseString);
//var oauthToken = (string)obj["access_token"];
//var serviceUrl = (string)obj["instance_url"];
var result = new GetAccessTokenResponse();
result.HttpResponseMessage = message;
//Convert json string into object
var accessTokenAPI = JsonConvert.DeserializeObject<AccessTokenAPI>(responseString);
if (accessTokenAPI != null)
{
result.AccessToken = new AccessTokenModel();
result.AccessToken.AccessToken = accessTokenAPI.access_token;
result.AccessToken.Id = accessTokenAPI.id;
result.AccessToken.InstanceUrl = accessTokenAPI.instance_url;
result.AccessToken.IssuedAt = accessTokenAPI.issued_at;
result.AccessToken.Signature = accessTokenAPI.signature;
result.AccessToken.TokenType = accessTokenAPI.token_type;
}
return result;
}
It's able to download all my source code example here ( include SOAP API as well )
https://bitbucket.org/tuanv2t/salesforceapidemo

How to Send Data from Ajax to Servlets

Servlet Code
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
String s = request.getAttribute("stopName").toString();
response.getWriter().write(s);
}
Ajax Code
function makeRequest(i) {
var stopName = document.getElementById('newStopName' + i).value;
var Longitude = document.getElementById('newLongitude' + i).value;
var Latitude = document.getElementById('newLatitude' + i).value;
var Description = document.getElementById('newStopDesc' + i).value;
document.getElementById('hidnewStopName' + i).value = stopName;
document.getElementById('hidnewLongitude' + i).value = Longitude;
document.getElementById('hidnewLatitude' + i).value = Latitude;
document.getElementById('hidnewStopDesc' + i).value = Description;
var xmlHttpRequest = getXMLHttpRequest();
xmlHttpRequest.onreadystatechange = getReadyStateHandler(xmlHttpRequest);
xmlHttpRequest.open("GET", "Edit_Route", true);
xmlHttpRequest.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
xmlHttpRequest.send("stopName="+encodeURIComponent(stopName));
}
/*
* Returns a function that waits for the state change in XMLHttpRequest
*/
function getReadyStateHandler(xmlHttpRequest) {
// an anonymous function returned
// it listens to the XMLHttpRequest instance
return function() {
if (xmlHttpRequest.readyState === 4) {
if (xmlHttpRequest.status === 200) {
alert(xmlHttpRequest.responseText);
} else {
alert("HTTP error " + xmlHttpRequest.status + ": " + xmlHttpRequest.statusText);
}
}
};
}
i want send StopName and and again send to client using ajax please help me using javascript not jquery.Actually i want send data and save it to database that s way i want test it
I think this might be come because u have get parameter in wrong way.
String stopName = request.getParameter("stopName") != null ? request.getParameter("stopName").toString() : "null value";
it will also handle the null condition.
try this code.
Is the servlet path correct in ajax code ?
I mean "/Edit_Route" not "Edit_Route"
Maybe the ajax can not found your servlet ,i think

how do you get the ticket_id on vimeo api with scribe

I am trying to upload video to vimeo and I understand that you need the ticket_id in order to be able to upload.
The think is I can not figure out how to get this ticket_id by using scribe.
Does anyone have any example how to do this?
Thanks in advance.
When I use:
OAuthRequest request = new OAuthRequest(Verb.GET, "http://vimeo.com/api/rest/v2");
request.addQuerystringParameter("method", "vimeo.videos.upload.getTicket");
this results in:
<err code="401" expl="The consumer key passed was not valid." msg="Invalid consumer key"/>
When I use method:
request.addQuerystringParameter("method", "vimeo.videos.upload.getQuota");
everything works fine. I tried putting some fake api key in the vimeo.videos.upload.getQuota method. That also resulted in invalid key. So it is not like method vimeo.videos.upload.getQuota does not need the api key. In fact it does and if you don't provide the valid key it wil not work. Somehow when calling method vimeo.videos.upload.getTicket, with the same api key that works for the mehod getQuota, I get response:
<err code="401" expl="The consumer key passed was not valid." msg="Invalid consumer key"/>
full code with fake api keys:
public class VimeoServiceConcept {
public static void main(String[] args) {
String apikey="api key";
String apisecret="secret";
String accessToken="access token";
String accessTokenSecret="access token secret";
OAuthService service = new ServiceBuilder()
.provider(VimeoApi.class)
.apiKey(apikey)
.apiSecret(apisecret)
.build();
Token token = new Token(accessToken, accessTokenSecret);
OAuthRequest request = new OAuthRequest(Verb.GET, "http://vimeo.com/api/rest/v2");
// request.addQuerystringParameter("method", "vimeo.videos.upload.getQuota");
request.addQuerystringParameter("format", "xml");
request.addQuerystringParameter("method", "vimeo.videos.upload.getTicket");
request.addQuerystringParameter("upload_method", "post");
service.signRequest(token, request);
System.out.println(request.getCompleteUrl());
Response response = request.send();
System.out.println("Got it! Lets see what we found...");
System.out.println(response.getHeader("code"));
System.out.println(response.getCode());
System.out.println(response.getBody());
}
}
Try getting the ticket after you get the quota. I have never tried getting the ticket without the quota first because their documentation explicitly states you need to check quota before you get the ticket. It looks like you just comment out what you're not testing. Try this instead:
public class VimeoServiceConcept {
public static void main(String[] args) {
String apikey="api key";
String apisecret="secret";
String accessToken="access token";
String accessTokenSecret="access token secret";
OAuthService service = new ServiceBuilder().provider(VimeoApi.class).apiKey(apiKey).apiSecret(apiSecret).build();
OAuthRequest request;
Response response;
accessToken = new Token("your_token", "your_tokens_secret");
accessToken = checkToken(vimeoAPIURL, accessToken, service);
if (accessToken == null) {
return;
}
// Get Quota
request = new OAuthRequest(Verb.GET, vimeoAPIURL);
request.addQuerystringParameter("method", "vimeo.videos.upload.getQuota");
signAndSendToVimeo(request, "getQuota", true);
// Get Ticket
request = new OAuthRequest(Verb.GET, vimeoAPIURL);
request.addQuerystringParameter("method", "vimeo.videos.upload.getTicket");
request.addQuerystringParameter("upload_method", "streaming");
response = signAndSendToVimeo(request, "getTicket", true);
//... the rest of your code...
}
}
Here's checkToken:
/**
* Checks the token to make sure it's still valid. If not, it pops up a dialog asking the user to
* authenticate.
*/
private static Token checkToken(String vimeoAPIURL, Token vimeoToken, OAuthService vimeoService) {
if (vimeoToken == null) {
vimeoToken = getNewToken(vimeoService);
} else {
OAuthRequest request = new OAuthRequest(Verb.GET, vimeoAPIURL);
request.addQuerystringParameter("method", "vimeo.oauth.checkAccessToken");
Response response = signAndSendToVimeo(request, "checkAccessToken", true);
if (response.isSuccessful()
&& (response.getCode() != 200 || response.getBody().contains("<err code=\"302\"")
|| response.getBody().contains("<err code=\"401\""))) {
vimeoToken = getNewToken(vimeoService);
}
}
return vimeoToken;
}
Here's getNewToken:
/**
* Gets authorization URL, pops up a dialog asking the user to authenticate with the url and the user
* returns the authorization code
*
* #param service
* #return
*/
private static Token getNewToken(OAuthService service) {
// Obtain the Authorization URL
Token requestToken = service.getRequestToken();
String authorizationUrl = service.getAuthorizationUrl(requestToken);
do {
String code = JOptionPane.showInputDialog("The token for the account (whatever)" + newline
+ "is either not set or is no longer valid." + newline
+ "Please go to the URL below and authorize this application." + newline
+ "Paste the code you're given on top of the URL here and click \'OK\'" + newline
+ "(click the 'x' or input the letter 'q' to cancel." + newline
+ "If you input an invalid code, I'll keep popping up).", authorizationUrl + "&permission=delete");
if (code == null) {
return null;
}
Verifier verifier = new Verifier(code);
// Trade the Request Token and Verfier for the Access Token
System.out.println("Trading the Request Token for an Access Token...");
try {
Token token = service.getAccessToken(requestToken, verifier);
System.out.println(token); //Use this output to copy the token into your code so you don't have to do this over and over.
return token;
} catch (OAuthException ex) {
int choice = JOptionPane.showConfirmDialog(null, "There was an OAuthException" + newline
+ ex + newline
+ "Would you like to try again?", "OAuthException", JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.NO_OPTION) {
break;
}
}
} while (true);
return null;
}
Here's signAndSend:
/**
* Signs the request and sends it. Returns the response.
*
* #param request
* #return response
*/
public static Response signAndSendToVimeo(OAuthRequest request, String description, boolean printBody) throws org.scribe.exceptions.OAuthException {
System.out.println(newline + newline
+ "Signing " + description + " request:"
+ ((printBody && !request.getBodyContents().isEmpty()) ? newline + "\tBody Contents:" + request.getBodyContents() : "")
+ ((!request.getHeaders().isEmpty()) ? newline + "\tHeaders: " + request.getHeaders() : ""));
service.signRequest(accessToken, request);
printRequest(request, description);
Response response = request.send();
printResponse(response, description, printBody);
return response;
}

Digest authentication with Jersey Client

I have written a REST web service with Jersey Server (that totally rocks !).
I am now developing the client part of it, with Jersey Client as well.
On the server side, I have chosen a DIGEST authentication, because I personally think that BASIC authentication is an heresy that should be marked as "DEPRECATED" in our heads.
Unfortunately, I do not see any support of the Digest authentication on the client side.
For BASIC authentication, one does something like :
client.addFilter(
new HTTPBasicAuthFilter(
user,
password));
But I see no "HTTPDigestAuthFilter" counterpart.
Am I missing something ?
Thanks for your help,
Raphael
I have just implemented it.
I have created a feature request in the Jersey issue tracker, and posted my implementation there, as attachment :
https://jersey.dev.java.net/issues/show_bug.cgi?id=542
It works fine for communicating with a DIGEST authentication of a Tomcat server.
I have not tested for other web servers yet.
Here I wrote some random uri. Please fill your desired URI
For sample testing you can take help of google services which are available in the internet for open.
import javax.ws.rs.core.*;
import org.apache.commons.codec.digest.*;
import org.codehaus.jettison.json.*;
import com.sun.jersey.api.*;
public class DigestClient {
//Dividing into two parts because we need to send the last part of uri in our second request to service.
static String baseUri = "https://www.something.com";
static String subUri = "/later-part";
public static void main(String[] args) throws JSONException{
ClientConfig cc = new DefaultClientConfig();
Client client = Client.create(cc);
WebResource webResource = client.resource(baseUri+subUri);
ClientResponse response = webResource.get(ClientResponse.class);
// Basically in Digest-Authentication mechanism, we hit the rest service two times.
// First time with No Authentication, which returns some values (qop, nonce, realm) which are used as inputs in second call to rest service.
/*--------------- First call-----------------*/
// We get 401, Unauthorized
System.out.println(response.getStatus()+" "+response.getStatusInfo());
// Here is the complete header information
System.out.println(response.getHeaders());
// We need "WWW-Authenticate" part information for our second call to rest
System.out.println("WWW-Authenticate: \t" + response.getHeaders().get("www-Authenticate"));
String noAuthResp = response.getHeaders().get("www-Authenticate").toString();
noAuthResp = noAuthResp.replace("Digest ", "");
noAuthResp = noAuthResp.replace('[', '{');
noAuthResp = noAuthResp.replace(']', '}');
// Creating a JSONObject for easy information retrieval
JSONObject resp = new JSONObject(noAuthResp);
/*--------------- Second call-----------------*/
// Here client has to set the fields which was returned from the first call
String user = "postman"; // username
String password = "password"; // password
String realm = resp.getString("realm"); // realm value from the first rest-call response
String qop = resp.getString("qop"); //qop value from the first rest-call response
String nonce = resp.getString("nonce"); // nonce value from the first rest-call response
String opaque = resp.getString("opaque"); // Some times if we don't get this value, set it with ""
String algorithm = "MD5"; // The algorithm set by the client
int nonceCount = 678; // Some numerical input from the client
String clientNonce = "afdjas0"; // Some random text from the client for encryption
String method = "GET"; // HTTP method
String ha1 = new DigestClient().formHA1(user, realm, password);
String ha2 = new DigestClient().formHA2(method, subUri);
String responseCode = new DigestClient().generateResponse(ha1, nonce, nonceCount, clientNonce, qop, ha2);
// Header to be sent to the service
String value = "Digest username=\""+user+"\", realm=\""+realm+"\", nonce=\""+nonce+"\", uri=\""+subUri+"\", qop="+qop+", nc="+nonceCount+", cnonce=\""+clientNonce+"\", response=\""+responseCode+"\", opaque=\""+opaque+"\"";
// Hitting the service
response = webResource.header("authorization", value).type(MediaType.TEXT_PLAIN).accept("*").get(ClientResponse.class);
System.out.println("\nComplete Response:\n"+response+"\n");
String output = response.getEntity(String.class);
System.out.println("Response Text: "+output);
}
// For generating HA1 value
public String formHA1(String userName,String realm,String password){
String ha1 = DigestUtils.md5Hex(userName + ":" + realm + ":" + password);
return ha1;
}
// For generating HA2 value
public String formHA2(String method,String uri){
String ha2=DigestUtils.md5Hex(method + ":" + uri);
return ha2;
}
// For generating response at client side
public String generateResponse(String ha1,String nonce,int nonceCount,String clientNonce,String qop,String ha2){
String response=DigestUtils.md5Hex(ha1 + ":" + nonce + ":" + nonceCount + ":" +clientNonce +":" + qop + ":" +ha2);
return response;
}
}

Categories