001    /*
002     * UniqueNodeNamePolicy.java
003     *
004     * Developed for the "Rethinking CS101" project. See http://www.cs101.org, the
005     * CS101 homepage or email las@olin.edu.
006     *
007     * Created on February 20, 2003, 11:54 AM
008     */
009    
010    package nodenet.registrar;
011    
012    import nodenet.Node;
013    
014    import java.beans.PropertyChangeEvent;
015    import java.beans.PropertyVetoException;
016    
017    import java.util.Vector;
018    import java.util.ArrayList;
019    
020    /**
021     * This class is designed to be plugged into {@link NodeNameRegistry}
022     * via the <code>setPolicy(NodeNameRegistrar)</code> method. It enforces
023     * the uniqueness of node names, and provides access to a node via its
024     * textual name.
025     *
026     * @author  Patrick G. Heck, gus.heck@olin.edu
027     * @version $Id: UniqueNodeNamePolicy.java,v 1.8 2004/01/14 21:43:17 gus Exp $
028     */
029    public class UniqueNodeNamePolicy implements NodeNameRegistrar {
030        
031        private static final String NAME_PREFIX = "Node ";
032        private volatile int nodeSerialNum;
033        
034        private Vector nodes = new Vector();
035        
036        /** Creates a new instance of UniqueNodeNamePolicy */
037        public UniqueNodeNamePolicy() {
038        }
039        
040        /* (Copy of original doc. Generated version is inherited)
041         *
042         * Provides a name that is currently legal. The legality of the name is
043         * not guaranteed to remain legal for all time. This is particularly true
044         * if the policy implemented by the <code>Registrar</code> requires names
045         * to be unique. The implementation of this method should make a reasonable
046         * attempt not to give out names that will become illegal quickly, either
047         * due to temporal relevance of the name, or due to copetition between
048         * names given out to the clients. For example, this method should not
049         * give out the same node name on consecutive invocations if uniqueness is
050         * a qualification for legality.
051         *
052         * @returns A name that is currently legal, and should remain legal for a
053         *          reasonable period of time, if possible.
054         */
055        public synchronized String getLegalName() {
056            String temp;
057            do {
058                nodeSerialNum++;
059                temp = NAME_PREFIX + nodeSerialNum;
060            } while (!isUnique(temp));
061            
062            return temp;
063        }
064        
065        
066        /* (Copy of original doc. Generated version is inherited)
067         *
068         * Provides access to nodes via their registred name. This method is
069         * optional, but if it is not implemented it should throw an
070         * <code>UnsupportedOperationException</code> rather than returning
071         * a bogus node or null.
072         *
073         * @param aName   The name of the node to look for.
074         * @return        A reference to the node if found, null otherwise.
075         */
076        public synchronized Node getNode(String aName) throws UnsupportedOperationException {
077            for (int i=0; i<nodes.size(); i++) {
078                Node aNode = ((Node)nodes.get(i));
079                if(aNode.getName().equals(aName)) {
080                    return aNode;
081                }
082            }
083            return null;
084        }
085        
086        /* (Copy of original doc. Generated version is inherited)
087         *
088         * Provides a list of currently registered node names. This method is
089         * optional, but if it is not implemented it should throw an
090         * <code>UnsupportedOperationException</code> rather than returning
091         * a bogus list or null.
092         *
093         * @returns An array of node names currently in use.
094         */
095        public synchronized String[] getRegisteredNames() throws UnsupportedOperationException {
096            String[] temp = new String[nodes.size()];
097            for (int i=0; i<temp.length;i++) {
098                temp[i] = ((Node)nodes.get(i)).getName();
099            }
100            return temp;
101        }
102        
103        /* (Copy of original doc. Generated version is inherited)
104         *
105         * Tests a name to see if it is currently legal. The legality of the name is
106         * not guaranteed to remain invariant for all time. This is particularly
107         * true if the policy implemented by the <code>Registrar</code> requires
108         * names to be unique.
109         *
110         * @param   aName   The node name to be tested.
111         * @returns <code>true</code> if the name is legal, <code>false</code>
112         *          otherwise.
113         */
114        public boolean isLegalName(String aName) {
115            return isUnique(aName);
116        }
117        
118        /* (Copy of original doc. Generated version is inherited)
119         *
120         * Tests to see if a name belongs to a registered node. For obvious reasons
121         * the results of this test are only valid while the client has a lock
122         * on the registry.
123         *
124         * @param The node name to test
125         * @return <code>true</code> if the name is registered <code>false</code>
126         *         otherwise.
127         */
128        public boolean isRegistered(String aName) {
129            String[] names = getRegisteredNames();
130            for (int i=0; i<names.length; i++) {
131                if (names[i].equals(aName)) {
132                    return true;
133                }
134            }
135            return false;
136        }
137        
138        /* (Copy of original doc. Generated version is inherited)
139         *
140         * Tests to see if a node has been registered.
141         *
142         * @param The node to test
143         * @return <code>true</code> if the node is registered <code>false</code>
144         *         otherwise.
145         */
146        public boolean isRegistered(Node aNode) {
147            return isRegistered(aNode.getName());
148        }
149        
150        /* (Copy of original doc. Generated version is inherited)
151         *
152         * Gives the node a legal name and registers the node in one step. This
153         * method guarantees that the node will be registered, and no exceptions
154         * should be thrown. The node to be registered must expose a method
155         * with the signature setName(String).
156         */
157        public synchronized void nameAndRegister(Node aNode) {
158            aNode.setName(getLegalName());
159            this.register(aNode);
160        }
161        
162        /* (Copy of original doc. Generated version is inherited)
163         *
164         * Attempt to register a node. This method proposes to register a node
165         * with an existing name. The node will be rejected if and only if it
166         * contains a name that would currently generate a false response
167         * from {@link #isLegalName(String)}. If the name contained in the node
168         * is rejected, The node is not registered or tracked in any way and an
169         * <code>IllegalArgumentException</code> will be thrown.
170         *
171         * @param aNode The node that wishes to register itself.
172         */
173        public synchronized void register(Node aNode) throws IllegalArgumentException {
174            
175            if (!isUnique(aNode.getName())) {
176                throw new IllegalArgumentException("Tried to register " +
177                "a node with a name that exists!\n Use nameNode to " +
178                "get a unique name before registering.\n");
179            } else {
180                nodes.add(aNode);
181            }
182        }
183        
184        /* (Copy of original doc. Generated version is inherited)
185         *
186         * Ensures that the specified node is nolonger registered. If the node
187         * was never registred, it simply returns with no side effects.
188         *
189         * @param aNode the node to unregister
190         */
191        public void unregister(Node aNode) {
192            nodes.remove(aNode);
193        }
194        
195        public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
196            if (!isLegalName((String)pce.getNewValue())) {
197                throw new PropertyVetoException("Duplicate names not allowed!",pce);
198            }
199        }
200        
201        
202        /**
203         * Checks for the uniqueness of the a potential node name.
204         *
205         * @param name The name to check for uniqueness.
206         * @return     <code>true</code> if the name is not in use <code>false</code>
207         *             otherwise
208         */
209        private synchronized boolean isUnique(String name) {
210            for (int i=0; i<nodes.size();i++){
211                if (name.equals(((Node) nodes.get(i)).getName())) {
212                    return false;
213                }
214            }
215            return true;
216        }
217    }
218    
219    
220    /*
221     * $Log: UniqueNodeNamePolicy.java,v $
222     * Revision 1.8  2004/01/14 21:43:17  gus
223     * more javadoc, plus reformat
224     *
225     * Revision 1.7  2004/01/14 20:23:21  gus
226     * Javadoc and comment cleanup
227     *
228     * Revision 1.6  2003/02/25 22:35:18  gus
229     * adding log comment
230     *
231     */