. Hi, as a young android developer i was looking at a way to get a JSON response from a server.
I started looking at AsyncTask but i not feeling comfortable to code an AsyncTask for each time i needed to ask a WebService.
Then i started to code a class (extends AsyncTask) that query an URL (POST or GET) and provide a callback containing the response from the server.
I wanted to have some feedback, is it really useful, and not an useless overlay of an AsyncTask cause i missed understand something at the beginning.
The more i code it, the more i doubt.
Thanks in advance for your feedback.
Here's the code i use to query a server with my class :
HashMap<String, String> parameters = new HashMap<String, String>();
parameters.put("address", "sidney");
parameters.put("sensor", "false");
WebServiceAsyncTask asyncWS = new WebServiceAsyncTask(MainActivity.this);
asyncWS.setParameters(parameters);
asyncWS.execute(
"http://maps.googleapis.com/maps/api/geocode/json",
WebServiceAsyncTask.GET,
new WebServiceAsyncTaskCallback() {
#Override
void callbackMethod(String result) {
Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
}
}
);
Here's the code of my WebServiceAsyncTask :
import android.app.ProgressDialog;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Anthony Raymond
*/
public class WebServiceAsyncTask extends AsyncTask<Object, String, String> {
public static final String GET = "GET";
public static final String POST = "POST";
private static final String PROGRESS_TEXT_PREPARING = "Preparing request";
private static final String PROGRESS_PERCENT_PREPARING = "25";
private static final String PROGRESS_TEXT_CONNECTION_SERVER = "Connecting to the server";
private static final String PROGRESS_PERCENT_CONNECTION_SERVER = "50";
private static final String PROGRESS_TEXT_PARSING = "Parsing received data";
private static final String PROGRESS_PERCENT_PARSING = "75";
private static final String PROGRESS_TEXT_END = "Process ended";
private static final String PROGRESS_PERCENT_END = "100";
private Context context;
private HashMap<String, String> mData = new HashMap<String, String>();
private ProgressDialog progressDialog;
private WebServiceAsyncTaskCallback callbackClass;
/**
* If a Context is passed, a ProgressDialog will be displayed
* NEED TO PASS Context LIKE THIS :
* MyActivity.this
* DO NOT USE getApplicationContext()
* #param applicationContext
*/
public WebServiceAsyncTask(Context applicationContext)
{
this.context = applicationContext;
}
/**
* Create a WebServiceAsyncTask.
* Usage : add request parameter by passing an HashMap<String, String> with the setParameter Method, then call
* .execute(String url, WebServiceAsyncTask constant (GET or SET), WebServiceAsyncTaskCallback callback)
* exemple :
* HashMap<String, String> parameters = new HashMap<String, String>();
* parameters.put("address", "Sidney");
* parameters.put("sensor", "false");
* WebServiceAsyncTask asyncWS = new WebServiceAsyncTask(MainActivity.this);
* asyncWS.setParameters(parameters);
* asyncWS.execute(
* "http://maps.googleapis.com/maps/api/geocode/json",
* WebServiceAsyncTask.GET,
* new WebServiceAsyncTaskCallback() {
* #Override
* void callbackMethod(String result) {
* Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
* }
* }
* );
*/
public WebServiceAsyncTask()
{
this.context = null;
}
private void prepareProgressDialog()
{
if (this.context != null)
{
this.progressDialog = new ProgressDialog(this.context);
this.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
this.progressDialog.setCancelable(true);
this.progressDialog.setTitle("Please Wait...");
this.progressDialog.setMessage(PROGRESS_TEXT_PREPARING);
this.progressDialog.setProgress(Integer.parseInt(PROGRESS_PERCENT_PREPARING));
}
}
private String getPostResponse(String url)
{
byte[] result;
String str = "";
HttpClient client = new DefaultHttpClient();
HttpPost http = new HttpPost(url);
// set up post data
List<NameValuePair> nameValuePair = new ArrayList<NameValuePair>();
for (String key : this.mData.keySet()) {
nameValuePair.add(new BasicNameValuePair(key, this.mData.get(key)));
}
UrlEncodedFormEntity urlEncodedFormEntity;
try
{
urlEncodedFormEntity = new UrlEncodedFormEntity(nameValuePair);
http.setEntity(urlEncodedFormEntity);
this.publishProgress(PROGRESS_TEXT_CONNECTION_SERVER, PROGRESS_PERCENT_CONNECTION_SERVER);
HttpResponse response = client.execute(http);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpURLConnection.HTTP_OK)
{
this.publishProgress(PROGRESS_TEXT_PARSING, PROGRESS_PERCENT_PARSING);
result = EntityUtils.toByteArray(response.getEntity());
str = new String(result, HTTP.UTF_8);
}
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
return str;
}
private String getGetResponse(String url)
{
byte[] result;
String str = "";
HttpClient client = new DefaultHttpClient();
try
{
// set up get data and URL
Uri.Builder uri = Uri.parse(url).buildUpon();
for (String key : this.mData.keySet()) {
uri.appendQueryParameter(key, this.mData.get(key));
}
HttpGet http = new HttpGet(String.valueOf(uri));
this.publishProgress(PROGRESS_TEXT_CONNECTION_SERVER, PROGRESS_PERCENT_CONNECTION_SERVER);
HttpResponse response = client.execute(http);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpURLConnection.HTTP_OK)
{
this.publishProgress(PROGRESS_TEXT_PARSING, PROGRESS_PERCENT_PARSING);
result = EntityUtils.toByteArray(response.getEntity());
str = new String(result, HTTP.UTF_8);
}
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
return str;
}
public void setParameters(HashMap<String, String> httpRequestParameters)
{
this.mData = httpRequestParameters;
}
#Override
protected String doInBackground(Object... params)
{
// Ensure that we got, URL, http method and Callback
if (params.length != 3)
{
this.cancel(true);
}
else
{
if ((params[2] instanceof WebServiceAsyncTaskCallback))
{
this.callbackClass = ((WebServiceAsyncTaskCallback)params[2]);
}
else
{
this.cancel(true);
}
try {
URL url = new URL((String)params[0]);
} catch (MalformedURLException e) {
this.callbackClass.onError("First param must be a valid URL. (" + params[0] + " given)");
this.cancel(true);
}
if (!((String)params[1]).equals(POST) && !((String)params[1]).equals(GET))
{
this.callbackClass.onError("Second parameters must be " + this.getClass().getName() + " POST or GET constant");
this.cancel(true);
}
}
String str = "";
//IS OUR REQUEST A POST
if (params.length > 1)
{
if (((String)params[1]).toUpperCase().equals(WebServiceAsyncTask.POST))
{
str = getPostResponse(((String)params[0]));
}
else if(((String)params[1]).toUpperCase().equals(WebServiceAsyncTask.GET)) //THEN GET
{
str = getGetResponse(((String)params[0]));
}
}
return str;
}
#Override
protected void onPostExecute(String result)
{
this.mData = null;
if (this.context != null)
{
this.publishProgress(PROGRESS_TEXT_END, PROGRESS_PERCENT_END);
this.progressDialog.dismiss();
}
if (this.callbackClass != null)
{
this.callbackClass.callbackMethod(result);
}
}
#Override
protected void onPreExecute()
{
if (this.context != null)
{
this.prepareProgressDialog();
this.progressDialog.show();
}
}
#Override
protected void onProgressUpdate(String... values) {
if (this.context != null)
{
this.progressDialog.setMessage(values[0]);
this.progressDialog.setProgress(Integer.parseInt(values[1]));
}
}
}
/**
* Allow to easily get the server response
*/
abstract class WebServiceAsyncTaskCallback{
/**
* Return the server response as String
* #param result server response as a String
*/
abstract void callbackMethod(String result);
/**
* This method is design to report simple errors for development phase.
* #param errMessage contains error message
*/
protected void onError(String errMessage){};
;
}
Your use of AsyncTask appears appropriate. As you may be aware.. for network communications you must use AsyncTask or your own thread (extend HandlerThread.)
If your app is frequently calling AsyncTask or is executing simultaneous AsyncTask then creating your own thread will be more efficient (all AsyncTask requests use a single thread in API 13 and up.)
I'm unfamiliar with your app and how it functions.. do your users require the dialogs and status feedback for thses background network transmissions?
Can I just point out that, because you are not doing this in a Service, your remote query stands every chance of being killed, as soon your Activity is hidden. You have, essentially, rewritten IntentService... except that your version will get killed and the version the framework provides, free, will not
IntentService, FTW
Related
I've recently used AsyncTask into my android app and what this piece of code is doing, is making a get request to the provided url, and retrieving the song name from it. (The URL is a Spotify song). When I print out the response I am getting, it says
com.(projectname).(projectname).TRetrieve$HttpGetRequest#aed19ea
(TRetrieve is the name of the class that is doing this request)
How can I make the request and properly get the name of the song back?
This is the code for the class so far:
public class HttpGetRequest extends AsyncTask<String, Void, String> {
public static final String REQUEST_METHOD = "GET";
public static final int READ_TIMEOUT = 15000;
public static final int CONNECTION_TIMEOUT = 15000;
#Override
protected String doInBackground(String... params){
String stringUrl = "https://open.spotify.com/track/5Q41NLTmGbVPozwHKK7bk2";
String result;
String inputLine;
try {
URL myUrl = new URL(stringUrl);
HttpURLConnection connection = (HttpURLConnection)
myUrl.openConnection();
connection.setRequestMethod(REQUEST_METHOD);
connection.setReadTimeout(READ_TIMEOUT);
connection.setConnectTimeout(CONNECTION_TIMEOUT);
connection.connect();
InputStreamReader streamReader = new
InputStreamReader(connection.getInputStream());
BufferedReader reader = new BufferedReader(streamReader);
StringBuilder stringBuilder = new StringBuilder();
while ((inputLine = reader.readLine()) != null) {
stringBuilder.append(inputLine);
}
reader.close();
streamReader.close();
result = stringBuilder.toString();
linkLoc = result.indexOf(testString) + testString.length();
for (int i = linkLoc; i < result.indexOf("on Spotify"); i++) {
sname += result.charAt(i) + "";
}
}
catch(IOException e){
e.printStackTrace();
sname = "Error";
}
return sname;
}
protected void onPostExecute(String result){
super.onPostExecute(result);
}
Interacting with API using AsyncTask / HttpURLConnection is very old-school. I suggest yo to use modern way to do it, using RxJava / Retrofit / Gson
1). Adding necessary dependencies
Add next dependencies to your <root>/app/build.gradle:
compile 'com.squareup.okhttp3:okhttp:3.3.1'
compile ('com.squareup.retrofit2:retrofit:2.0.2')
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
compile 'com.google.code.gson:gson:2.4'
compile 'io.reactivex:rxjava:1.0.13'
compile 'io.reactivex:rxandroid:0.25.0'
2). Creating HTTP client
2.1)* (This is optional, only if you need to send AUTH token in headers)
Create interceptor:
import com.betcade.sdk.util.AuthUtil;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class DBQRequestInterceptor implements Interceptor {
public DBQRequestInterceptor(){
}
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder();
if(<if necessary to send a token>){
requestBuilder.addHeader(<TOKEN_HEADER_NAME>, <TOKEN>);
}
Request request = requestBuilder.build();
return chain.proceed(request);
}
}
2.2)* (Also, optional step, only if you want to log request/response)
Create logging interceptor:
HttpLoggingInterceptor interceptor1 = new HttpLoggingInterceptor();
interceptor1.setLevel(HttpLoggingInterceptor.Level.BODY);
2.3) Create HTTP client
OkHttpClient client = new OkHttpClient.Builder()
.writeTimeout(8, TimeUnit.SECONDS)
.readTimeout(8, TimeUnit.SECONDS)
.addInterceptor(interceptor) // interceptor from step 2.1
.addInterceptor(interceptor1) // interceptor from step 2.2
.build();
2.4). Create TrackResponse model:
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class TrackResponse {
#SerializedName("id")
#Expose
private String id;
#SerializedName("name")
#Expose
private String name;
/**
*
* #return
* The id
*/
public String getId() {
return id;
}
/**
*
* #param id
* The id
*/
public void setId(String id) {
this.id = id;
}
/**
*
* #return
* The name
*/
public String getName() {
return name;
}
/**
*
* #param name
* The name
*/
public void setName(String name) {
this.name = name;
}
}
2.5) Create interface ApiClient:
public interface ApiClient {
#GET("tracks/{id}")
Observable<TrackResponse> getTrackInfo(#Path("id") String trackId);
}
2.6). Creat instance of ApiClient:
Retrofit API = new Retrofit.Builder()
.client(client)
.baseUrl("https://api.spotify.com/v1/")
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.addCallAdapterFactory(RxErrorHandlingCallAdapterFactory.create())
.build();
ApiClient client = API.create(ApiClient.class);
2.7). Getting the name:
client.getTrackInfo("5Q41NLTmGbVPozwHKK7bk2")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<TrackResponse>() {
#Override
public void call(TrackResponse trackResponse) {
String name = track.getName();
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
});
I am trying to consume data from local web service in an android emulator using ksoap2 library, I test the same app with a online webservice http://www.webservicex.net/New/Home/ServiceDetail/17 and It works,
the webService has been made it on Csharp, it has a method to return a column from a DB, call neptuno(spanish adventure works),when execute dont show the data and after a moment show the error message programmed, I change the localhost for my local IP
[WebService(Namespace = "http://testapi.idat/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class Service : System.Web.Services.WebService
{
SqlConnection cn = new SqlConnection("data source=.;initial catalog = neptuno; integrated security=true");
public Service () {
//InitializeComponent();
}
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
[WebMethod]
public DataSet mostrar(){
DataSet ds = new DataSet();
cn.Open();
String sql = "select idProducto from productos";
SqlDataAdapter da = new SqlDataAdapter(sql,cn);
da.Fill(ds);
return ds;
}
}
the service works and return the column IDProduct, the problem is call with the method, I already add the permission on manifest, and the layout is just a textview for error message and edittext multiline for show the data
package com.example.webservice;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
import android.widget.TextView;
import android.os.AsyncTask;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
public class MainActivity extends Activity {
EditText resultMultiline;
TextView message;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resultMultiline = (EditText)findViewById(R.id.editText1);
message = (TextView) findViewById(R.id.textView);
CallWebservice webservice = new CallWebservice();
webservice.execute();
}
public class CallWebservice extends AsyncTask<Integer,Integer,Boolean>{
String resultText = "";
protected Boolean doInBackground(Integer... params){
boolean result = true;
final String SOAP_ACTION = "http://testapi.idat/mostrar";
final String NAMESPACE = "http://testapi.idat/";
final String METHOD_NAME = "mostrar";
final String URL = "http://192.168.1.45:51582/Webservice/Service.asmx?WSDL";
HttpTransportSE transport = new HttpTransportSE(URL);
SoapObject request = new SoapObject(NAMESPACE,METHOD_NAME);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
try {
transport.call(SOAP_ACTION,envelope);
SoapPrimitive respSoap = (SoapPrimitive)envelope.getResponse();
resultText = respSoap.toString();
}catch (Exception e){
result = false;
Log.d("Debug", e.getMessage().toString());
}
return result;
}
protected void onPostExecute(Boolean result){
if (result){
resultMultiline.setText(resultText);
Log.d("Debug","Web service works");
}else{
message.setText("ERROR");
}
}
}
}
Use the Following function it is working in my case this is normal Login soap call you need to add internet permission in your menifest
/*
* Vishal Mokal 05-MAR-2015
* soapCALL() function returns String Array.
* Make A sope call and returns response.
* if responce is success full then user will get responce array
* first element status = 1 if syccessfull 0 = if any exception of faliur
* second element = response srtring if successful or error message.
* */
public String[] soapCALL(RequestDetails requestDetails, String wsdlUserName, String wsdlPassword , String headerName) {
String url = requestDetails.getUrl().toString();
String nameSpace = requestDetails.getNameSpace().toString();
String methodName = requestDetails.getMethodName().toString();
String soapAction = requestDetails.getSoapAction().toString();
String[] responses = new String[2];
Element[] header = new Element[1];
// header[0] = new Element().createElement(nameSpace, "AuthenticationHeader");
header[0] = new Element().createElement(nameSpace, headerName);
try {
Element UserName = new Element().createElement(nameSpace, "UserName");
UserName.addChild(Node.TEXT, wsdlUserName);
header[0].addChild(Node.ELEMENT, UserName);
Element Password = new Element().createElement(nameSpace, "Password");
Password.addChild(Node.TEXT, wsdlPassword);
header[0].addChild(Node.ELEMENT, Password);
SoapObject request = requestDetails.getSoapObject();
SoapSerializationEnvelope soapSerilizationEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
soapSerilizationEnvelope.dotNet = true;
soapSerilizationEnvelope.headerOut = header;
soapSerilizationEnvelope.setOutputSoapObject(request);
Object env = soapSerilizationEnvelope.bodyOut;
HttpTransportSE httptransport = new HttpTransportSE(url);
httptransport.call(soapAction, soapSerilizationEnvelope);
SoapPrimitive response = (SoapPrimitive) soapSerilizationEnvelope.getResponse();
responses[0] = "1";
responses[1] = response.toString();
Log.d("Respons", response.toString());
return responses;
}
catch (SocketTimeoutException e)
{
responses[0] = "0";
responses[1] = "Sorry!Unable To Connect Server Please Check Your Internet Connection Or Try After Some Time.";
return responses;
}
catch (SocketException e)
{
responses[0] = "0";
responses[1] = "Sorry!Unable To Connect Server Please Try After Some Time.";
return responses;
}
catch (Exception e) {
responses[0] = "0";
responses[1] = "Sorry!Unable To Connect Server Please Try After Some Time.";
return responses;
}
}
Following is the structure for the Requestdetail class
public class RequestDetails {
private String nameSpace;
private String url;
private String methodName;
private String SoapAction;
private SoapObject soapObject;
public RequestDetails(String nameSpace, String url, String methodName, String soapAction) {
this.nameSpace = nameSpace;
this.url = url;
this.methodName = methodName;
SoapAction = soapAction;
}
public String getNameSpace() {
return nameSpace;
}
public String getUrl() {
return url;
}
public String getMethodName() {
return methodName;
}
public String getSoapAction() {
return SoapAction;
}
public SoapObject getSoapObject() {
return soapObject;
}
public void setSoapObject(SoapObject soapObject) {
this.soapObject = soapObject;
}
}
I have a ArrayAdapter which updates the ListView by fetching data from an API. API is working fine and I'm getting the data using an AsyncTask.
The OnPostExecute method should clear the ArrayAdapter and add new data to it.
But I'm facing some errors saying java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ArrayAdapter.clear()' on a null object reference
package com.example.sunshine;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.format.Time;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A simple {#link Fragment} subclass.
* Activities that contain this fragment must implement the
* {#link WeatherFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {#link WeatherFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class WeatherFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private ArrayAdapter<String> mAdapter;
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public EditText locationCity;
private OnFragmentInteractionListener mListener;
public WeatherFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment WeatherFragment.
*/
// TODO: Rename and change types and number of parameters
public static WeatherFragment newInstance(String param1, String param2) {
WeatherFragment fragment = new WeatherFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_weather, container, false);
String[] forecastArray = {"Mon 6/23 - Sunny - 31/17",
"Tue 6/24 - Foggy - 21/8",
"Wed 6/25 - Cloudy - 22/17",
"Thurs 6/26 - Rainy - 18/11",
"Fri 6/27 - Foggy - 21/10",
"Sat 6/28 - TRAPPED IN WEATHERSTATION - 23/18",
"Sun 6/29 - Sunny - 20/7"};
List<String> weekForecast = new ArrayList<>(Arrays.asList(forecastArray));
mAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, weekForecast );
mAdapter.notifyDataSetChanged();
ListView listView = (ListView) view.findViewById(R.id.listView1);
Log.d("Log", "If listview is null "+listView);
listView.setAdapter(mAdapter);
return view;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
public class FetchWeatherTask extends AsyncTask<String, Void, String[]> {
private final String LOG_TAG = FetchWeatherTask.class.getSimpleName();
/* The date/time conversion code is going to be moved outside the asynctask later,
* so for convenience we're breaking it out into its own method now.
*/
private String getReadableDateString(long time){
// Because the API returns a unix timestamp (measured in seconds),
// it must be converted to milliseconds in order to be converted to valid date.
SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("EEE MMM dd");
return shortenedDateFormat.format(time);
}
/**
* Prepare the weather high/lows for presentation.
*/
private String formatHighLows(double high, double low) {
// For presentation, assume the user doesn't care about tenths of a degree.
long roundedHigh = Math.round(high);
long roundedLow = Math.round(low);
return roundedHigh + "/" + roundedLow;
}
/**
* Take the String representing the complete forecast in JSON Format and
* pull out the data we need to construct the Strings needed for the wireframes.
*
* Fortunately parsing is easy: constructor takes the JSON string and converts it
* into an Object hierarchy for us.
*/
private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
throws JSONException {
// These are the names of the JSON objects that need to be extracted.
final String OWM_LIST = "list";
final String OWM_WEATHER = "weather";
final String OWM_TEMPERATURE = "temp";
final String OWM_MAX = "max";
final String OWM_MIN = "min";
final String OWM_DESCRIPTION = "main";
JSONObject forecastJson = new JSONObject(forecastJsonStr);
JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);
// OWM returns daily forecasts based upon the local time of the city that is being
// asked for, which means that we need to know the GMT offset to translate this data
// properly.
// Since this data is also sent in-order and the first day is always the
// current day, we're going to take advantage of that to get a nice
// normalized UTC date for all of our weather.
Time dayTime = new Time();
dayTime.setToNow();
// we start at the day returned by local time. Otherwise this is a mess.
int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);
// now we work exclusively in UTC
dayTime = new Time();
String[] resultStrs = new String[numDays];
for(int i = 0; i < weatherArray.length(); i++) {
// For now, using the format "Day, description, hi/low"
String day;
String description;
String highAndLow;
// Get the JSON object representing the day
JSONObject dayForecast = weatherArray.getJSONObject(i);
// The date/time is returned as a long. We need to convert that
// into something human-readable, since most people won't read "1400356800" as
// "this saturday".
long dateTime;
// Cheating to convert this to UTC time, which is what we want anyhow
dateTime = dayTime.setJulianDay(julianStartDay+i);
day = getReadableDateString(dateTime);
// description is in a child array called "weather", which is 1 element long.
JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
description = weatherObject.getString(OWM_DESCRIPTION);
// Temperatures are in a child object called "temp". Try not to name variables
// "temp" when working with temperature. It confuses everybody.
JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
double high = temperatureObject.getDouble(OWM_MAX);
double low = temperatureObject.getDouble(OWM_MIN);
highAndLow = formatHighLows(high, low);
resultStrs[i] = day + " - " + description + " - " + highAndLow;
}
for (String s : resultStrs) {
Log.v(LOG_TAG, "Forecast entry: " + s);
}
return resultStrs;
}
#Override
protected String[] doInBackground(String... params) {
if(params.length == 0){
return null;
}
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String format = "json";
String units = "metric";
int numDays = 7;
String forecastJSONStr = null;
try {
final String BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?";
final String QUERY_PARAM = "q";
final String FORMAT_PARAM = "mode";
final String UNITS_PARAM = "units";
final String COUNT_PARAM = "cnt";
final String APPID_PARAM = "APPID";
Uri builtUri = Uri.parse(BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, params[0])
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(UNITS_PARAM, units)
.appendQueryParameter(COUNT_PARAM, Integer.toString(numDays))
.appendQueryParameter(APPID_PARAM, BuildConfig.OWMAPIKey)
.build();
URL url = new URL(builtUri.toString());
Log.v(LOG_TAG, "Built Uri"+ builtUri.toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuilder buffer = new StringBuilder();
if(inputStream == null){
forecastJSONStr = null;
}
if(inputStream != null){
reader = new BufferedReader(new InputStreamReader(inputStream));
}
String line;
if(reader != null){
while((line = reader.readLine()) != null){
buffer.append(line).append('\n');
}
}
if(buffer.length() == 0){
forecastJSONStr = null;
}
forecastJSONStr = buffer.toString();
Log.e(LOG_TAG, "Forecast String " + forecastJSONStr);
} catch (ProtocolException | MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
Log.e(LOG_TAG, "onCreateView: Error", e);
forecastJSONStr = null;
}finally {
if(urlConnection != null){
urlConnection.disconnect();
}
if(reader != null){
try {
reader.close();
} catch (final IOException e) {
Log.e(LOG_TAG, "Error closing stream ", e);
}
}
}
try {
if(forecastJSONStr != null){
Log.v(LOG_TAG, "doInBackground: "+forecastJSONStr);
String[] results= getWeatherDataFromJson(forecastJSONStr, numDays);
Log.v(LOG_TAG, "doInBackground: Check result" +Arrays.toString(results));
return results;
// return getWeatherDataFromJson(forecastJSONStr, numDays);
}
else{
Log.e(LOG_TAG, "Check your internet!" );
}
}catch (JSONException e){
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String[] result) {
Log.v(LOG_TAG, "onPostExecute: Check result object" + Arrays.toString(result));
Log.i(LOG_TAG, "onPostExecute: "+mAdapter);
mAdapter.clear();
mAdapter.addAll(result);
// if(result != null){
//// for(String dayForecastStr : result) {
//// mAdapter.add(dayForecastStr);
//// }
//
// }
// super.onPostExecute(result);
}
}
}
Check Line 351 for the exact line which is causing the problem.
Apologies if it's a noob question, but I am new to Android Development.
This is quite a common problem. One way to think about this could be that after an AsyncTask is started, you don't really have much control over when it will end, since that depends on a number of factors, task size, etc. So, the view that called the AsyncTask itself might not be available.
Since, in your case, the mAdapter is getting set to null thus causing a NullPointerException, I would suggest you do one of the following.
inside the onPostExecute(..), start an activity on the UI thread that first re-initializes your mAdapter if it is null (if the view itself has become inactive, this wont'work)
pass a callback handler function to your AsyncTask; the function must be in WeatherFragment to ensure that the fragment is initialized and running when the AsyncTask returns; again re-initialize mAdapter if it is null and update UI accordingly based on data received from AsyncTask.
Unfortunately, given that you have not posted a more specific problem, these are the only 2 suggestions that comes to mind. You will be able to find numerous resources for each of these design choices on google. Let me know if either way worked.
In WeatherFragment.java at line no 251
mAdapter.clear();
first try to check isEmpty using this code
if(mAdapter.getCount()!=0 && mAdapter!=null){
mAdapter.clear();
}
else you can assign new one like
mAdapter = new ArrayAdapter<String>(result);
this and remove mAdapter.clear();
I have a Java application that leverages the OBIEE Web Service API to consume data from the BI Server. I am able to XMLViewService and the WebCatalogService just fine, but I can't quite get the HtmlViewService to properly render a report in the Java app. The report just shows the spinning loader, but never actually renders the report. I'm pretty sure it has to do with the fact that the Java app and the BI Server are on different domains. This is what the API documentation says:
In situations where Oracle BI Web Services and the third-party Web server do not belong to the same Domain Name Service (DNS) domain, users may get JavaScript errors related to browser security constraints for cross-domain scripting. To avoid these issues, use the setBridge() method to modify callback URLs to point to the third-party Web server. Be aware that a Web component executed by the third-party Web server to re-route requests to Oracle BI Web Services is not provided. This function would need to be fulfilled by the third-party application.
Several years ago, I did this same type of integration using .NET/C# and ran in the the same issue because the .NET app and the BI Server were on different domains. As a result, I had to create an HTTP Handler (.ashx file) as well as use the setBridge() method to to solve the issue.
The challenge that I'm having is that I can't find a servlet bridge example for Java. And I'm not too confident in porting the .NET/.ASHX code to a Java servlet/bridge. Does anyone have any code examples or direction they could provide to point me in the right direction? Here's a snippet of code to show you what I'm doing to pull back the report data:
// define report path
ReportRef reportRef = new ReportRef();
reportRef.setReportPath(reportFolder + "/" + reportName);
// set page params
StartPageParams pageParams = new StartPageParams();
pageParams.setDontUseHttpCookies(true);
// set report params
String pageId = htmlService.startPage(pageParams, sawSessionId);
String reportId = pageId + reportName;
htmlService.addReportToPage(pageId, reportId, reportRef, null, null, null, sawSessionId);
// get report html
StringBuffer reportHtml = new StringBuffer();
reportHtml.append(htmlService.getHtmlForReport(pageId, reportId, sawSessionId));
// return html
return reportHtml.toString();
This is the error that is coming back in the browser:
XMLHttpRequest cannot load http://myobiserver.com/analytics/saw.dll?ajaxGo. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://myjavaapp.com' is therefore not allowed access.
Per requested, here is my .NET/.ASHX bridge:
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Web;
using System;
using System.Collections;
using System.Configuration;
using System.Collections.Specialized;
using System.Web;
using System.Text;
using System.Net;
using System.IO;
using System.Diagnostics;
/*
This is a ASP.NET handler that handles communication
between the SharePoint site and OracleBI.
It will be deployed to:
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\OracleBI
*/
public class OracleBridge: IHttpHandler
{
public bool IsReusable {get{return true;}}
public OracleBridge()
{
}
string getServer()
{
string strServer = "http://<enter-domain>/analytics/saw.dll";
int index = strServer.LastIndexOf("/");//split off saw.dll
if (index >=0)
return strServer.Substring(0,index+1);
else
return strServer;
}
public void ProcessRequest(HttpContext context)
{
HttpWebRequest req = forwardRequest(context);
forwardResponse(context,req);
}
private HttpWebRequest forwardRequest(HttpContext context)
{
string strURL = makeURL(context);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(strURL);
req.Method = context.Request.HttpMethod;
NameValueCollection headers = context.Request.Headers;
req.Accept = headers.Get("Accept");
req.Expect = headers.Get("Expect");
req.ContentType = headers.Get("Content-Type");
string strModifiedSince = headers.Get("If-Modified-Since");
if (strModifiedSince != null && strModifiedSince.Length != 0)
req.IfModifiedSince = DateTime.Parse(strModifiedSince);
req.Referer = headers.Get("Referer");
req.UserAgent = headers.Get("User-Agent");
if (!req.Method.Equals("GET"))
{
CopyStreams(context.Request.InputStream,req.GetRequestStream());
}
return req;
}
private void forwardResponse(HttpContext context, HttpWebRequest req)
{
HttpWebResponse resp =null;
try
{
resp = (HttpWebResponse)req.GetResponse();
}
catch(WebException e)
{
resp = (HttpWebResponse)e.Response;
}
context.Response.StatusCode = (int)resp.StatusCode;
for (int i = 0; i < resp.Cookies.Count; i++)
{
Cookie c = resp.Cookies[i];
HttpCookie hc = new HttpCookie(c.Name, c.Value);
hc.Path = c.Path;
hc.Domain = getServer();
context.Response.Cookies.Add(hc);
}
context.Response.ContentType = resp.ContentType;
CopyStreams(resp.GetResponseStream(), context.Response.OutputStream);
}
private string makeURL(HttpContext context)
{
string strQuery = context.Request.Url.Query;
string[] arrParams = strQuery.Split('?','&');
StringBuilder resultingParams = new StringBuilder();
string strURL=null;
foreach(string strParam in arrParams )
{
string[] arrNameValue = strParam.Split('=');
if (!arrNameValue[0].Equals("RedirectURL"))
{
if (strParam.Length != 0)
{
if (resultingParams.Length != 0)
resultingParams.Append("&");
resultingParams.Append(strParam);
}
}
else if (arrNameValue.Length >1)
strURL = HttpUtility.UrlDecode(arrNameValue[1]);
}
if (strURL ==null)
throw new Exception("Invalid URL format. requestURL parameter is missing");
String sAppendChar = strURL.Contains("?") ? "&" : "?";
if (strURL.StartsWith("http:") || strURL.StartsWith("https:"))
{
String tmpURL = strURL + sAppendChar + resultingParams.ToString();
return tmpURL;
}
else
{
String tmpURL = getServer() + strURL + sAppendChar + resultingParams.ToString();
return tmpURL;
}
}
private void CopyStreams(Stream inStr,Stream outStr)
{
byte[] buf = new byte[4096];
try
{
do
{
int iRead = inStr.Read(buf,0,4096);
if (iRead == 0)
break;
outStr.Write(buf,0,iRead);
}
while (true);
}
finally
{
outStr.Close();
}
}
}
Using the BridgeServlet from link (http://pastebin.com/NibVnBLb) posted in previous answer did not work for us. In our web portal, embedding Oracle BI dashboard using BridgeServlet above, redirected us to OBI login page and console log showed incorrect resources(js/css) web links (local URL instead of OBIEE URL's).
Instead we used this class (with some minor adjustments) https://gist.github.com/rafaeltuelho/9376341#file-obieehttpservletbridge-java.
Tested with Java 11, Oracle Business Intelligence 12.2.1.4.0, WSDL v12 of OBIEE (http://OBIEE-server:port/analytics/saw.dll/wsdl/v12), with SSO disabled.
Here it is the BridgeServlet class:
package com.abs.bi;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class OBIEEBridge
*/
public class BridgeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public BridgeServlet() {
super();
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
this.processRequest(request, response);
} catch (Exception e) {
throw new ServletException(e);
}
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
this.processRequest(request, response);
} catch (Exception e) {
throw new ServletException(e);
}
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpURLConnection urlCon = forwardRequest(request);
forwardResponse(response, urlCon);
}
#SuppressWarnings("unchecked")
private String decodeURL(HttpServletRequest request) {
StringBuffer bufURL = new StringBuffer("");
Map<String, String[]> params = request.getParameterMap();
String[] arrURL = params.get("RedirectURL");
String strURL = arrURL == null || arrURL.length == 0 ? null : arrURL[0];
bufURL.append(strURL);
int nQIndex = strURL.lastIndexOf('?');
if (params != null && !params.isEmpty()) {
bufURL.append(((nQIndex >= 0) ? "&" : "?"));
Set<String> keys = params.keySet();
Iterator<String> it = keys.iterator();
while (it.hasNext()) {
try {
String strKey = it.next();
if (strKey.equalsIgnoreCase("RedirectURL")) {
continue;
}
String strEncodedKey = URLEncoder.encode(strKey, "UTF-8");
String[] paramValues = params.get(strKey);
for (String paramValue : paramValues) {
bufURL.append(strEncodedKey);
bufURL.append("=");
bufURL.append(URLEncoder.encode(paramValue, "UTF-8"));
bufURL.append("&");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
bufURL.deleteCharAt(bufURL.length() - 1);
}
return bufURL.toString();
}
#SuppressWarnings("unchecked")
private HttpURLConnection forwardRequest(HttpServletRequest request) throws IOException {
String strURL = decodeURL(request);
String[] arrURL = strURL.split("&", 2);
String baseURL = arrURL[0];
URL url = new URL(baseURL);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
String strMethod = request.getMethod();
con.setRequestMethod(strMethod);
Enumeration<String> en = request.getHeaderNames();
String strHeader;
while (en.hasMoreElements()) {
strHeader = en.nextElement();
String strHeaderValue = request.getHeader(strHeader);
con.setRequestProperty(strHeader, strHeaderValue);
}
// is not a HTTP GET request
if (strMethod.compareTo("GET") != 0) {
con.setDoOutput(true);
con.setDoInput(true);
con.setUseCaches(false);
DataOutputStream forwardStream = new DataOutputStream(con.getOutputStream());
try {
String urlParameters = arrURL[1];
forwardStream.writeBytes(urlParameters);
forwardStream.flush();
} finally {
forwardStream.close();
}
}
return con;
}
private void forwardResponse(HttpServletResponse response, HttpURLConnection con) throws IOException {
int nContentLen = -1;
String strKey;
String strValue;
try {
response.setStatus(con.getResponseCode());
for (int i = 1; true; ++i) {
strKey = con.getHeaderFieldKey(i);
strValue = con.getHeaderField(i);
if (strKey == null) {
break;
}
if (strKey.equals("Content-Length")) {
nContentLen = Integer.parseInt(con.getHeaderField(i));
continue;
}
if (strKey.equalsIgnoreCase("Connection") || strKey.equalsIgnoreCase("Server")
|| strKey.equalsIgnoreCase("Transfer-Encoding") || strKey.equalsIgnoreCase("Content-Length")) {
continue; // skip certain headers
}
if (strKey.equalsIgnoreCase("Set-Cookie")) {
String[] cookieStr1 = strValue.split(";");
String[] cookieStr2 = cookieStr1[0].split("=");
// String[] cookieStr3 = cookieStr1[1].split("=");
/*
* Change the Set-Cookie HTTP Header to remove the 'path' attribute. Thus the
* browser can accept the ORA_BIPS_NQID cookie from Oracle BI Server
*/
Cookie c = new Cookie(cookieStr2[0], cookieStr2[1]);
c.setPath("/");
response.addCookie(c);
} else {
response.setHeader(strKey, strValue);
}
}
copyStreams(con.getInputStream(), response.getOutputStream(), nContentLen);
} finally {
response.getOutputStream().close();
con.getInputStream().close();
}
}
private void copyStreams(InputStream inputStream, OutputStream forwardStream, int nContentLen) throws IOException {
byte[] buf = new byte[1024];
int nCount = 0;
int nBytesToRead = 1024;
int nTotalCount = 0;
do {
if (nContentLen != -1)
nBytesToRead = nContentLen - nTotalCount > 1024 ? 1024 : nContentLen - nTotalCount;
if (nBytesToRead == 0)
break;
// try to read some bytes from src stream
nCount = inputStream.read(buf, 0, nBytesToRead);
if (nCount < 0)
break;
nTotalCount += nCount;
// try to write some bytes in target stream
forwardStream.write(buf, 0, nCount);
} while (true);
}
}
AbsServiceUtils which contains SAWSessionService and HtmlViewService web service calls to Oracle BI server:
package com.abs.bi;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspWriter;
import oracle.bi.web.soap.AuthResult;
import oracle.bi.web.soap.HtmlViewService;
import oracle.bi.web.soap.HtmlViewServiceSoap;
import oracle.bi.web.soap.ReportHTMLLinksMode;
import oracle.bi.web.soap.ReportHTMLOptions;
import oracle.bi.web.soap.ReportRef;
import oracle.bi.web.soap.SAWLocale;
import oracle.bi.web.soap.SAWSessionParameters;
import oracle.bi.web.soap.SAWSessionService;
import oracle.bi.web.soap.SAWSessionServiceSoap;
import oracle.bi.web.soap.StartPageParams;
public class AbsServiceUtils {
private AbsServiceUtils() {
}
public static URL buildWsdlUrl() throws MalformedURLException {
return new URL(IAbsService.BASEWSDLURL);
}
public static void writeBiContent(HttpServletRequest request, JspWriter out, String biReport) throws IOException {
String userAgent = request.getHeader("User-Agent");
Locale userLocale = request.getLocale();
String bridgeServletContextPath = request.getContextPath() + "/bridgeservlet";
String reportHtml = writeBiContent(biReport, userAgent, userLocale, bridgeServletContextPath);
if (out != null) {
out.println(reportHtml);
}
}
public static String writeBiContent(String biReport, String userAgent, Locale userLocale,
String bridgeServletContextPath) throws MalformedURLException {
HtmlViewService htmlViewService = new HtmlViewService(buildWsdlUrl());
HtmlViewServiceSoap htmlClient = htmlViewService.getHtmlViewService();
SAWSessionService sAWSessionService = new SAWSessionService(buildWsdlUrl());
SAWSessionServiceSoap myPort = sAWSessionService.getSAWSessionServiceSoap();
SAWSessionParameters sessionparams = new SAWSessionParameters();
sessionparams.setUserAgent(userAgent);
SAWLocale sawlocale = new SAWLocale();
sawlocale.setLanguage(userLocale.getLanguage());
sawlocale.setCountry(userLocale.getCountry());
sessionparams.setLocale(sawlocale);
sessionparams.setAsyncLogon(false);
AuthResult result = myPort.logonex(IAbsService.BIUSERNAME, IAbsService.BIPASSWORD, sessionparams);
String sessionID = result.getSessionID();
List<String> keepAliveSessionList = new ArrayList<>(1);
keepAliveSessionList.add(sessionID);
myPort.keepAlive(keepAliveSessionList);
StartPageParams spparams = new StartPageParams();
spparams.setDontUseHttpCookies(true);
String pageID = htmlClient.startPage(spparams, sessionID);
/**
* This method will set the path to the servlet which will act like a bridge to
* retrieve all the OBIEE resources like the javascript, CSS and the report.
*/
if (bridgeServletContextPath != null) {
htmlClient.setBridge(bridgeServletContextPath, sessionID);
}
ReportHTMLOptions htmlOptions = new ReportHTMLOptions();
htmlOptions.setEnableDelayLoading(false);
htmlOptions.setLinkMode(ReportHTMLLinksMode.IN_PLACE.value());
ReportRef reportref = new ReportRef();
reportref.setReportPath(IAbsService.BIROOTPATH + biReport);
StartPageParams startpageparams = new StartPageParams();
startpageparams.setDontUseHttpCookies(false);
htmlClient.addReportToPage(pageID, biReport.replace(" ", ""), reportref, null, null, htmlOptions, sessionID);
String reportHtml = htmlClient.getHeadersHtml(pageID, sessionID);
reportHtml = reportHtml + htmlClient.getHtmlForReport(pageID, biReport.replace(" ", ""), sessionID);
reportHtml = reportHtml + htmlClient.getCommonBodyHtml(pageID, sessionID);
return reportHtml;
}
}
IAbsService:
package com.abs.bi;
public interface IAbsService {
public static final String BASEWSDLURL = "http://<OracleBIServer:port>/analytics/saw.dll/wsdl/v12";
public static final String BIUSERNAME = "USER";
public static final String BIPASSWORD = "PASS";
public static final String BIROOTPATH = "/shared/sharedfolder/";
public static final String BIREPORTNAME = "report";
}
Use the link http://pastebin.com/NibVnBLb to check out the bridge code for java. Hope this might be helful.
When I execute a CalendarService.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer()); I get an OAuthException 401 Error Unknown authorization header.
I'm using GWT+GAE I don't know why I'm receiving this error, oauthParameters seem to be OK.
I get user login on
loginService.login
I check if I have
the authentication already on
oauthService.checkOauthTokenSecret
If not, I'll do a redirect to Google
Aproval page for GCalendar
permission
I get querystring
returned by Google and I get Access
Token and Access Token Secret and
set it to the user entity for later
use on oauthService.upgradeLogin.
And trying to get calendars on
oauthService.getPublicCalendars.
I'm using MVP pattern with mvp4g framework, sorry if is a bit confusing 0:-)
Any idea why I'm receiving 401 error? I think is something about I'm going up & down through client and server and external pages... and something is missing :-( but all parameters seem to be correctly fullfilled.
Client side
public void onStart(){
GWT.log("onStart");
loginService.login(GWT.getHostPageBaseURL(), new AsyncCallback<LoginInfo>() {
#Override
public void onSuccess(LoginInfo result) {
Common.loginInfo = result;
if(Common.loginInfo.isLoggedIn()) {
oauthService.checkOauthTokenSecret(new AsyncCallback<String>() {
#Override
public void onSuccess(String result) {
if (result == null){
eventBus.OauthLogin();
}else{
oauthService.upgradeLogin(Window.Location.getQueryString(),Common.loginInfo, new AsyncCallback<LoginInfo>() {
#Override
public void onSuccess(LoginInfo result) {
Common.loginInfo = result;
getCitas();
}
#Override public void onFailure(Throwable caught) {
Common.handleError(caught);
}
});
}
}
#Override public void onFailure(Throwable caught) {
Common.handleError(caught);
}
});
}else{
eventBus.LoadLogin();
}
}
#Override public void onFailure(Throwable caught) {
Common.handleError(caught);
}
});
}
Server Side
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import com.google.gdata.client.authn.oauth.GoogleOAuthHelper;
import com.google.gdata.client.authn.oauth.GoogleOAuthParameters;
import com.google.gdata.client.authn.oauth.OAuthException;
import com.google.gdata.client.authn.oauth.OAuthHmacSha1Signer;
import com.google.gdata.client.authn.oauth.OAuthParameters;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.util.ServiceException;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.rdt.citas.client.OAuthoritzationService;
import com.rdt.citas.client.shared.LoginInfo;
public class OAuthoritzationServiceImpl extends RemoteServiceServlet
implements OAuthoritzationService {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final Logger log = Logger.getLogger(OAuthoritzationServiceImpl.class.getName());
private static String KEY_PARAM = "oauth_consumer_key";
private static String SECRET_PARAM = "oauth_consumer_secret";
private static String SCOPE_PARAM = "scope_calendars";
private static String CALLBACK_PARAM = "oauth_callback";
public String checkOauthTokenSecret(){
ServletContext context = this.getServletContext();
getOauthParams(context);
return (String) this.getThreadLocalRequest().getSession().getAttribute("oauthTokenSecret");;
}
public String getApprovalOAuthPageURL() throws IOException{
ServletContext context = this.getServletContext();
getOauthParams(context);
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(getFromSession(KEY_PARAM));
oauthParameters.setOAuthConsumerSecret(getFromSession(SECRET_PARAM));
oauthParameters.setScope(getFromSession(SCOPE_PARAM));
oauthParameters.setOAuthCallback(getFromSession(CALLBACK_PARAM));
GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
try {
oauthHelper.getUnauthorizedRequestToken(oauthParameters);
String approvalPageUrl = oauthHelper.createUserAuthorizationUrl(oauthParameters);
String oauthTokenSecret = oauthParameters.getOAuthTokenSecret();
this.getThreadLocalRequest().getSession().setAttribute("oauthTokenSecret", oauthTokenSecret);
return approvalPageUrl;
} catch (OAuthException e) {
log.log(Level.WARNING,e.toString());
return "";
} finally{
}
}
public LoginInfo upgradeLogin(String queryString, LoginInfo login){
// receiving '?key1=value1&key2=value2
queryString = queryString.substring(1, queryString.length());
String k = getFromSession(KEY_PARAM);
String s = getFromSession(SECRET_PARAM);
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(k);
oauthParameters.setOAuthConsumerSecret(s);
String oauthTS = (String) this.getThreadLocalRequest().getSession().getAttribute("oauthTokenSecret");//oauthParameters.getOAuthTokenSecret();
oauthParameters.setOAuthTokenSecret(oauthTS);
GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
oauthHelper.getOAuthParametersFromCallback(queryString,oauthParameters);
login.setQueryStringTokens(queryString);
login.setAccessTokenSecret(oauthTS);
try {
String accesToken = oauthHelper.getAccessToken(oauthParameters);
login.setTokenSecret(accesToken);
} catch (OAuthException e) {
log.log(Level.WARNING,e.toString());
}
return login;
}
public ArrayList<String> getPublicCalendars(String accessToken, String accessTokenSecret){
ArrayList<String> result = new ArrayList<String>();
CalendarFeed calendarResultFeed = null;
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(getFromSession(KEY_PARAM));
oauthParameters.setOAuthConsumerSecret(getFromSession(SECRET_PARAM));
oauthParameters.setOAuthToken(accessToken);
oauthParameters.setOAuthTokenSecret(accessTokenSecret);
oauthParameters.setOAuthType(OAuthParameters.OAuthType.THREE_LEGGED_OAUTH);
oauthParameters.setScope(getFromSession(SCOPE_PARAM));
CalendarService myService = new CalendarService("exampleCo-exampleApp-1");
try {
myService.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());
URL calendarFeedUrl = new URL("https://www.google.com/calendar/feeds/default/owncalendars/full");
calendarResultFeed = myService.getFeed(calendarFeedUrl, CalendarFeed.class);
} catch (OAuthException e) {
log.info("OAuthException");
log.log(Level.WARNING,e.toString());
e.printStackTrace();
} catch (MalformedURLException e) {
log.info("MalformedURLException");
log.log(Level.WARNING,e.toString());
e.printStackTrace();
} catch (IOException e) {
log.info("IOException");
log.log(Level.WARNING,e.toString());
e.printStackTrace();
} catch (ServiceException e) {
log.info("ServiceException");
log.log(Level.WARNING,e.toString());
e.printStackTrace();
}
if (calendarResultFeed != null && calendarResultFeed.getEntries() != null) {
for (int i = 0; i < calendarResultFeed.getEntries().size(); i++) {
CalendarEntry entry = calendarResultFeed.getEntries().get(i);
result.add(entry.getTitle().getPlainText());
}
}
return result;
}
private void getOauthParams(ServletContext context) {
this.getThreadLocalRequest().getSession()
.setAttribute(KEY_PARAM, context.getInitParameter(KEY_PARAM));
this.getThreadLocalRequest().getSession()
.setAttribute(SECRET_PARAM, context.getInitParameter(SECRET_PARAM));
this.getThreadLocalRequest().getSession()
.setAttribute(SCOPE_PARAM, context.getInitParameter(SCOPE_PARAM));
this.getThreadLocalRequest().getSession()
.setAttribute(CALLBACK_PARAM, context.getInitParameter(CALLBACK_PARAM));
}
private String getFromSession(String param){
return (String) this.getThreadLocalRequest().getSession().getAttribute(param);
}
}
I have recently been working with oAuth. Inside upgradeLogin(...) when you are upgrading to an access token you are not fetching the respective access token secret.
The access token secret following the getAccessToken() request is different to the access token secret before the request. You are currently setting the access token secret (via login.setAccessTokenSecret(oauthTS)), it is the pre-updated access token secret value you are using. You need to set it to the access token secret value returned after the update request:
String accesToken = oauthHelper.getAccessToken(oauthParameters);
String accesTokenSecret = oauthParameters.getOAuthTokenSecret();
login.setTokenSecret(accesToken);
login.setAccessTokenSecret(accesTokenSecret);
You also probably want to store this updated token/secret pair somewhere. It is this value of access token secret that should then to be used inside getPublicCalendars(...) in the line:
oauthParameters.setOAuthTokenSecret(accessTokenSecret);
The post update access token/secret pair is long-lived and can therefore be re-used (without needing to update it again) until such time as it is revoked.
Incidentally I found the oAuth Playground Tool useful in diagnosing my problems.
I hope this helps,