Update model asynchronously

Allow model to update icon attach to a Device
diff --git a/services/org.eclipse.sensinact.studio.model.manager/.classpath b/services/org.eclipse.sensinact.studio.model.manager/.classpath
index 098194c..01836c4 100644
--- a/services/org.eclipse.sensinact.studio.model.manager/.classpath
+++ b/services/org.eclipse.sensinact.studio.model.manager/.classpath
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
-	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/http/DeviceInfoRoute.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/http/DeviceInfoRoute.java
index d004eed..6236ace 100644
--- a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/http/DeviceInfoRoute.java
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/http/DeviceInfoRoute.java
@@ -41,7 +41,7 @@
 			sb.append("<b>" + fullName + "</b><br/>");
 			List<String> serviceIds = ModelEditor.getInstance().getServicesId(gatewayName, deviceName);
 			if(serviceIds.size()==0){
-				ModelUpdater.getInstance().updateServices(gatewayName, deviceName, true);
+				ModelUpdater.getInstance().updateServices(gatewayName, deviceName);
 				serviceIds = ModelEditor.getInstance().getServicesId(gatewayName, deviceName);
 			}
 			for (String serviceId : serviceIds) {
@@ -51,9 +51,6 @@
 			}
 			
 			return sb.toString();
-		} catch (InterruptedException e) {
-			logger.error("DeviceInfoRoute", e);
-			return "ERROR - see logs";
 		} catch (UnsupportedEncodingException e) {
 			logger.error("DeviceInfoRoute - decode error", e);
 			return "ERROR - see logs";
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/http/UpdateLocationRoute.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/http/UpdateLocationRoute.java
index 98095c8..2a58ef3 100644
--- a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/http/UpdateLocationRoute.java
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/http/UpdateLocationRoute.java
@@ -14,7 +14,7 @@
 
 import org.apache.log4j.Logger;
 import org.eclipse.sensinact.studio.http.services.server.SensinactServerResource;
-import org.eclipse.sensinact.studio.model.manager.listener.devicelocation.DeviceLocationManager;
+import org.eclipse.sensinact.studio.model.manager.listener.devicelocation.DeviceUpdateManager;
 import org.eclipse.sensinact.studio.model.resource.utils.DeviceDescriptor;
 import org.eclipse.sensinact.studio.model.resource.utils.GPScoordinates;
 import org.json.JSONException;
@@ -35,13 +35,11 @@
 	public Response getValue(String params) throws UnsupportedEncodingException {
 		Response response = getResponse();
 
-		DeviceLocationManager locationManager = DeviceLocationManager.getInstance();
+		DeviceUpdateManager locationManager = DeviceUpdateManager.getInstance();
 		String gatewayName = getRequestAttribute("gateway");
 		String deviceName = getRequestAttribute("device");
 		DeviceDescriptor deviceDescriptor = new DeviceDescriptor(gatewayName, deviceName);
 		GPScoordinates oldLocation = locationManager.getKnownLocation(deviceDescriptor);
-		
-		
 		try {		
 			JSONObject jsonMsg = new JSONObject(params);
 			double lat = (Double) jsonMsg.get("lat");
@@ -55,7 +53,7 @@
 				response.setStatus(Status.CLIENT_ERROR_UNAUTHORIZED);
 				setCoordinatesInEntity(response, oldLocation.getLat(), oldLocation.getLng());
 			}
-		} catch (JSONException e) {
+		} catch (NullPointerException | JSONException e) {
 			logger.error("Update Location Route", e);
 			setCoordinatesInEntity(response, oldLocation.getLat(), oldLocation.getLng());
 			response.setStatus(Status.SERVER_ERROR_INTERNAL);
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceIconListener.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceIconListener.java
new file mode 100644
index 0000000..ec9fcee
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceIconListener.java
@@ -0,0 +1,23 @@
+/**

+ * 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.listener.devicelocation;

+

+import org.eclipse.sensinact.studio.model.resource.utils.DeviceDescriptor;

+

+/**

+ * 

+ */

+public interface DeviceIconListener {

+

+	public void deviceIconUpdated(DeviceDescriptor descriptor);

+	

+	public void deviceRemoved(DeviceDescriptor descriptor);

+}

diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceLocationListener.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceLocationListener.java
index 3f4cac6..2bceb0d 100644
--- a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceLocationListener.java
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceLocationListener.java
@@ -1,24 +1,24 @@
-/**
- * Copyright (c) 2019 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.listener.devicelocation;
-
-import org.eclipse.sensinact.studio.model.resource.utils.DeviceDescriptor;
-import org.eclipse.sensinact.studio.model.resource.utils.GPScoordinates;
-
-/**
- * @author Etienne Gandrille
- */
-public interface DeviceLocationListener {
-
-	public void deviceLocationUpdated(GPScoordinates coordinate, DeviceDescriptor descriptor);
-	
-	public void deviceRemoved(DeviceDescriptor descriptor);
-}
+/**

+ * 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.listener.devicelocation;

+

+import org.eclipse.sensinact.studio.model.resource.utils.DeviceDescriptor;

+import org.eclipse.sensinact.studio.model.resource.utils.GPScoordinates;

+

+/**

+ * @author Etienne Gandrille

+ */

+public interface DeviceLocationListener {

+

+	public void deviceLocationUpdated(GPScoordinates coordinate, DeviceDescriptor descriptor);

+	

+	public void deviceRemoved(DeviceDescriptor descriptor);

+}

diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceLocationManager.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceLocationManager.java
deleted file mode 100644
index d1dfec8..0000000
--- a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceLocationManager.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * Copyright (c) 2019 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.listener.devicelocation;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.log4j.Logger;
-import org.eclipse.sensinact.studio.model.manager.modelupdater.ModelUpdater;
-import org.eclipse.sensinact.studio.model.resource.utils.DeviceDescriptor;
-import org.eclipse.sensinact.studio.model.resource.utils.GPScoordinates;
-
-/**
- * @author Etienne Gandrille
- */
-public class DeviceLocationManager {
-
-	private static final Logger logger = Logger.getLogger(DeviceLocationManager.class);
-	
-	private static DeviceLocationManager INSTANCE = null;
-	private final Set<DeviceLocationListener> locationListeners = new HashSet<DeviceLocationListener>();
-
-	private final Map<DeviceDescriptor, GPScoordinates> locations = new HashMap<DeviceDescriptor, GPScoordinates>();  
-	
-	private DeviceLocationManager() {
-	}
-
-	public static DeviceLocationManager getInstance() {
-		if (INSTANCE == null)
-			INSTANCE = new DeviceLocationManager();
-		return INSTANCE;
-	}
-
-	public void removeDeviceLocationListener(DeviceLocationListener listener) {
-		locationListeners.remove(listener);
-	}
-
-	public void addDeviceLocationListener(DeviceLocationListener listener) {
-		locationListeners.add(listener);
-	}
-
-	public void updateLocationInStudio(DeviceDescriptor deviceDescriptor, GPScoordinates newCoordinates) {
-		if (needUpdate(deviceDescriptor, newCoordinates)) {
-			locations.put(deviceDescriptor, newCoordinates);
-			logger.debug("Device location updated for " + deviceDescriptor + ". Notification fired (" + locationListeners.size() + " listeners");
-			for (DeviceLocationListener listener : locationListeners) {
-				listener.deviceLocationUpdated(newCoordinates, deviceDescriptor);
-			}
-		}
-	}
-
-	public void deleteGatewayInStudio(String gatewayName) {
-		// for iterating safely over the keyset while deleting elements in the map
-		DeviceDescriptor[] tab = locations.keySet().toArray(new DeviceDescriptor[0]);
-		
-		for (int i=0; i<tab.length; i++) {
-			DeviceDescriptor descriptor = tab [i];
-			if (descriptor.getGateway() != null && descriptor.getGateway().equals(gatewayName)) {
-				deleteDeviceInStudio(descriptor);
-			}
-		}
-	}
-	
-	public void deleteDeviceInStudio(DeviceDescriptor deviceDescriptor) {
-		locations.remove(deviceDescriptor);
-		logger.debug("Device location removed for " + deviceDescriptor + ". Notification fired (" + locationListeners.size() + " listeners");
-		for (DeviceLocationListener listener : locationListeners) {
-			listener.deviceRemoved(deviceDescriptor);
-		}
-	}
-	
-	public GPScoordinates getKnownLocation(DeviceDescriptor deviceDescriptor) {
-		return locations.get(deviceDescriptor);
-	}
-	
-	/**
-	 * 
-	 * @param deviceDescriptor
-	 * @param newCoordinates
-	 * @return true if success, false if update location failed. It happens when the location is not updatable. 
-	 */
-	public boolean updateLocationInServer(DeviceDescriptor deviceDescriptor, GPScoordinates newCoordinates) {
-		if (needUpdate(deviceDescriptor, newCoordinates)) {
-			if (ModelUpdater.getInstance().updateLocationOnServer(deviceDescriptor, newCoordinates)) {
-				locations.put(deviceDescriptor, newCoordinates);
-				return true;
-			} else {
-				return false;
-			}
-		} else {
-			return false;
-		}
-	}
-	
-	private boolean needUpdate(DeviceDescriptor deviceDescriptor, GPScoordinates newCoordinates) {
-		GPScoordinates oldCoordinates = locations.get(deviceDescriptor);
-		return (! newCoordinates.equals(oldCoordinates));
-	}
-	
-	@Override
-	public String toString() {
-		StringBuilder sb = new StringBuilder();
-		boolean start = true;
-		for (DeviceDescriptor deviceDescriptor : locations.keySet()) {
-			if (start)
-				start = false;
-			else
-				sb.append("\n");
-			sb.append(deviceDescriptor);
-			sb.append(" ");
-			sb.append(locations.get(deviceDescriptor));
-		}
-		return sb.toString();
-	}
-}
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceSelectionListener.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceSelectionListener.java
new file mode 100644
index 0000000..8a55cde
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceSelectionListener.java
@@ -0,0 +1,11 @@
+package org.eclipse.sensinact.studio.model.manager.listener.devicelocation;
+
+import org.eclipse.sensinact.studio.model.resource.utils.GPScoordinates;
+
+/**
+ *
+ */
+public interface DeviceSelectionListener {
+	
+	void deviceSelected(final GPScoordinates coordinate);
+}
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceUpdateManager.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceUpdateManager.java
new file mode 100644
index 0000000..db06779
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/listener/devicelocation/DeviceUpdateManager.java
@@ -0,0 +1,235 @@
+/**

+ * 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.listener.devicelocation;

+

+import java.io.IOException;

+import java.util.HashSet;

+import java.util.List;

+import java.util.Set;

+

+import org.apache.log4j.Logger;

+import org.eclipse.emf.common.notify.Notification;

+import org.eclipse.emf.ecore.EAttribute;

+import org.eclipse.emf.ecore.EObject;

+import org.eclipse.emf.edit.provider.INotifyChangedListener;

+import org.eclipse.sensinact.studio.model.manager.modelupdater.ModelEditor;

+import org.eclipse.sensinact.studio.model.manager.modelupdater.ModelUpdater;

+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.resource.Device;

+import org.eclipse.sensinact.studio.resource.Gateway;

+import org.eclipse.sensinact.studio.resource.Service;

+

+/**

+ * @author Etienne Gandrille

+ * @contributor Christophe Munilla

+ */

+public class DeviceUpdateManager implements INotifyChangedListener {

+

+	private static DeviceUpdateManager INSTANCE = null;

+	private static final Logger logger = Logger.getLogger(DeviceUpdateManager.class);

+

+	private final Set<DeviceLocationListener> locationListeners = new HashSet<DeviceLocationListener>();

+	private final Set<DeviceIconListener> iconListeners = new HashSet<DeviceIconListener>();

+	private final Set<DeviceSelectionListener> selectionListeners = new HashSet<DeviceSelectionListener>();

+

+	public synchronized static DeviceUpdateManager getInstance() {

+		if (INSTANCE == null)

+			INSTANCE = new DeviceUpdateManager();

+		return INSTANCE;

+	}

+	

+	DeviceUpdateManager() {

+		ModelEditor.getInstance().addNotifyChangedListener(this);

+	}

+

+	@Override

+	public void notifyChanged(Notification arg0) {		

+		if(arg0.getEventType() == Notification.SET && arg0.getFeature() instanceof EAttribute) {

+			if("location".equals(((EAttribute)arg0.getFeature()).getName())) {

+				try {

+					DeviceDescriptor descriptor = new DeviceDescriptor(((Gateway)((EObject)

+						arg0.getNotifier()).eContainer()).getName(), ((Device)arg0.getNotifier()

+								).getName());

+					

+					descriptor.setIcon(((Device)arg0.getNotifier()).getIcon());

+					descriptor.setLocation((String) arg0.getNewValue());

+					

+					GPScoordinates gps = new GPScoordinates((String) arg0.getNewValue());

+

+					for (DeviceLocationListener listener : locationListeners) {

+						listener.deviceLocationUpdated(gps,descriptor);

+					}

+				} catch (GPSparsingException e) {				

+					logger.error(e.getMessage(),e); 

+				}

+			}

+			if("icon".equals(((EAttribute)arg0.getFeature()).getName())) {

+				DeviceDescriptor descriptor = new DeviceDescriptor(((Gateway)((EObject)

+					arg0.getNotifier()).eContainer()).getName(), ((Device)arg0.getNotifier()

+							).getName());

+				

+				descriptor.setLocation(((Device)arg0.getNotifier()).getLocation());

+				descriptor.setIcon((String) arg0.getNewValue());

+				

+				for (DeviceIconListener listener : iconListeners) {

+					listener.deviceIconUpdated(descriptor);

+				}

+			}

+		} else if(arg0.getEventType() == Notification.REMOVE 

+				&& arg0.getNotifier() instanceof Gateway

+				&& arg0.getOldValue() instanceof Device){			

+			

+			DeviceDescriptor descriptor = new DeviceDescriptor(((Gateway)

+				arg0.getNotifier()).getName(), ((Device)arg0.getOldValue()

+						).getName());

+			

+			for (DeviceLocationListener listener : locationListeners) {

+				listener.deviceRemoved(descriptor);

+			}

+		} else if(arg0.getEventType() == Notification.ADD) {

+		

+			if(arg0.getNotifier() instanceof Gateway && arg0.getNewValue() instanceof Device){			

+			

+				DeviceDescriptor descriptor = new DeviceDescriptor(((Gateway)

+					arg0.getNotifier()).getName(), ((Device)arg0.getNewValue()

+							).getName());	

+				

+				String location = ((Device)arg0.getNewValue()).getLocation();

+				String icon = ((Device)arg0.getNewValue()).getIcon();

+				

+				descriptor.setIcon(icon);

+				descriptor.setLocation(location);

+				

+				if(location != null && !"null".equals(location)) {			

+					GPScoordinates gps = null;

+					try {

+						gps = new GPScoordinates(((Device)arg0.getNewValue()).getLocation());

+					} catch (GPSparsingException e) {				

+						e.printStackTrace();

+					}

+					for (DeviceLocationListener listener : locationListeners) {

+						listener.deviceLocationUpdated(gps, descriptor);;

+					}

+				}

+				if(icon != null && !"null".equals(icon)) {

+					for (DeviceIconListener listener : iconListeners) {

+						listener.deviceIconUpdated(descriptor);

+					}

+				}

+				try {

+					ModelUpdater.getInstance().updateServices(((Gateway)

+						arg0.getNotifier()).getName(), ((Device)arg0.getNewValue()

+								).getName());

+				} catch (IOException e) {

+					e.printStackTrace();

+				}

+			}

+			else if(arg0.getNotifier() instanceof Device && arg0.getNewValue() instanceof Service){			

+				try {

+					ModelUpdater.getInstance().updateResources(((Gateway)((Device)(arg0.getNotifier())).eContainer()).getName(), 

+						((Device)arg0.getNotifier()).getName(), ((Service)arg0.getNewValue()

+								).getName());

+				} catch (IOException e) {

+					e.printStackTrace();

+				}

+			}

+		}

+	}

+	

+	/**

+	 * 

+	 * @param deviceDescriptor

+	 * @param newCoordinates

+	 * @return true if success, false if update location failed. It happens when the location is not updatable. 

+	 */

+	public boolean updateLocationInServer(DeviceDescriptor deviceDescriptor, GPScoordinates newCoordinates) {

+		if (needUpdate(deviceDescriptor, newCoordinates)) {

+			if (ModelUpdater.getInstance().updateLocationOnServer(deviceDescriptor, newCoordinates)) {

+				return true;

+			} else {

+				return false;

+			}

+		} else {

+			return false;

+		}

+	}

+	

+	public void updateDeviceSelection(GPScoordinates coordinates) {		

+		for (DeviceSelectionListener listener : selectionListeners) {

+				listener.deviceSelected(coordinates);

+		}

+	}

+	

+	private boolean needUpdate(DeviceDescriptor deviceDescriptor, GPScoordinates newCoordinates) {

+		GPScoordinates oldCoordinates = ModelEditor.getInstance().getLocation(deviceDescriptor);		

+		return (! newCoordinates.equals(oldCoordinates));

+	}

+

+	public void removeDeviceIconistener(DeviceIconListener listener) {

+		iconListeners.remove(listener);

+	}

+

+	public void addDeviceIconListener(DeviceIconListener listener) {

+		iconListeners.add(listener);

+	}

+

+	

+	public void removeDeviceLocationListener(DeviceLocationListener listener) {

+		locationListeners.remove(listener);

+	}

+

+	public void addDeviceLocationListener(DeviceLocationListener listener) {

+		locationListeners.add(listener);

+	}

+

+	public void removeDeviceSelectionListener(DeviceSelectionListener listener) {

+		selectionListeners.remove(listener);

+	}

+

+	public void addDeviceSelectionListener(DeviceSelectionListener listener) {

+		selectionListeners.add(listener);

+	}

+

+	public void deleteDeviceInStudio(DeviceDescriptor deviceDescriptor) {

+		if(deviceDescriptor == null)

+			return;

+		logger.debug("Device location removed for " + deviceDescriptor + ". Notification fired (" + locationListeners.size() + " listeners");

+		for (DeviceLocationListener listener : locationListeners) {

+			listener.deviceRemoved(deviceDescriptor);

+		}

+	}

+	

+	public void deleteGatewayInStudio(String gatewayName) {

+		// for iterating safely over the keyset while deleting elements in the map

+		List<String> list  = ModelEditor.getInstance().getDevicesId(gatewayName);

+		list.stream().forEach(d -> deleteDeviceInStudio(ModelEditor.getInstance().getDeviceDescriptor(gatewayName, d)));

+	}

+	

+	public GPScoordinates getKnownLocation(DeviceDescriptor deviceDescriptor) {

+		DeviceDescriptor desc =  ModelEditor.getInstance().getDeviceDescriptor(deviceDescriptor.getGateway(),deviceDescriptor.getDevice());

+		if(desc == null )

+			return null;

+		String location = desc.getLocation();

+		if(location == null)

+			return null;

+		String[] coordinates = location.split(":");

+		if(coordinates.length != 2)

+			return null;

+		try {

+			return new GPScoordinates(Double.parseDouble(coordinates[0]),Double.parseDouble(coordinates[1]));

+		} catch(Exception e) {

+			e.printStackTrace();

+		}

+		return null;

+	}

+}

diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/DeviceAppearing.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/DeviceAppearing.java
new file mode 100644
index 0000000..be1469a
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/DeviceAppearing.java
@@ -0,0 +1,59 @@
+/**
+ * 
+ */
+package org.eclipse.sensinact.studio.model.manager.modelupdater;
+
+import org.eclipse.sensinact.studio.http.messages.snamessage.ObjectNameTypeValue;
+import org.eclipse.sensinact.studio.model.resource.utils.DeviceDescriptor;
+
+/**
+ *
+ */
+public class DeviceAppearing extends ModelUpdate<DeviceDescriptor> {
+
+	/**
+	 * @param object
+	 */
+	public DeviceAppearing(DeviceDescriptor object) {
+		super(object);
+	}
+
+	@Override
+	public boolean addNext(ModelUpdate<?> next){
+		if(super.addNext(next)){
+			if(next instanceof ResourceAppearing
+				&& "location".equals(((ResourceAppearing)next).object.getResource()) 
+				&& "admin".equals(((ResourceAppearing)next).object.getService())){	
+					ObjectNameTypeValue ontv = ((ResourceAppearing)next).object.getInitial();
+					if(ontv!=null)
+						super.object.setLocation(ontv.getValueAsString());
+				}
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	protected void doApply(){
+		ModelUpdater.executeInThread( () -> {
+			ModelEditor.getInstance().addDeviceIfNotExist(
+			super.object.getGateway(),
+			super.object.getDevice(),
+			super.object.getIcon(),
+			super.object.getLocation());
+		});
+	}
+	
+	@Override
+	public boolean complete(){		
+		return doComplete();
+	}
+	
+	@Override
+	protected boolean doComplete() {
+		return super.object.getGateway()!=null 
+		   && super.object.getDevice()!=null 
+		   && super.object.getLocation()!=null 
+		   && super.existsGateway(super.object.getGateway());
+	}
+}
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/DeviceDisappearing.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/DeviceDisappearing.java
new file mode 100644
index 0000000..ddbcb36
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/DeviceDisappearing.java
@@ -0,0 +1,31 @@
+package org.eclipse.sensinact.studio.model.manager.modelupdater;
+
+
+import org.eclipse.sensinact.studio.model.resource.utils.DeviceDescriptor;
+
+public class DeviceDisappearing extends ModelUpdate<DeviceDescriptor> {
+
+	/**
+	 * @param object
+	 */
+	public DeviceDisappearing(DeviceDescriptor object) {
+		super(object);
+	}
+
+	@Override
+	protected void doApply(){		
+		ModelUpdater.executeInThread( () -> {
+			ModelEditor.getInstance().removeDevice(
+				super.object.getGateway(),
+				super.object.getDevice());
+			}
+		);
+	}
+
+	@Override
+	protected boolean doComplete() {
+		return super.object.getGateway()!=null &&
+			   super.object.getDevice()!=null;
+	}
+
+}
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelEditor.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelEditor.java
index 8d6e840..3ec6e5d 100644
--- a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelEditor.java
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelEditor.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019 CEA.
+ * 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
@@ -11,18 +11,34 @@
 package org.eclipse.sensinact.studio.model.manager.modelupdater;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
-import java.util.function.Supplier;
 
+import org.apache.log4j.Logger;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.util.BasicEList;
 import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.common.util.WrappedException;
 import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EContentAdapter;
+import org.eclipse.emf.edit.provider.INotifyChangedListener;
 import org.eclipse.emf.transaction.RecordingCommand;
 import org.eclipse.emf.transaction.RunnableWithResult;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
 import org.eclipse.sensinact.studio.http.messages.snamessage.MsgSensinact;
 import org.eclipse.sensinact.studio.http.messages.snamessage.describeresource.MsgDescribeRessource;
+import org.eclipse.sensinact.studio.http.messages.snamessage.describeresource.ObjectAccessMethods;
+import org.eclipse.sensinact.studio.http.messages.snamessage.describeresource.ObjectParameter;
 import org.eclipse.sensinact.studio.http.services.client.GatewayHttpClient;
-import org.eclipse.sensinact.studio.model.manager.listener.devicelocation.DeviceLocationManager;
+import org.eclipse.sensinact.studio.http.services.client.connectionmanager.ConnectionListener;
+import org.eclipse.sensinact.studio.http.services.client.connectionmanager.NotifDispatcher;
 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;
@@ -31,21 +47,55 @@
 import org.eclipse.sensinact.studio.preferences.GatewayHttpConfig;
 import org.eclipse.sensinact.studio.resource.AccessMethod;
 import org.eclipse.sensinact.studio.resource.AccessMethodType;
+import org.eclipse.sensinact.studio.resource.Device;
+import org.eclipse.sensinact.studio.resource.Gateway;
+import org.eclipse.sensinact.studio.resource.Parameter;
+import org.eclipse.sensinact.studio.resource.Resource;
+import org.eclipse.sensinact.studio.resource.ResourceFactory;
+import org.eclipse.sensinact.studio.resource.ResourcePackage;
+import org.eclipse.sensinact.studio.resource.Service;
 import org.eclipse.sensinact.studio.resource.Studio;
 
 /**
  * @author Nicolas Hili, Etienne Gandrille
+ * @contributor Christophe Munilla
  */
-public class ModelEditor extends ModelEditorHelpers implements ConfigurationListerner {
+public class ModelEditor implements ConfigurationListerner, ConnectionListener {
 
 	/* ===================== */
 	/* Model data structures */
 	/* ===================== */
 
+	private static org.eclipse.emf.ecore.resource.Resource resource;
+
+	private final static String EDITING_DOMAIN_ID = "org.eclipse.sensinact.studio.model.resource.editingDomain";
+
+	private static TransactionalEditingDomain editingDomain;
+
+	private static final Logger logger = Logger.getLogger(ModelEditor.class);
+
 	private static ModelEditor INSTANCE = null;
 
+	private List<INotifyChangedListener> listeners;
+	
 	private ModelEditor() {
+		NotifDispatcher.getInstance().subscribe(this);
 		ConfigurationManager.addListener(this);
+		
+		this.listeners = new ArrayList<INotifyChangedListener>();		
+		getEditingDomain().getResourceSet().eAdapters().add(new EContentAdapter() {
+			@Override
+			public void notifyChanged(Notification notification) {
+				synchronized(listeners){
+					Iterator<INotifyChangedListener> it= ModelEditor.this.listeners.iterator();
+					while(it.hasNext()){
+						it.next().notifyChanged(notification);
+					}
+				}
+				super.notifyChanged(notification);
+			}
+		});
+		
 	}
 
 	public synchronized static ModelEditor getInstance() {
@@ -53,10 +103,28 @@
 			INSTANCE = new ModelEditor();
 		return INSTANCE;
 	}
+	
+	public void addNotifyChangedListener(INotifyChangedListener listener){
+		if(listener==null){
+			return;
+		}
+		synchronized(listeners){
+			this.listeners.add(listener);
+		}
+	}
 
-	/* ====================== */
-	/* ConfigurationListerner */
-	/* ====================== */
+	public void deleteNotifyChangedListener(INotifyChangedListener listener){
+		if(listener==null){
+			return;
+		}
+		synchronized(listeners){
+			int index =listeners.indexOf(listener);
+			if(index < 0){
+				return;
+			}
+			this.listeners.remove(index);
+		}
+	}
 	
 	@Override
 	public void gatewayAddedOrUpdatedNotif(GatewayHttpConfig gateway) {
@@ -72,39 +140,23 @@
 	public void studioPortUpdatedNotif(int port) {
 		// do nothing
 	}
-	
-	/* ============= */
-	/* Run exclusive */
-	/* ============= */
-		
-	private void runExclusive(Runnable runnable) {
-		RecordingCommand command = new RecordingCommand(getEditingDomain()) {
-			@Override
-			protected void doExecute() {
-				USE_IN_RUNEXLUSIVE_setupStudio();
-				runnable.run();
-			}
-		};
-		getEditingDomain().getCommandStack().execute(command);
-	}
-	
-	@SuppressWarnings("unchecked")
-	private <T> T runExclusive(Supplier<T> supplier) throws InterruptedException {
-		return (T) getEditingDomain().runExclusive(new RunnableWithResult.Impl<T>() {
-			@Override
-			public void run() {
-				USE_IN_RUNEXLUSIVE_setupStudio();
-				T value = supplier.get();
-				setResult(value);
-				return;
-			}
-		});
+
+	private synchronized static TransactionalEditingDomain getEditingDomain() {
+		if (editingDomain == null) {
+			editingDomain = TransactionalEditingDomain.Registry.INSTANCE.getEditingDomain(EDITING_DOMAIN_ID);
+		}
+		return editingDomain;
 	}
 
-	/* ========== */
-	/* Root level */
-	/* ========== */
-	
+	private static org.eclipse.emf.ecore.resource.Resource getResource() {
+		if (resource == null) {
+			String path = "/org.eclipse.sensinact.studio.model.resource/cache/resource.cache";
+			URI uri = URI.createPlatformPluginURI(path, true);
+			resource = getEditingDomain().getResourceSet().createResource(uri);
+		}
+		return resource;
+	}
+
 	/**
 	 * IMPORTANT. This method MUST NOT BE USED TO UPDATE THE MODEL !!!!
 	 * 
@@ -113,69 +165,390 @@
 	 */
 	public Studio getViewerInput() throws InterruptedException {
 
-		runExclusive(() -> USE_IN_RUNEXLUSIVE_setupStudio());
+		setupStudio();
 
 		// Init available gateways names
 		for (GatewayHttpConfig gateway : ConfigurationManager.getGateways()) {
 			addGatewayIfNotExist_UNSAFE(gateway.getName());
 		}
 
-		return runExclusive(() -> USE_IN_RUNEXLUSIVE_getStudio());
+		return (Studio) getEditingDomain().runExclusive(new RunnableWithResult.Impl<Studio>() {
+			@Override
+			public void run() {
+				setResult(USE_IN_RUNEXLUSIVE_getStudio());
+				return;
+			}
+		});
+	}
+
+	private void setupStudio() {
+		
+		final String label=getResource() instanceof Resource?((Resource)getResource()).getName():"Unknown resource";
+		
+		RecordingCommand command = new RecordingCommand(getEditingDomain(),label) {
+			@Override
+			protected void doExecute() {
+				EList<EObject> contents = getResource().getContents();
+				if (contents.size() == 0)
+					getResource().getContents().add(ResourceFactory.eINSTANCE.createStudio());
+			}
+		};
+		getEditingDomain().getCommandStack().execute(command);
+	}
+
+	/* ====================== */
+	/* Internal NON EXCLUSIVE */
+	/* ====================== */
+
+	private static Studio USE_IN_RUNEXLUSIVE_getStudio() {
+		EList<EObject> contents = getResource().getContents();
+		return (Studio) contents.get(0);
+	}
+
+	private static Gateway USE_IN_RUNEXLUSIVE_getGateway(String gatewayName) {
+		EList<Gateway> gateways = USE_IN_RUNEXLUSIVE_getStudio().getGateways();
+		for (Gateway gateway : gateways) {
+			if (gateway.getName().equals(gatewayName)) {
+				return gateway;
+			}
+		}
+		return null;
+	}
+
+	private static Device USE_IN_RUNEXLUSIVE_getDevice(String gatewayName, String devicename) {
+
+		Gateway gateway = USE_IN_RUNEXLUSIVE_getGateway(gatewayName);
+		if (gateway == null)
+			return null;
+		EList<Device> devices = gateway.getDevice();
+		for (Device device : devices) {
+			if (device.getName().equals(devicename)) {
+				return device;
+			}
+		}
+		return null;
+	}
+
+	private static Service USE_IN_RUNEXLUSIVE_getService(String gatewayName, String devicename, String servicename) {
+		Device device = USE_IN_RUNEXLUSIVE_getDevice(gatewayName, devicename);
+		if (device == null)
+			return null;
+
+		for (Service service : device.getService()) {
+			if (service.getName().equals(servicename)) {
+				return service;
+			}
+		}
+
+		return null;
+	}
+
+	private static Resource USE_IN_RUNEXLUSIVE_getResource(ResourceDescriptor descriptor) {
+		Service service = USE_IN_RUNEXLUSIVE_getService(descriptor.getGateway(), descriptor.getDevice(), descriptor.getService());
+		if (service == null)
+			return null;
+
+		for (Resource resource : service.getResource()) {
+			if (resource.getName().equals(descriptor.getResource())) {
+				return resource;
+			}
+		}
+
+		return null;
+	}
+
+	private void USE_IN_RUNEXLUSIVE_addDeviceIfNotExist(final String gatewayName, final String deviceId,
+			String icon, String location)
+	{
+		Device addedDevice;
+		if ((addedDevice = USE_IN_RUNEXLUSIVE_getDevice(gatewayName, deviceId)) != null)
+		{
+			addedDevice.setLocation(location);
+			return;
+		}
+		addedDevice = ResourceFactory.eINSTANCE.createDevice();
+		addedDevice.setName(deviceId);
+		addedDevice.setIcon(icon);
+		addedDevice.setLocation(location);
+		USE_IN_RUNEXLUSIVE_getGateway(gatewayName).getDevice().add(addedDevice);
+	}
+
+	private void USE_IN_RUNEXLUSIVE_addServiceIfNotExist(final String gatewayName, final String deviceId, final String serviceId) {
+		if (USE_IN_RUNEXLUSIVE_getService(gatewayName, deviceId, serviceId) != null)
+			return;
+
+		final Service addedService = ResourceFactory.eINSTANCE.createService();
+		addedService.setName(serviceId);
+		try {
+			USE_IN_RUNEXLUSIVE_getDevice(gatewayName, deviceId).getService().add(addedService);
+		} catch (NullPointerException e) {
+			e.printStackTrace();
+		}
+	}
+
+	public List<ServiceDescriptor> findApplications() throws InterruptedException {
+		return USE_IN_RUNEXCLUSIVE_findApplications();
+	}
+	
+	protected List<ServiceDescriptor> USE_IN_RUNEXCLUSIVE_findApplications() {
+		List<ServiceDescriptor> retval = new ArrayList<>();
+		EList<Gateway> gateways = USE_IN_RUNEXLUSIVE_getStudio().getGateways();
+		for (Gateway gateway : gateways) {
+			Device appManager = findAppManager(gateway.getDevice());
+			if (appManager != null) {
+				retval.addAll(findApplications(appManager));
+			}
+		}
+		return retval;
+	}
+	
+
+	protected Device findAppManager(EList<Device> devices) {
+		for (Device device : devices) {
+			if (device.getName().equals("AppManager"))
+				return device;
+		}
+		return null;
+	}
+
+	protected List<ServiceDescriptor> findApplications(Device appManager) {
+		List<ServiceDescriptor> retval = new ArrayList<>();
+
+		String gateway = ((Gateway) appManager.eContainer()).getName();
+		String device = appManager.getName();
+
+		for (Service service : appManager.getService()) {
+			String srvName = service.getName();
+			if (srvName != null && (!srvName.equalsIgnoreCase("admin"))) {
+				retval.add(new ServiceDescriptor(gateway, device, srvName));
+			}
+		}
+		return retval;
+	}
+	
+	protected List<String> USE_IN_RUNEXCLUSIVE_getConnectedGatewaysId() {
+		List<String> retval = new ArrayList<String>();
+		EList<Gateway> gateways = USE_IN_RUNEXLUSIVE_getStudio().getGateways();
+		for (Gateway gateway : gateways) {
+			if (gateway.getDevice().size() != 0)
+				retval.add(gateway.getName());
+		}
+		return retval;
+	}
+	
+	public List<String> getConnectedGatewaysId() throws InterruptedException {
+		return USE_IN_RUNEXCLUSIVE_getConnectedGatewaysId();
+	}
+	
+	/* ======= */
+	/* Get/Set Location */
+	/* ======= */
+
+	public GPScoordinates getLocation(final DeviceDescriptor descriptor) {
+
+		GPScoordinates coordinates = null;
+		try {
+			coordinates = (GPScoordinates) getEditingDomain().runExclusive(new RunnableWithResult.Impl<GPScoordinates>() {
+				@Override
+				public void run() {
+					Device device = USE_IN_RUNEXLUSIVE_getDevice(descriptor.getGateway(),descriptor.getDevice());
+					GPScoordinates coordinates=null;
+					try {
+						coordinates = new GPScoordinates(device.getLocation());				
+					} catch (NullPointerException | GPSparsingException e) {
+						logger.error(e.getMessage(),e);
+					}
+					setResult(coordinates);
+					return;
+				}
+			});
+		} catch (InterruptedException e) {
+			Thread.interrupted();
+			e.printStackTrace();
+		}
+		return coordinates;
+	}
+
+	public String getIcon(final DeviceDescriptor descriptor) {
+
+		String icon = null;
+		try {
+			icon = (String) getEditingDomain().runExclusive(
+				new RunnableWithResult.Impl<String>() {
+				@Override
+				public void run() {
+					Device device = USE_IN_RUNEXLUSIVE_getDevice(descriptor.getGateway(),descriptor.getDevice());
+					String icon=null;
+					try {
+						icon =  device.getIcon();				
+					} catch (NullPointerException e) {
+						logger.error(e.getMessage(),e);
+					}
+					setResult(icon);
+					return;
+				}
+			});
+		} catch (InterruptedException e) {
+			Thread.interrupted();
+		}
+		return icon;
+	}
+
+	public void setLocation(final DeviceDescriptor descriptor, final GPScoordinates coordinates) {
+		RecordingCommand command = new RecordingCommand(getEditingDomain()) {
+			@Override
+			protected void doExecute() {
+				if(coordinates == null){
+					return;
+				}
+				Device device = ModelEditor.USE_IN_RUNEXLUSIVE_getDevice(descriptor.getGateway(),descriptor.getDevice());
+				if(device == null){
+					return;
+				}
+				device.setLocation(new StringBuilder().append(coordinates.getLat()
+					).append(":").append(coordinates.getLng()).toString());
+			}
+		};
+		getEditingDomain().getCommandStack().execute(command);
+	}
+
+	public void setIcon(final DeviceDescriptor descriptor, final String icon) {
+		RecordingCommand command = new RecordingCommand(getEditingDomain()) {
+			@Override
+			protected void doExecute() {
+				if(icon == null){
+					return;
+				}
+				Device device = ModelEditor.USE_IN_RUNEXLUSIVE_getDevice(descriptor.getGateway(),descriptor.getDevice());
+				if(device == null){
+					return;
+				}
+				device.setIcon(icon);
+			}
+		};
+		getEditingDomain().getCommandStack().execute(command);
 	}
 	
 	/* ======= */
 	/* Get IDs */
 	/* ======= */
 
-	public List<String> getGatewaysId() throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXCLUSIVE_getGatewaysId());
-	}
-	
-	public List<String> getConnectedGatewaysId() throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXCLUSIVE_getConnectedGatewaysId());
-	}
-	
-	public List<String> getDevicesId(String gatewayName) throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXCLUSIVE_getDevicesId(gatewayName));
+	@SuppressWarnings("unchecked")
+	public List<String> getGatewaysId() {
+
+		setupStudio();
+		try {
+			return (List<String>) getEditingDomain().runExclusive(new RunnableWithResult.Impl<List<String>>() {
+				@Override
+				public void run() {
+					List<String> retval = new ArrayList<String>();
+					EList<Gateway> gateways = USE_IN_RUNEXLUSIVE_getStudio().getGateways();
+					for (Gateway gateway : gateways) {
+						retval.add(gateway.getName());
+					}
+					setResult(retval);
+					return;
+				}
+			});
+		} catch (InterruptedException e) {
+			Thread.interrupted();
+		}
+		return Collections.emptyList();
 	}
 
-	public List<String> getServicesId(String gatewayName, String devicename) throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXCLUSIVE_getServicesId(gatewayName, devicename));
+	@SuppressWarnings("unchecked")
+	public List<String> getDevicesId(final String gatewayName) {
+		try {
+			return (List<String>) getEditingDomain().runExclusive(new RunnableWithResult.Impl<List<String>>() {
+				@Override
+				public void run() {
+					List<String> retval = new ArrayList<String>();
+					EList<Device> devices = USE_IN_RUNEXLUSIVE_getGateway(gatewayName).getDevice();
+					for (Device device : devices) {
+						retval.add(device.getName());
+					}
+					setResult(retval);
+					return;
+				}
+			});
+		} catch(InterruptedException e) {
+			Thread.interrupted();
+		} catch(Exception e) {
+			e.printStackTrace();
+		}
+		return Collections.<String>emptyList();
 	}
 
-	public List<String> getResourcesId(String gatewayName, String devicename, String servicename) throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXCLUSIVE_getResourcesId(gatewayName, devicename, servicename));
+	@SuppressWarnings("unchecked")
+	public List<String> getServicesId(final String gatewayName, final String devicename)  {
+		try {
+			return (List<String>) getEditingDomain().runExclusive(new RunnableWithResult.Impl<List<String>>() {
+				@Override
+				public void run() {
+					List<String> retval = new ArrayList<String>();
+					Device device = USE_IN_RUNEXLUSIVE_getDevice(gatewayName, devicename);
+					if (device != null) {
+						for (Service service : device.getService()) {
+							retval.add(service.getName());
+						}
+					}
+					setResult(retval);
+					return;
+				}
+			});
+		} catch (InterruptedException e) {
+			Thread.interrupted();
+		} catch(Exception e) {
+			e.printStackTrace();
+		}
+		return Collections.<String>emptyList();
 	}
 
-	public EClass getResourceClass(final ResourceDescriptor descriptor) throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXLUSIVE_getResource(descriptor).eClass());
-	}
+	@SuppressWarnings("unchecked")
+	public List<String> getResourcesId(final String gatewayName, final String devicename, final String servicename) {
+		try {
+			return (List<String>) getEditingDomain().runExclusive(new RunnableWithResult.Impl<List<String>>() {
+				@Override
+				public void run() {
+					List<String> retval = new ArrayList<String>();
 	
-	/* ================= */
-	/* Find Applications */
-	/* ================= */
+					Service service = USE_IN_RUNEXLUSIVE_getService(gatewayName, devicename, servicename);
 	
-	public List<ServiceDescriptor> findApplications() throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXCLUSIVE_findApplications());
+					if (service != null) {
+						for (Resource resource : service.getResource()) {
+							retval.add(resource.getName());
+						}
+					}
+	
+					setResult(retval);
+					return;
+				}
+			});
+		} catch (InterruptedException e) {
+			Thread.interrupted();
+		} catch(Exception e) {
+			e.printStackTrace();
+		}
+		return Collections.<String>emptyList();
 	}
-		
+
 	/* ============= */
 	/* Checks exists */
 	/* ============= */
 
-	public boolean existsGateway(String gatewayId) throws InterruptedException {
+	public boolean existsGateway(final String gatewayId) throws InterruptedException {
 		return getGatewaysId().contains(gatewayId);
 	}
 
-	public boolean existsDevice(String gatewayId, String deviceId) throws InterruptedException {
+	public boolean existsDevice(final String gatewayId, String deviceId) throws InterruptedException {
 		return getDevicesId(gatewayId).contains(deviceId);
 	}
 
-	public boolean existsService(String gatewayId, String deviceId, String serviceId) throws InterruptedException {
+	public boolean existsService(final String gatewayId, String deviceId, String serviceId) throws InterruptedException {
 		return getServicesId(gatewayId, deviceId).contains(serviceId);
 	}
 
-	public boolean existsResource(String gatewayId, String deviceId, String serviceId, String resourceId) throws InterruptedException {
+	public boolean existsResource(final String gatewayId, String deviceId, String serviceId, String resourceId) throws InterruptedException {
 		return existsResource(new ResourceDescriptor(gatewayId, deviceId, serviceId, resourceId));
 	}
 
@@ -186,21 +559,63 @@
 	/* ============== */
 	/* Access Methods */
 	/* ============== */
-	
-	public EList<AccessMethod> getAccessMethods(ResourceDescriptor descriptor) throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXCLUSIVE_getAccessMethods(descriptor));
+
+	@SuppressWarnings("unchecked")
+	public EList<AccessMethod> getAccessMethods(final ResourceDescriptor descriptor) throws InterruptedException {
+		EList<AccessMethod> accessMethods = null;
+		accessMethods = (EList<AccessMethod>) getEditingDomain().runExclusive(new RunnableWithResult.Impl<EList<AccessMethod>>() {
+			@Override
+			public void run() {
+				EList<AccessMethod> accessMethods = new BasicEList<AccessMethod>();
+				Resource resource = USE_IN_RUNEXLUSIVE_getResource(descriptor);
+				for (AccessMethod accessMethod : resource.getAccessMethod()) {
+					accessMethods.add(accessMethod);
+				}
+				setResult(accessMethods);
+				return;
+			}
+		});
+		return accessMethods;
 	}
 
-	public int getAccessMethodNb(final ResourceDescriptor descriptor) throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXCLUSIVE_getAccessMethods(descriptor).size());
-	}
-	
-	public EList<AccessMethod> getAccessMethodsWithType(ResourceDescriptor descriptor, AccessMethodType type) throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXCLUSIVE_getAccessMethodsWithType(descriptor, type));
+	@SuppressWarnings("unchecked")
+	public EList<AccessMethod> getAccessMethodsWithType(final ResourceDescriptor descriptor, final AccessMethodType type) throws InterruptedException {
+		EList<AccessMethod> accessMethods = null;
+		accessMethods = (EList<AccessMethod>) getEditingDomain().runExclusive(new RunnableWithResult.Impl<EList<AccessMethod>>() {
+			@Override
+			public void run() {
+				EList<AccessMethod> accessMethods = new BasicEList<AccessMethod>();
+				Resource resource = USE_IN_RUNEXLUSIVE_getResource(descriptor);
+				for (AccessMethod accessMethod : resource.getAccessMethod()) {
+					if (accessMethod.getType().equals(type)) {
+						accessMethods.add(accessMethod);
+					}
+				}
+				setResult(accessMethods);
+				return;
+			}
+		});
+		return accessMethods;
 	}
 
-	public AccessMethod getAccessMethodWithTypeNbParams(ResourceDescriptor descriptor, AccessMethodType type, int nbOfParameters) throws InterruptedException {
-		return runExclusive(() -> USE_IN_RUNEXCLUSIVE_getAccessMethodWithTypeNbParams(descriptor, type, nbOfParameters));
+	public AccessMethod getAccessMethodWithTypeNbParams(final ResourceDescriptor descriptor, final AccessMethodType type, final int nbOfParameters)
+			throws InterruptedException {
+		return (AccessMethod) getEditingDomain().runExclusive(new RunnableWithResult.Impl<AccessMethod>() {
+			@Override
+			public void run() {
+				Resource resource = USE_IN_RUNEXLUSIVE_getResource(descriptor);
+				for (AccessMethod accessMethod : resource.getAccessMethod()) {
+					if (accessMethod.getType().equals(type)) {
+						if (accessMethod.getParameter().size() == nbOfParameters) {
+							setResult(accessMethod);
+							return;
+						}
+					}
+				}
+				setResult(null);
+				return;
+			}
+		});
 	}
 
 	/* ================= */
@@ -211,25 +626,96 @@
 	// usually, if you want to add a gateway, use
 	// ConfigurationManager.addGateway
 	private void addGatewayIfNotExist_UNSAFE(final String gatewayName) {
-		runExclusive(() -> USE_IN_RUNEXLUSIVE_addGatewayIfNotExist(gatewayName));
+
+		//setupStudio();
+
+		RecordingCommand command = new RecordingCommand(getEditingDomain()) {
+
+			@Override
+			protected void doExecute() {
+				if (USE_IN_RUNEXLUSIVE_getGateway(gatewayName) != null)
+					return;
+
+				final Gateway addedGateway = ResourceFactory.eINSTANCE.createGateway();
+				addedGateway.setName(gatewayName);
+//				System.err.println("####################################");
+//
+//				ResourceEditPlugin.ADAPTER_FACTORY.adaptAllNew(addedGateway);
+//
+//				ResourceEditPlugin.ADAPTER_FACTORY.adapt(addedGateway, Gateway.class);
+//				Adapter a = ResourceEditPlugin.ADAPTER_FACTORY.adaptNew(addedGateway, Device.class);
+//
+//				System.err.println("#################################### \t"+a);
+				USE_IN_RUNEXLUSIVE_getStudio().getGateways().add(addedGateway);
+				
+				return;
+			}
+		};
+		getEditingDomain().getCommandStack().execute(command);
 	}
 
-	public void addDeviceIfNotExist(final String gatewayName, final String deviceId) {
-		runExclusive(() -> USE_IN_RUNEXLUSIVE_addDeviceIfNotExist(gatewayName, deviceId));
+	public void addDeviceIfNotExist(final String gatewayName, final String deviceId,
+			final String icon, final String location) 
+	{
+		//setupStudio();
+
+		RecordingCommand command = new RecordingCommand(getEditingDomain()) {
+			@Override
+			protected void doExecute() {
+				USE_IN_RUNEXLUSIVE_addDeviceIfNotExist(gatewayName, deviceId, icon, location);
+			}
+		};
+		getEditingDomain().getCommandStack().execute(command);
 	}
 
+
+	public DeviceDescriptor getDeviceDescriptor(String gatewayId, String deviceId) {EList<AccessMethod> accessMethods = null;
+		DeviceDescriptor deviceDescriptor = null;
+		try {
+			deviceDescriptor = (DeviceDescriptor) getEditingDomain().runExclusive(
+				new RunnableWithResult.Impl<DeviceDescriptor>() {
+					@Override
+					public void run() {
+						EList<AccessMethod> accessMethods = new BasicEList<AccessMethod>();
+						Device device = USE_IN_RUNEXLUSIVE_getDevice(gatewayId,deviceId);
+						DeviceDescriptor descriptor = new DeviceDescriptor(gatewayId,deviceId);
+						descriptor.setIcon(device.getIcon());
+						descriptor.setLocation(device.getLocation());
+						setResult(descriptor);
+						return;
+					}
+				});
+		} catch (InterruptedException e) {
+			Thread.interrupted();
+			e.printStackTrace();
+		}
+		return deviceDescriptor;
+	}
+	
 	public void addServiceIfNotExist(final String gatewayName, final String deviceId, final String serviceId) {
-		runExclusive(() -> {
-			USE_IN_RUNEXLUSIVE_addDeviceIfNotExist(gatewayName, deviceId);
-			USE_IN_RUNEXLUSIVE_addServiceIfNotExist(gatewayName, deviceId, serviceId);
-		});
+
+		//setupStudio();
+
+		RecordingCommand command = new RecordingCommand(getEditingDomain()) {
+			@Override
+			protected void doExecute() {
+				//USE_IN_RUNEXLUSIVE_addDeviceIfNotExist(gatewayName, deviceId);
+				USE_IN_RUNEXLUSIVE_addServiceIfNotExist(gatewayName, deviceId, serviceId);
+			}
+		};
+		getEditingDomain().getCommandStack().execute(command);
 	}
 
 	public void addResourceIfNotExist(final ResourceDescriptor descriptor) {
+
+		//setupStudio();		
+		//addServiceIfNotExist(descriptor.getGateway(), descriptor.getDevice(), descriptor.getService());
+
 		try {
 			if (!existsResource(descriptor)) {
 				Segments segment = new Segments.Builder().resource(descriptor).build();
 				
+				
 				MsgSensinact response = null;
 				try {
 					response = GatewayHttpClient.sendGetRequest(segment);
@@ -241,8 +727,52 @@
 					throw new RuntimeException("Can't get remote resources info for " + descriptor);
 				
 				final MsgDescribeRessource responseMessage = (MsgDescribeRessource) response;
-				
-				runExclusive(() -> USE_IN_RUNEXLUSIVE_addResourceIfNotExist(descriptor, responseMessage));
+
+				RecordingCommand command = new RecordingCommand(getEditingDomain()) {
+					@Override
+					protected void doExecute() {
+
+						if (USE_IN_RUNEXLUSIVE_getResource(descriptor) != null)
+							return;
+
+						// create resource
+						String resourceType = responseMessage.getResponse().getType();
+						EClass type = literalToType(resourceType);
+						Resource createdResource = (Resource) ResourceFactory.eINSTANCE.create(type);
+						createdResource.setName(descriptor.getResource());
+
+						// create access methods
+						for (ObjectAccessMethods am : responseMessage.getResponse().getAccessMethods()) {
+							if (am != null) { // test to be removed after gateway bug fix 
+								AccessMethod accessMethod = ResourceFactory.eINSTANCE.createAccessMethod();
+								accessMethod.setType(AccessMethodType.get(am.getName()));
+	
+								Parameter[] parameters = new Parameter[am.getParameters().size()];
+								for (int i = 0; i < am.getParameters().size(); i++) {
+									ObjectParameter param = am.getParameters().get(i);
+									Parameter parameter = ResourceFactory.eINSTANCE.createParameter();
+									parameter.setName(param.getName());
+									parameter.setType(param.getType());
+									parameters[i] = parameter;
+								}
+	
+								for (Parameter parameter : parameters) {
+									accessMethod.getParameter().add(parameter);
+								}
+								createdResource.getAccessMethod().add(accessMethod);
+							}
+						}
+						USE_IN_RUNEXLUSIVE_getService(descriptor.getGateway(), descriptor.getDevice(), descriptor.getService()
+								).getResource().add(createdResource);
+						return;
+					}
+				};
+				try {
+					getEditingDomain().getCommandStack().execute(command);
+				}catch (WrappedException we){
+					getEditingDomain().getCommandStack().flush();
+					//Caused by multiple events received.
+				}
 			}
 		} catch (NullPointerException | InterruptedException e) {
 			getEditingDomain().getCommandStack().flush();
@@ -250,6 +780,30 @@
 		}
 	}
 
+	static EClass literalToType(final String type) {
+
+		final EClass resourceType;
+		// Literals
+		EClass stateVariableLiteral = ResourcePackage.Literals.STATE_VARIABLE;
+		EClass actionLiteral = ResourcePackage.Literals.ACTION;
+		EClass propertyLiteral = ResourcePackage.Literals.PROPERTY;
+		EClass sensorDataLiteral = ResourcePackage.Literals.SENSOR_DATA;
+
+		if ("STATE_VARIABLE".equals(type)) {
+			resourceType = stateVariableLiteral;
+		} else if ("ACTION".equals(type)) {
+			resourceType = actionLiteral;
+		} else if ("PROPERTY".equals(type)) {
+			resourceType = propertyLiteral;
+		} else if ("SENSOR".equals(type)) {
+			resourceType = sensorDataLiteral;
+		} else {
+			logger.error(ModelEditor.class.getCanonicalName() + "::updateResource with type=" + type + " - Is it a bug or a feature ?");
+			resourceType = actionLiteral;
+		}
+		return resourceType;
+	}
+
 	/* ==================== */
 	/* REMOVE Objects by ID */
 	/* ==================== */
@@ -257,26 +811,125 @@
 	// USE CAREFULLY
 	// usually, if you want to remove a gateway, use
 	// ConfigurationManager.removeGateway
-	private void removeGateway_UNSAFE(String gatewayName) {
-		runExclusive(() -> USE_IN_RUNEXLUSIVE_removeGateway(gatewayName));
-		DeviceLocationManager.getInstance().deleteGatewayInStudio(gatewayName);
-	}
-		
-	public void clearGatewayContent(String gatewayName) {
-		runExclusive(() -> USE_IN_RUNEXCLUSIVE_removeAllDevices(gatewayName));
-		DeviceLocationManager.getInstance().deleteGatewayInStudio(gatewayName);
+	private void removeGateway_UNSAFE(final String gatewayName) {
+		RecordingCommand command = new RecordingCommand(getEditingDomain()) {
+			@Override
+			protected void doExecute() {
+				EList<Gateway> gateways = USE_IN_RUNEXLUSIVE_getStudio().getGateways();
+
+				for (int i = 0; i < gateways.size(); i++) {
+					Gateway gateway = gateways.get(i);
+					if (gateway.getName().equals(gatewayName)) {
+						gateways.remove(i);
+						return;
+					}
+				}
+			}
+		};
+		getEditingDomain().getCommandStack().execute(command);
+		//DeviceLocationManager.getInstance().deleteGatewayInStudio(gatewayName);
 	}
 
-	public void removeDevice(String gatewayName, String deviceId) {
-		runExclusive(() -> USE_IN_RUNEXCLUSIVE_removeDevice(gatewayName, deviceId));
-		DeviceLocationManager.getInstance().deleteDeviceInStudio(new DeviceDescriptor(gatewayName, deviceId));
+	public void clearGatewayContent(String name) {
+		for (String device : getDevicesId(name)) {
+			removeDevice(name, device);
+		}
 	}
-		
-	public void removeService(String gatewayName, String deviceId, String serviceId) {
-		runExclusive(() -> USE_IN_RUNEXCLUSIVE_removeService(gatewayName, deviceId, serviceId)); 		
+
+	public void removeDevice(final String gatewayName, final String deviceId) {
+		RecordingCommand command = new RecordingCommand(getEditingDomain()) {
+			@Override
+			protected void doExecute() {
+				Gateway gateway = USE_IN_RUNEXLUSIVE_getGateway(gatewayName);
+				if (gateway != null) {
+					EList<Device> devices = gateway.getDevice();
+					for (int i = 0; i < devices.size(); i++) {
+						Device device = devices.get(i);
+						if (deviceId.equals(device.getName())) {
+							devices.remove(i);
+							return;
+						}
+					}
+				}
+			}
+		};
+		getEditingDomain().getCommandStack().execute(command);
+
+//		DeviceLocationObservable.INSTANCE.deleteDeviceInStudio(new DeviceDescriptor(gatewayName, deviceId));
 	}
-	
+
+	public void removeService(final String gatewayName, final String deviceId, final String serviceId) {
+		RecordingCommand command = new RecordingCommand(getEditingDomain()) {
+			@Override
+			protected void doExecute() {
+				Device device = USE_IN_RUNEXLUSIVE_getDevice(gatewayName, deviceId);
+				if (device != null) {
+					EList<Service> services = device.getService();
+					for (int i = 0; i < services.size(); i++) {
+						Service service = services.get(i);
+						if (serviceId.equals(service.getName())) {
+							services.remove(i);
+							return;
+						}
+					}
+				}
+			}
+		};
+		getEditingDomain().getCommandStack().execute(command);
+	}
+
 	public void removeResource(final ResourceDescriptor descriptor) {
-		runExclusive(() -> USE_IN_RUNEXCLUSIVE_removeResource(descriptor));
+		RecordingCommand command = new RecordingCommand(getEditingDomain()) {
+			@Override
+			protected void doExecute() {
+				Service service = USE_IN_RUNEXLUSIVE_getService(descriptor.getGateway(), descriptor.getDevice(), descriptor.getService());
+				if (service != null) {
+					EList<Resource> resources = service.getResource();
+					for (int i = 0; i < resources.size(); i++) {
+						Resource resource = resources.get(i);
+						if (descriptor.getResource().equals(resource.getName())) {
+							resources.remove(i);
+							return;
+						}
+					}
+				}
+			}
+		};
+		getEditingDomain().getCommandStack().execute(command);
+	}
+
+	/* ==== */
+	/* MISC */
+	/* ==== */
+
+	public EClass getResourceClass(final ResourceDescriptor descriptor) throws InterruptedException {
+		return (EClass) getEditingDomain().runExclusive(new RunnableWithResult.Impl<EClass>() {
+			@Override
+			public void run() {
+				Resource resource = USE_IN_RUNEXLUSIVE_getResource(descriptor);
+				setResult(resource.eClass());
+				return;
+			}
+		});
+	}
+
+	public int getAccessMethodNb(final ResourceDescriptor descriptor) throws InterruptedException {
+		return (Integer) getEditingDomain().runExclusive(new RunnableWithResult.Impl<Integer>() {
+			@Override
+			public void run() {
+				Resource resource = USE_IN_RUNEXLUSIVE_getResource(descriptor);
+				setResult(new Integer(resource.getAccessMethod().size()));
+				return;
+			}
+		});
+	}
+
+	@Override
+	public void onConnect(String gatewayname) {
+	}
+
+	@Override
+	public void onDisconnect(String gatewayname) {
+		this.clearGatewayContent(gatewayname);
 	}
 }
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelEditorHelpers.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelEditorHelpers.java
deleted file mode 100644
index 04248e8..0000000
--- a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelEditorHelpers.java
+++ /dev/null
@@ -1,420 +0,0 @@
-/**
- * Copyright (c) 2019 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.util.ArrayList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-import org.eclipse.emf.common.util.BasicEList;
-import org.eclipse.emf.common.util.EList;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.transaction.TransactionalEditingDomain;
-import org.eclipse.sensinact.studio.http.messages.snamessage.describeresource.MsgDescribeRessource;
-import org.eclipse.sensinact.studio.http.messages.snamessage.describeresource.ObjectAccessMethods;
-import org.eclipse.sensinact.studio.http.messages.snamessage.describeresource.ObjectParameter;
-import org.eclipse.sensinact.studio.model.resource.utils.ResourceDescriptor;
-import org.eclipse.sensinact.studio.model.resource.utils.ServiceDescriptor;
-import org.eclipse.sensinact.studio.resource.AccessMethod;
-import org.eclipse.sensinact.studio.resource.AccessMethodType;
-import org.eclipse.sensinact.studio.resource.Device;
-import org.eclipse.sensinact.studio.resource.Gateway;
-import org.eclipse.sensinact.studio.resource.Parameter;
-import org.eclipse.sensinact.studio.resource.Resource;
-import org.eclipse.sensinact.studio.resource.ResourceFactory;
-import org.eclipse.sensinact.studio.resource.ResourcePackage;
-import org.eclipse.sensinact.studio.resource.Service;
-import org.eclipse.sensinact.studio.resource.Studio;
-
-public abstract class ModelEditorHelpers {
-
-	private static final Logger logger = Logger.getLogger(ModelEditorHelpers.class);
-	
-	private static org.eclipse.emf.ecore.resource.Resource resource;
-
-	private static TransactionalEditingDomain editingDomain;
-
-	private final static String EDITING_DOMAIN_ID = "org.eclipse.sensinact.studio.model.resource.editingDomain";
-
-	protected synchronized static org.eclipse.emf.ecore.resource.Resource getResource() {
-		if (resource == null) {
-			String path = "/org.eclipse.sensinact.studio.model.resource/cache/resource.cache";
-			URI uri = URI.createPlatformPluginURI(path, true);
-			resource = getEditingDomain().getResourceSet().createResource(uri);
-		}
-		return resource;
-	}
-
-	protected synchronized static TransactionalEditingDomain getEditingDomain() {
-		if (editingDomain == null) {
-			editingDomain = TransactionalEditingDomain.Registry.INSTANCE.getEditingDomain(EDITING_DOMAIN_ID);
-		}
-		return editingDomain;
-	}
-
-	protected static void USE_IN_RUNEXLUSIVE_setupStudio() {
-		EList<EObject> contents = getResource().getContents();
-		if (contents.size() == 0)
-			getResource().getContents().add(ResourceFactory.eINSTANCE.createStudio());
-	}
-
-	protected static Studio USE_IN_RUNEXLUSIVE_getStudio() {
-		EList<EObject> contents = getResource().getContents();
-		return (Studio) contents.get(0);
-	}
-
-	protected static Gateway USE_IN_RUNEXLUSIVE_getGateway(String gatewayName) {
-		EList<Gateway> gateways = USE_IN_RUNEXLUSIVE_getStudio().getGateways();
-		for (Gateway gateway : gateways) {
-			if (gateway.getName().equals(gatewayName)) {
-				return gateway;
-			}
-		}
-		return null;
-	}
-
-	protected static Device USE_IN_RUNEXLUSIVE_getDevice(String gatewayName, String devicename) {
-
-		Gateway gateway = USE_IN_RUNEXLUSIVE_getGateway(gatewayName);
-		if (gateway == null)
-			return null;
-
-		EList<Device> devices = gateway.getDevice();
-		for (Device device : devices) {
-			if (device.getName().equals(devicename)) {
-				return device;
-			}
-		}
-		return null;
-	}
-
-	protected static Service USE_IN_RUNEXLUSIVE_getService(String gatewayName, String devicename, String servicename) {
-		Device device = USE_IN_RUNEXLUSIVE_getDevice(gatewayName, devicename);
-		if (device == null)
-			return null;
-
-		for (Service service : device.getService()) {
-			if (service.getName().equals(servicename)) {
-				return service;
-			}
-		}
-
-		return null;
-	}
-
-	protected static Resource USE_IN_RUNEXLUSIVE_getResource(ResourceDescriptor descriptor) {
-		Service service = USE_IN_RUNEXLUSIVE_getService(descriptor.getGateway(), descriptor.getDevice(),
-				descriptor.getService());
-		if (service == null)
-			return null;
-
-		for (Resource resource : service.getResource()) {
-			if (resource.getName().equals(descriptor.getResource())) {
-				return resource;
-			}
-		}
-
-		return null;
-	}
-
-	protected void USE_IN_RUNEXLUSIVE_addGatewayIfNotExist(final String gatewayName) {
-		if (USE_IN_RUNEXLUSIVE_getGateway(gatewayName) != null)
-			return;
-
-		final Gateway addedGateway = ResourceFactory.eINSTANCE.createGateway();
-		addedGateway.setName(gatewayName);
-		USE_IN_RUNEXLUSIVE_getStudio().getGateways().add(addedGateway);
-		return;
-	}
-
-	protected void USE_IN_RUNEXLUSIVE_addDeviceIfNotExist(String gatewayName, String deviceId) {
-		if (USE_IN_RUNEXLUSIVE_getDevice(gatewayName, deviceId) != null)
-			return;
-
-		final Device addedDevice = ResourceFactory.eINSTANCE.createDevice();
-		addedDevice.setName(deviceId);
-		USE_IN_RUNEXLUSIVE_getGateway(gatewayName).getDevice().add(addedDevice);
-	}
-
-	protected void USE_IN_RUNEXLUSIVE_addServiceIfNotExist(String gatewayName, String deviceId, String serviceId) {
-		if (USE_IN_RUNEXLUSIVE_getService(gatewayName, deviceId, serviceId) != null)
-			return;
-
-		final Service addedService = ResourceFactory.eINSTANCE.createService();
-		addedService.setName(serviceId);
-		try {
-			USE_IN_RUNEXLUSIVE_getDevice(gatewayName, deviceId).getService().add(addedService);
-		} catch (NullPointerException e) {
-			e.printStackTrace();
-		}
-	}
-
-	protected void USE_IN_RUNEXLUSIVE_addResourceIfNotExist(ResourceDescriptor descriptor,
-			MsgDescribeRessource responseMessage) {
-		if (USE_IN_RUNEXLUSIVE_getResource(descriptor) != null)
-			return;
-
-		// preparation
-		USE_IN_RUNEXLUSIVE_addDeviceIfNotExist(descriptor.getGateway(), descriptor.getDevice());
-		USE_IN_RUNEXLUSIVE_addServiceIfNotExist(descriptor.getGateway(), descriptor.getDevice(),
-				descriptor.getService());
-
-		// create resource
-		String resourceType = responseMessage.getResponse().getType();
-		EClass type = literalToType(resourceType);
-		Resource createdResource = (Resource) ResourceFactory.eINSTANCE.create(type);
-		createdResource.setName(descriptor.getResource());
-
-		// create access methods
-		for (ObjectAccessMethods am : responseMessage.getResponse().getAccessMethods()) {
-			if (am != null) { // test to be removed after gateway bug fix
-				AccessMethod accessMethod = ResourceFactory.eINSTANCE.createAccessMethod();
-				accessMethod.setType(AccessMethodType.get(am.getName()));
-
-				Parameter[] parameters = new Parameter[am.getParameters().size()];
-				for (int i = 0; i < am.getParameters().size(); i++) {
-					ObjectParameter param = am.getParameters().get(i);
-					Parameter parameter = ResourceFactory.eINSTANCE.createParameter();
-					parameter.setName(param.getName());
-					parameter.setType(param.getType());
-					parameters[i] = parameter;
-				}
-
-				for (Parameter parameter : parameters) {
-					accessMethod.getParameter().add(parameter);
-				}
-				createdResource.getAccessMethod().add(accessMethod);
-			}
-		}
-
-		USE_IN_RUNEXLUSIVE_getService(descriptor.getGateway(), descriptor.getDevice(), descriptor.getService())
-				.getResource().add(createdResource);
-	}
-
-	protected void USE_IN_RUNEXLUSIVE_removeGateway(String gatewayName) {
-		EList<Gateway> gateways = USE_IN_RUNEXLUSIVE_getStudio().getGateways();
-
-		for (int i = 0; i < gateways.size(); i++) {
-			Gateway gateway = gateways.get(i);
-			if (gateway.getName().equals(gatewayName)) {
-				gateways.remove(i);
-				return;
-			}
-		}
-	}
-
-	protected void USE_IN_RUNEXCLUSIVE_removeDevice(String gatewayName, String deviceId) {
-		Gateway gateway = USE_IN_RUNEXLUSIVE_getGateway(gatewayName);
-		if (gateway != null) {
-			EList<Device> devices = gateway.getDevice();
-			for (int i = 0; i < devices.size(); i++) {
-				Device device = devices.get(i);
-				if (deviceId.equals(device.getName())) {
-					devices.remove(i);
-					return;
-				}
-			}
-		}
-	}
-
-	protected void USE_IN_RUNEXCLUSIVE_removeAllDevices(String gatewayName) {
-		Gateway gateway = USE_IN_RUNEXLUSIVE_getGateway(gatewayName);
-		if (gateway != null) {
-			gateway.getDevice().clear();
-		}
-	}
-
-	protected List<String> USE_IN_RUNEXCLUSIVE_getGatewaysId() {
-		List<String> retval = new ArrayList<String>();
-		EList<Gateway> gateways = USE_IN_RUNEXLUSIVE_getStudio().getGateways();
-		for (Gateway gateway : gateways) {
-			retval.add(gateway.getName());
-		}
-		return retval;
-	}
-
-	protected List<String> USE_IN_RUNEXCLUSIVE_getConnectedGatewaysId() {
-		List<String> retval = new ArrayList<String>();
-		EList<Gateway> gateways = USE_IN_RUNEXLUSIVE_getStudio().getGateways();
-		for (Gateway gateway : gateways) {
-			if (gateway.getDevice().size() != 0)
-				retval.add(gateway.getName());
-		}
-		return retval;
-	}
-
-	protected List<String> USE_IN_RUNEXCLUSIVE_getDevicesId(String gatewayName) {
-		List<String> retval = new ArrayList<String>();
-		EList<Device> devices = USE_IN_RUNEXLUSIVE_getGateway(gatewayName).getDevice();
-		for (Device device : devices) {
-			retval.add(device.getName());
-		}
-		return retval;
-	}
-
-	protected List<String> USE_IN_RUNEXCLUSIVE_getServicesId(String gatewayName, String devicename) {
-		List<String> retval = new ArrayList<String>();
-		Device device = USE_IN_RUNEXLUSIVE_getDevice(gatewayName, devicename);
-
-		if (device != null) {
-			for (Service service : device.getService()) {
-				retval.add(service.getName());
-			}
-		}
-		return retval;
-	}
-
-	protected List<String> USE_IN_RUNEXCLUSIVE_getResourcesId(String gatewayName, String devicename,
-			String servicename) {
-		List<String> retval = new ArrayList<String>();
-		Service service = USE_IN_RUNEXLUSIVE_getService(gatewayName, devicename, servicename);
-		if (service != null) {
-			for (Resource resource : service.getResource()) {
-				retval.add(resource.getName());
-			}
-		}
-		return retval;
-	}
-
-	protected List<ServiceDescriptor> USE_IN_RUNEXCLUSIVE_findApplications() {
-		List<ServiceDescriptor> retval = new ArrayList<>();
-		EList<Gateway> gateways = USE_IN_RUNEXLUSIVE_getStudio().getGateways();
-		for (Gateway gateway : gateways) {
-			Device appManager = findAppManager(gateway.getDevice());
-			if (appManager != null) {
-				retval.addAll(findApplications(appManager));
-			}
-		}
-		return retval;
-	}
-
-	protected EList<AccessMethod> USE_IN_RUNEXCLUSIVE_getAccessMethods(ResourceDescriptor descriptor) {
-		EList<AccessMethod> accessMethods = new BasicEList<AccessMethod>();
-		Resource resource = USE_IN_RUNEXLUSIVE_getResource(descriptor);
-		for (AccessMethod accessMethod : resource.getAccessMethod()) {
-			accessMethods.add(accessMethod);
-		}
-		return accessMethods;
-	}
-
-	protected EList<AccessMethod> USE_IN_RUNEXCLUSIVE_getAccessMethodsWithType(ResourceDescriptor descriptor,
-			AccessMethodType type) {
-		EList<AccessMethod> accessMethods = new BasicEList<AccessMethod>();
-		Resource resource = USE_IN_RUNEXLUSIVE_getResource(descriptor);
-		for (AccessMethod accessMethod : resource.getAccessMethod()) {
-			if (accessMethod.getType().equals(type)) {
-				accessMethods.add(accessMethod);
-			}
-		}
-		return accessMethods;
-	}
-
-	protected AccessMethod USE_IN_RUNEXCLUSIVE_getAccessMethodWithTypeNbParams(ResourceDescriptor descriptor,
-			AccessMethodType type, int nbOfParameters) {
-		Resource resource = USE_IN_RUNEXLUSIVE_getResource(descriptor);
-		for (AccessMethod accessMethod : resource.getAccessMethod()) {
-			if (accessMethod.getType().equals(type)) {
-				if (accessMethod.getParameter().size() == nbOfParameters) {
-					return accessMethod;
-				}
-			}
-		}
-		return null;
-	}
-
-	protected void USE_IN_RUNEXCLUSIVE_removeResource(final ResourceDescriptor descriptor) {
-		Service service = USE_IN_RUNEXLUSIVE_getService(descriptor.getGateway(), descriptor.getDevice(),
-				descriptor.getService());
-		if (service != null) {
-			EList<Resource> resources = service.getResource();
-			for (int i = 0; i < resources.size(); i++) {
-				Resource resource = resources.get(i);
-				if (descriptor.getResource().equals(resource.getName())) {
-					resources.remove(i);
-					return;
-				}
-			}
-		}
-	}
-
-	protected void USE_IN_RUNEXCLUSIVE_removeService(final String gatewayName, final String deviceId,
-			final String serviceId) {
-		Device device = USE_IN_RUNEXLUSIVE_getDevice(gatewayName, deviceId);
-		if (device != null) {
-			EList<Service> services = device.getService();
-			for (int i = 0; i < services.size(); i++) {
-				Service service = services.get(i);
-				if (serviceId.equals(service.getName())) {
-					services.remove(i);
-					return;
-				}
-			}
-		}
-	}
-
-	/* ============ */
-	/* RunExclusive */
-	/* ============ */
-
-	protected static EClass literalToType(final String type) {
-
-		final EClass resourceType;
-		// Literals
-		EClass stateVariableLiteral = ResourcePackage.Literals.STATE_VARIABLE;
-		EClass actionLiteral = ResourcePackage.Literals.ACTION;
-		EClass propertyLiteral = ResourcePackage.Literals.PROPERTY;
-		EClass sensorDataLiteral = ResourcePackage.Literals.SENSOR_DATA;
-
-		if ("STATE_VARIABLE".equals(type)) {
-			resourceType = stateVariableLiteral;
-		} else if ("ACTION".equals(type)) {
-			resourceType = actionLiteral;
-		} else if ("PROPERTY".equals(type)) {
-			resourceType = propertyLiteral;
-		} else if ("SENSOR".equals(type)) {
-			resourceType = sensorDataLiteral;
-		} else {
-			logger.error(ModelEditor.class.getCanonicalName() + "::updateResource with type=" + type + " - Is it a bug or a feature ?");
-			resourceType = actionLiteral;
-		}
-		return resourceType;
-	}
-
-	/* ============= */
-	/* MODEL HELPERS */
-	/* ============= */
-
-	protected Device findAppManager(EList<Device> devices) {
-		for (Device device : devices) {
-			if (device.getName().equals("AppManager"))
-				return device;
-		}
-		return null;
-	}
-
-	protected List<ServiceDescriptor> findApplications(Device appManager) {
-		List<ServiceDescriptor> retval = new ArrayList<>();
-
-		String gateway = ((Gateway) appManager.eContainer()).getName();
-		String device = appManager.getName();
-
-		for (Service service : appManager.getService()) {
-			String srvName = service.getName();
-			if (srvName != null && (!srvName.equalsIgnoreCase("admin"))) {
-				retval.add(new ServiceDescriptor(gateway, device, srvName));
-			}
-		}
-		return retval;
-	}
-
-}
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelUpdate.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelUpdate.java
new file mode 100644
index 0000000..c086b1f
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelUpdate.java
@@ -0,0 +1,82 @@
+package org.eclipse.sensinact.studio.model.manager.modelupdater;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.sensinact.studio.model.resource.utils.Descriptor;
+import org.eclipse.sensinact.studio.model.resource.utils.ResourceDescriptor;
+
+public abstract class ModelUpdate<D extends Descriptor> {
+
+	protected abstract void doApply();
+	protected abstract boolean doComplete();
+	
+	protected final D object;
+	protected List<ModelUpdate<?>> next;
+
+	public ModelUpdate(D object){
+		this.object = object;
+		next = new ArrayList<>();
+	}
+
+	public boolean complete(){		
+		if(doComplete()){			
+			for(ModelUpdate<?> mu:next){				
+				if(!mu.complete())
+					return false;
+			}
+			return true;
+		}
+		return false;
+	}
+	
+	public void apply(){		
+		if(!complete())
+			return;
+		this.doApply();
+		for(ModelUpdate<?> mu:next){
+			mu.apply();
+		}
+	}
+
+	private Descriptor getDescriptor(){
+		return this.object;
+	}
+	
+	public boolean addNext(ModelUpdate<?> next){		
+		int compare = this.object.compareTo(next.getDescriptor());		
+		if(compare==0 || compare==1)
+			return false;
+		for(ModelUpdate<?> mu:this.next){			
+			if(mu.addNext(next))
+				return true;
+		}
+		return this.next.add(next);
+	}
+	
+	public boolean branch(ModelUpdate<?> mu) {
+		Descriptor d = mu.object;
+		String branch = d.commonBranch(object);
+		return branch!=null && branch.length()>1;
+	}
+
+	protected boolean existsGateway(final String gatewayId) {
+		return ModelEditor.getInstance().getGatewaysId().contains(gatewayId);
+	}
+
+	protected boolean existsDevice(final String gatewayId, String deviceId) {
+		return ModelEditor.getInstance().getDevicesId(gatewayId).contains(deviceId);
+	}
+
+	protected boolean existsService(final String gatewayId, String deviceId, String serviceId){
+		return ModelEditor.getInstance().getServicesId(gatewayId, deviceId).contains(serviceId);
+	}
+
+	protected boolean existsResource(final String gatewayId, String deviceId, String serviceId, String resourceId) {
+		return this.existsResource(new ResourceDescriptor(gatewayId, deviceId, serviceId, resourceId));
+	}
+
+	protected boolean existsResource(ResourceDescriptor descriptor) {
+		return ModelEditor.getInstance().getResourcesId(descriptor.getGateway(), descriptor.getDevice(), descriptor.getService()).contains(descriptor.getResource());
+	}
+}
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelUpdateStack.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelUpdateStack.java
new file mode 100644
index 0000000..790af31
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelUpdateStack.java
@@ -0,0 +1,63 @@
+/**
+ * 
+ */
+package org.eclipse.sensinact.studio.model.manager.modelupdater;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * 
+ */
+public class ModelUpdateStack extends AbstractList<ModelUpdate<?>> {
+
+	List<ModelUpdate<?>> stack;
+	
+	public ModelUpdateStack() {
+		super();
+		this.stack = Collections.synchronizedList(new ArrayList<ModelUpdate<?>>());
+	}
+	
+	@Override
+	public ModelUpdate<?> get(int index) {
+		return this.stack.get(index);
+	}
+	
+	public boolean add(ModelUpdate<?> mu){
+		if(mu == null)
+			return false;
+        if(mu.complete()){
+        	mu.apply();
+        	return true;
+        }
+		synchronized (stack){			
+	        Iterator<ModelUpdate<?>> i = stack.iterator(); 
+	        while (i.hasNext()){
+	    	    ModelUpdate<?> model = i.next();
+	            if(model.addNext(mu)){
+	        	    if(model.complete()){
+	        		    model.apply();
+	        		    i.remove();
+	        	   }
+	        	   return true;
+	            } if(mu.addNext(model)){
+ 	        	   i.remove();
+ 	               if(mu.complete()){
+ 	        	       mu.apply();
+ 	        	       return true;
+ 	               }
+ 	        	   break;
+	            }
+	        }
+		}
+	    return stack.add(mu);
+	}
+
+	@Override
+	public int size() {
+		return this.stack.size();
+	}
+}
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelUpdater.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelUpdater.java
index 9c5cbec..e82384c 100644
--- a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelUpdater.java
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ModelUpdater.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019 CEA.
+ * 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
@@ -12,16 +12,15 @@
 
 import java.io.IOException;
 import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
 
 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.completelist.ObjectResource;
-import org.eclipse.sensinact.studio.http.messages.snamessage.completelist.ObjectService;
+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;
@@ -29,37 +28,39 @@
 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.ConnectionListener;
 import org.eclipse.sensinact.studio.http.services.client.connectionmanager.NotifDispatcher;
-import org.eclipse.sensinact.studio.http.services.client.connectionmanager.NotifSubscriptionListener;
-import org.eclipse.sensinact.studio.model.manager.listener.devicelocation.DeviceLocationManager;
+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, ConnectionListener {
+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((NotifSubscriptionListener) this);
-		NotifDispatcher.getInstance().subscribe((ConnectionListener) this);
+		NotifDispatcher.getInstance().subscribe(this);
 	}
 
 	/**
@@ -74,36 +75,36 @@
 			Segments segments = new Segments.Builder().gateway(gatewayName).root().build();
 			MsgSensinact snaMsg = GatewayHttpClient.sendGetRequest(segments);
 			
-			if (!(snaMsg instanceof MsgCompleteList))
-				throwExceptionOnError(snaMsg, "devices");
+			if (!(snaMsg instanceof MsgCompleteList)) {
+				displayLogOnError(snaMsg, "devices");
+				return;
+			}
 
 			MsgCompleteList list = (MsgCompleteList) snaMsg;
 			
 			// update devices list
 			new Thread() {
 				public void run() {
-					try {
-		
-						// add devices						
-						for (ObjectProvider provider : list.getProviders())
-							ModelEditor.getInstance().addDeviceIfNotExist(gatewayName, provider.getName());
-						
-						// remove device
-						for (String localDevicesId : ModelEditor.getInstance().getDevicesId(gatewayName)) {			
-							Optional<String> elem = list.getProviders().stream().map(p -> p.getName()).filter(name -> name.equals(localDevicesId)).findFirst();
-							if( ! elem.isPresent()) {
-								ModelEditor.getInstance().removeDevice(gatewayName, localDevicesId);
-							}
+					// 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);							
 						}
-					} catch (InterruptedException e) {
-						e.printStackTrace();
+					}
+					// 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();
-			
-			// update locations
-			for (ObjectProvider provider : list.getProviders())
-				updateLocation(new DeviceDescriptor(gatewayName, provider.getName()), provider.getLocation());
 	}
 
 	/**
@@ -113,45 +114,31 @@
 	 *            the device from which services need to be retrieved
 	 * @throws IOException
 	 */
-	public void updateServices(final String gatewayName, final String deviceId, boolean recursive) throws IOException {
+	public void updateServices(final String gatewayName, final String deviceId) throws IOException {
 		
-		String expr = "jsonpath=$..*[?(@.name=='" + deviceId + "')]";
-		Segments segments = new Segments.Builder().gateway(gatewayName).jsonPath(expr).build();
-
+		Segments segments = new Segments.Builder().gateway(gatewayName).device(deviceId).services().build();		
 		MsgSensinact snaMsg = GatewayHttpClient.sendGetRequest(segments);
 		
-		if (!(snaMsg instanceof MsgCompleteList))
-			throwExceptionOnError(snaMsg, "services");
+		if (!(snaMsg instanceof MsgServicesList)) {
+			System.out.println(snaMsg);
+			displayLogOnError(snaMsg, "services");
+			return;
+		}
+		if(((MsgServicesList) snaMsg).getServices() == null)
+			return;
 
-		MsgCompleteList list = (MsgCompleteList) snaMsg;
-
-		try {
-			ObjectProvider provider = list.getProvider(deviceId);
-			
-			// location update
-			updateLocation(new DeviceDescriptor(gatewayName, deviceId), provider.getLocation());
-			
-			// add service
-			for (ObjectService service : provider.getServices()) {
-				ModelEditor.getInstance().addServiceIfNotExist(gatewayName, deviceId, service.getName());
-				if(recursive) {
-					List<ObjectResource> resources = service.getResources();
-					for (ObjectResource resource : resources) {
-						ModelEditor.getInstance().addResourceIfNotExist(new ResourceDescriptor(gatewayName, deviceId, service.getName(), resource.getName()));
-					}
-				}
+		// 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);
 			}
-
-			// remove service
-			for (String localServicesId : ModelEditor.getInstance().getServicesId(gatewayName, deviceId)) {
-				List<String> servicesIds = list.getProvider(deviceId).getServices().stream().map(s->s.getName()).collect(Collectors.toList());
-				if(!servicesIds.contains(localServicesId)){
-					ModelEditor.getInstance().removeService(gatewayName, deviceId, localServicesId);
-				}
-			}
-			
-		} catch (Exception e) {
-			throw new IOException("Error while parsing infos for " + gatewayName + "/" + deviceId, e); 
+		}
+		
+		for (String service : ((MsgServicesList) snaMsg).getServices()){
+			stack.add(new ServiceAppearing(new ServiceDescriptor(gatewayName, deviceId, service)));
 		}
 	}
 	
@@ -171,51 +158,79 @@
 
 		MsgSensinact msg = GatewayHttpClient.sendGetRequest(segment);
 		
-		if (msg instanceof MsgResourcesList) {
-			List<String> resources = ((MsgResourcesList) msg).getResources();
-			for (int i = 0; i < resources.size(); i++) {
-				final String resourceId = resources.get(i);
-				ModelEditor.getInstance().addResourceIfNotExist(new ResourceDescriptor(gatewayName, deviceId, serviceId, resourceId));
+		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);
 			}
-		} else {
-			throwExceptionOnError(msg, "resources");
 		}
+		//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 */
 	/* =============== */
 
-	private void updateLocation(DeviceDescriptor descriptor, String coordinates) {
-		if (validCoordinates(coordinates)) {
-			try {
-				GPScoordinates gps = new GPScoordinates(coordinates);
-				DeviceLocationManager.getInstance().updateLocationInStudio(descriptor, gps);
-			} catch (GPSparsingException e) {
-				logger.error("coordinates parsing error for " + descriptor + " (" + coordinates + ")");
-			}
-		}
-	}
-
-	private static boolean validCoordinates(String coordinate) {
-		if (coordinate == null)
-			return false;
-		if (coordinate.isEmpty())
-			return false;
-		if (coordinate.equals("null"))
-			return false;
-		if (coordinate.equals("null:null"))
-			return false;
-		return true;
-	}
-
 	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", "java.lang.String", coordinates.getLat() + ":" + coordinates.getLng());
-		
+		RequestParameter param = new RequestParameter("location", "string", coordinates.getLat() + ":" + coordinates.getLng());
 		try {
 			MsgSensinact msg = GatewayHttpClient.sendPostRequest(segments, null,param);
-			return msg.isValid();
+			if (msg instanceof MsgHttpError) {
+				return false;
+			} else {
+				return true;
+			}
 		} catch (IOException e) {
 			logger.error("Update location on server failed", e);
 			return false;
@@ -231,77 +246,65 @@
 		for (MsgSensinact message : messages)
 			onLifecycleEvent(gateway, message);
 	}
-
+	
 	public void onLifecycleEvent(String gateway, MsgSensinact message) {
 		
-		if (message instanceof MsgProviderAppearing) {
-			MsgProviderAppearing msg = (MsgProviderAppearing) message;
-			String providerName = getProviderName(msg.getUri());
-			// updateLocation(new DeviceDescriptor(gateway, providerName), provider.getLocation());
-			executeInThread( () -> ModelEditor.getInstance().addDeviceIfNotExist(gateway, providerName));
+		String uri = message.getUri();
+		ModelUpdate<?> mu = null;
 		
+		if (message instanceof MsgProviderAppearing) {
+			mu = new DeviceAppearing(new DeviceDescriptor(gateway, getProviderName(uri)));
+			
 		} else if (message instanceof MsgProviderDisappearing) {
-			MsgProviderDisappearing msg = (MsgProviderDisappearing) message;
-			String providerName = getProviderName(msg.getUri());
-			DeviceLocationManager.getInstance().deleteDeviceInStudio(new DeviceDescriptor(gateway, providerName));
-			executeInThread( () -> ModelEditor.getInstance().removeDevice(gateway, providerName));		
+			mu = new DeviceDisappearing(new DeviceDescriptor(gateway, getProviderName(uri)));			
 			
 		} else if (message instanceof MsgServiceAppearing) {
-			MsgServiceAppearing msg = (MsgServiceAppearing) message;
-			String providerName = getProviderName(msg.getUri());
-			String serviceName = getServiceName(msg.getUri());
-			executeInThread( () -> ModelEditor.getInstance().addServiceIfNotExist(gateway, providerName, serviceName));
+			mu = new ServiceAppearing(new ServiceDescriptor(gateway, getProviderName(uri),getServiceName(uri)));
 		
 		} else if (message instanceof MsgServiceDisappearing) {
-			MsgServiceDisappearing msg = (MsgServiceDisappearing) message;
-			String providerName = getProviderName(msg.getUri());
-			String serviceName = getServiceName(msg.getUri());
-			executeInThread( () -> ModelEditor.getInstance().removeService(gateway, providerName, serviceName));
+			mu = new ServiceDisappearing(new ServiceDescriptor(gateway, getProviderName(uri),getServiceName(uri)));
 			
 		} else if (message instanceof MsgResourceAppearing) {
-			MsgResourceAppearing msg = (MsgResourceAppearing) message;
-			String providerName = getProviderName(msg.getUri());
-			String serviceName = getServiceName(msg.getUri());
-			String resourceName = getResourceName(msg.getUri());
-			executeInThread( () -> ModelEditor.getInstance().addResourceIfNotExist(new ResourceDescriptor(gateway, providerName, serviceName, resourceName)));
-			if ("location".equals(resourceName)) {
-				String coordinates = msg.getInitial().getValueAsString();
-				updateLocation(new DeviceDescriptor(gateway, providerName), coordinates);
-			}
+			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) {
-			MsgResourceDisappearing msg = (MsgResourceDisappearing) message;
-			String providerName = getProviderName(msg.getUri());
-			String serviceName = getServiceName(msg.getUri());
-			String resourceName = getResourceName(msg.getUri());
-			executeInThread( () -> ModelEditor.getInstance().removeResource(new ResourceDescriptor(gateway, providerName, serviceName, resourceName)));
-			
+			mu = new ResourceDisappearing(new ResourceDescriptor(gateway, 
+					getProviderName(uri),getServiceName(uri),
+					getResourceName(uri)));
 		} else {
-			throw new RuntimeException("Unhandled lifecycle event of class " + message.getClass() + " " + message.toString());
+			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 gatewayName, MsgSensinact message) {
-		if (message instanceof MsgAttributeValueUpdated) {
-			MsgAttributeValueUpdated msg = (MsgAttributeValueUpdated) message;
-			String deviceId = msg.getUri().split("/")[1];
-			String location = msg.getNotification().getValueAsString();
-			updateLocation(new DeviceDescriptor(gatewayName, deviceId), location);	
+	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);
 		}
 	}
 	
-	@Override
-	public void onValueEvent(String gateway, List<MsgSensinact> messages) {
-		// do nothing
-	}
-	
-	private static void executeInThread(Runnable r){
+	static void executeInThread(Runnable r){
 		Runnable runnableWithTry = () -> {
 			try {
 				r.run();
@@ -311,7 +314,24 @@
 		}; 		
 		new Thread(runnableWithTry).start();
     }
-	
+
+
+	@Override
+	public void onIconEvent(String gateway, List<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("/");
@@ -328,22 +348,12 @@
 		return tokens[3];
 	}
 	
-	@Override
-	public void onConnect(String gatewayname) {
-		logger.info("Gateway " + gatewayname + " connected");
-	}
-
-	@Override
-	public void onDisconnect(String gatewayname) {
-		ModelEditor.getInstance().clearGatewayContent(gatewayname);
-	}
-	
 	/* ========= */
 	/* Exception */
 	/* ========= */
 	
-	private void throwExceptionOnError(MsgSensinact response, String elementName) {
+	private void displayLogOnError(MsgSensinact response, String elementName) {
 		String fullMsg = String.format("Error sent by gateway while getting %s (%s)", elementName, response.getType());
-		throw new RuntimeException(fullMsg);
+		logger.error(fullMsg);
 	}
 }
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ResourceAppearing.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ResourceAppearing.java
new file mode 100644
index 0000000..5321a54
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ResourceAppearing.java
@@ -0,0 +1,61 @@
+/**
+ * 
+ */
+package org.eclipse.sensinact.studio.model.manager.modelupdater;
+
+import org.eclipse.sensinact.studio.http.messages.snamessage.ObjectNameTypeValue;
+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;
+
+/**
+ *
+ */
+public class ResourceAppearing extends ModelUpdate<ResourceDescriptor> {
+
+	/**
+	 * @param object
+	 */
+	public ResourceAppearing(ResourceDescriptor object) {
+		super(object);
+	}
+
+	@Override
+	protected void doApply(){		
+		ResourceDescriptor d = super.object;
+		ModelUpdater.executeInThread(
+			() -> ModelEditor.getInstance().addResourceIfNotExist(super.object)
+		);
+		ObjectNameTypeValue ontv = d.getInitial();
+		if(ontv==null) 
+			return;
+		String value = ontv.getValueAsString();
+		if(value==null || "null".equals(value))
+			return;
+		final DeviceDescriptor descriptor = new DeviceDescriptor(d.getGateway(),d.getDevice());
+		if("location".equals(d.getResource()) && "admin".equals(d.getService())){				
+			GPScoordinates gps;
+			try {
+				gps = new GPScoordinates(value);
+			} catch (GPSparsingException e) {
+				e.printStackTrace();
+				return;
+			}
+			ModelUpdater.executeInThread(() -> ModelEditor.getInstance().setLocation(descriptor, gps));
+		}		
+		if("icon".equals(d.getResource()) && "admin".equals(d.getService())){
+			ModelUpdater.executeInThread(() -> ModelEditor.getInstance().setIcon(descriptor, value));
+		}
+	}
+
+	@Override
+	protected boolean doComplete() {
+		return super.object.getGateway()!=null &&
+			   super.object.getDevice()!=null  &&
+			   super.object.getService()!=null &&
+			   super.object.getResource()!=null &&
+			   super.existsService(super.object.getGateway(),super.object.getDevice(),super.object.getService());
+	}
+
+}
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ResourceDisappearing.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ResourceDisappearing.java
new file mode 100644
index 0000000..a63346c
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ResourceDisappearing.java
@@ -0,0 +1,40 @@
+/**
+ * 
+ */
+package org.eclipse.sensinact.studio.model.manager.modelupdater;
+
+import org.eclipse.sensinact.studio.model.resource.utils.ResourceDescriptor;
+
+/**
+ *
+ */
+public class ResourceDisappearing extends ModelUpdate<ResourceDescriptor> {
+
+	/**
+	 * @param object
+	 */
+	public ResourceDisappearing(ResourceDescriptor object) {
+		super(object);
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.sensinact.studio.model.manager.modelupdater.ModelUpdate#doApply()
+	 */
+	@Override
+	protected void doApply(){
+		
+		ModelUpdater.executeInThread(
+				() -> ModelEditor.getInstance().removeResource(
+						super.object)
+			);
+	}
+
+	@Override
+	protected boolean doComplete() {
+		return super.object.getGateway()!=null &&
+			   super.object.getDevice()!=null &&
+			   super.object.getService()!=null &&
+			   super.object.getResource()!=null;
+	}
+
+}
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ServiceAppearing.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ServiceAppearing.java
new file mode 100644
index 0000000..f21d6dc
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ServiceAppearing.java
@@ -0,0 +1,38 @@
+/**
+ * 
+ */
+package org.eclipse.sensinact.studio.model.manager.modelupdater;
+
+import org.eclipse.sensinact.studio.model.resource.utils.ServiceDescriptor;
+
+/**
+ *
+ */
+public class ServiceAppearing extends ModelUpdate<ServiceDescriptor> {
+
+	/**
+	 * @param object
+	 */
+	public ServiceAppearing(ServiceDescriptor object) {
+		super(object);
+	}
+
+	@Override
+	protected void doApply(){
+		ModelUpdater.executeInThread(
+			() -> ModelEditor.getInstance().addServiceIfNotExist(
+					super.object.getGateway(),
+					super.object.getDevice(),
+					super.object.getService())
+			);
+	}
+	
+	@Override
+	protected boolean doComplete() {
+		return super.object.getGateway()!=null &&
+			   super.object.getDevice()!=null &&
+			   super.object.getService()!=null &&
+			   super.existsDevice(super.object.getGateway(),super.object.getDevice());
+	}
+
+}
diff --git a/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ServiceDisappearing.java b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ServiceDisappearing.java
new file mode 100644
index 0000000..825c474
--- /dev/null
+++ b/services/org.eclipse.sensinact.studio.model.manager/src/org/eclipse/sensinact/studio/model/manager/modelupdater/ServiceDisappearing.java
@@ -0,0 +1,38 @@
+/**
+ * 
+ */
+package org.eclipse.sensinact.studio.model.manager.modelupdater;
+
+import org.eclipse.sensinact.studio.model.resource.utils.ServiceDescriptor;
+
+/**
+ *
+ */
+public class ServiceDisappearing extends ModelUpdate<ServiceDescriptor> {
+
+	/**
+	 * @param object
+	 */
+	public ServiceDisappearing(ServiceDescriptor object) {
+		super(object);
+	}
+
+	@Override
+	protected void doApply(){
+		
+		ModelUpdater.executeInThread(
+				() -> ModelEditor.getInstance().removeService(
+					super.object.getGateway(),
+					super.object.getDevice(),
+					super.object.getService())
+			);
+	}
+
+	@Override
+	protected boolean doComplete() {
+		return super.object.getGateway()!=null &&
+			   super.object.getDevice()!=null &&
+			   super.object.getService()!=null;
+	}
+
+}