samer@0: /* samer@0: * Node.java samer@0: * samer@0: * Copyright (c) 2000, Samer Abdallah, King's College London. samer@0: * All rights reserved. samer@0: * samer@0: * This software is provided AS iS and WITHOUT ANY WARRANTY; samer@0: * without even the implied warranty of MERCHANTABILITY or samer@0: * FITNESS FOR A PARTICULAR PURPOSE. samer@0: * samer@0: * Change history: samer@0: * samer@0: * Removed all references to parent nodes - each node now samer@0: * stores its full name. Uses more memory but simpler in the samer@0: * long run, I think. samer@0: */ samer@0: samer@0: package samer.core; samer@0: import java.util.*; samer@0: samer@0: /** samer@0:

A Node is essentially a path in a hierarchical samer@0: name space. Each node is an independent object. samer@0: A Node can be constructed either with an explicit samer@0: parent Node, or with an absolute path, or as a child samer@0: of the current Node maintained by the current Shell. samer@0: Names are constructed in parts, concatenated with samer@0: dots, eg, samer@0: samer@0: Node A=new Node("top",null); samer@0: Node B=new Node("middle",A); samer@0: Node C=new Node("bottom",B); samer@0: samer@0: Then node A is "top", node B is "top.middle" and node samer@0: C is "top.middle.bottom" samer@0: samer@0:

The top level Environment (see Environment) samer@0: actually uses a nameless top level node: "", so that samer@0: all fully specified node paths begin with ".", eg samer@0: ".antelope.gibbon.firebucket" samer@0: This is so that names that don't start with a samer@0: dot are treated as relative to the current Environment's node. samer@0: */ samer@0: samer@0: public class Node implements java.io.Serializable samer@0: { samer@0: private final String name; samer@0: samer@0: /** Construct new Node with given name as a child of the samer@0: current Environment's base node, ie samer@0: Shell.env().node() samer@0: */ samer@0: public Node(String name) { samer@0: if (name==null || name.equals("")) samer@0: throw new Error("Node with empty name"); samer@0: samer@0: if (isAbsolute(name)) this.name=name; samer@0: else this.name=Shell.env().node().fullNameFor(name); samer@0: } samer@0: samer@0: samer@0: private Node() { name=""; } samer@0: samer@0: /** Construct new Node with given name and parent samer@0: If parent is null, a top level node is created samer@0: */ samer@0: public Node(String name, Node parent) { this.name = parent.fullName()+"."+name; } samer@0: samer@0: /** Returns parent Node, or null if no parent */ samer@0: public Node getParent() { return new Node(name.substring(0,name.lastIndexOf('.'))); } samer@0: public static String lastPart(String str) { return str.substring(1+str.lastIndexOf('.')); } samer@0: public String fullName() { return name; } samer@0: public String shortName() { return lastPart(name); } samer@0: samer@0: /** Return full name of hypothetical Node with given name samer@0: as a child of this Node, ie, this node's full name + "."+ nm. samer@0: */ samer@0: public String fullNameFor(String nm) { return name+"."+nm; } samer@0: samer@0: /** Absolute names start with a . This is only true of the top samer@0: level Node has an empty name! samer@0: */ samer@0: public static boolean isAbsolute(String nm) { return (nm.charAt(0)=='.'); } samer@0: samer@0: /** Returns true if and only if the given name is a child of this one. samer@0: This is trivially true if the given name is relative (ie doesn't start samer@0: with a dot). If it does, then the initial substrings must match. samer@0: */ samer@0: public boolean isSubnode(String nm) { samer@0: if (!isAbsolute(nm)) return true; samer@0: return nm.startsWith(name); samer@0: } samer@0: samer@0: /** Returns the full name of this node. */ samer@0: public String toString() { return name; } samer@0: samer@0: /** Returns a NEW top-level node each time it is called. */ samer@0: public static Node root() { return new Node(); } samer@0: }