/*
* Copyright (C) 2012 Eyal LEZMY (http://www.eyal.fr)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fr.eyal.lib.data.service;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.http.Header;
import org.apache.http.client.CookieStore;
import org.apache.http.cookie.CookieSpecRegistry;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.util.Log;
import fr.eyal.lib.data.model.BusinessObjectDAO;
import fr.eyal.lib.data.model.ResponseBusinessObjectDAO;
import fr.eyal.lib.data.processor.ProcessorResponseHandler;
import fr.eyal.lib.data.service.model.BusinessResponse;
import fr.eyal.lib.data.service.model.ComplexOptions;
import fr.eyal.lib.data.service.model.DataLibRequest;
import fr.eyal.lib.data.service.model.DataLibResponse;
import fr.eyal.lib.service.MultiThreadService;
import fr.eyal.lib.util.FileManager;
import fr.eyal.lib.util.Out;
@TargetApi(Build.VERSION_CODES.CUPCAKE)
public abstract class DataLibService extends MultiThreadService implements ProcessorResponseHandler {
private static final String TAG = "DataLibService";
protected static final int MAX_THREADS = 3;
//different Service's possible actions
public static final int COOKIES_FLUSH = 999999999;
//different information recieved by the Service
/**
* Intext extra content : Webservice type
*/
public static final String INTENT_EXTRA_PROCESSOR_TYPE = "processorType";
/**
* Intext extra content : Useragent to send
*/
public static final String INTENT_EXTRA_USER_AGENT = "userAgent";
/**
* Intext extra content : Webservice URL
*/
public static final String INTENT_EXTRA_URL = "url";
/**
* Intext extra content : parameters to send
*/
public static final String INTENT_EXTRA_PARAMS = "params";
/**
* Intext extra content : Webservice path
*/
public static final String INTENT_EXTRA_PATH = "path";
/**
* Intext extra content : web service data
*/
public static final String INTENT_EXTRA_DATA = "data";
/**
* Intext extra content : content type
*/
public static final String INTENT_EXTRA_CONTENT_TYPE = "contentType";
/**
* Intext extra content : options to add to the request
*/
public static final String INTENT_EXTRA_REQUEST_OPTION = "optionRequest";
/**
* Intext extra content : parsing type of the response
*/
public static final String INTENT_EXTRA_PARSE_TYPE = "parseType";
/**
* Intext extra content : complex option for the request
*/
public static final String INTENT_EXTRA_COMPLEX_OPTIONS = "complexOptions";
/**
* title of the cookies' header
*/
protected static final String COOKIE_HEADER_TITLE = "Set-Cookie";
protected ArrayList<Header> mHeaders; //Headers to send at every client request with NetworkConnection
public static CookieStore mCookies = null; //Headers to send at every client request with NetworkConnection
public static CookieSpecRegistry mCookiesSpec = null; //Headers returned by the server
/**
* Connectivity Manager to access to the network configuration
*/
protected ConnectivityManager mConnectivityManager;
public DataLibService() {
super(MAX_THREADS);
mHeaders = new ArrayList<Header>();
}
public DataLibService(final int maxThreads) {
super(maxThreads);
}
@Override
public void onCreate() {
mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
//we initialize the FileManager
FileManager.getInstance(getApplicationContext());
super.onCreate();
}
@SuppressWarnings("unchecked")
@Override
protected void onHandleIntent(final Intent intent) {
final int processorType = intent.getIntExtra(INTENT_EXTRA_PROCESSOR_TYPE, -1);
Out.d(TAG, "onHandleIntent");
// String userAgent = intent.getStringExtra(INTENT_EXTRA_USER_AGENT);
final DataLibRequest request = new DataLibRequest();
DataLibWebConfig.applyToRequest(request, DataLibWebConfig.getInstance()); //we apply a default configuration for the request
//we get the action data
request.url = intent.getStringExtra(INTENT_EXTRA_URL);
request.params = intent.getParcelableExtra(INTENT_EXTRA_PARAMS);
request.parseType = intent.getIntExtra(INTENT_EXTRA_PARSE_TYPE, DataLibRequest.PARSE_TYPE_SAX_XML);
//we eventually add the complex options
Object complexOptions = intent.getSerializableExtra(INTENT_EXTRA_COMPLEX_OPTIONS);
if(complexOptions instanceof ComplexOptions)
request.complexOptions = (ComplexOptions) complexOptions;
request.context = getApplicationContext();
//we get the options to apply
int option = intent.getIntExtra(INTENT_EXTRA_REQUEST_OPTION, DataLibRequest.OPTION_NO_OPTION);
DataLibWebConfig.applyToRequest(request, option, true);
//we add the intent
request.intent = intent;
try {
if (processorType == COOKIES_FLUSH)
this.flushCookies();
else {
//we launch the processor on a daughter class
launchProcessor(processorType, request);
}
} catch (final Exception e) {
Out.e(TAG, "Erreur", e);
final BusinessResponse response = new BusinessResponse();
response.status = BusinessResponse.STATUS_ERROR;
response.statusMessage = Log.getStackTraceString(e);
sendResult(request, response, response.status);
}
}
/**
* Function that flush the cookies stored inside the headers ArrayList
*/
private void flushCookies() {
for (final Header header : mHeaders) {
if (header.getName().equalsIgnoreCase(COOKIE_HEADER_TITLE))
mHeaders.remove(header);
}
}
/**
* Send the result of a request to the linked {@link ServiceHelper}
*
* @param request the request
* @param response the response
* @param code the status of the request
*/
protected void sendResult(final DataLibRequest request, final BusinessResponse response, final int code) {
Out.d(TAG, "sendResult");
final Intent intent = request.intent;
final ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra(INTENT_EXTRA_RECEIVER);
if (receiver != null) {
final Bundle b = new Bundle();
if (response != null && response.response != null) {
//if the Business Object have to be transmit inside the Bundle
if (request.isParcelableMethodEnabled())
b.putParcelable(ServiceHelper.RECEIVER_EXTRA_RESULT, response.response);
//we add the request id to the response
if (response.response instanceof ResponseBusinessObjectDAO) {
ResponseBusinessObjectDAO r = (ResponseBusinessObjectDAO) response.response;
b.putLong(ServiceHelper.RECEIVER_EXTRA_RESULT_ID, r._id);
} else {
//in case of no data cache, we set an invalid ID
b.putLong(ServiceHelper.RECEIVER_EXTRA_RESULT_ID, BusinessObjectDAO.ID_INVALID);
}
} else {
Out.e(TAG, "Unfined response");
}
//we copy the content of the response in the intent's bundle
b.putInt(ServiceHelper.RECEIVER_EXTRA_REQUEST_ID, intent.getIntExtra(INTENT_EXTRA_REQUEST_ID, -1));
b.putInt(ServiceHelper.RECEIVER_EXTRA_WEBSERVICE_TYPE, intent.getIntExtra(INTENT_EXTRA_PROCESSOR_TYPE, -1));
b.putInt(ServiceHelper.RECEIVER_EXTRA_RETURN_CODE, response.returnCode);
b.putInt(ServiceHelper.RECEIVER_EXTRA_RESULT_CODE, response.status);
b.putString(ServiceHelper.RECEIVER_EXTRA_RESULT_MESSAGE, response.statusMessage);
b.putParcelable(ServiceHelper.RECEIVER_EXTRA_REQUEST, request);
receiver.send(code, b);
}
}
@Override
public void handleProcessorResponse(final DataLibResponse response) {
final DataLibRequest request = response.request;
//we add the cookies to the service's headers
if (request.isConservingTheCookies()) {
//TODO CHECK THE COOKIE CONSERVATION
// final Header[] headers = response.headers;
//
// if (headers != null) {
// for (final Header header : headers) {
// //if we have to keep the cookie
// if (request.isConservingTheCookies() && header.getName().equalsIgnoreCase(COOKIE_HEADER_TITLE))
// mHeaders.add(header);
// }
// }
}
sendResult(request, response, response.status);
}
/**
* Function that implements the instantiation and the launching of the processor process. i-e. network requesting, parsing, ... and returning the
* {@link DataLibResponse} through {@link handleProcessorResponse} in the {@link DataLibService} class
*
* @param processorType type of response to handle
* @param request Request passed to the Service
*/
public abstract void launchProcessor(final int processorType, final DataLibRequest request);
}