/*
* Created on Oct 10, 2006 by mschilli
*/
package alma.acs.commandcenter.meta;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import si.ijs.maci.ClientInfo;
import si.ijs.maci.ComponentInfo;
import si.ijs.maci.ContainerInfo;
import com.cosylab.acs.maci.HandleConstants;
public class MaciInfo extends DefaultTreeModel {
// ====================================================================
// Public API
// This is for the benefit of a client like Exec that in some way or
// another analyzes the contents of the MaciInfo. To not force them
// to work closely on our tree node structure, this public API provides
// some logical view onto us.
public List<ContainerInfo> getContainers() {
// grab reference as it is in this very moment, this is atomic.
List<ContainerInfo> current = containers;
List<ContainerInfo> ret = new ArrayList<ContainerInfo>(current);
return ret;
}
public ContainerInfo getContainer (String name) {
// grab reference as it is in this very moment, this is atomic.
List<ContainerInfo> current = containers;
for (ContainerInfo info : current)
if (info.name.equals(name))
return info;
return null;
}
public ContainerInfo getContainer (int handle) {
// grab reference as it is in this very moment, this is atomic.
List<ContainerInfo> current = containers;
for (ContainerInfo info : current)
if (info.h == handle)
return info;
return null;
}
public List<ClientInfo> getClients() {
// grab reference as it is in this very moment, this is atomic.
List<ClientInfo> current = clientApps;
List<ClientInfo> ret = new ArrayList<ClientInfo>(current);
return ret;
}
public ClientInfo getClient (String name) {
// grab reference as it is in this very moment, this is atomic.
List<ClientInfo> current = clientApps;
for (ClientInfo info : current)
if (info.name.equals(name))
return info;
return null;
}
public ClientInfo getClient (int handle) {
// grab reference as it is in this very moment, this is atomic.
List<ClientInfo> current = clientApps;
for (ClientInfo info : current)
if (info.h == handle)
return info;
return null;
}
public List<ComponentInfo> getComponents () {
// grab reference as it is in this very moment, this is atomic.
List<ComponentInfo> current = components;
List<ComponentInfo> ret = new ArrayList<ComponentInfo>(current);
return ret;
}
public ComponentInfo getComponent (String name) {
// grab reference as it is in this very moment, this is atomic.
List<ComponentInfo> current = components;
for (ComponentInfo info : current)
if (info.name.equals(name))
return info;
return null;
}
public ComponentInfo getComponent (int handle) {
// grab reference as it is in this very moment, this is atomic.
List<ComponentInfo> current = components;
for (ComponentInfo info : current)
if (info.h == handle)
return info;
return null;
}
public List<ComponentInfo> getStartedComponents () {
// grab reference as it is in this very moment, this is atomic.
List<ComponentInfo> current = components;
List<ComponentInfo> ret = new ArrayList<ComponentInfo>(current.size());
for (ComponentInfo info : current)
if (info.h != 0) // skip non-activated components
ret.add(info);
return ret;
}
// when new data comes in, each of these references is rewritten,
// which is atomic per se and will trigger a memory flush.
volatile List<ComponentInfo> components = Collections.EMPTY_LIST;
volatile List<ContainerInfo> containers = Collections.EMPTY_LIST;
volatile List<ClientInfo> clientApps = Collections.EMPTY_LIST;
// ====================================================================
// Not-so-public API
// These are the portions used by the MaciSupervisor to construct the
// MaciInfo, and by commandcenter's DeploymentTree to present it.
protected MaciInfo () {
super(null);
root = managerNode = createNode("Manager");
managerNode.add(containerNode = createNode(new FolderInfo("Containers")));
managerNode.add(clientNode = createNode(new FolderInfo("Client Applications")));
managerNode.add(componentNode = createNode(new FolderInfo("Components")));
}
protected final SortingTreeNode managerNode;
protected final SortingTreeNode containerNode;
protected final SortingTreeNode clientNode;
protected final SortingTreeNode componentNode;
/**
* Sets the components, containers, and clients.
* The given lists must not be changed anymore (otherwise
* this method would have to make a copy of them).
*/
protected void setContents (
List<ComponentInfo> newComponents,
List<ContainerInfo> newContainers,
List<ClientInfo> newClientApps,
Map<Object,String> auxiliary) {
// bend references, each assignment is atomic and triggers a flush.
// note we shall not modify the lists anymore after this point!
this.components = newComponents;
this.containers = newContainers;
this.clientApps = newClientApps;
// re-populate the toplevel nodes
// ---------------------------------------------
componentNode.removeAllChildren();
for (ComponentInfo comp : newComponents) {
SortingTreeNode n = createNode(comp);
addInfoNodes(n, auxiliary);
componentNode.add(n);
}
containerNode.removeAllChildren();
for (ContainerInfo cont : newContainers) {
SortingTreeNode n = createNode(cont);
addInfoNodes(n, auxiliary);
// attach components that are active in this container
for (ComponentInfo comp : newComponents) {
if (comp.container == cont.h && comp.h != 0)
n.add(createNode(comp));
}
containerNode.add(n);
}
clientNode.removeAllChildren();
for (ClientInfo client : newClientApps) {
SortingTreeNode n = createNode(client);
addInfoNodes(n, auxiliary);
clientNode.add(n);
}
// we sort - for some great user experience
componentNode.sortChildrenByName();
containerNode.sortChildrenByName();
clientNode.sortChildrenByName();
// send out change event
nodeStructureChanged(managerNode);
}
/**
* Factory method
*/
protected SortingTreeNode createNode (Object info) {
SortingTreeNode ret = new SortingTreeNode();
if (info instanceof ContainerInfo) {
ret.setUserObject(info);
ContainerInfo casted = (ContainerInfo) info;
if (casted.h != 0)
ret.representedHandles = new int[]{casted.h};
} else
if (info instanceof ClientInfo) {
ret.setUserObject(info);
ClientInfo casted = (ClientInfo) info;
if (casted.h != 0)
ret.representedHandles = new int[]{casted.h};
} else
if (info instanceof ComponentInfo) {
ret.setUserObject(info);
ComponentInfo casted = (ComponentInfo) info;
if (casted.h != 0)
ret.representedHandles = new int[]{casted.h};
} else
if (info instanceof InfoDetail) {
InfoDetail casted = (InfoDetail) info;
ret.setUserObject(info);
ret.representedHandles = casted.representedHandles;
} else
if (info instanceof FolderInfo) {
ret.setUserObject(info);
} else {
ret.setUserObject(info);
/* when a component is configured as "autostart", it will have
* the manager as its first client.
* matej email 2009-04: there is no way to retrieve the handle
* of the manager... but it is always fixed. */
if ("Manager".equals(info)) // = 83886080
ret.representedHandles = new int[]{HandleConstants.MANAGER_MASK};
}
return ret;
}
protected void addInfoNodes (SortingTreeNode node, Map<Object,String> auxiliary) {
Object info = node.getUserObject();
int infokey = System.identityHashCode(info);
if (info instanceof ContainerInfo) {
//ContainerInfo casted = (ContainerInfo)info;
node.add(createNode(new InfoDetail("location", auxiliary.get(infokey+".location") )));
} else
if (info instanceof ClientInfo) {
ClientInfo casted = (ClientInfo)info;
node.add(createNode(new InfoDetail("location", auxiliary.get(infokey+".location") )));
node.add(createNode(new InfoDetail("components", casted.components, true)));
node.add(createNode(new InfoDetail("access", casted.access, false)));
node.add(createNode(new InfoDetail("reference", casted.reference)));
} else
if (info instanceof ComponentInfo) {
ComponentInfo casted = (ComponentInfo)info;
node.add(createNode(new InfoDetail("clients", casted.clients, true)));
node.add(createNode(new InfoDetail("container", casted.container, true)));
node.add(createNode(new InfoDetail("container_name", casted.container_name)));
node.add(createNode(new InfoDetail("access", casted.access, false)));
node.add(createNode(new InfoDetail("reference", casted.reference)));
node.add(createNode(new InfoDetail("interfaces", casted.interfaces)));
node.add(createNode(new InfoDetail("type", casted.type)));
node.add(createNode(new InfoDetail("code", casted.code)));
}
}
// wraps a single piece of info from ComponentInfo,
// each piece is to be shown in its own node.
static public class InfoDetail {
public String key;
public String value;
/**
* Many tree nodes represent
* a) something that has a handle or
* b) something that references other things that have a handle
*/
public int[] representedHandles = new int[]{};
protected InfoDetail(String key, String[] value) {
if (value.length == 0)
this.value = "none";
else {
StringBuffer list = new StringBuffer();
for (int i=0; i<value.length ; i++)
list.append(String.valueOf(value[i])).append(",");
list.setLength(list.length() - ",".length());
this.value = list.toString();
}
this.key = key;
}
protected InfoDetail(String key, int[] value, boolean intRepresentsHandle) {
StringBuffer list = new StringBuffer();
if (value.length == 0)
list.append("none");
else {
for (int i=0; i<value.length ; i++)
list.append(String.valueOf(value[i])).append(",");
list.setLength(list.length() - ",".length());
}
this.key = key;
this.value = list.toString();
if (intRepresentsHandle)
this.representedHandles = value;
}
protected InfoDetail(String key, Object value) {
this.key = key;
this.value = String.valueOf(value);
}
protected InfoDetail(String key, int value, boolean intRepresentsHandle) {
this.key = key;
this.value = String.valueOf(value);
if (intRepresentsHandle && value != 0)
this.representedHandles = new int[]{value};
}
@Override
public String toString() {
return "Detail \""+key+"="+value+"\"";
}
}
/**
* Used as the userobject for the nodes "containers", "client applications", "components"
*/
static public class FolderInfo {
public String name;
public String filter;
public boolean hasFilter() {
return filter!=null && !filter.isEmpty();
}
protected FolderInfo(String name) {
this.name = name;
}
@Override
public String toString() {
return "Folder \""+name+"\"";
}
}
static public class SortingTreeNode extends DefaultMutableTreeNode {
protected SortingTreeNode() {
super();
}
public SortingTreeNode(Object userObject) {
super(userObject);
}
public int[] representedHandles = new int[]{};
public boolean represents (int h) {
for (int i=0; i<representedHandles.length; i++)
if (representedHandles[i] == h) return true;
return false;
}
public boolean filtered;
/**
* Support for guis (deployment tree). This is not a deep-clone. The userobject and
* representedHandles will be the same as in the source node but children and
* parent references will not be cloned.
*/
@Override
public SortingTreeNode clone () {
SortingTreeNode ret = (SortingTreeNode) super.clone();
ret.representedHandles = (this.representedHandles);
return ret;
}
/** Syntactic sugar, for easy iteration over this node's children. */
public Iterable<SortingTreeNode> childrens() {
final Enumeration<?> orig = children();
return new Iterable<SortingTreeNode>() {
@Override public Iterator<SortingTreeNode> iterator () {
return new java.util.Iterator<SortingTreeNode>() {
@Override public boolean hasNext () {return orig.hasMoreElements();}
@Override public SortingTreeNode next () {return (SortingTreeNode)orig.nextElement();}
@Override public void remove () {throw new UnsupportedOperationException();}
};
}
};
}
public void sortChildrenByName () {
if (children != null) {
synchronized (children) {
Collections.sort (children, byName);
}
}
}
// a comparator for names, needed for sorting
static Comparator<Object> byName = new Comparator<Object>(){
public int compare (Object a, Object b) {
String valA = ((SortingTreeNode) a).infoName();
String valB = ((SortingTreeNode) b).infoName();
return valA.compareTo(valB);
}
};
/**
* Read the 'name' value from the contained info struct.
*/
protected String infoName () {
if (userObject instanceof ContainerInfo)
return ((ContainerInfo)userObject).name;
if (userObject instanceof ClientInfo)
return ((ClientInfo)userObject).name;
if (userObject instanceof ComponentInfo)
return ((ComponentInfo)userObject).name;
return "";
}
/** */
public boolean equals (SortingTreeNode other) {
Object otherObject = other.getUserObject();
if (userObject == null || otherObject == null)
return false;
if (userObject.getClass() != otherObject.getClass())
return false;
if (userObject instanceof ContainerInfo)
return ((ContainerInfo)userObject).name.equals( ((ContainerInfo)otherObject).name);
if (userObject instanceof ClientInfo)
return ((ClientInfo)userObject).h == ((ClientInfo)otherObject).h;
if (userObject instanceof ComponentInfo)
return ((ComponentInfo)userObject).name.equals( ((ComponentInfo)otherObject).name);
return false;
}
}
}