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 */