package vandy.mooc.model.services;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import vandy.mooc.common.Utils;
import vandy.mooc.model.aidl.AcronymExpansion;
import vandy.mooc.model.aidl.AcronymRequest;
import vandy.mooc.model.aidl.AcronymResults;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
/**
* @class AcronymServiceAsync
*
* @brief This class uses asynchronous AIDL interactions to expand
* acronyms via an Acronym Web service. The AcronymModel that
* binds to this Service will receive an IBinder that's an
* instance of AcronymRequest, which extends IBinder. The
* AcronymModel can then interact with this Service by making
* one-way method calls on the AcronymRequest object asking
* this Service to lookup the Acronym's meaning, passing in an
* AcronymResults object and the Acronym string. After the
* lookup is finished, this Service sends the Acronym results
* back to the AcronymModel by calling sendResults() on the
* AcronymResults object.
*
* AIDL is an example of the Broker Pattern, in which all
* interprocess communication details are hidden behind the
* AIDL interfaces.
*/
public class AcronymServiceAsync extends AcronymServiceBase {
/**
* Reference to the ExecutorService that manages a pool of
* threads. We need this feature since Android's Binder framework
* executes oneway methods from a client in a single thread rather
* than a pool of thread.
*/
private ExecutorService mExecutorService;
/**
* Factory method that makes an Intent used to start the
* AcronymServiceAsync when passed to bindService().
*
* @param context
* The context of the calling component.
*/
public static Intent makeIntent(Context context) {
return new Intent(context,
AcronymServiceAsync.class);
}
/**
* Called when a client (e.g., AcronymModel) calls bindService()
* with the proper Intent. Returns the implementation of
* AcronymRequest, which is implicitly cast as an IBinder.
*/
@Override
public IBinder onBind(Intent intent) {
return mAcronymRequestImpl;
}
/**
* Hook method called when the Service is created.
*/
@Override
public void onCreate() {
// Call up to the super onCreate() method to perform its
// initialization operations.
super.onCreate();
// Create an ExecutorService that manages a pool of threads.
mExecutorService = Executors.newCachedThreadPool();
}
/**
* Hook method called when the last client unbinds from the
* Service.
*/
@Override
public void onDestroy() {
// Immediately shutdown the ExecutorService.
mExecutorService.shutdownNow();
// Call up to the super onCreate() method to perform its
// destruction operations.
super.onDestroy();
}
/**
* The concrete implementation of the AIDL AcronymRequest
* interface, which extends the Stub class that implements
* AcronymRequest, thereby allowing Android to handle calls across
* process boundaries. This method runs in a separate Thread as
* part of the Android Binder framework.
*
* This implementation plays the role of Invoker in the Broker
* Pattern.
*/
private final AcronymRequest.Stub mAcronymRequestImpl =
new AcronymRequest.Stub() {
/**
* Implement the AIDL AcronymRequest expandAcronym()
* method, which forwards to getAcronymResults() to obtain
* the results and then sends these results back to the
* AcronymModel via a callback.
*/
@Override
public void expandAcronym(final String acronym,
final AcronymResults callback)
throws RemoteException {
final Runnable getCurrentAcronymRunnable = new Runnable() {
public void run() {
try {
// Call the Acronym Web service to get the
// list of possible expansions of the
// designated location.
final List<AcronymExpansion> acronymExpansions =
getAcronymExpansions(acronym);
if (acronymExpansions != null) {
Log.d(TAG, ""
+ acronymExpansions.size()
+ " result(s) for Acronym: "
+ acronym);
// Invoke a one-way callback to send
// list of Acronym expansions back to
// the client.
callback.sendResults(acronymExpansions);
} else {
Log.d(TAG,
"No expansion for \""
+ acronym
+ "\" found");
// Invoke a one-way callback to send
// an error message back to the
// client.es
callback.sendError("No expansion for \""
+ acronym
+ "\" found");
}
} catch (Exception e) {
Log.d(TAG,
"getCurrentAcronym() "
+ e);
}
}
};
// Determine if we're on the UI thread or not.
if (Utils.runningOnUiThread())
// Execute getCurrentAcronymRunnable in a separate
// thread if this service has been configured to
// be collocated with an Activity.
mExecutorService.execute(getCurrentAcronymRunnable);
else
// Run the getCurrentAcronymRunnable in the pool
// thread if this service has been configured to
// run in its own process.
getCurrentAcronymRunnable.run();
}
};
}