Java tutorial
/* * Copyright (C) 2014 TU Darmstadt, Hessen, Germany. * Department of Computer Science Databases and Distributed Systems * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * */ package de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.transformationmanager; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import org.osgi.framework.Bundle; import android.app.Service; 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.Binder; import android.os.IBinder; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.AbstractChannel; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.Event; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.localmanagement.EventTransformationRequest; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.localmanagement.EventTransformationResponse; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.management.Announcement; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.management.StopProducer; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.transformationmanager.database.LocalTransformationDBMS; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.transformationmanager.database.Transformation; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.transformationmanager.services.FelixService; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.transformationmanager.services.FelixService.FelixServiceBinder; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.transformationmanager.services.IFelixServiceBinder; import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.transformationmanager.services.WebRequestService; /** * @author Christian Seeger * */ public class TransformationManager extends Service { /** For Debugging */ private static final String TAG = "TransformationManager"; private static boolean D = false; // receives management events such as transformation requests private ManagementReceiver mManagementReceiver; private TransformationDownloadReceiver mDownloadReceiver; // database including already downloaded availableTransformations private LocalTransformationDBMS transformationDB; // web request channel private static String WEB_REQUEST_CHANNEL = "webRequestChannel"; public static String TM_SUCCUESSFUL_WEB_REQUEST = "tmSuccessfulWebRequest"; public static final String INTENT_EXTRA_TRANSFORMATION = "transformation"; // service binder to Felix OSGi service private IFelixServiceBinder felixServiceBinder; // list of available availableTransformations private ArrayList<Transformation> availableTransformations; // for transformation management (stopping transformations) private HashMap<String, List<Transformation>> requiredEventTypes; private HashMap<String, List<Transformation>> providedEventTypes; private LinkedList<Transformation> runningTransformations; private final IBinder mTransformationManagerBinder = new TransformationManagerBinder(); public class TransformationManagerBinder extends Binder { public Bundle[] getTransformations() { if (felixServiceBinder != null) { return felixServiceBinder.getTransformations(); } else return null; } public void deleteTransformation(long name) { if (felixServiceBinder != null) felixServiceBinder.removeTransformation(name); if (transformationDB != null) transformationDB.deleteTransformation(name); availableTransformations = transformationDB.getAvailableTransformations(); } public void stopTransformation(long name) { if (felixServiceBinder != null) felixServiceBinder.stopTransformation(name); } public void startTransformation(long name) { if (felixServiceBinder != null) felixServiceBinder.startTransformation(name); } } @Override public IBinder onBind(Intent arg0) { return mTransformationManagerBinder; } public void onUnbind() { } @Override public void onCreate() { if (D) Log.i(TAG, "TransformationManager created."); // start Felix OSGi service Intent intent = new Intent(this, FelixService.class); bindService(intent, felixServiceConnection, Context.BIND_AUTO_CREATE); // register local management receiver mManagementReceiver = new ManagementReceiver(); LocalBroadcastManager.getInstance(this).registerReceiver(mManagementReceiver, new IntentFilter(AbstractChannel.LOCAL_MANAGEMENT)); LocalBroadcastManager.getInstance(this).registerReceiver(mManagementReceiver, new IntentFilter(WEB_REQUEST_CHANNEL)); // register transformation download receiver mDownloadReceiver = new TransformationDownloadReceiver(); LocalBroadcastManager.getInstance(this).registerReceiver(mDownloadReceiver, new IntentFilter(TM_SUCCUESSFUL_WEB_REQUEST)); // initialize database this.transformationDB = new LocalTransformationDBMS(getApplicationContext()); //TODO better solution transformationDB.open(); availableTransformations = transformationDB.getAvailableTransformations(); if (D) printLocalTransformations(); // initialize management lists providedEventTypes = new HashMap<String, List<Transformation>>(); requiredEventTypes = new HashMap<String, List<Transformation>>(); runningTransformations = new LinkedList<Transformation>(); } @Override public void onDestroy() { Log.i(TAG, "TransformationManager destroyed."); // stop all transformations for (Transformation transformation : runningTransformations) { if (D) Log.d(TAG, "Stop transformation: " + transformation.getTransformationName()); if (felixServiceBinder != null) felixServiceBinder.stopTransformation(transformation.getBundleId()); } // stop felix service unbindService(felixServiceConnection); // unregister local management receiver LocalBroadcastManager.getInstance(this).unregisterReceiver(mManagementReceiver); LocalBroadcastManager.getInstance(this).unregisterReceiver(mDownloadReceiver); // close database transformationDB.close(); } /** Management Receiver */ private class ManagementReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // extract event Event evt = intent.getParcelableExtra(Event.PARCELABLE_EXTRA_EVENT); // handle event transformation requests if (evt instanceof EventTransformationRequest) { incomingTransformationRequest((EventTransformationRequest) evt); } else if (evt instanceof Announcement) { if (((Announcement) evt) .getAnnouncement() == Announcement.UNADVERTISMENT_EVENT_TYPE_NOT_LONGER_AVAILABLE) incomingUnadvertisement(((Announcement) evt).getTransmittedEventType()); } else if (evt instanceof StopProducer) { incomingStopProducer((StopProducer) evt); } } }; private void incomingUnadvertisement(String eventType) { if (D) Log.d(TAG, "Handle unadvertisement for " + eventType); // Check whether transformations require this event type List<Transformation> transformations = requiredEventTypes.get(eventType); if (transformations != null) deleteTransformationsFromManagementLists(transformations); } public void incomingStopProducer(StopProducer stop) { if (D) Log.d(TAG, "Handle stop producer for " + stop.getShortEventType()); // Check whether a transformation produces this event type List<Transformation> transformations = providedEventTypes.get(stop.getStopEventType()); if (transformations != null) deleteTransformationsFromManagementLists(transformations); } private void deleteTransformationsFromManagementLists(List<Transformation> transformations) { // stop corresponding transformations for (Transformation transformation : transformations) { // delete from running transformations runningTransformations.remove(transformation); // stop transformation if (felixServiceBinder != null) felixServiceBinder.stopTransformation(transformation.getBundleId()); // delete required event types List<String> reqTypes = transformation.getRequiredEventTypes(); for (String type : reqTypes) { requiredEventTypes.get(type).remove(transformation); } // delete produced event type providedEventTypes.get(transformation.getProducedEventType()).remove(transformation); } } private void addToRunningTransformations(Transformation transformation) { // Add to running transformations runningTransformations.add(transformation); // Add to list of provided event types List<Transformation> producers = providedEventTypes.get(transformation.getProducedEventType()); if (producers != null) { producers.add(transformation); } else { producers = new ArrayList<Transformation>(); producers.add(transformation); } providedEventTypes.put(transformation.getProducedEventType(), producers); // Add to list of required event types List<String> requiredTypes = transformation.getRequiredEventTypes(); for (String eventType : requiredTypes) { List<Transformation> transformations = requiredEventTypes.get(eventType); if (transformations != null) { transformations.add(transformation); } else { transformations = new ArrayList<Transformation>(); transformations.add(transformation); } requiredEventTypes.put(eventType, transformations); } } /** Transformation Download Receiver */ private class TransformationDownloadReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { EventTransformationResponse response = intent.getParcelableExtra(Event.PARCELABLE_EXTRA_EVENT); if (response.isTransformationFound()) { Transformation transformation = intent.getParcelableExtra(INTENT_EXTRA_TRANSFORMATION); if (D) Log.d(TAG, "Transformation was found: " + transformation.getTransformationName()); // Add new and already started transformation to DB if (transformationDB != null) transformationDB.addTransformation(transformation.getBundleId(), transformation.getTransformationName(), transformation.getProducedEventType(), transformation.getRequiredEventTypes(), transformation.getTransformationCost()); // Add transformation to list of availableTransformations availableTransformations.add(transformation); // Add to running transformations addToRunningTransformations(transformation); } else { if (D) Log.d(TAG, "No transformation found."); //TODO } } }; /** * @param transformationRequest */ private void incomingTransformationRequest(EventTransformationRequest transformationRequest) { if (D) printTransformationRequest(transformationRequest); // skip request if no event types are advertised if (transformationRequest.getAdvertisedEvents().length == 0) return; // is transformation stored locally? Transformation trans = getLocalTransformation(transformationRequest); if (trans != null) { if (felixServiceBinder != null) { felixServiceBinder.startTransformation(trans.getBundleId()); addToRunningTransformations(trans); } else { if (D) Log.e(TAG, "not connected to felix service."); } // if not, query remote repository } else { Log.i(TAG, "Query remote repository for transformation to: " + transformationRequest.getEventSubscription()); Intent intentRequest = new Intent(getApplicationContext(), WebRequestService.class); intentRequest.putExtra(Event.PARCELABLE_EXTRA_EVENT, transformationRequest); getApplicationContext().startService(intentRequest); } } /** * Queries for local transformation that is applicable and has the lowest costs. * @param transformationRequest containing the available event types and the requested event types. * @return transformation. <code>null</code> if no transformation was found. */ private Transformation getLocalTransformation(EventTransformationRequest transformationRequest) { //TODO make it efficient ArrayList<String> list = new ArrayList<String>(); String[] advertisedEvents = transformationRequest.getAdvertisedEvents(); for (int i = 0; i < advertisedEvents.length; i++) { list.add(advertisedEvents[i]); } // Find a transformation Transformation bestTransformation = null; int costs = Integer.MAX_VALUE; int tempCosts; for (Transformation trans : availableTransformations) { tempCosts = trans.isTransformationApplicable(list, transformationRequest.getEventSubscription()); // if the transformation is applicable and the costs are lower than before, store if (tempCosts != -1 && tempCosts < costs) { costs = tempCosts; bestTransformation = trans; } } return bestTransformation; } private ServiceConnection felixServiceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { felixServiceBinder = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { FelixServiceBinder binder = ((FelixServiceBinder) service); felixServiceBinder = (IFelixServiceBinder) binder.getService(); } }; /* ============================================================================= helper methods ============================================================================= */ /** * Prints a transformation request. * @param req event transformation request */ private void printTransformationRequest(EventTransformationRequest req) { String out = "Incoming event transformation request for event type\n"; out += req.getEventSubscription(); out += "\nhaving the following event types available:"; for (String type : req.getAdvertisedEvents()) { out += "\n" + type; } Log.d(TAG, out); } /** * Returns only the last part after the "." of an event type. * @return Short event type */ public String getShortEventType(String eventType) { if (eventType.contains("myhealthassistant.event.")) { return eventType.substring(eventType.lastIndexOf("myhealthassistant.event.") + 24, eventType.length()); } else { return eventType; } } private void printLocalTransformations() { String out = "List of available availableTransformations\n"; out += "ID | Name\n"; for (Transformation trans : availableTransformations) { out += trans.getBundleId() + " | " + trans.getTransformationName() + "\n"; } Log.d(TAG, out); } }