/**
Copyright 2014 ATOS SPAIN S.A.
Licensed under the Apache License, Version 2.0 (the License);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Authors :
Sergio GarcĂa Villalonga. Atos Research and Innovation, Atos SPAIN SA
@email sergio.garciavillalonga@atos.net
**/
package eu.betaas.betaasandroidapp.gateway;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import eu.betaas.betaasandroidapp.communicator.GatewayCommunicator;
import eu.betaas.betaasandroidapp.communicator.GatewayCommunicatorException;
import eu.betaas.betaasandroidapp.communicator.GatewayCommunicatorFactory;
import eu.betaas.betaasandroidapp.db.DatabaseManager;
import eu.betaas.betaasandroidapp.pojo.Gateway;
import eu.betaas.betaasandroidapp.pojo.Measurement;
public class GatewayManager {
public enum CommunicationState {UNINSTALLED, INSTALLING, INSTALLED, UNREGISTERED, REGISTERING, REGISTERED,UPDATING, ERROR};
private static Context context = null;
private static GatewayManager instance = null;
private static ArrayList<GatewayListener> gatewayGlobalListeners;
private static HashMap<String, ArrayList<GatewayListener>> gatewayListeners;
private static HashMap<String, Gateway> gateways = null;
private static HashMap<String, CommunicationState> applicationState;
private static HashMap<String, CommunicationState> serviceState;
private static HashMap<String, List<AsyncTask>> installationTasks = null;
public static synchronized GatewayManager getInstance(Context context) {
if (instance == null) {
instance = new GatewayManager(context);
}
return instance;
}
private GatewayManager (Context context) {
GatewayManager.context = context;
GatewayManager.gateways =
new HashMap<String, Gateway>();
GatewayManager.gatewayGlobalListeners =
new ArrayList<GatewayListener>();
GatewayManager.gatewayListeners =
new HashMap<String, ArrayList<GatewayListener>>();
GatewayManager.applicationState =
new HashMap<String, CommunicationState>();
GatewayManager.serviceState =
new HashMap<String, CommunicationState>();
GatewayManager.installationTasks =
new HashMap<String, List<AsyncTask>>();
DatabaseManager dbm =
DatabaseManager.getInstance(GatewayManager.context);
for (Gateway gateway : dbm.getGateways()) {
gateways.put(gateway.getId(), gateway);
applicationState.put(gateway.getId(), CommunicationState.UNINSTALLED);
installationTasks.put(gateway.getId(), new ArrayList<AsyncTask>());
}
}
public List<Gateway> getGateways() {
return new ArrayList(gateways.values());
}
public Gateway getGateway(String gatewayId) {
return gateways.get(gatewayId);
}
public void registerForEvents(String gatewayId, GatewayListener listener) {
ArrayList<GatewayListener> listeners;
synchronized (gatewayListeners) {
listeners = gatewayListeners.get(gatewayId);
if (listeners == null) {
listeners = new ArrayList<GatewayListener>();
listeners.add(listener);
gatewayListeners.put(gatewayId, listeners);
} else {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
}
}
public void unRegisterForEvents(String gatewayId, GatewayListener listener) {
ArrayList<GatewayListener> listeners;
synchronized (gatewayListeners) {
listeners = gatewayListeners.get(gatewayId);
if (listeners != null) {
if (listeners.contains(listener)) {
listeners.remove(listener);
}
}
}
}
public void registerForAllEvents(GatewayListener listener) {
synchronized (gatewayGlobalListeners) {
if (!gatewayGlobalListeners.contains(listener)) {
gatewayGlobalListeners.add(listener);
}
}
}
public void unRegisterForAllEvents(GatewayListener listener) {
synchronized (gatewayGlobalListeners) {
if (gatewayGlobalListeners.contains(listener)) {
gatewayGlobalListeners.remove(listener);
}
}
}
public void registerGateway (String name, String uri, int port) {
boolean register = false;
AsyncTask<Gateway, Void, Object> task;
Gateway gateway = new Gateway(name, uri, port, "",
new ArrayList<String>(), new ArrayList<String>());
synchronized (gateways) {
if (!gateways.keySet().contains(gateway.getId())) {
gateways.put(gateway.getId(), gateway);
register = true;
}
}
if (register) {
synchronized (applicationState) {
applicationState.put(gateway.getId(), CommunicationState.UNINSTALLED);
}
synchronized (serviceState) {
for (String service : gateway.getServices()) {
serviceState.put(gateway.getId()+gateway.getAppId()+service,
CommunicationState.UNREGISTERED);
}
}
task = new AsyncTask<Gateway, Void, Object>() {
@Override
protected Object doInBackground(Gateway... params) {
DatabaseManager dbm =
DatabaseManager.getInstance(context);
dbm.storeGateway(params[0]);
installationTasks.put(params[0].getId(),
new ArrayList<AsyncTask>());
return params[0];
}
@Override
protected void onPostExecute(Object result) {
notifyGatewayInstalled((Gateway) result);
super.onPostExecute(result);
}
};
executeTask(task, gateway);
}
}
public void updateGateway (Gateway gateway) {
boolean update = false;
AsyncTask<Gateway, Void, Object> task;
synchronized (gateways) {
if (gateways.keySet().contains(gateway.getId())) {
gateways.put(gateway.getId(), gateway);
update = true;
}
}
if (update) {
task = new AsyncTask<Gateway, Void, Object>() {
@Override
protected Object doInBackground(Gateway... params) {
DatabaseManager dbm =
DatabaseManager.getInstance(context);
dbm.updateGateway(params[0]);
return params[0];
}
@Override
protected void onPostExecute(Object result) {
notifyGatewayUpdated((Gateway)result);
super.onPostExecute(result);
}
};
executeTask(task, gateway);
}
}
public synchronized void deleteGateway (final Gateway gateway) {
boolean delete = false;
AsyncTask<Gateway, Void, Object> task;
synchronized (gateways) {
if (gateways.keySet().contains(gateway.getId())) {
gateways.remove(gateway.getId());
delete = true;
}
}
if (delete) {
synchronized (applicationState) {
applicationState.remove(gateway.getId());
}
synchronized (serviceState) {
for (String service : gateway.getServices()) {
serviceState.remove(gateway.getId()+gateway.getAppId()+service);
}
}
task = new AsyncTask<Gateway, Void, Object>() {
@Override
protected Object doInBackground(Gateway... params) {
final Gateway gw = params[0];
GatewayCommunicator gc =
GatewayCommunicatorFactory.getCommunicator(
gw.getUri(), gw.getPort());
for (String service : gw.getServices()) {
try {
gc.unsubscribe(gw, service);
} catch (GatewayCommunicatorException e) {}
}
for (AsyncTask task : installationTasks.get(gw.getId())) {
task.cancel(true);
}
installationTasks.remove(gw.getId());
try {
gc.uninstallApplication(gw);
} catch (GatewayCommunicatorException e) {
return e;
}
DatabaseManager dbm =
DatabaseManager.getInstance(context);
dbm.deleteGateway(gw);
return gw;
}
@Override
protected void onPostExecute(Object result) {
if (result instanceof Gateway) {
notifyGatewayRemoved(CommunicationState.UNINSTALLED,
(Gateway) result, "");
} else if (result instanceof GatewayCommunicatorException) {
GatewayCommunicatorException e =
(GatewayCommunicatorException) result;
notifyGatewayRemoved(CommunicationState.ERROR,
e.getGateway(),
"Delete gateway: " + e.getCode() + " - " + e.getMessage());
}
super.onPostExecute(result);
}
};
executeTask(task, gateway);
}
}
public CommunicationState installApplication(String gatewayId) {
AsyncTask<Gateway, Void, Object> task;
Gateway gateway;
CommunicationState state;
synchronized (applicationState) {
state = applicationState.get(gatewayId);
if (state == CommunicationState.UNINSTALLED) {
state = CommunicationState.INSTALLING;
applicationState.put(gatewayId, state);
} else {
return state;
}
}
synchronized (gateways) {
gateway = gateways.get(gatewayId);
}
task = new AsyncTask<Gateway, Void, Object>() {
@Override
protected Object doInBackground(Gateway... params) {
Gateway gw = params[0];
GatewayCommunicator gc =
GatewayCommunicatorFactory.getCommunicator(gw.getUri(), gw.getPort());
Gateway ret;
try {
ret = gc.installApplication(gw);
synchronized (applicationState) {
if (applicationState.get(ret.getId()) ==
CommunicationState.INSTALLING) {
String ref;
DatabaseManager dbm =
DatabaseManager.getInstance(context);
dbm.updateGatewayAppId(ret);
dbm.updateGatewayServices(ret);
dbm.updateGatewayTokens(ret);
for (String service : ret.getServices()) {
ref = ret.getId() + ret.getAppId() + service;
serviceState.put(ref, CommunicationState.UNREGISTERED);
}
applicationState.put(ret.getId(),
CommunicationState.INSTALLED);
}
}
return ret;
} catch (GatewayCommunicatorException e) {
synchronized (applicationState) {
if (applicationState.get(e.getGateway().getId()) ==
CommunicationState.INSTALLING) {
applicationState.put(e.getGateway().getId(),
CommunicationState.UNINSTALLED);
}
}
return e;
}
}
@Override
protected void onPostExecute(Object result) {
if (result instanceof Gateway) {
notifyApplicationInstalled(CommunicationState.INSTALLED,
(Gateway) result, "");
} else if (result instanceof GatewayCommunicatorException) {
GatewayCommunicatorException e =
(GatewayCommunicatorException) result;
notifyApplicationInstalled(CommunicationState.ERROR,
e.getGateway(),
"Install application: " + e.getCode() + " - " + e.getMessage());
}
super.onPostExecute(result);
}
};
installationTasks.get(gatewayId).add(task);
executeTask(task, gateway);
return state;
}
public CommunicationState subscribe(String gatewayId,
final String serviceId) {
AsyncTask<Gateway, Void, Object> task;
String ref;
Gateway gateway;
CommunicationState state;
synchronized (gateways) {
gateway = gateways.get(gatewayId);
if (!gateway.getServices().contains(serviceId)) {
return CommunicationState.ERROR;
}
}
ref = gateway.getId()+gateway.getAppId()+serviceId;
synchronized (serviceState) {
state = serviceState.get(ref);
if (state == CommunicationState.UNREGISTERED) {
state = CommunicationState.REGISTERING;
serviceState.put(ref, state);
} else {
//Could return REGISTERING, REGISTERED, UPDATING
return state;
}
}
task = new AsyncTask<Gateway, Void, Object>() {
@Override
protected Object doInBackground(Gateway... params) {
Gateway gw = params[0];
GatewayCommunicator gc =
GatewayCommunicatorFactory.getCommunicator(gw.getUri(), gw.getPort());
Gateway ret;
try {
ret = gc.subscribe(gw, serviceId);
String ref = ret.getId() + ret.getAppId() + serviceId;
synchronized (applicationState) {
if (serviceState.get(ref) ==
CommunicationState.REGISTERING) {
serviceState.put(ref, CommunicationState.REGISTERED);
}
}
return ret;
} catch (GatewayCommunicatorException e) {
ret = e.getGateway();
String ref = ret.getId() + ret.getAppId() + serviceId;
synchronized (serviceState) {
if (serviceState.get(ref) ==
CommunicationState.REGISTERING) {
serviceState.put(ref, CommunicationState.UNREGISTERED);
}
}
return e;
}
}
@Override
protected void onPostExecute(Object result) {
if (result instanceof Gateway) {
notifyServiceSubscribed(CommunicationState.REGISTERED,
(Gateway) result, serviceId, "");
} else if (result instanceof GatewayCommunicatorException) {
GatewayCommunicatorException e =
(GatewayCommunicatorException) result;
notifyServiceSubscribed(CommunicationState.ERROR,
e.getGateway(), serviceId,
"Subscribe: " + e.getCode() + " - " + e.getMessage());
}
super.onPostExecute(result);
}
};
executeTask(task, gateway);
return state;
}
public CommunicationState getPresence (String gatewayId,
final String serviceId) {
AsyncTask<Gateway, Void, Object> task;
String ref;
Gateway gateway;
CommunicationState state;
synchronized (gateways) {
gateway = gateways.get(gatewayId);
if (!gateway.getServices().contains(serviceId)) {
return CommunicationState.ERROR;
}
}
ref = gateway.getId()+gateway.getAppId()+serviceId;
synchronized (serviceState) {
state = serviceState.get(ref);
if (state == CommunicationState.REGISTERED) {
state = CommunicationState.UPDATING;
serviceState.put(ref, state);
} else {
//Could return UNREGISTERED, REGINSTERING, UPDATING, ERROR
return state;
}
}
task = new AsyncTask<Gateway, Void, Object>() {
@Override
protected Object doInBackground(Gateway... params) {
Gateway gw = params[0];
GatewayCommunicator gc =
GatewayCommunicatorFactory.getCommunicator(gw.getUri(), gw.getPort());
Measurement measurement;
try {
measurement = gc.getPresence(gw, serviceId);
DatabaseManager dbm =
DatabaseManager.getInstance(context);
dbm.storeMeasurement(measurement);
String ref = gw.getId() + gw.getAppId() + serviceId;
synchronized (serviceState) {
serviceState.put(ref, CommunicationState.REGISTERED);
}
} catch (GatewayCommunicatorException e) {
return e;
}
return measurement;
}
@Override
protected void onPostExecute(Object result) {
if (result instanceof Measurement) {
notifyDataUpdate((Measurement) result);
}
super.onPostExecute(result);
}
};
executeTask(task, gateway);
return state;
}
public CommunicationState uninstallApplication () {
return null;
}
public CommunicationState unsubscribe() {
return null;
}
private ArrayList<GatewayListener> getListeners(String idGateway) {
ArrayList<GatewayListener> ret = new ArrayList<GatewayListener>();
ArrayList<GatewayListener> listeners;
synchronized (gatewayListeners) {
listeners = gatewayListeners.get(idGateway);
if (listeners != null) {
ret = (ArrayList<GatewayListener>) listeners.clone();
}
}
return ret;
}
private void notifyGatewayInstalled(Gateway gateway) {
ArrayList<GatewayListener> globalListeners;
ArrayList<GatewayListener> listeners = getListeners(gateway.getId());
synchronized (gatewayGlobalListeners) {
globalListeners =
(ArrayList<GatewayListener>) gatewayGlobalListeners.clone();
}
for (GatewayListener listener : listeners) {
listener.onGatewayInstallSuccess(gateway);
}
for (GatewayListener listener : globalListeners) {
listener.onGatewayInstallSuccess(gateway);
}
}
private void notifyGatewayUpdated(Gateway gateway) {
ArrayList<GatewayListener> globalListeners;
ArrayList<GatewayListener> listeners = getListeners(gateway.getId());
synchronized (gatewayGlobalListeners) {
globalListeners =
(ArrayList<GatewayListener>) gatewayGlobalListeners.clone();
}
for (GatewayListener listener : listeners) {
listener.onGatewayUpdateSuccess(gateway);
}
for (GatewayListener listener : globalListeners) {
listener.onGatewayUpdateSuccess(gateway);
}
}
private void notifyGatewayRemoved(CommunicationState state,
Gateway gateway,
String cause) {
ArrayList<GatewayListener> globalListeners;
ArrayList<GatewayListener> listeners = getListeners(gateway.getId());
synchronized (gatewayGlobalListeners) {
globalListeners =
(ArrayList<GatewayListener>) gatewayGlobalListeners.clone();
}
if (state != CommunicationState.ERROR) {
for (GatewayListener listener : listeners) {
listener.onGatewayRemoveSuccess(gateway);
}
for (GatewayListener listener : globalListeners) {
listener.onGatewayRemoveSuccess(gateway);
}
} else {
for (GatewayListener listener : listeners) {
listener.onGatewayRemoveFailure(gateway, cause);
}
for (GatewayListener listener : globalListeners) {
listener.onGatewayRemoveFailure(gateway, cause);
}
}
}
private void notifyApplicationInstalled(CommunicationState state,
Gateway gateway,
String cause) {
ArrayList<GatewayListener> listeners = getListeners(gateway.getId());
if (state != CommunicationState.ERROR) {
for (GatewayListener listener : listeners) {
listener.onApplicationInstallSuccess(gateway);
}
} else {
for (GatewayListener listener : listeners) {
listener.onApplicationInstallFailure(cause);
}
}
}
private void notifyApplicationUninstalled(String idGateway) {
ArrayList<GatewayListener> listeners = getListeners(idGateway);
for (GatewayListener listener : listeners) {
listener.onApplicationUninstallSuccess();
}
}
private void notifyServiceSubscribed(CommunicationState state,
Gateway gateway,
String serviceId,
String cause) {
ArrayList<GatewayListener> listeners = getListeners(gateway.getId());
if (state != CommunicationState.ERROR) {
for (GatewayListener listener : listeners) {
listener.onServiceSubscribeSuccess(serviceId);
}
} else {
for (GatewayListener listener : listeners) {
listener.onServiceSubscribeFailure(serviceId, cause);
}
}
}
private void notifyServiceUnSubscribed(String idGateway) {
ArrayList<GatewayListener> listeners = getListeners(idGateway);
for (GatewayListener listener : listeners) {
listener.onServiceUnSubscribeSuccess();
}
}
private void notifyDataUpdate(Measurement measurement) {
ArrayList<GatewayListener> listeners = getListeners(measurement.getGatewayId());
for (GatewayListener listener : listeners) {
listener.onDataUpdate(measurement);
}
}
private void executeTask(AsyncTask<Gateway, Void, Object> task, Gateway gateway) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, gateway);
} else {
task.execute(gateway);
}
}
}