opends/build.xml
@@ -80,6 +80,11 @@ <property name="quicksetup.src.dir" location="src/quicksetup" /> <property name="quicksetup.classes.dir" location="${build.dir}/quicksetup/classes" /> <!-- Properties for use with the Status Panel. --> <property name="statuspanel.src.dir" location="src/statuspanel" /> <property name="statuspanel.classes.dir" location="${build.dir}/statuspanel/classes" /> <!-- Properties for code coverage testing. --> <property name="coverage.dir" location="build/coverage" /> @@ -232,17 +237,23 @@ <taskdef resource="checkstyletask.properties" classpath="${checkstyle.dir}/checkstyle-all-4.1.jar" /> <checkstyle config="${checkstyle.dir}/opends-checkstyle.xml" <checkstyle config="${checkstyle.dir}/opends-checkstyle.xml" failOnViolation="true"> <fileset dir="${src.dir}" includes="**/*.java" /> <formatter type="plain" /> </checkstyle> <checkstyle config="${checkstyle.dir}/opends-checkstyle.xml" failOnViolation="true"> <fileset dir="${quicksetup.src.dir}" includes="**/*.java" /> <formatter type="plain" /> </checkstyle> <checkstyle config="${checkstyle.dir}/opends-checkstyle.xml" failOnViolation="true"> <fileset dir="${statuspanel.src.dir}" includes="**/*.java" /> <formatter type="plain" /> </checkstyle> <checkstyle config="${checkstyle.dir}/opends-doctarget-checkstyle.xml" failOnViolation="true"> @@ -270,7 +281,7 @@ <!-- Compile the Directory Server source files. --> <target name="cleancompile" depends="cleaninit,compile,compilequicksetup" <target name="cleancompile" depends="cleaninit,compile,compilequicksetup,compilestatuspanel" description="Recompile the Directory Server source files."> </target> @@ -322,6 +333,28 @@ includes="**/DynamicConstants.class **/SetupUtils.class" /> </copy> </target> <!-- Compile the Status Panel source files. --> <target name="compilestatuspanel" depends="compilequicksetup" description="Compile the Status Panel source files."> <mkdir dir="${statuspanel.classes.dir}" /> <javac srcdir="${statuspanel.src.dir}" destdir="${statuspanel.classes.dir}" optimize="true" debug="on" debuglevel="lines,source" source="1.5" target="1.5" deprecation="true" fork="true" memoryInitialSize="${MEM}" memoryMaximumSize="${MEM}"> <compilerarg value="-Xlint:all" /> <classpath> <pathelement path="${classes.dir}"/> <pathelement path="${quicksetup.classes.dir}"/> </classpath> </javac> <copy todir="${statuspanel.classes.dir}"> <fileset dir="${statuspanel.src.dir}" includes="**/*.properties, **/*.gif, **/*.png" /> </copy> </target> <!-- ! Rebuild the Directory Server without destroying any existing configuration @@ -351,6 +384,7 @@ <delete file="${pdir}.zip" /> <delete dir="${quicksetup.classes.dir}" /> <delete file="${package.dir}/lib/quicksetup.jar" /> <delete file="${package.dir}/lib/statuspanel.jar" /> <!-- Recreate the classes directory and recompile into it. --> <mkdir dir="${classes.dir}" /> @@ -401,6 +435,29 @@ <!-- Generate the quicksetup.jar file --> <jar jarfile="${pdir}/lib/quicksetup.jar" basedir="${quicksetup.classes.dir}" compress="true" index="true" /> <!-- Recreate the controlpanel classes directory and recompile into it. --> <mkdir dir="${controlpanel.classes.dir}" /> <javac srcdir="${controlpanel.src.dir}" destdir="${controlpanel.classes.dir}" optimize="true" debug="on" debuglevel="lines,source" source="1.5" target="1.5" deprecation="true" fork="true" memoryInitialSize="${MEM}" memoryMaximumSize="${MEM}"> <compilerarg value="-Xlint:all" /> <classpath> <fileset dir="${pdir}/lib"> <include name="OpenDS.jar" /> </fileset> </classpath> </javac> <copy todir="${controlpanel.classes.dir}"> <fileset dir="${controlpanel.src.dir}" includes="**/*.properties, **/*.gif, **/*.png"/> </copy> <!-- Generate the statuspanel.jar file --> <jar jarfile="${pdir}/lib/statuspanel.jar" basedir="${statuspanel.classes.dir}" compress="true" index="true" /> </target> @@ -436,6 +493,9 @@ <jar jarfile="${pdir}/lib/quicksetup.jar" basedir="${quicksetup.classes.dir}" compress="true" index="true" /> <jar jarfile="${pdir}/lib/statuspanel.jar" basedir="${statuspanel.classes.dir}" compress="true" index="true" /> <copy todir="${pdir}/lib"> <fileset file="${lib.dir}/*.jar" /> opends/resource/bin/status
New file @@ -0,0 +1,34 @@ #!/bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at # trunk/opends/resource/legal-notices/OpenDS.LICENSE # or https://OpenDS.dev.java.net/OpenDS.LICENSE. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at # trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, # add the following below this CDDL HEADER, with the fields enclosed # by brackets "[]" replaced with your own identifying * information: # Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Portions Copyright 2006 Sun Microsystems, Inc. # This script may be used to display the status panel. OPENDS_INVOKE_CLASS="org.opends.statuspanel.StatusCli" export OPENDS_INVOKE_CLASS SCRIPT_DIR=`dirname "${0}"` "${SCRIPT_DIR}/_server-script.sh" "${@}" opends/resource/bin/status.bat
New file @@ -0,0 +1,32 @@ @echo off rem CDDL HEADER START rem rem The contents of this file are subject to the terms of the rem Common Development and Distribution License, Version 1.0 only rem (the "License"). You may not use this file except in compliance rem with the License. rem rem You can obtain a copy of the license at rem trunk/opends/resource/legal-notices/OpenDS.LICENSE rem or https://OpenDS.dev.java.net/OpenDS.LICENSE. rem See the License for the specific language governing permissions rem and limitations under the License. rem rem When distributing Covered Code, include this CDDL HEADER in each rem file and include the License file at rem trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, rem add the following below this CDDL HEADER, with the fields enclosed rem by brackets "[]" replaced with your own identifying * information: rem Portions Copyright [yyyy] [name of copyright owner] rem rem CDDL HEADER END rem rem rem Portions Copyright 2006 Sun Microsystems, Inc. setlocal set OPENDS_INVOKE_CLASS="org.opends.statuspanel.StatusCli" set SCRIPT_NAME_ARG="-Dorg.opends.server.scriptName=status" call "%~dP0\_server-script.bat" %* opends/resource/bin/statuspanel
New file @@ -0,0 +1,34 @@ #!/bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at # trunk/opends/resource/legal-notices/OpenDS.LICENSE # or https://OpenDS.dev.java.net/OpenDS.LICENSE. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at # trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, # add the following below this CDDL HEADER, with the fields enclosed # by brackets "[]" replaced with your own identifying * information: # Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Portions Copyright 2006 Sun Microsystems, Inc. # This script may be used to display the status panel. OPENDS_INVOKE_CLASS="org.opends.statuspanel.StatusPanelLauncher" export OPENDS_INVOKE_CLASS SCRIPT_DIR=`dirname "${0}"` "${SCRIPT_DIR}/_server-script.sh" "${@}" opends/resource/bin/statuspanel.bat
New file @@ -0,0 +1,32 @@ @echo off rem CDDL HEADER START rem rem The contents of this file are subject to the terms of the rem Common Development and Distribution License, Version 1.0 only rem (the "License"). You may not use this file except in compliance rem with the License. rem rem You can obtain a copy of the license at rem trunk/opends/resource/legal-notices/OpenDS.LICENSE rem or https://OpenDS.dev.java.net/OpenDS.LICENSE. rem See the License for the specific language governing permissions rem and limitations under the License. rem rem When distributing Covered Code, include this CDDL HEADER in each rem file and include the License file at rem trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, rem add the following below this CDDL HEADER, with the fields enclosed rem by brackets "[]" replaced with your own identifying * information: rem Portions Copyright [yyyy] [name of copyright owner] rem rem CDDL HEADER END rem rem rem Portions Copyright 2006 Sun Microsystems, Inc. setlocal set OPENDS_INVOKE_CLASS="org.opends.statuspanel.StatusPanelLauncher" set SCRIPT_NAME_ARG="-Dorg.opends.server.scriptName=statuspanel" call "%~dP0\_server-script.bat" %* opends/src/quicksetup/org/opends/quicksetup/ButtonName.java
@@ -46,6 +46,10 @@ */ QUIT, /** * The Continue with install button. */ CONTINUE_INSTALL, /** * The Close button. */ CLOSE, @@ -56,5 +60,9 @@ /** * The Cancel button. */ CANCEL CANCEL, /** * The Launch Status Panel button. */ LAUNCH_STATUS_PANEL } opends/src/quicksetup/org/opends/quicksetup/CurrentInstallStatus.java
@@ -52,6 +52,8 @@ { private boolean isInstalled; private boolean canOverwriteCurrentInstall; private String installationMsg; private String configFileContents; @@ -77,24 +79,18 @@ isInstalled = false; } else { boolean dbFileExists = false; ArrayList<String> msgs = new ArrayList<String>(); if (isServerRunning()) { if (isConfigFileModified() || (getPort() != 389)) { /* * If the config file is not modified and the port is 389 the common * case is that there is already a server running on the default port, * so it does not correspond to this install. */ msgs.add(getMsg("installstatus-serverrunning", new String[] msgs.add(getMsg("installstatus-serverrunning", new String[] { String.valueOf(getPort()) })); } } if (dbFilesExist()) { dbFileExists = true; msgs.add(getMsg("installstatus-dbfileexist")); } @@ -102,8 +98,14 @@ { msgs.add(getMsg("installstatus-configfilemodified")); } canOverwriteCurrentInstall = (msgs.size() == 1) && dbFileExists; isInstalled = msgs.size() > 0; if (isInstalled) if (canOverwriteCurrentInstall) { installationMsg = getMsg("installstatus-canoverwritecurrentinstall-msg"); } else if (isInstalled) { StringBuffer buf = new StringBuffer(); buf.append("<ul>"); @@ -134,6 +136,18 @@ } /** * Indicates can overwrite current install. * * @return <CODE>true</CODE> if there is something installed under the * binaries that we are running and we can overwrite it and * <CODE>false</CODE> if not. */ public boolean canOverwriteCurrentInstall() { return canOverwriteCurrentInstall; } /** * Provides a localized message to be displayed to the user in HTML format * informing of the installation status. * opends/src/quicksetup/org/opends/quicksetup/QuickSetup.java
@@ -27,10 +27,12 @@ package org.opends.quicksetup; import java.io.File; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.swing.SwingUtilities; @@ -197,6 +199,10 @@ quitClicked(); break; case CONTINUE_INSTALL: continueInstallClicked(); break; case PREVIOUS: previousClicked(); break; @@ -205,6 +211,10 @@ cancelClicked(); break; case LAUNCH_STATUS_PANEL: launchStatusPanelClicked(); break; default: throw new IllegalArgumentException("Unknown button name: " + ev.getButtonName()); @@ -557,6 +567,25 @@ } /** * Method called when user clicks 'Continue' button in the case where there * is something installed. */ private void continueInstallClicked() { Step cStep = getCurrentStep(); switch (cStep) { case WELCOME: getDialog().forceToDisplaySetup(); setCurrentStep(Step.WELCOME); break; default: throw new IllegalStateException( "Continue only can be clicked on WELCOME step"); } } /** * Method called when user clicks 'Close' button of the wizard. * */ @@ -612,6 +641,64 @@ } } private void launchStatusPanelClicked() { BackgroundTask worker = new BackgroundTask() { public Object processBackgroundTask() throws UserInstallDataException { try { String cmd = Utils.isWindows()?"statuspanel.bat":"statuspanel"; String serverPath; if (Utils.isWebStart()) { serverPath = getUserInstallData().getServerLocation(); } else { serverPath = Utils.getInstallPathFromClasspath(); } cmd = Utils.getPath(serverPath, "bin"+File.separator+cmd); ProcessBuilder pb = new ProcessBuilder(new String[]{cmd}); Map<String, String> env = pb.environment(); env.put("JAVA_HOME", System.getProperty("java.home")); /* Remove JAVA_BIN to be sure that we use the JVM running the * uninstaller JVM to stop the server. */ env.remove("JAVA_BIN"); Process process = pb.start(); int returnValue = process.waitFor(); if (returnValue != 0) { throw new Error(getMsg("could-not-launch-status-panel-msg")); } } catch (Throwable t) { // This looks like a bug t.printStackTrace(); throw new Error(getMsg("could-not-launch-status-panel-msg")); } return null; } public void backgroundTaskCompleted(Object returnValue, Throwable throwable) { getDialog().workerFinished(); if (throwable != null) { displayError(throwable.getMessage(), getMsg("error-title")); } } }; getDialog().workerStarted(); worker.startBackgroundTask(); } /** * Method called when we want to quit the setup (for instance when the user * clicks on 'Close' or 'Quit' buttons and has confirmed that (s)he wants to opends/src/quicksetup/org/opends/quicksetup/SplashScreen.java
@@ -41,12 +41,18 @@ import org.opends.quicksetup.util.Utils; /** * This is the class that is called to launch QuickSetup. It will display a * splash screen and in the background it will create QuickSetup object. * This is the class that displays a splash screen and in the background it will * create QuickSetup object. * * The main method of this class is directly called by the Java Web Start * mechanism to launch the JWS setup. * * This class tries to minimize the time to be displayed. So it does the loading * of the setup class in runtime once we already have displayed the splash * screen. This is why the quickSetup variable is of type Object. * * This class can be reused by simply overwriting the methods * constructApplication() and displayApplication(). */ public class SplashScreen extends Window { @@ -54,11 +60,9 @@ private Image image; private static SplashScreen splash; private Object quickSetup; private static Object quickSetup; private static Class<?> quickSetupClass; private Class<?> quickSetupClass; // Constant for the display of the splash screen private static final int MIN_SPLASH_DISPLAY = 3000; @@ -70,21 +74,8 @@ */ public static void main(String[] args) { if (SwingUtilities.isEventDispatchThread()) { final String[] fArgs = args; Thread t = new Thread(new Runnable() { public void run() { mainOutsideEventThread(fArgs); } }); t.start(); } else { mainOutsideEventThread(args); } SplashScreen screen = new SplashScreen(); screen.display(args); } /** @@ -104,10 +95,10 @@ } /** * Private constructor to force to use the main method. * Protected constructor to force to use the main method. * */ private SplashScreen() protected SplashScreen() { super(new Frame()); try @@ -130,6 +121,31 @@ } /** * The method used to display the splash screen. It will also call create * the application associated with this SplashScreen and display it. * It can be called from the event thread and outside the event thread. * @param args arguments to be passed to the method QuickSetup.initialize */ protected void display(String[] args) { if (SwingUtilities.isEventDispatchThread()) { final String[] fArgs = args; Thread t = new Thread(new Runnable() { public void run() { mainOutsideEventThread(fArgs); } }); t.start(); } else { mainOutsideEventThread(args); } } /** * This method creates the image directly instead of using UIFactory to reduce * class loading. * @return the splash image. @@ -148,30 +164,29 @@ * * @param args arguments to be passed to the method QuickSetup.initialize. */ private static void mainOutsideEventThread(String[] args) private void mainOutsideEventThread(String[] args) { displaySplashScreen(); long splashDisplayStartTime = System.currentTimeMillis(); constructQuickSetup(args); constructApplication(args); sleepIfNecessary(splashDisplayStartTime); disposeSplashScreen(); displayQuickSetup(); displayApplication(); } /** * This methods displays the splash screen. * This method assumes that is being called outside the event thread. */ private static void displaySplashScreen() private void displaySplashScreen() { splash = new SplashScreen(); try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { splash.setVisible(true); setVisible(true); } }); } catch (Exception ex) @@ -181,11 +196,13 @@ } /** * This methods constructs the QuickSetup object. * This methods constructs the objects before displaying them. * This method assumes that is being called outside the event thread. * @param args arguments to be passed to the method QuickSetup.initialize. * This method can be overwritten by subclasses to construct other objects * different than the Quick Setup. * @param args arguments passed in the main of this class. */ private static void constructQuickSetup(String[] args) protected void constructApplication(String[] args) { try { @@ -207,8 +224,10 @@ * This method displays the QuickSetup dialog. * @see QuickSetup.display. * This method assumes that is being called outside the event thread. * This method can be overwritten by subclasses to construct other objects * different than the Quick Setup. */ private static void displayQuickSetup() protected void displayApplication() { try { @@ -237,7 +256,7 @@ * Disposes the splash screen. * This method assumes that is being called outside the event thread. */ private static void disposeSplashScreen() private void disposeSplashScreen() { try { @@ -245,8 +264,8 @@ { public void run() { splash.setVisible(false); splash.dispose(); setVisible(false); dispose(); } }); } catch (Exception ex) @@ -262,7 +281,7 @@ * @param splashDisplayStartTime the time in milliseconds when the splash * screen started displaying. */ private static void sleepIfNecessary(long splashDisplayStartTime) private void sleepIfNecessary(long splashDisplayStartTime) { long t2 = System.currentTimeMillis(); opends/src/quicksetup/org/opends/quicksetup/i18n/ResourceProvider.java
@@ -49,7 +49,11 @@ private static final String BUNDLE_NAME = "org.opends.quicksetup.resources.Resources"; private ResourceProvider() /** * This constructor is protected to be able to subclass. * */ protected ResourceProvider() { } opends/src/quicksetup/org/opends/quicksetup/images/divider-left.png
opends/src/quicksetup/org/opends/quicksetup/images/divider-right.png
opends/src/quicksetup/org/opends/quicksetup/images/error_large.gif
opends/src/quicksetup/org/opends/quicksetup/images/error_medium.gif
opends/src/quicksetup/org/opends/quicksetup/images/error_small.gif
opends/src/quicksetup/org/opends/quicksetup/images/help_large.gif
opends/src/quicksetup/org/opends/quicksetup/images/help_medium.gif
opends/src/quicksetup/org/opends/quicksetup/images/help_small.gif
opends/src/quicksetup/org/opends/quicksetup/images/info_large.gif
opends/src/quicksetup/org/opends/quicksetup/images/info_medium.gif
opends/src/quicksetup/org/opends/quicksetup/images/info_small.gif
opends/src/quicksetup/org/opends/quicksetup/images/opends_logo_small.png
opends/src/quicksetup/org/opends/quicksetup/images/warning_large.gifopends/src/quicksetup/org/opends/quicksetup/images/warning_medium.gif
opends/src/quicksetup/org/opends/quicksetup/images/warning_small.gif
opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
@@ -41,6 +41,7 @@ import org.opends.quicksetup.event.InstallProgressUpdateEvent; import org.opends.quicksetup.event.InstallProgressUpdateListener; import org.opends.quicksetup.i18n.ResourceProvider; import org.opends.quicksetup.ui.UIFactory; import org.opends.quicksetup.util.ProgressMessageFormatter; import org.opends.quicksetup.util.Utils; import org.opends.server.util.SetupUtils; @@ -1039,10 +1040,20 @@ hmSummary.put(InstallProgressStep.STARTING_SERVER, getFormattedSummary(getMsg("summary-starting"))); String[] arg = {formatter.getFormattedText(getInstallationPath())}; String cmd; if (Utils.isWindows()) { cmd = "bin"+File.separator+"statuspanel.bat"; } else { cmd = "bin"+File.separator+"statuspanel"; } cmd = UIFactory.applyFontToHtml(cmd, UIFactory.INSTRUCTIONS_MONOSPACE_FONT); String[] args = {formatter.getFormattedText(getInstallationPath()), cmd}; hmSummary.put(InstallProgressStep.FINISHED_SUCCESSFULLY, getFormattedSuccess( getMsg("summary-install-finished-successfully", arg))); getMsg("summary-install-finished-successfully", args))); hmSummary.put(InstallProgressStep.FINISHED_WITH_ERROR, getFormattedError(getMsg("summary-install-finished-with-error"))); } opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
@@ -109,6 +109,8 @@ */ private void doInstall() { PrintStream origErr = System.err; PrintStream origOut = System.out; try { PrintStream err = new ErrorPrintStream(); @@ -171,6 +173,8 @@ String msg = getFormattedError(ex, true); notifyListeners(msg); } System.setErr(origErr); System.setOut(origOut); } /** opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
@@ -129,6 +129,8 @@ */ private void doInstall() { PrintStream origErr = System.err; PrintStream origOut = System.out; try { PrintStream err = new ErrorPrintStream(); @@ -195,6 +197,8 @@ String msg = getFormattedError(ex, true); notifyListeners(msg); } System.setErr(origErr); System.setOut(origOut); } /** opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
@@ -1,3 +1,31 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at # trunk/opends/resource/legal-notices/OpenDS.LICENSE # or https://OpenDS.dev.java.net/OpenDS.LICENSE. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at # trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, # add the following below this CDDL HEADER, with the fields enclosed # by brackets "[]" replaced with your own identifying * information: # Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # This file contains the primary Directory Server configuration. It must not # be directly edited while the server is online. The server configuration # should only be managed using the administration utilities provided with the # Directory Server. # # Setup command line messages # @@ -51,8 +79,8 @@ -w {password} or --rootUserPassword {password}\n Specifies the password \ of the Administrative User (Directory Manager) of the Directory Server.\n\ -W {filename} or --rootUserPasswordFile {filename}\n Specifies the path \ to a file containing the password for the initial Administrative\n\ User \ for the Directory Server.\n\ to a file containing the password for the Administrative\n\ User \ of the Directory Server.\n\ -s or --silentUninstall\n Perform a silent uninstall. uninstall-launcher-usage-unix=This utility may be used to uninstall the \ Directory Server.\n\ @@ -156,6 +184,8 @@ cancel-button-label=Cancel cancel-button-uninstall-tooltip=Cancel Uninstall shutdown-button-label=Shutdown continue-button-label=Continue continue-button-install-tooltip=Continue with the QuickSetup Tool # # Confirmation dialogs @@ -187,6 +217,12 @@ error-title=Error # # Error when we cannot launch the status panel # could-not-launch-status-panel-msg=An unexpected error occurred launching the \ Status Panel. # # Browser launching error dialog # error-browser-display-msg=Could not launch the web browser.<br>You can copy \ @@ -288,12 +324,16 @@ warning-icon-description=Warning. error-icon-description=Error. information-icon-description=Information. opends-small-icon-description=OpenDS icon. subsection-left-icon-description=Decoration icon. subsection-right-icon-description=Decoration icon. help-small-icon-description=Help icon. # # Icon tooltips. # current-step-icon-tooltip=Current Step Indicator splash-icon-tooltip=Open DS QuickSetup Launching splash-icon-tooltip=OpenDS QuickSetup Launching minimized-icon-tooltip=OpenDS QuickSetup background-icon-tooltip=OpenDS QuickSetup warning-icon-tooltip=Warning @@ -311,10 +351,16 @@ minimized-mac-icon=images/opendsminimizedmac.png splash-icon=images/opendssplash.png background-icon=images/opendsbackground.png error-icon=images/error.gif warning-icon=images/warning.gif error-icon=images/error_small.gif error-large-icon=images/error_large.gif warning-icon=images/warning_small.gif warning-large-icon=images/warning_large.gif information-icon=images/information.gif information-icon=images/info_small.gif information-large-icon=images/info_large.gif subsection-left-icon=images/divider-left.png subsection-right-icon=images/divider-right.png opends-small-icon=images/opends_logo_small.png help-small-icon=images/help_small.gif # # Welcome Panel specific labels @@ -486,7 +532,9 @@ Successfully.</b><br>OpenDS is now installed in {0}.<br><br>Visit the \ <a href="https://opends.dev.java.net/public/docs/user-docs/OpenDS-QuickReference.html"> \ OpenDS Quick Reference</a> page for an overview of server management and \ configuration. configuration.<br>To see basic server configuration status and to start/stop \ the server, click Launch Status Panel. Note that you can launch this tool \ later using {1}.<br><INPUT type="submit" value="Launch Status Panel"></INPUT> summary-install-finished-with-error=An error occurred. Check 'Details' text \ area for more information. summary-stopping=Stopping Directory Server... @@ -587,3 +635,6 @@ QuickSetup can only be used with OpenDS Servers that have not yet been \ configured. The current server:{0} installstatus-not-installed=The Directory Server is not installed. installstatus-canoverwritecurrentinstall-msg=The Directory Server contains \ some database files.<br>If you continue with the setup the contents of these \ database files will be deleted. opends/src/quicksetup/org/opends/quicksetup/ui/CurrentStepPanel.java
@@ -34,6 +34,7 @@ import org.opends.quicksetup.CurrentInstallStatus; import org.opends.quicksetup.Step; import org.opends.quicksetup.event.ButtonActionListener; import org.opends.quicksetup.installer.FieldName; import org.opends.quicksetup.installer.InstallProgressDescriptor; import org.opends.quicksetup.installer.UserInstallData; @@ -167,6 +168,31 @@ } /** * Adds a button listener. All the button listeners will be notified when * the buttons are clicked (by the user or programatically). * @param l the ButtonActionListener to be added. */ public void addButtonActionListener(ButtonActionListener l) { for (Step s : hmPanels.keySet()) { getPanel(s).addButtonActionListener(l); } } /** * Removes a button listener. * @param l the ButtonActionListener to be removed. */ public void removeButtonActionListener(ButtonActionListener l) { for (Step s : hmPanels.keySet()) { getPanel(s).removeButtonActionListener(l); } } /** * Displays the panel corresponding to the provided step. The panel contents * are updated with the contents of the UserInstallData object. * @param step the step that we want to display. opends/src/quicksetup/org/opends/quicksetup/ui/CustomHTMLEditorKit.java
New file @@ -0,0 +1,125 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.quicksetup.ui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashSet; import javax.swing.text.Element; import javax.swing.text.View; import javax.swing.text.ViewFactory; import javax.swing.text.html.FormView; import javax.swing.text.html.HTMLEditorKit; /** * Class used to be able to detect events in the button inside an HTML pane. */ class CustomHTMLEditorKit extends HTMLEditorKit { private HashSet<ActionListener> listeners = new HashSet<ActionListener>(); private static final long serialVersionUID = 298103926252426388L; /** * Default constructor. */ CustomHTMLEditorKit() { super(); } /** * {@inheritDoc} */ public ViewFactory getViewFactory() { return new MyHTMLFactory(); } /** * Adds an action listener. * @param l the action listener to add. */ public void addActionListener(ActionListener l) { listeners.add(l); } /** * Removes an action listener. * @param l the action listener to remove. */ public void removeActionListener(ActionListener l) { listeners.remove(l); } /** * Class used to be able to detect events in the button inside an HTML pane. */ class MyHTMLFactory extends HTMLFactory { /** * {@inheritDoc} */ public View create(Element elem) { View v = super.create(elem); if (v instanceof FormView) { v = new MyFormView(elem); } return v; } } /** * Class used to be able to detect events in the button inside an HTML pane. */ class MyFormView extends FormView { /** * {@inheritDoc} */ MyFormView(Element elem) { super(elem); } /** * {@inheritDoc} */ public void actionPerformed(ActionEvent ev) { for (ActionListener l: listeners) { l.actionPerformed(ev); } } } } opends/src/quicksetup/org/opends/quicksetup/ui/DirectoryManagerAuthenticationDialog.java
@@ -185,7 +185,7 @@ gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.anchor = GridBagConstraints.NORTHWEST; gbc.insets = UIFactory.getCurrentStepPanelInsets(); p1.add(UIFactory.makeJLabel(UIFactory.IconType.WARNING_LARGE, null, p1.add(UIFactory.makeJLabel(UIFactory.IconType.INFORMATION_LARGE, null, UIFactory.TextStyle.NO_STYLE), gbc); gbc.weightx = 1.0; gbc.fill = GridBagConstraints.BOTH; @@ -195,6 +195,7 @@ JTextComponent textPane = UIFactory.makeHtmlPane(msg, UIFactory.INSTRUCTIONS_FONT); textPane.setOpaque(false); textPane.setEditable(false); p1.add(textPane, gbc); JPanel p2 = new JPanel(new GridBagLayout()); opends/src/quicksetup/org/opends/quicksetup/ui/ProgressPanel.java
@@ -30,6 +30,8 @@ import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.Box; import javax.swing.JEditorPane; @@ -40,6 +42,8 @@ import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import org.opends.quicksetup.ButtonName; import org.opends.quicksetup.event.ButtonEvent; import org.opends.quicksetup.installer.InstallProgressDescriptor; import org.opends.quicksetup.installer.InstallProgressStep; import org.opends.quicksetup.uninstaller.UninstallProgressDescriptor; @@ -87,9 +91,22 @@ gbc.weightx = 1.0; gbc.fill = GridBagConstraints.HORIZONTAL; progressBarLabel = UIFactory.makeHtmlPane(getMsg("progressbar-initial-label"), UIFactory.PROGRESS_FONT); progressBarLabel = UIFactory.makeHtmlPane( getMsg("progressbar-initial-label"), UIFactory.PROGRESS_FONT); progressBarLabel.setOpaque(false); progressBarLabel.setEditable(false); CustomHTMLEditorKit htmlEditor = new CustomHTMLEditorKit(); htmlEditor.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { // Assume is the authentication button. ButtonEvent be = new ButtonEvent(ev.getSource(), ButtonName.LAUNCH_STATUS_PANEL); notifyButtonListeners(be); } }); progressBarLabel.setEditorKit(htmlEditor); progressBarLabel.addHyperlinkListener(this); panel.add(progressBarLabel, gbc); @@ -159,9 +176,15 @@ */ public void displayProgress(InstallProgressDescriptor descriptor) { progressBarLabel.setText(UIFactory.applyFontToHtml(descriptor .getProgressBarMsg(), UIFactory.PROGRESS_FONT)); InstallProgressStep status = descriptor.getProgressStep(); String summaryText = UIFactory.applyFontToHtml(descriptor .getProgressBarMsg(), UIFactory.PROGRESS_FONT); if (status == InstallProgressStep.FINISHED_SUCCESSFULLY) { summaryText = "<form>"+summaryText+"</form>"; } progressBarLabel.setText(summaryText); if ((status == InstallProgressStep.FINISHED_WITH_ERROR) || (status == InstallProgressStep.FINISHED_SUCCESSFULLY)) { @@ -182,9 +205,15 @@ */ public void displayProgress(UninstallProgressDescriptor descriptor) { progressBarLabel.setText(UIFactory.applyFontToHtml(descriptor .getProgressBarMsg(), UIFactory.PROGRESS_FONT)); UninstallProgressStep status = descriptor.getProgressStep(); String summaryText = UIFactory.applyFontToHtml(descriptor .getProgressBarMsg(), UIFactory.PROGRESS_FONT); if (status == UninstallProgressStep.FINISHED_SUCCESSFULLY) { summaryText = "<form>"+summaryText+"</form>"; } progressBarLabel.setText(summaryText); if ((status == UninstallProgressStep.FINISHED_WITH_ERROR) || (status == UninstallProgressStep.FINISHED_SUCCESSFULLY)) { opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupDialog.java
@@ -27,6 +27,7 @@ package org.opends.quicksetup.ui; import java.awt.event.ComponentListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.HashSet; @@ -87,6 +88,8 @@ private HashSet<ButtonActionListener> buttonListeners = new HashSet<ButtonActionListener>(); private boolean forceToDisplaySetup; /** * Constructor of QuickSetupDialog. * @param defaultUserData the default values to be proposed to the user in @@ -123,10 +126,10 @@ // Simulate a quit button event notifyButtonEvent(ButtonName.QUIT); } } else if (isInstalled()) } else if (isInstalled() && !forceToDisplaySetup) { // Simulate a close button event notifyButtonEvent(ButtonName.CLOSE); notifyButtonEvent(ButtonName.QUIT); } else { if (getDisplayedStep() == Step.PROGRESS) @@ -166,12 +169,19 @@ if (isUninstall()) { setFocusOnButton(ButtonName.FINISH); } else if (!isInstalled()) } else if (!isInstalled() || forceToDisplaySetup) { setFocusOnButton(ButtonName.NEXT); } else { setFocusOnButton(ButtonName.QUIT); if (installStatus.canOverwriteCurrentInstall()) { setFocusOnButton(ButtonName.CONTINUE_INSTALL); } else { setFocusOnButton(ButtonName.QUIT); } } frame.addComponentListener(new MinimumSizeComponentListener(frame, @@ -181,6 +191,36 @@ } /** * This method is called when we detected that there is something installed * we inform of this to the user and the user wants to proceed with the * installation destroying the contents of the data and the configuration * in the current installation. * */ public void forceToDisplaySetup() { forceToDisplaySetup = true; frame.getContentPane().removeAll(); frame.getContentPane().add(getFramePanel()); frame.pack(); Utils.centerOnScreen(frame); setFocusOnButton(ButtonName.NEXT); int minWidth = (int) frame.getPreferredSize().getWidth(); int minHeight = (int) frame.getPreferredSize().getHeight(); ComponentListener[] listeners = frame.getComponentListeners(); for (int i=0; i<listeners.length; i++) { if (listeners[i] instanceof MinimumSizeComponentListener) { frame.removeComponentListener(listeners[i]); } } frame.addComponentListener(new MinimumSizeComponentListener(frame, minWidth, minHeight)); } /** * Displays the panel corresponding to the provided step. The panel contents * are updated with the contents of the UserInstallData object. * @param step the step that we want to display. @@ -221,7 +261,7 @@ setButtonEnabled(ButtonName.CLOSE, false); break; } } else if (!isInstalled()) } else if (!isInstalled() || forceToDisplaySetup) { // First call the panels to do the required updates on their layout getButtonsPanel().setDisplayedStep(step); @@ -380,16 +420,11 @@ */ public void addButtonActionListener(ButtonActionListener l) { if (isUninstall()) { getButtonsPanel().addButtonActionListener(l); } else if (isInstalled()) { getInstalledPanel().addButtonActionListener(l); } else { getButtonsPanel().addButtonActionListener(l); } getButtonsPanel().addButtonActionListener(l); getInstalledPanel().addButtonActionListener(l); getButtonsPanel().addButtonActionListener(l); getCurrentStepPanel().addButtonActionListener(l); buttonListeners.add(l); } @@ -402,7 +437,7 @@ if (isUninstall()) { getButtonsPanel().removeButtonActionListener(l); } else if (isInstalled()) } else if (isInstalled() && !forceToDisplaySetup) { getInstalledPanel().removeButtonActionListener(l); } else @@ -519,7 +554,7 @@ getButtonsPanel()); } p = framePanel; } else if (isInstalled()) } else if (isInstalled() && !forceToDisplaySetup) { p = getInstalledPanel(); } else @@ -598,11 +633,14 @@ if (isUninstall()) { button = getButtonsPanel().getButton(buttonName); } else if (isInstalled()) } else if (isInstalled() && !forceToDisplaySetup) { if (buttonName == ButtonName.QUIT) { button = getInstalledPanel().getQuitButton(); } else if (buttonName == ButtonName.CONTINUE_INSTALL) { button = getInstalledPanel().getContinueInstallButton(); } else { throw new IllegalStateException("Invalid button name " + buttonName @@ -686,8 +724,7 @@ { if (installedPanel == null) { installedPanel = new QuickSetupErrorPanel(installStatus.getInstallationMsg()); installedPanel = new QuickSetupErrorPanel(installStatus); } return installedPanel; } opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupErrorPanel.java
@@ -39,6 +39,7 @@ import javax.swing.text.JTextComponent; import org.opends.quicksetup.ButtonName; import org.opends.quicksetup.CurrentInstallStatus; import org.opends.quicksetup.event.ButtonActionListener; import org.opends.quicksetup.event.ButtonEvent; @@ -56,13 +57,14 @@ new HashSet<ButtonActionListener>(); private JButton quitButton; private JButton continueButton; /** * Constructor of the QuickSetupErrorPanel. * * @param htmlMsg the error message to be displayed. * @param installStatus the current install status. */ public QuickSetupErrorPanel(String htmlMsg) public QuickSetupErrorPanel(CurrentInstallStatus installStatus) { JPanel p1 = new JPanel(new GridBagLayout()); p1.setBackground(UIFactory.CURRENT_STEP_PANEL_BACKGROUND); @@ -78,8 +80,10 @@ gbc.fill = GridBagConstraints.BOTH; gbc.insets.left = 0; JTextComponent tf = UIFactory.makeHtmlPane(htmlMsg, UIFactory.INSTRUCTIONS_FONT); UIFactory.makeHtmlPane(installStatus.getInstallationMsg(), UIFactory.INSTRUCTIONS_FONT); tf.setOpaque(false); tf.setEditable(false); p1.add(tf, gbc); gbc.weighty = 1.0; @@ -91,29 +95,53 @@ gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1.0; gbc.insets = UIFactory.getEmptyInsets(); gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.gridwidth = 3; p2.add(Box.createHorizontalGlue(), gbc); quitButton = UIFactory.makeJButton(getMsg("quit-button-label"), getMsg("quit-button-install-tooltip")); final ButtonName fButtonName = ButtonName.QUIT; final ButtonName fQuitButtonName = ButtonName.QUIT; ActionListener actionListener = new ActionListener() ActionListener quitListener = new ActionListener() { public void actionPerformed(ActionEvent ev) { ButtonEvent be = new ButtonEvent(ev.getSource(), fButtonName); ButtonEvent be = new ButtonEvent(ev.getSource(), fQuitButtonName); for (ButtonActionListener li : buttonListeners) { li.buttonActionPerformed(be); } } }; quitButton.addActionListener(actionListener); quitButton.addActionListener(quitListener); continueButton = UIFactory.makeJButton(getMsg("continue-button-label"), getMsg("continue-button-install-tooltip")); final ButtonName fContinueButtonName = ButtonName.CONTINUE_INSTALL; ActionListener continueListener = new ActionListener() { public void actionPerformed(ActionEvent ev) { ButtonEvent be = new ButtonEvent(ev.getSource(), fContinueButtonName); for (ButtonActionListener li : buttonListeners) { li.buttonActionPerformed(be); } } }; continueButton.addActionListener(continueListener); gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0.0; gbc.gridwidth = GridBagConstraints.RELATIVE; p2.add(continueButton, gbc); continueButton.setVisible(installStatus.canOverwriteCurrentInstall()); gbc.insets.left = UIFactory.HORIZONTAL_INSET_BETWEEN_BUTTONS; gbc.gridwidth = GridBagConstraints.REMAINDER; p2.add(quitButton, gbc); @@ -158,4 +186,13 @@ { return quitButton; } /** * Returns the continue install button. * @return the continue install button. */ public JButton getContinueInstallButton() { return continueButton; } } opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupStepPanel.java
@@ -32,6 +32,7 @@ import java.awt.GridBagLayout; import java.util.HashMap; import java.util.HashSet; import javax.swing.Box; import javax.swing.JEditorPane; @@ -41,6 +42,8 @@ import javax.swing.event.HyperlinkListener; import javax.swing.text.JTextComponent; import org.opends.quicksetup.event.ButtonActionListener; import org.opends.quicksetup.event.ButtonEvent; import org.opends.quicksetup.installer.FieldName; import org.opends.quicksetup.installer.InstallProgressDescriptor; import org.opends.quicksetup.installer.LabelFieldDescriptor; @@ -63,6 +66,9 @@ { private Component inputPanel; private HashSet<ButtonActionListener> buttonListeners = new HashSet<ButtonActionListener>(); private ProgressMessageFormatter formatter; /* We can use a HashMap (not multi-thread safe) because all @@ -190,6 +196,37 @@ return height; } /** * Adds a button listener. All the button listeners will be notified when * the buttons are clicked (by the user or programatically). * @param l the ButtonActionListener to be added. */ public void addButtonActionListener(ButtonActionListener l) { buttonListeners.add(l); } /** * Removes a button listener. * @param l the ButtonActionListener to be removed. */ public void removeButtonActionListener(ButtonActionListener l) { buttonListeners.remove(l); } /** * Notifies the button action listeners that an event occurred. * @param ev the button event to be notified. */ protected void notifyButtonListeners(ButtonEvent ev) { for (ButtonActionListener l : buttonListeners) { l.buttonActionPerformed(ev); } } /** * Creates the layout of the panel. * opends/src/quicksetup/org/opends/quicksetup/ui/UIFactory.java
@@ -77,6 +77,11 @@ public static final int HORIZONTAL_INSET_BETWEEN_BUTTONS = 5; /** * Specifies the horizontal inset for the control panel sub section. */ public static final int HORIZONTAL_INSET_CONTROL_PANEL_SUBSECTION = 20; /** * Specifies the top inset for the steps. */ public static final int TOP_INSET_STEP = 15; @@ -142,6 +147,11 @@ public static final int TOP_INSET_BROWSE = 5; /** * Specifies the top inset for the control panel sub section. */ public static final int TOP_INSET_CONTROL_PANEL_SUBSECTION = 30; /** * Specifies the right inset for background image. */ public static final int RIGHT_INSET_BACKGROUND = 20; @@ -293,10 +303,15 @@ public static final Color PASSWORD_FIELD_COLOR = Color.BLACK; /** * Specifies the panel border color. */ public static final Color PANEL_BORDER_COLOR = new Color(204, 204, 204); /** * Specifies the current step panel border. */ public static final Border CURRENT_STEP_PANEL_BORDER = BorderFactory.createMatteBorder(0, 2, 2, 0, new Color(204, 204, 204)); BorderFactory.createMatteBorder(0, 2, 2, 0, PANEL_BORDER_COLOR); /** * Specifies the text area border. @@ -308,7 +323,7 @@ * Specifies the dialog border. */ public static final Border DIALOG_PANEL_BORDER = BorderFactory.createMatteBorder(0, 0, 2, 0, new Color(204, 204, 204)); BorderFactory.createMatteBorder(0, 0, 2, 0, PANEL_BORDER_COLOR); /** * Specifies the font for the step which is not the current one in the steps @@ -498,18 +513,42 @@ */ WARNING, /** * The error icon. */ ERROR, /** * The warning large icon. */ WARNING_LARGE, /** * The error icon. */ ERROR, /** * The error large icon. */ ERROR_LARGE, /** * The information icon. */ INFORMATION, /** * The information large icon. */ INFORMATION_LARGE, /** * Icon of OpenDS. */ OPENDS_SMALL, /** * Icon to create subsection title in Status Panel. */ SUBSECTION_LEFT, /** * Icon to create subsection title in Status Panel. */ SUBSECTION_RIGHT, /** * Question icon. */ HELP_SMALL, /** * No icon. */ NO_ICON @@ -1194,12 +1233,36 @@ key = "information-icon"; break; case INFORMATION_LARGE: key = "information-large-icon"; break; case OPENDS_SMALL: key = "opends-small-icon"; break; case SUBSECTION_LEFT: key = "subsection-left-icon"; break; case SUBSECTION_RIGHT: key = "subsection-right-icon"; break; case HELP_SMALL: key = "help-small-icon"; break; case ERROR: key = "error-icon"; break; case ERROR_LARGE: key = "error-large-icon"; break; default: throw new IllegalArgumentException("Unknow iconName: " + iconType); throw new IllegalArgumentException("Unknown iconName: " + iconType); } return getParentPackagePath() + "/" + getMsg(key); } @@ -1235,19 +1298,43 @@ break; case WARNING: description = "warning-icon-description"; description = getMsg("warning-icon-description"); break; case WARNING_LARGE: description = "warning-icon-description"; description = getMsg("warning-icon-description"); break; case ERROR: description = "error-icon-description"; description = getMsg("error-icon-description"); break; case ERROR_LARGE: description = getMsg("error-icon-description"); break; case INFORMATION: description = "information-icon-description"; description = getMsg("information-icon-description"); break; case INFORMATION_LARGE: description = getMsg("information-icon-description"); break; case OPENDS_SMALL: description = getMsg("opends-small-icon-description"); break; case SUBSECTION_LEFT: description = getMsg("subsection-left-icon-description"); break; case SUBSECTION_RIGHT: description = getMsg("subsection-right-icon-description"); break; case HELP_SMALL: description = getMsg("help-small-icon-description"); break; case NO_ICON: @@ -1255,8 +1342,9 @@ break; default: throw new IllegalArgumentException("Unknow iconName: " + iconType); throw new IllegalArgumentException("Unknown iconName: " + iconType); } return description; } @@ -1291,28 +1379,52 @@ break; case WARNING: tooltip = "warning-icon-tooltip"; tooltip = getMsg("warning-icon-tooltip"); break; case WARNING_LARGE: tooltip = "warning-icon-tooltip"; tooltip = getMsg("warning-icon-tooltip"); break; case ERROR: tooltip = "error-icon-tooltip"; tooltip = getMsg("error-icon-tooltip"); break; case ERROR_LARGE: tooltip = getMsg("error-icon-tooltip"); break; case INFORMATION: tooltip = "information-icon-tooltip"; tooltip = getMsg("information-icon-tooltip"); break; case INFORMATION_LARGE: tooltip = getMsg("information-icon-tooltip"); break; case OPENDS_SMALL: tooltip = null; break; case SUBSECTION_LEFT: tooltip = null; break; case SUBSECTION_RIGHT: tooltip = null; break; case HELP_SMALL: tooltip = null; break; case NO_ICON: tooltip = null; break; default: throw new IllegalArgumentException("Unknow iconName: " + iconType); throw new IllegalArgumentException("Unknown iconName: " + iconType); } return tooltip; } opends/src/quicksetup/org/opends/quicksetup/ui/WebBrowserErrorDialog.java
@@ -136,6 +136,7 @@ UIFactory.makeHtmlPane(msg, UIFactory.BROWSER_ERROR_DIALOG_FONT); tf.setOpaque(false); tf.setEditable(false); p1.add(tf, gbc); gbc.weightx = 0.0; opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCli.java
@@ -79,8 +79,6 @@ static int BUG = 5; private static String LINE_SEPARATOR = System.getProperty("line.separator"); static int MAX_LINE_WIDTH = 80; private String[] args; @@ -126,7 +124,7 @@ { System.out.print( org.opends.server.util.StaticUtils.wrapText(ev.getNewLogs(), MAX_LINE_WIDTH)); Utils.getCommandLineMaxLineWidth())); } }); uninstaller.start(); @@ -1092,13 +1090,13 @@ private static String getMsg(String key) { return org.opends.server.util.StaticUtils.wrapText(getI18n().getMsg(key), MAX_LINE_WIDTH); Utils.getCommandLineMaxLineWidth()); } private static String getMsg(String key, String[] args) { return org.opends.server.util.StaticUtils.wrapText( getI18n().getMsg(key, args), MAX_LINE_WIDTH); getI18n().getMsg(key, args), Utils.getCommandLineMaxLineWidth()); } private static ResourceProvider getI18n() opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java
@@ -210,13 +210,13 @@ private static String getMsg(String key) { return org.opends.server.util.StaticUtils.wrapText(getI18n().getMsg(key), UninstallCli.MAX_LINE_WIDTH); Utils.getCommandLineMaxLineWidth()); } private static String getMsg(String key, String[] args) { return org.opends.server.util.StaticUtils.wrapText( getI18n().getMsg(key, args), UninstallCli.MAX_LINE_WIDTH); getI18n().getMsg(key, args), Utils.getCommandLineMaxLineWidth()); } private static ResourceProvider getI18n() opends/src/quicksetup/org/opends/quicksetup/util/HtmlProgressMessageFormatter.java
@@ -93,7 +93,7 @@ public String getFormattedError(String text, boolean applyMargin) { String html = UIFactory.getIconHtml(UIFactory.IconType.ERROR) UIFactory.getIconHtml(UIFactory.IconType.ERROR_LARGE) + SPACE + SPACE + UIFactory.applyFontToHtml(getHtml(text), @@ -120,7 +120,7 @@ public String getFormattedWarning(String text, boolean applyMargin) { String html = UIFactory.getIconHtml(UIFactory.IconType.WARNING) UIFactory.getIconHtml(UIFactory.IconType.WARNING_LARGE) + SPACE + SPACE + UIFactory.applyFontToHtml(getHtml(text), @@ -146,7 +146,7 @@ { // Note: the text we get already is in HTML form String html = UIFactory.getIconHtml(UIFactory.IconType.INFORMATION) + SPACE UIFactory.getIconHtml(UIFactory.IconType.INFORMATION_LARGE) + SPACE + SPACE + UIFactory.applyFontToHtml(text, UIFactory.PROGRESS_FONT); String result = UIFactory.applySuccessfulBackgroundToHtml(html); @@ -279,7 +279,7 @@ closeDiv, false)); String html = UIFactory.getIconHtml(UIFactory.IconType.ERROR) + SPACE + SPACE UIFactory.getIconHtml(UIFactory.IconType.ERROR_LARGE) + SPACE + SPACE + buf.toString(); String result; opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
@@ -72,6 +72,8 @@ { private static final int BUFFER_SIZE = 1024; private static final int MAX_LINE_WIDTH = 80; private static final String[] OPEN_DS_JAR_RELATIVE_PATHS = { "lib/quicksetup.jar", "lib/OpenDS.jar", "lib/je.jar" }; @@ -950,6 +952,8 @@ */ public static String getInstallPathFromClasspath() { String installPath; /* Get the install path from the Class Path */ String sep = System.getProperty("path.separator"); String[] classPaths = System.getProperty("java.class.path").split(sep); @@ -969,7 +973,20 @@ File f = new File(path).getAbsoluteFile(); File binariesDir = f.getParentFile(); return binariesDir.getParent(); /* * Do a best effort to avoid having a relative representation (for * instance to avoid having ../../../). */ try { installPath = binariesDir.getParentFile().getCanonicalPath(); } catch (IOException ioe) { // Best effort installPath = binariesDir.getParent(); } return installPath; } /** @@ -1310,4 +1327,15 @@ } return (InitialLdapContext) pair[0]; } /** * Returns the max size in character of a line to be displayed in the command * line. * @return the max size in character of a line to be displayed in the command * line. */ public static int getCommandLineMaxLineWidth() { return MAX_LINE_WIDTH; } } opends/src/statuspanel/org/opends/statuspanel/ConfigFromFile.java
New file @@ -0,0 +1,418 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel; import java.io.IOException; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.opends.server.core.DirectoryServer; import org.opends.server.util.LDIFException; import org.opends.server.util.LDIFReader; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeValue; import org.opends.server.types.Entry; import org.opends.server.types.LDIFImportConfig; import org.opends.server.types.ObjectClass; import org.opends.statuspanel.i18n.ResourceProvider; import org.opends.quicksetup.util.Utils; /** * This class is used to retrieve configuration information directly from the * config.ldif file. * */ public class ConfigFromFile { private final ObjectClass connectionHandlerOc = DirectoryServer.getObjectClass("ds-cfg-connection-handler", true); private final ObjectClass ldapConnectionHandlerOc = DirectoryServer.getObjectClass("ds-cfg-ldap-connection-handler", true); private final ObjectClass jmxConnectionHandlerOc = DirectoryServer.getObjectClass("ds-cfg-jmx-connection-handler", true); private final ObjectClass backendOc = DirectoryServer.getObjectClass("ds-cfg-backend", true); private final ObjectClass administrativeUserOc = DirectoryServer.getObjectClass("ds-cfg-root-dn", true); private HashSet<ListenerDescriptor> listeners = new HashSet<ListenerDescriptor>(); private HashSet<DatabaseDescriptor> databases = new HashSet<DatabaseDescriptor>(); private HashSet<String> administrativeUsers = new HashSet<String>(); private String errorMessage; /** * Default constructor. * */ public ConfigFromFile() { } /** * Reads the configuration from the config.ldif file. When calling this * method the thread is blocked until all the configuration is read. * */ public void readConfiguration() { errorMessage = null; try { LDIFImportConfig c = new LDIFImportConfig( Utils.getConfigFileFromClasspath()); LDIFReader reader = new LDIFReader(c); for (Entry entry = reader.readEntry(false); entry != null; entry = reader.readEntry(false)) { updateConfig(entry); } } catch (IOException ioe) { errorMessage = Utils.getThrowableMsg(getI18n(), "error-reading-config-file", null, ioe); } catch (LDIFException le) { errorMessage = Utils.getThrowableMsg(getI18n(), "error-reading-config-file", null, le); } catch (Throwable t) { // Bug t.printStackTrace(); errorMessage = Utils.getThrowableMsg(getI18n(), "error-reading-config-file", null, t); } } /** * Returns the Administrative User DNs found in the config.ldif. * @return the Administrative User DNs found in the config.ldif. */ public HashSet<String> getAdministrativeUsers() { return administrativeUsers; } /** * Returns the database descriptors found in the config.ldif. * @return the database descriptors found in the config.ldif. */ public HashSet<DatabaseDescriptor> getDatabases() { return databases; } /** * Returns the listener descriptors found in the config.ldif. * @return the listeners descriptors found in the config.ldif. */ public HashSet<ListenerDescriptor> getListeners() { return listeners; } /** * Returns the error message that we got when retrieving the information * from the config.ldif file. * @return the error message that we got when retrieving the information * from the config.ldif file. */ public String getErrorMessage() { return errorMessage; } /** * Returns the ldap URL that we can use to connect to the server based in * what we found in the config.ldif file. * @return the ldap URL that we can use to connect to the server based in * what we found in the config.ldif file. */ public String getLDAPURL() { String url = null; for (ListenerDescriptor desc : getListeners()) { if (desc.getState() == ListenerDescriptor.State.ENABLED) { int port = -1; try { String addressPort = desc.getAddressPort(); int index = addressPort.indexOf(":"); if (index != -1) { port = Integer.parseInt(addressPort.substring(index+1)); } else { port = Integer.parseInt(addressPort); } } catch (Exception ex) { // Could not get the port } if (port != -1) { if (desc.getProtocol() == ListenerDescriptor.Protocol.LDAP) { url = "ldap://localhost:"+port; /* We prefer to test using the LDAP port: do not continue * searching */ break; } else if (desc.getProtocol() == ListenerDescriptor.Protocol.LDAPS) { url = "ldaps://localhost:"+port; } } } } return url; } /** * An convenience method to know if the provided ID corresponds to a * configuration backend or not. * @param id the backend ID to analyze * @return <CODE>true</CODE> if the the id corresponds to a configuration * backend and <CODE>false</CODE> otherwise. */ static boolean isConfigBackend(String id) { return "tasks".equalsIgnoreCase(id) || "schema".equalsIgnoreCase(id) || "config".equalsIgnoreCase(id) || "monitor".equalsIgnoreCase(id) || "backup".equalsIgnoreCase(id); } /** * Updates the configuration data we expose to the user with the provided * entry object. * @param entry the entry to analyze. */ private void updateConfig(Entry entry) { if (entry.hasObjectClass(connectionHandlerOc)) { updateConfigWithConnectionHandler(entry); } else if (entry.hasObjectClass(backendOc)) { updateConfigWithBackend(entry); } else if (entry.hasObjectClass(administrativeUserOc)) { updateConfigWithAdministrativeUser(entry); } } /** * Updates the listener configuration data we expose to the user with the * provided entry object. * @param entry the entry to analyze. */ private void updateConfigWithConnectionHandler(Entry entry) { String address = getFirstValue(entry, "ds-cfg-listen-address"); String port = getFirstValue(entry, "ds-cfg-listen-port"); String addressPort; boolean isSecure = "true".equalsIgnoreCase( getFirstValue(entry, "ds-cfg-use-ssl")); ListenerDescriptor.Protocol protocol; String protocolDescription; ListenerDescriptor.State state; if (entry.hasObjectClass(ldapConnectionHandlerOc)) { addressPort = address+":"+port; if (isSecure) { protocolDescription = getMsg("ldaps-protocol-label"); protocol = ListenerDescriptor.Protocol.LDAPS; } else { protocolDescription = getMsg("ldap-protocol-label"); protocol = ListenerDescriptor.Protocol.LDAP; } boolean enabled = "true".equalsIgnoreCase( getFirstValue(entry, "ds-cfg-connection-handler-enabled")); if (enabled) { state = ListenerDescriptor.State.ENABLED; } else { state = ListenerDescriptor.State.DISABLED; } } else if (entry.hasObjectClass(jmxConnectionHandlerOc)) { addressPort = "0.0.0.0:"+port; if (isSecure) { protocolDescription = getMsg("jmx-secure-protocol-label"); protocol = ListenerDescriptor.Protocol.JMXS; } else { protocolDescription = getMsg("jmx-protocol-label"); protocol = ListenerDescriptor.Protocol.JMX; } boolean enabled = "true".equalsIgnoreCase( getFirstValue(entry, "ds-cfg-connection-handler-enabled")); if (enabled) { state = ListenerDescriptor.State.ENABLED; } else { state = ListenerDescriptor.State.DISABLED; } } else { addressPort = getMsg("unknown-label"); protocolDescription = null; protocol = ListenerDescriptor.Protocol.OTHER; /* Try to figure a name from the cn */ String cn = getFirstValue(entry, "cn"); if (cn != null) { int index = cn.toLowerCase().indexOf("connection handler"); if (index > 0) { protocolDescription = cn.substring(0, index).trim(); } else { protocolDescription = cn; } } else { protocolDescription = getMsg("undefined-protocol-label"); } state = ListenerDescriptor.State.UNKNOWN; } listeners.add(new ListenerDescriptor(addressPort, protocol, protocolDescription, state)); } /** * Updates the database configuration data we expose to the user with the * provided entry object. * @param entry the entry to analyze. */ private void updateConfigWithBackend(Entry entry) { String baseDn = getFirstValue(entry, "ds-cfg-backend-base-dn"); String id = getFirstValue(entry, "ds-cfg-backend-id"); int nEntries = -1; // Unknown if (!isConfigBackend(id)) { databases.add(new DatabaseDescriptor(id, baseDn, nEntries)); } } /** * Updates the administrative user configuration data we expose to the user * with the provided entry object. * @param entry the entry to analyze. */ private void updateConfigWithAdministrativeUser(Entry entry) { administrativeUsers.addAll(getValues(entry, "ds-cfg-alternate-bind-dn")); } /** * The following three methods are just commodity methods to get localized * messages. */ private String getMsg(String key) { return getI18n().getMsg(key); } private ResourceProvider getI18n() { return ResourceProvider.getInstance(); } /* * The following 2 methods are convenience methods to retrieve String values * from an entry. */ private Set<String> getValues(Entry entry, String attrName) { Set<String> values = new HashSet<String>(); List<Attribute> attrs = entry.getAttribute(attrName); if ((attrs != null) && attrs.size() > 0) { Attribute attr = attrs.iterator().next(); LinkedHashSet<AttributeValue> vs = attr.getValues(); if ((vs != null) && (vs.size() > 0)) { for (AttributeValue v : vs) { values.add(v.getStringValue()); } } } return values; } private String getFirstValue(Entry entry, String attrName) { String v = null; Set<String> values = getValues(entry, attrName); if (values.size() > 0) { v = values.iterator().next(); } return v; } } opends/src/statuspanel/org/opends/statuspanel/ConfigFromLDAP.java
New file @@ -0,0 +1,702 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel; import java.util.HashSet; import java.util.Set; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapName; import org.opends.statuspanel.i18n.ResourceProvider; import org.opends.quicksetup.util.Utils; /** * This class is used to retrieve configuration and monitoring information using * LDAP protocol. * */ public class ConfigFromLDAP { private HashSet<ListenerDescriptor> listeners = new HashSet<ListenerDescriptor>(); private HashSet<DatabaseDescriptor> databases = new HashSet<DatabaseDescriptor>(); private HashSet<String> administrativeUsers = new HashSet<String>(); private String errorMessage; private String dn; private String pwd; private String ldapUrl; private InitialLdapContext ctx; private String javaVersion; private int openConnections = -1; /** * Default constructor. * */ public ConfigFromLDAP() { } /** * Sets the connection information required to contact the server using LDAP. * @param ldapUrl the LDAP URL of the server. * @param dn the authentication Distinguished Name to bind. * @param pwd the authentication password to bind. */ public void setConnectionInfo(String ldapUrl, String dn, String pwd) { if (ldapUrl == null) { throw new IllegalArgumentException("ldapUrl cannot be null."); } if (dn == null) { throw new IllegalArgumentException("dn cannot be null."); } if (pwd == null) { throw new IllegalArgumentException("pwd cannot be null."); } if (!Utils.areDnsEqual(dn, this.dn) || !pwd.equals(this.pwd) || !ldapUrl.equals(this.ldapUrl)) { if (ctx != null) { try { ctx.close(); } catch (Throwable t) { } ctx = null; } } this.ldapUrl = ldapUrl; this.dn = dn; this.pwd = pwd; } /** * Reads the configuration and monitoring information of the server using * LDAP. * When calling this method the thread is blocked until all the configuration * is read. * * This method assumes that the setConnectionInfo has been called previously. * */ public void readConfiguration() { errorMessage = null; listeners.clear(); databases.clear(); administrativeUsers.clear(); javaVersion = null; openConnections = -1; try { InitialLdapContext ctx = getDirContext(); updateAdministrativeUsers(ctx); updateListeners(ctx); updateDatabases(ctx); javaVersion = getJavaVersion(ctx); openConnections = getOpenConnections(ctx); } catch (NamingException ne) { String detail; if (ne.getMessage() != null) { detail = ne.getMessage(); } else { detail = ne.toString(); } String[] arg = {detail}; errorMessage = getMsg("error-reading-config-ldap", arg); } catch (Throwable t) { // Bug t.printStackTrace(); String[] arg = {t.toString()}; errorMessage = getMsg("error-reading-config-ldap", arg); } } /** * Returns the Administrative User DNs found using LDAP. * @return the Administrative User DNs found using LDAP. */ public HashSet<String> getAdministrativeUsers() { return administrativeUsers; } /** * Returns the database descriptors found using LDAP. * @return the database descriptors found using LDAP. */ public HashSet<DatabaseDescriptor> getDatabases() { return databases; } /** * Returns the listener descriptors found using LDAP. * @return the listeners descriptors found using LDAP. */ public HashSet<ListenerDescriptor> getListeners() { return listeners; } /** * Return the java version we found using LDAP. * @return the java version we found using LDAP. */ public String getJavaVersion() { return javaVersion; } /** * Return the number of open connections we found using LDAP. * @return the number of open connections we found using LDAP. */ public int getOpenConnections() { return openConnections; } /** * Returns the error message that we got when retrieving the information * using LDAP. * @return the error message that we got when retrieving the information * using LDAP. */ public String getErrorMessage() { return errorMessage; } /** * Returns the InitialLdapContext object to be used to retrieve configuration * and monitoring information. * @return the InitialLdapContext object to be used to retrieve configuration * and monitoring information. * @throws NamingException if we could not get an InitialLdapContext. */ private InitialLdapContext getDirContext() throws NamingException { if (ctx != null) { try { pingDirContext(ctx); } catch (NamingException ne) { try { ctx.close(); } catch(NamingException xx) { } ctx = null; } } if (ctx == null) { ctx = Utils.createLdapContext(ldapUrl, dn, pwd, 3000, null); } return ctx; } /** * Ping the specified InitialLdapContext. * This method sends a search request on the root entry of the DIT * and forward the corresponding exception (if any). * @param ctx the InitialLdapContext to be "pinged". * @throws NamingException if the ping could not be performed. */ private void pingDirContext(InitialLdapContext ctx) throws NamingException { SearchControls sc = new SearchControls( SearchControls.OBJECT_SCOPE, 0, // count limit 0, // time limit new String[0], // No attributes false, // Don't return bound object false // Don't dereference link ); ctx.search("", "objectclass=*", sc); } /** * Updates the listener configuration data we expose to the user with the * provided InitialLdapContext. * @param ctx the InitialLdapContext to use to update the configuration. * @throws NamingException if there was an error. */ private void updateListeners(InitialLdapContext ctx) throws NamingException { SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); ctls.setReturningAttributes( new String[] { "ds-cfg-connection-handler-enabled", "ds-cfg-listen-address", "ds-cfg-listen-port", "ds-cfg-use-ssl", "objectclass" }); String filter = "(objectclass=ds-cfg-connection-handler)"; LdapName jndiName = new LdapName("cn=config"); NamingEnumeration listeners = ctx.search(jndiName, filter, ctls); while(listeners.hasMore()) { SearchResult sr = (SearchResult)listeners.next(); updateConfigWithConnectionHandler(sr); } } /** * Updates the database configuration data we expose to the user with the * provided InitialLdapContext. * @param ctx the InitialLdapContext to use to update the configuration. * @throws NamingException if there was an error. */ private void updateDatabases(InitialLdapContext ctx) throws NamingException { SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); ctls.setReturningAttributes( new String[] { "ds-cfg-backend-base-dn", "ds-cfg-backend-id" }); String filter = "(objectclass=ds-cfg-backend)"; LdapName jndiName = new LdapName("cn=config"); NamingEnumeration databases = ctx.search(jndiName, filter, ctls); while(databases.hasMore()) { SearchResult sr = (SearchResult)databases.next(); updateConfigWithBackend(sr, ctx); } } /** * Updates the administrative user configuration we expose to the user with * the provided InitialLdapContext. * @param ctx the InitialLdapContext to use to update the configuration. * @throws NamingException if there was an error. */ private void updateAdministrativeUsers(InitialLdapContext ctx) throws NamingException { SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); ctls.setReturningAttributes( new String[] { "ds-cfg-alternate-bind-dn" }); String filter = "(objectclass=ds-cfg-root-dn)"; LdapName jndiName = new LdapName("cn=config"); NamingEnumeration users = ctx.search(jndiName, filter, ctls); while(users.hasMore()) { SearchResult sr = (SearchResult)users.next(); updateConfigWithAdministrativeUser(sr); } } /** * Returns the java version we find using the provided InitialLdapContext. * @param ctx the InitialLdapContext to use to update the configuration. * @return the java version we find using the provided InitialLdapContext. * @throws NamingException if there was an error. */ private String getJavaVersion(InitialLdapContext ctx) throws NamingException { String v = null; SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.OBJECT_SCOPE); ctls.setReturningAttributes( new String[] { "jvmVersion" }); String filter = "(objectclass=*)"; LdapName jndiName = new LdapName("cn=System Information,cn=monitor"); NamingEnumeration listeners = ctx.search(jndiName, filter, ctls); while(listeners.hasMore()) { SearchResult sr = (SearchResult)listeners.next(); v = getFirstValue(sr, "jvmVersion"); } return v; } /** * Returns the number of open connections we find using the provided * InitialLdapContext. * @param ctx the InitialLdapContext to use to update the configuration. * @return the number of open connections we find using the provided * InitialLdapContext. * @throws NamingException if there was an error. */ private int getOpenConnections(InitialLdapContext ctx) throws NamingException { int nConnections = -1; String v = null; SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.OBJECT_SCOPE); ctls.setReturningAttributes( new String[] { "currentConnections" }); String filter = "(objectclass=*)"; LdapName jndiName = new LdapName("cn=monitor"); NamingEnumeration listeners = ctx.search(jndiName, filter, ctls); while(listeners.hasMore()) { SearchResult sr = (SearchResult)listeners.next(); v = getFirstValue(sr, "currentConnections"); } try { nConnections = Integer.parseInt(v); } catch (Exception ex) { } return nConnections; } /** * Returns the number of entries in a given backend using the provided * InitialLdapContext. * @param ctx the InitialLdapContext to use to update the configuration. * @param backenID the id of the backend. * @return the number of entries in the backend. * @throws NamingException if there was an error. */ private int getEntryCount(InitialLdapContext ctx, String backendID) throws NamingException { int nEntries = -1; String v = null; SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.ONELEVEL_SCOPE); ctls.setReturningAttributes( new String[] { "ds-backend-entry-count" }); String filter = "(ds-backend-id="+backendID+")"; LdapName jndiName = new LdapName("cn=monitor"); NamingEnumeration listeners = ctx.search(jndiName, filter, ctls); while(listeners.hasMore()) { SearchResult sr = (SearchResult)listeners.next(); v = getFirstValue(sr, "ds-backend-entry-count"); } try { nEntries = Integer.parseInt(v); } catch (Exception ex) { } return nEntries; } /** * Updates the listener configuration data we expose to the user with the * provided SearchResult object. * @param entry the entry to analyze. * @throws NamingException if there was an error. */ private void updateConfigWithConnectionHandler(SearchResult entry) throws NamingException { String address = getFirstValue(entry, "ds-cfg-listen-address"); String port = getFirstValue(entry, "ds-cfg-listen-port"); String addressPort; boolean isSecure = "true".equalsIgnoreCase( getFirstValue(entry, "ds-cfg-use-ssl")); ListenerDescriptor.Protocol protocol; String protocolDescription; ListenerDescriptor.State state; if (hasObjectClass(entry, "ds-cfg-ldap-connection-handler")) { addressPort = address+":"+port; if (isSecure) { protocolDescription = getMsg("ldaps-protocol-label"); protocol = ListenerDescriptor.Protocol.LDAPS; } else { protocolDescription = getMsg("ldap-protocol-label"); protocol = ListenerDescriptor.Protocol.LDAP; } boolean enabled = "true".equalsIgnoreCase( getFirstValue(entry, "ds-cfg-connection-handler-enabled")); if (enabled) { state = ListenerDescriptor.State.ENABLED; } else { state = ListenerDescriptor.State.DISABLED; } } else if (hasObjectClass(entry, "ds-cfg-jmx-connection-handler")) { addressPort = "0.0.0.0:"+port; if (isSecure) { protocolDescription = getMsg("jmx-secure-protocol-label"); protocol = ListenerDescriptor.Protocol.JMXS; } else { protocolDescription = getMsg("jmx-protocol-label"); protocol = ListenerDescriptor.Protocol.JMX; } boolean enabled = "true".equalsIgnoreCase( getFirstValue(entry, "ds-cfg-connection-handler-enabled")); if (enabled) { state = ListenerDescriptor.State.ENABLED; } else { state = ListenerDescriptor.State.DISABLED; } } else { addressPort = getMsg("unknown-label"); protocolDescription = null; protocol = ListenerDescriptor.Protocol.OTHER; /* Try to figure a name from the cn */ String cn = getFirstValue(entry, "cn"); if (cn != null) { int index = cn.toLowerCase().indexOf("connection handler"); if (index > 0) { protocolDescription = cn.substring(0, index).trim(); } else { protocolDescription = cn; } } else { protocolDescription = getMsg("undefined-protocol-label"); } state = ListenerDescriptor.State.UNKNOWN; } listeners.add(new ListenerDescriptor(addressPort, protocol, protocolDescription, state)); } /** * Updates the database configuration data we expose to the user with the * provided SearchResult object. * @param entry the entry to analyze. * @throws NamingException if there was an error. */ private void updateConfigWithBackend(SearchResult entry, InitialLdapContext ctx) throws NamingException { String baseDn = getFirstValue(entry, "ds-cfg-backend-base-dn"); String id = getFirstValue(entry, "ds-cfg-backend-id"); if (!isConfigBackend(id)) { int nEntries = getEntryCount(ctx, id); databases.add(new DatabaseDescriptor(id, baseDn, nEntries)); } } /** * Updates the administrative user configuration data we expose to the user * with the provided SearchResult object. * @param entry the entry to analyze. * @throws NamingException if there was an error. */ private void updateConfigWithAdministrativeUser(SearchResult entry) throws NamingException { administrativeUsers.addAll(getValues(entry, "ds-cfg-alternate-bind-dn")); } /* * The following 2 methods are convenience methods to retrieve String values * from an entry. */ private String getFirstValue(SearchResult entry, String attrName) throws NamingException { String v = null; Attributes attrs = entry.getAttributes(); if (attrs != null) { Attribute attr = attrs.get(attrName); if ((attr != null) && (attr.size() > 0)) { v = (String)attr.get(); } } return v; } private Set<String> getValues(SearchResult entry, String attrName) throws NamingException { Set<String> values = new HashSet<String>(); Attributes attrs = entry.getAttributes(); if (attrs != null) { Attribute attr = attrs.get(attrName); if (attr != null) { for (int i=0; i<attr.size(); i++) { values.add((String)attr.get(i)); } } } return values; } /** * Returns true if the SearchResult object is of a given objectclass. * @param entry the SearchResult to analyze. * @param ocName the objectclass. * @return <CODE>true</CODE> if the SearchResult is of a the objectclass and * <CODE>false</CODE> otherwise. * @throws NamingException if there was an error. */ private boolean hasObjectClass(SearchResult entry, String ocName) throws NamingException { boolean hasObjectClass = false; Attributes attrs = entry.getAttributes(); if (attrs != null) { Attribute attr = attrs.get("objectclass"); if (attr != null) { for (int i=0; i<attr.size() && !hasObjectClass; i++) { hasObjectClass = ocName.equalsIgnoreCase((String)attr.get(i)); } } } return hasObjectClass; } private boolean isConfigBackend(String id) { return ConfigFromFile.isConfigBackend(id); } /** * The following three methods are just commodity methods to get localized * messages. */ private String getMsg(String key) { return getI18n().getMsg(key); } private String getMsg(String key, String[] args) { return getI18n().getMsg(key, args); } private ResourceProvider getI18n() { return ResourceProvider.getInstance(); } } opends/src/statuspanel/org/opends/statuspanel/DatabaseDescriptor.java
New file @@ -0,0 +1,113 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel; import org.opends.quicksetup.util.Utils; /** * This class is used to represent a Database and is aimed to be used by the * classes in the DatabasesTableModel class. */ public class DatabaseDescriptor { private String backendID; private String baseDn; private int entries; /** * Constructor for this class. * @param backendID the backend ID of the Database. * @param baseDn the base DN associated with the Database. * @param entries the number of entries in the Database. */ public DatabaseDescriptor(String backendID, String baseDn, int entries) { this.backendID = backendID; this.baseDn = baseDn; this.entries = entries; } /** * Returns the ID of the Backend. * @return the ID of the Backend. */ public String getBackendID() { return backendID; } /** * Return the base DN associated with the database. * @return the base DN associated with the database. */ public String getBaseDn() { return baseDn; } /** * Return the number of entries in the database. * -1 indicates that the number of entries could not be found. * @return the number of entries in the database. */ public int getEntries() { return entries; } /** * {@inheritDoc} */ public boolean equals(Object v) { boolean equals = false; if (this != v) { if (v instanceof DatabaseDescriptor) { DatabaseDescriptor desc = (DatabaseDescriptor)v; equals = getBackendID().equals(desc.getBackendID()) && Utils.areDnsEqual(getBaseDn(), desc.getBaseDn()) && (getEntries() == desc.getEntries()); } } else { equals = true; } return equals; } /** * {@inheritDoc} */ public int hashCode() { return (getBackendID() + getBaseDn() + getEntries()).hashCode(); } } opends/src/statuspanel/org/opends/statuspanel/ListenerDescriptor.java
New file @@ -0,0 +1,148 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel; /** * This class is used to represent a Listener and is aimed to be used by the * classes in the ListenersTableModel class. */ public class ListenerDescriptor { /** * Enumeration used to represent the state of the listener. */ public enum State { /** * The listener is enabled. */ ENABLED, /** * The listener is disabled. */ DISABLED, /** * The state of the listener is unknown. */ UNKNOWN }; /** * Enumeration used to represent the Protocol of the listener. * */ public enum Protocol { /** * LDAP protocol. */ LDAP, /** * LDAP secure protocol. */ LDAPS, /** * JMX protocol. */ JMX, /** * JMX secure protocol. */ JMXS, /** * Other protocol. */ OTHER } private State state; private String addressPort; private Protocol protocol; private String protocolDescription; /** * Constructor for thid class. * @param addressPort the address port reprentation of the listener. * @param protocol the protocol of the listener. * @param protocolDescription the String used to describe the protocol. * @param state the state of the listener. */ public ListenerDescriptor(String addressPort, Protocol protocol, String protocolDescription, State state) { this.addressPort = addressPort; this.protocol = protocol; this.protocolDescription = protocolDescription; this.state = state; } /** * Returns the address port representation of the listener. * @return the address port representation of the listener. */ public String getAddressPort() { return addressPort; } /** * Returns the protocol of the listener. * @return the protocol of the listener. */ public Protocol getProtocol() { return protocol; } /** * Returns the protocol description of the listener. * @return the protocol description of the listener. */ public String getProtocolDescription() { return protocolDescription; } /** * Returns the state of the listener. * @return the state of the listener. */ public State getState() { return state; } /** * {@inheritDoc} */ public int hashCode() { return (getAddressPort() + getProtocolDescription() + getState()).hashCode(); } } opends/src/statuspanel/org/opends/statuspanel/ServerStatusDescriptor.java
New file @@ -0,0 +1,356 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel; import java.io.File; import java.util.Set; /** * This is just a class used to provide a data model describing what the * StatusPanelDialog will show to the user. */ public class ServerStatusDescriptor { private ServerStatus status; private int openConnections; private Set<DatabaseDescriptor> databases; private Set<ListenerDescriptor> listeners; private Set<String> administrativeUsers; private File installPath; private String openDSVersion; private String javaVersion; private String errorMsg; private boolean isAuthenticated; /** * Enumeration indicating the status of the server. * */ public enum ServerStatus { /** * Server Started. */ STARTED, /** * Server Stopped. */ STOPPED, /** * Server Starting. */ STARTING, /** * Server Stopping. */ STOPPING, /** * Status Unknown. */ UNKNOWN } /** * Default constructor. */ public ServerStatusDescriptor() { } /** * Return the administrative users. * @return the administrative users. */ public Set<String> getAdministrativeUsers() { return administrativeUsers; } /** * Set the administrative users. * @param administrativeUsers the administrative users to set */ public void setAdministrativeUsers(Set<String> administrativeUsers) { this.administrativeUsers = administrativeUsers; } /** * Return the install path where the server is installed. * @return the install path where the server is installed. */ public File getInstallPath() { return installPath; } /** * Sets the install path where the server is installed. * @param installPath the install path where the server is installed. */ public void setInstallPath(File installPath) { this.installPath = installPath; } /** * Return the java version used to run the server. * @return the java version used to run the server. */ public String getJavaVersion() { return javaVersion; } /** * Set the java version used to run the server. * @param javaVersion the java version used to run the server. */ public void setJavaVersion(String javaVersion) { this.javaVersion = javaVersion; } /** * Returns the number of open connection in the server. * @return the number of open connection in the server. */ public int getOpenConnections() { return openConnections; } /** * Set the number of open connections. * @param openConnections the number of open connections. */ public void setOpenConnections(int openConnections) { this.openConnections = openConnections; } /** * Returns the version of the server. * @return the version of the server. */ public String getOpenDSVersion() { return openDSVersion; } /** * Sets the version of the server. * @param openDSVersion the version of the server. */ public void setOpenDSVersion(String openDSVersion) { this.openDSVersion = openDSVersion; } /** * Returns the status of the server. * @return the status of the server. */ public ServerStatus getStatus() { return status; } /** * Sets the status of the server. * @param status the status of the server. */ public void setStatus(ServerStatus status) { this.status = status; } /** * {@inheritDoc} */ public boolean equals(Object o) { boolean equals = false; if (this != o) { if (o instanceof ServerStatusDescriptor) { ServerStatusDescriptor desc = (ServerStatusDescriptor)o; equals = desc.getStatus() == getStatus(); if (equals) { equals = desc.getOpenConnections() == getOpenConnections(); } if (equals) { equals = desc.getInstallPath().equals(getInstallPath()); } if (equals) { if (desc.getJavaVersion() == null) { equals = getJavaVersion() == null; } else { equals = desc.getJavaVersion().equals(getJavaVersion()); } } if (equals) { equals = desc.getOpenDSVersion().equals(getOpenDSVersion()); } if (equals) { equals = desc.getAdministrativeUsers().equals( getAdministrativeUsers()); } if (equals) { equals = desc.getDatabases().equals(getDatabases()); } if (equals) { if (desc.getErrorMessage() == null) { equals = getErrorMessage() == null; } else { equals = desc.getErrorMessage().equals(getErrorMessage()); } } } } else { equals = true; } return equals; } /** * {@inheritDoc} */ public int hashCode() { return status.hashCode() + openConnections + databases.hashCode() + listeners.hashCode() + administrativeUsers.hashCode() + (String.valueOf( installPath+openDSVersion+javaVersion+errorMsg+isAuthenticated)). hashCode(); } /** * Returns the error message that we encountered generating this server * status descriptor. * @return the error message that we encountered generating this server * status descriptor. */ public String getErrorMessage() { return errorMsg; } /** * Sets the error message that we encountered generating this server * status descriptor. * @param errorMsg the error message that we encountered generating this * server status descriptor. */ public void setErrorMessage(String errorMsg) { this.errorMsg = errorMsg; } /** * Return whether we were authenticated when retrieving the information of * this ServerStatusDescriptor. * @return <CODE>true</CODE> if we were authenticated when retrieving the * information of this ServerStatusDescriptor and <CODE>false</CODE> * otherwise. */ public boolean isAuthenticated() { return isAuthenticated; } /** * Sets whether we were authenticated when retrieving the information of * this ServerStatusDescriptor. * @param isAuthenticated whether we were authenticated when retrieving the * information of this ServerStatusDescriptor. */ public void setAuthenticated(boolean isAuthenticated) { this.isAuthenticated = isAuthenticated; } /** * Returns the database descriptors of the server. * @return the database descriptors of the server. */ public Set<DatabaseDescriptor> getDatabases() { return databases; } /** * Sets the database descriptors of the server. * @param databases the database descriptors to set. */ public void setDatabases(Set<DatabaseDescriptor> databases) { this.databases = databases; } /** * Returns the listener descriptors of the server. * @return the listener descriptors of the server. */ public Set<ListenerDescriptor> getListeners() { return listeners; } /** * Sets the listener descriptors of the server. * @param listeners the listener descriptors to set. */ public void setListeners(Set<ListenerDescriptor> listeners) { this.listeners = listeners; } } opends/src/statuspanel/org/opends/statuspanel/ServerStatusPooler.java
New file @@ -0,0 +1,408 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel; import java.io.File; import java.util.HashSet; import org.opends.quicksetup.util.Utils; import org.opends.statuspanel.event.ServerStatusChangeEvent; import org.opends.statuspanel.event.ServerStatusChangeListener; import org.opends.statuspanel.i18n.ResourceProvider; /** * This class just reads the status of the server periodically and generates * ServerStatusChangeEvent when the status changes. To receive this events * other classes must register using the addServerStatusChangeListener method. * */ public class ServerStatusPooler { private String dn; private String pwd; private ServerStatusDescriptor lastDescriptor; private boolean stopPooling; private Thread t; private HashSet<ServerStatusChangeListener> listeners = new HashSet<ServerStatusChangeListener>(); private boolean starting; private boolean stopping; private ConfigFromFile offLineConf = new ConfigFromFile(); private ConfigFromLDAP onLineConf = new ConfigFromLDAP(); private String ldapUrl; private int nTriesWithErrorOnline; /* The pooling periods */ private static final int OFFLINE_POOLING_PERIOD = 3000; private static final int ONLINE_POOLING_PERIOD = 5000; /** * Default constructor. */ public ServerStatusPooler() { /* This is required to retrieve the ldap url to be used by the * ConfigFromLDAP class. */ offLineConf.readConfiguration(); ldapUrl = offLineConf.getLDAPURL(); } /** * Starts pooling the server status. This method does not block the thread * that called it. * */ public void startPooling() { stopPooling = false; t = new Thread(new Runnable() { public void run() { try { nTriesWithErrorOnline = 0; while (!stopPooling) { long t1 = System.currentTimeMillis(); ServerStatusDescriptor desc = generateDescriptor(); if (!desc.equals(lastDescriptor)) { lastDescriptor = desc; notifyListeners(lastDescriptor); } long t2 = System.currentTimeMillis(); long poolingPeriod = desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED? ONLINE_POOLING_PERIOD : OFFLINE_POOLING_PERIOD; if (t2 - t1 < poolingPeriod) { try { Thread.sleep(poolingPeriod - (t2 - t1)); } catch (Exception ex) { if (!stopPooling) { /* Should not happen. */ throw ex; } } } } } catch (Throwable t) { if (!stopPooling) { /* This is a bug. */ t.printStackTrace(); } } } }); t.start(); } /** * Returns the last server descriptor found. * @return the last server descriptor found. */ public ServerStatusDescriptor getLastDescriptor() { return lastDescriptor; } /** * This method is called to notify that the server is being started. */ public void beginServerStart() { starting = true; } /** * This method is called to notify that the server start operation ended. */ public void endServerStart() { starting = false; } /** * This method is called to notify that the server is being stopped. */ public void beginServerStop() { stopping = true; } /** * This method is called to notify that the server stop operation ended. */ public void endServerStop() { stopping = false; } /** * Adds a ServerStatusChangeListener that will be notified of updates in * the server status. * @param l the ServerStatusChangeListener to be added. */ public void addServerStatusChangeListener(ServerStatusChangeListener l) { listeners.add(l); } /** * Removes a ServerStatusChangeListener. * @param l the ServerStatusChangeListener to be removed. */ public void removeServerStatusChangeListener(ServerStatusChangeListener l) { listeners.remove(l); } /** * Returns <CODE>true</CODE> if this class already has authentication * information (setAuthentication method has been called with non-null * parameters). * @return <CODE>true</CODE> if this class already has authentication * information and <CODE>false</CODE> otherwise. */ public boolean isAuthenticated() { return (dn != null) && (pwd != null); } /** * Sets the authentication information to be used by this class to retrieve * information using LDAP. * @param dn the authentication Distinguished Name to bind. * @param pwd the authentication password to bind. */ public void setAuthentication(String dn, String pwd) { this.dn = dn; this.pwd = pwd; if ((ldapUrl != null) && (t != null) && t.isAlive() && !stopPooling) { /* If we are pooling, stop the pooling update the connection information * and restart the pooling. Set the stopPooling boolean to true to * indicate to the code in the Thread 't' to ignore the * InterruptedExceptions. * */ stopPooling = true; t.interrupt(); try { t.join(5000); } catch (Throwable t) { /* This should not happen: this thread should not be interrupted. */ t.printStackTrace(); } t = null; onLineConf.setConnectionInfo(ldapUrl, dn, pwd); startPooling(); } else if (ldapUrl != null) { onLineConf.setConnectionInfo(ldapUrl, dn, pwd); } } /** * This method notifies the ServerStatusChangeListeners that there was an * update in the installation progress. * @param desc the ServerStatusDescriptor. */ private void notifyListeners(ServerStatusDescriptor desc) { ServerStatusChangeEvent ev = new ServerStatusChangeEvent(desc); for (ServerStatusChangeListener l : listeners) { l.statusChanged(ev); } } /** * Retrieves information of the server. The method used will depend on the * status of the server (started or not). * @return a ServerStatusDescriptor object describing the status of the * server. */ private ServerStatusDescriptor generateDescriptor() { ServerStatusDescriptor desc = new ServerStatusDescriptor(); desc.setAuthenticated((dn != null) && (pwd != null)); if (starting) { desc.setStatus(ServerStatusDescriptor.ServerStatus.STARTING); } else if (stopping) { desc.setStatus(ServerStatusDescriptor.ServerStatus.STOPPING); } else if (Utils.isServerRunning(Utils.getInstallPathFromClasspath())) { desc.setStatus(ServerStatusDescriptor.ServerStatus.STARTED); } else { desc.setStatus(ServerStatusDescriptor.ServerStatus.STOPPED); } desc.setInstallPath(new File(Utils.getInstallPathFromClasspath())); desc.setOpenDSVersion( org.opends.server.util.DynamicConstants.FULL_VERSION_STRING); if (desc.getStatus() != ServerStatusDescriptor.ServerStatus.STARTED) { updateDescriptorWithOffLineInfo(desc); } else { try { if ((dn == null) || (pwd == null)) { desc.setAdministrativeUsers(new HashSet<String>()); desc.setDatabases(new HashSet<DatabaseDescriptor>()); desc.setListeners(new HashSet<ListenerDescriptor>()); desc.setOpenConnections(-1); } else if (ldapUrl != null) { updateDescriptorWithOnLineInfo(desc); } else { /* We cannot retrieve an ldapurl from the config file. Display * what we got in the config file. */ updateDescriptorWithOffLineInfo(desc); if (desc.getErrorMessage() != null) { desc.setErrorMessage(getMsg("could-not-find-valid-ldapurl")); } } } catch (Exception ex) { // Bug ex.printStackTrace(); } } return desc; } /** * Updates the ServerStatusDescriptor object using the information in the * config.ldif file (we use a ConfigFromFile object to do this). * @param desc the ServerStatusDescriptor object to be updated. */ private void updateDescriptorWithOffLineInfo(ServerStatusDescriptor desc) { /* Read the list of administrative users from CurrentInstallStatus * (which reads directly config.ldif. This is the best we can do today * when the server is not started. */ offLineConf.readConfiguration(); desc.setAdministrativeUsers(offLineConf.getAdministrativeUsers()); desc.setDatabases(offLineConf.getDatabases()); desc.setListeners(offLineConf.getListeners()); desc.setErrorMessage(offLineConf.getErrorMessage()); ldapUrl = offLineConf.getLDAPURL(); if ((ldapUrl != null) && (dn != null) && (pwd != null)) { onLineConf.setConnectionInfo(ldapUrl, dn, pwd); } desc.setOpenConnections(-1); desc.setJavaVersion(null); } /** * Updates the ServerStatusDescriptor object using the LDAP protocol (we use a * ConfigFromLDAP object to do this). * @param desc the ServerStatusDescriptor object to be updated. */ private void updateDescriptorWithOnLineInfo(ServerStatusDescriptor desc) { onLineConf.readConfiguration(); desc.setAdministrativeUsers(onLineConf.getAdministrativeUsers()); desc.setDatabases(onLineConf.getDatabases()); desc.setListeners(onLineConf.getListeners()); desc.setErrorMessage(onLineConf.getErrorMessage()); desc.setJavaVersion(onLineConf.getJavaVersion()); desc.setOpenConnections(onLineConf.getOpenConnections()); if (desc.getErrorMessage() != null) { nTriesWithErrorOnline++; /* Something happened: if this is the 5th try with the current URL * just try to check if the information has changed in the config.ldif * file. */ if (nTriesWithErrorOnline >= 5) { offLineConf.readConfiguration(); ldapUrl = offLineConf.getLDAPURL(); onLineConf.setConnectionInfo(ldapUrl, dn, pwd); nTriesWithErrorOnline = 0; } } } /** * The following three methods are just commodity methods to get localized * messages. */ private String getMsg(String key) { return getI18n().getMsg(key); } private ResourceProvider getI18n() { return ResourceProvider.getInstance(); } } opends/src/statuspanel/org/opends/statuspanel/SplashScreen.java
New file @@ -0,0 +1,111 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel; import javax.swing.SwingUtilities; /** * This class will display a splash screen and in the background it will * create The StatusPanel object. * * This class just extends the org.opends.quicksetup.SplashScreen by * overwritting the construct and display methods. */ public class SplashScreen extends org.opends.quicksetup.SplashScreen { private static final long serialVersionUID = 4472839063380302713L; private static Object statusPanel; private static Class<?> statusPanelClass; /** * The main method for this class. * It can be called from the event thread and outside the event thread. * @param args arguments to be passed to the method QuickSetup.initialize */ public static void main(String[] args) { SplashScreen screen = new SplashScreen(); screen.display(args); } /** * This methods constructs the StatusPanel object. * This method assumes that is being called outside the event thread. * @param args arguments to be passed to the method StatusPanel.initialize. */ protected void constructApplication(String[] args) { try { statusPanelClass = Class.forName( "org.opends.statuspanel.StatusPanelController"); statusPanel = statusPanelClass.newInstance(); statusPanelClass.getMethod("initialize", new Class[] { String[].class }).invoke(statusPanel, new Object[] { args }); } catch (Exception e) { InternalError error = new InternalError("Failed to invoke initialize method"); error.initCause(e); throw error; } } /** * This method displays the StatusPanel dialog. * @see StatusPanelController.display. * This method assumes that is being called outside the event thread. */ protected void displayApplication() { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { try { statusPanelClass.getMethod("display").invoke(statusPanel); } catch (Exception e) { InternalError error = new InternalError("Failed to invoke display method"); error.initCause(e); throw error; } } }); } catch (Exception ex) { } } } opends/src/statuspanel/org/opends/statuspanel/StatusCli.java
New file @@ -0,0 +1,943 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.util.ArrayList; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; import javax.swing.table.TableModel; import org.opends.quicksetup.util.Utils; import org.opends.server.core.DirectoryServer; import org.opends.statuspanel.i18n.ResourceProvider; import org.opends.statuspanel.ui.DatabasesTableModel; import org.opends.statuspanel.ui.ListenersTableModel; /** * The class used to provide some CLI interface to display status. * * This class basically is in charge of parsing the data provided by the user * in the command line. * */ class StatusCli { private static String LINE_SEPARATOR = System.getProperty("line.separator"); private String[] args; private boolean displayMustAuthenticateLegend; private boolean displayMustStartLegend; /** * Return code: Uninstall successful. */ static int SUCCESSFUL = 0; /** * Return code: User provided invalid data. */ static int USER_DATA_ERROR = 1; /** * Return code: Bug. */ static int BUG = 2; private static String COMMAND_NAME_WINDOWS = "status.bat"; private static String COMMAND_NAME_UNIX = "status"; /** * The main method which is called by the status command lines. * @param args the arguments passed by the status command lines. */ public static void main(String[] args) { StatusCli cli = new StatusCli(args); System.exit(cli.run()); } /** * The constructor for this object. * @param args the arguments of the status command line. */ StatusCli(String[] args) { /* Ignore the first 4 arguments */ if ((args != null) && (args.length >= 4)) { this.args = new String[args.length - 4]; for (int i=0; i<this.args.length; i++) { this.args[i] = args[i+4]; } } else { this.args = args; } DirectoryServer.bootstrapClient(); } /** * Parses the user data and displays usage if something is missing and the * status otherwise. * * @return the return code (SUCCESSFUL, USER_DATA_ERROR or BUG. */ int run() { int returnValue = SUCCESSFUL; ArrayList<String> errors = new ArrayList<String>(); boolean printUsage = false; String directoryManagerPwd = null; String directoryManagerPwdFile = null; String directoryManagerDn = null; for (int i=0; i<args.length; i++) { if (args[i].equalsIgnoreCase("-H") || args[i].equalsIgnoreCase("--help")) { printUsage = true; } else if (args[i].equalsIgnoreCase("-D") || args[i].equalsIgnoreCase("--bindDN")) { if (i+1 >= args.length) { errors.add(getMsg("cli-status-root-user-dn-not-provided", true)); } else { if (args[i+1].indexOf("-") == 0) { errors.add(getMsg("cli-status-root-user-dn-not-provided", true)); } else { directoryManagerDn = args[i+1]; i++; } } } else if (args[i].equals("-w") || args[i].equalsIgnoreCase("--bindPassword")) { if (i+1 >= args.length) { errors.add(getMsg("cli-status-root-user-pwd-not-provided", true)); } else { if (args[i+1].indexOf("-") == 0) { errors.add(getMsg("cli-status-root-user-pwd-not-provided", true)); } else { directoryManagerPwd = args[i+1]; i++; } } } else if (args[i].equals("-j") || args[i].equalsIgnoreCase("--bindPasswordFile")) { if (i+1 >= args.length) { errors.add(getMsg("cli-status-root-user-pwd-file-not-provided", true)); } else { if (args[i+1].indexOf("-") == 0) { errors.add(getMsg("cli-status-root-user-pwd-file-not-provided", true)); } else { directoryManagerPwdFile = args[i+1]; i++; } } } else { String[] arg = {args[i]}; errors.add(getMsg("cli-status-unknown-argument", arg, true)); } } if ((directoryManagerPwdFile != null) && (directoryManagerPwd != null)) { errors.add(getMsg("cli-status-pwd-and-pwd-file-provided", true)); } else { if (directoryManagerPwdFile != null) { directoryManagerPwd = readPwdFromFile(directoryManagerPwdFile); if (directoryManagerPwd == null) { String[] arg = {directoryManagerPwdFile}; errors.add(getMsg("cli-status-error-reading-pwd-file", arg, true)); } } } if (printUsage) { printUsage(); } else if (errors.size() > 0) { System.err.println(Utils.getStringFromCollection(errors, LINE_SEPARATOR+LINE_SEPARATOR)); System.out.println(); printUsage(); returnValue = USER_DATA_ERROR; } else { boolean isServerRunning = Utils.isServerRunning(Utils.getInstallPathFromClasspath()); /* This is required to retrieve the ldap url to be used by the * ConfigFromLDAP class. */ ConfigFromFile offLineConf = new ConfigFromFile(); offLineConf.readConfiguration(); ServerStatusDescriptor desc = createServerStatusDescriptor( directoryManagerDn, directoryManagerPwd); if (isServerRunning) { String ldapUrl = offLineConf.getLDAPURL(); if (directoryManagerDn == null) { directoryManagerDn = ""; } if (directoryManagerPwd == null) { directoryManagerPwd = ""; } ConfigFromLDAP onLineConf = new ConfigFromLDAP(); onLineConf.setConnectionInfo(ldapUrl, directoryManagerDn, directoryManagerPwd); onLineConf.readConfiguration(); updateDescriptorWithOnLineInfo(desc, onLineConf); } else { updateDescriptorWithOffLineInfo(desc, offLineConf); } writeStatus(desc); } return returnValue; } /** * Returns the password stored in a file. Returns <CODE>null</CODE> if no * password is found. * @param path the path of the file containing the password. * @return the password stored in a file. Returns <CODE>null</CODE> if no * password is found. */ private String readPwdFromFile(String path) { String pwd = null; BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(path)); pwd = reader.readLine(); } catch (Exception e) { } finally { try { if (reader != null) { reader.close(); } } catch (Exception e) {} } return pwd; } /** * The following three methods are just commodity methods to get localized * messages. */ private String getMsg(String key, boolean wrap) { String t = getI18n().getMsg(key); if (wrap) { t= wrap(t); } return t; } private String getMsg(String key, String[] args, boolean wrap) { String t = getI18n().getMsg(key, args); if (wrap) { t= wrap(t); } return t; } private static ResourceProvider getI18n() { return ResourceProvider.getInstance(); } private void printUsage() { String arg; if (Utils.isWindows()) { arg = COMMAND_NAME_WINDOWS; } else { arg = COMMAND_NAME_UNIX; } /* * This is required because the usage message contains '{' characters that * mess up the MessageFormat.format method. */ String msg = getMsg("status-cli-usage", true); msg = msg.replace("{0}", arg); System.err.println(msg); } private ServerStatusDescriptor createServerStatusDescriptor(String dn, String pwd) { ServerStatusDescriptor desc = new ServerStatusDescriptor(); desc.setAuthenticated((dn != null) && (pwd != null)); if (Utils.isServerRunning(Utils.getInstallPathFromClasspath())) { desc.setStatus(ServerStatusDescriptor.ServerStatus.STARTED); } else { desc.setStatus(ServerStatusDescriptor.ServerStatus.STOPPED); } desc.setInstallPath(new File(Utils.getInstallPathFromClasspath())); desc.setOpenDSVersion( org.opends.server.util.DynamicConstants.FULL_VERSION_STRING); return desc; } /** * Updates the ServerStatusDescriptor object using the information in the * config.ldif file (we use a ConfigFromFile object to do this). * @param desc the ServerStatusDescriptor object to be updated. * @param offLineConf the ConfigFromFile object to be used. */ private void updateDescriptorWithOffLineInfo(ServerStatusDescriptor desc, ConfigFromFile offLineConf) { desc.setAdministrativeUsers(offLineConf.getAdministrativeUsers()); desc.setDatabases(offLineConf.getDatabases()); desc.setListeners(offLineConf.getListeners()); desc.setErrorMessage(offLineConf.getErrorMessage()); desc.setOpenConnections(-1); desc.setJavaVersion(null); } /** * Updates the ServerStatusDescriptor object using the LDAP protocol (we use a * ConfigFromLDAP object to do this). * @param desc the ServerStatusDescriptor object to be updated. * @param onLineConf the ConfigFromLDAP object to be used. */ private void updateDescriptorWithOnLineInfo(ServerStatusDescriptor desc, ConfigFromLDAP onLineConf) { desc.setAdministrativeUsers(onLineConf.getAdministrativeUsers()); desc.setDatabases(onLineConf.getDatabases()); desc.setListeners(onLineConf.getListeners()); desc.setErrorMessage(onLineConf.getErrorMessage()); desc.setJavaVersion(onLineConf.getJavaVersion()); desc.setOpenConnections(onLineConf.getOpenConnections()); } private void writeStatus(ServerStatusDescriptor desc) { String[] labels = { getMsg("server-status-label", false), getMsg("connections-label", false), getMsg("administrative-users-label", false), getMsg("installation-path-label", false), getMsg("opends-version-label", false), getMsg("java-version-label", false) }; int labelWidth = 0; for (int i=0; i<labels.length; i++) { labelWidth = Math.max(labelWidth, labels[i].length()); } System.out.println(); String title = getMsg("server-status-title", false); System.out.println(centerTitle(title)); writeStatusContents(desc, labelWidth); writeCurrentConnectionContents(desc, labelWidth); System.out.println(); title = getMsg("server-details-title", false); System.out.println(centerTitle(title)); writeAdministrativeUserContents(desc, labelWidth); writeInstallPathContents(desc, labelWidth); writeVersionContents(desc, labelWidth); writeJavaVersionContents(desc, labelWidth); System.out.println(); writeListenerContents(desc); System.out.println(); writeDatabaseContents(desc); writeErrorContents(desc); if (displayMustStartLegend) { System.out.println(); System.out.println(getMsg("not-available-server-down-cli-legend", true)); } else if (displayMustAuthenticateLegend) { System.out.println(); System.out.println( getMsg("not-available-authentication-required-cli-legend", true)); } System.out.println(); } /** * Writes the status contents displaying with what is specified in the * provided ServerStatusDescriptor object. * @param desc the ServerStatusDescriptor object. */ private void writeStatusContents(ServerStatusDescriptor desc, int maxLabelWidth) { String status; switch (desc.getStatus()) { case STARTED: status = getMsg("server-started-label", false); break; case STOPPED: status = getMsg("server-stopped-label", false); break; case STARTING: status = getMsg("server-starting-label", false); break; case STOPPING: status = getMsg("server-stopping-label", false); break; case UNKNOWN: status = getMsg("server-unknown-status-label", false); break; default: throw new IllegalStateException("Unknown status: "+desc.getStatus()); } writeLabelValue(getMsg("server-status-label", false), status, maxLabelWidth); } /** * Writes the current connection contents displaying with what is specified * in the provided ServerStatusDescriptor object. * @param desc the ServerStatusDescriptor object. */ private void writeCurrentConnectionContents(ServerStatusDescriptor desc, int maxLabelWidth) { String text; if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { int nConn = desc.getOpenConnections(); if (nConn >= 0) { text = String.valueOf(nConn); } else { if (!desc.isAuthenticated()) { text = getNotAvailableBecauseAuthenticationIsRequiredText(); } else { text = getNotAvailableText(); } } } else { text = getNotAvailableBecauseServerIsDownText(); } writeLabelValue(getMsg("connections-label", false), text, maxLabelWidth); } /** * Writes the administrative user contents displaying with what is specified * in the provided ServerStatusDescriptor object. * @param desc the ServerStatusDescriptor object. */ private void writeAdministrativeUserContents(ServerStatusDescriptor desc, int maxLabelWidth) { Set<String> administrators = desc.getAdministrativeUsers(); String text; if (administrators.size() > 0) { TreeSet<String> ordered = new TreeSet<String>(); ordered.addAll(administrators); String first = ordered.iterator().next(); writeLabelValue(getMsg("administrative-users-label", false), first, maxLabelWidth); Iterator<String> it = ordered.iterator(); // First one already printed it.next(); while (it.hasNext()) { writeLabelValue(getMsg("administrative-users-label", false), it.next(), maxLabelWidth); } } else { if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { if (!desc.isAuthenticated()) { text = getNotAvailableBecauseAuthenticationIsRequiredText(); } else { text = getNotAvailableText(); } } else { text = getNotAvailableText(); } writeLabelValue(getMsg("administrative-users-label", false), text, maxLabelWidth); } } /** * Writes the install path contents displaying with what is specified in the * provided ServerStatusDescriptor object. * @param desc the ServerStatusDescriptor object. */ private void writeInstallPathContents(ServerStatusDescriptor desc, int maxLabelWidth) { File path = desc.getInstallPath(); writeLabelValue(getMsg("installation-path-label", false), path.toString(), maxLabelWidth); } /** * Updates the server version contents displaying with what is specified in * the provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void writeVersionContents(ServerStatusDescriptor desc, int maxLabelWidth) { String openDSVersion = desc.getOpenDSVersion(); writeLabelValue(getMsg("opends-version-label", false), openDSVersion, maxLabelWidth); } /** * Updates the java version contents displaying with what is specified in * the provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void writeJavaVersionContents(ServerStatusDescriptor desc, int maxLabelWidth) { String text; if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { text = desc.getJavaVersion(); if (text == null) { if (!desc.isAuthenticated()) { text = getNotAvailableBecauseAuthenticationIsRequiredText(); } else { text = getNotAvailableText(); } } } else { text = getNotAvailableBecauseServerIsDownText(); } writeLabelValue(getMsg("java-version-label", false), text, maxLabelWidth); } /** * Writes the listeners contents displaying with what is specified in * the provided ServerStatusDescriptor object. * @param desc the ServerStatusDescriptor object. */ private void writeListenerContents(ServerStatusDescriptor desc) { String title = getMsg("listeners-title", false); System.out.println(centerTitle(title)); Set<ListenerDescriptor> listeners = desc.getListeners(); if (listeners.size() == 0) { if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { if (!desc.isAuthenticated()) { System.out.println( getMsg("not-available-authentication-required-cli-label", true)); } else { System.out.println(getMsg("no-listeners-found", true)); } } else { System.out.println(getMsg("no-listeners-found", true)); } } else { ListenersTableModel listenersTableModel = new ListenersTableModel(); listenersTableModel.setData(desc.getListeners()); writeTableModel(listenersTableModel, desc); } } /** * Writes the databases contents displaying with what is specified in * the provided ServerStatusDescriptor object. * @param desc the ServerStatusDescriptor object. */ private void writeDatabaseContents(ServerStatusDescriptor desc) { String title = getMsg("databases-title", false); System.out.println(centerTitle(title)); Set<DatabaseDescriptor> databases = desc.getDatabases(); if (databases.size() == 0) { if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { if (!desc.isAuthenticated()) { System.out.println( getMsg("not-available-authentication-required-cli-label", true)); } else { System.out.println(getMsg("no-dbs-found", true)); } } else { System.out.println(getMsg("no-dbs-found", true)); } } else { DatabasesTableModel databasesTableModel = new DatabasesTableModel(); databasesTableModel.setData(desc.getDatabases()); writeTableModel(databasesTableModel, desc); } } /** * Writes the error label contents displaying with what is specified in * the provided ServerStatusDescriptor object. * @param desc the ServerStatusDescriptor object. */ private void writeErrorContents(ServerStatusDescriptor desc) { String errorMsg = desc.getErrorMessage(); if (errorMsg != null) { System.out.println(); System.out.println(wrap(errorMsg)); } } /** * Returns the not available text explaining that the data is not available * because the server is down. * @return the text. */ private String getNotAvailableBecauseServerIsDownText() { displayMustStartLegend = true; return getMsg("not-available-server-down-cli-label", false); } /** * Returns the not available text explaining that the data is not available * because authentication is required. * @return the text. */ private String getNotAvailableBecauseAuthenticationIsRequiredText() { displayMustAuthenticateLegend = true; return getMsg("not-available-authentication-required-cli-label", false); } /** * Returns the not available text explaining that the data is not available. * @return the text. */ private String getNotAvailableText() { return getMsg("not-available-label", false); } private void writeTableModel(TableModel tableModel, ServerStatusDescriptor desc) { int[] maxWidths = new int[tableModel.getColumnCount()]; for (int i=0; i<maxWidths.length; i++) { maxWidths[i] = tableModel.getColumnName(i).length(); } for (int i=0; i<tableModel.getRowCount(); i++) { for (int j=0; j<maxWidths.length; j++) { Object v = tableModel.getValueAt(i, j); if (v != null) { if (v instanceof String) { maxWidths[j] = Math.max(maxWidths[j], ((String)v).length()); } else if (v instanceof Integer) { String text; int nEntries = ((Integer)v).intValue(); if (nEntries >= 0) { text = String.valueOf(nEntries); } else { if (!desc.isAuthenticated()) { text = getNotAvailableBecauseAuthenticationIsRequiredText(); } else { text = getNotAvailableText(); } } maxWidths[j] = Math.max(maxWidths[j], text.length()); } else { throw new IllegalStateException("Unknown object type: "+v); } } } } int totalWidth = 0; for (int i=0; i<maxWidths.length; i++) { if (i < maxWidths.length - 1) { maxWidths[i] += 5; } totalWidth += maxWidths[i]; } StringBuffer headerLine = new StringBuffer(); for (int i=0; i<maxWidths.length; i++) { String header = tableModel.getColumnName(i); headerLine.append(header); int extra = maxWidths[i] - header.length(); for (int j=0; j<extra; j++) { headerLine.append(" "); } } System.out.println(wrap(headerLine.toString())); StringBuffer t = new StringBuffer(); for (int i=0; i<headerLine.length(); i++) { t.append("="); } System.out.println(wrap(t.toString())); for (int i=0; i<tableModel.getRowCount(); i++) { StringBuffer line = new StringBuffer(); for (int j=0; j<tableModel.getColumnCount(); j++) { int extra = maxWidths[j]; Object v = tableModel.getValueAt(i, j); if (v != null) { if (v instanceof String) { line.append(v); extra -= ((String)v).length(); } else if (v instanceof Integer) { int nEntries = ((Integer)v).intValue(); if (nEntries >= 0) { line.append(nEntries); } else { if (!desc.isAuthenticated()) { line.append( getNotAvailableBecauseAuthenticationIsRequiredText()); } else { line.append(getNotAvailableText()); } } } else { throw new IllegalStateException("Unknown object type: "+v); } } for (int k=0; k<extra; k++) { line.append(" "); } } System.out.println(wrap(line.toString())); } } private void writeLabelValue(String label, String value, int maxLabelWidth) { StringBuffer buf = new StringBuffer(); buf.append(label); int extra = maxLabelWidth - label.length(); for (int i = 0; i<extra; i++) { buf.append(" "); } buf.append(" "+value); System.out.println(wrap(buf.toString())); } private String wrap(String text) { return org.opends.server.util.StaticUtils.wrapText(text, Utils.getCommandLineMaxLineWidth()); } private String centerTitle(String text) { String centered; if (text.length() <= Utils.getCommandLineMaxLineWidth() - 8) { StringBuffer buf = new StringBuffer(); int extra = Math.min(10, (Utils.getCommandLineMaxLineWidth() - 8 - text.length()) / 2); for (int i=0; i<extra; i++) { buf.append(" "); } buf.append("--- "+text+" ---"); centered = buf.toString(); } else { centered = text; } return centered; } } opends/src/statuspanel/org/opends/statuspanel/StatusPanelController.java
New file @@ -0,0 +1,1241 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Map; import javax.swing.SwingUtilities; import org.opends.server.core.DirectoryServer; import org.opends.quicksetup.ui.UIFactory; import org.opends.quicksetup.util.BackgroundTask; import org.opends.quicksetup.util.HtmlProgressMessageFormatter; import org.opends.quicksetup.util.Utils; import org.opends.statuspanel.event.ServerStatusChangeEvent; import org.opends.statuspanel.event.ServerStatusChangeListener; import org.opends.statuspanel.event.StatusPanelButtonListener; import org.opends.statuspanel.i18n.ResourceProvider; import org.opends.statuspanel.ui.LoginDialog; import org.opends.statuspanel.ui.ProgressDialog; import org.opends.statuspanel.ui.StatusPanelDialog; /** * This is the main class of the status panel. * * It is in charge of all the logic behind the displaying of the dialogs and * the one that initializes everything. This is also the class that ultimately * listens to user events (notably button clicks) and executes the associated * operations with these user events. * */ public class StatusPanelController implements ServerStatusChangeListener, StatusPanelButtonListener { private LoginDialog loginDialog; private StatusPanelDialog controlPanelDialog; private ProgressDialog progressDialog; private ServerStatusPooler serverStatusPooler; private HtmlProgressMessageFormatter formatter = new HtmlProgressMessageFormatter(); private boolean isStarting; private boolean isStopping; private boolean isRestarting; private boolean mustDisplayAuthenticateDialog; private ServerStatusDescriptor desc; private String lastDetail; private String lastSummary; private Thread progressUpdater; //Update period of the progress dialog. private static final int UPDATE_PERIOD = 500; /** * This method creates the control panel dialogs and to check the current * install status. This method must be called outside the event thread because * it can perform long operations which can make the user think that the UI is * blocked. * * Note that there is no synchronization code between threads. The * synchronization code is not required as all the start/stop/restart actions * are launched in the event thread so just using booleans that are updated * in the event thread is enough to guarantee that there are no multiple * operations launched at the same time. * * @param args for the moment this parameter is not used but we keep it in * order to (in case of need) pass parameters through the command line. */ public void initialize(String[] args) { DirectoryServer.bootstrapClient(); initLookAndFeel(); /* Call this methods to create the dialogs (the control panel dialog * is generated when we call getLoginDialog()). */ getLoginDialog(); getProgressDialog(); serverStatusPooler = new ServerStatusPooler(); serverStatusPooler.addServerStatusChangeListener(this); serverStatusPooler.startPooling(); desc = serverStatusPooler.getLastDescriptor(); while (desc == null) { try { Thread.sleep(100); } catch (Exception ex) { } desc = serverStatusPooler.getLastDescriptor(); } } /** * This method displays the required dialog. This method must be called from * the event thread. */ public void display() { getStatusPanelDialog().packAndShow(); if (!isAuthenticated()) { if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { authenticateClicked(); } } } /** * ServerStatusChangeListener implementation. This method is called when * a new ServerStatusDescriptor has been generated by the ServerStatusPooler. * @param ev the event we receive. */ public void statusChanged(final ServerStatusChangeEvent ev) { /* Here we assume that this events are not very frequent (not frequent * at least to generate flickering). This is acceptable since the * ServerStatusPooler does pooling every second. */ if (SwingUtilities.isEventDispatchThread()) { getStatusPanelDialog().updateContents(ev.getStatusDescriptor()); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { getStatusPanelDialog().updateContents(ev.getStatusDescriptor()); } }); } } /** * Method called when user clicks on Quit button. * StatusPanelButtonListener implementation. */ public void quitClicked() { System.exit(0); } /** * Method called when user clicks on Start button. * StatusPanelButtonListener implementation. */ public void startClicked() { if (isStarting) { if (!getProgressDialog().isVisible()) { getProgressDialog().setVisible(true); } } else if (isStopping) { /* Should not happen */ Thread.dumpStack(); } else if (isRestarting) { /* Should not happen */ Thread.dumpStack(); } else { isStarting = true; lastDetail = null; getProgressDialog().setSummary( getFormattedSummary(getMsg("summary-starting"))); getProgressDialog().setDetails(""); serverStatusPooler.beginServerStart(); getProgressDialog().setCloseButtonEnabled(false); getStatusPanelDialog().setStartButtonEnabled(false); getStatusPanelDialog().setStopButtonEnabled(false); getStatusPanelDialog().setRestartButtonEnabled(false); getStatusPanelDialog().setAuthenticateButtonEnabled(false); if (!getProgressDialog().isVisible()) { getProgressDialog().pack(); Utils.centerOnComponent(getProgressDialog(), getStatusPanelDialog()); getProgressDialog().setVisible(true); } BackgroundTask task = new BackgroundTask() { public Object processBackgroundTask() { if (progressUpdater == null) { runProgressUpdater(); } mustDisplayAuthenticateDialog = startServer() && !isAuthenticated(); serverStatusPooler.endServerStart(); return null; } public void backgroundTaskCompleted(Object value, Throwable t) { if (t != null) { // Bug t.printStackTrace(); } getStatusPanelDialog().setStartButtonEnabled(true); getStatusPanelDialog().setStopButtonEnabled(true); getStatusPanelDialog().setRestartButtonEnabled(true); getStatusPanelDialog().setAuthenticateButtonEnabled( !isAuthenticated()); getProgressDialog().setCloseButtonEnabled(true); isStarting = false; } }; task.startBackgroundTask(); } } /** * Method called when user clicks on Stop button. * StatusPanelButtonListener implementation. */ public void stopClicked() { if (isStopping) { if (!getProgressDialog().isVisible()) { getProgressDialog().setVisible(true); } } else if (isStarting) { /* Should not happen */ Thread.dumpStack(); } else if (isRestarting) { /* Should not happen */ Thread.dumpStack(); } else { boolean stopServer = false; if (requiresAuthenticationToStop()) { getLoginDialog().pack(); Utils.centerOnComponent(getLoginDialog(), getStatusPanelDialog()); getLoginDialog().setVisible(true); if (!getLoginDialog().isCancelled()) { serverStatusPooler.setAuthentication( getLoginDialog().getDirectoryManagerDn(), getLoginDialog().getDirectoryManagerPwd()); stopServer = confirmStop(); } } else { stopServer = confirmStop(); } if (stopServer) { isStopping = true; lastDetail = null; getProgressDialog().setSummary( getFormattedSummary(getMsg("summary-stopping"))); getProgressDialog().setDetails(""); serverStatusPooler.beginServerStop(); getProgressDialog().setCloseButtonEnabled(false); getStatusPanelDialog().setStartButtonEnabled(false); getStatusPanelDialog().setStopButtonEnabled(false); getStatusPanelDialog().setRestartButtonEnabled(false); getStatusPanelDialog().setAuthenticateButtonEnabled(false); if (!getProgressDialog().isVisible()) { getProgressDialog().pack(); Utils.centerOnComponent(getProgressDialog(), getStatusPanelDialog()); getProgressDialog().setVisible(true); } BackgroundTask task = new BackgroundTask() { public Object processBackgroundTask() { if (progressUpdater == null) { runProgressUpdater(); } stopServer(); serverStatusPooler.endServerStop(); mustDisplayAuthenticateDialog = false; return null; } public void backgroundTaskCompleted(Object value, Throwable t) { if (t != null) { // Bug t.printStackTrace(); } getStatusPanelDialog().setStartButtonEnabled(true); getStatusPanelDialog().setStopButtonEnabled(true); getStatusPanelDialog().setRestartButtonEnabled(true); getStatusPanelDialog().setAuthenticateButtonEnabled(false); getProgressDialog().setCloseButtonEnabled(true); isStopping = false; } }; task.startBackgroundTask(); } } } /** * Method called when user clicks on Restart button. * StatusPanelButtonListener implementation. */ public void restartClicked() { if (isRestarting) { if (!getProgressDialog().isVisible()) { getProgressDialog().setVisible(true); } } else if (isStopping) { /* Should not happen */ Thread.dumpStack(); } else if (isStarting) { /* Should not happen */ Thread.dumpStack(); } else { boolean restartServer = false; if (requiresAuthenticationToRestart()) { getLoginDialog().pack(); Utils.centerOnComponent(getLoginDialog(), getStatusPanelDialog()); getLoginDialog().setVisible(true); if (!getLoginDialog().isCancelled()) { serverStatusPooler.setAuthentication( getLoginDialog().getDirectoryManagerDn(), getLoginDialog().getDirectoryManagerPwd()); restartServer = confirmRestart(); } } else { restartServer = confirmRestart(); } if (restartServer) { isRestarting = true; lastDetail = null; getProgressDialog().setSummary( getFormattedSummary(getMsg("summary-stopping"))); getProgressDialog().setDetails(""); serverStatusPooler.beginServerStop(); getProgressDialog().setCloseButtonEnabled(false); getStatusPanelDialog().setStartButtonEnabled(false); getStatusPanelDialog().setStopButtonEnabled(false); getStatusPanelDialog().setRestartButtonEnabled(false); getStatusPanelDialog().setAuthenticateButtonEnabled(false); if (!getProgressDialog().isVisible()) { getProgressDialog().pack(); Utils.centerOnComponent(getProgressDialog(), getStatusPanelDialog()); getProgressDialog().setVisible(true); } BackgroundTask task = new BackgroundTask() { public Object processBackgroundTask() { if (progressUpdater == null) { runProgressUpdater(); } if (stopServer()) { serverStatusPooler.endServerStop(); serverStatusPooler.beginServerStart(); mustDisplayAuthenticateDialog = startServer() && !isAuthenticated(); serverStatusPooler.endServerStart(); } else { serverStatusPooler.endServerStop(); mustDisplayAuthenticateDialog = false; } return null; } public void backgroundTaskCompleted(Object value, Throwable t) { if (t != null) { // Bug t.printStackTrace(); } getStatusPanelDialog().setStartButtonEnabled(true); getStatusPanelDialog().setStopButtonEnabled(true); getStatusPanelDialog().setRestartButtonEnabled(true); getStatusPanelDialog().setAuthenticateButtonEnabled( !isAuthenticated()); getProgressDialog().setCloseButtonEnabled(true); isRestarting = false; } }; task.startBackgroundTask(); } } } /** * Method called when user clicks on Authenticate button. * StatusPanelButtonListener implementation. */ public void authenticateClicked() { getLoginDialog().pack(); Utils.centerOnComponent(getLoginDialog(), getStatusPanelDialog()); getLoginDialog().setVisible(true); if (!getLoginDialog().isCancelled()) { serverStatusPooler.setAuthentication( getLoginDialog().getDirectoryManagerDn(), getLoginDialog().getDirectoryManagerPwd()); } } /** * A method to initialize the look and feel. * */ private void initLookAndFeel() { UIFactory.initialize(); } /** * Returns the login dialog and creates it if it does not exist. * @return the login dialog. */ private LoginDialog getLoginDialog() { if (loginDialog == null) { loginDialog = new LoginDialog(getStatusPanelDialog()); loginDialog.setModal(true); } return loginDialog; } /** * Returns the progress dialog and creates it if it does not exist. * As we only can run an operation at a time (considering the nature of the * operations we provide today) having a single progress dialog is enough. * @return the progress dialog. */ private ProgressDialog getProgressDialog() { if (progressDialog == null) { progressDialog = new ProgressDialog(getStatusPanelDialog()); progressDialog.addWindowListener(new WindowAdapter() { public void windowClosed(WindowEvent ev) { if (mustDisplayAuthenticateDialog) { mustDisplayAuthenticateDialog = false; authenticateClicked(); } } }); } return progressDialog; } /** * Returns the status panel dialog and creates it if it does not exist. This * is the dialog that displays the status information to the user. * @return the status panel dialog. */ private StatusPanelDialog getStatusPanelDialog() { if (controlPanelDialog == null) { controlPanelDialog = new StatusPanelDialog(); controlPanelDialog.addButtonListener(this); } return controlPanelDialog; } /** * This methods starts the server and updates the progress with the start * messages. * @return <CODE>true</CODE> if the server started successfully and * <CODE>false</CODE> otherwise. */ protected boolean startServer() { boolean started = false; if (isRestarting) { updateProgress( getFormattedSummary(getMsg("summary-starting")), getTaskSeparator()); } updateProgress( getFormattedSummary(getMsg("summary-starting")), getFormattedProgress(getMsg("progress-starting")) + getLineBreak()); ArrayList<String> argList = new ArrayList<String>(); if (Utils.isWindows()) { argList.add(Utils.getPath(getBinariesPath(), "start-ds.bat")); } else { argList.add(Utils.getPath(getBinariesPath(), "start-ds")); } String[] args = new String[argList.size()]; argList.toArray(args); ProcessBuilder pb = new ProcessBuilder(args); Map<String, String> env = pb.environment(); env.put("JAVA_HOME", System.getProperty("java.home")); /* Remove JAVA_BIN to be sure that we use the JVM running the installer * JVM to start the server. */ env.remove("JAVA_BIN"); try { Process process = pb.start(); BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream())); BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream())); /* Create these objects to resend the stop process output to the details * area. */ new ProgressReader(err, true, true); new ProgressReader(out, false, true); int returnValue = process.waitFor(); if (returnValue == 0) { /* * There are no exceptions from the readers and they are marked as * finished. This means that the server has written in its output the * message id informing that it started. So it seems that everything * went fine. * * However we can have issues with the firewalls or do not have rights * to connect. Just check if we can connect to the server. * Try 5 times with an interval of 1 second between try. */ boolean running = false; for (int i=0; i<5 && !running; i++) { running = Utils.isServerRunning( Utils.getInstallPathFromClasspath()); } if (!running) { try { Thread.sleep(1000); } catch (Throwable t) { } } if (!running) { updateProgress(getFormattedError(getMsg("summary-start-error")), getFormattedError(getMsg("error-starting-server-generic"), true)); } else { updateProgress( getFormattedSuccess(getMsg("summary-start-success")), ""); started = true; } } else { String[] arg = {String.valueOf(returnValue)}; String msg = getMsg("error-starting-server-code", arg); /* * The return code is not the one expected, assume the server could * not be started. */ updateProgress( getFormattedError(getMsg("summary-start-error")), msg); } } catch (IOException ioe) { String msg = getThrowableMsg("error-starting-server", ioe); updateProgress( getFormattedError(getMsg("summary-start-error")), msg); } catch (InterruptedException ie) { String msg = getThrowableMsg("error-starting-server", ie); updateProgress( getFormattedError(getMsg("summary-start-error")), msg); } return started; } /** * This methods stops the server and updates the progress with the stop * messages. * @return <CODE>true</CODE> if the server stopped successfully and * <CODE>false</CODE> otherwise. */ private boolean stopServer() { boolean stopped = false; updateProgress( getFormattedSummary(getMsg("summary-stopping")), getFormattedProgress(getMsg("progress-stopping")) + getLineBreak()); ArrayList<String> argList = new ArrayList<String>(); if (Utils.isWindows()) { argList.add(Utils.getPath(getBinariesPath(), "stop-ds.bat")); argList.add("--bindDN"); argList.add(getLoginDialog().getDirectoryManagerDn()); argList.add("--bindPassword"); argList.add(getLoginDialog().getDirectoryManagerPwd()); } else { argList.add(Utils.getPath(getBinariesPath(), "stop-ds")); } String[] args = new String[argList.size()]; argList.toArray(args); ProcessBuilder pb = new ProcessBuilder(args); Map<String, String> env = pb.environment(); env.put("JAVA_HOME", System.getProperty("java.home")); /* Remove JAVA_BIN to be sure that we use the JVM running the uninstaller * JVM to stop the server. */ env.remove("JAVA_BIN"); try { Process process = pb.start(); BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream())); BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream())); /* Create these objects to resend the stop process output to the details * area. */ new ProgressReader(err, true, false); new ProgressReader(out, false, false); int returnValue = process.waitFor(); int clientSideError = org.opends.server.protocols.ldap.LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR; if ((returnValue == clientSideError) || (returnValue == 0)) { if (Utils.isWindows()) { /* * Sometimes the server keeps some locks on the files. * TODO: remove this code once stop-ds returns properly when server * is stopped. */ int nTries = 10; for (int i=0; i<nTries && !stopped; i++) { stopped = !Utils.isServerRunning( Utils.getInstallPathFromClasspath()); if (!stopped) { String msg = getFormattedLog(getMsg("progress-server-waiting-to-stop"))+ getLineBreak(); updateProgress( getFormattedSummary(getMsg("summary-stopping")), msg); try { Thread.sleep(5000); } catch (Exception ex) { } } } if (!stopped) { returnValue = -1; } } } if (returnValue == clientSideError) { String msg = getLineBreak() + getFormattedLog(getMsg("progress-server-already-stopped"))+ getLineBreak(); if (!isRestarting) { updateProgress( getFormattedSuccess(getMsg("summary-stop-success")), msg); } else { updateProgress( getFormattedSummary(getMsg("summary-stop-success")), msg); } stopped = true; } else if (returnValue != 0) { String[] arg = {String.valueOf(returnValue)}; String msg = getMsg("error-stopping-server-code", arg); /* * The return code is not the one expected, assume the server could * not be stopped. */ updateProgress( getFormattedError(getMsg("summary-stop-error")), msg); } else { String msg = getFormattedLog(getMsg("progress-server-stopped")); if (!isRestarting) { updateProgress( getFormattedSuccess(getMsg("summary-stop-success")), msg); } else { updateProgress( getFormattedSummary(getMsg("summary-stop-success")), msg); } stopped = true; } } catch (IOException ioe) { String msg = getThrowableMsg("error-stopping-server", ioe); updateProgress( getFormattedError(getMsg("summary-stop-error")), msg); } catch (InterruptedException ie) { String msg = getThrowableMsg("error-stopping-server", ie); updateProgress( getFormattedError(getMsg("summary-stop-error")), msg); } return stopped; } /** * Updates the progress variables used to update the progress dialog during * start/stop/restart. * * @param summary the summary for the start/stop/restart operation. * @param newDetail the new detail for the start/stop/restart operation. */ private synchronized void updateProgress(final String summary, final String newDetail) { if (lastDetail == null) { lastDetail = newDetail; } else { lastDetail += newDetail; } lastSummary = summary; } /** * This method is used to update the progress dialog. * * We are receiving notifications from the installer and uninstaller (this * class is a ProgressListener). However if we lots of notifications updating * the progress panel every time we get a progress update can result of a lot * of flickering. So the idea here is to have a minimal time between 2 updates * of the progress dialog (specified by UPDATE_PERIOD). */ private void runProgressUpdater() { progressUpdater = new Thread() { public void run() { try { String lastDisplayedSummary = null; String lastDisplayedDetail = null; while (true) { if (lastSummary != null) { if (lastSummary != lastDisplayedSummary) { lastDisplayedSummary = lastSummary; SwingUtilities.invokeLater(new Runnable() { public void run() { getProgressDialog().setSummary(lastSummary); } }); } } if (lastDetail != null) { if (lastDetail != lastDisplayedDetail) { lastDisplayedDetail = lastDetail; SwingUtilities.invokeLater(new Runnable() { public void run() { getProgressDialog().setDetails(lastDetail); } }); } } try { Thread.sleep(UPDATE_PERIOD); } catch (Exception ex) { } } } catch (Throwable t) { // Bug t.printStackTrace(); } } }; progressUpdater.start(); } /** * Returns a localized message for a key value. In the properties file we * have something of type: * key=value * * @see ResourceProvider.getMsg(String key) * @param key the key in the properties file. * @return the value associated to the key in the properties file. * properties file. */ private String getMsg(String key) { return getI18n().getMsg(key); } /** * Returns a localized message for a key value. In the properties file we * have something of type: * key=value * * For instance if we pass as key "mykey" and as arguments {"value1"} and * in the properties file we have: * mykey=value with argument {0}. * * This method will return "value with argument value1". * @see ResourceProvider.getMsg(String key, String[] args) * @param key the key in the properties file. * @param args the arguments to be passed to generate the resulting value. * @return the value associated to the key in the properties file. */ private String getMsg(String key, String[] args) { return getI18n().getMsg(key, args); } /** * Returns a ResourceProvider instance. * @return a ResourceProvider instance. */ private ResourceProvider getI18n() { return ResourceProvider.getInstance(); } /** * Returns the path to the binaries. * @return the path to the binaries. */ private String getBinariesPath() { return Utils.getPath(Utils.getInstallPathFromClasspath(), Utils.getBinariesRelativePath()); } /** * Returns the formatted representation of the text that is the summary of the * installation process (the one that goes in the UI next to the progress * bar). * @param text the source text from which we want to get the formatted * representation * @return the formatted representation of an error for the given text. */ private String getFormattedSummary(String text) { return formatter.getFormattedSummary(text); } /** * Returns the formatted representation of a success message for a given text. * @param text the source text from which we want to get the formatted * representation. * @return the formatted representation of an success message for the given * text. */ private String getFormattedSuccess(String text) { return formatter.getFormattedSuccess(text); } /** * Returns the formatted representation of an error for a given text. * @param text the source text from which we want to get the formatted * representation * @return the formatted representation of an error for the given text. */ private String getFormattedError(String text) { return formatter.getFormattedError(text, false); } /** * Returns the formatted representation of an error for a given text. * @param text the source text from which we want to get the formatted * representation * @return the formatted representation of an error for the given text. */ private String getFormattedError(String text, boolean applyMargin) { return formatter.getFormattedError(text, applyMargin); } /** * Returns the formatted representation of a log error message for a given * text. * @param text the source text from which we want to get the formatted * representation * @return the formatted representation of a log error message for the given * text. */ private String getFormattedLogError(String text) { return formatter.getFormattedLogError(text); } /** * Returns the formatted representation of a log message for a given text. * @param text the source text from which we want to get the formatted * representation * @return the formatted representation of a log message for the given text. */ private String getFormattedLog(String text) { return formatter.getFormattedLog(text); } /** * Returns the line break formatted. * @return the line break formatted. */ private String getLineBreak() { return formatter.getLineBreak(); } /** * Returns the task separator formatted. * @return the task separator formatted. */ private String getTaskSeparator() { return formatter.getTaskSeparator(); } /** * Returns the formatted representation of a progress message for a given * text. * @param text the source text from which we want to get the formatted * representation * @return the formatted representation of a progress message for the given * text. */ private String getFormattedProgress(String text) { return formatter.getFormattedProgress(text); } /** * Returns a localized message for a given properties key and throwable. * @param key the key of the message in the properties file. * @param t the throwable for which we want to get a message. * @return a localized message for a given properties key and throwable. */ private String getThrowableMsg(String key, Throwable t) { return getThrowableMsg(key, null, t); } /** * Returns a localized message for a given properties key and throwable. * @param key the key of the message in the properties file. * @param args the arguments of the message in the properties file. * @param t the throwable for which we want to get a message. * * @return a localized message for a given properties key and throwable. */ private String getThrowableMsg(String key, String[] args, Throwable t) { return Utils.getThrowableMsg(getI18n(), key, args, t); } /** * This class is used to read the standard error and standard output of the * Stop/Start process. * * When a new log message is found notifies the progress listeners of it. If * an error occurs it also notifies the listeners. * */ private class ProgressReader { private boolean isFirstLine; private String errorMsg; /** * The protected constructor. * @param reader the BufferedReader of the stop process. * @param isError a boolean indicating whether the BufferedReader * corresponds to the standard error or to the standard output. * @param isStart a boolean indicating whether we are starting or stopping * the server. */ public ProgressReader(final BufferedReader reader, final boolean isError, final boolean isStart) { final String errorTag = isError ? "error-reading-erroroutput" : "error-reading-output"; isFirstLine = true; Thread t = new Thread(new Runnable() { public void run() { try { String line = reader.readLine(); while (line != null) { StringBuffer buf = new StringBuffer(); if (!isFirstLine) { buf.append(formatter.getLineBreak()); } if (isError) { buf.append(getFormattedLogError(line)); } else { buf.append(getFormattedLog(line)); } String summary = isStart? getFormattedSummary(getMsg("summary-starting")): getFormattedSummary(getMsg("summary-stopping")); updateProgress(summary, buf.toString()); isFirstLine = false; line = reader.readLine(); } } catch (IOException ioe) { errorMsg = getThrowableMsg(errorTag, ioe); } catch (Throwable t) { errorMsg = getThrowableMsg(errorTag, t); } } }); t.start(); } public String getErrorMessage() { return errorMsg; } } /** * Displays a confirmation dialog asking the user whether to stop the server * or not. * @return <CODE>true</CODE> if the server confirms that (s)he wants to stop * the server and <CODE>false</CODE> otherwise. */ private boolean confirmStop() { return Utils.displayConfirmation(getStatusPanelDialog(), getMsg("confirm-stop-message"), getMsg("confirm-stop-title")); } /** * Displays a confirmation dialog asking the user whether to restart the * server or not. * @return <CODE>true</CODE> if the server confirms that (s)he wants to * restart the server and <CODE>false</CODE> otherwise. */ private boolean confirmRestart() { return Utils.displayConfirmation(getStatusPanelDialog(), getMsg("confirm-restart-message"), getMsg("confirm-restart-title")); } /** * Returns whether the user provided LDAP authentication or not. * @return <CODE>true</CODE> if the server provided LDAP authentication and * <CODE>false</CODE> otherwise. */ private boolean isAuthenticated() { return serverStatusPooler.isAuthenticated(); } private boolean requiresAuthenticationToStop() { boolean requireAuthentication; ServerStatusDescriptor desc = serverStatusPooler.getLastDescriptor(); if (desc == null) { requireAuthentication = Utils.isWindows() && !isAuthenticated(); } else { requireAuthentication = Utils.isWindows() && (!isAuthenticated() || desc.getErrorMessage() != null); } return requireAuthentication; } private boolean requiresAuthenticationToRestart() { return requiresAuthenticationToStop(); } } opends/src/statuspanel/org/opends/statuspanel/StatusPanelLauncher.java
New file @@ -0,0 +1,178 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import org.opends.quicksetup.util.Utils; import org.opends.statuspanel.i18n.ResourceProvider; /** * This class is called by the control panel command lines to launch the * control panel of the Directory Server. * */ public class StatusPanelLauncher { private static String COMMAND_NAME_WINDOWS = "statuspanel.bat"; private static String COMMAND_NAME_UNIX = "statuspanel"; /** * The main method which is called by the control panel command lines. * @param args the arguments passed by the command lines. */ public static void main(String[] args) { boolean printUsage = false; if ((args != null) && (args.length > 4)) { printUsage = true; } if (printUsage) { printUsage(); System.exit(1); } else { int exitCode = launchGuiStatusPanel(args); if (exitCode != 0) { System.err.println(getMsg("status-panel-launcher-gui-launch-failed")); System.exit(exitCode); } } } /** * Launches the graphical status panel. It is launched in a * different thread that the main thread because if we have a problem with the * graphical system (for instance the DISPLAY environment variable is not * correctly set) the native libraries will call exit. However if we launch * this from another thread, the thread will just be killed. * * This code also assumes that if the call to SplashWindow.main worked (and * the splash screen was displayed) we will never get out of it (we will call * a System.exit() when we close the graphical uninstall dialog). * * @params String[] args the arguments used to call the SplashWindow main * method * @return 0 if everything worked fine, or 1 if we could not display properly * the SplashWindow. */ private static int launchGuiStatusPanel(final String[] args) { final int[] returnValue = { -1 }; Thread t = new Thread(new Runnable() { public void run() { SplashScreen.main(args); returnValue[0] = 0; } }); /* * This is done to avoid displaying the stack that might occur if there are * problems with the display environment. */ PrintStream printStream = System.err; //System.setErr(new EmptyPrintStream()); t.start(); try { t.join(); } catch (InterruptedException ie) { /* An error occurred, so the return value will be -1. We got nothing to do with this exception. */ } System.setErr(printStream); return returnValue[0]; } private static void printUsage() { String arg; if (Utils.isWindows()) { arg = COMMAND_NAME_WINDOWS; } else { arg = COMMAND_NAME_UNIX; } /* * This is required because the usage message contains '{' characters that * mess up the MessageFormat.format method. */ String msg = getMsg("status-panel-launcher-usage"); msg = msg.replace("{0}", arg); System.err.println(msg); } /** * The following three methods are just commodity methods to get localized * messages. */ private static String getMsg(String key) { return org.opends.server.util.StaticUtils.wrapText(getI18n().getMsg(key), Utils.getCommandLineMaxLineWidth()); } private static ResourceProvider getI18n() { return ResourceProvider.getInstance(); } /** * This class is used to avoid displaying the error message related to display * problems that we might have when trying to display the SplashWindow. * */ static class EmptyPrintStream extends PrintStream { /** * Default constructor. * */ public EmptyPrintStream() { super(new ByteArrayOutputStream(), true); } /** * {@inheritDoc} */ public void println(String msg) { } } } opends/src/statuspanel/org/opends/statuspanel/event/ServerStatusChangeEvent.java
New file @@ -0,0 +1,63 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel.event; import org.opends.statuspanel.ServerStatusDescriptor; /** * The event that is generated when there is a change of the server status. * * In the current implementation this events are generated by the * ServerStatusPooler object and are notified to the objects implementing * ServerStatusChangeListener (StatusPanelController object). * */ public class ServerStatusChangeEvent { private ServerStatusDescriptor statusDescriptor; /** * Constructor of the ServerStatusChangeEvent. * @param statusDescriptor the object describing the current server status * and configuration. */ public ServerStatusChangeEvent(ServerStatusDescriptor statusDescriptor) { this.statusDescriptor = statusDescriptor; } /** * Returns the ServerStatusDescriptor object. * @return the ServerStatusDescriptor object. */ public ServerStatusDescriptor getStatusDescriptor() { return statusDescriptor; } } opends/src/statuspanel/org/opends/statuspanel/event/ServerStatusChangeListener.java
New file @@ -0,0 +1,44 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel.event; /** * Interface that implement the objects that want to receive notifications of * changes in the server status. * */ public interface ServerStatusChangeListener { /** * Method called when an change in the server status occurs. * * @param ev the ServerStatusChangeEvent describing the change that occurred * in the server status. */ public void statusChanged(ServerStatusChangeEvent ev); } opends/src/statuspanel/org/opends/statuspanel/event/StatusPanelButtonListener.java
New file @@ -0,0 +1,60 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel.event; /** * Interface used to be notified of the button actions that can occur in the * StatusPanelDialog. * * In the current implementation StatusPanelController implements this * interface. * */ public interface StatusPanelButtonListener { /** * Method called when user clicks on Authenticate button. */ public void authenticateClicked(); /** * Method called when user clicks on Start button. */ public void startClicked(); /** * Method called when user clicks on Restart button. */ public void restartClicked(); /** * Method called when user clicks on Stop button. */ public void stopClicked(); /** * Method called when user clicks on Quit button. */ public void quitClicked(); } opends/src/statuspanel/org/opends/statuspanel/i18n/ResourceProvider.java
New file @@ -0,0 +1,192 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel.i18n; import java.text.MessageFormat; import java.util.ResourceBundle; /** * This class is used to retrieve localized messages from Resources.properties * files. This class extends org.opends.quicksetup.i18n.ResourceProvider so * that it first looks for properties in the Resources.properties located in * the org.opends.quicksetup.resources package and then if they are not there * looks for properties in org.opends.statuspanel.resources. * * This is done to avoid duplication of properties between the setup and the * status panel. * */ public class ResourceProvider extends org.opends.quicksetup.i18n.ResourceProvider { private ResourceBundle bundle; private static ResourceProvider instance; private static final String BUNDLE_NAME = "org.opends.statuspanel.resources.Resources"; private ResourceProvider() { } /** * Provides an instance of the ResourceProvider. The instance is unique for * this process (which implies that during the process lifetime we can only * have messages in one language). * * @return an instance of ResourceProvider. */ public static ResourceProvider getInstance() { if (instance == null) { instance = new ResourceProvider(); } return instance; } /** * Gets a localized message for a key value. In the properties file we have * something of type: * key=value * @param key the key in the properties file. * @return the value associated to the key in the properties file. * @throws IllegalArgumentException if the key could not be found in the * properties file. */ public String getMsg(String key) throws IllegalArgumentException { String msg; try { /* First try to quick setup resource provider as it contains most of * the labels. */ msg = super.getMsg(key); } catch (Exception ex) { /* Now try with the status panel specific resources. */ try { msg = getResourceBundle().getString(key); } catch (java.util.MissingResourceException e) { // The less brutal alternative here is to do msg = key instead // of // throwing an exception but this helps being strict with // resources // (so I prefer to keep it as it is at least at the beginning) throw new IllegalArgumentException("Unknown Resource Bundle key: " + key); } } return msg; } /** * Gets a localized message for a key value. In the properties file we have * something of type: * key=value * * For instance if we pass as key "mykey" and as arguments {"value1"} and * in the properties file we have: * mykey=value with argument {0}. * * This method will return "value with argument value1". * * @param key the key in the properties file. * @param args the arguments to be passed to generate the resulting value. * @return the value associated to the key in the properties file. * @throws IllegalArgumentException if the key could not be found in the * properties file. */ public String getMsg(String key, String[] args) throws IllegalArgumentException { String msg; try { /* First try to quick setup resource provider as it contains most of * the labels. */ msg = super.getMsg(key, args); } catch (Exception ex) { /* Now try with the status panel specific resources. */ try { String pattern = getResourceBundle().getString(key); MessageFormat mf = new MessageFormat(pattern); msg = mf.format(args); } catch (java.util.MissingResourceException e) { // The less brutal alternative here is to do msg = key instead // of // throwing an exception but this helps being strict with // resources // (so I prefer to keep it as it is at least at the beginning) throw new IllegalArgumentException("Unknown Resource Bundle key: " + key); } } return msg; } /** * The ResourceBundle that will be used to get the localized messages. * @return the ResourceBundle that will be used to get the localized * messages. */ private ResourceBundle getResourceBundle() { if (bundle == null) { try { bundle = ResourceBundle.getBundle(BUNDLE_NAME, getLocale(), this .getClass().getClassLoader()); } catch (java.util.MissingResourceException e) { throw new IllegalStateException("Could not retrieve Resource Bundle: " + BUNDLE_NAME, e); } } return bundle; } } opends/src/statuspanel/org/opends/statuspanel/resources/Resources.properties
New file @@ -0,0 +1,179 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at # trunk/opends/resource/legal-notices/OpenDS.LICENSE # or https://OpenDS.dev.java.net/OpenDS.LICENSE. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at # trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, # add the following below this CDDL HEADER, with the fields enclosed # by brackets "[]" replaced with your own identifying * information: # Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # This file contains the primary Directory Server configuration. It must not # be directly edited while the server is online. The server configuration # should only be managed using the administration utilities provided with the # Directory Server. # # StatusPanel launcher # status-panel-launcher-usage=This command launches the Status Panel window \ which displays basic server information and will allow you to start, stop and \ restart the server.\n\ Usage: {0} {options}\n where {options} include:\n\ -H or --help\n Displays usage information for this program. status-panel-launcher-gui-launch-failed=Could not launch Status Panel. Check \ that you have access to the display. # # StatusPanel # statuspanel-dialog-title=OpenDS Status Panel quit-status-panel-button-tooltip=Quit Status Panel server-status-title=Server Status server-status-label=Server Run Status: not-available-label=<not available> not-available-server-down-tooltip=<html>Information is only available if \ server is running and you are authenticated<br>as an administrative user. not-available-authentication-required-tooltip=<html>Information is only \ available if you are authenticated<br>as an administrative user. stop-button-label=Stop stop-button-tooltip=Stops the Directory Server start-button-label=Start start-button-tooltip=Starts the Directory Server restart-button-label=Restart restart-button-tooltip=Restarts the Directory Server connections-label=Open Connections: server-details-title=Server Details administrative-users-label=Administrative Users: installation-path-label=Installation Path: opends-version-label=OpenDS Version: java-version-label=Java Version: login-dialog-title=Authentication Required login-dialog-windows-msg=You must provide an Administrative User DN and \ password to retrieve monitoring information and to be able to Stop and Restart \ the Directory Server. server-started-label=Started server-stopped-label=Stopped server-starting-label=Starting server-stopping-label=Stopping server-unknown-status-label=Unknown cannot-connect-to-login-with-cause=Could not connect to the Directory \ Server with the provided credentials. The possible causes for this are:\n{0} cannot-connect-to-login-without-cause=Could not connect to the Directory \ Server with the provided credentials.\nCheck that the Administrative User DN \ and password are valid. error-starting-server-generic=Could not Start server. authenticate-button-label=Authenticate authenticate-status-panel-button-tooltip=Authenticate as an administrative \ user to view all monitoring information listeners-title=Listener Ports address-port-column=Address:Port protocol-column=Protocol state-column=State databases-title=Data Sources backendid-column=Backend ID basedn-column=Base DN number-entries-column=Entries enabled-label=Enabled disabled-label=Disabled unknown-label=-- ldap-protocol-label=LDAP ldaps-protocol-label=LDAPS jmx-protocol-label=JMX jmx-secure-protocol-label=JMX (Secure) undefined-protocol-label=-Unknown- error-reading-config-file=Error reading the configuration file. could-not-find-valid-ldapurl=Error reading the configuration file.\n\ This could be caused because there is not an enabled LDAP port to retrieve \ monitoring information or because you do not have read rights on the \ configuration file. error-reading-config-ldap=Error reading data from server. Try \ re-authenticating.\nDetails: {0} no-dbs-found=-No LDAP Databases Found- no-listeners-found=-No Listener Ports Found- # # Progress Dialog # close-progress-button-tooltip=Close Progress Dialog progress-title=Progress summary-starting=Starting Server... summary-stopping=Stopping Server... summary-start-error=An error occurred Starting Server. Check 'Details' text \ area for more information. summary-stop-error=An error occurred Stopping Server. Check 'Details' text \ area for more information. error-starting-server-code=Error Starting Directory Server. Error code: {0}. summary-start-success=OpenDS Started Successfully. summary-stop-success=OpenDS Stopped Successfully. # # Confirmation messages # confirm-stop-message=Are you sure you want to Stop the Directory Server? confirm-stop-title=Confirmation Required confirm-restart-message=Are you sure you want to Restart the Directory Server? confirm-restart-title=Confirmation Required # # Login Dialog # login-dialog-unix-msg=You must provide an Administrative User DN and password \ to retrieve monitoring information. login-dn-label=Administrative User DN: login-dn-tooltip=Enter the distinguished name (DN) of the \ Administrative User account that will used to retrieve monitoring information login-pwd-label=Administrative User Password: login-pwd-tooltip=Enter the password of the \ Administrative User account that will used to retrieve monitoring information ok-button-label=OK login-dialog-server-not-running-msg=The Directory Server is not running. \ Click OK to continue to the Status Panel. login-dialog-server-not-running-title=Directory Server not Running login-ok-button-tooltip=Proceed with authentication login-cancel-button-tooltip=Close Login Dialog # # Status Command Line # cli-status-root-user-dn-not-provided=You must provide a value for the \ option -D (or --bindDN) cli-status-root-user-pwd-not-provided=You must provide a value for the \ option -w (or --bindPassword) cli-status-root-user-pwd-file-not-provided=You must provide a value for the \ option -W (or --bindPasswordFile) cli-status-unknown-argument=Unknown argument {0} cli-status-pwd-and-pwd-file-provided=You cannot provide Bind Password (-w or \ --bindPassword) and Bind Password File (-W or --bindPasswordFile) at the same \ time. cli-status-error-reading-pwd-file=Could not read the password from \ file {0}. Check that the file path is correct, that you have access rights to \ it and that it contains a password. status-cli-usage=This command displays basic server information.\n\n\ Usage: {0} {options}\n where {options} include:\n\ -D {bindDN} or --bindDN {bindDN}\n Bind DN\n\ -w {bindPassword} or --bindPassword {bindPassword}\n Bind password\n\ -j {bindPasswordFile} or --bindPasswordFile {bindPasswordFile}\n Bind \ password file\n\ -H or --help\n Display this usage information. not-available-authentication-required-cli-label=<not available> (*) not-available-authentication-required-cli-legend=* Information only available \ if you provide authentication information when launching the status \ command. not-available-server-down-cli-label=<not available> (*) not-available-server-down-cli-legend=* Information only available if server is \ running and you provide authentication information when launching the status \ command. opends/src/statuspanel/org/opends/statuspanel/ui/DatabasesTableModel.java
New file @@ -0,0 +1,274 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel.ui; import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; import javax.swing.table.AbstractTableModel; import org.opends.statuspanel.DatabaseDescriptor; import org.opends.statuspanel.i18n.ResourceProvider; /** * This class is just a table model used to display the information about * databases in a table. * */ public class DatabasesTableModel extends AbstractTableModel implements SortableTableModel, Comparator<DatabaseDescriptor> { private static final long serialVersionUID = -5650762484071136983L; private HashSet<DatabaseDescriptor> data = new HashSet<DatabaseDescriptor>(); private ArrayList<DatabaseDescriptor> dataArray = new ArrayList<DatabaseDescriptor>(); private final String[] COLUMN_NAMES = { getMsg("backendid-column"), getMsg("basedn-column"), getMsg("number-entries-column") }; private int sortColumn = 0; private boolean sortAscending = true; /** * Sets the data for this table model. * @param newData the data for this table model. */ public void setData(Set<DatabaseDescriptor> newData) { if (!newData.equals(data)) { data.clear(); data.addAll(newData); dataArray.clear(); TreeSet<DatabaseDescriptor> sortedSet = new TreeSet<DatabaseDescriptor>(this); sortedSet.addAll(data); dataArray.addAll(sortedSet); fireTableDataChanged(); } } /** * Updates the table model contents and sorts its contents depending on the * sort options set by the user. */ public void forceResort() { dataArray.clear(); TreeSet<DatabaseDescriptor> sortedSet = new TreeSet<DatabaseDescriptor>(this); sortedSet.addAll(data); dataArray.addAll(sortedSet); fireTableDataChanged(); } /** * Comparable implementation. * @param desc1 the first database descriptor to compare. * @param desc2 the second database descriptor to compare. * @return 1 if according to the sorting options set by the user the first * database descriptor must be put before the second descriptor, 0 if they * are equivalent in terms of sorting and -1 if the second descriptor must * be put before the first descriptor. */ public int compare(DatabaseDescriptor desc1, DatabaseDescriptor desc2) { int result = 0; if (sortColumn == 0) { result = desc1.getBackendID().compareTo(desc2.getBackendID()); if (result == 0) { result = desc1.getBaseDn().compareTo(desc2.getBaseDn()); } if (result == 0) { if (desc1.getEntries() > desc2.getEntries()) { result = 1; } else if (desc1.getEntries() < desc2.getEntries()) { result = -1; } } } else if (sortColumn == 1) { result = desc1.getBaseDn().compareTo(desc2.getBaseDn()); if (result == 0) { result = desc1.getBackendID().compareTo(desc2.getBackendID()); } if (result == 0) { if (desc1.getEntries() > desc2.getEntries()) { result = 1; } else if (desc1.getEntries() < desc2.getEntries()) { result = -1; } } } else { if (desc1.getEntries() > desc2.getEntries()) { result = 1; } else if (desc1.getEntries() < desc2.getEntries()) { result = -1; } if (result == 0) { result = desc1.getBackendID().compareTo(desc2.getBackendID()); } if (result == 0) { result = desc1.getBaseDn().compareTo(desc2.getBaseDn()); } } if (!sortAscending) { result = -result; } return result; } /** * {@inheritDoc} */ public int getColumnCount() { return 3; } /** * {@inheritDoc} */ public int getRowCount() { return dataArray.size(); } /** * {@inheritDoc} */ public Object getValueAt(int row, int col) { Object v; DatabaseDescriptor desc = dataArray.get(row); if (col == 0) { v = desc.getBackendID(); } else if (col == 1) { v = desc.getBaseDn(); } else { v = new Integer(desc.getEntries()); } return v; } /** * {@inheritDoc} */ public String getColumnName(int col) { return COLUMN_NAMES[col]; } /** * Returns whether the sort is ascending or descending. * @return <CODE>true</CODE> if the sort is ascending and <CODE>false</CODE> * otherwise. */ public boolean isSortAscending() { return sortAscending; } /** * Sets whether to sort ascending of descending. * @param sortAscending whether to sort ascending or descending. */ public void setSortAscending(boolean sortAscending) { this.sortAscending = sortAscending; } /** * Returns the column index used to sort. * @return the column index used to sort. */ public int getSortColumn() { return sortColumn; } /** * Sets the column index used to sort. * @param sortColumn column index used to sort.. */ public void setSortColumn(int sortColumn) { this.sortColumn = sortColumn; } /** * The following three methods are just commodity methods to get localized * messages. */ private String getMsg(String key) { return getI18n().getMsg(key); } private ResourceProvider getI18n() { return ResourceProvider.getInstance(); } } opends/src/statuspanel/org/opends/statuspanel/ui/ListenersTableModel.java
New file @@ -0,0 +1,272 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel.ui; import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; import javax.swing.table.AbstractTableModel; import org.opends.statuspanel.ListenerDescriptor; import org.opends.statuspanel.i18n.ResourceProvider; /** * This class is just a table model used to display the information about * listeners in a table. * */ public class ListenersTableModel extends AbstractTableModel implements SortableTableModel, Comparator<ListenerDescriptor> { private static final long serialVersionUID = -1121308303480078376L; private HashSet<ListenerDescriptor> data = new HashSet<ListenerDescriptor>(); private ArrayList<ListenerDescriptor> dataArray = new ArrayList<ListenerDescriptor>(); private final String[] COLUMN_NAMES = { getMsg("address-port-column"), getMsg("protocol-column"), getMsg("state-column") }; private int sortColumn = 0; private boolean sortAscending = true; /** * Sets the data for this table model. * @param newData the data for this table model. */ public void setData(Set<ListenerDescriptor> newData) { if (!newData.equals(data)) { data.clear(); data.addAll(newData); dataArray.clear(); TreeSet<ListenerDescriptor> sortedSet = new TreeSet<ListenerDescriptor>(this); sortedSet.addAll(data); dataArray.addAll(sortedSet); fireTableDataChanged(); } } /** * Updates the table model contents and sorts its contents depending on the * sort options set by the user. */ public void forceResort() { dataArray.clear(); TreeSet<ListenerDescriptor> sortedSet = new TreeSet<ListenerDescriptor>(this); sortedSet.addAll(data); dataArray.addAll(sortedSet); fireTableDataChanged(); } /** * Comparable implementation. * @param desc1 the first listener descriptor to compare. * @param desc2 the second listener descriptor to compare. * @return 1 if according to the sorting options set by the user the first * listener descriptor must be put before the second descriptor, 0 if they * are equivalent in terms of sorting and -1 if the second descriptor must * be put before the first descriptor. */ public int compare(ListenerDescriptor desc1, ListenerDescriptor desc2) { int result = 0; if (sortColumn == 0) { result = desc1.getAddressPort().compareTo(desc2.getAddressPort()); if (result == 0) { result = desc1.getProtocolDescription().compareTo( desc2.getProtocolDescription()); } if (result == 0) { result = desc1.getState().compareTo(desc2.getState()); } } else if (sortColumn == 1) { result = desc1.getProtocolDescription().compareTo( desc2.getProtocolDescription()); if (result == 0) { result = desc1.getAddressPort().compareTo(desc2.getAddressPort()); } if (result == 0) { result = desc1.getState().compareTo(desc2.getState()); } } else { result = desc1.getState().compareTo(desc2.getState()); if (result == 0) { result = desc1.getAddressPort().compareTo(desc2.getAddressPort()); } if (result == 0) { result = desc1.getProtocolDescription().compareTo( desc2.getProtocolDescription()); } } if (!sortAscending) { result = -result; } return result; } /** * {@inheritDoc} */ public int getColumnCount() { return 3; } /** * {@inheritDoc} */ public int getRowCount() { return dataArray.size(); } /** * {@inheritDoc} */ public Object getValueAt(int row, int col) { Object v; ListenerDescriptor desc = dataArray.get(row); if (col == 0) { v = desc.getAddressPort(); } else if (col == 1) { v = desc.getProtocolDescription().toString(); } else { switch (desc.getState()) { case ENABLED: v = getMsg("enabled-label"); break; case DISABLED: v = getMsg("disabled-label"); break; case UNKNOWN: v = getMsg("unknown-label"); break; default: throw new IllegalStateException("Unknown state: "+desc.getState()); } } return v; } /** * {@inheritDoc} */ public String getColumnName(int col) { return COLUMN_NAMES[col]; } /** * Returns whether the sort is ascending or descending. * @return <CODE>true</CODE> if the sort is ascending and <CODE>false</CODE> * otherwise. */ public boolean isSortAscending() { return sortAscending; } /** * Sets whether to sort ascending of descending. * @param sortAscending whether to sort ascending or descending. */ public void setSortAscending(boolean sortAscending) { this.sortAscending = sortAscending; } /** * Returns the column index used to sort. * @return the column index used to sort. */ public int getSortColumn() { return sortColumn; } /** * Sets the column index used to sort. * @param sortColumn column index used to sort.. */ public void setSortColumn(int sortColumn) { this.sortColumn = sortColumn; } /** * The following three methods are just commodity methods to get localized * messages. */ private String getMsg(String key) { return getI18n().getMsg(key); } private ResourceProvider getI18n() { return ResourceProvider.getInstance(); } } opends/src/statuspanel/org/opends/statuspanel/ui/LoginDialog.java
New file @@ -0,0 +1,610 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel.ui; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Iterator; import java.util.Set; import javax.naming.NamingException; import javax.naming.directory.SearchControls; import javax.naming.ldap.InitialLdapContext; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.text.JTextComponent; import org.opends.quicksetup.event.MinimumSizeComponentListener; import org.opends.quicksetup.ui.UIFactory; import org.opends.quicksetup.util.BackgroundTask; import org.opends.quicksetup.util.Utils; import org.opends.statuspanel.ConfigFromFile; import org.opends.statuspanel.i18n.ResourceProvider; /** * This class is a dialog that appears when the user must provide authentication * to connect to the Directory Server in order to be able to display * information. */ public class LoginDialog extends JDialog { private static final long serialVersionUID = 9049409381101152000L; private JFrame parent; private JLabel lDn; private JLabel lPwd; private JTextField tfDn; private JTextField tfPwd; private JButton cancelButton; private JButton okButton; private boolean isCancelled = true; private ConfigFromFile conf; /** * Constructor of the LoginDialog. * @param parent the parent frame for this dialog. */ public LoginDialog(JFrame parent) { super(parent); setTitle(getMsg("login-dialog-title")); this.parent = parent; getContentPane().add(createPanel()); /* * TODO: find a way to calculate this dynamically. This is done to avoid * all the text in a single line. */ setPreferredSize(new Dimension(500, 250)); addComponentListener(new MinimumSizeComponentListener(this, 500, 250)); getRootPane().setDefaultButton(okButton); } /** * Returns <CODE>true</CODE> if the user clicked on cancel and * <CODE>false</CODE> otherwise. * @return <CODE>true</CODE> if the user clicked on cancel and * <CODE>false</CODE> otherwise. */ public boolean isCancelled() { return isCancelled; } /** * {@inheritDoc} * */ public void setVisible(boolean visible) { cancelButton.setEnabled(true); okButton.setEnabled(true); if (visible) { tfPwd.setText(""); tfPwd.requestFocusInWindow(); UIFactory.setTextStyle(lDn, UIFactory.TextStyle.PRIMARY_FIELD_VALID); UIFactory.setTextStyle(lPwd, UIFactory.TextStyle.PRIMARY_FIELD_VALID); getRootPane().setDefaultButton(okButton); } super.setVisible(visible); } /** * Returns the Directory Manager DN provided by the user. * @return the Directory Manager DN provided by the user. */ public String getDirectoryManagerDn() { return tfDn.getText(); } /** * Returns the Directory Manager password provided by the user. * @return the Directory Manager password provided by the user. */ public String getDirectoryManagerPwd() { return tfPwd.getText(); } /** * Creates and returns the panel of the dialog. * @return the panel of the dialog. */ private JPanel createPanel() { JPanel p1 = new JPanel(new GridBagLayout()); p1.setBackground(UIFactory.CURRENT_STEP_PANEL_BACKGROUND); p1.setBorder(UIFactory.DIALOG_PANEL_BORDER); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.anchor = GridBagConstraints.NORTHWEST; gbc.insets = UIFactory.getCurrentStepPanelInsets(); p1.add(UIFactory.makeJLabel(UIFactory.IconType.INFORMATION_LARGE, null, UIFactory.TextStyle.NO_STYLE), gbc); gbc.weightx = 1.0; gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets.left = 0; String msg; if (Utils.isWindows()) { msg = getMsg("login-dialog-windows-msg"); } else { msg = getMsg("login-dialog-unix-msg"); } JTextComponent textPane = UIFactory.makeHtmlPane(msg, UIFactory.INSTRUCTIONS_FONT); textPane.setOpaque(false); textPane.setEditable(false); p1.add(textPane, gbc); JPanel p2 = new JPanel(new GridBagLayout()); p2.setOpaque(false); gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.weightx = 0.0; gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD; gbc.insets.left = 0; gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL; lDn = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, getMsg("login-dn-label"), UIFactory.TextStyle.PRIMARY_FIELD_VALID); p2.add(lDn, gbc); gbc.weightx = 1.0; gbc.insets.left = UIFactory.LEFT_INSET_PRIMARY_FIELD; gbc.gridwidth = GridBagConstraints.REMAINDER; tfDn = UIFactory.makeJTextField(getProposedAdministrativeUserDn(), getMsg("login-dn-tooltip"), UIFactory.DN_FIELD_SIZE, UIFactory.TextStyle.TEXTFIELD); p2.add(tfDn, gbc); gbc.insets.top = 0; gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.weightx = 0.0; gbc.insets.left = 0; lPwd = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, getMsg("login-pwd-label"), UIFactory.TextStyle.PRIMARY_FIELD_VALID); p2.add(lPwd, gbc); gbc.insets.left = UIFactory.LEFT_INSET_PRIMARY_FIELD; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridwidth = GridBagConstraints.REMAINDER; JPanel p3 = new JPanel(new GridBagLayout()); p3.setOpaque(false); tfPwd = UIFactory.makeJPasswordField(null, getMsg("login-pwd-tooltip"), UIFactory.PASSWORD_FIELD_SIZE, UIFactory.TextStyle.PASSWORD_FIELD); p2.add(p3, gbc); gbc.insets = UIFactory.getEmptyInsets(); gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.weightx = 0.0; p3.add(tfPwd, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; p3.add(Box.createHorizontalGlue(), gbc); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = UIFactory.getEmptyInsets(); gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.weightx = 0.0; gbc.insets.top = 0; p1.add(Box.createHorizontalGlue(), gbc); gbc.weightx = 1.0; gbc.gridwidth = GridBagConstraints.REMAINDER; p1.add(p2, gbc); gbc.weighty = 1.0; gbc.fill = GridBagConstraints.VERTICAL; p1.add(Box.createVerticalGlue(), gbc); JPanel buttonPanel = new JPanel(new GridBagLayout()); buttonPanel.setOpaque(false); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1.0; gbc.insets = UIFactory.getEmptyInsets(); gbc.gridwidth = 3; buttonPanel.add(Box.createHorizontalGlue(), gbc); gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0.0; okButton = UIFactory.makeJButton(getMsg("ok-button-label"), getMsg("login-ok-button-tooltip")); buttonPanel.add(okButton, gbc); okButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { okClicked(); } }); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets.left = UIFactory.HORIZONTAL_INSET_BETWEEN_BUTTONS; cancelButton = UIFactory.makeJButton(getMsg("cancel-button-label"), getMsg("login-cancel-button-tooltip")); buttonPanel.add(cancelButton, gbc); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { cancelClicked(); } }); JPanel p = new JPanel(new GridBagLayout()); p.setBackground(UIFactory.DEFAULT_BACKGROUND); gbc.insets = UIFactory.getEmptyInsets(); gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; gbc.weighty = 1.0; p.add(p1, gbc); gbc.weighty = 0.0; gbc.insets = UIFactory.getButtonsPanelInsets(); p.add(buttonPanel, gbc); return p; } /** * Returns the first administrative user DN found in the configuration file. * @return the first administrative user DN found in the configuration file. */ private String getProposedAdministrativeUserDn() { String dn; Set<String> dns = getAdministrativeUserDns(); if (dns.size() > 0) { dn = dns.iterator().next(); } else { dn = null; } return dn; } /** * Method called when user clicks on cancel. * */ private void cancelClicked() { isCancelled = true; dispose(); } /** * Method called when user clicks on OK. * */ private void okClicked() { BackgroundTask worker = new BackgroundTask() { public Object processBackgroundTask() throws NamingException { Boolean isServerRunning = Boolean.TRUE; try { InitialLdapContext ctx = null; String ldapUrl = getLDAPURL(); if (ldapUrl != null) { ctx = Utils.createLdapContext(ldapUrl, tfDn.getText(), tfPwd.getText(), 3000, null); } else { throw new Error("could-not-find-valid-ldapurl"); } /* * Search for the config to check that it is the directory manager. */ SearchControls searchControls = new SearchControls(); searchControls.setCountLimit(1); searchControls.setSearchScope( SearchControls. OBJECT_SCOPE); searchControls.setReturningAttributes( new String[] {"dn"}); ctx.search("cn=config", "objectclass=*", searchControls); } catch (NamingException ne) { if (isServerRunning()) { throw ne; } isServerRunning = Boolean.FALSE; } catch (IllegalStateException ise) { throw ise; } catch (Throwable t) { throw new IllegalStateException("Unexpected throwable.", t); } return isServerRunning; } public void backgroundTaskCompleted(Object returnValue, Throwable throwable) { if (throwable != null) { if (throwable instanceof NamingException) { boolean dnInvalid = false; boolean pwdInvalid = false; String dn = tfDn.getText(); ArrayList<String> possibleCauses = new ArrayList<String>(); if ("".equals(dn.trim())) { dnInvalid = true; possibleCauses.add(getMsg("empty-directory-manager-dn")); } else if (!Utils.isDn(dn)) { dnInvalid = true; possibleCauses.add(getMsg("not-a-directory-manager-dn")); } else { boolean found = false; Iterator<String> it = getAdministrativeUserDns().iterator(); while (it.hasNext() && !found) { found = Utils.areDnsEqual(dn, it.next()); } if (!found) { dnInvalid = true; possibleCauses.add(getMsg("not-a-directory-manager-in-config")); } } if ("".equals(tfPwd.getText())) { pwdInvalid = true; possibleCauses.add(getMsg("empty-pwd")); } if (dnInvalid) { UIFactory.setTextStyle(lDn, UIFactory.TextStyle.PRIMARY_FIELD_INVALID); } else { UIFactory.setTextStyle(lDn, UIFactory.TextStyle.PRIMARY_FIELD_VALID); pwdInvalid = true; } if (pwdInvalid) { UIFactory.setTextStyle(lPwd, UIFactory.TextStyle.PRIMARY_FIELD_INVALID); } else { UIFactory.setTextStyle(lPwd, UIFactory.TextStyle.PRIMARY_FIELD_VALID); } if (possibleCauses.size() > 0) { // Message with causes String[] arg = { Utils.getStringFromCollection(possibleCauses, "\n") }; displayError( getMsg("cannot-connect-to-login-with-cause", arg), getMsg("error-title")); } else { // Generic message displayError( getMsg("cannot-connect-to-login-without-cause"), getMsg("error-title")); } } else if (throwable instanceof Error) { displayError(throwable.getMessage(), getMsg("error-title")); } else { // This is a bug throwable.printStackTrace(); displayError( Utils.getThrowableMsg(getI18n(), "bug-msg", null, throwable), getMsg("error-title")); } cancelButton.setEnabled(true); okButton.setEnabled(true); } else { if (Boolean.FALSE.equals(returnValue)) { displayInformationMessage( getMsg("login-dialog-server-not-running-msg"), getMsg("login-dialog-server-not-running-title")); } UIFactory.setTextStyle(lDn, UIFactory.TextStyle.PRIMARY_FIELD_VALID); UIFactory.setTextStyle(lPwd, UIFactory.TextStyle.PRIMARY_FIELD_VALID); isCancelled = false; cancelButton.setEnabled(true); okButton.setEnabled(true); dispose(); } } }; cancelButton.setEnabled(false); okButton.setEnabled(false); worker.startBackgroundTask(); } /** * Displays an error message dialog. * * @param msg * the error message. * @param title * the title for the dialog. */ private void displayError(String msg, String title) { Utils.displayError(parent, msg, title); toFront(); } /** * Displays an information message dialog. * * @param msg * the information message. * @param title * the title for the dialog. */ private void displayInformationMessage(String msg, String title) { Utils.displayInformationMessage(parent, msg, title); toFront(); } /** * Returns the administrative user DNs found in the config file. * @return the administrative user DNs found in the config file. */ private Set<String> getAdministrativeUserDns() { return getConfig().getAdministrativeUsers(); } /** * Returns whether the server is running or not. * @return <CODE>true</CODE> if the server is running and <CODE>false</CODE> * otherwise. */ private boolean isServerRunning() { return Utils.isServerRunning(Utils.getInstallPathFromClasspath()); } /** * Returns the ldap URL used to log into the server based in the contents * of the config file. * @return the ldap URL used to log into the server based in the contents * of the config file. */ private String getLDAPURL() { return getConfig().getLDAPURL(); } /** * Returns the ConfigFromFile object that contains the configuration read * from the config file. * @return the ConfigFromFile object that contains the configuration read * from the config file. */ private ConfigFromFile getConfig() { if (conf == null) { conf = new ConfigFromFile(); conf.readConfiguration(); } return conf; } /* The following three methods are just commodity methods to retrieve * localized messages */ private String getMsg(String key) { return getI18n().getMsg(key); } private String getMsg(String key, String[] args) { return getI18n().getMsg(key, args); } private ResourceProvider getI18n() { return ResourceProvider.getInstance(); } /** * Method written for testing purposes. * @param args the arguments to be passed to the test program. */ public static void main(String[] args) { try { // UIFactory.initialize(); LoginDialog dlg = new LoginDialog(new JFrame()); dlg.pack(); dlg.setVisible(true); } catch (Exception ex) { ex.printStackTrace(); } } } opends/src/statuspanel/org/opends/statuspanel/ui/ProgressDialog.java
New file @@ -0,0 +1,375 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel.ui; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import org.opends.quicksetup.event.MinimumSizeComponentListener; import org.opends.quicksetup.ui.UIFactory; import org.opends.quicksetup.util.HtmlProgressMessageFormatter; import org.opends.quicksetup.util.ProgressMessageFormatter; import org.opends.statuspanel.i18n.ResourceProvider; /** * This panel is used to show the progress of the start/stop/restart operations. * */ public class ProgressDialog extends JDialog { private static final long serialVersionUID = 8635080171100378470L; private JEditorPane progressBarLabel; private JProgressBar progressBar; private JEditorPane detailsTextArea; private JScrollPane scroll; private String lastText; private JFrame parent; private JButton closeButton; private String panelTitle = getMsg("progress-title"); private ProgressMessageFormatter formatter = new HtmlProgressMessageFormatter(); /** * ProgressDialog constructor. * @param frame the parent frame for this dialog. */ public ProgressDialog(JFrame frame) { super(frame); this.parent = frame; setTitle(getMsg("statuspanel-dialog-title")); createLayout(); } /** * Prepares size for this dialog. * */ public void pack() { /* * TODO: find a way to calculate this dynamically. */ setPreferredSize(new Dimension(500, 300)); addComponentListener(new MinimumSizeComponentListener(this, 500, 300)); super.pack(); closeButton.requestFocusInWindow(); getRootPane().setDefaultButton(closeButton); } /** * Returns the parent for this dialog. * @return the parent for this dialog. */ public JFrame getFrame() { return parent; } /** * Sets the title of the panel. * @param title the title of the panel. */ public void setPanelTitle(String title) { this.panelTitle = title; } /** * Returns the title of the panel. * @return the title of the panel */ public String getPanelTitle() { return panelTitle; } /** * Sets the enable state of the close button. * @param enable whether to enable or disable the button. */ public void setCloseButtonEnabled(boolean enable) { closeButton.setEnabled(enable); } /** * Sets the text in the summary label. The text can be in HTML format. * @param text the text to be set. */ public void setSummary(String text) { progressBarLabel.setText(text); } /** * Sets the text in the details text pane. The text can be in HTML format. * @param text the text to be set. */ public void setDetails(String text) { detailsTextArea.setText(text); } /** * Returns the formatter that will be used to display the messages in this * panel. * @return the formatter that will be used to display the messages in this * panel. */ private ProgressMessageFormatter getFormatter() { if (formatter == null) { formatter = new HtmlProgressMessageFormatter(); } return formatter; } /** * Creates the layout of the dialog panel. * */ private void createLayout() { /* Create title panel */ JPanel titlePanel = new JPanel(new GridBagLayout()); titlePanel.setOpaque(false); GridBagConstraints gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.NORTHWEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 0.0; gbc.gridwidth = GridBagConstraints.RELATIVE; String title = getPanelTitle(); JLabel l = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, title, UIFactory.TextStyle.TITLE); l.setOpaque(false); titlePanel.add(l, gbc); gbc.weightx = 1.0; gbc.gridwidth = GridBagConstraints.REMAINDER; titlePanel.add(Box.createHorizontalGlue(), gbc); /* Create input panel. */ JPanel mainPanel = new JPanel(new GridBagLayout()); mainPanel.setOpaque(false); gbc.insets = UIFactory.getEmptyInsets(); gbc.anchor = GridBagConstraints.NORTHWEST; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; gbc.fill = GridBagConstraints.HORIZONTAL; mainPanel.add(titlePanel, gbc); gbc.insets.top = UIFactory.TOP_INSET_INSTRUCTIONS_SUBPANEL; progressBarLabel = UIFactory.makeHtmlPane(getMsg("progressbar-initial-label"), UIFactory.PROGRESS_FONT); progressBarLabel.setOpaque(false); progressBarLabel.setEditable(false); mainPanel.add(progressBarLabel, gbc); gbc.insets.top = UIFactory.TOP_INSET_PROGRESS_BAR; gbc.insets.bottom = UIFactory.BOTTOM_INSET_PROGRESS_BAR; mainPanel.add(createProgressBarPanel(), gbc); progressBar.setToolTipText(getMsg("progressbar-tooltip")); l = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, getMsg("progress-details-label"), UIFactory.TextStyle.SECONDARY_FIELD_VALID); gbc.insets = UIFactory.getEmptyInsets(); mainPanel.add(l, gbc); scroll = new JScrollPane(); detailsTextArea = UIFactory.makeProgressPane(scroll); detailsTextArea.setBackground( UIFactory.CURRENT_STEP_PANEL_BACKGROUND); detailsTextArea.addHyperlinkListener(new HyperlinkListener() { public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { String url = e.getURL().toString(); String newText = getFormatter().getFormattedAfterUrlClick(url, lastText); lastText = newText; detailsTextArea.setText(lastText); } } }); detailsTextArea.setAutoscrolls(true); scroll.setViewportView(detailsTextArea); scroll.setBorder(UIFactory.TEXT_AREA_BORDER); scroll.setWheelScrollingEnabled(true); l.setLabelFor(detailsTextArea); gbc.insets.top = UIFactory.TOP_INSET_PROGRESS_TEXTAREA; gbc.fill = GridBagConstraints.BOTH; gbc.weighty = 1.0; mainPanel.add(scroll, gbc); /* Create buttons panel */ JPanel buttonsPanel = new JPanel(new GridBagLayout()); buttonsPanel.setBackground(UIFactory.DEFAULT_BACKGROUND); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1.0; gbc.insets = UIFactory.getEmptyInsets(); gbc.gridwidth = GridBagConstraints.RELATIVE; buttonsPanel.add(Box.createHorizontalGlue(), gbc); closeButton = UIFactory.makeJButton(getMsg("close-button-label"), getMsg("close-progress-button-tooltip")); gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0.0; gbc.gridwidth = GridBagConstraints.REMAINDER; buttonsPanel.add(closeButton, gbc); closeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { dispose(); } }); JPanel p = new JPanel(new GridBagLayout()); p.setBackground(UIFactory.DEFAULT_BACKGROUND); gbc.insets = UIFactory.getEmptyInsets(); gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; gbc.weighty = 1.0; gbc.insets = UIFactory.getEmptyInsets(); JPanel p1 = new JPanel(new GridBagLayout()); p1.setBackground(UIFactory.CURRENT_STEP_PANEL_BACKGROUND); p1.setBorder(UIFactory.DIALOG_PANEL_BORDER); gbc.insets = UIFactory.getCurrentStepPanelInsets(); p1.add(mainPanel, gbc); gbc.insets = UIFactory.getEmptyInsets(); p.add(p1, gbc); gbc.weighty = 0.0; gbc.insets = UIFactory.getButtonsPanelInsets(); p.add(buttonsPanel, gbc); getContentPane().add(p); } /** * Creates the progress bar panel. * @return the created panel. */ private JPanel createProgressBarPanel() { JPanel panel = new JPanel(new GridBagLayout()); panel.setOpaque(false); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = UIFactory.getEmptyInsets(); gbc.fill = GridBagConstraints.HORIZONTAL; progressBar = new JProgressBar(); progressBar.setIndeterminate(true); // The ProgressDescriptor provides the ratio in % progressBar.setMaximum(100); gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.weightx = 0.0; panel.add(Box.createHorizontalStrut(UIFactory.PROGRESS_BAR_SIZE), gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; panel.add(Box.createHorizontalGlue(), gbc); gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.weightx = 0.0; //panel.add(progressBar, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; panel.add(Box.createHorizontalGlue(), gbc); return panel; } /** * The following three methods are just commodity methods to get localized * messages. */ private String getMsg(String key) { return getI18n().getMsg(key); } private ResourceProvider getI18n() { return ResourceProvider.getInstance(); } /** * Method written for testing purposes. * @param args the arguments to be passed to the test program. */ public static void main(String[] args) { try { ProgressDialog dlg = new ProgressDialog(new JFrame()); dlg.pack(); dlg.setVisible(true); } catch (Exception ex) { ex.printStackTrace(); } } } opends/src/statuspanel/org/opends/statuspanel/ui/SortableTableModel.java
New file @@ -0,0 +1,67 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel.ui; import javax.swing.table.TableModel; /** * A generic interface that must implement table models that are sortable. */ interface SortableTableModel extends TableModel { /** * Returns whether the sort is ascending or descending. * @return <CODE>true</CODE> if the sort is ascending and <CODE>false</CODE> * otherwise. */ public boolean isSortAscending(); /** * Sets whether to sort ascending of descending. * @param sortAscending whether to sort ascending or descending. */ public void setSortAscending(boolean sortAscending); /** * Returns the column index used to sort. * @return the column index used to sort. */ public int getSortColumn(); /** * Sets the column index used to sort. * @param sortColumn column index used to sort.. */ public void setSortColumn(int sortColumn); /** * Updates the table model contents and sorts its contents depending on the * sort options set by the user. */ public void forceResort(); } opends/src/statuspanel/org/opends/statuspanel/ui/StatusPanelDialog.java
New file @@ -0,0 +1,1459 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.statuspanel.ui; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JToolTip; import javax.swing.Popup; import javax.swing.PopupFactory; import javax.swing.SwingConstants; import javax.swing.ToolTipManager; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import org.opends.quicksetup.event.MinimumSizeComponentListener; import org.opends.quicksetup.ui.UIFactory; import org.opends.quicksetup.util.HtmlProgressMessageFormatter; import org.opends.quicksetup.util.Utils; import org.opends.statuspanel.ServerStatusDescriptor; import org.opends.statuspanel.event.StatusPanelButtonListener; import org.opends.statuspanel.i18n.ResourceProvider; /** * This panel is used to display basic information about the server status. * */ public class StatusPanelDialog extends JFrame { private static final long serialVersionUID = 6832422469078074151L; private ServerStatusDescriptor lastDescriptor; private HashSet<StatusPanelButtonListener> listeners = new HashSet<StatusPanelButtonListener>(); private JButton quitButton; private JButton authenticateButton; private JLabel lServerStatus; private JLabel lCurrentConnections; private JLabel lAdministrativeUsers; private JLabel lInstallPath; private JLabel lOpenDSVersion; private JLabel lJavaVersion; private JLabel lDbTableEmpty; private JLabel lListenersTableEmpty; private JEditorPane lError; private JButton stopButton; private JButton startButton; private JButton restartButton; private HtmlProgressMessageFormatter formatter = new HtmlProgressMessageFormatter(); private HashSet<JLabel> subsectionLabels = new HashSet<JLabel>(); private DatabasesTableModel dbTableModel; private JTable dbTable; private ListenersTableModel listenersTableModel; private JTable listenersTable; private InstantaneousToolTipManager toolTipManager; private final String NOT_AVAILABLE = getMsg("not-available-label"); private final int MAXIMAL_WIDTH = 1000; private final int MAXIMAL_HEIGHT = 1000; /** * ProgressDialog constructor. */ public StatusPanelDialog() { super(); setTitle(getMsg("statuspanel-dialog-title")); createLayout(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { quitClicked(); } }); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); UIFactory.IconType ic; if (Utils.isMacOS()) { ic = UIFactory.IconType.MINIMIZED_MAC; } else { ic = UIFactory.IconType.MINIMIZED; } setIconImage(UIFactory.getImageIcon(ic).getImage()); } /** * Packs and displays this dialog. * */ public void packAndShow() { pack(); int packedMinWidth = (int) getPreferredSize().getWidth(); int packedMinHeight = (int) getPreferredSize().getHeight(); int minWidth = Math.min(packedMinWidth, MAXIMAL_WIDTH); int minHeight = Math.min(packedMinHeight, MAXIMAL_HEIGHT); addComponentListener(new MinimumSizeComponentListener(this, minWidth, minHeight)); if ((minWidth != packedMinWidth) || (minHeight != packedMinHeight)) { setPreferredSize(new Dimension(minWidth, minHeight)); pack(); } Utils.centerOnScreen(this); setVisible(true); } /** * Updates the contents displaying with what is specified in the provided * ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ public void updateContents(ServerStatusDescriptor desc) { lastDescriptor = desc; updateStatusContents(desc); updateCurrentConnectionContents(desc); updateAdministrativeUserContents(desc); updateInstallPathContents(desc); updateVersionContents(desc); updateJavaVersionContents(desc); updateListenerContents(desc); updateDatabaseContents(desc); updateErrorContents(desc); } /** * Adds a StatusPanelButtonListener that will be notified of clicks in * the control panel dialog. * @param l the StatusPanelButtonListener to be added. */ public void addButtonListener(StatusPanelButtonListener l) { listeners.add(l); } /** * Removes a StatusPanelButtonListener. * @param l the StatusPanelButtonListener to be removed. */ public void removeButtonListener(StatusPanelButtonListener l) { listeners.remove(l); } /** * Sets the enable state of the authenticate button. * @param enable whether to enable or disable the button. */ public void setAuthenticateButtonEnabled(boolean enable) { authenticateButton.setEnabled(enable); } /** * Sets the enable state of the start button. * @param enable whether to enable or disable the button. */ public void setStartButtonEnabled(boolean enable) { startButton.setEnabled(enable); } /** * Sets the enable state of the stop button. * @param enable whether to enable or disable the button. */ public void setStopButtonEnabled(boolean enable) { stopButton.setEnabled(enable); } /** * Sets the enable state of the restart button. * @param enable whether to enable or disable the button. */ public void setRestartButtonEnabled(boolean enable) { restartButton.setEnabled(enable); } /** * Creates the layout of the dialog panel. * */ private void createLayout() { toolTipManager = new InstantaneousToolTipManager(); /* Create input panel. */ JPanel inputPanel = new JPanel(new GridBagLayout()); inputPanel.setOpaque(false); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = UIFactory.getEmptyInsets(); gbc.anchor = GridBagConstraints.NORTHWEST; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets.bottom = UIFactory.BOTTOM_INSET_PROGRESS_BAR; lError = UIFactory.makeHtmlPane("", UIFactory.PROGRESS_FONT); lError.setOpaque(false); lError.setEditable(false); inputPanel.add(lError, gbc); gbc.insets.bottom = 0; gbc.insets.top = UIFactory.TOP_INSET_CONTROL_PANEL_SUBSECTION - UIFactory.getCurrentStepPanelInsets().top; inputPanel.add(createServerStatusPanel(), gbc); inputPanel.add(createServerDetailsPanel(), gbc); inputPanel.add(createListenersPanel(), gbc); inputPanel.add(createDatabasesPanel(), gbc); gbc.weighty = 1.0; inputPanel.add(Box.createVerticalGlue(), gbc); /* Create buttons panel */ JPanel buttonsPanel = new JPanel(new GridBagLayout()); buttonsPanel.setOpaque(false); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.SOUTH; gbc.gridwidth = 4; gbc.insets = UIFactory.getEmptyInsets(); gbc.insets.left = UIFactory.getCurrentStepPanelInsets().left; buttonsPanel.add(UIFactory.makeJLabel(UIFactory.IconType.OPENDS_SMALL, null, UIFactory.TextStyle.NO_STYLE), gbc); gbc.weightx = 1.0; gbc.gridwidth--; gbc.insets.left = 0; buttonsPanel.add(Box.createHorizontalGlue(), gbc); authenticateButton = UIFactory.makeJButton(getMsg("authenticate-button-label"), getMsg("authenticate-status-panel-button-tooltip")); gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0.0; gbc.gridwidth = GridBagConstraints.RELATIVE; buttonsPanel.add(authenticateButton, gbc); authenticateButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { authenticateClicked(); } }); quitButton = UIFactory.makeJButton(getMsg("quit-button-label"), getMsg("quit-status-panel-button-tooltip")); gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0.0; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets.left = UIFactory.HORIZONTAL_INSET_BETWEEN_BUTTONS; buttonsPanel.add(quitButton, gbc); quitButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { quitClicked(); } }); JPanel p = new JPanel(new GridBagLayout()); p.setBackground(UIFactory.DEFAULT_BACKGROUND); gbc.insets = UIFactory.getEmptyInsets(); gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; gbc.weighty = 1.0; JPanel p1 = new JPanel(new GridBagLayout()); p1.setBorder(UIFactory.DIALOG_PANEL_BORDER); p1.setBackground(UIFactory.CURRENT_STEP_PANEL_BACKGROUND); gbc.insets = UIFactory.getCurrentStepPanelInsets(); p1.add(inputPanel, gbc); gbc.insets = UIFactory.getEmptyInsets(); p.add(new JScrollPane(p1), gbc); gbc.weighty = 0.0; gbc.insets = UIFactory.getButtonsPanelInsets(); p.add(buttonsPanel, gbc); getContentPane().add(p); /* Update the preferred sizes of labels */ int maxWidth = 0; for (JLabel l : subsectionLabels) { int width = (int) l.getPreferredSize().getWidth(); if (maxWidth <= width) { maxWidth = width; } } for (JLabel l : subsectionLabels) { int height = (int) l.getPreferredSize().getHeight(); l.setPreferredSize(new Dimension(maxWidth, height)); } } /** * Method called when start button is clicked. */ private void startClicked() { for (StatusPanelButtonListener l : listeners) { l.startClicked(); } } /** * Method called when quit button is clicked. */ private void quitClicked() { for (StatusPanelButtonListener l : listeners) { l.quitClicked(); } } /** * Method called when authenticate button is clicked. */ private void authenticateClicked() { for (StatusPanelButtonListener l : listeners) { l.authenticateClicked(); } } /** * Method called when stop button is clicked. */ private void stopClicked() { for (StatusPanelButtonListener l : listeners) { l.stopClicked(); } } /** * Method called when restart button is clicked. */ private void restartClicked() { for (StatusPanelButtonListener l : listeners) { l.restartClicked(); } } /** * Method usedto create the subsection title with two decoration icons * surrounding the text. * @param title the title of the subsection. */ private JPanel createSubsectionTitle(String title) { JPanel p = new JPanel(new GridBagLayout()); p.setOpaque(false); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridwidth = 5; gbc.weightx = 0.5; p.add(Box.createHorizontalGlue(), gbc); gbc.weightx = 0.0; gbc.gridwidth--; p.add(UIFactory.makeJLabel(UIFactory.IconType.SUBSECTION_LEFT, null, UIFactory.TextStyle.NO_STYLE), gbc); gbc.weightx = 0.0; gbc.gridwidth--; gbc.insets.left = UIFactory.HORIZONTAL_INSET_CONTROL_PANEL_SUBSECTION; JLabel l = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, title, UIFactory.TextStyle.TITLE); l.setHorizontalAlignment(SwingConstants.CENTER); subsectionLabels.add(l); p.add(l, gbc); gbc.gridwidth = GridBagConstraints.RELATIVE; p.add(UIFactory.makeJLabel(UIFactory.IconType.SUBSECTION_RIGHT, null, UIFactory.TextStyle.NO_STYLE), gbc); gbc.weightx = 0.5; gbc.insets.left = 0; p.add(Box.createHorizontalGlue(), gbc); return p; } /** * Creates the server status subsection panel. * @return the server status subsection panel. */ private JPanel createServerStatusPanel() { JPanel p = new JPanel(new GridBagLayout()); p.setOpaque(false); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; gbc.insets = UIFactory.getEmptyInsets(); p.add(createSubsectionTitle(getMsg("server-status-title")), gbc); JPanel auxPanel = new JPanel(new GridBagLayout()); auxPanel.setOpaque(false); gbc.anchor = GridBagConstraints.WEST; gbc.gridwidth = GridBagConstraints.RELATIVE; auxPanel.add(UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, getMsg("server-status-label"), UIFactory.TextStyle.PRIMARY_FIELD_VALID), gbc); JPanel statusPanel = new JPanel(new GridBagLayout()); statusPanel.setOpaque(false); gbc.gridwidth = 6; gbc.weightx = 0.0; lServerStatus = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, NOT_AVAILABLE, UIFactory.TextStyle.READ_ONLY); statusPanel.add(lServerStatus, gbc); toolTipManager.registerComponent(lServerStatus); gbc.gridwidth--; stopButton = UIFactory.makeJButton(getMsg("stop-button-label"), getMsg("stop-button-tooltip")); stopButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { stopClicked(); } }); gbc.insets.left = UIFactory.LEFT_INSET_PRIMARY_FIELD; statusPanel.add(stopButton, gbc); gbc.gridwidth--; gbc.insets.left = UIFactory.HORIZONTAL_INSET_BETWEEN_BUTTONS; startButton = UIFactory.makeJButton(getMsg("start-button-label"), getMsg("start-button-tooltip")); statusPanel.add(startButton, gbc); startButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { startClicked(); } }); gbc.gridwidth--; restartButton = UIFactory.makeJButton(getMsg("restart-button-label"), getMsg("restart-button-tooltip")); restartButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { restartClicked(); } }); statusPanel.add(restartButton, gbc); gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.weightx = 1.0; gbc.insets.left = 0; statusPanel.add(Box.createHorizontalGlue(), gbc); int maxButtonHeight = 0; maxButtonHeight = Math.max(maxButtonHeight, (int)startButton.getPreferredSize().getHeight()); maxButtonHeight = Math.max(maxButtonHeight, (int)restartButton.getPreferredSize().getHeight()); maxButtonHeight = Math.max(maxButtonHeight, (int)stopButton.getPreferredSize().getHeight()); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 0.0; statusPanel.add(Box.createVerticalStrut(maxButtonHeight), gbc); gbc.weightx = 1.0; gbc.insets.left = UIFactory.LEFT_INSET_PRIMARY_FIELD; auxPanel.add(statusPanel, gbc); gbc.insets.left = 0; gbc.weightx = 0.0; gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD; gbc.gridwidth = GridBagConstraints.RELATIVE; auxPanel.add(UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, getMsg("connections-label"), UIFactory.TextStyle.PRIMARY_FIELD_VALID), gbc); lCurrentConnections = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, NOT_AVAILABLE, UIFactory.TextStyle.READ_ONLY); toolTipManager.registerComponent(lCurrentConnections); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets.left = UIFactory.LEFT_INSET_PRIMARY_FIELD; auxPanel.add(lCurrentConnections, gbc); gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD; gbc.insets.left = 0; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; p.add(auxPanel, gbc); return p; } /** * Creates the server details subsection panel. * @return the server details subsection panel. */ private JPanel createServerDetailsPanel() { JPanel p = new JPanel(new GridBagLayout()); p.setOpaque(false); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = UIFactory.getEmptyInsets(); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; p.add(createSubsectionTitle(getMsg("server-details-title")), gbc); JPanel auxPanel = new JPanel(new GridBagLayout()); auxPanel.setOpaque(false); gbc.anchor = GridBagConstraints.NORTHWEST; gbc.weightx = 0.0; JLabel[] leftLabels = { UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, getMsg("administrative-users-label"), UIFactory.TextStyle.PRIMARY_FIELD_VALID), UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, getMsg("installation-path-label"), UIFactory.TextStyle.PRIMARY_FIELD_VALID), UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, getMsg("opends-version-label"), UIFactory.TextStyle.PRIMARY_FIELD_VALID), UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, getMsg("java-version-label"), UIFactory.TextStyle.PRIMARY_FIELD_VALID) }; lAdministrativeUsers = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, NOT_AVAILABLE, UIFactory.TextStyle.READ_ONLY); lInstallPath = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, NOT_AVAILABLE, UIFactory.TextStyle.READ_ONLY); lOpenDSVersion = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, NOT_AVAILABLE, UIFactory.TextStyle.READ_ONLY); lJavaVersion = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, NOT_AVAILABLE, UIFactory.TextStyle.READ_ONLY); JLabel[] rightLabels = { lAdministrativeUsers, lInstallPath, lOpenDSVersion, lJavaVersion }; for (int i=0; i<leftLabels.length; i++) { gbc.insets.left = 0; if (i != 0) { gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD; } gbc.gridwidth = GridBagConstraints.RELATIVE; auxPanel.add(leftLabels[i], gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets.left = UIFactory.LEFT_INSET_PRIMARY_FIELD; auxPanel.add(rightLabels[i], gbc); toolTipManager.registerComponent(rightLabels[i]); } gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD; gbc.insets.left = 0; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; p.add(auxPanel, gbc); return p; } /** * Creates the server listeners subsection panel. * @return the server listeners subsection panel. */ private JPanel createListenersPanel() { JPanel p = new JPanel(new GridBagLayout()); p.setOpaque(false); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = UIFactory.getEmptyInsets(); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; gbc.fill = GridBagConstraints.HORIZONTAL; p.add(createSubsectionTitle(getMsg("listeners-title")), gbc); listenersTableModel = new ListenersTableModel(); listenersTable = createTable(listenersTableModel, new ListenersCellRenderer(), new HeaderRenderer()); gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD; p.add(listenersTable.getTableHeader(), gbc); int height = (int) listenersTable.getTableHeader().getPreferredSize().getHeight(); listenersTable.setRowHeight(height); gbc.insets.top = 0; p.add(listenersTable, gbc); lListenersTableEmpty = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, "", UIFactory.TextStyle.PRIMARY_FIELD_VALID); gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD; p.add(lListenersTableEmpty, gbc); lListenersTableEmpty.setVisible(false); toolTipManager.registerComponent(lListenersTableEmpty); return p; } /** * Creates the server databases subsection panel. * @return the server databases subsection panel. */ private JPanel createDatabasesPanel() { JPanel p = new JPanel(new GridBagLayout()); p.setOpaque(false); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = UIFactory.getEmptyInsets(); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1.0; gbc.fill = GridBagConstraints.HORIZONTAL; p.add(createSubsectionTitle(getMsg("databases-title")), gbc); dbTableModel = new DatabasesTableModel(); dbTable = createTable(dbTableModel, new DatabasesCellRenderer(), new HeaderRenderer()); toolTipManager.registerComponent(dbTable); gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD; p.add(dbTable.getTableHeader(), gbc); int height = (int)dbTable.getTableHeader().getPreferredSize().getHeight(); dbTable.setRowHeight(height); gbc.insets.top = 0; p.add(dbTable, gbc); gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD; lDbTableEmpty = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, "", UIFactory.TextStyle.PRIMARY_FIELD_VALID); p.add(lDbTableEmpty, gbc); lDbTableEmpty.setVisible(false); toolTipManager.registerComponent(lDbTableEmpty); return p; } /** * Sets the not available text to a label and associates a help icon and * a tooltip explaining that the data is not available because the server is * down. * @param l the label. */ private void setNotAvailableBecauseServerIsDown(JLabel l) { l.setText(NOT_AVAILABLE); l.setIcon(UIFactory.getImageIcon(UIFactory.IconType.HELP_SMALL)); l.setToolTipText(getMsg("not-available-server-down-tooltip")); l.setHorizontalTextPosition(SwingConstants.LEFT); } /** * Sets the not available text to a label and associates a help icon and * a tooltip explaining that the data is not available because authentication * is required. * @param l the label. */ private void setNotAvailableBecauseAuthenticationIsRequired(JLabel l) { l.setText(NOT_AVAILABLE); l.setIcon(UIFactory.getImageIcon(UIFactory.IconType.HELP_SMALL)); l.setToolTipText(getMsg("not-available-authentication-required-tooltip")); l.setHorizontalTextPosition(SwingConstants.LEFT); } /** * Sets the not available text to a label with no icon nor tooltip. * @param l the label. */ private void setNotAvailable(JLabel l) { l.setText(NOT_AVAILABLE); l.setIcon(null); l.setToolTipText(null); } /** * Sets the a text to a label with no icon nor tooltip. * @param l the label. */ private void setTextValue(JLabel l, String text) { l.setText(text); l.setIcon(null); l.setToolTipText(null); } /** * Returns a table created with the provided model and renderers. * @param tableModel the table model. * @param renderer the cell renderer. * @param headerRenderer the header renderer. * @return a table created with the provided model and renderers. */ private JTable createTable(final SortableTableModel tableModel, TableCellRenderer renderer, TableCellRenderer headerRenderer) { final JTable table = new JTable(tableModel); table.setShowGrid(true); table.setGridColor(UIFactory.PANEL_BORDER_COLOR); table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); table.setBackground(UIFactory.CURRENT_STEP_PANEL_BACKGROUND); table.getTableHeader().setBackground(UIFactory.DEFAULT_BACKGROUND); table.setRowMargin(0); for (int i=0; i<tableModel.getColumnCount(); i++) { TableColumn col = table.getColumn(table.getColumnName(i)); col.setCellRenderer(renderer); col.setHeaderRenderer(headerRenderer); } MouseAdapter listMouseListener = new MouseAdapter() { public void mouseClicked(MouseEvent e) { TableColumnModel columnModel = table.getColumnModel(); int viewColumn = columnModel.getColumnIndexAtX(e.getX()); int sortedBy = table.convertColumnIndexToModel(viewColumn); if (e.getClickCount() == 1 && sortedBy != -1) { tableModel.setSortAscending(!tableModel.isSortAscending()); tableModel.setSortColumn(sortedBy); tableModel.forceResort(); } } }; table.getTableHeader().addMouseListener(listMouseListener); return table; } /** * Updates the status contents displaying with what is specified in the * provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void updateStatusContents(ServerStatusDescriptor desc) { String status; switch (desc.getStatus()) { case STARTED: status = getMsg("server-started-label"); startButton.setVisible(false); restartButton.setVisible(true); stopButton.setVisible(true); break; case STOPPED: status = getMsg("server-stopped-label"); startButton.setVisible(true); restartButton.setVisible(false); stopButton.setVisible(false); break; case STARTING: status = getMsg("server-starting-label"); startButton.setVisible(false); restartButton.setVisible(false); stopButton.setVisible(false); break; case STOPPING: status = getMsg("server-stopping-label"); startButton.setVisible(false); restartButton.setVisible(false); stopButton.setVisible(false); break; case UNKNOWN: status = getMsg("server-unknown-status-label"); startButton.setVisible(false); restartButton.setVisible(true); stopButton.setVisible(true); break; default: throw new IllegalStateException("Unknown status: "+desc.getStatus()); } lServerStatus.setText(status); /* Enable authenticate button only if the server is started AND we have * no authentication (or the authentication we have does not seem to work * because we get an error). */ authenticateButton.setVisible( (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) && (!desc.isAuthenticated() || (desc.getErrorMessage() != null))); } /** * Updates the current connection contents displaying with what is specified * in the provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void updateCurrentConnectionContents(ServerStatusDescriptor desc) { if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { int nConn = desc.getOpenConnections(); if (nConn >= 0) { setTextValue(lCurrentConnections, String.valueOf(nConn)); } else { if (!desc.isAuthenticated()) { setNotAvailableBecauseAuthenticationIsRequired(lCurrentConnections); } else { setNotAvailable(lCurrentConnections); } } } else { setNotAvailableBecauseServerIsDown(lCurrentConnections); } } /** * Updates the admiinistrative user contents displaying with what is specified * in the provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void updateAdministrativeUserContents(ServerStatusDescriptor desc) { Set<String> administrators = desc.getAdministrativeUsers(); if (administrators.size() > 0) { TreeSet<String> ordered = new TreeSet<String>(); for (String name: administrators) { ordered.add(formatter.getFormattedText(name)); } setTextValue(lAdministrativeUsers,"<html>"+ Utils.getStringFromCollection(ordered, "<br>")); } else { if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { if (!desc.isAuthenticated()) { setNotAvailableBecauseAuthenticationIsRequired(lAdministrativeUsers); } else { setNotAvailable(lAdministrativeUsers); } } else { setNotAvailable(lAdministrativeUsers); } } } /** * Updates the install path contents displaying with what is specified in the * provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void updateInstallPathContents(ServerStatusDescriptor desc) { File path = desc.getInstallPath(); lInstallPath.setText(path.toString()); } /** * Updates the server version contents displaying with what is specified in * the provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void updateVersionContents(ServerStatusDescriptor desc) { String openDSVersion = desc.getOpenDSVersion(); lOpenDSVersion.setText(openDSVersion); } /** * Updates the java version contents displaying with what is specified in * the provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void updateJavaVersionContents(ServerStatusDescriptor desc) { if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { String javaVersion = desc.getJavaVersion(); if (javaVersion != null) { setTextValue(lJavaVersion, javaVersion); } else { if (!desc.isAuthenticated()) { setNotAvailableBecauseAuthenticationIsRequired(lJavaVersion); } else { setNotAvailable(lJavaVersion); } } } else { setNotAvailableBecauseServerIsDown(lJavaVersion); } } /** * Updates the listeners contents displaying with what is specified in * the provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void updateListenerContents(ServerStatusDescriptor desc) { listenersTableModel.setData(desc.getListeners()); if (listenersTableModel.getRowCount() == 0) { listenersTable.setVisible(false); listenersTable.getTableHeader().setVisible(false); lListenersTableEmpty.setVisible(true); if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { if (!desc.isAuthenticated()) { setNotAvailableBecauseAuthenticationIsRequired(lListenersTableEmpty); } else { setTextValue(lListenersTableEmpty, getMsg("no-listeners-found")); } } else { setTextValue(lListenersTableEmpty, getMsg("no-listeners-found")); } } else { listenersTable.setVisible(true); listenersTable.getTableHeader().setVisible(true); lListenersTableEmpty.setVisible(false); } } /** * Updates the databases contents displaying with what is specified in * the provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void updateDatabaseContents(ServerStatusDescriptor desc) { dbTableModel.setData(desc.getDatabases()); if (dbTableModel.getRowCount() == 0) { dbTable.setVisible(false); dbTable.getTableHeader().setVisible(false); lDbTableEmpty.setVisible(true); if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { if (!desc.isAuthenticated()) { setNotAvailableBecauseAuthenticationIsRequired(lDbTableEmpty); } else { setTextValue(lDbTableEmpty, getMsg("no-dbs-found")); } } else { setTextValue(lDbTableEmpty, getMsg("no-dbs-found")); } } else { dbTable.setVisible(true); dbTable.getTableHeader().setVisible(true); lDbTableEmpty.setVisible(false); } } /** * Updates the error label contents displaying with what is specified in * the provided ServerStatusDescriptor object. * This method must be called from the event thread. * @param desc the ServerStatusDescriptor object. */ private void updateErrorContents(ServerStatusDescriptor desc) { String errorMsg = desc.getErrorMessage(); if (errorMsg == null) { lError.setVisible(false); } else { lError.setVisible(true); lError.setText(formatter.getFormattedError(errorMsg, false)); } } /** * The following three methods are just commodity methods to get localized * messages. */ private String getMsg(String key) { return getI18n().getMsg(key); } private ResourceProvider getI18n() { return ResourceProvider.getInstance(); } /** * Method written for testing purposes. * @param args the arguments to be passed to the test program. */ public static void main(String[] args) { try { UIFactory.initialize(); StatusPanelDialog dlg = new StatusPanelDialog(); dlg.packAndShow(); } catch (Exception ex) { ex.printStackTrace(); } } /** * Class used to render the databases table cells. */ class DatabasesCellRenderer extends JLabel implements TableCellRenderer { private static final long serialVersionUID = -256719167426289735L; /** * Default constructor. */ public DatabasesCellRenderer() { super(); UIFactory.setTextStyle(this, UIFactory.TextStyle.SECONDARY_FIELD_VALID); } /** * {@inheritDoc} */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (value instanceof String) { setTextValue(this, (String)value); } else { /* Is the number of entries: check if it is available or not */ if (lastDescriptor.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { int nEntries = (Integer)value; if (nEntries >= 0) { setTextValue(this, String.valueOf(nEntries)); } else { if (!lastDescriptor.isAuthenticated()) { setNotAvailableBecauseAuthenticationIsRequired(this); } else { setNotAvailable(this); } } } else { setNotAvailableBecauseServerIsDown(this); } } if (column == 0) { setBorder(BorderFactory.createCompoundBorder( BorderFactory.createMatteBorder(0, 1, 0, 0, UIFactory.PANEL_BORDER_COLOR), BorderFactory.createEmptyBorder(4, 4, 4, 4))); } else { setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); } return this; } } /** * Class used to render the listeners table cells. */ class ListenersCellRenderer extends JLabel implements TableCellRenderer { private static final long serialVersionUID = -256719167426289735L; /** * Default constructor. */ public ListenersCellRenderer() { super(); UIFactory.setTextStyle(this, UIFactory.TextStyle.SECONDARY_FIELD_VALID); } /** * {@inheritDoc} */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setTextValue(this, (String)value); if (column == 0) { setBorder(BorderFactory.createCompoundBorder( BorderFactory.createMatteBorder(0, 1, 0, 0, UIFactory.PANEL_BORDER_COLOR), BorderFactory.createEmptyBorder(4, 4, 4, 4))); } else { setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); } return this; } } /** * Class used to render the table headers. */ class HeaderRenderer extends JLabel implements TableCellRenderer { private static final long serialVersionUID = -8604332267021523835L; /** * Default constructor. */ public HeaderRenderer() { super(); UIFactory.setTextStyle(this, UIFactory.TextStyle.PRIMARY_FIELD_VALID); } /** * {@inheritDoc} */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setTextValue(this, (String)value); if (column == 0) { setBorder(BorderFactory.createCompoundBorder( BorderFactory.createMatteBorder(1, 1, 1, 1, UIFactory.PANEL_BORDER_COLOR), BorderFactory.createEmptyBorder(4, 4, 4, 4))); } else { setBorder(BorderFactory.createCompoundBorder( BorderFactory.createMatteBorder(1, 0, 1, 1, UIFactory.PANEL_BORDER_COLOR), BorderFactory.createEmptyBorder(4, 4, 4, 4))); } return this; } } } /** * This class is used to be able to have an instantaneous tooltip displayed * in the 'not available' labels. It replaces the default ToolTipManager class. * */ class InstantaneousToolTipManager extends MouseAdapter implements MouseMotionListener { private ToolTipManager ttipManager = ToolTipManager.sharedInstance(); private Popup tipWindow; private boolean isVisible; /** * The default constructor. */ public InstantaneousToolTipManager() { } /** * Register a component that will use this tool tip manager to display tool * tips. * @param comp the component to be registered. */ public void registerComponent(JComponent comp) { ttipManager.unregisterComponent(comp); comp.removeMouseListener(this); comp.addMouseListener(this); comp.removeMouseMotionListener(this); comp.addMouseMotionListener(this); } /** * Unregisters a component. Calling this method makes the component to be * registered by the default tool tip manager. * @param comp the component to be unregistered. */ public void unregisterComponent(JComponent comp) { ttipManager.registerComponent(comp); comp.removeMouseListener(this); comp.removeMouseMotionListener(this); } /** * {@inheritDoc} */ public void mouseDragged(MouseEvent event) { } /** * {@inheritDoc} */ public void mouseEntered(MouseEvent event) { displayToolTip(event); } /** * {@inheritDoc} */ public void mouseExited(MouseEvent event) { hideToolTip(event); } /** * {@inheritDoc} */ public void mouseMoved(MouseEvent event) { hideToolTip(event); displayToolTip(event); } /** * {@inheritDoc} */ public void mousePressed(MouseEvent event) { if (isVisible) { hideToolTip(event); } else { hideToolTip(event); displayToolTip(event); } } /** * Displays a tooltip depending on the MouseEvent received. * @param event the mouse event. */ private void displayToolTip(MouseEvent event) { JComponent component = (JComponent)event.getSource(); String toolTipText = component.getToolTipText(event); if (toolTipText != null) { Point preferredLocation = component.getToolTipLocation(event); Rectangle sBounds = component.getGraphicsConfiguration(). getBounds(); JToolTip tip = component.createToolTip(); tip.setTipText(toolTipText); Dimension size = tip.getPreferredSize(); Point location = new Point(); Point screenLocation = component.getLocationOnScreen(); if(preferredLocation != null) { location.x = screenLocation.x + preferredLocation.x; location.y = screenLocation.y + preferredLocation.y; } else { location.x = screenLocation.x + event.getX(); location.y = screenLocation.y + event.getY() + 20; } if (location.x < sBounds.x) { location.x = sBounds.x; } else if (location.x - sBounds.x + size.width > sBounds.width) { location.x = sBounds.x + Math.max(0, sBounds.width - size.width); } if (location.y < sBounds.y) { location.y = sBounds.y; } else if (location.y - sBounds.y + size.height > sBounds.height) { location.y = sBounds.y + Math.max(0, sBounds.height - size.height); } PopupFactory popupFactory = PopupFactory.getSharedInstance(); tipWindow = popupFactory.getPopup(component, tip, location.x, location.y); tipWindow.show(); } isVisible = true; } /** * Hides the tooltip if we are displaying it. * @param event the mouse event. */ private void hideToolTip(MouseEvent event) { if (tipWindow != null) { tipWindow.hide(); tipWindow = null; } isVisible = false; } }