001    /*
002     * NodeConfigurationBean.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, 5:05 PM
008     */
009    
010    package nodenet;
011    
012    import nodenet.registrar.NodeNameRegistry;
013    import nodenet.registrar.NodeNameRegistrar;
014    import nodenet.registrar.DestinationValidator;
015    
016    import java.io.Serializable;
017    
018    import java.util.ConcurrentModificationException;
019    
020    import java.beans.PropertyChangeEvent;
021    import java.beans.PropertyChangeSupport;
022    import java.beans.VetoableChangeSupport;
023    import java.beans.PropertyVetoException;
024    import java.beans.PropertyChangeListener;
025    import java.beans.VetoableChangeListener;
026    
027    import javax.swing.JPanel;
028    
029    
030    /**
031     * A bean to manage the configuration of nodes. Currently nodes can be
032     * configured to have custom names, display or not display their names,
033     * and be configured to hold the name of a destination (for use with
034     * node behaviors that generate packets).
035     *
036     * @author  Patrick G. Heck gus.heck@olin.edu
037     * @version $Id: NodeConfigurationBean.java,v 1.12 2004/01/14 22:10:34 gus Exp $
038     */
039    public class NodeConfigurationBean extends JPanel implements Serializable {
040        
041        public static final String PROP_NODE_NAME = "Node Name";
042        public static final String PROP_DISPLAY_NODE_NAME = "Display Node Name";
043        public static final String PROP_DEST = "Destination";
044        
045        private static NodeNameRegistry registrar = NodeNameRegistry.getInstance();
046        
047        // Constrained:
048        private String nodeName;
049        private String dest;
050        
051        //Bound:
052        private boolean displayNodeName;
053        
054        // Write only property: Our registrar should never be changed
055        // private NodeNameRegistrar
056        
057        private PropertyChangeSupport propertySupport;
058        private VetoableChangeSupport vetos;
059        
060        private DestinationValidator destVal;
061        
062        /** Creates new NodeConfigurationBean */
063        public NodeConfigurationBean() {
064            propertySupport = new PropertyChangeSupport( this );
065            vetos = new VetoableChangeSupport(this);
066            addVetoableChangeListener(registrar);
067            destVal = DestinationValidator.getInstance();
068            addVetoableChangeListener(destVal);
069            initComponents();
070            refreshComponents();
071        }
072        
073        /** This method is called from within the constructor to
074         * initialize the form.
075         * WARNING: Do NOT modify this code. The content of this method is
076         * always regenerated by the Form Editor.
077         */
078        private void initComponents() {//GEN-BEGIN:initComponents
079            java.awt.GridBagConstraints gridBagConstraints;
080    
081            namePanel = new javax.swing.JPanel();
082            nameLabel = new javax.swing.JLabel();
083            nameTextField = new javax.swing.JTextField();
084            nameDisplayCheckBox = new javax.swing.JCheckBox();
085            destinationPanel = new javax.swing.JPanel();
086            destinationLabel = new javax.swing.JLabel();
087            destinationTextField = new javax.swing.JTextField();
088            destDetailLabel = new javax.swing.JLabel();
089    
090            setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));
091    
092            namePanel.setLayout(new java.awt.GridBagLayout());
093    
094            nameLabel.setText("Node name:");
095            gridBagConstraints = new java.awt.GridBagConstraints();
096            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
097            gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
098            gridBagConstraints.weightx = 1.0;
099            gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
100            namePanel.add(nameLabel, gridBagConstraints);
101    
102            nameTextField.setColumns(15);
103            gridBagConstraints = new java.awt.GridBagConstraints();
104            gridBagConstraints.gridx = 1;
105            gridBagConstraints.gridy = 0;
106            namePanel.add(nameTextField, gridBagConstraints);
107    
108            nameDisplayCheckBox.setText("Display Node Name");
109            gridBagConstraints = new java.awt.GridBagConstraints();
110            gridBagConstraints.gridx = 0;
111            gridBagConstraints.gridy = 1;
112            gridBagConstraints.gridwidth = 2;
113            gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
114            gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
115            namePanel.add(nameDisplayCheckBox, gridBagConstraints);
116    
117            add(namePanel);
118    
119            destinationPanel.setLayout(new java.awt.GridBagLayout());
120    
121            destinationLabel.setText("Packet Destination:");
122            gridBagConstraints = new java.awt.GridBagConstraints();
123            gridBagConstraints.gridx = 0;
124            gridBagConstraints.gridy = 0;
125            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
126            gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
127            gridBagConstraints.weightx = 1.0;
128            destinationPanel.add(destinationLabel, gridBagConstraints);
129    
130            gridBagConstraints = new java.awt.GridBagConstraints();
131            gridBagConstraints.gridx = 1;
132            gridBagConstraints.gridy = 0;
133            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
134            gridBagConstraints.weightx = 1.0;
135            destinationPanel.add(destinationTextField, gridBagConstraints);
136    
137            destDetailLabel.setFont(new java.awt.Font("Dialog", 0, 10));
138            destDetailLabel.setText("(Not yet implemented)");
139            gridBagConstraints = new java.awt.GridBagConstraints();
140            gridBagConstraints.gridx = 0;
141            gridBagConstraints.gridy = 1;
142            gridBagConstraints.gridwidth = 2;
143            gridBagConstraints.weightx = 1.0;
144            destinationPanel.add(destDetailLabel, gridBagConstraints);
145    
146            add(destinationPanel);
147    
148        }//GEN-END:initComponents
149        
150        /**
151         * Gets the identifying name of the node.
152         *
153         * @return The name of the node.
154         */
155        public String getDest() {
156            return dest;
157        }
158        
159        /**
160         * Attempts to change the neme of the node. If the name is not a
161         * legal name it throws an exception and the name will remain unchanged.
162         *
163         * @param value The desired new name for the node
164         * @throws PropertyVetoException if the NodeNameRegistry is implementing
165         *         a registration policy that forbids the name.
166         * @see NodeNameRegistry
167         * @see NodeNameRegistrar
168         */
169        public void setDest(String value) throws PropertyVetoException {
170            String oldValue = dest;
171            synchronized (registrar) {
172                vetos.fireVetoableChange(PROP_DEST, oldValue, value);
173                dest = value;
174            }
175            propertySupport.firePropertyChange(PROP_DEST, oldValue, dest);
176        }
177        
178        
179        /**
180         * Gets the identifying name of the node.
181         *
182         * @return The name of the node.
183         */
184        public String getNodeName() {
185            return nodeName;
186        }
187        
188        /**
189         * Attempts to change the neme of the node. If the name is not a
190         * legal name it throws an exception and the name will remain unchanged.
191         *
192         * @param value The desired new name for the node
193         * @throws PropertyVetoException if the NodeNameRegistry is implementing
194         *         a registration policy that forbids the name.
195         * @see NodeNameRegistry
196         * @see NodeNameRegistrar
197         */
198        public void setNodeName(String value) throws PropertyVetoException {
199            String oldValue = nodeName;
200            synchronized (registrar) {
201                vetos.fireVetoableChange(PROP_NODE_NAME, oldValue, value);
202                nodeName = value;
203            }
204            propertySupport.firePropertyChange(PROP_NODE_NAME, oldValue, nodeName);
205        }
206        
207        /**
208         * A convenience method that yeilds the same result as
209         * NodeNameRegistry.getInstance().
210         *
211         * @return The NodeNameRegistry of which there can be only one.
212         * @see NodeNameRegistry
213         */
214        public NodeNameRegistrar getRegistrar() {
215            return registrar;
216        }
217        
218        /**
219         * Display the name of the node or not.
220         *
221         * @return <code>true</code> if the name should be displayed <code>false</code>
222         *         otherwise.
223         */
224        
225        public boolean getDisplayNodeName() {
226            return displayNodeName;
227        }
228        
229        /**
230         * Sets whether or not the name of the node is displayed.
231         *
232         * @param display whether or not to display the node.
233         */
234        public void setDisplayNodeName(boolean display) {
235            boolean oldVal = getDisplayNodeName();
236            displayNodeName = display;
237            propertySupport.firePropertyChange(PROP_DISPLAY_NODE_NAME, oldVal, display);
238        }
239        
240        /**
241         * Register an object to be notified when the properties of this bean
242         * are changed.
243         *
244         * @param listener The listening object
245         */
246        public void addPropertyChangeListener(PropertyChangeListener listener) {
247            propertySupport.addPropertyChangeListener(listener);
248        }
249        
250        /**
251         * Unregister an object that nolonger needs to be notified of property
252         * changes.
253         *
254         * @param listener The object that wants to stop listening.
255         */
256        public void removePropertyChangeListener(PropertyChangeListener listener) {
257            propertySupport.removePropertyChangeListener(listener);
258        }
259        
260        
261        /**
262         * Register an object that has the power to overide changes to this bean.
263         *
264         * @param l An object that can veto changes.
265         */
266        public void addVetoableChangeListener(VetoableChangeListener l) {
267            vetos.addVetoableChangeListener(l);
268        }
269        
270        /**
271         * Unregister an object that nolonger needs to overide changes to this bean.
272         *
273         * @param l A vetoer that nolonger wishes to vote on changes.
274         */
275        public void removeVetoableChangeListener(VetoableChangeListener l) {
276            vetos.removeVetoableChangeListener(l);
277        }
278        
279        /**
280         * Refresh the values displayed in the components used to display and
281         * configure this bean. This should be called immediately before displaying
282         * the bean in a Container.
283         */
284        public synchronized void refreshComponents() {
285            
286            // until destinations are implemented
287            this.destinationPanel.setVisible(false);
288            
289            this.nameTextField.setText(this.getNodeName());
290            this.nameDisplayCheckBox.setSelected(this.getDisplayNodeName());
291            this.destinationTextField.setText(this.getDest());
292        }
293        
294        /**
295         * Attempt to enact user changes. This method is typically called after
296         * the panel has been shown in a dialog and properties may have been
297         * edited. Changes are applied atomically once the have all been validated.
298         * If any changes have been vetoed, this method will throw the related
299         * exception. If conditions change after vetos have been checked causing
300         * a subsequent property veto a ConcurrentModificationException will be
301         * thrown.
302         *
303         * @throws PropertyVetoException if listenerns object.
304         */
305        public synchronized void implementUserChanges() throws PropertyVetoException,
306        ConcurrentModificationException {
307            
308            boolean reset=false;
309            
310            // gather a snapshot of the data from the components and the bean
311            String newName = nameTextField.getText();
312            String oldName = this.getNodeName();
313            boolean newShowName = nameDisplayCheckBox.isSelected();
314            boolean oldShowName = this.getDisplayNodeName();
315            String newDest = destinationTextField.getText();
316            String oldDest = this.getDest();
317            
318            // test the changes so that we throw a PropertyVetoException in
319            // preference to the ConcurrentModificationException. PVE's have more
320            // information that can be used to clarify the problem to the user.
321            // This also avoids having to re-throw the exception after we reset
322            // any values that have been changed.
323            if (!newName.equals(this.getNodeName())) {
324                vetos.fireVetoableChange(PROP_NODE_NAME, oldName, newName);
325            }
326            vetos.fireVetoableChange(PROP_DEST, oldDest, newDest);
327            // Now try to make the changes that can be vetoed.
328            try {
329                setNodeName(newName);
330                setDest(newDest);
331            } catch (PropertyVetoException pve) {
332                reset = true;
333            }
334            
335            // if something failed we have been concurrently modified,
336            // revert and throw and exception.
337            if (reset) {
338                nodeName=oldName;
339                dest = oldDest;
340                throw new ConcurrentModificationException("Node configuration" +
341                " concurrently modified");
342            }
343            
344            // Now proceed with non-vetoable changes
345            setDisplayNodeName(newShowName);
346        }
347        
348        
349        
350        
351        // Variables declaration - do not modify//GEN-BEGIN:variables
352        private javax.swing.JLabel destDetailLabel;
353        private javax.swing.JLabel destinationLabel;
354        private javax.swing.JPanel destinationPanel;
355        private javax.swing.JTextField destinationTextField;
356        private javax.swing.JCheckBox nameDisplayCheckBox;
357        private javax.swing.JLabel nameLabel;
358        private javax.swing.JPanel namePanel;
359        private javax.swing.JTextField nameTextField;
360        // End of variables declaration//GEN-END:variables
361        
362    }
363    
364    /*
365     * $Log: NodeConfigurationBean.java,v $
366     * Revision 1.12  2004/01/14 22:10:34  gus
367     * hide the destination panel until such time as we are ready to use it.
368     *
369     * Revision 1.11  2004/01/14 21:43:17  gus
370     * more javadoc, plus reformat
371     *
372     * Revision 1.10  2004/01/14 21:04:16  gus
373     * More javadoc fixes
374     *
375     * Revision 1.9  2004/01/14 20:23:21  gus
376     * Javadoc and comment cleanup
377     *
378     * Revision 1.8  2004/01/06 18:50:37  gus
379     * note that packet routing is not implemented
380     *
381     * Revision 1.7  2004/01/06 17:09:19  gus
382     * Netbeans generated code changed
383     *
384     * Revision 1.6  2003/02/25 22:35:18  gus
385     * adding log comment
386     *
387     */