de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.messagehandler.MessageHandler.java Source code

Java tutorial

Introduction

Here is the source code for de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.messagehandler.MessageHandler.java

Source

/* 
 * 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.messagehandler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.commontools.EventUtils;
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.Advertisement;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.management.Announcement;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.management.JSONDataExchange;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.management.ManagementEvent;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.management.StartProducer;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.management.StopProducer;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.management.Subscription;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.management.Unadvertisement;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.management.Unsubscription;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.notifications.NotificationEvent;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.sensorreadings.SensorReadingEvent;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.transformationmanager.database.LocalTransformationDB;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services.transformationmanager.database.LocalTransformationDBMS;

public class MessageHandler extends Service {

    /** For Debugging */
    private static final String TAG = "MessageHandler";
    private static boolean D = false;

    private static final String TAG_ANNOUNCEMENT = "Announcement MessageHandler";
    private static boolean D_ANNOUNCEMENT = false;

    private static final String TAG_ROUTING = "MessageHandler Routing";
    private static boolean D_ROUTING = true;

    DBAdapterSubscriptions db; // = new DBAdapterSubscriptions(this);
    private HashMap<String, List<String>> subscriberChannelHashMap;
    private HashMap<String, List<ProducerDetails>> advertisementHashMap;
    private HashMap<String, Integer> sensorConnectivityAnnouncement;

    private EventUtils evtUtils;

    private final IntentFilter sensorReadingsChannel = new IntentFilter(AbstractChannel.RECEIVER);
    private EventReceiver mEventReceiver;

    private ManagementReceiver mManagementReceiver;
    private final IntentFilter managementReceiverChannel = new IntentFilter(AbstractChannel.MANAGEMENT);

    private ResponseReceiver mResponseReceiver;
    private IntentFilter mResponseReceiverChannel = new IntentFilter(AbstractChannel.LOCAL_MANAGEMENT);

    private final IntentFilter notificationChannel = new IntentFilter(AbstractChannel.NOTIFICATION);
    private NotificationReceiver mNotificationReceiver;

    private class NotificationReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            final NotificationEvent evt = (NotificationEvent) intent
                    .getParcelableExtra(Event.PARCELABLE_EXTRA_EVENT);

            // Create subject
            String tempSubject = "myHealthAssistant ";
            switch (evt.severity) {
            case NotificationEvent.SEVERITY_INFORMATION:
                tempSubject += "INFORMATION";
                break;
            case NotificationEvent.SEVERITY_DEBUG:
                tempSubject += "DEBUG";
                break;
            case NotificationEvent.SEVERITY_CRITICAL:
                tempSubject += "CRITICAL";
                break;
            case NotificationEvent.SEVERITY_WARNING:
                tempSubject += "WARNING";
                break;
            }
            tempSubject += ": " + evt.subject;
            final String subject = tempSubject;

            // Create body
            final String body = "(This is an auto-generated message from myHealthAssistant.)" + "\n\nMessage: "
                    + evt.text + "\n\nProcuder: " + evt.getProducerID();

            // Send e-mail
            Thread thread = new Thread() {
                public void run() {
                    try {
                        //                  GMailSender sender = new GMailSender(
                        //                        null,
                        //                        null);
                        //                  sender.sendMail(subject, body,
                        //                        null,
                        //                        null);
                    } catch (Exception e) {
                        Log.e("SendMail", e.getMessage(), e);
                    }
                }
            };
            thread.start();
        }
    }

    /** Event Handler */
    private class EventReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Event evt = intent.getParcelableExtra(Event.PARCELABLE_EXTRA_EVENT);
            if (D)
                Log.d(TAG, "Incoming event of type " + evt.getEventType());

            String eventType = intent.getStringExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE);

            // Discard null values for a String
            if (eventType == null) {
                Log.e(TAG, "eventType is null");
                return;
            }

            // Parse event type into an event tree
            String[] eventTree = parseEventType(eventType);

            // Discard invalid events
            if (eventTree == null) {
                Log.e(TAG, "Invalid incoming event type: " + eventType);
                return;
            }

            // Skip if tree height is smaller than 2
            if (eventTree.length < 1) {
                Log.e(TAG, "Event tree too small. Event is not forwarded. " + eventType);
                return;
            }

            List<String> tempSubscriberForEventTypeList;
            String eventTypeKey = Event.EVENT_ROOT;

            //Check for each step in the eventTree if anyone is subscribed
            for (int i = 0; i < eventTree.length; i++) {
                eventTypeKey = (eventTypeKey + "." + eventTree[i]);
                tempSubscriberForEventTypeList = subscriberChannelHashMap.get(eventTypeKey);

                if (tempSubscriberForEventTypeList != null) {
                    //set implicit
                    intent.setAction(eventTypeKey);
                    //Send to all subscribers
                    for (int j = 0; j < tempSubscriberForEventTypeList.size(); j++) {
                        String receiverPackage = tempSubscriberForEventTypeList.get(j);

                        /*if(receiverPackage.equals(getPackageName())) {
                           // send locally
                           if(D)Log.i(TAG, "Send locally to package: "+receiverPackage);
                               
                           LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
                            
                           //TODO
                           intent.setPackage(tempSubscriberForEventTypeList.get(j));
                            getApplicationContext().sendBroadcast(intent);
                        } else {*/
                        // globally
                        if (D)
                            Log.i(TAG, "Send globally to package: " + receiverPackage);

                        //set explicit
                        intent.setPackage(tempSubscriberForEventTypeList.get(j));
                        getApplicationContext().sendBroadcast(intent);
                        //}
                    }
                }
            }
        };
    }

    /** Management Receiver */
    private class ManagementReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {

            if (intent == null)
                return;

            //Log.d(TAG, "Received EventTypeShort: "+getLastStringAfterDot(intent.getStringExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE)));
            Event evt = intent.getParcelableExtra(Event.PARCELABLE_EXTRA_EVENT);

            //Checks the ManamgentEvent and notifies the sender about the invalid argument
            if (!isManagementEventValid(evt))
                return;

            // JSONDataExchange
            if (evt.getEventType().equals(ManagementEvent.JSON_DATA_EXCHANGE)) {
                Log.d(TAG, "JSON Data Exchange event from: " + evt.getProducerID());

                String eventProducerID = evt.getProducerID();
                String eventProducersPackageName = ((JSONDataExchange) evt).getPackageName();
                String dataExchangeEventType = ((JSONDataExchange) evt).getDataExchangeEventType();
                //              ProducerDetails producerDetails = new ProducerDetails(eventProducerID, eventProducersPackageName);
                String jsonDataString = ((JSONDataExchange) evt).getJSONEncodedData();

                try {
                    JSONObject jsonData = new JSONObject(jsonDataString);
                    String json_request = jsonData.optString(JSONDataExchange.JSON_REQUEST, "null");
                    JSONArray jObjArray = jsonData.optJSONArray(JSONDataExchange.JSON_CONTENT_ARRAY);

                    if (json_request.equalsIgnoreCase(JSONDataExchange.JSON_STORE) && jObjArray != null) {
                        // save contents to db
                        ArrayList<ContentValues> vArray = new ArrayList<ContentValues>();
                        for (int i = 0; i < jObjArray.length(); i++) {
                            JSONObject jObj = jObjArray.optJSONObject(i);
                            if (jObj != null) {

                                String contents = jObj.toString();
                                String contentDate = jObj.optString(JSONDataExchange.JSON_DATE, "null");
                                String contentExtra = jObj.optString(JSONDataExchange.JSON_EXTRA, "null");

                                ContentValues value = new ContentValues();
                                value.put(LocalTransformationDB.COUMN_JSON_DATE, contentDate);
                                value.put(LocalTransformationDB.COUMN_JSON_CONTENT, contents);
                                value.put(LocalTransformationDB.COUMN_JSON_EXTRA, contentExtra);

                                vArray.add(value);
                            }
                        }
                        LocalTransformationDBMS transformationDB = new LocalTransformationDBMS(context);
                        transformationDB.open();
                        transformationDB.storeJsonData(vArray);
                        transformationDB.close();

                    } else if (json_request.equalsIgnoreCase(JSONDataExchange.JSON_GET)) {
                        // send to eventProducer all data from db
                        LocalTransformationDBMS transformationDB = new LocalTransformationDBMS(context);
                        transformationDB.open();
                        JSONArray getJArray = transformationDB.getAlljsonData();
                        transformationDB.close();
                        JSONObject jEncodedData = new JSONObject();
                        jEncodedData.putOpt(JSONDataExchange.JSON_REQUEST, JSONDataExchange.JSON_GET);
                        jEncodedData.putOpt(JSONDataExchange.JSON_CONTENT_ARRAY, getJArray);

                        if (evtUtils != null) {
                            JSONDataExchange eData = new JSONDataExchange(evtUtils.getEventID(),
                                    evtUtils.getTimestamp(), TAG, eventProducersPackageName, dataExchangeEventType,
                                    jEncodedData.toString());
                            sendToManagementChannel(eData, eventProducersPackageName);
                            Log.e(TAG,
                                    "send EncodedData to " + eventProducersPackageName + "; ID:" + eventProducerID);

                        } else {
                            Log.e(TAG, "cant send back jsonEncodedData to " + eventProducersPackageName + "; ID:"
                                    + eventProducerID);
                        }
                    } else if (json_request.equalsIgnoreCase(JSONDataExchange.JSON_EDIT) && jObjArray != null) {
                        // edit contents in db
                        ArrayList<ContentValues> vArray = new ArrayList<ContentValues>();
                        int id = -1;
                        for (int i = 0; i < jObjArray.length(); i++) {
                            JSONObject jObj = jObjArray.optJSONObject(i);
                            if (jObj != null) {

                                id = jObj.optInt(JSONDataExchange.JSON_CONTENT_ID, -1);
                                String contents = jObj.toString();
                                String contentDate = jObj.optString(JSONDataExchange.JSON_DATE, "null");
                                String contentExtra = jObj.optString(JSONDataExchange.JSON_EXTRA, "null");

                                ContentValues value = new ContentValues();
                                value.put(LocalTransformationDB.COUMN_JSON_DATE, contentDate);
                                value.put(LocalTransformationDB.COUMN_JSON_CONTENT, contents);
                                value.put(LocalTransformationDB.COUMN_JSON_EXTRA, contentExtra);

                                vArray.add(value);
                            }
                        }
                        LocalTransformationDBMS transformationDB = new LocalTransformationDBMS(context);
                        transformationDB.open();
                        transformationDB.editJsonData(id, vArray.get(0)); // assume that only one jObj passed in
                        transformationDB.close();

                    } else if (json_request.equalsIgnoreCase(JSONDataExchange.JSON_DEL) && jObjArray != null) {
                        // delete contents in db
                        int id = -1;
                        for (int i = 0; i < jObjArray.length(); i++) {
                            JSONObject jObj = jObjArray.optJSONObject(i);
                            if (jObj != null) {
                                id = jObj.optInt(JSONDataExchange.JSON_CONTENT_ID, -1);
                            }
                        }
                        Log.e(TAG, "delet json:" + id);
                        LocalTransformationDBMS transformationDB = new LocalTransformationDBMS(context);
                        transformationDB.open();
                        transformationDB.deleteJsonData(id);
                        transformationDB.close();

                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            //Advertisement
            if (evt.getEventType().equals(ManagementEvent.ADVERTISEMENT)) {
                if (D)
                    Log.d(TAG, "Advertisement event from " + evt.getProducerID());

                String eventProducerID = evt.getProducerID();
                String eventProducersPackageName = ((Advertisement) evt).getPackageName();
                String advertisedEventType = ((Advertisement) evt).getAdvertisedEventType();
                ProducerDetails producerDetails = new ProducerDetails(eventProducerID, eventProducersPackageName);

                //Get producers for the EventType
                List<ProducerDetails> tempProducerDetailsList = advertisementHashMap.get(advertisedEventType);

                // Check if anyone is already providing the event
                if (tempProducerDetailsList != null) {
                    //Check if producer is already in list
                    for (int i = 0; i < tempProducerDetailsList.size(); i++) {
                        if (tempProducerDetailsList.get(i).getProducerID().equals(eventProducerID)) {
                            if (D)
                                Log.d(TAG, "Producer already in List: " + eventProducerID);
                            sendAnnouncement(Announcement.ADVERTSIMENT_UNSUCESSFULL_PRODUCER_ALREADY_IN_LIST,
                                    advertisedEventType, eventProducersPackageName);
                            return;
                        }
                    }
                    tempProducerDetailsList.add(producerDetails);
                    if (D)
                        Log.d(TAG, "Producer added to advertisementList: " + eventProducerID);
                } else {
                    // If no producer exists for EventType create a new entry
                    List<ProducerDetails> producerList = new ArrayList<ProducerDetails>();
                    producerList.add(producerDetails);
                    advertisementHashMap.put(advertisedEventType, producerList);
                    if (D)
                        Log.d(TAG, "New Entry in Producer HashMap: " + eventProducerID);
                }

                // Send a startEvent/StopEvent to the producer and a ManagementEvent to all subscribers
                List<String> subscribersListForEventType = getSubscribersListForEventType(advertisedEventType);
                if (subscribersListForEventType != null) {
                    sendStartEvent(eventProducerID, advertisedEventType, eventProducersPackageName);
                    sendAnnouncementToRecieverList(Announcement.ADVERTISMENT_NEW_EVENT_TYPE_AVAILABLE,
                            advertisedEventType, subscribersListForEventType);
                } else {
                    sendStopEvent(eventProducerID, advertisedEventType, eventProducersPackageName);
                }
                sendAnnouncement(Announcement.ADVERTISMENT_SUCCESSFULL, advertisedEventType,
                        eventProducersPackageName);

                if (D_ROUTING)
                    printAdvertisementsAndSubscriptions();

                //Unadvertisement
            } else if (evt.getEventType().equals(ManagementEvent.UNADVERTISEMENT)) {
                String eventProducer = evt.getProducerID();
                String packageName = ((Unadvertisement) evt).getPackageName();
                String unadvertisedEventType = ((Unadvertisement) evt).getUnadvertisedEventType();
                ProducerDetails producerDetails = new ProducerDetails(eventProducer, packageName);

                //Check if there are producers for EventType
                if (advertisementHashMap.containsKey(unadvertisedEventType)) {
                    List<ProducerDetails> producerDetailsList = advertisementHashMap.get(unadvertisedEventType);

                    for (int i = 0; i < producerDetailsList.size(); i++) {
                        if (producerDetailsList.get(i).getProducerID().equals(producerDetails.getProducerID())) {
                            producerDetailsList.remove(i);
                            i--;
                            if (D)
                                Log.d(TAG,
                                        "Removed ProducerDetails: ProducerID: " + producerDetails.getProducerID()
                                                + " PackageNameShort "
                                                + getLastStringAfterDot(producerDetails.getProducerPackageName()));
                        }
                    }

                    //If there are no more producer for the EventType remove from EventType advertismentHashMap and notify all subscribers
                    if (producerDetailsList.isEmpty()) {
                        advertisementHashMap.remove(unadvertisedEventType);
                        //Notify all EventType subscribers
                        List<String> receiverPackageNameList = getSubscribersListForEventType(
                                unadvertisedEventType);
                        if (receiverPackageNameList != null) {
                            sendAnnouncementToRecieverList(
                                    Announcement.UNADVERTISMENT_EVENT_TYPE_NOT_LONGER_AVAILABLE,
                                    unadvertisedEventType, receiverPackageNameList);
                        }
                    }
                    sendAnnouncement(Announcement.UNADVERTISMENT_SUCCESSFULL, unadvertisedEventType, packageName);
                }

                if (D_ROUTING)
                    printAdvertisementsAndSubscriptions();

                //Subscription
            } else if (evt.getEventType().equals(ManagementEvent.SUBSCRIPITON)) {
                if (D)
                    Log.d(TAG, "Subscription event from " + evt.getProducerID());

                String subscribersPackageName = ((Subscription) evt).getPackageName();
                String subscriptionSensorReadings = ((Subscription) evt).getSubscriptionSensorReadings();

                // Check if an entry for the eventType already exists
                if (subscriberChannelHashMap.containsKey(subscriptionSensorReadings)) {
                    List<String> tempSubscribersListForEventType = subscriberChannelHashMap
                            .get(subscriptionSensorReadings);

                    if (!tempSubscribersListForEventType.contains(subscribersPackageName)) {
                        //Check all effected producers and send a StartEvent if no one is already subscribed to it
                        subscriptionCheckWithAllAvailableEventsThatMatch(subscriptionSensorReadings); //Important: check before adding!
                        tempSubscribersListForEventType.add(subscribersPackageName);
                        if (D)
                            Log.d(TAG,
                                    "Subscriber added to Entry in subscribersHashMap: EventTypeShort: "
                                            + getLastStringAfterDot(subscriptionSensorReadings)
                                            + ", PackageNameShort: " + subscribersPackageName);
                    } else {
                        sendAnnouncement(Announcement.SUBSCRIPTOPN_SUBSCRIBER_ALREADY_IN_LIST,
                                subscriptionSensorReadings, subscribersPackageName);
                        return;
                    }
                } else {
                    // If no entry exists create a new one and send a StartEvent to the EventType producer
                    List<String> receiverList = new ArrayList<String>();
                    receiverList.add(subscribersPackageName);
                    //Check all effected producers and send a StartEvent if no one is already subscribed to it
                    subscriptionCheckWithAllAvailableEventsThatMatch(subscriptionSensorReadings); //Important: check before adding!
                    subscriberChannelHashMap.put(subscriptionSensorReadings, receiverList);
                    if (D)
                        Log.d(TAG,
                                "Subscriber Package new Entry in subscribersHashMap: EventTypeShort: "
                                        + getLastStringAfterDot(subscriptionSensorReadings) + ", PackageNameShort: "
                                        + subscribersPackageName);
                }
                sendAnnouncement(Announcement.SUBSCRIPTION_SUCCESSFULL, subscriptionSensorReadings,
                        subscribersPackageName);
                // send sensor connectivity
                if (sensorConnectivityAnnouncement.containsKey(subscriptionSensorReadings))
                    sendAnnouncement(sensorConnectivityAnnouncement.get(subscriptionSensorReadings),
                            subscriptionSensorReadings, subscribersPackageName);

                //Write Subscription into databases
                db.openWritabelDB();
                db.insertOrReplaceRecord(evt.getEventType(), evt.getID(),
                        evt.getTimestamp() /*evtUtils.getTimestamp()*/, evt.getProducerID(), subscribersPackageName,
                        subscriptionSensorReadings);
                if (D)
                    Log.d(TAG,
                            "insertOrReplaceRecord(" + evt.getEventType() + ", " + evt.getID() + ", "
                                    + evt.getTimestamp() + ", " + evt.getProducerID() + ", "
                                    + subscribersPackageName + ", " + subscriptionSensorReadings + ")");
                db.close();

                //If there are no EventProducers send a TransformationManagerRequest
                //TODO: Due to lack in restore DB - erwaehnen in der Bachelorthesis
                if (advertisementHashMap.get(subscriptionSensorReadings) == null) {
                    sendEventTransformationRequest(subscriptionSensorReadings);
                    if (D)
                        Log.d(TAG, "sendTransfromtionRequest(" + subscriptionSensorReadings + ");");
                }

                if (D_ROUTING)
                    printAdvertisementsAndSubscriptions();

                //Unsubscription
            } else if (evt.getEventType().equals(ManagementEvent.UNSUBSCRIPTION)) {

                if (D)
                    Log.d(TAG, "Unsubscription event from " + evt.getProducerID());

                String unsubscribersPackageName = ((Unsubscription) evt).getPackageName();
                String unsubscriptionSensorReadings = ((Unsubscription) evt).getUnsubscriptionSensorReadings();

                //Check if Event is already subscribed
                if (subscriberChannelHashMap.containsKey(unsubscriptionSensorReadings)) {
                    List<String> tempList = subscriberChannelHashMap.get(unsubscriptionSensorReadings);

                    if (tempList.contains(unsubscribersPackageName)) {
                        //Check all effected producers and send a StartEvent if no one is already subscribed to it
                        unsubscriptionCheckWithAllAvailableEventsThatMatch(unsubscriptionSensorReadings); //Important: Check before removing!
                        tempList.remove(unsubscribersPackageName);
                        if (D)
                            Log.d(TAG, "Unsubscription successful: EventTypeShort: "
                                    + getLastStringAfterDot(unsubscriptionSensorReadings) + ", PackageNameShort: "
                                    + getLastStringAfterDot(unsubscribersPackageName));
                        //Unsubscription successful write to database
                        db.openWritabelDB();
                        db.insertOrReplaceRecord(evt.getEventType(), evt.getID(),
                                evt.getTimestamp() /*evtUtils.getTimestamp() */, evt.getProducerID(),
                                unsubscribersPackageName, unsubscriptionSensorReadings);
                        if (D)
                            Log.d(TAG,
                                    "insertRecord(" + evt.getEventType() + ", " + evt.getID() + ", "
                                            + evt.getTimestamp() + ", " + evt.getProducerID() + ", "
                                            + unsubscribersPackageName + ", " + unsubscriptionSensorReadings + ")");
                        db.close();
                    }
                    if (tempList.isEmpty()) {
                        // delete key from HashMap if there are no more subscriptions for this EventType
                        subscriberChannelHashMap.remove(unsubscriptionSensorReadings);
                        if (D)
                            Log.d(TAG, "No more Subscribers delte Entry in subscribersHashMap for EventTypeShort: "
                                    + getLastStringAfterDot(unsubscriptionSensorReadings));
                    }
                }

                if (D_ROUTING)
                    printAdvertisementsAndSubscriptions();

                //Announcement   
            } else if (evt.getEventType().equals(ManagementEvent.ANNOUNCEMENT)) {
                int announcement = ((Announcement) evt).getAnnouncement();
                String packageName = ((Announcement) evt).getPackageName();
                String eventType = ((Announcement) evt).getTransmittedEventType();
                String sender = ((Announcement) evt).getProducerID();

                printAnnouncement(evt);

                switch (announcement) {
                case Announcement.SENSOR_CONNECTED:
                case Announcement.SENSOR_DISCONNECTED:
                    // Distribute announcement via LocalBroadcastManager for SensorConfigurationActivity
                    sendToManagementChannel(evt, getPackageName());

                    // Distribute announcement to subscribed consumers
                    List<String> receiverPackageNameList = getSubscribersListForEventType(eventType);
                    if (receiverPackageNameList != null) {
                        sendAnnouncementToRecieverList(announcement, eventType, receiverPackageNameList);
                    }

                    // store state for future subscriptions
                    sensorConnectivityAnnouncement.put(eventType, announcement);
                    if (D_ANNOUNCEMENT)
                        Log.d(TAG, "Announcement Received: " + announcement + " from: " + sender);
                    break;

                case Announcement.GET_ALL_AVAILABLE_EVENT_TYPES:
                    sendAllAvailableEventTypes(packageName);
                    if (D_ANNOUNCEMENT)
                        Log.d(TAG, "Announcement Received: sendAllAvailableEventTypes from: " + sender);
                    break;

                case Announcement.DATABASE_CLEAR_ALL:
                    if (D_ANNOUNCEMENT)
                        Log.d(TAG_ANNOUNCEMENT, "Announcement Received: DATABASE_CLEAR_ALL from: " + sender);
                    db.openWritabelDB();
                    db.deleteAll();
                    db.close();
                    break;

                case Announcement.DATABASE_SHOW_WITH_ALL_SUBSCRIPTIONS_AND_UNSUBSCRIPTIONS:
                    if (D_ANNOUNCEMENT)
                        Log.d(TAG_ANNOUNCEMENT,
                                "Announcement Received: DATABASE_SHOW_WITH_ALL_SUBSCRIPTIONS_AND_UNSUBSCRIPTIONS from: "
                                        + sender);
                    db.openReadableDB();
                    Cursor c = db.getAllRecords();
                    if (c.moveToFirst()) {
                        if (D_ANNOUNCEMENT)
                            Log.d(TAG_ANNOUNCEMENT, "c.moveToFirst() == " + c.moveToFirst());
                        while (!c.isAfterLast()) {
                            displayRecord(c);
                            c.moveToNext();
                        }
                    }
                    db.close();

                    break;

                default:
                    break;
                }
            }
        };
    }

    /**
     * Sends an EventTransformationsRequest for the given event type and all available events.
     * @param requested event type
     */
    public void sendEventTransformationRequest(String subscriptionSensorReadings) {
        String[] allAvailableEvents = getAllAvailableEvents();

        // Create request
        EventTransformationRequest request = createRequestEvent(
                EventTransformationRequest.TYPE_REQUEST_TRANSFORMATION, allAvailableEvents,
                subscriptionSensorReadings);

        // Broadcast event locally
        Intent i = new Intent();
        i.putExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE, request.getEventType());
        i.putExtra(Event.PARCELABLE_EXTRA_EVENT, request);
        i.setAction(AbstractChannel.LOCAL_MANAGEMENT);
        LocalBroadcastManager.getInstance(this).sendBroadcast(i);
    }

    /**
     * Sends all available event types from the advertisementHashMap as an announcement using the package names for explicit addressing.
     * @param packageName used to setPackageName(packageName)
     */
    private void sendAllAvailableEventTypes(String packageName) {
        String[] availableEventTypes = getAllAvailableEvents();
        Announcement announcement = new Announcement(evtUtils.getEventID(), evtUtils.getTimestamp(), TAG, "",
                getPackageName(), Announcement.ALL_AVAILABLE_EVENT_TYPES);

        Intent intent = new Intent();
        intent.putExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE, announcement.getEventType());
        intent.putExtra(Event.PARCELABLE_EXTRA_EVENT, announcement);
        intent.putExtra(Event.PARCELABLE_EXTRA_AVAILABLE_EVENTS, availableEventTypes);
        if (D)
            Log.d(TAG, "availableEventTypes String[]" + availableEventTypes);
        //Implicit addressing
        intent.setAction(AbstractChannel.MANAGEMENT);
        //Explicit addressing
        intent.setPackage(packageName);
        getApplicationContext().sendBroadcast(intent);
    }

    /**
     * Sends a StopEvent to all producers who have exactly one subscriber now and will have zero after removing.
     * @param unsubscriptionSensorReadings event type that gets unsubscribed
     */
    private void unsubscriptionCheckWithAllAvailableEventsThatMatch(String unsubscriptionSensorReadings) {
        String[] allAvailableEventTypes = getAllAvailableEvents();
        List<String> matchUnsubscriptionAvailableEventTypes = new ArrayList<String>();

        if (allAvailableEventTypes == null)
            return;

        //Get all availableEvents that start with channel subscription
        for (int i = 0; i < allAvailableEventTypes.length; i++) {
            if (allAvailableEventTypes[i].startsWith(unsubscriptionSensorReadings)) {
                matchUnsubscriptionAvailableEventTypes.add(allAvailableEventTypes[i]);
            }
        }
        //Needs to check with each possible matching event, due to the tree structure and possibility to unsubscribe on a node or leaf
        //Send a StopEvent to all producers, who have exactly one subscribers yet and will have zero after removing
        for (int j = 0; j < matchUnsubscriptionAvailableEventTypes.size(); j++) {
            //StopEvent to all producers only if no other channel is subscribed on this EventType already
            if (getSubscribersListForEventType(matchUnsubscriptionAvailableEventTypes.get(j)).size() == 1) {
                sendStopEventToAllProducersForEventType(matchUnsubscriptionAvailableEventTypes.get(j));
            }
        }
    }

    /**
     * Sends a StartEvent to all producers, who have zero subscriber now and will have one after removing.
     * @param subscriptionSensorReadings EventType that gets subscribed for
     */
    private void subscriptionCheckWithAllAvailableEventsThatMatch(String subscriptionSensorReadings) {
        String[] allAvailableEventTypes = getAllAvailableEvents();
        List<String> matchSubscriptionAvailableEventTypes = new ArrayList<String>();

        if (allAvailableEventTypes == null)
            return;

        //Get all availableEvents that start with channel subscription
        for (int i = 0; i < allAvailableEventTypes.length; i++) {
            if (allAvailableEventTypes[i].startsWith(subscriptionSensorReadings)) {
                matchSubscriptionAvailableEventTypes.add(allAvailableEventTypes[i]);
            }
        }
        //Needs to check with each possible event, due to the tree structure and possibility to subscribe on a node or leaf
        //Send a StartEvent to all producers, who have no subscribers yet and will have exactly 1 after subscription
        for (int j = 0; j < matchSubscriptionAvailableEventTypes.size(); j++) {
            //StartEvent to all producers only if no other channel is subscribed on this EventType already
            if (getSubscribersListForEventType(matchSubscriptionAvailableEventTypes.get(j)) == null) {
                sendStartEventToAllProducersForEventType(matchSubscriptionAvailableEventTypes.get(j));
            }
        }
    }

    /**
     * Sends a StopEvent to all producers in the advertismentHashMap for the given event type.
     * @param eventType
     */
    private void sendStopEventToAllProducersForEventType(String eventType) {
        List<ProducerDetails> producersDetailsList = advertisementHashMap.get(eventType);
        if (producersDetailsList == null)
            return;
        for (int i = 0; i < producersDetailsList.size(); i++) {
            sendStopEvent(producersDetailsList.get(i).getProducerID(), eventType,
                    producersDetailsList.get(i).getProducerPackageName());
        }
    }

    /**
     * Sends a StartEvent to all producers in the advertismentHashMap for the given event type
     * @param eventType
     */
    private void sendStartEventToAllProducersForEventType(String eventType) {
        List<ProducerDetails> producersDetailsList = advertisementHashMap.get(eventType);
        if (producersDetailsList == null)
            return;
        for (int i = 0; i < producersDetailsList.size(); i++) {
            sendStartEvent(producersDetailsList.get(i).getProducerID(), eventType,
                    producersDetailsList.get(i).getProducerPackageName());
        }
    }

    /**
     * Different checks if the given Event is valid. Announcements are sent accordingly to the violation.
     * @param evt The Event that has to be checked
     * @return returns true if all checks are passed successful
     */
    public boolean isManagementEventValid(Event evt) {
        String packageName = null;
        String transmittedEventType = null;

        //discard invalid EventTypes
        if (evt.getEventType() == null)
            return false;

        //Advertisement
        if (evt.getEventType().equals(ManagementEvent.JSON_DATA_EXCHANGE)) {
            packageName = ((JSONDataExchange) evt).getPackageName();
            transmittedEventType = ((JSONDataExchange) evt).getDataExchangeEventType();

            String json = ((JSONDataExchange) evt).getJSONEncodedData();
            if (json == null) {
                sendAnnouncement(Announcement.INVALID_EVENT_TYPE_ARGUMENTS, transmittedEventType, packageName);
                return false;
            }
        }
        //Advertisement
        if (evt.getEventType().equals(ManagementEvent.ADVERTISEMENT)) {
            packageName = ((Advertisement) evt).getPackageName();
            transmittedEventType = ((Advertisement) evt).getAdvertisedEventType();

            String json = ((Advertisement) evt).getJSONEncodedProperties();
            if (json == null) {
                sendAnnouncement(Announcement.INVALID_EVENT_TYPE_ARGUMENTS, transmittedEventType, packageName);
                return false;
            }

            //Unadvertisement
        } else if (evt.getEventType().equals(ManagementEvent.UNADVERTISEMENT)) {
            packageName = ((Unadvertisement) evt).getPackageName();
            transmittedEventType = ((Unadvertisement) evt).getUnadvertisedEventType();

            //Subscription
        } else if (evt.getEventType().equals(ManagementEvent.SUBSCRIPITON)) {
            packageName = ((Subscription) evt).getPackageName();
            transmittedEventType = ((Subscription) evt).getSubscriptionSensorReadings();

            /*
            //Check if application(packageName) has permission to subscribe to this EventType
            if(!securityManager.hasPermission(packageName, transmittedEventType)){
               sendAnnouncement(ManagementEvent.SUBSCRIPTION_UNSUCCESSFULL_NO_PERMISSION, transmittedEventType, packageName);
               return false;
            } 
            */

            //Unsubscription
        } else if (evt.getEventType().equals(ManagementEvent.UNSUBSCRIPTION)) {
            packageName = ((Unsubscription) evt).getPackageName();
            transmittedEventType = ((Unsubscription) evt).getUnsubscriptionSensorReadings();

            //Announcement
        } else if (evt.getEventType().equals(ManagementEvent.ANNOUNCEMENT)) {
            packageName = ((Announcement) evt).getPackageName();
            //none transmitted, set to valid value to support the testing scheme
            transmittedEventType = Event.EVENT_ROOT;
        }

        // If any Event variables are null
        if (evt.getID() == null || evt.getProducerID() == null || evt.getTimestamp() == null) {
            Log.w(TAG, "Error at least one Event argument is null");
            sendAnnouncement(Announcement.INVALID_EVENT_TYPE_ARGUMENTS, transmittedEventType, packageName);
            return false;
        }

        //If EventType does not follow conventions
        if (!doesEventTypeMatchConventions(transmittedEventType)) {
            Log.w(TAG, "Error EVENT_TYPE_DOES_NOT_MATCH_NAME_CONVENTION");
            sendAnnouncement(Announcement.EVENT_TYPE_DOES_NOT_MATCH_NAME_CONVENTION, transmittedEventType,
                    packageName);
            return false;
        }

        //Check if application(packageName) is installed on device
        if (!isPackageInstalled(packageName)) {
            //Probably not useful to send this announcement
            Log.w(TAG, "PackageName invalid:" + packageName);
            sendAnnouncement(Announcement.MANAGEMENTEVENT_UNSUCCESSFULL_APPLICATION_NOT_INSTALLED,
                    transmittedEventType, packageName);
            return false;
        }
        return true;
    }

    /**
      * Check if the event type matches event type conventions
      * @param eventType
      * @return returns true if check is passed
      */
    public boolean doesEventTypeMatchConventions(String eventType) {
        if (eventType == null)
            return false;
        if (eventType.startsWith(Event.EVENT_ROOT))
            return true;
        return false;
    }

    /**
     * Sends an announcement event to the given announcement receiver package name ManagementReceiver
     * @param typeOfAnnouncement Types defined in ManagmentEvent.STRING
     * @param transmittedEventType
     * @param announcementReceiverPackageName Used for explicit addressing - setPackageName(packageName)
     */
    private void sendAnnouncement(int typeOfAnnouncement, String transmittedEventType,
            String announcementReceiverPackageName) {

        //if no packageName is set do not send an announcement
        if (announcementReceiverPackageName == null)
            return;

        Announcement announcement = new Announcement(evtUtils.getEventID(), evtUtils.getTimestamp(), TAG,
                transmittedEventType, announcementReceiverPackageName, typeOfAnnouncement);

        sendToManagementChannel(announcement, announcementReceiverPackageName);
        /*Intent intent = new Intent();
        intent.putExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE, announcement.getEventType());
        intent.putExtra(Event.PARCELABLE_EXTRA_EVENT, announcement);
        //Implicit addressing
        intent.setAction(ReadingChannels.MANAGEMENT);
        //Explicit addressing
        printAnnouncement(announcement);
            
        intent.setPackage(announcementReceiverPackageName);
            
        getApplicationContext().sendBroadcast(intent);*/
    }

    /**
     * Sends announcements events to the given receiver package names list
     * @param typeOfAnnouncement Types defined in ManagmentEvent.STRING
     * @param eventType
     * @param listOfRecievers List of receiver package names used to explicit address ManagementReceivers
     */
    private void sendAnnouncementToRecieverList(int typeOfAnnouncement, String eventType,
            List<String> listOfRecievers) {
        for (int i = 0; i < listOfRecievers.size(); i++) {
            sendAnnouncement(typeOfAnnouncement, eventType, listOfRecievers.get(i));
        }
    }

    /**
     * Sends a start event to the given package names ManagementReceiver
     * @param eventProducerID
     * @param startEventType
     * @param packageName Receivers package name used to explicit address ManagementReceivers
     */
    private void sendStartEvent(String eventProducerID, String startEventType, String packageName) {
        StartProducer startEvent = new StartProducer(evtUtils.getEventID(), evtUtils.getTimestamp(), TAG,
                eventProducerID, startEventType);
        sendToManagementChannel(startEvent, packageName);
        Log.i(TAG,
                "StartProducer Sensor: " + eventProducerID + ", EventTypeShort: "
                        + getLastStringAfterDot(startEventType) + ", PackageNameShort: "
                        + getLastStringAfterDot(packageName));
    }

    /**
     * Sends a StopEvent to the given package names ManagementReceiver
     * @param eventProducerID
     * @param stopEventType
     * @param packageName Receivers package name used to explicit address ManagementReceiver
     */
    private void sendStopEvent(String eventProducerID, String stopEventType, String packageName) {
        StopProducer stopEvent = new StopProducer(evtUtils.getEventID(), evtUtils.getTimestamp(), TAG,
                eventProducerID, stopEventType);
        sendToManagementChannel(stopEvent, packageName);
        Log.i(TAG,
                "StopProducer Sensor: " + eventProducerID + ", EventTypeShort: "
                        + getLastStringAfterDot(stopEventType) + ", PackageNameShort: "
                        + getLastStringAfterDot(packageName));
    }

    /**
     * Sends an event to the local or global management channel depending on
     * the packageName. If the packageName equals the myHealthHub package name, 
     * the event is send locally.
     * @param event that needs to be send
     * @param packageName of the receiver
     */
    private void sendToManagementChannel(Event evt, String packageName) {
        Intent intent = new Intent();
        intent.putExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE, evt.getEventType());
        intent.putExtra(Event.PARCELABLE_EXTRA_EVENT, evt);

        // use local management channel for internal sensor modules
        if (packageName.equals(getPackageName())) {
            if (D)
                Log.d(TAG, "Sending on local management channel:" + evt.getEventType());
            intent.setAction(AbstractChannel.LOCAL_MANAGEMENT);
            LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

            // use global management channel for external sensor modules (i.e. other applications)
        } else {
            if (D)
                Log.d(TAG, "Sending on global management channel:" + evt.getEventType());
            //Implicit addressing
            intent.setAction(AbstractChannel.MANAGEMENT);
            //Explicit addressing          
            intent.setPackage(packageName);
            getApplicationContext().sendBroadcast(intent);
        }
    }

    /**
     * Creates a EventTransformationRequest
     * @param requestType
     * @param advertisedEvents
     * @param eventSubscription
     * @return EventTransformationRequest
     */
    private EventTransformationRequest createRequestEvent(int requestType, String[] advertisedEvents,
            String eventSubscription) {
        return new EventTransformationRequest(evtUtils.getEventID(), evtUtils.getTimestamp(), TAG, requestType,
                advertisedEvents, eventSubscription);
    }

    /**
     * Get all available events from the advertismentHashMap
     * @return String[] containing all available event types
     */
    public String[] getAllAvailableEvents() {
        //Android documentation: The set does not support adding
        Set<String> availableEvents = advertisementHashMap.keySet();
        if (availableEvents == null)
            return null;
        String[] events = availableEvents.toArray(new String[availableEvents.size()]);
        for (int i = 0; i < events.length; i++) {
            if (D || D_ROUTING)
                Log.d(TAG, "String[" + i + "] = Value: " + events[i]);
        }
        return events;
    }

    /**
     * Checks the subscribers permission for the channel/event type with a list of allowed subscribers for the channel/event type
     * @param eventType
     * @param allowedSubscribersPackageNamesList
     */
    public void checkPermissionsForEventType(String eventType, List<String> allowedSubscribersPackageNamesList) {

        List<String> subscribersPackageNames = subscriberChannelHashMap.get(eventType);
        List<String> toBeUnsubscribedPackageNamesList = new ArrayList<String>();
        //If there are subscribers verify them with allowedSubscribersPackageNamesList
        if (subscribersPackageNames != null) {
            for (int i = 0; i < subscribersPackageNames.size(); i++) {
                //Check if subscriber still has the permission
                if (allowedSubscribersPackageNamesList.contains(subscribersPackageNames.get(i))) {
                    if (D)
                        Log.d(TAG, "Permission verified successfull" + subscribersPackageNames.get(i));
                } else {
                    if (D)
                        Log.d(TAG, "Permission not verified - unsubscribe" + subscribersPackageNames.get(i));
                    sendAnnouncement(Announcement.SECURITY_PERMISSION_REMOVED, eventType,
                            subscribersPackageNames.get(i));
                    toBeUnsubscribedPackageNamesList.add(subscribersPackageNames.get(i));
                }
            }
        }
        sendUnsubscriptionsForAllInvalidSubscribers(eventType, toBeUnsubscribedPackageNamesList);
    }

    /**
     * Sends an Unsubscription event for all subscribers package names in the list
     * @param eventType
     * @param toBeUnsubscribedPackageNamesList Package names to be removed from the subscribersHashMap
     */
    private void sendUnsubscriptionsForAllInvalidSubscribers(String eventType,
            List<String> toBeUnsubscribedPackageNamesList) {
        for (int i = 0; i < toBeUnsubscribedPackageNamesList.size(); i++) {
            sendUnsubscription(eventType, toBeUnsubscribedPackageNamesList.get(i));
        }
    }

    /**
     * Sends an Unsubscription event to the subscribers package name for the given event type
     * @param eventType
     * @param toBeUnsubscribedPackageName
     */
    private void sendUnsubscription(String eventType, String toBeUnsubscribedPackageName) {
        Unsubscription unsubcribe = new Unsubscription(evtUtils.getEventID(), evtUtils.getTimestamp(), TAG,
                toBeUnsubscribedPackageName, eventType);
        Intent intent = new Intent();
        intent.putExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE, unsubcribe.getEventType());
        intent.putExtra(Event.PARCELABLE_EXTRA_EVENT, unsubcribe);
        intent.setAction(AbstractChannel.MANAGEMENT);
        sendBroadcast(intent);
    }

    /**
      * Parses event type filed and returns String array representing
      * the tree structure of the event type. myHealhAssistant prefix
      * is removed.
      * @param EVENT_TYPE Event type.
      * @return String[] including event tree. 
      */
    private String[] parseEventType(String eventType) {

        // Return null if not myHealthAssistant prefix
        if (!eventType.startsWith(Event.EVENT_ROOT))
            return null;

        // Remove prefix
        eventType = eventType.substring(Event.EVENT_ROOT.length() + 1, eventType.length());

        // Store fields into String array
        String[] eventTree = eventType.split("\\.");

        return eventTree;
    }

    /**
     * Get all subscribers (for each step in the event tree) for the event type, according to the tree structure and the possibility to subscribe to a node or leaf
     * 
     * @return: a list of package names or null if there are no receivers
     */
    private List<String> getSubscribersListForEventType(String eventType) {

        // Parse event type into an event tree
        String[] eventTree = parseEventType(eventType);

        // Discard invalid events
        if (eventTree == null) {
            Log.e(TAG, "Invalid incoming event type: " + eventType);
            return null;
        }

        List<String> listOfReceivers = new ArrayList<String>();
        List<String> tempSubscriberList;
        String channelName = Event.EVENT_ROOT;

        //Build a list of receivers referring to the event tree subscriptions
        for (int i = 0; i < eventTree.length; i++) {
            channelName = (channelName + "." + eventTree[i]);
            //Log.d(TAG,"Search key for HashMap: "+channelName);
            tempSubscriberList = subscriberChannelHashMap.get(channelName);
            if (tempSubscriberList != null) {
                //Log.d(TAG,"Length HashMap result: "+tempSubscriberList.size());
                listOfReceivers.addAll(tempSubscriberList);
            }
        }
        if (listOfReceivers.size() != 0) {
            return listOfReceivers;
        }
        return null;
    }

    /**
     * Verifies if the package is installed using the PackageManager and the given package name
     * @param packageName
     * @return Returns true if package is installed
     */
    public boolean isPackageInstalled(String packageName) {
        if (packageName == null)
            return false;
        PackageManager pm = getPackageManager();
        try {
            PackageInfo info = pm.getPackageInfo(packageName, PackageManager.GET_META_DATA);
        } catch (NameNotFoundException e) {
            return false;
        }
        return true;
    }

    /**
     * SecurityManager: quick and dirty implementation for testing only
     */
    private class SecurityManager {
        private HashMap<String, List<String>> permissionHashMap;
        private List<String> listOfPermissionApplication01 = new ArrayList<String>();
        private List<String> listOfPermissionApplication02 = new ArrayList<String>();

        public SecurityManager() {
            permissionHashMap = new HashMap<String, List<String>>();
            listOfPermissionApplication01.add(SensorReadingEvent.READING_EVENT);
            listOfPermissionApplication01.add(SensorReadingEvent.ACCELEROMETER);
            listOfPermissionApplication02.add(SensorReadingEvent.HEART_RATE);
            permissionHashMap.put("com.example.myhealthhubsetpackage.application01", listOfPermissionApplication01);
            permissionHashMap.put("com.example.myhealthhubsetpackage.application02", listOfPermissionApplication02);
        }

        /**
         * Checks if a application has permission to subscribe on channel
         */
        private boolean hasPermission(String packageName, String channel) {
            List<String> tempList = new ArrayList<String>();
            tempList = permissionHashMap.get(packageName);
            if (tempList != null) {
                if (tempList.contains(channel)) {
                    if (D)
                        Log.d(TAG, "True: Permission is avaiable: " + channel);
                    return true;
                }
            }
            if (D)
                Log.d(TAG, "False: Permission is avaiable: " + channel);
            return false;
        }
    }

    /** EventTransformation event receiver */
    public class ResponseReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            // Skip if not a event transformation response
            if (!intent.getStringExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE)
                    .equals(EventTransformationResponse.EVENT_TYPE))
                return;

            // Get and print event
            EventTransformationResponse response = intent.getParcelableExtra(Event.PARCELABLE_EXTRA_EVENT);
            if (D)
                Log.d(TAG, "Got result " + response.isTransformationFound() + " for request ID: " + response.getID()
                        + ".");
        }
    }

    /**
     * Returns the last String separated by "."
     * @param name
     * @return Returns last String separated by "."
     */
    private String getLastStringAfterDot(String name) {
        if (name.contains(".") && name.length() >= 3) {
            String[] nameSplit = name.split("\\.");
            return nameSplit[nameSplit.length - 1];
        }
        return "Error String does not contain '.' or is to short)";
    }

    /**
     * Used for connecting a producerID with a package name to explicit address the producer
     * @author Jens
     *
     */
    private class ProducerDetails {
        private String ProducerID;
        private String ProducerPackageName;

        public ProducerDetails(String producerID, String producerPackageName) {
            ProducerID = producerID;
            ProducerPackageName = producerPackageName;
        }

        public String getProducerID() {
            return ProducerID;
        }

        public void setProducerID(String producerID) {
            ProducerID = producerID;
        }

        public String getProducerPackageName() {
            return ProducerPackageName;
        }

        public void setProducerPackageName(String producerPackageName) {
            ProducerPackageName = producerPackageName;
        }
    }

    @Override
    public void onCreate() {
        Log.i(TAG, getPackageName());

        // Initialize event RECEIVER
        mEventReceiver = new EventReceiver();
        getApplication().registerReceiver(mEventReceiver, sensorReadingsChannel);
        LocalBroadcastManager.getInstance(this).registerReceiver(mEventReceiver, sensorReadingsChannel);

        // Notification Receiver
        mNotificationReceiver = new NotificationReceiver();
        getApplication().registerReceiver(mNotificationReceiver, notificationChannel);

        // Management Receiver
        mManagementReceiver = new ManagementReceiver();
        getApplication().registerReceiver(mManagementReceiver, managementReceiverChannel);
        LocalBroadcastManager.getInstance(this).registerReceiver(mManagementReceiver, managementReceiverChannel);

        mResponseReceiver = new ResponseReceiver();
        LocalBroadcastManager.getInstance(this).registerReceiver(mResponseReceiver, mResponseReceiverChannel);

        subscriberChannelHashMap = new HashMap<String, List<String>>();
        advertisementHashMap = new HashMap<String, List<ProducerDetails>>();
        sensorConnectivityAnnouncement = new HashMap<String, Integer>();
        //securityManager = new SecurityManager();
        evtUtils = new EventUtils(NotificationEvent.EVENT_TYPE, TAG);

        //mTransformationManager = new TransformationManager(this, AbstractChannel.LOCAL_MANAGEMENT);

        db = new DBAdapterSubscriptions(this);
        restoreSubscriptionsFromDB();
    }

    /**
     * Starts to restore the subscriberHashMap from a database
     */
    private void restoreSubscriptionsFromDB() {
        Log.i(TAG, "Restore Subscriptions From DB");

        db.openReadableDB();
        Cursor c = db.getAllRecords();
        if (c.moveToFirst()) {
            while (!c.isAfterLast()) {
                sendSubscription(c);
                c.moveToNext();
            }
        }
        db.close();
        printAdvertisementsAndSubscriptions();
    }

    /**
     * Creates Subscriptions 
     * @param c Cursor fetched from database with the necessary information to create a Subscription
     */
    private void sendSubscription(Cursor c) {
        String eventType = c.getString(1);
        String eventID = c.getString(2);
        String timeStamp = c.getString(3);
        String producerID = c.getString(4);
        String packageName = c.getString(5);
        String subscribedEventType = c.getString(6);

        Intent intent = new Intent();

        if (eventType.equals(ManagementEvent.SUBSCRIPITON)) {
            Subscription subscribe = new Subscription(eventID, timeStamp, producerID, packageName,
                    subscribedEventType);
            intent.putExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE, subscribe.getEventType());
            intent.putExtra(Event.PARCELABLE_EXTRA_EVENT, subscribe);
            if (D_ANNOUNCEMENT)
                Log.d(TAG_ANNOUNCEMENT,
                        "Subscription sent: " + producerID + ", packageNameShort: "
                                + getLastStringAfterDot(packageName) + ", subscribedEventTypeShort: "
                                + getLastStringAfterDot(subscribedEventType));
            intent.setAction(AbstractChannel.MANAGEMENT);
            intent.setPackage(getPackageName());
            sendBroadcast(intent);
        }
        //No need to send Unsubscription
        else if (eventType.equals(ManagementEvent.UNSUBSCRIPTION)) {
            Unsubscription unsubscribe = new Unsubscription(eventID, timeStamp, producerID, packageName,
                    subscribedEventType);
            //intent.putExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE, unsubscribe.getEventType());
            //intent.putExtra(Event.PARCELABLE_EXTRA_EVENT, unsubscribe);
            if (D_ANNOUNCEMENT)
                Log.d(TAG_ANNOUNCEMENT,
                        "Unsubscription restored but not sent: " + producerID + ", packageNameShort: "
                                + getLastStringAfterDot(packageName) + ", subscribedEventTypeShort: "
                                + getLastStringAfterDot(subscribedEventType));
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind(): entered...");
        return null;
    }

    public void onUnbind() {
        if (D)
            Log.d(TAG, "onUnbind(): entered...");
    }

    public void onDestroy() {
        if (D)
            Log.d(TAG, "onDestroy() entered...");
        getApplication().unregisterReceiver(mEventReceiver);
        getApplication().unregisterReceiver(mNotificationReceiver);
    }

    //TODO: Can be removed after testing
    /**
     * Prints an announcement to LogCat using TAG_ANNOUNCEMENT
     * @param evt
     */
    public void printAnnouncement(Event evt) {
        int announcement = ((Announcement) evt).getAnnouncement();
        String packageName = ((Announcement) evt).getPackageName();
        String eventType = ((Announcement) evt).getTransmittedEventType();
        String sender = ((Announcement) evt).getProducerID();

        if (D_ANNOUNCEMENT)
            Log.d(TAG_ANNOUNCEMENT,
                    "Announcement Details: " + sender + ", AnnouncementType: " + announcement
                            + ", PackageNameShort: " + getLastStringAfterDot(packageName) + ", EventTypeShort: "
                            + getLastStringAfterDot(eventType));
    }

    /**
     * Prints an database entry to LogCat using TAG_ANNOUNCEMENT
     * @param c
     */
    private void displayRecord(Cursor c) {
        Log.d(TAG, "DisplayRecord: ");
        Log.d(TAG,
                "" + DBAdapterSubscriptions.KEY_ROWID + " : " + c.getString(0) + "\n"
                        + DBAdapterSubscriptions.KEY_EVENT_TYPE + " : " + c.getString(1) + "\n"
                        + DBAdapterSubscriptions.KEY_EVENT_ID + " : " + c.getString(2) + "\n"
                        + DBAdapterSubscriptions.KEY_TIMESTAMP + " : " + c.getString(3) + "\n"
                        + DBAdapterSubscriptions.KEY_PRODUCER_ID + " : " + c.getString(4) + "\n"
                        + DBAdapterSubscriptions.KEY_PACKAGE_NAME + " : " + c.getString(5) + "\n"
                        + DBAdapterSubscriptions.KEY_READING_EVENT_TYPE + " : " + c.getString(6) + "\n");
    }

    /**
     * Prints lists of advertised and subscribed events.
     */
    private void printAdvertisementsAndSubscriptions() {
        Log.d(TAG_ROUTING, "--\nList of Advertisements:");
        Log.d(TAG_ROUTING, "=======================");
        getAllAvailableEvents();

        Log.d(TAG_ROUTING, "\nList of Subscriptions:");
        Log.d(TAG_ROUTING, "======================");
        String output = "";
        Iterator<Entry<String, List<String>>> it = subscriberChannelHashMap.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, List<String>> e = it.next();
            output += e.getKey() + "\t | ";
            for (String channel : e.getValue()) {
                output += channel + ", ";
            }
            output += "\n";
        }
        Log.d(TAG_ROUTING, output + "\n--");
    }

}