eu.musesproject.client.usercontexteventhandler.UserContextEventHandler.java Source code

Java tutorial

Introduction

Here is the source code for eu.musesproject.client.usercontexteventhandler.UserContextEventHandler.java

Source

/*
 * MUSES High-Level Object Oriented Model
 * Copyright MUSES project (European Commission FP7) - 2013 
 */
package eu.musesproject.client.usercontexteventhandler;

/*
 * #%L
 * musesclient
 * %%
 * Copyright (C) 2013 - 2014 HITEC
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms stoof the GNU Affero 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 Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.SharedPreferences;
import eu.musesproject.client.connectionmanager.*;
import eu.musesproject.client.db.entity.ActionProperty;
import eu.musesproject.client.model.decisiontable.*;
import eu.musesproject.client.model.decisiontable.Request;
import eu.musesproject.client.ui.MainActivity;
import eu.musesproject.client.utils.MusesUtils;
import org.json.JSONObject;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import eu.musesproject.client.actuators.ActuatorController;
import eu.musesproject.client.contextmonitoring.UserContextMonitoringController;
import eu.musesproject.client.contextmonitoring.sensors.SettingsSensor;
import eu.musesproject.client.db.entity.Configuration;
import eu.musesproject.client.db.entity.Property;
import eu.musesproject.client.db.entity.SensorConfiguration;
import eu.musesproject.client.db.handler.DBManager;
import eu.musesproject.client.db.handler.ResourceCreator;
import eu.musesproject.client.decisionmaker.DecisionMaker;
import eu.musesproject.client.model.RequestType;
import eu.musesproject.client.securitypolicyreceiver.RemotePolicyReceiver;
import eu.musesproject.contextmodel.ContextEvent;

/**
 * The Class UserContextEventHandler. Singleton
 * @author Christoph
 * @version 28 feb 2014
 */
public class UserContextEventHandler implements RequestTimeoutTimer.RequestTimeoutHandler {
    private static final String TAG = UserContextEventHandler.class.getSimpleName();
    public static final String TAG_RQT = "REQUEST_TIMEOUT";
    public static final String TAG_MUSES_AWARE = "MUSES_AWARE";
    private static final String APP_TAG = "APP_TAG";

    private static UserContextEventHandler userContextEventHandler = null;
    //   private static final String MUSES_SERVER_URL = "http://192.168.44.101:8888/commain";
    //   private static final String MUSES_SERVER_URL = "https://192.168.44.101:8443/server/commain";
    //  private static final String MUSES_SERVER_URL = "https://192.168.44.101:8443/server-0.0.1-SNAPSHOT/commain";
    //  private static final String MUSES_SERVER_URL = "http://192.168.44.107:8080/server/commain";
    //  private static final String MUSES_SERVER_URL = "http://192.168.35.198/server/commain";
    private static final String MUSES_SERVER_URL = "https://172.17.3.5:8443/server/commain";

    private Context context;

    private SharedPreferences prefs;

    // connection fields
    private ConnectionManager connectionManager;
    private IConnectionCallbacks connectionCallback;
    public int serverStatus;
    private int serverDetailedStatus;
    private boolean isUserAuthenticated;
    public static boolean serverOnlineAndUserAuthenticated;

    private DecisionMaker decisionMaker;

    private Map<Integer, RequestHolder> mapOfPendingRequests;//String key is the hashID of the request object

    private String imei;
    private String userName;
    private String tmpLoginUserName;
    private String tmpLoginPassword;
    private DBManager dbManager;

    private UserContextEventHandler() {
        connectionManager = new ConnectionManager();
        connectionCallback = new ConnectionCallback();

        serverStatus = Statuses.CURRENT_STATUS;
        serverDetailedStatus = Statuses.OFFLINE;
        isUserAuthenticated = false;
        serverOnlineAndUserAuthenticated = false;

        decisionMaker = new DecisionMaker();

        mapOfPendingRequests = new HashMap<Integer, RequestHolder>();
    }

    /**
     * Method to get the current server status (online, offline)
     * @return int. {@link Statuses} online: 1; offline:0
     */
    public int getServerStatus() {
        return serverStatus;
    }

    public static UserContextEventHandler getInstance() {
        if (userContextEventHandler == null) {
            userContextEventHandler = new UserContextEventHandler();
        }
        return userContextEventHandler;
    }

    /**
     * connects to the MUSES server
     */
    public void connectToServer() {
        Configuration config = getServerConfigurationFromDB();
        String url = "https://" + config.getServerIP() + ":" + config.getServerPort()
                + config.getServerContextPath() + config.getServerServletPath();
        AlarmReceiver.DEFAULT_POLL_INTERVAL = config.getPollTimeout();
        AlarmReceiver.DEFAULT_SLEEP_POLL_INTERVAL = config.getSleepPollTimeout();
        connectionManager.connect(url, AlarmReceiver.DEFAULT_POLL_INTERVAL,
                AlarmReceiver.DEFAULT_SLEEP_POLL_INTERVAL, connectionCallback, context);
    }

    private Configuration getServerConfigurationFromDB() {
        if (dbManager == null) {
            dbManager = new DBManager(context);
        }

        dbManager.openDB();
        Configuration config = dbManager.getConfigurations();
        dbManager.closeDB();
        return config;
    }

    /**
     *  Method to first check the local decision maker for a decision to the corresponding
     *      {@link eu.musesproject.client.contextmonitoring.service.aidl.Action}
     *
     *  Sends request to the server if there is no local stored decision /
     *      perform default procedure if the server is not reachable
     *
     * @param action {@link Action}
     * @param properties {@link Map}<String, String>
     * @param contextEvents {@link ContextEvent}
     */
    public void send(Action action, Map<String, String> properties, List<ContextEvent> contextEvents) {
        Log.d(MusesUtils.TEST_TAG, "UCEH - send(action, prop, context_events)");
        Log.d(APP_TAG, "Action: " + action.getActionType());
        Log.d(TAG, "called: send(Action action, Map<String, String> properties, List<ContextEvent> contextEvents)");
        boolean onlineDecisionRequested = false;

        Decision decision = retrieveDecision(action, properties, contextEvents);

        if (decision != null) { // local decision found
            Log.d(APP_TAG, "Info DC, Local decision found, now calling actuator to showFeedback");
            Log.d(APP_TAG, "showFeedback1");
            ActuatorController.getInstance().showFeedback(decision);
        } else { // if there is no local decision, send a request to the server
            if (serverStatus == Statuses.ONLINE && isUserAuthenticated) { // if the server is online, request a decision
                // flag that an online decision is requested
                onlineDecisionRequested = true;

                // temporary store the information so that the decision can be made after the server responded with
                // an database update (new policies are sent from the server to the client and stored in the database)
                // In addition, add a timeout to every request
                final RequestHolder requestHolder = new RequestHolder(action, properties, contextEvents);
                Log.d(TAG_RQT, "1. send: request_id: " + requestHolder.getId());
                Handler handler = new Handler(Looper.getMainLooper());
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        requestHolder.setRequestTimeoutTimer(
                                new RequestTimeoutTimer(UserContextEventHandler.this, requestHolder.getId()));
                        requestHolder.getRequestTimeoutTimer().start();
                    }
                }, 0);
                mapOfPendingRequests.put(requestHolder.getId(), requestHolder);

                // create the JSON request and send it to the server
                JSONObject requestObject = JSONManager.createJSON(getImei(), getUserName(), requestHolder.getId(),
                        RequestType.ONLINE_DECISION, action, properties, contextEvents);
                Log.d(APP_TAG,
                        "Info DC, No Local decision found, Sever is ONLINE, sending user data JSON(actions,properties,contextevnts) to server");
                sendRequestToServer(requestObject);
            } else if (serverStatus == Statuses.ONLINE && !isUserAuthenticated) {
                storeContextEvent(action, properties, contextEvents);
            } else if (serverStatus == Statuses.OFFLINE && isUserAuthenticated) {
                Log.d(APP_TAG, "showFeedback2");
                ActuatorController.getInstance().showFeedback(new DecisionMaker().getDefaultDecision());
                storeContextEvent(action, properties, contextEvents);
            } else if (serverStatus == Statuses.OFFLINE && !isUserAuthenticated) {
                storeContextEvent(action, properties, contextEvents);
            }
        }
        // update context events even if a local decision was found.
        // Prevent sending context events again if they are already sent for a online decision
        if ((!onlineDecisionRequested) && (serverStatus == Statuses.ONLINE) && isUserAuthenticated) {
            Log.d(APP_TAG, "Info DB, update context events even if a local decision was found.");

            RequestHolder requestHolder = new RequestHolder(action, properties, contextEvents);
            JSONObject requestObject = JSONManager.createJSON(getImei(), getUserName(), requestHolder.getId(),
                    RequestType.LOCAL_DECISION, action, properties, contextEvents);
            sendRequestToServer(requestObject);
        }
    }

    /**
     * Method that handles the necessary steps to retrieve a decision from the decision maker
     * 1. Generate the {@link Resource}
     * 2. Generate the {@link Request}
     * 3. Make sure that the {@link DecisionMaker} is initialized
     * 4. Request a decision from the {@link DecisionMaker}
     *
     * @param action
     * @param properties
     * @param contextEvents
     * @return
     */
    private Decision retrieveDecision(Action action, Map<String, String> properties,
            List<ContextEvent> contextEvents) {
        if (action == null || properties == null || contextEvents == null) {
            return null;
        }
        Resource resource = ResourceCreator.create(action, properties);
        Request request = new Request(action, resource);
        Log.d(APP_TAG, "Info DC, Calling decision maker");
        if (decisionMaker == null) {
            decisionMaker = new DecisionMaker();
        }
        return decisionMaker.makeDecision(request, contextEvents, properties);
    }

    /**
     * Method that takes an {@link eu.musesproject.client.model.decisiontable.Action}
     * which contains the decision taken by the user on the MUSES UI.
     * This behavior will be send to the server
     * @param action
     */
    public void sendUserBehavior(Action action) {
        if (serverStatus == Statuses.ONLINE && isUserAuthenticated) {
            Log.d(MusesUtils.TEST_TAG, "UCEH - sendUserBehavior(Action action)");
            Log.d(APP_TAG, "Info U, sending user behavior to server with action");
            JSONObject userBehaviorJSON = JSONManager.createUserBehaviorJSON(getImei(), getUserName(),
                    action.getActionType());
            sendRequestToServer(userBehaviorJSON);
        } else {
            // TODO store it offline
        }
    }

    /**
     * Method to log in to MUSES.
     * Necessary to establish server communication and for 
     * using this application
     *
     * @param userName
     * @param password
     */
    public void login(String userName, String password) {
        Log.d(MusesUtils.TEST_TAG, "UCEH - login(String userName, String password)");
        Log.d(TAG, "called: login(String userName, String password)");
        this.userName = userName;
        tmpLoginUserName = userName;
        tmpLoginPassword = password;

        String deviceId;
        dbManager.openDB();
        if ((deviceId = dbManager.getDevId()) == null || deviceId.isEmpty()) {
            deviceId = getImei();
        }
        dbManager.closeDB();

        if (serverStatus == Statuses.ONLINE) {
            Log.d(APP_TAG, "Info U, Authenticating user login to server with username: " + tmpLoginUserName
                    + " password: " + tmpLoginPassword + " deviceId: " + deviceId);
            JSONObject requestObject = JSONManager.createLoginJSON(tmpLoginUserName, tmpLoginPassword, deviceId);
            sendRequestToServer(requestObject);
        } else { // TODO add information to the callback with an explanation what happened
            Log.d(APP_TAG, "Info U, Authenticating login with username:" + tmpLoginUserName + " password:"
                    + tmpLoginPassword + " deviceId: " + deviceId + " in localdatabase");
            dbManager.openDB();
            isUserAuthenticated = dbManager.isUserAuthenticated(getImei(), tmpLoginUserName, tmpLoginPassword);
            dbManager.closeDB();
            ActuatorController.getInstance().sendLoginResponse(isUserAuthenticated);
            if (isUserAuthenticated) {
                sendConfigSyncRequest();
            }
        }

    }

    /**
     * Method to try to login with existing credentials in the database
     */
    public void autoLogin() {
        Log.d(MusesUtils.TEST_TAG, "UCEH - autoLogin()");
        if (prefs == null) {
            prefs = context.getSharedPreferences(MainActivity.PREFERENCES_KEY, Context.MODE_PRIVATE);
        }
        this.userName = prefs.getString(MainActivity.USERNAME, "");
        String password = prefs.getString(MainActivity.PASSWORD, "");

        if (userName.isEmpty() || password.isEmpty()) {
            Log.d("auto_login_test", "cannot auto login");
            return; // user wasn't logged in before
        }

        dbManager.openDB();
        isUserAuthenticated = dbManager.isUserAuthenticated(getImei(), userName, password);
        boolean sensorConfigExists = dbManager.hasSensorConfig();
        dbManager.closeDB();
        ActuatorController.getInstance().sendLoginResponse(isUserAuthenticated);

        updateServerOnlineAndUserAuthenticated();

        if (isUserAuthenticated) {
            if (sensorConfigExists) {
                manageMonitoringComponent();
            } else {
                sendConfigSyncRequest();
            }
        }
    }

    private void manageMonitoringComponent() {
        Log.d(MusesUtils.TEST_TAG, "UCEH - manageMonitoringComponent()");
        if (isUserAuthenticated) {
            UserContextMonitoringController.getInstance(getContext()).startContextObservation();
        }
    }

    /**
     * Method to request a configuration update
     */
    private void sendConfigSyncRequest() {
        Log.d(MusesUtils.TEST_TAG, "UCEH - sendConfigSyncRequest()");
        JSONObject configSyncRequest = JSONManager.createConfigSyncJSON(getImei(), getUserName());
        sendRequestToServer(configSyncRequest);
    }

    /**
     * Method to logout the user, so that no more events are send to the server in his/her name
     */
    public void logout() {
        Log.d(MusesUtils.TEST_TAG, "UCEH - logout()");
        JSONObject logoutJSON = JSONManager.createLogoutJSON(getUserName(), getImei());
        sendRequestToServer(logoutJSON);

        isUserAuthenticated = false;
        updateServerOnlineAndUserAuthenticated();
    }

    /**
     * Method to store a context event in the database if
     * there is no connection to the server
     *
     * @param action {@link Action}
     * @param properties {@link Map}<String, String>
     * @param contextEvents {@link ContextEvent}
     */
    public void storeContextEvent(Action action, Map<String, String> properties, List<ContextEvent> contextEvents) {
        Log.d(MusesUtils.TEST_TAG, "UCEH - storeContextEvent()");
        Log.d(TAG,
                "called: storeContextEvent(Action action, Map<String, String> properties, List<ContextEvent> contextEvents)");
        // TODO maybe remove this: (properties != null) && (contextEvents != null) because a user behavior doesn't contain this information
        if ((action != null) && (properties != null) && (contextEvents != null)) {
            if (dbManager == null) {
                dbManager = new DBManager(context);
            }
            dbManager.openDB();

            int actionId = (int) dbManager.addAction(DBEntityParser.transformActionToEntityAction(action));
            for (Map.Entry<String, String> entry : properties.entrySet()) {
                // transform to action property
                ActionProperty actionProperty = new ActionProperty();
                actionProperty.setActionId(actionId);
                actionProperty.setKey(entry.getKey());
                actionProperty.setValue(entry.getValue());

                dbManager.addActionProperty(actionProperty);
            }

            for (ContextEvent contextEvent : contextEvents) {
                long contextEventId = dbManager
                        .addContextEvent(DBEntityParser.transformContextEvent(actionId, contextEvent));
                for (Property property : DBEntityParser.transformProperty(contextEventId, contextEvent)) {
                    dbManager.addProperty(property);
                }
            }
            dbManager.closeDB();
        }
    }

    /**
     * Method to send locally stored data to the server
     */
    public void sendOfflineStoredContextEventsToServer() {
        Log.d(MusesUtils.TEST_TAG, "UCEH - sendOfflineStoredContextEventsToServer()");
        Log.d(TAG, "called: sendOfflineStoredContextEventsToServer()");
        /*
         * 1. check if the user is authenticated
         * 2. check if the dbManager object is null
         * 3. get a list of all stored actions
         * 4. for each action do:
         * 4.1 get all related properties of that action
         * 4.2 get all context events of that action
         * 4.3 for each context event:
         * 4.3.1 get all related properties to that action
         * 4.4. create a json for
         * 4.5. send this json to the server
         */

        //1. check if the user is authenticated
        if (isUserAuthenticated) {
            Log.d(APP_TAG, "Info SS, Sending offline stored context events to server if user authenticated.");
            // 2. check if the dbManager object is null
            if (dbManager == null) {
                dbManager = new DBManager(context);
            }

            dbManager.openDB();

            // 3. get a list of all stored actions
            for (eu.musesproject.client.db.entity.Action entityAction : dbManager.getActionList()) {
                Action action = DBEntityParser.transformAction(entityAction);

                //  4.1 get all related properties of that action
                List<ActionProperty> entityActionProperties = dbManager
                        .getActionPropertiesOfAction(entityAction.getId());
                Map<String, String> actionProperties = DBEntityParser
                        .transformActionPropertyToMap(entityActionProperties);

                //4.2 get all context events of that action
                List<ContextEvent> contextEvents = new ArrayList<ContextEvent>();
                for (eu.musesproject.client.db.entity.ContextEvent dbContextEvent : dbManager
                        .getStoredContextEventByActionId(entityAction.getId())) {
                    ContextEvent contextEvent = DBEntityParser.transformEntityContextEvent(dbContextEvent);

                    // 4.3.1 get all related properties to that action
                    List<Property> properties = dbManager.getPropertiesOfContextEvent(contextEvent.getId());
                    for (Property property : properties) {
                        contextEvent.addProperty(property.getKey(), property.getValue());
                    }

                    contextEvents.add(contextEvent);
                }

                // 4.4. create a json for
                JSONObject requestObject = JSONManager.createJSON(getImei(), getUserName(), -1,
                        RequestType.ONLINE_DECISION, action, actionProperties, contextEvents);

                // 4.5. send this json to the server
                sendRequestToServer(requestObject);
            }
            dbManager.closeDB();
        }
    }

    /**
     * Info SS
     *
     * Method to send a request to the server
     *
     * @param requestJSON {@link org.json.JSONObject}
     */
    public void sendRequestToServer(JSONObject requestJSON) {
        Log.d(MusesUtils.TEST_TAG, "UCEH - sendRequestToServer(JSONObject requestJSON)");
        Log.d(TAG, "called: sendRequestToServer(JSONObject requestJSON)");
        if (requestJSON != null) {
            if (serverStatus == Statuses.ONLINE) {
                String sendData = requestJSON.toString();
                Log.d(TAG, "sendData:" + sendData);//Demo Debug
                connectionManager.sendData(sendData);
            }
        }
    }

    /**
     * Should be called when the background service is created
     * @param context {@link Context}
     */
    public void setContext(Context context) {
        this.context = context;
    }

    public Context getContext() {
        return this.context;
    }

    public static boolean isServerOnlineAndUserAuthenticated() {
        return serverOnlineAndUserAuthenticated;
    }

    public void updateServerOnlineAndUserAuthenticated() {
        Log.d(MusesUtils.TEST_TAG, "UCEH - updateServerOnlineAndUserAuthenticated Server="
                + (serverStatus == Statuses.ONLINE) + " auth=" + isUserAuthenticated);
        if (serverStatus == Statuses.ONLINE && isUserAuthenticated) {
            serverOnlineAndUserAuthenticated = true;
        } else {
            serverOnlineAndUserAuthenticated = false;
        }
    }

    private class ConnectionCallback implements IConnectionCallbacks {

        @Override
        public int receiveCb(String receivedData) {
            Log.d(MusesUtils.TEST_TAG, "UCEH - receiveCb()");
            Log.d(TAG, "called: receiveCb(String receivedData)");
            if ((receivedData != null) && (!receivedData.equals(""))) {
                if (dbManager == null) {
                    dbManager = new DBManager(context);
                }

                // identify the request type
                String requestType = JSONManager.getRequestType(receivedData);
                Log.d(MusesUtils.TEST_TAG, "UCEH - receiveCb(); requestType=" + requestType);
                Log.d(APP_TAG, "Request type was " + requestType);

                if (requestType.equals(RequestType.ONLINE_DECISION)) {
                    // TODO get decision from the json
                    // send decision to the actuator controller
                    // dummy data
                    Decision decision = new Decision();
                    decision.setName(Decision.GRANTED_ACCESS);
                    Log.d(APP_TAG, "Info DC, Hardcoding decision to GRANT_ACCESS");
                    Log.d(APP_TAG, "Info CT, calling actuator to showFeedback");
                    Log.d(APP_TAG, "showFeedback3");
                    ActuatorController.getInstance().showFeedback(decision);
                } else if (requestType.equals(RequestType.UPDATE_POLICIES)) {
                    Log.d(APP_TAG, "Updating polices");
                    RemotePolicyReceiver.getInstance().updateJSONPolicy(receivedData, context);

                    // look for the related request
                    int requestId = JSONManager.getRequestId(receivedData);
                    Log.d(TAG_RQT, "request_id from the json is " + requestId);
                    if (mapOfPendingRequests != null && mapOfPendingRequests.containsKey(requestId)) {
                        RequestHolder requestHolder = mapOfPendingRequests.get(requestId);
                        requestHolder.getRequestTimeoutTimer().cancel();
                        mapOfPendingRequests.remove(requestId);
                        send(requestHolder.getAction(), requestHolder.getActionProperties(),
                                requestHolder.getContextEvents());
                    }
                } else if (requestType.equals(RequestType.AUTH_RESPONSE)) {
                    Log.d(APP_TAG, "Retreiving auth response from JSON");

                    isUserAuthenticated = JSONManager.getAuthResult(receivedData);
                    if (isUserAuthenticated) {
                        dbManager.openDB();
                        dbManager.insertCredentials(getImei(), tmpLoginUserName, tmpLoginPassword);
                        dbManager.closeDB();
                        // clear the credentials in the fields
                        userName = tmpLoginUserName;
                        tmpLoginUserName = "";
                        tmpLoginPassword = "";

                        serverStatus = Statuses.ONLINE;
                        sendOfflineStoredContextEventsToServer();
                        updateServerOnlineAndUserAuthenticated();
                        sendConfigSyncRequest();
                    }
                    ActuatorController.getInstance().sendLoginResponse(isUserAuthenticated);
                } else if (requestType.equals(RequestType.CONFIG_UPDATE)) {
                    /*
                     *  sensor configuration
                     *  1.1 load config items from JSON
                     *  1.2 insert config items in db
                     *  1.3 notify sensors about the new configuration
                     */
                    // 1.1 load config items from JSON
                    List<SensorConfiguration> configList = JSONManager.getSensorConfig(receivedData);
                    // 1.2 insert config items in db
                    boolean sensorConfigAlreadyExists;
                    dbManager.openDB();
                    sensorConfigAlreadyExists = dbManager.hasSensorConfig();
                    dbManager.closeDB();
                    if (!sensorConfigAlreadyExists) {
                        dbManager.openDB();
                        for (SensorConfiguration configItem : configList) {
                            dbManager.insertSensorConfiguration(configItem);
                        }
                        dbManager.closeDB();
                        // 1.3 notify sensors about the new configuration
                        UserContextMonitoringController.getInstance(getContext()).onSensorConfigurationChanged();
                    }

                    /*
                     *  trials configuration
                     *  2.1 load config from JSON
                     *  2.2 insert into the database
                     */
                    // 2.1
                    boolean isSilentModeActivated = JSONManager.isSilentModeActivated(receivedData);

                    /*
                     *  connection configuration
                     *  3.1 load config from JSON
                     *  3.2 insert new config in the db
                     *  3.3 update the connection manager 
                     */
                    // 3.1 load config from JSON
                    Configuration connectionConfig = JSONManager.getConnectionConfiguration(receivedData,
                            getContext());
                    connectionConfig.setSilentMode(isSilentModeActivated ? 1 : 0);
                    Log.d(MusesUtils.TEST_TAG, "UCEH - isSilentModeActivated=" + isSilentModeActivated);
                    // 2.2 & 3.2 insert new config in the db
                    if (connectionConfig != null) {
                        dbManager.openDB();
                        dbManager.insertConfiguration(connectionConfig);
                        dbManager.closeDB();
                        // 3.3 update the connection manager
                        connectionManager.setTimeout(connectionConfig.getTimeout());
                        connectionManager.setPolling(connectionConfig.getPollingEnabled());
                        connectionManager.setPollTimeOuts(connectionConfig.getPollTimeout(),
                                connectionConfig.getSleepPollTimeout());
                    }
                }
            }
            return 0;
        }

        @Override
        public int statusCb(int status, int detailedStatus) {
            Log.d(TAG, "called: statusCb(int status, int detailedStatus)");
            // detect if server is back online after an offline status
            if (status == Statuses.ONLINE) {
                if (serverStatus == Statuses.OFFLINE) {
                    Log.d(APP_TAG, "Server back to ONLINE, sending offline stored events to server");
                    sendOfflineStoredContextEventsToServer();
                    isUserAuthenticated = false;
                }
                serverStatus = status;
                updateServerOnlineAndUserAuthenticated();
            } else if (status == Statuses.OFFLINE) {
                serverStatus = status;
                updateServerOnlineAndUserAuthenticated();
            }

            if (detailedStatus == DetailedStatuses.UNKNOWN_ERROR) {
                Log.d(MusesUtils.TEST_TAG, "UCEH - UNKNOWN_ERROR callback");
                // fires the unknown error feedback
                //            ActuatorController.getInstance().showFeedback(null);
            }
            serverDetailedStatus = detailedStatus;
            return 0;
        }
    }

    public String getImei() {
        if (imei == null || imei.equals("")) {
            this.imei = new SettingsSensor(getContext()).getIMEI();
        }
        return imei;
    }

    public String getUserName() {
        if (isUserAuthenticated) {
            if (prefs == null) {
                prefs = context.getSharedPreferences(MainActivity.PREFERENCES_KEY, Context.MODE_PRIVATE);
            }
            this.userName = prefs.getString(MainActivity.USERNAME, "");
            if (userName == null || userName.equals("")) {
                this.userName = "unknown"; // TODO look in db too
            }

            return userName;
        } else {
            return "unknown";
        }
    }

    public void removeRequestById(int requestId) {
        Log.d(TAG_RQT, "6. removeRequestById map size: " + mapOfPendingRequests.size());
        if (mapOfPendingRequests != null && mapOfPendingRequests.containsKey(requestId)) {
            mapOfPendingRequests.remove(requestId);
            Log.d(TAG_RQT, "7. removeRequestById map size afterwards: " + mapOfPendingRequests.size());
        }
    }

    @Override
    public void handleRequestTimeout(int requestId) {
        Log.d(TAG_RQT, "5. handleRequestTimeout to id: " + requestId);
        // 1. store object temporary
        // 2. remove object from the map that holds all RequestHolder
        // 3. perform default decision

        // -> 1.
        RequestHolder requestHolder = mapOfPendingRequests.get(requestId);
        // -> 2.
        removeRequestById(requestId);
        // -> 3.
        if (decisionMaker == null) {
            decisionMaker = new DecisionMaker();
        }
        Decision decision = decisionMaker.getDefaultDecision(requestHolder.getAction(),
                requestHolder.getActionProperties(), requestHolder.getContextEvents());
        Log.d(APP_TAG, "showFeedback4");
        ActuatorController.getInstance().showFeedback(decision);
    }
}