/**
* Copyright (c) 2011, SOCIETIES Consortium (WATERFORD INSTITUTE OF TECHNOLOGY (TSSG), HERIOT-WATT UNIVERSITY (HWU), SOLUTA.NET
* (SN), GERMAN AEROSPACE CENTRE (Deutsches Zentrum fuer Luft- und Raumfahrt e.V.) (DLR), Zavod za varnostne tehnologije
* informacijske družbe in elektronsko poslovanje (SETCCE), INSTITUTE OF COMMUNICATION AND COMPUTER SYSTEMS (ICCS), LAKE
* COMMUNICATIONS (LAKE), INTEL PERFORMANCE LEARNING SOLUTIONS LTD (INTEL), PORTUGAL TELECOM INOVAÇÃO, SA (PTIN), IBM Corp.,
* INSTITUT TELECOM (ITSUD), AMITEC DIACHYTI EFYIA PLIROFORIKI KAI EPIKINONIES ETERIA PERIORISMENIS EFTHINIS (AMITEC), TELECOM
* ITALIA S.p.a.(TI), TRIALOG (TRIALOG), Stiftelsen SINTEF (SINTEF), NEC EUROPE LTD (NEC))
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.societies.android.platform.phongegap;
import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult;
import org.apache.cordova.api.PluginResult.Status;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.societies.android.api.css.manager.IServiceManager;
import org.societies.android.api.identity.util.RequestorUtils;
import org.societies.android.api.internal.privacytrust.IPrivacyPolicyManager;
import org.societies.android.api.internal.privacytrust.intent.PrivacyPolicyIntentHelper;
import org.societies.android.api.privacytrust.privacy.model.PrivacyException;
import org.societies.android.privacytrust.policymanagement.service.PrivacyPolicyManagerLocalService;
import org.societies.android.privacytrust.policymanagement.service.PrivacyPolicyManagerLocalService.LocalBinder;
import org.societies.api.internal.schema.privacytrust.privacyprotection.privacypolicymanagement.MethodType;
import org.societies.api.schema.identity.RequestorCisBean;
import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.RequestPolicy;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
/**
* PhoneGap plugin to use the privacy policy manager
* To show the Javascript API: use "mvn site" on this project, and go to target/doc folder
* @author Olivier Maridat (Trialog)
*/
public class PrivacyPolicyManagerPlugin extends Plugin {
private final static String TAG = PrivacyPolicyManagerPlugin.class.getSimpleName();
/** Callback to call */
public String methodName;
public JSONArray arguments;
public String callbackId;
/** Helpers */
protected Gson jsonHelper;
protected String clientPackage;
/** Local data */
private boolean pluginIsInit = false;
private boolean serviceIsInit = false;
private int nbOfCall = 0;
private IPrivacyPolicyManager privacyPolicyManagerService = null;
private ServiceReceiver pivacyPolicyManagerReceiver = null;
public PrivacyPolicyManagerPlugin() {
jsonHelper = new Gson();
}
/*
* (non-Javadoc)
* @see org.apache.cordova.api.Plugin#execute(java.lang.String, org.json.JSONArray, java.lang.String)
*/
@Override
public PluginResult execute(String methodName, JSONArray arguments, String callbackId) {
Log.d(TAG, "Execute: "+(null != methodName ? methodName : "Unknown method"));
Log.d(TAG, "Parameters: "+(null != arguments ? arguments.toString() : "No params"));
nbOfCall++;
// -- Plugin not initialized: initialize the plugin (it will be executed at the init end)
if (!pluginIsInit && null != methodName) {
return initPlugin(methodName, arguments, callbackId);
}
// -- Execute the plugin
return executePlugin(methodName, arguments, callbackId);
}
/**
* This method is called when the plugin is called (execution) but not yet initialized
*/
private PluginResult initPlugin(String methodName, JSONArray arguments, String callbackId) {
Log.d(TAG, "Plugin Called (first time: connect to service)");
clientPackage = this.ctx.getPackageName();
// - Inform the JS side: async mode
PluginResult result = new PluginResult(Status.NO_RESULT);
result.setKeepCallback(true);
// - Create the broadcast receiver
if (null == pivacyPolicyManagerReceiver) {
Log.d(TAG, "Listen intents for PrivacyPolicy");
pivacyPolicyManagerReceiver = new ServiceReceiver();
IntentFilter intentFilter = new IntentFilter() ;
intentFilter.addAction(IServiceManager.INTENT_SERVICE_STARTED_STATUS);
intentFilter.addAction(IPrivacyPolicyManager.INTENT_DEFAULT_ACTION);
intentFilter.addAction(MethodType.GET_PRIVACY_POLICY.name());
intentFilter.addAction(MethodType.UPDATE_PRIVACY_POLICY.name());
intentFilter.addAction(MethodType.DELETE_PRIVACY_POLICY.name());
intentFilter.addAction(MethodType.INFER_PRIVACY_POLICY.name());
this.ctx.getApplicationContext().registerReceiver(pivacyPolicyManagerReceiver, intentFilter);
}
// - Connect to the Android service
// Copy requested parameters
this.methodName = methodName;
this.arguments = arguments;
this.callbackId = callbackId;
// Connect
Intent serviceIntent = new Intent(this.ctx.getContext(), PrivacyPolicyManagerLocalService.class);
this.ctx.getContext().bindService(serviceIntent, androidServiceConnection, Context.BIND_AUTO_CREATE);
return result;
}
/**
* This method is called when the plugin is called (execution) and already initialized
*/
private PluginResult executePlugin(String methodName, JSONArray arguments, String callbackId) {
if (nbOfCall <= 0) {
nbOfCall = 0;
return null;
}
nbOfCall--;
Log.d(TAG, "Plugin Called");
// --- Save the callback
this.callbackId = callbackId;
// --- Prepare the result
PluginResult result = null;
try {
// -- Manage the relevant method
// - GET_PRIVACY_POLICY
if (methodName.equals(MethodType.GET_PRIVACY_POLICY.value())) {
result = executeGetPrivacyPolicy(arguments);
}
// -- Error: Unknown method name
else {
Log.d(TAG, "Invalid method name : "+methodName+" passed");
result = new PluginResult(Status.INVALID_ACTION);
}
}
catch (JsonSyntaxException e) {
Log.e(TAG, "JsonSyntaxException", e);
result = new PluginResult(Status.ERROR, "JsonSyntaxException");
result.setKeepCallback(false);
this.error(result, this.callbackId);
} catch (JSONException e) {
Log.e(TAG, "JSONException", e);
result = new PluginResult(Status.ERROR, "JSONException");
result.setKeepCallback(false);
this.error(result, this.callbackId);
} catch (PrivacyException e) {
Log.e(TAG, "PrivacyException", e);
result = new PluginResult(Status.ERROR, "PrivacyException");
result.setKeepCallback(false);
this.error(result, this.callbackId);
}
return result;
}
@Override
public void onDestroy() {
Log.d(TAG, "Destroyed");
// -- Close the broadcast receiver
if (null != pivacyPolicyManagerReceiver) {
Log.d(TAG, "Unregister from intents");
this.ctx.getContext().unregisterReceiver(pivacyPolicyManagerReceiver);
}
// -- Unlink with services
if (pluginIsInit) {
pluginIsInit = false;
serviceIsInit = false;
this.ctx.getContext().unbindService(androidServiceConnection);
}
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
/**
* Execute a getPrivacyPolicy
*/
private PluginResult executeGetPrivacyPolicy(JSONArray arguments) throws JsonSyntaxException, JSONException, PrivacyException {
// - Launch service method
RequestorCisBean owner = jsonHelper.fromJson(arguments.getString(0), RequestorCisBean.class);
Log.d(TAG, "Retrieving privacy policy from: "+RequestorUtils.toXmlString(owner));
// An other way to manage this
// JSONObject jsonRequestor = (JSONObject) arguments.get(0);
// RequestorCisBean owner = new RequestorCisBean();
// owner.setRequestorId(jsonRequestor.getString("requestorId"));
// owner.setCisRequestorId(jsonRequestor.getString("cisRequestId"));
privacyPolicyManagerService.getPrivacyPolicy(clientPackage, owner);
// - Inform the JS side: async mode
PluginResult result = new PluginResult(Status.NO_RESULT);
result.setKeepCallback(true);
this.success(result, callbackId);
return result;
}
/**
* Broadcast receiver to receive intents from Service methods
*/
private class ServiceReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Intent received: "+intent.getAction());
try {
// -- PrivacyPolicyManagerService started
if (intent.getAction().equals(IServiceManager.INTENT_SERVICE_STARTED_STATUS)) {
Log.d(TAG, "Service started message received: "+intent.getAction());
boolean ack = intent.hasExtra(IServiceManager.INTENT_RETURN_VALUE_KEY) && intent.getBooleanExtra(IServiceManager.INTENT_RETURN_VALUE_KEY, false);
boolean isPrivacyPolicyManager = intent.hasExtra("type") && "PrivacyPolicyManager".equals(intent.getStringExtra("type"));
// Execute the plugin
if (ack && isPrivacyPolicyManager) {
serviceIsInit = true;
if (pluginIsInit && serviceIsInit) {
executePlugin(methodName, arguments, callbackId);
}
}
return;
}
// -- Ack
boolean ack = intent.hasExtra(IPrivacyPolicyManager.INTENT_RETURN_STATUS_KEY) && intent.getBooleanExtra(IPrivacyPolicyManager.INTENT_RETURN_STATUS_KEY, false);
Log.d(TAG, "Privacy Response received: "+intent.getAction()+(ack ? " with success" : " with an error"));
// -- Get Privacy Policy
if (intent.getAction().equals(MethodType.GET_PRIVACY_POLICY.name())) {
JSONArray data = new JSONArray();
if(ack && intent.hasExtra(IPrivacyPolicyManager.INTENT_RETURN_VALUE_KEY)) {
RequestPolicy privacyPolicy = (RequestPolicy) intent.getSerializableExtra(IPrivacyPolicyManager.INTENT_RETURN_VALUE_KEY); // TODO Parcelable
String jsonPrivacyPolicy = jsonHelper.toJson(privacyPolicy, RequestPolicy.class);
Log.d(TAG, "Privacy policy retrieved: "+jsonPrivacyPolicy);
// data.put(PrivacyPolicyIntentHelper.RESULT_PRIVACY_POLICY, jsonPrivacyPolicy);
data.put(jsonPrivacyPolicy);
}
// -- Send data
PluginResult result = new PluginResult(Status.OK, data);
result.setKeepCallback(false);
success(result, callbackId);
}
else {
Log.e(TAG, "But this action is unknown, or data are missing");
// -- Send data
PluginResult result = new PluginResult(Status.INVALID_ACTION, "Response received: "+intent.getAction()+", but this action is unknown, or data are missing.");
result.setKeepCallback(false);
error(result, callbackId);
}
}
catch (Exception e) {
PluginResult result = new PluginResult(Status.ERROR, "Error during the JSON parsing of the result");
result.setKeepCallback(false);
error(result, callbackId);
}
}
}
private ServiceConnection androidServiceConnection = new ServiceConnection()
{
public void onServiceDisconnected(ComponentName name) {
pluginIsInit = false;
}
public void onServiceConnected(ComponentName name, IBinder service) {
LocalBinder binder = (LocalBinder) service;
privacyPolicyManagerService = (IPrivacyPolicyManager) binder.getService();
pluginIsInit = true;
// Wait for the init of the plugin
if (pluginIsInit && serviceIsInit) {
executePlugin(methodName, arguments, callbackId);
}
}
};
}