blob: c4d49927291f2b7a779b8f59e5e3b1795b9c6f94 [file] [log] [blame]
/**
* Copyright (c) 2018 CEA.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* CEA - initial API and implementation and/or initial documentation
*/
package org.eclipse.sensinact.studio.model.manager.modelupdater;
import java.io.IOException;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.sensinact.studio.http.messages.snamessage.MsgSensinact;
import org.eclipse.sensinact.studio.http.messages.snamessage.ObjectNameTypeValue;
import org.eclipse.sensinact.studio.http.messages.snamessage.attributevalueupdated.MsgAttributeValueUpdated;
import org.eclipse.sensinact.studio.http.messages.snamessage.basic.MsgHttpError;
import org.eclipse.sensinact.studio.http.messages.snamessage.completelist.MsgCompleteList;
import org.eclipse.sensinact.studio.http.messages.snamessage.completelist.ObjectProvider;
import org.eclipse.sensinact.studio.http.messages.snamessage.getresponse.MsgGetResponse;
import org.eclipse.sensinact.studio.http.messages.snamessage.lifecycle.MsgProviderAppearing;
import org.eclipse.sensinact.studio.http.messages.snamessage.lifecycle.MsgProviderDisappearing;
import org.eclipse.sensinact.studio.http.messages.snamessage.lifecycle.MsgResourceAppearing;
import org.eclipse.sensinact.studio.http.messages.snamessage.lifecycle.MsgResourceDisappearing;
import org.eclipse.sensinact.studio.http.messages.snamessage.lifecycle.MsgServiceAppearing;
import org.eclipse.sensinact.studio.http.messages.snamessage.lifecycle.MsgServiceDisappearing;
import org.eclipse.sensinact.studio.http.messages.snamessage.resourceslist.MsgResourcesList;
import org.eclipse.sensinact.studio.http.messages.snamessage.serviceslist.MsgServicesList;
import org.eclipse.sensinact.studio.http.services.client.GatewayHttpClient;
import org.eclipse.sensinact.studio.http.services.client.GatewayHttpClient.RequestParameter;
import org.eclipse.sensinact.studio.http.services.client.connectionmanager.NotifDispatcher;
import org.eclipse.sensinact.studio.http.services.client.listener.NotifSubscriptionListener;
import org.eclipse.sensinact.studio.model.resource.utils.DeviceDescriptor;
import org.eclipse.sensinact.studio.model.resource.utils.GPScoordinates;
import org.eclipse.sensinact.studio.model.resource.utils.GPSparsingException;
import org.eclipse.sensinact.studio.model.resource.utils.ResourceDescriptor;
import org.eclipse.sensinact.studio.model.resource.utils.Segments;
import org.eclipse.sensinact.studio.model.resource.utils.ServiceDescriptor;
import org.eclipse.sensinact.studio.resource.AccessMethodType;
/**
* @author Nicolas Hili, Etienne Gandrille, Jander and others
*/
public class ModelUpdater implements NotifSubscriptionListener {
private static final Logger logger = Logger.getLogger(ModelUpdater.class);
private static ModelUpdater INSTANCE;
public static ModelUpdater getInstance() {
if (INSTANCE == null)
INSTANCE = new ModelUpdater();
return INSTANCE;
}
private final ModelUpdateStack stack = new ModelUpdateStack();
private ModelUpdater() {
NotifDispatcher.getInstance().subscribe(this);
}
/**
* Get all devices from the gateway and updates the model.
*
* @throws IOException
*/
public void updateDevices(final String gatewayName) throws IOException {
logger.info("Full model update triggered");
Segments segments = new Segments.Builder().gateway(gatewayName).root().build();
MsgSensinact snaMsg = GatewayHttpClient.sendGetRequest(segments);
if (!(snaMsg instanceof MsgCompleteList)) {
displayLogOnError(snaMsg, "devices");
return;
}
MsgCompleteList list = (MsgCompleteList) snaMsg;
// update devices list
new Thread() {
public void run() {
// remove device
for (String localDeviceId : ModelEditor.getInstance().getDevicesId(gatewayName)) {
try {
if(!list.getProvidersId().contains(localDeviceId))
stack.add(new DeviceDisappearing(new DeviceDescriptor(gatewayName, localDeviceId)));
}catch(Exception e) {
logger.error(e.getMessage(),e);
}
}
// add devices
for (ObjectProvider provider : list.getProviders()){
if(provider.getLocation() == null){
continue;
}
DeviceDescriptor desc = new DeviceDescriptor(gatewayName, provider.getName());
desc.setLocation(provider.getLocation());
stack.add(new DeviceAppearing(desc));
}
}
}.start();
}
/**
* Get all services on a device, from the gateway, and updates the model.
*
* @param device
* the device from which services need to be retrieved
* @throws IOException
*/
public void updateServices(final String gatewayName, final String deviceId) throws IOException {
Segments segments = new Segments.Builder().gateway(gatewayName).device(deviceId).services().build();
MsgSensinact snaMsg = GatewayHttpClient.sendGetRequest(segments);
if (!(snaMsg instanceof MsgServicesList)) {
System.out.println(snaMsg);
displayLogOnError(snaMsg, "services");
return;
}
if(((MsgServicesList) snaMsg).getServices() == null)
return;
// remove service
for (String localServiceId : ModelEditor.getInstance().getServicesId(gatewayName, deviceId)) {
try {
if(!((MsgServicesList) snaMsg).getServices().contains(localServiceId))
stack.add(new ServiceDisappearing(new ServiceDescriptor(gatewayName, deviceId, localServiceId)));
} catch(Exception ex) {
logger.error(ex.getMessage(),ex);
}
}
for (String service : ((MsgServicesList) snaMsg).getServices()){
stack.add(new ServiceAppearing(new ServiceDescriptor(gatewayName, deviceId, service)));
}
}
/* ================ */
/* Update resources */
/* ================ */
/**
* Retrieve all resources from one service
*
* @param service
* the service from which resources need to be retrieved
* @throws IOException
*/
public void updateResources(final String gatewayName, final String deviceId, final String serviceId) throws IOException {
Segments segment = new Segments.Builder().gateway(gatewayName).device(deviceId).service(serviceId).resources().build();
MsgSensinact msg = GatewayHttpClient.sendGetRequest(segment);
if (!(msg instanceof MsgResourcesList)) {
displayLogOnError(msg, "resources");
return;
}
if(((MsgResourcesList) msg).getResources() == null)
return;
// remove resources
for (String localResourceId : ModelEditor.getInstance().getResourcesId(gatewayName, deviceId, serviceId)) {
try {
if(!((MsgResourcesList) msg).getResources().contains(localResourceId))
stack.add(new ResourceDisappearing(new ResourceDescriptor(gatewayName, deviceId, serviceId,localResourceId)));
} catch(Exception ex) {
logger.error(ex.getMessage(),ex);
}
}
//add resources
for (String resource : ((MsgResourcesList) msg).getResources()) {
if(serviceId.equals("admin") && resource.equals("icon")) {
try {
ResourceDescriptor rd = updateResource(gatewayName, deviceId, serviceId, resource);
if(rd != null) {
stack.add(new ResourceAppearing(rd));
String icon = null;
ObjectNameTypeValue ontv = rd.getInitial();
if(ontv != null) {
String ic = ontv.getValueAsString();
icon = "null".equals(ic)?null:ic;
}
ModelEditor.getInstance().setIcon(new DeviceDescriptor(rd.getGateway(), rd.getDevice()), icon);
}
} catch(Exception ex) {
logger.error(ex.getMessage(),ex);
}
} else
stack.add(new ResourceAppearing(new ResourceDescriptor(gatewayName, deviceId, serviceId, resource)));
}
}
/**
* Retrieve all resources from one service
*
* @param service
* the service from which resources need to be retrieved
* @throws IOException
*/
public ResourceDescriptor updateResource(final String gatewayName, final String deviceId, final String serviceId, final String resourceId) throws IOException {
Segments segment = new Segments.Builder().gateway(gatewayName).device(deviceId).service(serviceId).resource(resourceId).method(AccessMethodType.GET).build();
MsgSensinact msg = GatewayHttpClient.sendGetRequest(segment);
if (!(msg instanceof MsgGetResponse)) {
displayLogOnError(msg, "GET");
return null;
}
MsgGetResponse response = (MsgGetResponse)msg;
ResourceDescriptor desc = new ResourceDescriptor(gatewayName, deviceId, serviceId, resourceId);
desc.setInitial(response.getResponse());
return desc;
}
/* =============== */
/* Update location */
/* =============== */
public boolean updateLocationOnServer(DeviceDescriptor deviceDescriptor, GPScoordinates coordinates) {
Segments segments = new Segments.Builder().device(deviceDescriptor).service("admin").resource("location").method(AccessMethodType.SET).build();
RequestParameter param = new RequestParameter("location", "string", coordinates.getLat() + ":" + coordinates.getLng());
try {
MsgSensinact msg = GatewayHttpClient.sendPostRequest(segments, null,param);
if (msg instanceof MsgHttpError) {
return false;
} else {
return true;
}
} catch (IOException e) {
logger.error("Update location on server failed", e);
return false;
}
}
/* ========= */
/* Listeners */
/* ========= */
@Override
public void onLifecycleEvent(String gateway, List<MsgSensinact> messages) {
for (MsgSensinact message : messages)
onLifecycleEvent(gateway, message);
}
public void onLifecycleEvent(String gateway, MsgSensinact message) {
String uri = message.getUri();
ModelUpdate<?> mu = null;
if (message instanceof MsgProviderAppearing) {
mu = new DeviceAppearing(new DeviceDescriptor(gateway, getProviderName(uri)));
} else if (message instanceof MsgProviderDisappearing) {
mu = new DeviceDisappearing(new DeviceDescriptor(gateway, getProviderName(uri)));
} else if (message instanceof MsgServiceAppearing) {
mu = new ServiceAppearing(new ServiceDescriptor(gateway, getProviderName(uri),getServiceName(uri)));
} else if (message instanceof MsgServiceDisappearing) {
mu = new ServiceDisappearing(new ServiceDescriptor(gateway, getProviderName(uri),getServiceName(uri)));
} else if (message instanceof MsgResourceAppearing) {
ResourceDescriptor d = new ResourceDescriptor(gateway,getProviderName(uri),getServiceName(uri),getResourceName(uri));
d.setInitial(((MsgResourceAppearing)message).getInitial());
mu = new ResourceAppearing(d);
} else if (message instanceof MsgResourceDisappearing) {
mu = new ResourceDisappearing(new ResourceDescriptor(gateway,
getProviderName(uri),getServiceName(uri),
getResourceName(uri)));
} else {
displayLogOnError(message, "lifecycle");
return;
}
stack.add(mu);
}
@Override
public void onLocationEvent(String gateway, List<MsgSensinact> messages) {
for (MsgSensinact message : messages)
onLocationEvent(gateway, message);
}
public void onLocationEvent(String gateway, MsgSensinact message) {
if(!(message instanceof MsgAttributeValueUpdated) || !((MsgAttributeValueUpdated)message).isLocationValue()){
return;
}
MsgAttributeValueUpdated lu = (MsgAttributeValueUpdated)message;
String uri = lu.getUri();
String device = getProviderName(uri);
try {
lu.getUri();
ModelEditor.getInstance().setLocation(new DeviceDescriptor(gateway, device),
new GPScoordinates(lu.getNotification().getValueAsString()));
} catch (GPSparsingException e) {
logger.error(e.getMessage(),e);
}
}
static void executeInThread(Runnable r){
Runnable runnableWithTry = () -> {
try {
r.run();
} catch (Exception e) {
logger.error(e);
}
};
new Thread(runnableWithTry).start();
}
public void onIconEvent(String gateway, List<MsgSensinact> messages) {
for (MsgSensinact message : messages)
onIconEvent(gateway, message);
}
@Override
public void onIconEvent(String gateway, MsgSensinact message) {
if(!(message instanceof MsgAttributeValueUpdated) || !((MsgAttributeValueUpdated)message).isIconValue()){
return;
}
MsgAttributeValueUpdated lu = (MsgAttributeValueUpdated)message;
String uri = lu.getUri();
String device = getProviderName(uri);
ModelEditor.getInstance().setIcon(new DeviceDescriptor(gateway, device), lu.getNotification().getValueAsString());
}
@Override
public void onValueEvent(String gateway, List<MsgSensinact> messages) {
// do nothing for now
}
private String getProviderName(String uri) {
String[] tokens = uri.split("/");
return tokens[1];
}
private String getServiceName(String uri) {
String[] tokens = uri.split("/");
return tokens[2];
}
private String getResourceName(String uri) {
String[] tokens = uri.split("/");
return tokens[3];
}
/* ========= */
/* Exception */
/* ========= */
private void displayLogOnError(MsgSensinact response, String elementName) {
String fullMsg = String.format("Error sent by gateway while getting %s (%s)", elementName, response.getType());
logger.error(fullMsg);
}
}