/*
* Copyright 2008 the original author or authors.
*
* 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 org.rioproject.tools.ui;
import net.jini.config.Configuration;
import net.jini.core.entry.Entry;
import net.jini.core.lookup.ServiceItem;
import net.jini.id.Uuid;
import org.rioproject.deploy.ServiceBeanInstance;
import org.rioproject.entry.OperationalStringEntry;
import org.rioproject.monitor.ProvisionMonitor;
import org.rioproject.opstring.OperationalString;
import org.rioproject.opstring.OperationalStringManager;
import org.rioproject.opstring.ServiceElement;
import org.rioproject.tools.ui.progresspanel.SingleComponentInfiniteProgress;
import org.rioproject.ui.Util;
import prefuse.Display;
import prefuse.Visualization;
import prefuse.action.ActionList;
import prefuse.action.GroupAction;
import prefuse.action.ItemAction;
import prefuse.action.RepaintAction;
import prefuse.action.animate.ColorAnimator;
import prefuse.action.animate.PolarLocationAnimator;
import prefuse.action.animate.QualityControlAnimator;
import prefuse.action.animate.VisibilityAnimator;
import prefuse.action.assignment.ColorAction;
import prefuse.action.assignment.FontAction;
import prefuse.action.layout.CollapsedSubtreeLayout;
import prefuse.action.layout.Layout;
import prefuse.action.layout.graph.NodeLinkTreeLayout;
import prefuse.activity.Activity;
import prefuse.activity.SlowInSlowOutPacer;
import prefuse.controls.*;
import prefuse.data.Graph;
import prefuse.data.Node;
import prefuse.data.Schema;
import prefuse.data.Tuple;
import prefuse.data.event.TupleSetListener;
import prefuse.data.expression.Predicate;
import prefuse.data.expression.parser.ExpressionParser;
import prefuse.data.tuple.DefaultTupleSet;
import prefuse.data.tuple.TableNode;
import prefuse.data.tuple.TupleSet;
import prefuse.render.DefaultRendererFactory;
import prefuse.render.EdgeRenderer;
import prefuse.render.LabelRenderer;
import prefuse.render.ShapeRenderer;
import prefuse.util.ColorLib;
import prefuse.util.FontLib;
import prefuse.util.GraphicsLib;
import prefuse.util.PrefuseLib;
import prefuse.util.display.DisplayLib;
import prefuse.visual.DecoratorItem;
import prefuse.visual.VisualItem;
import prefuse.visual.expression.InGroupPredicate;
import prefuse.visual.sort.TreeDepthItemSorter;
import javax.swing.*;
import javax.swing.plaf.basic.BasicToolTipUI;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
/**
* A tree viewer to display the status of deployed OperationalStrings
*
* @author Dennis Reedy
*/
public class GraphView extends Display {
private final Graph g;
private final Node root;
//private SearchTupleSet search;
private static final Schema DECORATOR_SCHEMA = PrefuseLib.getVisualItemSchema();
static {
DECORATOR_SCHEMA.setDefault(VisualItem.INTERACTIVE, false);
DECORATOR_SCHEMA.setDefault(VisualItem.TEXTCOLOR, ColorLib.rgb(255,250,250));
DECORATOR_SCHEMA.setDefault(VisualItem.FONT, FontLib.getFont("Tahoma",12));
}
private final NodeLinkTreeLayout graphLayout;
private final JFrame frame;
private final Visualization vis = m_vis;
private static final Predicate rootFilter = ExpressionParser.predicate("INDEGREE()==0");
private int orientation;
private SingleComponentInfiniteProgress progressPanel;
private final Configuration config;
private final ColorManager colorManager;
private final ProvisionMonitor monitor;
public GraphView(final JFrame frame,
final Configuration config,
final ColorManager colorManager,
final ProvisionMonitor monitor,
final int orientation) {
super(new Visualization());
this.frame = frame;
this.config = config;
this.colorManager = colorManager;
this.monitor = monitor;
this.orientation = orientation;
g = new Graph(true);
g.addColumn(VisualItem.LABEL, String.class);
g.addColumn(Constants.USER_OBJECT, Object.class);
g.addColumn(Constants.STATE, int.class);
addControlListener(new GraphListener(g, frame));
setCustomToolTip(new MultiLineToolTip());
root = g.addNode();
root.set(VisualItem.LABEL, Constants.ROOT);
root.set(Constants.USER_OBJECT, Constants.ROOT);
// -- set up visualization --
vis.add(Constants.TREE, g);
vis.setInteractive(Constants.TREE_EDGES, null, false);
/* Make the root invisible until the system is discovered */
vis.setVisible(Constants.TREE_NODES, null, false);
// -- set up edge renderers --
DefaultRendererFactory drf = new DefaultRendererFactory();
drf.setDefaultRenderer(new CustomShapeRenderer());
drf.add(new InGroupPredicate(Constants.NODE_DECORATORS), new MyLabelRenderer());
drf.add(new InGroupPredicate(Constants.TREE_EDGES), getEdgeTypeRenderer(orientation));
//drf.add(new InGroupPredicate(Constants.TREE_EDGES),
//new EdgeRenderer(prefuse.Constants.EDGE_TYPE_LINE));
// new EdgeRenderer(prefuse.Constants.EDGE_TYPE_CURVE));
vis.setRendererFactory(drf);
vis.addDecorators(Constants.NODE_DECORATORS,
Constants.TREE_NODES,
DECORATOR_SCHEMA);
// -- set up processing actions --
ColorAction nodeStroke = new ColorAction(Constants.TREE_NODES, VisualItem.STROKECOLOR);
nodeStroke.setDefaultColor(ColorManager.BORDER_COLOR_RGB);
nodeStroke.add("_hover", ColorManager.BORDER_COLOR_RGB);
ColorAction nodeFill = new ColorAction(Constants.TREE_NODES, VisualItem.FILLCOLOR);
nodeFill.add("_hover", ColorManager.HOVER_COLOR_RGB);
/* Color predicates */
nodeFill.add(rootFilter, ColorManager.ROOT_COLOR_RGB);
//Predicate okayFilter =
// ExpressionParser.predicate(Constants.STATE+"=="+Constants.ACTIVE+" || " +
// Constants.STATE+"=="+Constants.ACTIVE_NO_SERVICE_ITEM);
Predicate unManagedFilter = ExpressionParser.predicate(Constants.STATE+"=="+Constants.ACTIVE_UNMANAGED);
nodeFill.add(unManagedFilter, ColorLib.color(colorManager.getUnManagedColor()));
Predicate okayFilter = ExpressionParser.predicate(Constants.STATE+"=="+Constants.ACTIVE);
nodeFill.add(okayFilter, ColorLib.color(colorManager.getOkayColor()));
Predicate emptyFilter = ExpressionParser.predicate(Constants.STATE+"=="+Constants.EMPTY);
nodeFill.add(emptyFilter, ColorManager.EMPTY_COLOR_RGB);
Predicate ambiguousFilter = ExpressionParser.predicate(Constants.STATE+"=="+Constants.WARNING);
nodeFill.add(ambiguousFilter, ColorLib.color(colorManager.getWarningColor()));
Predicate noServiceItemFilter = ExpressionParser.predicate("state=="+Constants.ACTIVE_NO_SERVICE_ITEM);
nodeFill.add(noServiceItemFilter, ColorLib.color(colorManager.getWarningColor()));
Predicate failureFilter = ExpressionParser.predicate(Constants.STATE+"=="+Constants.FAILED);
nodeFill.add(failureFilter, ColorLib.color(colorManager.getFailureColor()));
colorManager.setColorAction(nodeFill);
colorManager.setAmbiguousFilter(ambiguousFilter);
colorManager.setFailureFilter(failureFilter);
colorManager.setOkayFilter(okayFilter);
colorManager.setUnManagedFilter(unManagedFilter);
colorManager.setNoServiceItemFilter(noServiceItemFilter);
//ItemAction nodeColor = new NodeColorAction(TREE_NODES);
ItemAction textColor = new TextColorAction(Constants.TREE_NODES);
vis.putAction("textColor", textColor);
ItemAction edgeColor = new ColorAction(Constants.TREE_EDGES,
VisualItem.STROKECOLOR,
ColorManager.EDGE_COLOR_RGB);
FontAction fonts = new FontAction(Constants.TREE_NODES,
FontLib.getFont("Tahoma", 12));
fonts.add("ingroup('_focus_')", FontLib.getFont("Tahoma", 13));
// recolor
ActionList recolor = new ActionList();
//recolor.add(new NodeColorAction());
recolor.add(textColor);
recolor.add(nodeStroke);
recolor.add(nodeFill);
vis.putAction("recolor", recolor);
// repaint
ActionList repaint = new ActionList();
repaint.add(recolor);
repaint.add(new RepaintAction());
vis.putAction("repaint", repaint);
// animate paint change
ActionList animatePaint = new ActionList(400);
animatePaint.add(new ColorAnimator(Constants.TREE_NODES));
animatePaint.add(new RepaintAction());
vis.putAction("animatePaint", animatePaint);
//TreeLayout graphLayout = new RadialTreeLayout(Constants.TREE);
graphLayout = new NodeLinkTreeLayout(Constants.TREE, orientation, 48, 12, 16);
// create the tree layout action
CollapsedSubtreeLayout subLayout = new CollapsedSubtreeLayout(Constants.TREE);
vis.putAction("subLayout", subLayout);
ActionList layout = new ActionList(Activity.INFINITY);
layout.add(graphLayout);
layout.add(subLayout);
layout.add(new LabelPositionLayout(Constants.NODE_DECORATORS));
vis.putAction("graphLayout", layout);
ActionList treeRoot = new ActionList();
treeRoot.add(new TreeRootAction(Constants.TREE));
vis.putAction("treeRoot", treeRoot);
// create the filtering and layout
ActionList filter = new ActionList();
filter.add(treeRoot);
filter.add(fonts);
filter.add(layout);
filter.add(edgeColor);
filter.add(recolor);
vis.putAction("filter", filter);
// animated transition
ActionList animate = new ActionList(1000);
animate.setPacingFunction(new SlowInSlowOutPacer());
animate.add(new QualityControlAnimator());
animate.add(new VisibilityAnimator(Constants.TREE));
animate.add(new PolarLocationAnimator(Constants.TREE_NODES, Constants.LINEAR));
animate.add(new ColorAnimator(Constants.TREE_NODES));
animate.add(new RepaintAction());
vis.putAction("animate", animate);
vis.alwaysRunAfter("filter", "animate");
// initialize the display
setSize(500, 500);
setItemSorter(new TreeDepthItemSorter());
addControlListener(new DragControl());
addControlListener(new ZoomControl());
addControlListener(new PanControl());
addControlListener(new FocusControl(1, "filter"));
addControlListener(new HoverActionControl("repaint"));
//addControlListener(new NeighborHighlightControl("repaint"));
// filter graph and perform layout
vis.run("filter");
// maintain a set of items that should be interpolated linearly
// this isn't absolutely necessary, but makes the animations nicer
// the PolarLocationAnimator should read this set and act accordingly
vis.addFocusGroup(Constants.LINEAR, new DefaultTupleSet());
vis.getGroup(Visualization.FOCUS_ITEMS).addTupleSetListener(
new TupleSetListener() {
public void tupleSetChanged(TupleSet t,
Tuple[] add,
Tuple[] rem) {
TupleSet linearInterp = vis.getGroup(Constants.LINEAR);
if (add.length < 1)
return;
linearInterp.clear();
for (Node n = (Node) add[0]; n != null; n = n.getParent())
linearInterp.addTuple(n);
}
}
);
}
public ColorManager getColorManager() {
return colorManager;
}
/*public void showProgressPanel() {
if(progressPanel==null) {
progressPanel = new SingleComponentInfiniteProgress(false);
GlassPaneContainer.findGlassPaneContainerFor(getParent())
.setGlassPane(progressPanel);
}
String waitMessage = "Waiting to discover the Rio system ...";
try {
waitMessage = (String)config.getEntry(COMPONENT,
"waitMessage",
String.class,
waitMessage);
} catch (ConfigurationException e) {
e.printStackTrace();
}
progressPanel.setText(waitMessage);
progressPanel.start();
}
public void systemDown() {
synchronized(vis) {
vis.cancel("filter");
vis.setVisible(Constants.TREE_NODES, rootFilter, false);
vis.run("filter");
}
showProgressPanel();
}
public void systemUp() {
if(progressPanel!=null) {
progressPanel.stop();
}
synchronized(vis) {
vis.cancel("filter");
vis.setVisible(Constants.TREE_NODES, rootFilter, true);
vis.run("filter");
}
}*/
public void systemUp() {
synchronized(vis) {
vis.cancel("filter");
vis.setVisible(Constants.TREE_NODES, rootFilter, true);
vis.run("filter");
}
}
public void zoomToFit() {
if (!isTranformInProgress()) {
int margin = 20;
long duration = 2000;
Rectangle2D bounds = vis.getBounds(Constants.TREE);
GraphicsLib.expand(bounds, margin + (int)(1/getScale()));
DisplayLib.fitViewToBounds(this, bounds, duration);
}
}
/*public void zoom(final double degree) {
zoom(new Point2D.Float(),degree);
repaint();
}*/
public void setOrientation(final int orientation) {
this.orientation = orientation;
synchronized(vis) {
DefaultRendererFactory drf = new DefaultRendererFactory();
drf.setDefaultRenderer(new CustomShapeRenderer());
drf.add(new InGroupPredicate(Constants.NODE_DECORATORS),
new MyLabelRenderer());
drf.add(new InGroupPredicate(Constants.TREE_EDGES),
getEdgeTypeRenderer(orientation));
vis.setRendererFactory(drf);
vis.cancel("filter");
graphLayout.setOrientation(orientation);
vis.run("filter");
}
}
private prefuse.render.Renderer getEdgeTypeRenderer(final int orientation) {
prefuse.render.Renderer edgeTypeRenderer;
if(orientation==prefuse.Constants.ORIENT_TOP_BOTTOM) {
edgeTypeRenderer = new EdgeRenderer(prefuse.Constants.EDGE_TYPE_LINE);
} else {
edgeTypeRenderer = new EdgeRenderer(prefuse.Constants.EDGE_TYPE_CURVE);
}
return edgeTypeRenderer;
}
public int getOrientation() {
return orientation;
}
/*
* Add an OperationalString
*/
public GraphNode addOpString(final OperationalString opstring) {
if(getOpStringNode(opstring.getName())==null) {
synchronized(vis) {
vis.cancel("filter");
Node opstringNode = g.addNode();
opstringNode.set(VisualItem.LABEL, opstring.getName());
opstringNode.set(Constants.USER_OBJECT,
new GraphNode(monitor,
opstring,
(TableNode)opstringNode));
opstringNode.set(Constants.STATE, Constants.EMPTY);
g.addEdge(root, opstringNode);
//if(parent!=null)
// g.addEdge(parent, opstringNode);
ServiceElement[] services = opstring.getServices();
System.err.println("Adding ["+services.length+"] services for "+opstring.getName());
for(ServiceElement service : services) {
doAddServiceElement(service);
}
vis.run("filter");
}
}
return getOpStringNode(opstring.getName());
}
public ProvisionMonitor getProvisionMonitor() {
return monitor;
}
void removeAllOpStrings() {
GraphNode[] children = GraphUtil.getChildren(g, (TableNode) root);
for(GraphNode child : children) {
removeOpString(child.getOpStringName());
}
//vis.run("filter");
}
void removeOpString(final String name) {
synchronized(vis) {
GraphUtil.removeOpString(g, vis, name);
}
}
void refresh() {
GraphNode[] children = GraphUtil.getChildren(g, (TableNode) root);
for(GraphNode child : children) {
updateOpString(child.getOpString());
}
}
/*
* Update an OperationalString
*/
void updateOpString(final OperationalString opString) {
synchronized(vis) {
vis.cancel("filter");
GraphNode opStringNode = getOpStringNode(opString.getName());
if(opStringNode!=null && !opStringNode.isExternal()) {
OperationalStringManager mgr;
try {
mgr = Util.getOperationalStringManager(monitor, opString.getName());
} catch (Exception e) {
Util.showError(e, frame,
"Could not get an OperationalStringManager");
GraphUtil.removeOpString(g, vis, opString.getName());
vis.run("filter");
return;
}
opStringNode.setOpString(opString);
opStringNode.setProvisionMonitor(monitor);
ServiceElement[] services = opString.getServices();
// TODO: If there are existing ServiceElements that are no longer
// in the opstring they need to be removed
for(ServiceElement service : services) {
GraphNode sElemNode = getServiceElementNode(opStringNode, service);
if(sElemNode!=null) {
sElemNode.setServiceElement(service);
sElemNode.setProvisionMonitor(monitor);
Node serviceNode = sElemNode.getTableNode();
/* Fetch the known ServiceBeanInstances */
ServiceBeanInstance[] instances = new ServiceBeanInstance[0];
try {
instances = mgr.getServiceBeanInstances(service);
} catch (Exception e) {
Util.showError(e, frame, "Fetching ServiceBean Instances");
}
/* If not collapsed, easier to delete the instance
* nodes and re-add them */
if(!(opStringNode.isCollapsed() || sElemNode.isCollapsed())) {
int instanceCount = removeServiceInstances(sElemNode);
for(int i=0; i<instanceCount; i++) {
Node instanceNode =
GraphUtil.addServiceInstance(g,
serviceNode,
opString.getName(),
Constants.AVAILABLE_ID);
GraphNode ign =
(GraphNode)instanceNode.get(Constants.USER_OBJECT);
ign.setProvisionMonitor(monitor);
}
}
for(ServiceBeanInstance instance : instances) {
GraphNode n = getServiceBeanInstance(sElemNode, instance);
if(n!=null) {
n.setInstance(instance);
RequestQueues.write(n, this);
if(n.getTableNode()!=null) {
n.getTableNode().set(Constants.STATE,
Constants.ACTIVE_NO_SERVICE_ITEM);
}
} else {
System.err.println("### updateOpString(): " +
"ServiceBeanInstance node null for " +
"["+service.getName()+"], instanceID=" +
"["+instance.getServiceBeanConfig().getInstanceID()+"]");
}
}
} else {
Node node = GraphUtil.addService(g, opStringNode.getTableNode(), service);
GraphNode sgn = (GraphNode)node.get(Constants.USER_OBJECT);
sgn.setProvisionMonitor(monitor);
}
}
}
vis.run("filter");
}
}
/*
* Get the OperationalString Names
*/
String[] getOpStringNames() {
ArrayList<String> list = new ArrayList<String>();
for(Iterator it=g.neighbors(root); it.hasNext();) {
Tuple t = (Tuple)it.next();
Object o = t.get(Constants.USER_OBJECT);
if(o!=null && o instanceof GraphNode) {
if(((GraphNode)o).getOpString()!=null)
list.add(((GraphNode)o).getOpStringName());
}
}
return(list.toArray(new String[list.size()]));
}
void addServiceElement(final ServiceElement sElem) {
synchronized(vis) {
vis.cancel("filter");
doAddServiceElement(sElem);
vis.run("filter");
}
}
private void doAddServiceElement(final ServiceElement sElem) {
GraphNode opStringNode =
getOpStringNode(sElem.getOperationalStringName());
if(opStringNode!=null) {
GraphNode elemNode = getServiceElementNode(opStringNode, sElem);
if(elemNode == null) {
Node serviceNode = GraphUtil.addService(g, opStringNode.getTableNode(), sElem);
GraphNode sgn =
(GraphNode)serviceNode.get(Constants.USER_OBJECT);
sgn.setProvisionMonitor(monitor);
for(int i=0; i<sElem.getPlanned(); i++) {
doAddServiceBeanInstance(opStringNode.getOpStringName(), serviceNode);
}
setOpStringState(sElem.getOperationalStringName());
}
} else {
System.err.println("Unable to add "+sElem.getName()+", cannot get opstring node "+
sElem.getOperationalStringName());
}
}
private GraphNode doAddServiceBeanInstance(final String opStringName,
final Node serviceNode) {
Node instanceNode = GraphUtil.addServiceInstance(g, serviceNode, opStringName, Constants.AVAILABLE_ID);
GraphNode serviceInstance = (GraphNode)instanceNode.get(Constants.USER_OBJECT);
serviceInstance.setProvisionMonitor(monitor);
return serviceInstance;
}
void removeServiceElement(final ServiceElement elem) {
synchronized(vis) {
vis.cancel("filter");
GraphNode serviceElementNode = getServiceElementNode(elem);
if(serviceElementNode!=null) {
removeServiceInstances(serviceElementNode);
g.removeTuple(serviceElementNode.getTableNode());
setOpStringState(elem.getOperationalStringName());
} else {
System.err.println("Unable to remove service element "+elem.getName()+"ServiceElement node is null");
}
vis.run("filter");
}
}
/*
* Indicate that a service has been terminated or failed
*/
void serviceDown(final ServiceElement sElem, final ServiceBeanInstance instance) {
synchronized(vis) {
GraphNode node = getServiceBeanInstance(sElem, instance);
if(node!=null) {
ServiceElement.ProvisionType pType = sElem.getProvisionType();
if(pType.equals(ServiceElement.ProvisionType.FIXED)) {
GraphNode sElemNode = getServiceElementNode(sElem);
if(sElemNode==null) {
System.err.println("!!! serviceDown(): FIXED service " +
"["+sElem.getName()+"] " +
"instance ["+
instance.getServiceBeanConfig().getInstanceID()+"] " +
"ServiceElement node is null");
return;
}
GraphNode[] children = GraphUtil.getChildren(g, sElemNode.getTableNode());
if(children.length>sElem.getPlanned()) {
vis.cancel("filter");
g.removeTuple(node.getTableNode());
vis.run("filter");
} else {
serviceInstanceDown(sElem, instance, node);
vis.run("repaint");
}
} else {
serviceInstanceDown(sElem, instance, node);
vis.run("repaint");
}
} else {
if (instance != null && instance.getServiceBeanConfig() != null) {
System.err.println("!!! serviceDown(): " +
"["+sElem.getName()+"] " +
"instance ["+
instance.getServiceBeanConfig().getInstanceID()+"] " +
"node is null");
} else {
System.err.println("!!! serviceDown(): ["+sElem.getName()+"] instance [??] node is null");
}
}
}
}
/*
* Indicate that a service instance has been terminated or failed
*/
private void serviceInstanceDown(final ServiceElement sElem,
final ServiceBeanInstance instance,
final GraphNode node) {
node.setInstance(null);
node.setServiceItem(null);
if(node.getTableNode()!=null) {
node.getTableNode().set(Constants.STATE, Constants.FAILED);
} else {
System.err.println("!!! ["+sElem.getName()+"] " +
"instance ["+
instance.getServiceBeanConfig().getInstanceID()+"] " +
"no TableNode");
}
}
/*
* Indicate that a service is active
*/
GraphNode serviceUp(final ServiceElement sElem, final ServiceBeanInstance instance) {
GraphNode node;
synchronized(vis) {
node = getServiceBeanInstance(sElem, instance);
if(node!=null) {
node.setInstance(instance);
if(node.getTableNode()!=null) {
node.getTableNode().set(Constants.STATE,
node.getServiceItem()!=null?
getServiceState(sElem) :
Constants.ACTIVE_NO_SERVICE_ITEM);
}
vis.run("repaint");
} else {
System.err.println("### serviceUp(): " +
"ServiceBeanInstance node null for " +
"["+sElem.getName()+"], instanceID=" +
"["+instance.getServiceBeanConfig().getInstanceID()+"], " +
"create one on the fly");
vis.cancel("filter");
GraphNode sElemNode = getServiceElementNode(sElem);
node = doAddServiceBeanInstance(sElem.getOperationalStringName(),
sElemNode.getTableNode());
node.setInstance(instance);
node.setInstanceID(instance.getServiceBeanConfig().getInstanceID());
if(node.getTableNode()!=null)
node.getTableNode().set(Constants.STATE, getServiceState(sElem));
vis.run("filter");
}
}
return(node);
}
/*
* Increment a service instance
*/
void serviceIncrement(final ServiceElement sElem) {
synchronized(vis) {
vis.cancel("filter");
GraphNode sElemNode = getServiceElementNode(sElem);
GraphUtil.addServiceInstance(g,
sElemNode.getTableNode(),
sElemNode.getOpStringName(),
Constants.AVAILABLE_ID);
vis.run("filter");
}
}
/*
* Decrement a service instance
*/
void serviceDecrement(final ServiceElement sElem, final ServiceBeanInstance instance) {
GraphNode node;
synchronized(vis) {
GraphNode sElemNode = getServiceElementNode(sElem);
sElemNode.setServiceElement(sElem);
node = getServiceBeanInstance(sElem, instance);
if(node!=null) {
vis.cancel("filter");
g.removeTuple(node.getTableNode());
setOpStringState(sElem.getOperationalStringName());
vis.run("filter");
} else {
System.err.println("### serviceDecrement(): " +
"ServiceBeanInstance node null for " +
"["+sElem.getName()+"], instanceID=" +
"["+instance.getServiceBeanConfig().getInstanceID()+"]");
}
}
}
/*
* Set the state of the OperationalString
*/
void setOpStringState(final String name) {
GraphNode opStringNode = getOpStringNode(name);
if (opStringNode != null) {
GraphUtil.setOpStringState(g, opStringNode);
vis.run("repaint");
} else {
System.err.println("Expected to obtain an opstring node for [" + name + "]");
}
}
void setGraphNodeServiceItem(final GraphNode node, final ServiceItem item) {
if(item!=null && node !=null) {
node.setServiceItem(item);
if(node.getTableNode()!=null) {
node.getTableNode().set(Constants.STATE, getServiceState(item));
setOpStringState(node.opStringName);
}
}
}
private int getServiceState(ServiceElement service) {
return service.getOperationalStringName().equals(Constants.UNMANAGED)?Constants.ACTIVE_UNMANAGED:Constants.ACTIVE;
}
private int getServiceState(ServiceItem item) {
int state = Constants.ACTIVE_UNMANAGED;
for(Entry e : item.attributeSets) {
if(e instanceof OperationalStringEntry) {
state = Constants.ACTIVE;
break;
}
}
return state;
}
/*
* Get the GraphNode for a ServiceBeanInstance
*/
GraphNode getServiceBeanInstance(final ServiceElement sElem, final ServiceBeanInstance instance) {
GraphNode instanceNode = null;
GraphNode sElemNode = getServiceElementNode(sElem);
if(sElemNode!=null) {
instanceNode = getServiceBeanInstance(sElemNode, instance);
}
return(instanceNode);
}
/*
* Get the GraphNode for a ServiceBeanInstance
*/
GraphNode getServiceBeanInstance(final GraphNode sElemNode, final ServiceBeanInstance instance) {
GraphNode instanceNode = null;
GraphNode[] instances = new GraphNode[0];
if(sElemNode.getCollapsedVertex()!=null) {
GraphListener.CollapsedServiceElement elem =
(GraphListener.CollapsedServiceElement)
sElemNode.getCollapsedVertex();
instances = elem.getInstances();
} else {
if(sElemNode.getTableNode()!=null)
instances = GraphUtil.getChildren(g, sElemNode.getTableNode());
}
for(GraphNode node : instances) {
if(instance != null &&
node.isServiceInstance() &&
instance.getServiceBeanConfig() != null &&
instance.getServiceBeanConfig().getInstanceID() == node.instanceID) {
instanceNode = node;
break;
}
}
/* Look for available nodes */
if(instanceNode==null) {
for(GraphNode node : instances) {
if(node.getInstanceID()==Constants.AVAILABLE_ID &&
node.isServiceInstance() &&
instance != null) {
node.setInstanceID(instance.getServiceBeanConfig().getInstanceID());
node.setInstance(instance);
instanceNode = node;
break;
}
}
}
return(instanceNode);
}
/*
* Get the GraphNode for a ServiceBeanInstance
*/
GraphNode getServiceBeanInstance(final GraphNode sElemNode, final Uuid uuid) {
GraphNode instanceNode = null;
GraphNode[] instances = new GraphNode[0];
if(sElemNode.getCollapsedVertex()!=null) {
GraphListener.CollapsedServiceElement elem =
(GraphListener.CollapsedServiceElement)
sElemNode.getCollapsedVertex();
instances = elem.getInstances();
} else {
if(sElemNode.getTableNode()!=null)
instances = GraphUtil.getChildren(g, sElemNode.getTableNode());
}
for(GraphNode node : instances) {
if(node.getInstance()==null)
continue;
if(uuid.equals(node.getInstance().getServiceBeanID())) {
instanceNode = node;
break;
}
}
return(instanceNode);
}
/*
* Get the TableNode for a ServiceElement
*/
GraphNode getServiceElementNode(final ServiceElement sElem) {
GraphNode sElemNode = null;
GraphNode opStringNode = getOpStringNode(sElem.getOperationalStringName());
if(opStringNode!=null) {
sElemNode = getServiceElementNode(opStringNode, sElem);
} else {
System.err.println("### getServiceElementNode: OpString node null for ["+sElem.getOperationalStringName()+"]");
}
return(sElemNode);
}
/*
* Get the TableNode for a ServiceElement
*/
GraphNode getServiceElementNode(final GraphNode opStringNode, final ServiceElement sElem) {
GraphNode sElemNode = null;
GraphNode[] nodes;
if(opStringNode.isCollapsed()) {
ArrayList<GraphNode> list = new ArrayList<GraphNode>();
GraphListener.CollapsedOpString collapsed =
(GraphListener.CollapsedOpString)opStringNode.getCollapsedVertex();
GraphListener.CollapsedServiceElement[] elems = collapsed.getInstances();
for(GraphListener.CollapsedServiceElement elem : elems) {
list.add(elem.getServiceElementNode());
}
nodes = list.toArray(new GraphNode[list.size()]);
} else {
nodes = GraphUtil.getChildren(g, opStringNode.getTableNode());
}
for(GraphNode node : nodes) {
if(node.getServiceElement().getName().equals(sElem.getName())) {
sElemNode = node;
break;
}
}
return(sElemNode);
}
/*
* Get an OperationalString GraphNode
*/
GraphNode getOpStringNode(final String name) {
GraphNode opStringNode = null;
for(Iterator it=g.neighbors(root); it.hasNext();) {
Tuple t = (Tuple)it.next();
Object o = t.get(Constants.USER_OBJECT);
if(o!=null && o instanceof GraphNode) {
GraphNode node = (GraphNode)o;
if(node.getOpString()!=null &&
node.getOpStringName().equals(name)) {
opStringNode = node;
break;
}
}
}
return(opStringNode);
}
/*
* Remove a ServiceElement's instances
*/
int removeServiceInstances(final GraphNode node) {
ArrayList<GraphNode> list = new ArrayList<GraphNode>();
for (Iterator it = g.outNeighbors(node.getTableNode()); it.hasNext();) {
Tuple t = (Tuple) it.next();
Object o = t.get(Constants.USER_OBJECT);
if (o != null && o instanceof GraphNode) {
GraphNode g = (GraphNode) o;
if (node.isServiceElement() && g.isOpString())
continue;
list.add(g);
}
}
GraphNode[] gNodes = list.toArray(new GraphNode[list.size()]);
for (GraphNode gNode : gNodes) {
g.removeTuple(gNode.getTableNode());
}
return gNodes.length;
}
/**
* Switch the root of the tree by requesting a new spanning tree at the
* desired root
*/
class TreeRootAction extends GroupAction {
public TreeRootAction(final String graphGroup) {
super(graphGroup);
}
public void run(final double frac) {
TupleSet focus = vis.getGroup(Visualization.FOCUS_ITEMS);
if (focus == null || focus.getTupleCount() == 0)
return;
Graph g = (Graph) vis.getGroup(m_group);
Node f = null;
Iterator tuples = focus.tuples();
while (tuples.hasNext() &&
!g.containsTuple(f=(Node)tuples.next())) {
f = null;
}
if (f == null) {
return;
}
Object uo = f.get(Constants.USER_OBJECT);
if(uo!=null && uo instanceof GraphNode) {
GraphNode node = (GraphNode)uo;
if(node.isServiceInstance())
return;
}
g.getSpanningTree(f);
}
}
/**
* Set node label colors
*/
class TextColorAction extends ColorAction {
public TextColorAction(final String group) {
super(group, VisualItem.TEXTCOLOR, ColorLib.gray(0));
add("_hover", ColorLib.rgb(255, 250, 250));
}
}
/**
* Set node label labels
*/
class MyLabelRenderer extends LabelRenderer {
public String getText(final VisualItem vi) {
if(vi.getRow()==-1)
return("");
Object o = vi.get(Constants.USER_OBJECT);
String name="";
if(o==null) {
name = vi.getString(VisualItem.LABEL);
} else if(o instanceof GraphNode) {
GraphNode node = (GraphNode)o;
if(node.getOpString()!=null) {
name = checkNameLength(node.getOpStringName(), 10);
} else if(node.getServiceElement()!=null) {
name = node.getServiceElement().getName();
}
} else {
if(vi.getString(VisualItem.LABEL)==null) {
name = o.getClass().getName();
} else {
name = vi.getString(VisualItem.LABEL);
if(name.equals(Constants.ROOT))
name = "";
}
}
/*
String[] result = name.split("\\s");
StringBuffer sb = new StringBuffer();
for(int i=0; i<result.length; i++) {
if(i>0)
sb.append("\n");
sb.append(result[i]);
}
return sb.toString();
*/
return name;
}
}
/**
* Renders shapes for the graph
*/
class CustomShapeRenderer extends ShapeRenderer {
private final Rectangle2D frame = new Rectangle2D.Double();
private final RoundRectangle2D theRoundRectangle = new RoundRectangle2D.Float();
private final GeneralPath thePolygon = new GeneralPath();
protected Shape getRawShape(final VisualItem item) {
Shape shape;
if(item.getRow()==-1 || item.getSourceTuple().getRow()==-1) {
return(null);
}
double x = item.getX();
if ( Double.isNaN(x) || Double.isInfinite(x) )
x = 0;
double y = item.getY();
if ( Double.isNaN(y) || Double.isInfinite(y) )
y = 0;
double width = getBaseSize()*item.getSize();
// Center the shape around the specified x and y
if (width > 1 ) {
x = x-width/2;
y = y-width/2;
}
Object uo = item.get(Constants.USER_OBJECT);
if(uo!=null) {
if(uo.equals(Constants.ROOT)) {
width = 20*item.getSize();
shape = diamond((float)x, (float)y, (float)width);
} else if(uo instanceof GraphNode) {
GraphNode node = (GraphNode)uo;
if(node.isServiceInstance()) {
width = 20*item.getSize();
shape = ellipse(x, y, width, width);
} else {
String name;
if(node.getOpString()!=null) {
name = checkNameLength(node.getOpStringName(), 10);
} else {
name = node.getServiceElement().getName();
}
width = DEFAULT_GRAPHICS.getFontMetrics().stringWidth(name);
x = item.getX()-width/2;
int height = DEFAULT_GRAPHICS.getFontMetrics().getHeight();
if(node.isCollapsed()) {
shape = getCollapsedShape((float)x,
(float)y,
(float)width,
(float)height);
} else {
frame.setFrame(x, y, width, height);
float arc_size =
(float)Math.min(frame.getHeight(), frame.getWidth()) / 2;
theRoundRectangle.setRoundRect(frame.getX(),
frame.getY(),
frame.getWidth(),
frame.getHeight(),
arc_size,
arc_size);
shape = theRoundRectangle;
}
}
} else {
shape = super.getRawShape(item);
}
} else {
shape = super.getRawShape(item);
}
return(shape);
}
/*
* Returns a hexagon shape of the given dimensions.
*/
private Shape getCollapsedShape(final float x, final float y, final float width, final float height) {
thePolygon.reset();
thePolygon.moveTo(x, y);
thePolygon.lineTo(x+width, y);
thePolygon.lineTo(x+1.15f*width, y+0.5f*height);
thePolygon.lineTo(x+width, y+height);
thePolygon.lineTo(x, y+height);
thePolygon.closePath();
return thePolygon;
}
}
private String checkNameLength(String s, int maxLength) {
String name;
if(s.length()>maxLength) {
StringBuilder sb = new StringBuilder();
int l = s.length();
sb.append(s.substring(0, 3))
.append("...")
.append(s.substring(l-3, l));
name = sb.toString();
} else {
name = s;
}
return name;
}
/**
* Set label positions. Labels are assumed to be DecoratorItem instances,
* decorating their respective nodes. The layout simply gets the bounds
* of the decorated node and assigns the label coordinates to the center
* of those bounds.
*/
class LabelPositionLayout extends Layout {
public LabelPositionLayout(final String group) {
super(group);
}
public void run(final double frac) {
Iterator iter = vis.items(m_group);
while (iter.hasNext() ) {
DecoratorItem decorator = (DecoratorItem)iter.next();
if(decorator.getRow()==-1)
continue;
try {
if(decorator.isValid()) {
VisualItem decoratedItem = decorator.getDecoratedItem();
Rectangle2D bounds = decoratedItem.getBounds();
double x = bounds.getCenterX();
double y = bounds.getCenterY();
setX(decorator, null, x);
setY(decorator, null, y);
}
} catch(IllegalArgumentException e) {
e.printStackTrace();
}
}
}
}
public static class MultiLineToolTip extends JToolTip {
public MultiLineToolTip() {
setUI(new MultiLineToolTipUI());
}
}
public static class MultiLineToolTipUI extends BasicToolTipUI {
private String[] strs;
public void paint(final Graphics g, final JComponent c) {
FontMetrics metrics = g.getFontMetrics();
Dimension size = c.getSize();
g.setColor(c.getBackground());
g.fillRect(0, 0, size.width, size.height);
g.setColor(c.getForeground());
if (strs != null) {
for (int i = 0; i < strs.length; i++) {
g.drawString(strs[i], 3, (metrics.getHeight()) * (i + 1));
}
}
}
public Dimension getPreferredSize(final JComponent c) {
FontMetrics metrics = c.getFontMetrics(c.getFont());
String tipText = ((JToolTip) c).getTipText();
if (tipText == null) {
tipText = "";
}
BufferedReader br = new BufferedReader(new StringReader(tipText));
String line;
int maxWidth = 0;
Vector<String> v = new Vector<String>();
try {
while ((line = br.readLine()) != null) {
int width = SwingUtilities.computeStringWidth(metrics, line);
maxWidth = (maxWidth < width) ? width : maxWidth;
v.addElement(line);
}
} catch (IOException ex) {
ex.printStackTrace();
}
int lines = v.size();
if (lines < 1) {
strs = null;
lines = 1;
} else {
strs = new String[lines];
int i = 0;
for (Enumeration e = v.elements(); e.hasMoreElements(); i++) {
strs[i] = (String) e.nextElement();
}
}
int height = metrics.getHeight() * lines;
return new Dimension(maxWidth + 6, height + 4);
}
}
}