1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * ident        "%Z%%M% %I%     %E% SMI"
  24  *
  25  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  26  * Use is subject to license terms.
  27  */
  28 package com.sun.dhcpmgr.client;
  29 
  30 import java.awt.*;
  31 import java.awt.event.*;
  32 import java.util.*;
  33 import java.net.*;
  34 import java.rmi.RemoteException;
  35 import java.rmi.NotBoundException;
  36 import javax.swing.*;
  37 import java.text.MessageFormat;
  38 import java.applet.AppletContext;
  39 
  40 import com.sun.dhcpmgr.ui.*;
  41 import com.sun.dhcpmgr.data.*;
  42 import com.sun.dhcpmgr.server.DhcpMgr;
  43 import com.sun.dhcpmgr.server.DhcpServiceMgr;
  44 import com.sun.dhcpmgr.bridge.BridgeException;
  45 import com.sun.dhcpmgr.bridge.NotRunningException;
  46 
  47 /**
  48  * Main class for DHCP Manager.  It is theoretically possible to run this
  49  * application as a command managing the local system, a command managing a
  50  * remote system using RMI, or as an applet managing the system from which it
  51  * was downloaded.  We presently only support the first option, but there is
  52  * vestigial code here from when the other options were supported as they may
  53  * be again.  That's why we extend JApplet.
  54  */
  55 public class DhcpmgrApplet extends JApplet {
  56     private static MainFrame frame = null;
  57     private JButton button;
  58     public static boolean modeIsRelay;
  59     private static HelpIds helpIds = null;
  60     private static URL docBase = null;
  61     private static AppletContext appletContext = null;
  62     private AddressView addressView;
  63     private RestartAction restartAction;
  64     private StopAction stopAction;
  65     private StartAction startAction;
  66     private DisableAction disableAction;
  67     private EnableAction enableAction;
  68     
  69     // Handler for Help->Overview menu item
  70     class OverviewAction extends MnemonicAction {
  71         public OverviewAction() {
  72             super(ResourceStrings.getString("overview_item"));
  73         }
  74         
  75         public void actionPerformed(ActionEvent e) {
  76             showHelp("overview");
  77         }
  78     }
  79     
  80     // Handler for Help->How To menu item
  81     class HowToAction extends MnemonicAction {
  82         public HowToAction() {
  83             super(ResourceStrings.getString("howto_item"));
  84         }
  85         
  86         public void actionPerformed(ActionEvent e) {
  87             showHelp("howto");
  88         }
  89     }
  90     
  91     // Handler for Help->Index menu item
  92     class IndexAction extends MnemonicAction {
  93         public IndexAction() {
  94             super(ResourceStrings.getString("index_item"));
  95         }
  96         
  97         public void actionPerformed(ActionEvent e) {
  98             showHelp("index");
  99         }
 100     }
 101     
 102     // Handler for Help->On Service menu item
 103     class ServiceAction extends MnemonicAction {
 104         public ServiceAction() {
 105             super(ResourceStrings.getString("on_service_item"));
 106         }
 107         
 108         public void actionPerformed(ActionEvent e) {
 109             showHelp("service_reference");
 110         }
 111     }
 112     
 113     // Handler for the Service->Restart menu item
 114     class RestartAction extends MnemonicAction {
 115         public RestartAction() {
 116             super(ResourceStrings.getString("restart_item"));
 117         }
 118         
 119         public void actionPerformed(ActionEvent e) {
 120             try {
 121                 DataManager.get().getDhcpServiceMgr().reload();
 122                 frame.setStatusText(
 123                     ResourceStrings.getString("service_restarted"));
 124             } catch (NotRunningException ex) {
 125                 // Server not running, ignore the error and just start it
 126                 startAction.actionPerformed(e);
 127             } catch (Throwable t) {
 128                 Object [] args = new Object[1];
 129                 MessageFormat form = new MessageFormat(
 130                     ResourceStrings.getString("restart_server_error"));
 131                 args[0] = t.getMessage();
 132                 JOptionPane.showMessageDialog(frame, form.format(args),
 133                     ResourceStrings.getString("server_error_title"),
 134                     JOptionPane.ERROR_MESSAGE);
 135             }
 136         }
 137     }
 138     
 139     // Handler for the Service->Stop menu item
 140     class StopAction extends MnemonicAction {
 141         public StopAction() {
 142             super(ResourceStrings.getString("stop_item"));
 143         }
 144         
 145         public void actionPerformed(ActionEvent e) {
 146             try {
 147                 DataManager.get().getDhcpServiceMgr().shutdown();
 148                 frame.setStatusText(
 149                     ResourceStrings.getString("service_stopped"));
 150                 startAction.setEnabled(true);
 151                 restartAction.setEnabled(false);
 152                 setEnabled(false);
 153             } catch (Throwable t) {
 154                 Object [] args = new Object[1];
 155                 MessageFormat form = new MessageFormat(
 156                     ResourceStrings.getString("shutdown_server_error"));
 157                 args[0] = t.getMessage();
 158                 JOptionPane.showMessageDialog(frame, form.format(args),
 159                     ResourceStrings.getString("server_error_title"),
 160                     JOptionPane.ERROR_MESSAGE);
 161             }
 162         }
 163     }
 164     
 165     // Handler for the Service->Restart menu item
 166     class StartAction extends MnemonicAction {
 167         public StartAction() {
 168             super(ResourceStrings.getString("start_item"));
 169         }
 170         
 171         public void actionPerformed(ActionEvent e) {
 172             try {
 173                 DataManager.get().getDhcpServiceMgr().startup();
 174                 frame.setStatusText(
 175                     ResourceStrings.getString("service_started"));
 176                 stopAction.setEnabled(true);
 177                 restartAction.setEnabled(true);
 178                 setEnabled(false);
 179             } catch (Throwable t) {
 180                 Object [] args = new Object[1];
 181                 MessageFormat form = new MessageFormat(
 182                     ResourceStrings.getString("startup_server_error"));
 183                 args[0] = t.getMessage();
 184                 JOptionPane.showMessageDialog(frame, form.format(args),
 185                     ResourceStrings.getString("server_error_title"),
 186                     JOptionPane.ERROR_MESSAGE);
 187             }
 188         }
 189     }
 190     
 191     // handler for the Service->Disable service menu item
 192     class DisableAction extends MnemonicAction {
 193         public DisableAction() {
 194             super(ResourceStrings.getString("disable_item"));
 195         }
 196         
 197         public void actionPerformed(ActionEvent e) {
 198             DisableServiceDialog d = new DisableServiceDialog(frame, true);
 199             d.addActionListener(new ActionListener() {
 200                 public void actionPerformed(ActionEvent e) {
 201                     // Update menu item state once we've disabled it
 202                     enableAction.setEnabled(true);
 203                     disableAction.setEnabled(false);
 204                     stopAction.setEnabled(false);
 205                     startAction.setEnabled(false);
 206                     restartAction.setEnabled(false);
 207                 }
 208             });
 209             d.pack();
 210             d.setVisible(true);
 211         }
 212     }
 213     
 214     // handler for the Service->Enable service menu item
 215     class EnableAction extends MnemonicAction {
 216         public EnableAction() {
 217             super(ResourceStrings.getString("enable_item"));
 218         }
 219         
 220         public void actionPerformed(ActionEvent e) {
 221             DisableServiceDialog d = new DisableServiceDialog(frame, false);
 222             d.addActionListener(new ActionListener() {
 223                 public void actionPerformed(ActionEvent e) {
 224                     // Update menu item state once we've enabled it
 225                     disableAction.setEnabled(true);
 226                     enableAction.setEnabled(false);
 227                     stopAction.setEnabled(true);
 228                     startAction.setEnabled(false);
 229                     restartAction.setEnabled(true);
 230                 }
 231             });
 232             d.pack();
 233             d.setVisible(true);
 234         }
 235     }
 236     
 237     // handler for the Service->Modify service menu item
 238     class ModifyServiceAction extends MnemonicAction {
 239         public ModifyServiceAction() {
 240             super(ResourceStrings.getString("modify_service_item"));
 241         }
 242         
 243         public void actionPerformed(ActionEvent e) {
 244             try {
 245                 DhcpdOptions opts =
 246                     DataManager.get().getDhcpServiceMgr().readDefaults();
 247                 ServerOptionsDialog d = new ServerOptionsDialog(frame, opts);
 248                 d.pack();
 249                 d.setVisible(true);
 250             } catch (BridgeException ex) {
 251                 // Error reading options
 252                 MessageFormat form = new MessageFormat(
 253                     ResourceStrings.getString("err_reading_options"));
 254                 Object [] args = new Object[] { ex.getMessage() };
 255                 JOptionPane.showMessageDialog(frame, form.format(args),
 256                     ResourceStrings.getString("server_error_title"),
 257                     JOptionPane.ERROR_MESSAGE);
 258             }
 259         }
 260     }
 261     
 262     // handler for the Service->Convert service menu item
 263     class ConvertAction extends MnemonicAction {
 264         public ConvertAction() {
 265             super(ResourceStrings.getString("cvt_service_item"));
 266 
 267         }
 268         
 269         public void actionPerformed(ActionEvent e) {
 270             ConvertWizard wiz = new ConvertWizard(frame,
 271                 ResourceStrings.getString("cvt_wiz_title"));
 272             wiz.addActionListener(new ActionListener() {
 273                 public void actionPerformed(ActionEvent e) {
 274                     if (e.getActionCommand().equals("finished")) {
 275                         frame.refreshAllViews();
 276                         showFrame();
 277                     }
 278                 }
 279             });
 280             wiz.pack();
 281             wiz.setModal(true);
 282             wiz.setVisible(true);
 283         }
 284 
 285         public void setEnabled(boolean b) {
 286             if (!modeIsRelay) {
 287                 super.setEnabled(b);
 288             } else {
 289                 super.setEnabled(false);
 290             }
 291         }
 292     }
 293 
 294     // handler for the Service->Unconfigure service menu item
 295     class UnconfigureServiceAction extends MnemonicAction {
 296         public UnconfigureServiceAction() {
 297             super(ResourceStrings.getString("unconfigure_service_item"));
 298         }
 299         
 300         public void actionPerformed(ActionEvent e) {
 301             UnconfigureDialog d = new UnconfigureDialog(frame);
 302             d.addActionListener(new ActionListener() {
 303                 public void actionPerformed(ActionEvent e) {
 304                     if (e.getActionCommand().equals(DialogActions.OK)) {
 305                         /*
 306                          * User unconfigured the service; there's nothing
 307                          * else to do so just get rid of the frame which
 308                          * will as a side effect shut us down.
 309                          */
 310                         frame.setVisible(false);
 311                         frame.dispose();
 312                         frame = null;
 313                     }
 314                 }
 315             });     
 316             d.pack();
 317             d.setVisible(true);
 318         }
 319     }
 320 
 321     // Action for Service->Export data
 322     class ExportAction extends MnemonicAction {
 323         public ExportAction() {
 324             super(ResourceStrings.getString("export_item"));
 325         }
 326         public void actionPerformed(ActionEvent e) {
 327             ExportWizard wiz = new ExportWizard(frame);
 328             wiz.addActionListener(new ActionListener() {
 329                 public void actionPerformed(ActionEvent e) {
 330                     if (e.getActionCommand().equals("finished")) {
 331                         frame.refreshAllViews();
 332                         showFrame();
 333                     }
 334                 }
 335             });
 336             wiz.pack();
 337             wiz.setVisible(true);
 338         }
 339     }
 340 
 341     // Action for Service->Import data
 342     class ImportAction extends MnemonicAction {
 343         public ImportAction() {
 344             super(ResourceStrings.getString("import_item"));
 345         }
 346 
 347         public void actionPerformed(ActionEvent e) {
 348             ImportWizard wiz = new ImportWizard(frame);
 349             wiz.addActionListener(new ActionListener() {
 350                 public void actionPerformed(ActionEvent e) {
 351                     if (e.getActionCommand().equals("finished")) {
 352                         frame.refreshAllViews();
 353                         showFrame();
 354                     }
 355                 }
 356             });
 357             wiz.pack();
 358             wiz.setVisible(true);
 359         }
 360     }
 361 
 362     /*
 363      * This class provides a transition dialog which allows the user
 364      * to initiate the address wizard immediately upon startup.  It's
 365      * done this way so that the startMeUp() method can use invokeLater()
 366      * to cause it to be displayed after the config wizard exit event
 367      * has been processed rather than during that event's processing;
 368      * otherwise the wizard doesn't disappear until after the user presses
 369      * Yes or No in this dialog.
 370      */
 371     class WizardTransition implements Runnable {
 372         public void run() {
 373             // Now transition to configuring addresses
 374             int status = JOptionPane.showConfirmDialog(frame,
 375                 ResourceStrings.getString("start_address_wizard"),
 376                 ResourceStrings.getString("start_address_wizard_title"),
 377                 JOptionPane.YES_NO_OPTION);
 378             if (status == JOptionPane.YES_OPTION) {
 379                 addressView.startAddressWizard();
 380             }
 381         }
 382     }
 383 
 384     /*
 385      * This class provides a transition dialog which allows the user
 386      * to initiate the conversion wizard immediately upon startup if a
 387      * version mismatch exists (a data store upgrade is necessary).
 388      */
 389     class ConversionTransition implements Runnable {
 390         public void run() {
 391             try {
 392                 DhcpServiceMgr svcMgr = DataManager.get().getDhcpServiceMgr();
 393                 while (!svcMgr.isVersionCurrent()) {
 394                     int status = JOptionPane.showConfirmDialog(frame,
 395                         ResourceStrings.getString("start_cvt_wizard"),
 396                         ResourceStrings.getString("start_cvt_wizard_title"),
 397                         JOptionPane.YES_NO_OPTION);
 398                     if (status == JOptionPane.YES_OPTION) {
 399                         ConvertAction converter = new ConvertAction();
 400                         ActionEvent e = new ActionEvent(this,
 401                             ActionEvent.ACTION_PERFORMED, "");
 402                         converter.actionPerformed(e);
 403                     } else {
 404                         frame = null;
 405                         DataManager.get().reset();
 406                         requestExit();
 407                     }
 408                 }
 409             } catch (Throwable e) {
 410                 System.err.println(
 411                     ResourceStrings.getString("err_initializing_program"));
 412                 System.err.println(e.getMessage());
 413                 requestExit();
 414             }
 415         }
 416     }
 417 
 418     // Create the frame within which the UI will live
 419     private void createFrame() {
 420         if (frame == null) {
 421         
 422             frame = new MainFrame(ResourceStrings.getString("dhcp_manager"));
 423             
 424             // Create the views for this tool
 425             if (modeIsRelay) {
 426                 frame.addView(new RelayView(), true);
 427             } else {
 428                 addressView = new AddressView();
 429                 frame.addView(addressView, true);
 430                 frame.addView(new MacroView(), false);
 431                 frame.addView(new OptionView(), false);
 432             }
 433             
 434             // Set up the services menu
 435             frame.addMenuAction(MainFrame.ACTIONS_MENU,
 436                 (restartAction = new RestartAction()));
 437             frame.addMenuAction(MainFrame.ACTIONS_MENU,
 438                 (stopAction = new StopAction()));
 439             frame.addMenuAction(MainFrame.ACTIONS_MENU,
 440                 (startAction = new StartAction()));
 441             frame.addMenuAction(MainFrame.ACTIONS_MENU,
 442                 (disableAction = new DisableAction()));
 443             frame.addMenuAction(MainFrame.ACTIONS_MENU,
 444                 (enableAction = new EnableAction()));
 445             frame.addMenuAction(MainFrame.ACTIONS_MENU,
 446                 new ModifyServiceAction());
 447             if (!modeIsRelay) {
 448                 frame.addMenuAction(MainFrame.ACTIONS_MENU,
 449                     new ExportAction());
 450                 frame.addMenuAction(MainFrame.ACTIONS_MENU,
 451                     new ImportAction());
 452                 frame.addMenuAction(MainFrame.ACTIONS_MENU,
 453                     new ConvertAction());
 454             }
 455             frame.addMenuAction(MainFrame.ACTIONS_MENU,
 456                 new UnconfigureServiceAction());
 457             
 458             // Set up the Help menu
 459             frame.addMenuAction(MainFrame.HELP_MENU, new OverviewAction());
 460             frame.addMenuAction(MainFrame.HELP_MENU, new HowToAction());
 461             frame.addMenuAction(MainFrame.HELP_MENU, new IndexAction());
 462             frame.addMenuAction(MainFrame.HELP_MENU, new ServiceAction());
 463             
 464             // In relay mode, let it size itself (quite small)
 465             if (modeIsRelay) {
 466                 frame.pack();
 467             } else {
 468                 /*
 469                  * Normal mode set it to a reasonable size.  This ought to be
 470                  * a user preference, but until we run as something other than
 471                  * root it's not really a useful idea.
 472                  */
 473                 frame.setSize(800, 600);
 474             }
 475             
 476             // Listen for closing events
 477             frame.addWindowListener(new WindowAdapter() {
 478                 public void windowClosing(WindowEvent e) {
 479                     /*
 480                      * This is here to work around the Close selection frame
 481                      * menu on Solaris not causing the closed function to be
 482                      * called
 483                      */
 484                     windowClosed(e);
 485                 }
 486                 public void windowClosed(WindowEvent e) {
 487                     // Dispose of all data and exit when window goes away.
 488                     frame = null;
 489                     DataManager.get().reset();
 490                     requestExit();
 491                 }
 492             });
 493         }
 494     }
 495     
 496     // Show the frame
 497     private void showFrame() {
 498         if (frame == null) {
 499             createFrame();
 500         }
 501         frame.initialize();
 502         if (modeIsRelay) {
 503             // Disable edit & view menus in the relay case
 504             frame.setMenuEnabled(MainFrame.EDIT_MENU, false);
 505             frame.setMenuEnabled(MainFrame.VIEW_MENU, false);
 506         }
 507         try {
 508             // Set status of service menu options based on server state
 509             DhcpdOptions opts =
 510                 DataManager.get().getDhcpServiceMgr().readDefaults();
 511             boolean enabled = opts.isDaemonEnabled();
 512             enableAction.setEnabled(!enabled);
 513             disableAction.setEnabled(enabled);
 514             boolean running =
 515                 DataManager.get().getDhcpServiceMgr().isServerRunning();
 516             restartAction.setEnabled(running && enabled);
 517             stopAction.setEnabled(running);
 518             startAction.setEnabled(!running && enabled);
 519         } catch (Throwable e) {
 520             // Enable all the menu items, as something went wrong
 521             restartAction.setEnabled(true);
 522             stopAction.setEnabled(true);
 523             startAction.setEnabled(true);
 524             enableAction.setEnabled(true);
 525             disableAction.setEnabled(true);
 526         }    
 527         frame.setVisible(true);
 528     }
 529     
 530     /*
 531      * main startup code; checks whether server is already configured, and if
 532      * not runs through the config wizard sequence in order to get the server
 533      * configured.
 534      */
 535     private void startMeUp() {
 536         try {
 537             if (DataManager.get().getServer() == null) {
 538                 DataManager.get().setServer(getCodeBase().getHost());
 539             }
 540 
 541             // See if server is already configured, and start up
 542             DhcpServiceMgr svcMgr = DataManager.get().getDhcpServiceMgr();
 543             DhcpdOptions opts = svcMgr.readDefaults();
 544             modeIsRelay = opts.isRelay();
 545             // If server mode, ensure RESOURCE and PATH were set
 546             if (!modeIsRelay) {
 547                 if ((opts.getResource() == null) || (opts.getPath() == null)) {
 548                     System.err.println(
 549                         ResourceStrings.getString("err_initializing_options"));
 550                     requestExit();
 551                 }
 552             }
 553             
 554             showFrame();
 555 
 556             // Check to make sure that the data store version is up to date.
 557             // If not, inform the user and present them with the conversion
 558             // wizard so that they can upgrade.
 559             if (!modeIsRelay && !svcMgr.isVersionCurrent()) {
 560                 SwingUtilities.invokeLater(new ConversionTransition());
 561             }
 562 
 563         } catch (BridgeException e) {
 564             // Let user select which type of service to configure
 565             int choice = ConfigureChoiceDialog.showDialog(frame);
 566             if (choice == ConfigureChoiceDialog.DHCP) {
 567                 // DHCP; run the wizard
 568                 ConfigWizard wiz = new ConfigWizard(frame,
 569                     ResourceStrings.getString("cfg_wiz_title"), true);
 570                 wiz.addActionListener(new ActionListener() {
 571                     public void actionPerformed(ActionEvent e) {
 572                         if (e.getActionCommand().equals("finished")) {
 573                             // Service config completed, start up
 574                             modeIsRelay = false;
 575                             showFrame();
 576                             // Now transition to configuring addresses
 577                             SwingUtilities.invokeLater(new WizardTransition());
 578                         } else {
 579                             // User cancelled the wizard, exit
 580                             requestExit();
 581                         }
 582                     }
 583                 });
 584                 wiz.pack();
 585                 wiz.setVisible(true);
 586             } else if (choice == ConfigureChoiceDialog.BOOTP) {
 587                 // Wants to configure a relay, show the dialog for that
 588                 ConfigureRelayDialog d = new ConfigureRelayDialog(frame);
 589                 d.addActionListener(new ActionListener() {
 590                     public void actionPerformed(ActionEvent e) {
 591                         if (e.getActionCommand().equals(DialogActions.OK)) {
 592                             // Relay configuration completed, start up
 593                             modeIsRelay = true;
 594                             showFrame();
 595                         } else {
 596                             // User cancelled, exit
 597                             requestExit();
 598                         }
 599                     }
 600                 });
 601                 d.pack();
 602                 d.setVisible(true);
 603             } else {
 604                 // User cancelled; exit
 605                 requestExit();
 606             }
 607         } catch (Throwable e) {
 608             // Couldn't really get started, dump the stack and exit
 609             System.err.println(
 610                 ResourceStrings.getString("err_initializing_program"));
 611             System.err.println(e.getMessage());
 612             e.printStackTrace();
 613             requestExit();
 614         }
 615     }
 616 
 617     // Show a help file referenced by tag
 618     public static void showHelp(String helpId) {
 619         // If help tag mapping table not loaded yet, then load it
 620         if (helpIds == null) {
 621             try {
 622                 helpIds = new HelpIds("com.sun.dhcpmgr.client.HelpBundle");
 623             } catch (Throwable e) {
 624                 // Error initializing help system
 625                 JOptionPane.showMessageDialog(frame,
 626                     ResourceStrings.getString("err_initializing_help"),
 627                     ResourceStrings.getString("server_error_title"),
 628                     JOptionPane.ERROR_MESSAGE);
 629                 return;
 630             }
 631         }
 632         // Ask browser to display
 633         try {
 634             Runtime.getRuntime().exec(
 635                     "/usr/sfw/bin/mozilla file:"
 636                     + helpIds.getFilePath(helpId));
 637         } catch (java.io.IOException e) {
 638             JOptionPane.showMessageDialog(frame,
 639                 ResourceStrings.getString("err_starting_help"),
 640                 ResourceStrings.getString("server_error_title"),
 641                 JOptionPane.ERROR_MESSAGE);
 642         }
 643     }
 644     
 645     // Exit the application
 646     private void requestExit() {
 647         System.exit(0);
 648     }
 649     
 650     // Main function when we're run as an application
 651     public static void main(String [] args) {
 652 
 653         // Ensure that we're running as root; exit if not
 654         if (!System.getProperty("user.name").equals("root")) {
 655             System.err.println(ResourceStrings.getString("err_must_be_root"));
 656             System.exit(0);
 657         }
 658 
 659         DhcpmgrApplet applet = new DhcpmgrApplet();
 660         applet.startMeUp();
 661     }
 662 }