/* * Copyright (c) 2013 Technische Universitat Wien (TUW), Distributed Systems Group. http://dsg.tuwien.ac.at * * This work was partially supported by the European Commission in terms of the CELAR FP7 project (FP7-ICT-2011-8 #317790), http://www.celarcloud.eu/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.ac.tuwien.dsg.cloud.salsa.engine.services.jsondata; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.ServiceInstance; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.ServiceTopology; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.ServiceUnit; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.enums.SalsaEntityState; import at.ac.tuwien.dsg.cloud.salsa.common.cloudservice.model.enums.SalsaEntityType; import at.ac.tuwien.dsg.cloud.salsa.tosca.extension.SalsaCapaReqString; import at.ac.tuwien.dsg.cloud.salsa.tosca.extension.SalsaInstanceDescription_Docker; import at.ac.tuwien.dsg.cloud.salsa.tosca.extension.SalsaInstanceDescription_SystemProcess; import at.ac.tuwien.dsg.cloud.salsa.tosca.extension.SalsaInstanceDescription_VM; /** * The class contains information to be visualized as graph * * @author Duc-Hung Le * */ public class ServiceJsonDataTree { String id; String uuid; SalsaEntityState state; Map<String, String> properties; Object monitoring; public Object getMonitoring() { return monitoring; } public void setMonitoring(Object monitoring) { this.monitoring = monitoring; } List<ServiceJsonDataTree> children; boolean isAbstract = true; // true: tosca node, false: instance node String nodeType; String artifactType; List<String> connectto = new ArrayList<>(); static Logger logger; static { logger = Logger.getLogger("SalsaCenterLogger"); } public ServiceJsonDataTree() { } ; public ServiceJsonDataTree(String id) { this.id = id; } public ServiceJsonDataTree(int id) { this.id = Integer.toString(id); } public String getId() { return id; } public void setId(String id) { this.id = id; } public Map<String, String> getProperties() { return properties; } public void setProperties(Map<String, String> properties) { this.properties = properties; } public List<ServiceJsonDataTree> getChidren() { return children; } public void setChidren(List<ServiceJsonDataTree> chidren) { this.children = chidren; } public List<String> getConnectto() { return connectto; } public void setConnectto(List<String> connectto) { this.connectto = connectto; } public String getNodeType() { return nodeType; } public void setNodeType(String nodeType) { this.nodeType = nodeType; } public boolean isAbstract() { return isAbstract; } public void setAbstract(boolean isAbstract) { this.isAbstract = isAbstract; } public SalsaEntityState getState() { return state; } public void setState(SalsaEntityState state) { this.state = state; } public String getArtifactType() { return artifactType; } public void setArtifactType(String artifactType) { this.artifactType = artifactType; } public void addChild(ServiceJsonDataTree child) { if (children == null) { children = new ArrayList<>(); } children.add(child); } public void removeChild(ServiceJsonDataTree child) { children.remove(child); } public void removeChild(String id) { for (ServiceJsonDataTree child : children) { if (child.getId().equals(id)) { children.remove(child); } } } public void addProperty(String key, String value) { if (this.properties == null) { this.properties = new HashMap<>(); } this.properties.put(key, value); } // convert ServiceUnit and all it stack public void loadData(ServiceUnit data, int hostOnId, ServiceTopology topo) { //logger.debug("Starting loading abstract node: " + data.getId()); this.id = data.getId(); this.setState(data.getState()); this.isAbstract = true; this.setNodeType(data.getType()); this.connectto = data.getConnecttoId(); this.uuid = data.getUuid().toString(); List<ServiceInstance> instances; if (hostOnId < 0) { instances = data.getInstancesList(); } else { instances = data.getInstanceHostOn(hostOnId); // if load a instance for a abstract, the instance must be on hosted on another instance. } List<ServiceUnit> hostOnCompos = new ArrayList<>(); for (ServiceUnit compo : topo.getComponents()) { if (compo.getHostedId().equals(data.getId())) { // compare ID on TOSCA node hostOnCompos.add(compo); } } // logger.debug("This abstract node has instances: " + instances.size()); // logger.debug("This abstract node host on abstractnode: " + hostOnCompos.size()); // update the list of instance to this "children" for (ServiceInstance instance : instances) { // logger.debug("Work with instance id: " + instance.getInstanceId()); ServiceJsonDataTree oneChild = new ServiceJsonDataTree(instance.getInstanceId()); addChild(oneChild); // get the list of host on this components, which will come after the instances oneChild.loadDataInstance(instance, hostOnCompos, data, topo); } // if there is no instance of a node type, create a fake node of UNDEPLOYMENT and load data if (instances.isEmpty()) { ServiceJsonDataTree oneChild = new ServiceJsonDataTree("x"); addChild(oneChild); ServiceInstance fakeInstance = new ServiceInstance(); fakeInstance.setId(data.getId()); fakeInstance.setState(SalsaEntityState.UNDEPLOYED); fakeInstance.setHostedId_Integer(0); fakeInstance.setInstanceId(0); oneChild.loadDataInstance(fakeInstance, hostOnCompos, data, topo); } } // convert instance. abstractNode is for geting TYPE, knowing how to parse properties public void loadDataInstance(ServiceInstance instance, List<ServiceUnit> hostOnCompos, ServiceUnit abstractNode, ServiceTopology topo) { //logger.debug("Adding instance node id: " + instance.getInstanceId()); this.id = abstractNode.getId() + "_" + Integer.toString(instance.getInstanceId()); this.uuid = instance.getUuid().toString(); this.setState(instance.getState()); this.isAbstract = false; this.setMonitoring(instance.getMonitoring()); if (instance.getCapabilities() != null) { for (SalsaCapaReqString capaStr : instance.getCapabilities().getCapability()) { this.addProperty("Capability[" + capaStr.getId() + "]", capaStr.getValue()); } } this.setNodeType(abstractNode.getType()); //logger.debug("Let check connectto ID "); if (!abstractNode.getConnecttoId().isEmpty()) { // logger.debug("Inside the list "); for (String conId : abstractNode.getConnecttoId()) { // logger.debug("List item: " + conId); this.connectto.add(conId + "_0"); // all instance of this node connect to instance 0 // logger.debug("Add done: " + conId+"_0"); } } // set connectto links // if nodeType=SOFTWARE, change it into artifactType. so if it is os, leave there // if (abstractNode.getArtifactType() != null) { // if (!this.nodeType.equals(SalsaEntityType.OPERATING_SYSTEM.getEntityTypeString())) { // this.nodeType = abstractNode.getArtifactType(); // } // } this.nodeType = abstractNode.getType(); this.artifactType = abstractNode.getArtifactType(); //logger.debug("abstractNode.getType(): " + abstractNode.getType()); SalsaEntityType type = SalsaEntityType.fromString(abstractNode.getType()); //logger.debug("The instance node know it parent type is: " + type); // put properties if (type.equals(SalsaEntityType.OPERATING_SYSTEM) && instance.getProperties() != null) { // logger.debug("Putting property of OS type"); SalsaInstanceDescription_VM props = (SalsaInstanceDescription_VM) instance.getProperties().getAny(); this.setProperties(props.exportToMap()); } else if (type.equals(SalsaEntityType.DOCKER) && instance.getProperties() != null) { // logger.debug("Putting property of OS type"); SalsaInstanceDescription_Docker props = (SalsaInstanceDescription_Docker) instance.getProperties().getAny(); this.setProperties(props.exportToMap()); } else if (type.equals(SalsaEntityType.SERVICE) && instance.getProperties() != null) { SalsaInstanceDescription_SystemProcess props = (SalsaInstanceDescription_SystemProcess) instance.getProperties().getAny(); this.setProperties(props.exportToMap()); } this.addProperty("extra", instance.getExtra()); // TODO: properties for others // recursive components which host on this node // logger.debug("Will recursive by hostOnCompos.size(): " + hostOnCompos.size()); for (ServiceUnit compo : hostOnCompos) { // if there are too much node, just combine to one. // logger.debug(" -- PI123 - Recursiving id: " + compo.getId()); ServiceJsonDataTree newNode = new ServiceJsonDataTree(); newNode.loadData(compo, instance.getInstanceId(), topo); addChild(newNode); } // add one more property to show the reference if need if (abstractNode.getReference() != null) { this.addProperty("reference", abstractNode.getReference() + "/" + instance.getInstanceId()); } } // remove the abstract node, return instance children public List<ServiceJsonDataTree> compactData() { List<ServiceJsonDataTree> cleanChildren = new ArrayList<>(); if (this.children != null) { if (!this.getChidren().isEmpty()) { for (ServiceJsonDataTree child : this.getChidren()) { if (!child.isAbstract) { // && !child.getNodeType().equals(SalsaEntityType.OPERATING_SYSTEM.getEntityTypeString())){ cleanChildren.add(child); } } List<ServiceJsonDataTree> newChildren = new ArrayList<>(); for (ServiceJsonDataTree child : this.getChidren()) { newChildren.addAll(child.compactData()); } this.children.addAll(newChildren); List<ServiceJsonDataTree> toRemove = new ArrayList<>(); for (ServiceJsonDataTree child : this.getChidren()) { if (child.isAbstract && !child.getNodeType().equals("TOPOLOGY")) { // if there is no instance of the abstract node, keep it and put state undeployed. // if (child.getChidren()==null || child.getChidren().isEmpty()){ // child.isAbstract=false; // child.state = SalsaEntityState.UNDEPLOYED; // cleanChildren.add(child); // } else { toRemove.add(child); // } } } this.getChidren().removeAll(toRemove); } } return cleanChildren; } public void reduceLargeNumberOfInstances() { if (this.children == null) { return; } if (this.children.size() < 10) { for (ServiceJsonDataTree child : children) { child.reduceLargeNumberOfInstances(); } return; } ServiceJsonDataTree collective = new ServiceJsonDataTree(); ServiceJsonDataTree firstNode = this.children.get(0); children.add(collective); if (firstNode.getConnectto() != null) { collective.connectto = firstNode.getConnectto(); } collective.id = "Collection_of_" + firstNode.getId(); collective.isAbstract = false; collective.nodeType = "MANY ARTIFACTS"; collective.state = this.state; int total = this.children.size() - 1; Map<SalsaEntityState, Integer> stateCal = new HashMap<SalsaEntityState, Integer>(); for (ServiceJsonDataTree thisnode : children) { if (stateCal.get(thisnode.state) == null) { stateCal.put(thisnode.state, 0); } else { stateCal.put(thisnode.state, stateCal.get(thisnode.state) + 1); } } this.children = new ArrayList<ServiceJsonDataTree>(); children.add(collective); collective.properties = new HashMap<String, String>(); for (Map.Entry<SalsaEntityState, Integer> entry : stateCal.entrySet()) { if (entry.getValue() > 0) { collective.properties.put("Node[" + entry.getKey().toString() + "]", entry.getValue().toString()); } } collective.properties.put("Total number of nodes", total + ""); } }