/**
* Copyright (c) 2011-2014, OpenIoT
*
* This file is part of OpenIoT.
*
* OpenIoT is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* OpenIoT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OpenIoT. If not, see <http://www.gnu.org/licenses/>.
*
* Contact: OpenIoT mailto: info@openiot.eu
*/
package org.openiot.ui.request.commons.nodes.base;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Observer;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.openiot.ui.request.commons.annotations.GraphNodeClass;
import org.openiot.ui.request.commons.annotations.scanners.GraphNodeScanner;
import org.openiot.ui.request.commons.factory.GraphFactory;
import org.openiot.ui.request.commons.interfaces.GraphModel;
import org.openiot.ui.request.commons.logging.LoggerService;
import org.openiot.ui.request.commons.models.ObservableMap;
import org.openiot.ui.request.commons.nodes.interfaces.GraphNode;
import org.openiot.ui.request.commons.nodes.interfaces.GraphNodeConnection;
import org.openiot.ui.request.commons.nodes.interfaces.GraphNodeEndpoint;
import org.openiot.ui.request.commons.nodes.interfaces.GraphNodeProperty;
/**
*
* @author Achilleas Anagnostopoulos (aanag) email: aanag@sensap.eu
*/
public class DefaultGraphNode implements GraphNode, Serializable {
private static final long serialVersionUID = 1L;
private String UID = "graphNode_" + System.nanoTime();
private String type;
private String label;
private List<GraphNodeProperty> propertyDefinitions;
private List<GraphNodeEndpoint> endpointDefinitions;
private ObservableMap<String, Object> propertyMap;
private GraphModel graphModel;
public DefaultGraphNode() {
propertyMap = new ObservableMap<String, Object>(new HashMap<String, Object>());
// Check if we need to scan our class for annotations
GraphNodeClass annotationData = this.getClass().isAnnotationPresent(GraphNodeClass.class) ? this.getClass().getAnnotation(GraphNodeClass.class) : null;
if (annotationData != null && annotationData.scanProperties()) {
propertyDefinitions = GraphNodeScanner.detectPropertyDefinitions(this.getClass());
endpointDefinitions = GraphNodeScanner.detectEndpointDefinitions(this.getClass());
// Generate map fields
for (GraphNodeProperty property : propertyDefinitions) {
try {
propertyMap.put(property.getName(), property.getJavaType().newInstance());
} catch (Throwable ex) {
}
}
setLabel(annotationData.label());
setType(annotationData.type());
} else {
propertyDefinitions = new ArrayList<GraphNodeProperty>();
endpointDefinitions = new ArrayList<GraphNodeEndpoint>();
}
}
public void setGraphModel(GraphModel model) {
this.graphModel = model;
}
public GraphModel getGraphModel() {
return this.graphModel;
}
protected void disconnectEndpoint(GraphNodeEndpoint ep) {
// If we have a connection to this node, kill it
if (graphModel != null) {
List<GraphNodeConnection> connections = graphModel.findGraphEndpointConnections(ep);
if (!connections.isEmpty()) {
GraphNodeConnection connection = connections.get(0);
graphModel.disconnect(connection);
}
}
}
public String getUID() {
return UID;
}
public void setUID(String UID) {
this.UID = UID;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<GraphNodeProperty> getPropertyDefinitions() {
return propertyDefinitions;
}
public void setPropertyDefinitions(List<GraphNodeProperty> propertyDefinitions) {
this.propertyDefinitions = propertyDefinitions;
}
public GraphNodeProperty getPropertyByName(String name) {
for (GraphNodeProperty property : propertyDefinitions) {
if (property.getName().equals(name)) {
return property;
}
}
return null;
}
public Map<String, Object> getPropertyValueMap() {
return propertyMap;
}
public void setProperty(String propertyKey, Object propertyValue) {
propertyMap.put(propertyKey, propertyValue);
}
public List<GraphNodeEndpoint> getEndpointDefinitions() {
return endpointDefinitions;
}
public void setEndpointDefinitions(List<GraphNodeEndpoint> endpointDefinitions) {
this.endpointDefinitions = endpointDefinitions;
}
public GraphNodeEndpoint getEndpointByLabel(String label) {
for (GraphNodeEndpoint ep : endpointDefinitions) {
if (ep.getLabel().equals(label)) {
return ep;
}
}
return null;
}
public void addPropertyChangeObserver(Observer o) {
this.propertyMap.addObserver(o);
}
public void removePropertyChangeObserver(Observer o) {
this.propertyMap.deleteObserver(o);
}
public GraphNode getCopy() {
DefaultGraphNode copy = null;
try {
copy = this.getClass().newInstance();
copy.setLabel(label);
copy.setType(type);
List<GraphNodeEndpoint> endpointDefinitionsCopy = new ArrayList<GraphNodeEndpoint>(endpointDefinitions.size());
for (GraphNodeEndpoint ep : endpointDefinitions) {
endpointDefinitionsCopy.add(ep.getCopy());
}
copy.setEndpointDefinitions(endpointDefinitionsCopy);
List<GraphNodeProperty> propertyDefinitionsCopy = new ArrayList<GraphNodeProperty>(propertyDefinitions.size());
for (GraphNodeProperty prop : propertyDefinitions) {
propertyDefinitionsCopy.add(prop.getCopy());
if (propertyMap.containsKey(prop.getName())) {
copy.setProperty(prop.getName(), propertyMap.get(prop.getName()));
}
}
copy.setPropertyDefinitions(propertyDefinitionsCopy);
} catch (Throwable ex) {
}
return copy;
}
public JSONObject toJSON() {
JSONObject spec = new JSONObject();
try {
spec.put("class", this.getClass().getCanonicalName());
spec.put("uid", getUID());
spec.put("type", getType());
spec.put("label", getLabel());
// Encode property definitions
JSONArray propertyDefinitions = new JSONArray();
for (GraphNodeProperty prop : getPropertyDefinitions()) {
propertyDefinitions.put(prop.toJSON());
}
spec.put("propertyDefinitions", propertyDefinitions);
// Encode endpoint definitions
JSONArray endpointDefinitions = new JSONArray();
for (GraphNodeEndpoint endpoint : getEndpointDefinitions()) {
endpointDefinitions.put(endpoint.toJSON());
}
spec.put("endpointDefinitions", endpointDefinitions);
// Encode property values
JSONObject propertyValues = new JSONObject();
for (Map.Entry<String, Object> entry : propertyMap.entrySet()) {
Class javaType = getPropertyByName(entry.getKey()).getJavaType();
// Convert date to long
if( javaType.isAssignableFrom(Date.class)){
propertyValues.put(entry.getKey(), ((Date)entry.getValue()).getTime());
}else{
propertyValues.put(entry.getKey(), entry.getValue());
}
}
spec.put("propertyValues", propertyValues);
} catch (JSONException ex) {
LoggerService.log(ex);
}
return spec;
}
public void importJSON(JSONObject spec) throws JSONException {
setUID(spec.getString("uid"));
setType(spec.getString("type"));
setLabel(spec.getString("label"));
// Parse property definitions
JSONArray propertyDefinitions = spec.getJSONArray("propertyDefinitions");
this.propertyDefinitions.clear();
for (int index = 0; index < propertyDefinitions.length(); index++) {
this.propertyDefinitions.add(GraphFactory.createGraphNodeProperty(propertyDefinitions.getJSONObject(index)));
}
// Parse endpoint definitions
JSONArray endpointDefinitions = spec.getJSONArray("endpointDefinitions");
this.endpointDefinitions.clear();
for (int index = 0; index < endpointDefinitions.length(); index++) {
this.endpointDefinitions.add(GraphFactory.createGraphNodeEndpoint(endpointDefinitions.getJSONObject(index)));
}
// Parse property values
JSONObject propertyValues = spec.getJSONObject("propertyValues");
Iterator<?> keyIt = propertyValues.keys();
this.propertyMap.getWrappedMap().clear();
while (keyIt.hasNext()) {
String key = (String) keyIt.next();
Class javaType = getPropertyByName(key).getJavaType();
if (List.class.isAssignableFrom(javaType)) {
List<String> list = new ArrayList<String>();
JSONArray data = propertyValues.getJSONArray(key);
for (int index = 0; index < data.length(); index++) {
list.add(data.getString(index));
}
this.propertyMap.getWrappedMap().put(key, list);
} else {
if( javaType.isAssignableFrom(Date.class) ){
this.propertyMap.getWrappedMap().put(key, new Date(propertyValues.optLong(key)));
}else{
this.propertyMap.getWrappedMap().put(key, propertyValues.optString(key));
}
}
}
// Trigger refresh
if( this instanceof Observer){
((Observer)this).update(this.propertyMap, null);
}
}
@Override
public String toString() {
return "[type: " + getType() + ", label: " + getLabel() + ", properties: " + getPropertyDefinitions() + ", endPoints: " + endpointDefinitions + "]";
}
}