/* * Lokomo OneCMDB - An Open Source Software for Configuration * Management of Datacenter Resources * * Copyright (C) 2006 Lokomo Systems AB * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. * * Lokomo Systems AB can be contacted via e-mail: info@lokomo.com or via * paper mail: Lokomo Systems AB, Sv�rdv�gen 27, SE-182 33 * Danderyd, Sweden. * */ package org.onecmdb.rest.graph.model.prefuse; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.onecmdb.core.internal.storage.hibernate.PageInfo; import org.onecmdb.core.utils.bean.AttributeBean; import org.onecmdb.core.utils.bean.CiBean; import org.onecmdb.core.utils.bean.ValueBean; import org.onecmdb.core.utils.graph.query.GraphQuery; import org.onecmdb.core.utils.graph.query.constraint.AttributeValueConstraint; import org.onecmdb.core.utils.graph.query.constraint.ItemConstraint; import org.onecmdb.core.utils.graph.query.constraint.ItemOrGroupConstraint; import org.onecmdb.core.utils.graph.query.constraint.ItemSecurityConstraint; import org.onecmdb.core.utils.graph.query.selector.ItemAliasSelector; import org.onecmdb.core.utils.graph.query.selector.ItemOffspringSelector; import org.onecmdb.core.utils.graph.query.selector.ItemRelationSelector; import org.onecmdb.core.utils.graph.query.selector.ItemSelector; import org.onecmdb.core.utils.graph.result.Graph; import org.onecmdb.core.utils.graph.result.Template; import org.onecmdb.rest.graph.io.OneCMDBConnection; import prefuse.data.Edge; import prefuse.data.Node; import prefuse.data.Tuple; import prefuse.visual.VisualItem; public class InstanceGraphControl { GraphQuery q = new GraphQuery(); prefuse.data.Graph g = new prefuse.data.Graph(true); private Graph result; private boolean excludeRelation = true; private prefuse.data.Graph queryGraph = new prefuse.data.Graph(true); private HashMap<String, Node> queryGraphNodeMap = new HashMap<String, Node>(); private Integer maxSize = 100; private String group; private HashMap<String, Boolean> visualMap = new HashMap<String, Boolean>(); private HashMap<String, Aggregate> aggregateMap = new HashMap<String, Aggregate>(); private HashMap<String, Node> nodeMap = new HashMap<String, Node>(); private HashMap<String, String> searchMap = new HashMap<String, String>(); private long loadTime; class Aggregate { HashSet<String> members = new HashSet<String>(); public Aggregate() { super(); } public void addMember(String m) { members.add(m); } public Set<String> getMembers() { return(members); } public String getId() { return("Aggr-" + this.hashCode()); } } public InstanceGraphControl() { // Add Model g.addColumn("alias", String.class); g.addColumn("type", String.class); g.addColumn("mark", Boolean.class); g.addColumn("name", String.class); g.addColumn("aggregate", boolean.class); // On Edge g.addColumn("springCoefficient", float.class); g.addColumn("springLength", float.class); g.addColumn("visible", boolean.class); // On Node g.addColumn("massValue", float.class); g.addColumn("image", String.class); // Add Model queryGraph.addColumn("alias", String.class); queryGraph.addColumn("type", String.class); queryGraph.addColumn("mark", Boolean.class); queryGraph.addColumn("name", String.class); queryGraph.addColumn("id", String.class); queryGraph.addColumn("image", String.class); } public prefuse.data.Graph getGraph() { return(g); } protected ItemSelector addItem(String id, String alias, boolean primary, boolean instance) { ItemSelector selector = q.findSelector(id); if (selector == null) { if (instance) { selector = new ItemAliasSelector(id, "Root"); ((ItemAliasSelector)selector).setAlias(alias); } else { selector = new ItemOffspringSelector(id, alias); ((ItemOffspringSelector)selector).setMatchTemplate(Boolean.FALSE); ((ItemOffspringSelector)selector).setLimitToChild(false); } selector.setPrimary(primary); q.addSelector(selector); // Update query Graph. //CiBean template = OneCMDBConnection.instance().getBeanFromAlias(alias); Node n = queryGraph.addNode(); n.setString("id",id); n.setString("name", alias); n.setString("alias", alias); queryGraphNodeMap.put(id, n); } return(selector); } private ItemConstraint getSecurityConstraint() { if (group == null || group.length() == 0) { return(null); } String groups[] = group.split("\\|"); if (groups.length == 1) { ItemSecurityConstraint security = new ItemSecurityConstraint(); security.setGroupName(this.group); return(security); } ItemOrGroupConstraint or = new ItemOrGroupConstraint(); for (int i = 0; i < groups.length; i++) { ItemSecurityConstraint security = new ItemSecurityConstraint(); security.setGroupName(groups[i]); or.add(security); } return(or); } public void setSecurityGroup(String alias) { this.group = alias; } public boolean removeItem(String id) { ItemSelector selector = q.findSelector(id); if (selector == null) { return(false); } // Update Graph. if (selector instanceof ItemRelationSelector) { Iterator iter = queryGraph.edges(); while (iter.hasNext()) { Edge e = (Edge)iter.next(); if (e.getString("id").equals(id)) { queryGraph.removeEdge(e); } } } else { Iterator iter = queryGraph.nodes(); while (iter.hasNext()) { Node n = (Node)iter.next(); if (n.getString("id").equals(id)) { queryGraph.removeNode(n); } } queryGraphNodeMap.remove(id); } // Remove Selector, will also remove reference selectors. return(q.removeSelector(selector)); } public void setRoot(String template, String instanceAlias, boolean primary, boolean visable) { if (instanceAlias == null) { addNode(template, primary, visable); } else { addItem(instanceAlias, instanceAlias, primary, true); visualMap.put(instanceAlias, visable); System.out.println("AddInstance alias=" + instanceAlias + ", visable=" + visable); } } public void addNode(String alias, boolean primary, boolean visable) { addItem(alias, alias, primary, false); visualMap.put(alias, visable); System.out.println("AddNode alias=" + alias + ", visable=" + visable); } public void removeNode(String alias) { removeItem(alias); /* // Remove all relations. List<ItemRelationSelector> rels = new ArrayList<ItemRelationSelector>(q.fetchRelationSelectors()); for (ItemRelationSelector rel : rels) { if (rel.getSource().equals(alias)) { q.removeSelector(rel); } if (rel.getTarget().equals(alias)) { q.removeSelector(rel); } } */ } public ItemRelationSelector addRelation(String sourceId, String refType, String targetId) { String relId = sourceId + "2" + targetId; ItemSelector source = q.findSelector(sourceId); if (source == null) { throw new IllegalArgumentException("Source " + sourceId +" item is missing"); } ItemSelector target = q.findSelector(targetId); if (target == null) { throw new IllegalArgumentException("target " + sourceId +" item is missing"); } ItemSelector relation = q.findSelector(relId); if (relation == null) { relation = new ItemRelationSelector(relId, refType, target.getId(), source.getId()); q.addSelector(relation); if (excludeRelation) { ((ItemRelationSelector)relation).setMandatory(false); } // Add relation... Node sNode = queryGraphNodeMap.get(sourceId); Node tNode = queryGraphNodeMap.get(targetId); if (sNode != null && tNode != null) { Edge e = queryGraph.addEdge(sNode, tNode); e.setString("alias", refType); e.setString("id", relId); } } return((ItemRelationSelector)relation); } public boolean removeRelation(String sourceId, String refType, String targetId) { String relId = sourceId + "2" + targetId; ItemSelector relation = q.findSelector(relId); if (relation != null) { q.removeSelector(relation); return(true); } return(false); } public void update() { // Update security constraint. ItemConstraint security = getSecurityConstraint(); List<ItemSelector> sels = q.fetchSelectors(); if (sels != null) { for (ItemSelector sel : sels) { if (sel instanceof ItemRelationSelector) { ItemRelationSelector rel = (ItemRelationSelector)sel; rel.setMandatory(!excludeRelation); } if (sel.isPrimary()) { sel.applyConstraint(security); } String search = searchMap.get(sel.getId()); if (search == null || search.length() == 0) { sel.applyConstraint(null); } else { AttributeValueConstraint aCon = getValueConstrain(search); sel.applyConstraint(aCon); } sel.setPageInfo(new PageInfo(0, maxSize )); } } loadTime = 0; if (sels != null && sels.size() > 0) { if (q.fetchPrimarySelectors() == null) { q.fetchSelectors().get(0).setPrimary(true); } long start = System.currentTimeMillis(); result = OneCMDBConnection.instance().query(q); long stop = System.currentTimeMillis(); loadTime = stop-start; System.out.println(result.toString()); result.buildMap(); } else { result = new Graph(); result.buildMap(); } } public void queryCMDB(GraphQuery q) { long start = System.currentTimeMillis(); result = OneCMDBConnection.instance().query(q); long stop = System.currentTimeMillis(); loadTime = stop-start; System.out.println(result.toString()); result.buildMap(); } private AttributeValueConstraint getValueConstrain(String search) { String alias = null; int op = AttributeValueConstraint.LIKE; search = search.trim(); if (search.contains("==")) { String split[] = search.split("=="); alias = split[0]; search = split[1]; } if (search.startsWith("\"") && search.endsWith("\"")) { op = AttributeValueConstraint.EQUALS; search=search.replace('"',' '); search = search.trim(); } else { if (search.contains("*")) { search = search.replace("*", "%"); } else { search = "%" + search + "%"; } } AttributeValueConstraint aCon = new AttributeValueConstraint(); aCon.setOperation(op); aCon.setValue(search); aCon.setAlias(alias); return(aCon); } public Graph getResult() { return(this.result); } public void updateGraph() { HashMap<String, CiBean> nodeBeans = new HashMap<String, CiBean>(); HashMap<String, CiBean> edgeBeans = new HashMap<String, CiBean>(); for (Template t : result.getNodes()) { for (CiBean bean : t.getOffsprings()) { nodeBeans.put(bean.getAlias(), bean); } } for (Template t : result.getEdges()) { for (CiBean bean : t.getOffsprings()) { edgeBeans.put(bean.getAlias(), bean); } } // Syncronize the graph from concurrrent modifications. synchronized(g) { //HashMap<String, Node> nodeMap = new HashMap<String, Node>(); // handle update of nodes. List<Node> removeNode = new ArrayList<Node>(); Iterator nIter = g.getNodes().tuples(); while (nIter.hasNext()) { Object o = nIter.next(); if (o instanceof Tuple) { Tuple t = (Tuple) o; if (t.canGetString("alias")) { String alias = t.getString("alias"); if (result.findOffspringAlias(alias) == null) { System.out.println("Remove Node " + alias); Node n = g.getNode(t.getRow()); System.out.println("\t" + n); removeNode.add(n); nodeMap.remove(alias); } else { //nodeMap.put(alias, g.getNode(t.getRow())); if (nodeBeans.containsKey(alias)) { nodeBeans.remove(alias); } } } } } List<Edge> removeEdge = new ArrayList<Edge>(); Iterator eIter = g.getEdges().tuples(); while (eIter.hasNext()) { Object o = eIter.next(); if (o instanceof Tuple) { Tuple t = (Tuple)o; if (t.canGetString("alias")) { String alias = t.getString("alias"); if (result.findEdgeBean(alias) == null) { System.out.println("Remove Edge " + alias); Edge e = g.getEdge(t.getRow()); System.out.println("\t" + e); removeEdge.add(e); } if (edgeBeans.containsKey(alias)) { edgeBeans.remove(alias); } } } } // Start update the graph // remove first. for (Edge e : removeEdge) { g.removeEdge(e); } for (Node n : removeNode) { g.removeNode(n); } if (false) { // Handle aggregates. for (CiBean bean : edgeBeans.values()) { String sourceAlias = getSource(bean); if (sourceAlias == null) { continue; } String targetAlias = getTarget(bean); if (targetAlias == null) { continue; } CiBean target = result.findOffspringAlias(targetAlias); CiBean source = result.findOffspringAlias(sourceAlias); boolean targetVisible = visualMap.get(target.getDerivedFrom()); boolean sourceVisible = visualMap.get(source.getDerivedFrom()); if (!targetVisible && !sourceVisible) { Aggregate sourceAggregate = getAggregate(sourceAlias); Aggregate targetAggregate = getAggregate(targetAlias); // Create aggregated group. if (sourceAggregate == null && targetAggregate == null) { Aggregate a = new Aggregate(); a.addMember(sourceAlias); a.addMember(targetAlias); aggregateMap.put(sourceAlias, a); aggregateMap.put(targetAlias, a); } else if (sourceAggregate == null && targetAggregate != null) { targetAggregate.addMember(sourceAlias); } else if (sourceAggregate != null && targetAggregate == null) { sourceAggregate.addMember(targetAlias); } else { // Combine aggreagtes. combineAggregate(sourceAggregate, targetAggregate); } } else if (!sourceVisible) { // pointing to aggregate group. Aggregate a = new Aggregate(); a.addMember(sourceAlias); aggregateMap.put(sourceAlias, a); } else if (!targetVisible) { Aggregate a = new Aggregate(); a.addMember(targetAlias); aggregateMap.put(targetAlias, a); } } } // Add all nodes without releations. for (CiBean bean : nodeBeans.values()) { System.out.println("Add Node: " + bean.getAlias()); Node n = addNode(bean); } for (CiBean bean : edgeBeans.values()) { String source = getSource(bean); if (source == null) { continue; } String target = getTarget(bean); if (target == null) { continue; } System.out.println("Add Edge: " + source + "-->" + target); Node sourceNode = addNode(result.findOffspringAlias(source)); Node targetNode = addNode(result.findOffspringAlias(target)); Edge edge = addEdge(sourceNode, bean, targetNode); handleLength(edge, result.findOffspringAlias(source), bean, result.findOffspringAlias(target)); } /* for (CiBean bean : nodeBeans.values()) { Node n = g.addNode(); n.set("alias", bean.getAlias()); n.set("type", bean.getDerivedFrom()); String displayName = bean.getDisplayName(); if (displayName.length() > 20) { displayName = displayName.substring(0, 20) + "..."; } n.set("name", displayName); n.set("image", "http://localhost:8080/icons/generate?iconid=" + getValue(bean, "icon")); nodeMap.put(bean.getAlias(), n); } for (CiBean bean : edgeBeans.values()) { String sourceAlias = getSource(bean); String targetAlias = getTarget(bean); Node source = nodeMap.get(sourceAlias); Node target = nodeMap.get(targetAlias); if (source == null) { continue; } if (target == null) { continue; } Edge e = g.addEdge(source, target); e.set("alias", bean.getAlias()); e.set("type", bean.getDerivedFrom()); e.set("name", bean.getDerivedFrom()); } */ } // End of synchronized graph modification. } private void handleLength(Edge edge, CiBean source, CiBean reference, CiBean target) { /* if (reference.getDerivedFrom().equals("BelongsTo")) { edge.setFloat("springLength", 1); edge.setFloat("springCoefficient", 1e-4f); edge.setBoolean("visible", false); } */ } private void combineAggregate(Aggregate sourceAggregate, Aggregate targetAggregate) { for (String member: targetAggregate.getMembers()) { sourceAggregate.addMember(member); aggregateMap.put(member, sourceAggregate); } } private Aggregate getAggregate(String alias) { Aggregate a = aggregateMap.get(alias); return(a); } private Edge addEdge(Node source, CiBean bean, Node target) { System.out.println("Add Edge: " + source + "-->" + target); Edge e = g.addEdge(source, target); e.set("alias", bean.getAlias()); e.set("type", bean.getDerivedFrom()); e.set("name", bean.getDerivedFrom()); return(e); } private Node addNode(CiBean ci) { Node n = nodeMap.get(ci.getAlias()); if (n != null) { return(n); } Aggregate a = getAggregate(ci.getAlias()); if (a != null) { n = nodeMap.get(a.getId()); if (n != null) { return(n); } n = g.addNode(); n.set("aggregate", true); n.set("name", "Aggregate [" + a.getMembers().size()+ "]"); nodeMap.put(a.getId(), n); return(n); } n = g.addNode(); n.set("alias", ci.getAlias()); n.set("type", ci.getDerivedFrom()); String displayName = ci.getDisplayName(); if (displayName.length() > 20) { displayName = displayName.substring(0, 20) + "..."; } n.set("name", displayName); String icon = ""; if (getValue(ci, "icon") != null) { icon = "&icon=" + getValue(ci, "icon"); } n.set("image", OneCMDBConnection.instance().getIconURL() + "?type=" + ci.getDerivedFrom() + icon); nodeMap.put(ci.getAlias(), n); return(n); } private String getValue(CiBean bean, String alias) { ValueBean vBean = bean.fetchAttributeValueBean(alias, 0); if (vBean == null) { return(null); } if (vBean.hasEmptyValue()) { return(null); } return(vBean.getValue()); } private String getSource(CiBean bean) { return(getValue(bean, "source")); } private String getTarget(CiBean bean) { return(getValue(bean, "target")); } public void setExclude(boolean selected) { this.excludeRelation = selected; } public List<CiBean> graphBeanTemplate() { List<CiBean> beans = new ArrayList<CiBean>(); if (true) { return(beans); } CiBean graph = new CiBean(); graph.setAlias("GraphQuery"); AttributeBean selA = new AttributeBean("Selector(s)", "selector", "ItemSelector", "ComposedOf", true); selA.setMaxOccurs("unbound"); selA.setMinOccurs("0"); graph.addAttribute(selA); beans.add(graph); /* CiBean itemConstraint = new CiBean(); itemConstraint.setAlias("ItemSelector"); itemConstraint.addAttribute(new AttributeBean("template", "xs:string", null, false)); beans.add(itemSelector); */ CiBean itemSelector = new CiBean(); itemSelector.setAlias("ItemSelector"); itemSelector.addAttribute(new AttributeBean("template", "xs:string", null, false)); beans.add(itemSelector); CiBean itemOffspringSelector = new CiBean(); itemOffspringSelector.setDerivedFrom("ItemSelector"); itemOffspringSelector.setAlias("ItemOffspringSelector"); itemOffspringSelector.addAttribute(new AttributeBean("Template", "template", "xs:string", null, false)); beans.add(itemOffspringSelector); CiBean itemRelationSelector = new CiBean(); itemRelationSelector.setAlias("ItemRelationSelector"); itemRelationSelector.setDerivedFrom("ItemSelector"); itemRelationSelector.addAttribute(new AttributeBean("Template", "template", "xs:string", null, false)); itemRelationSelector.addAttribute(new AttributeBean("Source", "source", "ItemSelector", "PointsTo", true)); itemRelationSelector.addAttribute(new AttributeBean("Target", "target", "ItemSelector", "PointsTo", true)); beans.add(itemRelationSelector); return(beans); } public List<CiBean> graphToBean() { List<CiBean> beans = new ArrayList<CiBean>(); CiBean graph = new CiBean(); graph.setAlias("GraphQuery-1"); graph.setDerivedFrom("GraphQuery"); graph.setDisplayName(graph.getAlias()); beans.add(graph); for (ItemSelector sel : q.fetchSelectors()) { CiBean selBean = itemSelectorToBean(sel); if (selBean != null) { beans.add(selBean); graph.addAttributeValue(new ValueBean("selector", selBean.getAlias(), true)); } } return(beans); } private CiBean itemSelectorToBean(ItemSelector sel) { if (sel instanceof ItemOffspringSelector) { CiBean offspringSel = new CiBean(); offspringSel.setAlias("ItemSelector-" + sel.getId()); offspringSel.setDisplayName(sel.getId()); offspringSel.setDerivedFrom("ItemOffspringSelector"); offspringSel.addAttributeValue(new ValueBean("template", sel.getTemplateAlias(), false)); return(offspringSel); } if (sel instanceof ItemRelationSelector) { ItemRelationSelector rel = (ItemRelationSelector)sel; CiBean offspringSel = new CiBean(); offspringSel.setAlias("ItemSelector-" + sel.getId()); offspringSel.setDisplayName(sel.getId()); offspringSel.setDerivedFrom("ItemRelationSelector"); offspringSel.addAttributeValue(new ValueBean("template", sel.getTemplateAlias(), false)); offspringSel.addAttributeValue(new ValueBean("source", "ItemSelector-" + rel.getSource(), true)); offspringSel.addAttributeValue(new ValueBean("target", "ItemSelector-" + rel.getTarget(), true)); return(offspringSel); } return(null); } /** * Return the graph of the query * * @return */ public prefuse.data.Graph getQueryGraph() { return(this.queryGraph); } public void reset() { List<ItemSelector> sels = new ArrayList<ItemSelector>(q.fetchSelectors()); for (ItemSelector sel : sels) { q.removeSelector(sel); } update(); visualMap.clear(); } public String getResultAsHTML() { StringBuffer b = new StringBuffer(); for (Template t : result.getNodes()) { int size = 0; if (t.getOffsprings() != null) { size = t.getOffsprings().size(); } String of = ""; if (t.getTotalCount() != size) { of = " (" + t.getTotalCount() + ")"; } b.append(t.getTemplate().getAlias() + " " + size + of + " instances visible<br>"); } b.append("<b>Total</b> " + result.fetchAllNodeOffsprings().size() + " instances visible (Loaded in " + loadTime + "ms)<br>"); return(b.toString()); } public void setSearch(String id, String text) { searchMap.put(id, text); } public String getSearch(String id) { String search = searchMap.get(id); if (search == null) { return(""); } return(search); } public Integer getMaxSize() { return maxSize; } public void setMaxSize(Integer maxSize) { this.maxSize = maxSize; } }