/* * 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 2007 Sun Microsystems, Inc. */ package org.opends.guitools.statuspanel; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.net.URI; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; import javax.naming.NamingException; import javax.naming.ldap.InitialLdapContext; import javax.swing.table.TableModel; import org.opends.admin.ads.util.ApplicationTrustManager; import org.opends.admin.ads.util.ConnectionUtils; import org.opends.guitools.statuspanel.ui.DatabasesTableModel; import org.opends.guitools.statuspanel.ui.ListenersTableModel; import org.opends.quicksetup.CliApplicationHelper; import org.opends.quicksetup.Installation; import org.opends.quicksetup.QuickSetupLog; import org.opends.quicksetup.util.Utils; import static org.opends.quicksetup.util.Utils.*; import org.opends.server.admin.client.cli.DsFrameworkCliReturnCode; import org.opends.server.core.DirectoryServer; import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import static org.opends.messages.ToolMessages.*; import static org.opends.messages.AdminToolMessages.*; import static org.opends.messages.QuickSetupMessages.*; import org.opends.server.types.NullOutputStream; import org.opends.server.util.args.ArgumentException; /** * 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 extends CliApplicationHelper { private boolean displayMustAuthenticateLegend; private boolean displayMustStartLegend; /** Prefix for log files. */ static public final String LOG_FILE_PREFIX = "opends-status-"; /** Suffix for log files. */ static public final String LOG_FILE_SUFFIX = ".log"; /** * The enumeration containing the different return codes that the command-line * can have. * */ enum ErrorReturnCode { /** * Successful display of the status. */ SUCCESSFUL(0), /** * We did no have an error but the status was not displayed (displayed * version or usage). */ SUCCESSFUL_NOP(0), /** * Unexpected error (potential bug). */ ERROR_UNEXPECTED(1), /** * Cannot parse arguments. */ ERROR_PARSING_ARGS(2), /** * User cancelled (for instance not accepting the certificate proposed). */ USER_CANCELLED(3); private int returnCode; private ErrorReturnCode(int returnCode) { this.returnCode = returnCode; } /** * Get the corresponding return code value. * * @return The corresponding return code value. */ public int getReturnCode() { return returnCode; } }; /** * The Logger. */ static private final Logger LOG = Logger.getLogger(StatusCli.class.getName()); // The argument parser private StatusCliArgumentParser argParser; /** * Constructor for the StatusCli object. * * @param out the print stream to use for standard output. * @param err the print stream to use for standard error. * @param in the input stream to use for standard input. */ public StatusCli(PrintStream out, PrintStream err, InputStream in) { super(out, err, in); } /** * The main method for the status CLI tool. * * @param args the command-line arguments provided to this program. */ public static void main(String[] args) { int retCode = mainCLI(args, true, System.out, System.err, System.in); if(retCode != 0) { System.exit(retCode); } } /** * Parses the provided command-line arguments and uses that information to * run the status tool. * * @param args the command-line arguments provided to this program. * * @return The error code. */ public static int mainCLI(String[] args) { return mainCLI(args, true, System.out, System.err, System.in); } /** * Parses the provided command-line arguments and uses that information to * run the status tool. * * @param args The command-line arguments provided to this * program. * @param initializeServer Indicates whether to initialize the server. * @param outStream The output stream to use for standard output, or * null if standard output is not * needed. * @param errStream The output stream to use for standard error, or * null if standard error is not * needed. * @param inStream The input stream to use for standard input. * @return The error code. */ public static int mainCLI(String[] args, boolean initializeServer, OutputStream outStream, OutputStream errStream, InputStream inStream) { PrintStream out; if (outStream == null) { out = NullOutputStream.printStream(); } else { out = new PrintStream(outStream); } PrintStream err; if (errStream == null) { err = NullOutputStream.printStream(); } else { err = new PrintStream(errStream); } try { QuickSetupLog.initLogFileHandler( File.createTempFile(LOG_FILE_PREFIX, LOG_FILE_SUFFIX), "org.opends.guitools.statuspanel"); QuickSetupLog.disableConsoleLogging(); } catch (Throwable t) { System.err.println("Unable to initialize log"); t.printStackTrace(); } StatusCli statusCli = new StatusCli(out, err, inStream); return statusCli.execute(args, initializeServer); } /** * Parses the provided command-line arguments and uses that information to * run the status CLI. * * @param args the command-line arguments provided to this program. * @param initializeServer Indicates whether to initialize the server. * * @return the return code (SUCCESSFUL, USER_DATA_ERROR or BUG. */ public int execute(String[] args, boolean initializeServer) { if (initializeServer) { DirectoryServer.bootstrapClient(); } argParser = new StatusCliArgumentParser(StatusCli.class.getName()); try { argParser.initializeGlobalArguments(err); } catch (ArgumentException ae) { Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage()); err.println(wrap(message)); return ErrorReturnCode.ERROR_UNEXPECTED.getReturnCode(); } // Validate user provided data try { argParser.parseArguments(args); } catch (ArgumentException ae) { Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage()); printErrorMessage(message); printLineBreak(); printErrorMessage(argParser.getUsage()); return ErrorReturnCode.ERROR_PARSING_ARGS.getReturnCode(); } // If we should just display usage or version information, // then print it and exit. if (argParser.usageOrVersionDisplayed()) { return ErrorReturnCode.SUCCESSFUL_NOP.getReturnCode(); } int v = argParser.validateGlobalOptions(err); if (v != DsFrameworkCliReturnCode.SUCCESSFUL_NOP.getReturnCode()) { printErrorMessage(argParser.getUsage()); return v; } else { boolean isServerRunning = Installation.getLocal().getStatus().isServerRunning(); /* This is required to retrieve the ldap url to be used by the * ConfigFromLDAP class. */ ConfigFromFile offLineConf = new ConfigFromFile(); offLineConf.readConfiguration(); try { if (isServerRunning) { String bindDn; String bindPwd; boolean useSSL = argParser.useSSL(); boolean useStartTLS = argParser.useStartTLS(); if (argParser.isInteractive()) { boolean connected = false; boolean cancelled = false; boolean prompted = false; boolean canUseSSL = offLineConf.getLDAPSURL() != null; boolean canUseStartTLS = offLineConf.getStartTLSURL() != null; bindDn = argParser.getExplicitBindDn(); bindPwd = argParser.getBindPassword(); if (bindDn == null) { bindDn = promptForString( INFO_CLI_BINDDN_PROMPT.get(), argParser.getDefaultBindDn()); prompted = true; } if (bindPwd == null) { bindPwd = promptForPassword( INFO_LDAPAUTH_PASSWORD_PROMPT.get(bindDn)); prompted = true; } if (!useSSL && !useStartTLS) { if (canUseSSL) { printLineBreak(); useSSL = confirm(INFO_CLI_USESSL_PROMPT.get(), useSSL); } if (!useSSL && canUseStartTLS) { printLineBreak(); useStartTLS = confirm(INFO_CLI_USESTARTTLS_PROMPT.get(), useStartTLS); } prompted = true; } InitialLdapContext ctx = null; while (!connected && !cancelled) { if (prompted) { printLineBreak(); } String host = "localhost"; int port = 389; try { String ldapUrl = offLineConf.getURL( getConnectionPolicy(useSSL, useStartTLS)); try { URI uri = new URI(ldapUrl); host = uri.getHost(); port = uri.getPort(); } catch (Throwable t) { LOG.log(Level.SEVERE, "Error parsing url: "+ldapUrl); } ctx = createContext(host, port, useSSL, useStartTLS, bindDn, bindPwd, getTrustManager()); connected = true; } catch (ConfigException ce) { LOG.log(Level.WARNING, "Error reading config file: "+ce, ce); printLineBreak(); printErrorMessage(ERR_COULD_NOT_FIND_VALID_LDAPURL.get()); printLineBreak(); useSSL = confirm(INFO_CLI_USESSL_PROMPT.get(), useSSL); if (!useSSL) { useStartTLS = confirm(INFO_CLI_USESTARTTLS_PROMPT.get(), useStartTLS); } prompted = true; } catch (NamingException ne) { LOG.log(Level.WARNING, "Error connecting: "+ne, ne); if (Utils.isCertificateException(ne)) { String usedUrl = ConnectionUtils.getLDAPUrl(host, port, useSSL); if (!promptForCertificateConfirmation(ne, getTrustManager(), usedUrl, getTrustManager())) { cancelled = true; } prompted = true; } else { printLineBreak(); printErrorMessage( ERR_STATUS_CLI_ERROR_CONNECTING_PROMPT_AGAIN.get( ne.getMessage())); String defaultValue = (bindDn != null) ? bindDn : argParser.getDefaultBindDn(); bindDn = promptForString( INFO_CLI_BINDDN_PROMPT.get(), defaultValue); bindPwd = promptForPassword( INFO_LDAPAUTH_PASSWORD_PROMPT.get(bindDn)); printLineBreak(); useSSL = confirm(INFO_CLI_USESSL_PROMPT.get(), useSSL); if (!useSSL) { printLineBreak(); useStartTLS = confirm(INFO_CLI_USESTARTTLS_PROMPT.get(), useStartTLS); } prompted = true; } } } if (ctx != null) { try { ctx.close(); } catch (Throwable t) { } } if (cancelled) { return ErrorReturnCode.USER_CANCELLED.getReturnCode(); } } else { bindDn = argParser.getBindDN(); bindPwd = argParser.getBindPassword(); if (bindDn == null) { bindDn = ""; } if (bindPwd == null) { bindPwd = ""; } } ServerStatusDescriptor desc = createServerStatusDescriptor( bindDn, bindPwd); ConfigFromLDAP onLineConf = new ConfigFromLDAP(); ConnectionProtocolPolicy policy = getConnectionPolicy(useSSL, useStartTLS); onLineConf.setConnectionInfo(offLineConf, policy, bindDn, bindPwd, getTrustManager()); onLineConf.readConfiguration(); updateDescriptorWithOnLineInfo(desc, onLineConf); writeStatus(desc); } else { ServerStatusDescriptor desc = createServerStatusDescriptor(null, null); updateDescriptorWithOffLineInfo(desc, offLineConf); writeStatus(desc); } } catch (ConfigException ce) { printLineBreak(); printErrorMessage(ce.getMessageObject()); } } return ErrorReturnCode.SUCCESSFUL.getReturnCode(); } private ServerStatusDescriptor createServerStatusDescriptor(String dn, String pwd) { ServerStatusDescriptor desc = new ServerStatusDescriptor(); desc.setAuthenticated((dn != null) && (pwd != null)); if (Installation.getLocal().getStatus().isServerRunning()) { desc.setStatus(ServerStatusDescriptor.ServerStatus.STARTED); } else { desc.setStatus(ServerStatusDescriptor.ServerStatus.STOPPED); } desc.setInstallPath(new File(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) { Message[] labels = { INFO_SERVER_STATUS_LABEL.get(), INFO_CONNECTIONS_LABEL.get(), INFO_ADMINISTRATIVE_USERS_LABEL.get(), INFO_INSTALLATION_PATH_LABEL.get(), INFO_OPENDS_VERSION_LABEL.get(), INFO_JAVA_VERSION_LABEL.get() }; int labelWidth = 0; for (int i=0; i= 0) { text = Message.raw(String.valueOf(nConn)); } else { if (!desc.isAuthenticated()) { text = getNotAvailableBecauseAuthenticationIsRequiredText(); } else { text = getNotAvailableText(); } } } else { text = getNotAvailableBecauseServerIsDownText(); } writeLabelValue(INFO_CONNECTIONS_LABEL.get(), 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 administrators = desc.getAdministrativeUsers(); Message text; if (administrators.size() > 0) { TreeSet ordered = new TreeSet(); ordered.addAll(administrators); String first = ordered.iterator().next(); writeLabelValue( INFO_ADMINISTRATIVE_USERS_LABEL.get(), Message.raw(first), maxLabelWidth); Iterator it = ordered.iterator(); // First one already printed it.next(); while (it.hasNext()) { writeLabelValue( INFO_ADMINISTRATIVE_USERS_LABEL.get(), Message.raw(it.next()), maxLabelWidth); } } else { if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { if (!desc.isAuthenticated()) { text = getNotAvailableBecauseAuthenticationIsRequiredText(); } else { text = getNotAvailableText(); } } else { text = getNotAvailableText(); } writeLabelValue(INFO_ADMINISTRATIVE_USERS_LABEL.get(), 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(INFO_INSTALLATION_PATH_LABEL.get(), Message.raw(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(INFO_OPENDS_VERSION_LABEL.get(), Message.raw(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) { Message text; if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { text = Message.raw(desc.getJavaVersion()); if (text == null) { if (!desc.isAuthenticated()) { text = getNotAvailableBecauseAuthenticationIsRequiredText(); } else { text = getNotAvailableText(); } } } else { text = getNotAvailableBecauseServerIsDownText(); } writeLabelValue(INFO_JAVA_VERSION_LABEL.get(), 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) { Message title = INFO_LISTENERS_TITLE.get(); out.println(centerTitle(title)); Set listeners = desc.getListeners(); if (listeners.size() == 0) { if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { if (!desc.isAuthenticated()) { out.println( wrap(INFO_NOT_AVAILABLE_AUTHENTICATION_REQUIRED_CLI_LABEL.get())); } else { out.println(wrap(INFO_NO_LISTENERS_FOUND.get())); } } else { out.println(wrap(INFO_NO_LISTENERS_FOUND.get())); } } 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) { Message title = INFO_DATABASES_TITLE.get(); out.println(centerTitle(title)); Set databases = desc.getDatabases(); if (databases.size() == 0) { if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED) { if (!desc.isAuthenticated()) { out.println( wrap(INFO_NOT_AVAILABLE_AUTHENTICATION_REQUIRED_CLI_LABEL.get())); } else { out.println(wrap(INFO_NO_DBS_FOUND.get())); } } else { out.println(wrap(INFO_NO_DBS_FOUND.get())); } } else { DatabasesTableModel databasesTableModel = new DatabasesTableModel(true); Set replicas = new HashSet(); Set dbs = desc.getDatabases(); for (DatabaseDescriptor db: dbs) { replicas.addAll(db.getBaseDns()); } databasesTableModel.setData(replicas); writeDatabasesTableModel(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) { Message errorMsg = desc.getErrorMessage(); if (errorMsg != null) { out.println(); 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 Message getNotAvailableBecauseServerIsDownText() { displayMustStartLegend = true; return INFO_NOT_AVAILABLE_SERVER_DOWN_CLI_LABEL.get(); } /** * Returns the not available text explaining that the data is not available * because authentication is required. * @return the text. */ private Message getNotAvailableBecauseAuthenticationIsRequiredText() { displayMustAuthenticateLegend = true; return INFO_NOT_AVAILABLE_AUTHENTICATION_REQUIRED_CLI_LABEL.get(); } /** * Returns the not available text explaining that the data is not available. * @return the text. */ private Message getNotAvailableText() { return INFO_NOT_AVAILABLE_LABEL.get(); } /** * Writes the contents of the provided table model simulating a table layout * using text. * @param tableModel the TableModel. * @param desc the Server Status descriptor. */ private void writeTableModel(TableModel tableModel, ServerStatusDescriptor desc) { int[] maxWidths = new int[tableModel.getColumnCount()]; for (int i=0; i= 0) { text = Message.raw(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 0) { out.println(); } for (int j=0; j= 0) { value = Message.raw(String.valueOf(nEntries)); } else { if (!isRunning) { value = getNotAvailableBecauseServerIsDownText(); } if (!desc.isAuthenticated()) { value = getNotAvailableBecauseAuthenticationIsRequiredText(); } else { value = getNotAvailableText(); } } } else { throw new IllegalStateException("Unknown object type: "+v); } } else { value = Message.EMPTY; } if (value.equals(getNotAvailableText())) { if (!isRunning) { value = getNotAvailableBecauseServerIsDownText(); } if (!desc.isAuthenticated()) { value = getNotAvailableBecauseAuthenticationIsRequiredText(); } } boolean doWrite = true; if ((j == 4) || (j == 5)) { // If the suffix is not replicated we do not have to display these // lines. if (!replicatedLabel.equals(tableModel.getValueAt(i, 3))) { doWrite = false; } } if (doWrite) { writeLabelValue(labels[j], value, labelWidth); } } } } private void writeLabelValue(Message label, Message value, int maxLabelWidth) { MessageBuilder buf = new MessageBuilder(); buf.append(label); int extra = maxLabelWidth - label.length(); for (int i = 0; i