001 // edu.isi.gamebots.clients.BotRunnerApp 002 // Copyright 2000, University of Southern California, 003 // Information Science Institute 004 // 005 // Personal and Educational use is hereby granted. 006 // Permission required for commercial use and redistribution. 007 008 009 package edu.isi.gamebots.client; 010 011 import java.awt.BorderLayout; 012 import java.awt.Color; 013 import java.awt.Component; 014 import java.awt.Container; 015 import java.awt.Cursor; 016 import java.awt.Dimension; 017 import java.awt.FlowLayout; 018 import java.awt.Font; 019 import java.awt.GridBagLayout; 020 import java.awt.GridBagConstraints; 021 import java.awt.Insets; 022 //import java.awt.*; 023 import java.awt.event.*; 024 import java.io.*; 025 import java.lang.*; 026 import java.net.*; 027 import java.util.*; 028 029 import javax.swing.*; 030 import javax.swing.border.*; 031 import javax.swing.event.*; 032 033 import us.ca.la.anm.gui.*; 034 import us.ca.la.anm.util.io.*; 035 036 import edu.isi.gamebots.client.*; 037 import edu.isi.gamebots.examples.*; 038 039 040 /** 041 * This application is a test platform for any Bot or VizTool implementation. 042 * It provides a simple user interface for loading bot implementations, setting 043 * the server address and port, and connecting and disconnecting the clients. 044 * 045 * <h3>Future Goals:</h3> 046 * <ul> 047 * <li>Finish the Bot menu. Allow for individual Bot connection, 048 * reconnection, and disconnection, as well as the biligty to unload a 049 * bot from the team. 050 * <li>Add support for serializable Bots (load Bot from file, save Bot). 051 * </ul> 052 * 053 * @author <a href="mailto:amarshal#gamebots@isi.edu">Andrew n marshall</a> 054 */ 055 public class BotRunnerApp implements GamebotsConstants { 056 // Private Constants 057 /////////////////////////////////////////////////////////////////////////// 058 protected static final int MAX_CONNECTION_ATTEMPTS = 2; 059 protected static final long TIMEOUT = 10000; // 10 seconds 060 061 protected static final String DATA_CARD = "data"; // For AddBotDialog 062 protected static final String ERROR_CARD = "error"; // For AddBotDialog 063 064 protected static final String BOT = "Bot"; 065 protected static final String VIZ = "VizTool"; 066 067 // Private Data 068 /////////////////////////////////////////////////////////////////////////// 069 protected JTextAreaLog log = new JTextAreaLog(); 070 071 protected JFrame frame; 072 protected JMenu botMenu; 073 protected JTabbedPane tabbedPane; 074 protected JPanel serverPanel; 075 protected JTextArea text; 076 protected JLabel status; 077 078 protected JTextAreaLog curLogForText = log; 079 080 protected Hashtable tabManagers = new Hashtable(); // JCompopnet views to TabManagers 081 protected int botNameCount = 0; 082 protected int vizNameCount = 0; 083 protected int tabCount = 0; 084 protected int connectionCount = 0; 085 086 protected JTextField serverField; 087 protected InetAddress serverAddress = null; 088 protected JTextField botPortField; 089 protected int serverBotPort = GamebotsClient.DEFAULT_BOT_PORT; 090 protected JTextField vizPortField; 091 protected int serverVizPort = GamebotsClient.DEFAULT_VIZ_PORT; 092 093 protected Thread[] connectionEventThreads; 094 protected Vector connectionEventQueue; 095 096 // Public Methods 097 /////////////////////////////////////////////////////////////////////////// 098 public static void main( String[] args ) { 099 new BotRunnerApp( args ); 100 } 101 102 public BotRunnerApp( String[] args ) { 103 buildGUI(); 104 log.setJTextArea( text ); 105 106 connectionEventQueue = new Vector(); 107 connectionEventThreads = new Thread[ MAX_CONNECTION_ATTEMPTS ]; 108 for( int i=0; i<MAX_CONNECTION_ATTEMPTS; i++ ) { 109 connectionEventThreads[i] = new Thread( new ConnectionEventRunner(i) ); 110 connectionEventThreads[i].start(); 111 } 112 113 frame.show(); 114 } 115 116 // Private Methods 117 /////////////////////////////////////////////////////////////////////////// 118 protected void buildGUI() { 119 JMenuBar menuBar; 120 JMenu menu; 121 JMenuItem item; 122 JPanel panel, panel2; 123 JScrollPane scroll; 124 JSplitPane splitter; 125 JLabel label; 126 GridBagConstraints gbc; 127 128 requestAddBot.putValue( Action.NAME, "Add "+BOT+"..." ); 129 requestAddViz.putValue( Action.NAME, "Add "+VIZ+"..." ); 130 connectAll.putValue( Action.NAME, "Connect All" ); 131 connectAll.setEnabled( false ); 132 reconnectAll.putValue( Action.NAME, "Reconnect All" ); 133 connectAll.setEnabled( false ); 134 disconnectAll.putValue( Action.NAME, "Disconnect All" ); 135 disconnectAll.setEnabled( false ); 136 requestExit.putValue( Action.NAME, "Exit" ); 137 handleExit.putValue( Action.NAME, "Force Exit" ); 138 139 frame = new JFrame( "Gamebots Java Client" ); 140 menuBar = new JMenuBar(); 141 menu = new JMenu( "Team" ); 142 menu.add( new JMenuItem( requestAddBot ) ); 143 menu.add( new JMenuItem( requestAddViz ) ); 144 menu.addSeparator(); 145 menu.add( new JMenuItem( connectAll ) ); 146 menu.add( new JMenuItem( reconnectAll ) ); 147 menu.add( new JMenuItem( disconnectAll ) ); 148 menu.addSeparator(); 149 menu.add( new JMenuItem( requestExit ) ); 150 menuBar.add( menu ); 151 152 botMenu = new JMenu( BOT ); 153 botMenu.setEnabled( false ); 154 menuBar.add( botMenu ); 155 frame.setJMenuBar( menuBar ); 156 157 panel = new JPanel( new BorderLayout() ); 158 splitter = new JSplitPaneFix( JSplitPane.VERTICAL_SPLIT ); 159 tabbedPane = new JTabbedPane(); 160 tabbedPane.addChangeListener( tabListener ); 161 162 serverPanel = new JPanel( new GridBagLayout() ); 163 serverPanel.setBorder( new EmptyBorder( 2, 2, 2, 2 ) ); 164 165 label = new JLabel( "Server:" ); 166 gbc = new GridBagConstraints(); 167 gbc.gridx = gbc.gridy = 0; 168 gbc.weightx = 0.0; 169 gbc.weighty = 0.6; 170 gbc.fill = gbc.NONE; 171 gbc.anchor = gbc.SOUTHEAST; 172 serverPanel.add( label, gbc ); 173 174 serverField = new JTextField(); 175 serverField.addFocusListener( serverFocusListener ); 176 177 gbc.gridx++; 178 gbc.weightx = 1.0; 179 gbc.anchor = gbc.SOUTHWEST; 180 gbc.fill = gbc.HORIZONTAL; 181 serverPanel.add( serverField, gbc ); 182 183 label = new JLabel( BOT+" Port:", SwingConstants.TRAILING ); 184 gbc.gridx = 0; 185 gbc.gridy++; 186 gbc.weightx = gbc.weighty = 0.0; 187 gbc.fill = gbc.NONE; 188 gbc.anchor = gbc.EAST; 189 serverPanel.add( label, gbc ); 190 191 botPortField = new JTextField( Integer.toString( serverBotPort ) ); 192 botPortField.addFocusListener( botPortFocusListener ); 193 194 gbc.gridx++; 195 gbc.weightx = 1.0; 196 gbc.fill = gbc.HORIZONTAL; 197 gbc.anchor = gbc.EAST; 198 serverPanel.add( botPortField, gbc ); 199 200 label = new JLabel( VIZ+" Port:", SwingConstants.TRAILING ); 201 gbc.gridx = 0; 202 gbc.gridy++; 203 gbc.weightx = gbc.weighty = 0.0; 204 gbc.anchor = gbc.EAST; 205 gbc.fill = gbc.NONE; 206 serverPanel.add( label, gbc ); 207 208 vizPortField = new JTextField( Integer.toString( serverVizPort ) ); 209 vizPortField.addFocusListener( vizPortFocusListener ); 210 211 gbc.gridx++; 212 gbc.anchor = gbc.WEST; 213 gbc.fill = gbc.HORIZONTAL; 214 serverPanel.add( vizPortField, gbc ); 215 216 panel2 = new JPanel( new FlowLayout( FlowLayout.TRAILING ) ); 217 panel2.add( new JButton( connectAll ) ); 218 // panel2.add( new JButton( reconnectAll ) ); 219 panel2.add( new JButton( disconnectAll ) ); 220 221 gbc.gridx = 0; 222 gbc.gridy++; 223 gbc.weightx = gbc.weighty = 1.0; 224 gbc.gridwidth = 2; 225 gbc.anchor = gbc.SOUTH; 226 gbc.fill = gbc.HORIZONTAL; 227 serverPanel.add( panel2, gbc ); 228 tabbedPane.add( serverPanel, "Server" ); 229 splitter.setTopComponent( tabbedPane ); 230 231 text = new JTextArea(); 232 text.setFont( new Font( "Monospaced", Font.PLAIN, 11 ) ); 233 text.setAutoscrolls( true ); 234 text.setEditable( false ); 235 text.setMargin( new Insets( 2, 2, 2, 2 ) ); 236 scroll = new JScrollPane( text ); 237 scroll.setPreferredSize( new Dimension( 480, 360 ) ); 238 splitter.setBottomComponent( scroll ); 239 240 panel.add( splitter, BorderLayout.CENTER ); 241 242 status = new JLabel( " " ); 243 panel.add( status, BorderLayout.SOUTH ); 244 frame.setContentPane( panel ); 245 246 frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); 247 frame.addWindowListener( new WindowAdapter() { 248 public void windowClosing( WindowEvent event ) { 249 requestExit.actionPerformed( null ); 250 } 251 252 public void windowClosed( WindowEvent event ) { 253 handleExit.actionPerformed( null ); 254 } 255 } ); 256 frame.pack(); 257 } 258 259 protected void setStatus( String status ) { 260 this.status.setText( status ); 261 } 262 263 // Event Handlers 264 protected Action requestAddBot = new AbstractAction() { 265 public void actionPerformed( ActionEvent event ) { 266 JDialog dialog = new AddTabDialog( BOT ); 267 dialog.show(); 268 } 269 }; 270 271 protected Action requestAddViz = new AbstractAction() { 272 public void actionPerformed( ActionEvent event ) { 273 JDialog dialog = new AddTabDialog( VIZ ); 274 dialog.show(); 275 } 276 }; 277 278 protected Action connectAll = new AbstractAction() { 279 public void actionPerformed( ActionEvent event ) { 280 if( serverAddress == null ) { 281 log.logNote( "Cannot connect: No server defined." ); 282 log.flush(); 283 return; 284 } 285 286 synchronized( connectionEventQueue ) { 287 synchronized( tabManagers ) { 288 Iterator i = tabManagers.values().iterator(); 289 TabManager tab; 290 while( i.hasNext() ) 291 connectionEventQueue.add( ((TabManager) i.next()).connectRunner ); 292 } // end tab sync 293 294 connectionEventQueue.notifyAll(); 295 } 296 } 297 }; 298 299 protected Action reconnectAll = new AbstractAction() { 300 public void actionPerformed( ActionEvent event ) { 301 synchronized( connectionEventQueue ) { 302 connectAll.actionPerformed( event ); 303 disconnectAll.actionPerformed( event ); 304 } 305 } 306 }; 307 308 protected Action disconnectAll = new AbstractAction() { 309 public void actionPerformed( ActionEvent event ) { 310 synchronized( connectionEventQueue ) { 311 synchronized( tabManagers ) { 312 Iterator i = tabManagers.values().iterator(); 313 TabManager tab; 314 while( i.hasNext() ) 315 connectionEventQueue.add( ((TabManager) i.next()).disconnectRunner ); 316 } // end tab sync 317 318 connectionEventQueue.notifyAll(); 319 } 320 } 321 }; 322 323 protected ChangeListener tabListener = new ChangeListener() { 324 public void stateChanged( ChangeEvent event ) { 325 Component selected = tabbedPane.getSelectedComponent(); 326 327 if( selected == serverPanel ) { 328 if( curLogForText != log ) { 329 curLogForText.setJTextArea( null ); 330 text.setText( "" ); 331 curLogForText = log; 332 curLogForText.setJTextArea( text ); 333 334 botMenu.setEnabled( false ); 335 } 336 } else { 337 Object tab = tabManagers.get( selected ); 338 if( tab == null ) { 339 log.logError( "Selected component <"+selected+"> is not recognized." ); 340 } else { 341 JTextAreaLog newLog = ((TabManager) tab).tabLog; 342 if( curLogForText != newLog ) { 343 curLogForText.setJTextArea( null ); 344 text.setText( "" ); 345 curLogForText = newLog; 346 curLogForText.setJTextArea( text ); 347 } 348 } 349 } 350 } 351 }; 352 353 protected FocusListener serverFocusListener = new FocusListener() { 354 public void focusGained( FocusEvent event ) { 355 serverField.setForeground( Color.black ); 356 } 357 358 public void focusLost( FocusEvent event ) { 359 // This doesn't work 360 frame.setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) ); 361 362 try { 363 InetAddress oldAddress = serverAddress; 364 serverAddress = InetAddress.getByName( serverField.getText() ); 365 366 if( oldAddress == null || 367 !oldAddress.equals( serverAddress ) ) { 368 synchronized( tabManagers ) { 369 Iterator i = tabManagers.values().iterator(); 370 TabManager tab; 371 while( i.hasNext() ) { 372 tab = (TabManager) i.next(); 373 tab.client.setServerAddress( serverAddress ); 374 } 375 } 376 } 377 } catch( UnknownHostException error ) { 378 serverField.setForeground( Color.red ); 379 } 380 frame.setCursor( Cursor.getDefaultCursor() ); 381 } 382 }; 383 384 protected FocusListener botPortFocusListener = new FocusListener() { 385 public void focusGained( FocusEvent event ) { 386 botPortField.setForeground( Color.black ); 387 } 388 389 public void focusLost( FocusEvent event ) { 390 try { 391 int oldPort = serverBotPort; 392 serverBotPort = Integer.parseInt( botPortField.getText() ); 393 394 if( serverBotPort <= 0 ) { 395 botPortField.setForeground( Color.red ); 396 } else if( oldPort != serverBotPort ) { 397 synchronized( tabManagers ) { 398 Iterator i = tabManagers.values().iterator(); 399 TabManager tab; 400 while( i.hasNext() ) { 401 tab = (TabManager) i.next(); 402 if( tab instanceof BotManager ) 403 tab.client.setServerPort( serverBotPort ); 404 } 405 } 406 } 407 } catch( NumberFormatException error ) { 408 botPortField.setForeground( Color.red ); 409 } 410 } 411 }; 412 413 protected FocusListener vizPortFocusListener = new FocusListener() { 414 public void focusGained( FocusEvent event ) { 415 vizPortField.setForeground( Color.black ); 416 } 417 418 public void focusLost( FocusEvent event ) { 419 try { 420 int oldPort = serverVizPort; 421 serverVizPort = Integer.parseInt( vizPortField.getText() ); 422 423 if( serverVizPort <= 0 ) { 424 vizPortField.setForeground( Color.red ); 425 } else if( oldPort != serverVizPort ) { 426 synchronized( tabManagers ) { 427 Iterator i = tabManagers.values().iterator(); 428 TabManager tab; 429 while( i.hasNext() ) { 430 tab = (TabManager) i.next(); 431 if( tab instanceof VizManager ) { 432 tab.disconnect(); 433 tab.client.setServerPort( serverVizPort ); 434 } 435 } 436 } 437 } 438 } catch( NumberFormatException error ) { 439 vizPortField.setForeground( Color.red ); 440 } 441 } 442 }; 443 444 protected Action requestExit = new AbstractAction() { 445 public void actionPerformed( ActionEvent event ) { 446 frame.setVisible( false ); 447 frame.dispose(); 448 } 449 }; 450 451 protected Action handleExit = new AbstractAction() { 452 public void actionPerformed( ActionEvent event ) { 453 frame.setVisible( false ); 454 frame.dispose(); 455 456 for( int i=0; i<MAX_CONNECTION_ATTEMPTS; i++ ) 457 connectionEventThreads[i] = null; 458 459 synchronized( tabManagers ) { 460 Iterator i = tabManagers.values().iterator(); 461 while( i.hasNext() ) 462 ((TabManager) i.next()).destroy(); 463 } // end sync 464 465 System.exit( 0 ); 466 } 467 }; 468 469 470 // Protected Inner Classes 471 /////////////////////////////////////////////////////////////////////////// 472 protected class ConnectionEventRunner implements Runnable { 473 protected int number; 474 475 public ConnectionEventRunner( int number ) { 476 this.number = number; 477 } 478 479 public void run() { 480 Thread thisThread = Thread.currentThread(); 481 482 Runnable runner = null; 483 while( connectionEventThreads[number] == thisThread ) { 484 synchronized( connectionEventQueue ) { 485 if( connectionEventQueue.isEmpty() ) { 486 try { 487 connectionEventQueue.wait(); 488 } catch( InterruptedException error ) { 489 // ignore... 490 } 491 } else { 492 runner = (Runnable) connectionEventQueue.get( 0 ); 493 connectionEventQueue.remove( 0 ); 494 } 495 } // end synch 496 497 if( runner != null ) 498 runner.run(); 499 } 500 } 501 } 502 503 protected class AddTabDialog extends JDialog { 504 // Private Data 505 ///////////////////////////////////////////////////////////////////////// 506 /* 507 protected final JMenuItem ANY_TEAM_ITEM; 508 protected final JMenuItem RED_TEAM_ITEM; 509 protected final JMenuItem BLUE_TEAM_ITEM; 510 protected final JMenuItem GREEN_TEAM_ITEM; 511 protected final JMenuItem YELLOW_TEAM_ITEM; 512 protected final JMenuItem NO_TEAM_ITEM; 513 */ 514 515 protected String[] knownBots = { 516 "edu.isi.gamebots.examples.ExampleBot", 517 "edu.cmu.gamebots.CMU_JBot", 518 "edu.tamu.gamebots.humanbot.HumanBot", 519 "edu.tamu.agents.CAST_PM.unreal.AgentUnrealTournamentAdapter" 520 }; 521 522 protected String[] knownVizTools ={ 523 "edu.isi.gamebots.examples.ExampleVizTool" 524 }; 525 526 protected String panelType; 527 528 protected JCardStack cards; 529 protected JTextField nameField; 530 protected JComboBox teamField; 531 protected JTextField classpathField; 532 protected JComboBox classField;//changed by Ryan Rozich for user convienience 533 protected JButton addButton, cancelButton; 534 535 // Public Methods 536 ///////////////////////////////////////////////////////////////////////// 537 public AddTabDialog( String type ) { 538 /* 539 if( type == BOT ) { 540 ANY_TEAM_ITEM = new JMenuItem( "Any" ); 541 RED_TEAM_ITEM = new JMenuItem( "Red" ); 542 RED_TEAM_ITEM.setForeground( Color.red ); 543 BLUE_TEAM_ITEM = new JMenuItem( "Blue" ); 544 BLUE_TEAM_ITEM.setForeground( Color.blue ); 545 GREEN_TEAM_ITEM = new JMenuItem( "Green" ); 546 GREEN_TEAM_ITEM.setForeground( Color.green ); 547 YELLOW_TEAM_ITEM = new JMenuItem( "Yellow" ); 548 YELLOW_TEAM_ITEM.setForeground( Color.yellow.darker() ); 549 NO_TEAM_ITEM = new JMenuItem( "None" ); 550 } else { 551 ANY_TEAM_ITEM = RED_TEAM_ITEM = BLUE_TEAM_ITEM = GREEN_TEAM_ITEM 552 = YELLOW_TEAM_ITEM = NO_TEAM_ITEM = null; 553 } 554 */ 555 556 panelType = type; 557 558 JPanel panel, panel2; 559 JLabel label; 560 JButton button; 561 GridBagConstraints gbc; 562 563 Container content = getContentPane(); 564 cards = new JCardStack(); 565 panel = new JPanel( new GridBagLayout() ); 566 panel.setBorder( new EmptyBorder( 2, 2, 2, 2 ) ); 567 568 label = new JLabel( "Name:" ); 569 gbc = new GridBagConstraints(); 570 gbc.gridx = gbc.gridy = 0; 571 gbc.weightx = 0.0; 572 gbc.weighty = 0.3; 573 gbc.anchor = gbc.SOUTHEAST; 574 panel.add( label, gbc ); 575 576 if( panelType == BOT ) 577 nameField = new JTextField( panelType+(++botNameCount) ); 578 else // assume VIZ 579 nameField = new JTextField( panelType+(++vizNameCount) ); 580 581 gbc.gridx++; 582 gbc.weightx = 1.0; 583 gbc.anchor = gbc.SOUTHWEST; 584 gbc.fill = gbc.HORIZONTAL; 585 panel.add( nameField, gbc ); 586 587 if( panelType == BOT ) { 588 label = new JLabel( "Team:", SwingConstants.TRAILING ); 589 gbc.gridx++; 590 gbc.weightx = 0.0; 591 gbc.fill = gbc.NONE; 592 gbc.anchor = gbc.SOUTHEAST; 593 panel.add( label, gbc ); 594 595 teamField = new JComboBox(); 596 teamField.addItem( GamebotsConstants.TeamColorMap.teamToName( TEAM_ANY ) ); 597 teamField.addItem( GamebotsConstants.TeamColorMap.teamToName( TEAM_NONE ) ); 598 teamField.addItem( GamebotsConstants.TeamColorMap.teamToName( TEAM_RED ) ); 599 teamField.addItem( GamebotsConstants.TeamColorMap.teamToName( TEAM_BLUE ) ); 600 teamField.addItem( GamebotsConstants.TeamColorMap.teamToName( TEAM_GREEN ) ); 601 teamField.addItem( GamebotsConstants.TeamColorMap.teamToName( TEAM_GOLD ) ); 602 teamField.setEditable( false ); 603 604 gbc.gridx++; 605 gbc.anchor = gbc.SOUTHWEST; 606 gbc.fill = gbc.HORIZONTAL; 607 panel.add( teamField, gbc ); 608 } 609 610 /* 611 label = new JLabel( "Classpath:", SwingConstants.TRAILING ); 612 gbc.gridx = 0; 613 gbc.gridy++; 614 gbc.weightx = gbc.weighty = 0.0; 615 gbc.anchor = gbc.EAST; 616 panel.add( label, gbc ); 617 618 classpathField = new JTextField(); 619 620 gbc.gridx++; 621 gbc.gridwidth = 3; 622 gbc.weightx = 1.0; 623 gbc.anchor = gbc.WEST; 624 gbc.fill = gbc.HORIZONTAL; 625 panel.add( classpathField, gbc ); 626 */ 627 628 label = new JLabel( "Class:", SwingConstants.TRAILING ); 629 gbc.gridx = 0; 630 gbc.gridy++; 631 gbc.gridwidth = 1; 632 gbc.weightx = 0.0; 633 gbc.weighty = 1.0; 634 gbc.anchor = gbc.NORTHEAST; 635 panel.add( label, gbc ); 636 637 if( panelType == BOT ) 638 classField = new JComboBox( knownBots ); 639 else // assume VIZ 640 classField = new JComboBox( knownVizTools ); 641 642 classField.setEditable(true); 643 644 gbc.gridx++; 645 gbc.gridwidth = 3; 646 gbc.weightx = 1.0; 647 gbc.anchor = gbc.NORTHWEST; 648 gbc.fill = gbc.HORIZONTAL; 649 panel.add( classField, gbc ); 650 cards.add( panel, DATA_CARD ); 651 content.add( cards, BorderLayout.CENTER ); 652 653 panel = new JPanel( new FlowLayout( FlowLayout.TRAILING ) ); 654 addButton = new JButton( "Add "+panelType ); 655 addButton.addActionListener( new ActionListener() { 656 public void actionPerformed( ActionEvent event ) { 657 addTab(); 658 } 659 } ); 660 panel.add( addButton ); 661 662 cancelButton = new JButton( "Cancel" ); 663 cancelButton.addActionListener( new ActionListener() { 664 public void actionPerformed( ActionEvent event ) { 665 hide(); 666 dispose(); 667 } 668 } ); 669 panel.add( cancelButton ); 670 content.add( panel, BorderLayout.SOUTH ); 671 pack(); 672 } 673 674 // Private Methods 675 ///////////////////////////////////////////////////////////////////////// 676 protected void addTab() { 677 JLabel label; 678 679 try { 680 if( panelType == BOT ) { 681 Class botClass = Class.forName( ((String)classField.getSelectedItem()).trim() ); 682 Bot bot = (Bot) botClass.newInstance(); 683 int team; 684 String teamName = teamField.getSelectedItem().toString(); 685 if( teamName.equals("Any") ) 686 team = TEAM_ANY; 687 else if( teamName.equals("Red") ) 688 team = TEAM_RED; 689 else if( teamName.equals("Blue") ) 690 team = TEAM_BLUE; 691 else if( teamName.equals("Green") ) 692 team = TEAM_GREEN; 693 else if( teamName.equals("Gold") ) 694 team = TEAM_GOLD; 695 else // if( teamName.equals("None") ) 696 team = TEAM_NONE; 697 698 new BotManager( bot, nameField.getText().trim(), team ); 699 700 } else if( panelType == VIZ ) { 701 Class vizClass = Class.forName( ((String)classField.getSelectedItem()).trim() ); 702 VizTool viz = (VizTool) vizClass.newInstance(); 703 new VizManager( viz, nameField.getText().trim() ); 704 } 705 706 // Success, go ahead and clear the dialog 707 hide(); 708 dispose(); 709 } catch( Exception error ) { 710 label = new JLabel( "<html><font color='black'><b>Unable to create "+panelType+":</b><p>"+error.toString() ); 711 cards.add( label, ERROR_CARD ); 712 cards.show( ERROR_CARD ); 713 addButton.setVisible( false ); 714 } 715 } 716 } 717 718 protected abstract class TabManager extends GamebotsClient.Adapter { 719 // Private Data 720 /////////////////////////////////////////////////////////////////////// 721 protected final Object clientLock = new Object(); 722 public final GamebotsClient client; 723 724 public final JTextAreaLog tabLog; 725 726 protected String title; 727 728 // Protected Constructor 729 /////////////////////////////////////////////////////////////////////// 730 protected TabManager( String title ) { 731 this.title = title; 732 tabLog = new JTextAreaLog(); 733 client = new GamebotsClient(); 734 735 client.setLog( tabLog ); 736 client.addListener( this ); 737 738 if( serverAddress != null ) 739 client.setServerAddress( serverAddress ); 740 } 741 742 // Public Methods 743 /////////////////////////////////////////////////////////////////////// 744 public void connect() { 745 // tabLog.logNote( "Attempting Connection: Server: "+client.getServerAddress()+":"+client.getServerPort() ); 746 try { 747 synchronized( clientLock ) { 748 client.connect(); 749 long remaining = TIMEOUT; 750 long endTime = System.currentTimeMillis() + remaining; 751 while( !client.isConnected() ) { 752 try { 753 clientLock.wait( TIMEOUT ); 754 } catch( InterruptedException error ) { 755 // ignore 756 } 757 remaining = endTime - System.currentTimeMillis(); 758 if( remaining < 0 ) { 759 log.logNote( title+" <"+getClass().getName()+"> connection attempt timed out ("+new Date()+")" ); 760 break; 761 } 762 } 763 } // end synch 764 } catch ( IOException error ) { 765 log.logError( title+" <"+getClass().getName()+"> could not connect ("+new Date()+")", error ); 766 } catch ( RuntimeException error ) { 767 log.logError( title+" <"+getClass().getName()+"> could not connect ("+new Date()+")", error ); 768 } 769 } 770 771 public void disconnect() { 772 try { 773 synchronized( clientLock ) { 774 if( client.isConnected() ) { 775 client.disconnect(); 776 long remaining = TIMEOUT; 777 long endTime = System.currentTimeMillis() + remaining; 778 while( !client.isConnected() ) { 779 try { 780 clientLock.wait( TIMEOUT ); 781 } catch( InterruptedException error ) { 782 // ignore 783 } 784 remaining = endTime - System.currentTimeMillis(); 785 if( remaining < 0 ) { 786 log.logNote( title+" <"+getClass().getName()+"> disconnection attempt timed out ("+new Date()+")" ); 787 break; 788 } 789 } 790 } 791 } // end synch 792 } catch ( RuntimeException error ) { 793 log.logError( title+" <"+getClass().getName()+"> failed duing disconnect()", error ); 794 } 795 } 796 797 public void destroy() { 798 // close log??? 799 800 client.disconnect(); 801 } 802 803 // Event Handlers 804 public void connected() { 805 log.logNote( "Connection: \""+title+"\" ("+new Date()+")" ); 806 synchronized( tabManagers ) { 807 ++connectionCount; 808 809 disconnectAll.setEnabled( true ); 810 reconnectAll.setEnabled( true ); 811 connectAll.setEnabled( connectionCount != tabCount ); 812 } 813 synchronized( clientLock ) { 814 clientLock.notifyAll(); 815 } 816 } 817 818 public void disconnected() { 819 log.logNote( "Disconnection: \""+title+"\" ("+new Date()+")" ); 820 synchronized( tabManagers ) { 821 --connectionCount; 822 823 connectAll.setEnabled( true ); 824 boolean moreConnections = connectionCount > 0; 825 disconnectAll.setEnabled( moreConnections ); 826 reconnectAll.setEnabled( moreConnections ); 827 } 828 synchronized( clientLock ) { 829 clientLock.notifyAll(); 830 } 831 } 832 833 // Public Connection Event Runners 834 public Runnable connectRunner = new Runnable() { 835 public void run() { 836 try { 837 connect(); 838 } catch( RuntimeException error ) { 839 tabLog.logError( "Unexpected error during connection ("+new Date()+")", error ); 840 } 841 } 842 }; 843 844 public Runnable disconnectRunner = new Runnable() { 845 public void run() { 846 disconnect(); 847 } 848 }; 849 850 // Private Methods 851 /////////////////////////////////////////////////////////////////////// 852 protected void addTab( JComponent view ) { 853 synchronized( tabManagers ) { 854 ++tabCount; 855 tabbedPane.add( view, title ); 856 tabManagers.put( view, TabManager.this ); 857 858 connectAll.setEnabled( true ); 859 } 860 } 861 } 862 863 protected class BotManager extends TabManager { 864 public final Bot bot; 865 866 public BotManager( Bot bot, String name, int team ) { 867 super( name ); 868 869 this.bot = bot; 870 871 client.setServerPort( serverBotPort ); 872 873 bot.init( name, client, team, tabLog ); 874 addTab( bot.getView() ); 875 } 876 877 public void connect() { 878 if( client.isConnected() ) 879 return; 880 881 tabLog.logNote( "Attempting Connection: Server: "+client.getServerAddress()+":"+client.getServerPort() ); 882 try { 883 synchronized( clientLock ) { 884 bot.connect(); 885 long remaining = TIMEOUT; 886 long endTime = System.currentTimeMillis() + remaining; 887 while( !client.isConnected() ) { 888 try { 889 clientLock.wait( TIMEOUT ); 890 } catch( InterruptedException error ) { 891 // ignore 892 } 893 remaining = endTime - System.currentTimeMillis(); 894 if( remaining < 0 ) { 895 log.logNote( BOT+" \""+bot.getName()+"\" connection attempt timed out ("+new Date()+")" ); 896 break; 897 } 898 } 899 } 900 } catch ( RuntimeException error ) { 901 log.logError( BOT+" \""+bot.getName()+"\" could not connect ("+new Date()+")", error ); 902 } 903 } 904 905 public void disconnect() { 906 try { 907 bot.disconnect(); 908 } catch ( RuntimeException error ) { 909 log.logError( BOT+" \""+bot.getName()+"\" could not disconnect ("+new Date()+")", error ); 910 } 911 } 912 913 public void destroy() { 914 try { 915 bot.destroy(); 916 } catch ( RuntimeException error ) { 917 log.logError( BOT+" \""+bot.getName()+"\" failed during disconnect()", error ); 918 } 919 920 super.destroy(); 921 } 922 } 923 924 protected class VizManager extends TabManager { 925 // Private Data 926 ///////////////////////////////////////////////////////////////////////// 927 protected final VizTool viz; 928 929 // Public Methods 930 ///////////////////////////////////////////////////////////////////////// 931 public VizManager( VizTool viz, String name ) { 932 super( name ); 933 934 this.viz = viz; 935 936 client.setServerPort( serverVizPort ); 937 938 viz.init( tabLog ); 939 client.addListener( viz.getListener() ); 940 addTab( viz.getView() ); 941 } 942 } 943 }