How do I send a HTTP request using OAUTH2 in Android? - json

I am trying to retrieve the data from my account by connecting to the Fitbit API. I have my app returning the Access Token I need to make the HTTP Request that returns the JSON but anything that I try, it returns an error. I have two Activities - MainActivity.java and TestActivity.java
In MainActivity.java I am simply opening a Chrome Custom Tab to direct the user to the Fitbit Authentication(Login) page. Once the user enters their details they are redirected back to the TestActivity.java as per the Fitbit API documentation. I am then printing the Acess Token which proves to me that it is connecting to the API.
What I need to do it make an HTTP request to returns the sleep data in JSON format. I know how to do it in Java but I am unsure how to do it in Android using the AsyncTask way. Any help is appreciated!
public class TestActivity extends AppCompatActivity {
String string;
String token;
#Override
protected void onNewIntent(Intent intent) {
string = intent.getDataString();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
onNewIntent(getIntent());
//Toast.makeText(TestActivity.this, string , Toast.LENGTH_LONG).show();
Log.e("TAG", string);
Log.e("TAG", string.substring(string.indexOf("&access_token")+14));
token = string.substring(string.indexOf("&access_token")+14);
Context context = getApplicationContext();
Toast toast = Toast.makeText(context,"Access Token: "+ token,Toast.LENGTH_LONG );
Log.i("TAG", "Access Token: "+ token);
new JSONTask().execute("https://api.fitbit.com/1.2/user/-/sleep/date/2018-01-30.json");
}
public class JSONTask extends AsyncTask<String,String,String>
{
#Override
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try
{
URL url = new URL(params[0]);
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer " + token);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while((line = reader.readLine()) !=null)
{
buffer.append(line);
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s)
{
super.onPostExecute(s);
Log.i("TAG", s);
}
}

I ended up having a breakthrough with this question. I figured out that I was extracting the Access Token incorrectly. So, instead of doing the following:
token = string.substring(string.indexOf("&access_token")+14);
I instead had to use this:
token = string.substring(string.indexOf("&access_token")+36,308);
The App was then able to make the necessary HTTP request to the Fitbit API which returned the JSON data that I needed.

One order of codes should be changed for preventing FC.
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer " + token);

Related

Can we use the same signer object to sign all the requests?

I need to make mutiple rest api calls for fetching instance, volume and vnic details. Can i reuse the same signer object created for signing the other calls?
Signer object method
public RequestSigner getSigner(Properties properties, String pemFilePath, String apiKey) {
InputStream privateKeyStream;
PrivateKey privateKey = null;
try {
privateKeyStream = Files.newInputStream(Paths.get(pemFilePath));
privateKey = PEM.readPrivateKey(privateKeyStream);
} catch (InvalidKeySpecException e) {
// throw new RuntimeException("Invalid format for private key");
properties.setProperty(OracleCloudConstants.CUSTOM_DC_ERROR,
FormatUtil.getString("am.webclient.oraclecloud.customdc.invalidformat"));
AMLog.debug("OracleCloudDataCollector::CheckAuthentication()::Invalid format for private key::"
+ e.getMessage());
e.printStackTrace();
} catch (IOException e) {
properties.setProperty(OracleCloudConstants.CUSTOM_DC_ERROR,
FormatUtil.getString("am.webclient.oraclecloud.customdc.failedload"));
AMLog.debug(
"OracleCloudDataCollector::CheckAuthentication()::Failed to load private key::" + e.getMessage()); //No I18N
e.printStackTrace();
// throw new RuntimeException("Failed to load private key");
}
RequestSigner signer = null;
if (privateKey != null) {
signer = new RequestSigner(apiKey, privateKey);
}
return signer;
}
One signer object may be used to sign multiple requests. In fact, the SDK implementation does this too.
It is not clear what version of the SDK you are using. In version 1.5.7 (the most recent at the time of writing), com.oracle.bmc.http.signing.RequestSigner (https://github.com/oracle/oci-java-sdk/blob/master/bmc-common/src/main/java/com/oracle/bmc/http/signing/RequestSigner.java#L16) is an interface which cannot be new’ed as per the snippet above.

Consume jira rest with java

i'm using java and i want to consume the json in this url : http://jiraserver/rest/dev-status/latest/issue/detail?issueId=13879&applicationType=stash&dataType=repository
on the browser this url works perfectly and i get all json data needed but in my java program i get
java.io.IOException: Server returned HTTP response code: 400 for URL:
http://jiraserver/rest/dev-status/latest/issue/detail?issueId=13879&applicationType=stash&dataType=repository
public static void main(String[] args) {
System.out
.println(jsonGetRequest("http://jiraserver/rest/dev-status/latest/issue/detail?issueId=13879&applicationType=stash&dataType=repository
"));
}
private static String streamToString(InputStream inputStream) {
String text = new Scanner(inputStream, "UTF-8").useDelimiter("\\Z").next();
return text;
}
public static String jsonGetRequest(String urlQueryString) {
String json = null;
try {
URL url = new URL(urlQueryString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("GET");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("charset", "utf-8");
connection.connect();
InputStream inStream = connection.getInputStream();
json = streamToString(inStream); // input stream to string
} catch (IOException ex) {
ex.printStackTrace();
}
return json;
}
am i missing something ? if there's any simple implementation to consume that url feel free

HTTP error 500 on Android

So here is my code, its purpose is to fecth a json file. I get an error 500 from the server, which means I know that it is an internal server error. As I can't access to the logs of the the server, I'm pretty much stuck from now... I read about session and cookies, maybe that's it. What do you guy think of it ?
private class ListingFetcher extends AsyncTask<Void, Void, String> {
private static final String TAG = "ListingFetcher";
public static final String SERVER_URL = "http://www.myurl.com/listing.json";
#Override
protected String doInBackground(Void... params) {
try {
//Create an HTTP client
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(SERVER_URL);
//Perform the request and check the status code
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
try {
//Read the server response and attempt to parse it as JSON
Reader reader = new InputStreamReader(content);
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("M/d/yy hh:mm a");
Gson gson = gsonBuilder.create();
List<Listing> events = new ArrayList<Listing>();
events = Arrays.asList(gson.fromJson(reader, Listing[].class));
content.close();
handlePostsList(events);
} catch (Exception ex) {
Log.e(TAG, "Failed to parse JSON due to: " + ex);
failedLoadingPosts();
}
} else {
Log.e(TAG, "Server responded with status code: " + statusLine.getStatusCode());
failedLoadingPosts();
}
} catch(Exception ex) {
Log.e(TAG, "Failed to send HTTP POST request due to: " + ex);
failedLoadingPosts();
}
return null;
}
}
My code is perfectly working. THe only mistake is on this line :
HttpPost post = new HttpPost(SERVER_URL);
Which should be
HttpGet get = new HttpGet(SERVER_URL);

Using XPages to get data from managed bean

I am trying to create a list of Twitter users, populating it with the number of followers for the user and their profile image. Because of Twitter's API, you need to get an access token for your application prior to using their REST API. I thought the best way to do this was via Java and a managed bean. I posted the code below, which currently works. I get the access token from Twitter, then make the API call to get the user info, which is in JSON.
My question is, what is the best way to parse the JSON and iterate over a list of user names to create a table/grid on the XPage?
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import javax.net.ssl.HttpsURLConnection;
import org.apache.commons.codec.binary.Base64;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
public class TwitterUser implements Serializable {
private static final String consumerKey = "xxxx";
private static final String consumerSecret = "xxxx";
private static final String twitterApiUrl = "https://api.twitter.com";
private static final long serialVersionUID = -2084825539627902622L;
private static String accessToken;
private String twitUser;
public TwitterUser() {
this.twitUser = null;
}
public String getTwitterUser(String screenName) {
try {
this.requestTwitterUserInfo(screenName);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return twitUser;
}
public void setTwitterUser() {
twitUser = twitUser;
}
//Encodes the consumer key and secret to create the basic authorization key
private static String encodeKeys(String consumerKey, String consumerSecret) {
try {
String encodedConsumerKey = URLEncoder.encode(consumerKey, "UTF-8");
String encodedConsumerSecret = URLEncoder.encode(consumerSecret, "UTF-8");
String fullKey = encodedConsumerKey + ":" + encodedConsumerSecret;
byte[] encodedBytes = Base64.encodeBase64(fullKey.getBytes());
return new String(encodedBytes);
}
catch (UnsupportedEncodingException e) {
return new String();
}
}
//Constructs the request for requesting a bearer token and returns that token as a string
private static void requestAccessToken() throws IOException {
HttpsURLConnection connection = null;
String endPointUrl = twitterApiUrl + "/oauth2/token";
String encodedCredentials = encodeKeys(consumerKey,consumerSecret);
String key = "";
try {
URL url = new URL(endPointUrl);
connection = (HttpsURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Host", "api.twitter.com");
connection.setRequestProperty("User-Agent", "Your Program Name");
connection.setRequestProperty("Authorization", "Basic " + encodedCredentials);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
connection.setRequestProperty("Content-Length", "29");
connection.setUseCaches(false);
writeRequest(connection, "grant_type=client_credentials");
// Parse the JSON response into a JSON mapped object to fetch fields from.
JSONObject obj = (JSONObject)JSONValue.parse(readResponse(connection));
if (obj != null) {
String tokenType = (String)obj.get("token_type");
String token = (String)obj.get("access_token");
accessToken = ((tokenType.equals("bearer")) && (token != null)) ? token : "";
}
else {
accessToken = null;
}
}
catch (MalformedURLException e) {
throw new IOException("Invalid endpoint URL specified.", e);
}
finally {
if (connection != null) {
connection.disconnect();
}
}
}
private void requestTwitterUserInfo(String sn) throws IOException {
HttpsURLConnection connection = null;
if (accessToken == null) {
requestAccessToken();
}
String count = "";
try {
URL url = new URL(twitterApiUrl + "/1.1/users/show.json?screen_name=" + sn);
connection = (HttpsURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("GET");
connection.setRequestProperty("Host", "api.twitter.com");
connection.setRequestProperty("User-Agent", "Your Program Name");
connection.setRequestProperty("Authorization", "Bearer " + accessToken);
connection.setRequestProperty("Content-Type", "text/plain");
connection.setUseCaches(false);
}
catch (MalformedURLException e) {
throw new IOException("Invalid endpoint URL specified.", e);
}
finally {
if (connection != null) {
connection.disconnect();
}
}
twitUser = readResponse(connection);
}
//Writes a request to a connection
private static boolean writeRequest(HttpsURLConnection connection, String textBody) {
try {
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));
wr.write(textBody);
wr.flush();
wr.close();
return true;
}
catch (IOException e) { return false; }
}
// Reads a response for a given connection and returns it as a string.
private static String readResponse(HttpsURLConnection connection) {
try {
StringBuilder str = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = "";
while((line = br.readLine()) != null) {
str.append(line + System.getProperty("line.separator"));
}
return str.toString();
}
catch (IOException e) { return new String(); }
}
}
A few pointers:
Domino has the Apache HTTP client classes. They tend to be more robust than raw HTTP connections
Define a new class as a bean that contains all values that you want to see per row. You only need the getters public
add a method to your managed bean Collection getAllData()
bind that to a repeat control
you then can use repeatvar.someProperty in column values in EL
use better names than I just used

NullReferenceException during navigation from MainPage.xaml.cs to another xaml

My application takes username and password and on clinking the hyperlinkbutton, these values are sent to the server and hence server returns something like PASS:ClientID. I wish to navigate to SecondPage.xaml (from MainPage.xaml.cs) only if the responseString contains PASS.
Here is my code:
namespace aquila1
{
public partial class MainPage : PhoneApplicationPage
{
static string username;
static string password;
static string rs;
static NavigationService ns = new NavigationService();
// Constructor
public MainPage()
{
InitializeComponent();
}
private static ManualResetEvent allDone = new ManualResetEvent(true);
private void HyperlinkButton_Click_1(object sender, RoutedEventArgs e)
{
username = textbox1.Text;
password = textbox2.Text;
System.Diagnostics.Debug.WriteLine(username);
System.Diagnostics.Debug.WriteLine(password);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://60.243.245.181/fms_tracking/php/mobile_login.php?username=" + username + "&password=" + password);
request.ContentType = "application/x-www-form-urlencoded";
// Set the Method property to 'POST' to post data to the URI.
request.Method = "POST";
// start the asynchronous operation
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
// Keep the main thread from continuing while the asynchronous
// operation completes. A real world application
// could do something useful such as updating its user interface.
allDone.WaitOne();
}
private static void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
// Console.WriteLine("Please enter the input data to be posted:");
string postData = username + "+" + password;
System.Diagnostics.Debug.WriteLine(postData);
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Write to the request stream.
postStream.Write(byteArray, 0, postData.Length);
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private static void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
rs = responseString;
System.Diagnostics.Debug.WriteLine(responseString);
System.Diagnostics.Debug.WriteLine("#####");
System.Diagnostics.Debug.WriteLine(rs);
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
move2();
allDone.Set();
}
private static void move2()
{
string[] rs1 = rs.Split(':');
if ((rs1[0].Trim()).Equals("PASS"))
{
ns.Navigate(new Uri("/SecondPage.xaml", UriKind.Relative));
}
else
{
MessageBox.Show(rs);
}
}
}
}
On running the code, i always get NullReferenceException .
Plz help me find the error and suggest corrections.
Thanks in advance
You're most likely getting the error because the NavigationService cannot find the resource /SecondPage.xaml. Is SecondPage located at the root of your project?
This can also be caused by trying to navigate before the target resource is loaded (for example, by navigating inside a page's constructor), but that doesn't immediately appear to be your problem.
This answer suggests that this problem can occur after changing namespaces or assembly names. It states that cleaning the project, ensuring all bin and obj folders are empty, then recompiling will fix it. However, its reference link is dead.