mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

jvergara
16.48.2009 2d5ba62ec69e7ffa4b98149a9f6fef539e38251f
Fix for issue 3912 (Default automatic Backup should be offered by the control panel)

The fix consists on adding three new elements to the control panel.

1. Allow the user to specify a future date when the backup will be launched or a periodic schedule to launch the backup.

2. Allow the user to specify a future date when an export to LDIF will be launched or a periodic schedule to launch the export.

3. Allow the user to see the scheduled and ongoing tasks. This is a graphical equivalent of the manage-task command. In this first version, the GUI displays the tasks and allows to cancel them. It allows to display all the common task attributes in a table and also the specific attributes for a task in a separate pane.

With this proposal including the possibility of allowing scheduling other type of tasks (like import or restore) is just a matter of adding half a dozen of lines of code (since most of the code is in StatusGenericPanel) so if we find that allowing scheduling tasks for other tasks (apart from backup and export) makes sense, it is pretty straightforward to add this functionality.

10 files added
16 files modified
4342 ■■■■■ changed files
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/ControlPanelInfo.java 1 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/CustomSearchResult.java 100 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/ScheduleType.java 206 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/ServerDescriptor.java 26 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/TaskTableModel.java 421 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/task/CancelTaskTask.java 261 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/BackupPanel.java 30 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/ConnectionHandlerMonitoringPanel.java 58 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/ExportLDIFPanel.java 31 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/MainActionsPane.java 7 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/ManageTasksPanel.java 939 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/MonitoringAttributesViewPanel.java 19 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java 61 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/TaskToSchedulePanel.java 1178 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/components/NumericLimitedSizeDocumentFilter.java 116 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/components/ScheduleSummaryPanel.java 182 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/components/TimeDocumentFilter.java 198 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/renderer/NoLeftInsetCategoryComboBoxRenderer.java 71 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/renderer/TaskCellRenderer.java 95 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/util/ConfigFromDirContext.java 122 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/util/ConfigReader.java 15 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/util/Utilities.java 6 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/admin_tool.properties 130 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/task/RecurringTask.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/tasks/TaskEntry.java 65 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/util/LDIFReader.java 2 ●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/ControlPanelInfo.java
@@ -679,6 +679,7 @@
        desc.setAuthenticated(reader instanceof ConfigFromDirContext);
        desc.setJavaVersion(reader.getJavaVersion());
        desc.setOpenConnections(reader.getOpenConnections());
        desc.setTaskEntries(reader.getTaskEntries());
        if (reader instanceof ConfigFromDirContext)
        {
          ConfigFromDirContext rCtx = (ConfigFromDirContext)reader;
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/CustomSearchResult.java
@@ -27,9 +27,13 @@
package org.opends.guitools.controlpanel.datamodel;
import static org.opends.server.util.StaticUtils.toLowerCase;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
@@ -44,6 +48,17 @@
import javax.naming.directory.SearchResult;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.AttributeBuilder;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.AttributeValues;
import org.opends.server.types.ByteString;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.OpenDsException;
import org.opends.server.util.LDIFReader;
/**
 * This is a commodity class used to wrap the SearchResult class of JNDI.
@@ -261,4 +276,89 @@
  {
    return 23 + toString.hashCode();
  }
  /**
   * Gets the Entry object equivalent to this CustomSearchResult.
   * The method assumes that the schema in DirectoryServer has been initialized.
   * @return the Entry object equivalent to this CustomSearchResult.
   * @throws OpenDsException if there is an error parsing the DN or retrieving
   * the attributes definition and objectclasses in the schema of the server.
   */
  public Entry getEntry() throws OpenDsException
  {
    DN dn = DN.decode(this.getDN());
    Map<ObjectClass,String> objectClasses = new HashMap<ObjectClass,String>();
    Map<AttributeType,List<org.opends.server.types.Attribute>> userAttributes =
      new HashMap<AttributeType,List<org.opends.server.types.Attribute>>();
    Map<AttributeType,List<org.opends.server.types.Attribute>>
    operationalAttributes =
      new HashMap<AttributeType,List<org.opends.server.types.Attribute>>();
    for (String wholeName : this.getAttributeNames())
    {
      final org.opends.server.types.Attribute attribute =
        LDIFReader.parseAttrDescription(wholeName);
      final String attrName = attribute.getName();
      final String lowerName = toLowerCase(attrName);
      // See if this is an objectclass or an attribute.  Then get the
      // corresponding definition and add the value to the appropriate hash.
      if (lowerName.equals("objectclass"))
      {
        for (Object value : this.getAttributeValues(attrName))
        {
          String ocName = value.toString().trim();
          String lowerOCName = toLowerCase(ocName);
          ObjectClass objectClass =
            DirectoryServer.getObjectClass(lowerOCName);
          if (objectClass == null)
          {
            objectClass = DirectoryServer.getDefaultObjectClass(ocName);
          }
          objectClasses.put(objectClass, ocName);
        }
      }
      else
      {
        AttributeType attrType = DirectoryServer.getAttributeType(lowerName);
        if (attrType == null)
        {
          attrType = DirectoryServer.getDefaultAttributeType(attrName);
        }
        AttributeBuilder builder = new AttributeBuilder(attribute, true);
        for (Object value : this.getAttributeValues(attrName))
        {
          ByteString bs;
          if (value instanceof byte[])
          {
            bs = ByteString.wrap((byte[])value);
          }
          else
          {
            bs = ByteString.valueOf(value.toString());
          }
          AttributeValue attributeValue =
            AttributeValues.create(attrType, bs);
          builder.add(attributeValue);
        }
        List<org.opends.server.types.Attribute> attrList =
          new ArrayList<org.opends.server.types.Attribute>(1);
        attrList.add(builder.toAttribute());
        if (attrType.isOperational())
        {
          operationalAttributes.put(attrType, attrList);
        }
        else
        {
          userAttributes.put(attrType, attrList);
        }
      }
    }
    return new Entry(dn, objectClasses, userAttributes, operationalAttributes);
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/ScheduleType.java
New file
@@ -0,0 +1,206 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.datamodel;
import java.util.Date;
/**
 * The class to be used to describe the task schedule.
 *
 */
public class ScheduleType
{
  /**
   * The different type of schedules.
   *
   */
  public enum Type
  {
    /**
     * Launch now.
     */
    LAUNCH_NOW,
    /**
     * Launch later in a specific date.
     */
    LAUNCH_LATER,
    /**
     * Launch periodically.
     */
    LAUNCH_PERIODICALLY
  }
  private Type type;
  private Date launchLaterDate;
  private String cronValue;
  private String toString;
  private int hashCode;
  private ScheduleType()
  {
  }
  /**
   * Returns a schedule instance that launches the task now.
   * @return a schedule instance that launches the task now.
   */
  public static ScheduleType createLaunchNow()
  {
    ScheduleType schedule = new ScheduleType();
    schedule.type = Type.LAUNCH_NOW;
    schedule.toString = schedule.calculateToString();
    schedule.hashCode = schedule.calculateHashCode();
    return schedule;
  }
  /**
   * Returns a schedule instance that launches the task at a given date.
   * @param date the Date at which the task must be launched.
   * @return a schedule instance that launches the task at a given date.
   */
  public static ScheduleType createLaunchLater(Date date)
  {
    ScheduleType schedule = new ScheduleType();
    schedule.type = Type.LAUNCH_LATER;
    schedule.launchLaterDate = date;
    schedule.toString = schedule.calculateToString();
    schedule.hashCode = schedule.calculateHashCode();
    return schedule;
  }
  /**
   * Returns a schedule instance that launches the task using a cron schedule.
   * @param cron the String containing the cron schedule.
   * @return a schedule instance that launches the task using a cron schedule.
   */
  public static ScheduleType createCron(String cron)
  {
    ScheduleType schedule = new ScheduleType();
    schedule.type = Type.LAUNCH_PERIODICALLY;
    schedule.cronValue = cron;
    schedule.toString = schedule.calculateToString();
    schedule.hashCode = schedule.calculateHashCode();
    return schedule;
  }
  /**
   * Returns the type of the schedule.
   * @return the type of the schedule.
   */
  public Type getType()
  {
    return type;
  }
  /**
   * Returns the date on which the task will be launched.
   * @return the date on which the task will be launched.
   */
  public Date getLaunchLaterDate()
  {
    return launchLaterDate;
  }
  /**
   * Returns the CRON String representation of the schedule.
   * @return the CRON String representation of the schedule.
   */
  public String getCronValue()
  {
    return cronValue;
  }
  /**
   * {@inheritDoc}
   */
  public boolean equals(Object o)
  {
    boolean equals;
    if (o != null)
    {
      if (o == this)
      {
        equals = true;
      }
      else
      {
        equals = toString().equals(o.toString());
      }
    }
    else
    {
      equals = false;
    }
    return equals;
  }
  /**
   * {@inheritDoc}
   */
  public String toString()
  {
    return toString;
  }
  /**
   * {@inheritDoc}
   */
  public int hashCode()
  {
    return hashCode;
  }
  /**
   * Calculates the hashCode.
   * To be called after the calculateToString is called.
   * @return the value of the hashCode.
   */
  private int calculateHashCode()
  {
    return 32 + toString.hashCode();
  }
  private String calculateToString()
  {
    String toString;
    switch (type)
    {
    case LAUNCH_NOW:
      toString = "Schedule Type: Launch Now";
      break;
    case LAUNCH_LATER:
      toString = "Schedule Type: Launch Later at date "+launchLaterDate;
      break;
    case LAUNCH_PERIODICALLY:
      toString = "Schedule Type: periodical schedule "+cronValue;
      break;
      default:
        throw new IllegalStateException("Invalid type: "+type);
    }
    return toString;
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/ServerDescriptor.java
@@ -40,6 +40,7 @@
import org.opends.guitools.controlpanel.util.ConfigFromDirContext;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.server.tools.tasks.TaskEntry;
import org.opends.server.types.AttributeType;
import org.opends.server.types.DN;
import org.opends.server.types.ObjectClass;
@@ -79,6 +80,8 @@
  private CustomSearchResult workQueue;
  private Set<TaskEntry> taskEntries = new HashSet<TaskEntry>();
  private long runningTime = -1;
  private boolean isAuthenticated;
@@ -289,6 +292,24 @@
  }
  /**
   * Returns the task entries.
   * @return the task entries.
   */
  public Set<TaskEntry> getTaskEntries()
  {
    return taskEntries;
  }
  /**
   * Sets the the task entries.
   * @param taskEntries the task entries.
   */
  public void setTaskEntries(Set<TaskEntry> taskEntries)
  {
    this.taskEntries = Collections.unmodifiableSet(taskEntries);
  }
  /**
   * {@inheritDoc}
   */
  public boolean equals(Object o)
@@ -411,6 +432,11 @@
          equals =
            desc.isWindowsServiceEnabled() == isWindowsServiceEnabled();
        }
        if (equals)
        {
          desc.getTaskEntries().equals(getTaskEntries());
        }
      }
    }
    else
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/TaskTableModel.java
New file
@@ -0,0 +1,421 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.datamodel;
import static org.opends.messages.AdminToolMessages.*;
import static org.opends.messages.ToolMessages.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.opends.guitools.controlpanel.ui.ColorAndFontConstants;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.quicksetup.util.Utils;
import org.opends.server.backends.task.TaskState;
import org.opends.server.tools.tasks.TaskEntry;
/**
 * The table used to display the tasks.
 *
 */
public class TaskTableModel  extends SortableTableModel
implements Comparator<TaskEntry>
{
  private static final long serialVersionUID = -351142550147124L;
  private Set<TaskEntry> data = new HashSet<TaskEntry>();
  private ArrayList<TaskEntry> dataSourceArray = new ArrayList<TaskEntry>();
  LinkedHashSet<Message> displayedAttributes = new LinkedHashSet<Message>();
  final LinkedHashSet<Message> defaultAttributes = new LinkedHashSet<Message>();
  {
    defaultAttributes.add(INFO_TASKINFO_FIELD_ID.get());
    defaultAttributes.add(INFO_TASKINFO_FIELD_TYPE.get());
    defaultAttributes.add(INFO_TASKINFO_FIELD_STATUS.get());
    defaultAttributes.add(INFO_CTRL_PANEL_TASK_CANCELABLE.get());
  }
  LinkedHashSet<Message> allAttributes = new LinkedHashSet<Message>();
  {
    allAttributes.addAll(defaultAttributes);
    allAttributes.add(INFO_TASKINFO_FIELD_SCHEDULED_START.get());
    allAttributes.add(INFO_TASKINFO_FIELD_ACTUAL_START.get());
    allAttributes.add(INFO_TASKINFO_FIELD_COMPLETION_TIME.get());
    allAttributes.add(INFO_TASKINFO_FIELD_DEPENDENCY.get());
    allAttributes.add(INFO_TASKINFO_FIELD_FAILED_DEPENDENCY_ACTION.get());
    allAttributes.add(INFO_TASKINFO_FIELD_NOTIFY_ON_COMPLETION.get());
    allAttributes.add(INFO_TASKINFO_FIELD_NOTIFY_ON_ERROR.get());
  }
  private String[] columnNames = {};
  /**
   * The sort column of the table.
   */
  private int sortColumn = 0;
  /**
   * Whether the sorting is ascending or descending.
   */
  private boolean sortAscending = true;
  /**
   * Default constructor.
   */
  public TaskTableModel()
  {
    super();
    setAttributes(defaultAttributes);
  }
  /**
   * Sets the data for this table model.
   * @param newData the data for this table model.
   */
  public void setData(Set<TaskEntry> newData)
  {
    if (!newData.equals(data))
    {
      data.clear();
      data.addAll(newData);
      updateDataArray();
      fireTableDataChanged();
    }
  }
  /**
   * Updates the table model contents and sorts its contents depending on the
   * sort options set by the user.
   */
  public void forceResort()
  {
    updateDataArray();
    fireTableDataChanged();
  }
  /**
   * Updates the table model contents, sorts its contents depending on the
   * sort options set by the user and updates the column structure.
   */
  public void forceDataStructureChange()
  {
    updateDataArray();
    fireTableStructureChanged();
    fireTableDataChanged();
  }
  /**
   * Updates the array data.  This includes resorting it.
   */
  private void updateDataArray()
  {
    TreeSet<TaskEntry> sortedSet = new TreeSet<TaskEntry>(this);
    sortedSet.addAll(data);
    dataSourceArray.clear();
    for (TaskEntry task : sortedSet)
    {
      dataSourceArray.add(task);
    }
  }
  /**
   * Sets the operations displayed by this table model.
   * @param attributes the attributes displayed by this table model.
   */
  public void setAttributes(LinkedHashSet<Message> attributes)
  {
    if (!allAttributes.containsAll(attributes))
    {
      throw new IllegalArgumentException(
          "Some of the provided attributes are not valid.");
    }
    this.displayedAttributes.clear();
    this.displayedAttributes.addAll(attributes);
    int columnCount = attributes.size();
    columnNames = new String[columnCount];
    int i = 0;
    for (Message attribute : attributes)
    {
      columnNames[i] = getHeader(attribute, 15);
      i++;
    }
  }
  /**
   * {@inheritDoc}
   */
  public Class<?> getColumnClass(int column)
  {
    return Message.class;
  }
  /**
   * {@inheritDoc}
   */
  public String getColumnName(int col) {
    return columnNames[col];
  }
  /**
   * {@inheritDoc}
   */
  public Object getValueAt(int row, int column)
  {
    Message value;
    column = getFixedOrderColumn(column);
    TaskEntry taskEntry = get(row);
    switch (column)
    {
    case 0:
      value = Message.raw(taskEntry.getId());
      break;
    case 1:
      value = taskEntry.getType();
      break;
    case 2:
      value = taskEntry.getState();
      break;
    case 3:
      if (taskEntry.isCancelable())
      {
        value = INFO_CTRL_PANEL_TASK_IS_CANCELABLE.get();
      }
      else
      {
        value = INFO_CTRL_PANEL_TASK_IS_NOT_CANCELABLE.get();
      }
      break;
    case 4:
      if (TaskState.isRecurring(get(row).getTaskState()))
      {
        value = taskEntry.getScheduleTab();
      } else {
        value = taskEntry.getScheduledStartTime();
        if (value == null || value.equals(Message.EMPTY))
        {
          value = INFO_TASKINFO_IMMEDIATE_EXECUTION.get();
        }
      }
      break;
    case 5:
      value = taskEntry.getActualStartTime();
      break;
    case 6:
      value = taskEntry.getCompletionTime();
      break;
    case 7:
      value = getValue(taskEntry.getDependencyIds(),
          INFO_TASKINFO_NONE_SPECIFIED.get());
      break;
    case 8:
      value = taskEntry.getFailedDependencyAction();
      if (value == null)
      {
        value = INFO_TASKINFO_NONE.get();
      }
      break;
    case 9:
      value = getValue(taskEntry.getCompletionNotificationEmailAddresses(),
          INFO_TASKINFO_NONE_SPECIFIED.get());
      break;
    case 10:
      value = getValue(taskEntry.getErrorNotificationEmailAddresses(),
          INFO_TASKINFO_NONE_SPECIFIED.get());
      break;
    default:
      throw new IllegalArgumentException("Invalid column: "+column);
    }
    return value;
  }
  /**
   * Returns the row count.
   * @return the row count.
   */
  public int getRowCount()
  {
    return dataSourceArray.size();
  }
  /**
   * Returns the column count.
   * @return the column count.
   */
  public int getColumnCount()
  {
    return columnNames.length;
  }
  /**
   * Gets the TaskDescriptor in a given row.
   * @param row the row.
   * @return the TaskDescriptor in a given row.
   */
  public TaskEntry get(int row)
  {
    return dataSourceArray.get(row);
  }
  /**
   * Returns the set of attributes ordered.
   * @return the set of attributes ordered.
   */
  public LinkedHashSet<Message> getDisplayedAttributes()
  {
    return displayedAttributes;
  }
  /**
   * Returns the set of attributes ordered.
   * @return the set of attributes ordered.
   */
  public LinkedHashSet<Message> getAllAttributes()
  {
    return allAttributes;
  }
  /**
   * {@inheritDoc}
   */
  public int compare(TaskEntry desc1, TaskEntry desc2)
  {
    int result;
    ArrayList<Integer> possibleResults = new ArrayList<Integer>();
    possibleResults.add(desc1.getId().compareTo(desc2.getId()));
    possibleResults.add(desc1.getType().compareTo(desc2.getType()));
    possibleResults.add(desc1.getState().compareTo(desc2.getState()));
    possibleResults.add(String.valueOf(desc1.isCancelable()).compareTo(
        String.valueOf(desc2.isCancelable())));
    result = possibleResults.get(getSortColumn());
    if (result == 0)
    {
      for (int i : possibleResults)
      {
        if (i != 0)
        {
          result = i;
          break;
        }
      }
    }
    if (!isSortAscending())
    {
      result = -result;
    }
    return result;
  }
  /**
   * 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;
  }
  private int getFixedOrderColumn(int column)
  {
    int fixedOrderColumn = 0;
    int i=0;
    Message colMsg = null;
    for (Message msg : displayedAttributes)
    {
      if (i == column)
      {
        colMsg = msg;
        break;
      }
      i++;
    }
    for (Message msg : allAttributes)
    {
      if (msg.equals(colMsg))
      {
        break;
      }
      fixedOrderColumn++;
    }
    return fixedOrderColumn;
  }
  private Message getValue(List<String> values, Message valueIfEmpty)
  {
    Message msg;
    if (values.isEmpty())
    {
      msg = valueIfEmpty;
    }
    else
    {
      String s = Utils.getStringFromCollection(values, "<br>");
      if (values.size() > 1)
      {
        msg = Message.raw(
            "<html>"+Utilities.applyFont(s, ColorAndFontConstants.tableFont));
      }
      else
      {
        msg = Message.raw(s);
      }
    }
    return msg;
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/task/CancelTaskTask.java
New file
@@ -0,0 +1,261 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.task;
import static org.opends.messages.AdminToolMessages.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.SwingUtilities;
import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.ui.ColorAndFontConstants;
import org.opends.guitools.controlpanel.ui.ProgressDialog;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.server.tools.ManageTasks;
import org.opends.server.tools.tasks.TaskEntry;
import org.opends.server.util.cli.CommandBuilder;
/**
 * Task used to cancel tasks in server.
 *
 */
public class CancelTaskTask extends Task
{
  private Set<String> backendSet;
  private List<TaskEntry> tasks;
  /**
   * Constructor of the task.
   * @param info the control panel information.
   * @param dlg the progress dialog where the task progress will be displayed.
   * @param tasks the tasks to be canceled.
   */
  public CancelTaskTask(ControlPanelInfo info, ProgressDialog dlg,
      List<TaskEntry> tasks)
  {
    super(info, dlg);
    backendSet = new HashSet<String>();
    for (BackendDescriptor backend : info.getServerDescriptor().getBackends())
    {
      backendSet.add(backend.getBackendID());
    }
    this.tasks = new ArrayList<TaskEntry>(tasks);
  }
  /**
   * {@inheritDoc}
   */
  public Type getType()
  {
    // TODO: change this
    return Type.MODIFY_ENTRY;
  }
  /**
   * {@inheritDoc}
   */
  public Set<String> getBackends()
  {
    return backendSet;
  }
  /**
   * {@inheritDoc}
   */
  public Message getTaskDescription()
  {
    return INFO_CTRL_PANEL_CANCEL_TASK_DESCRIPTION.get();
  }
  /**
   * {@inheritDoc}
   */
  public boolean regenerateDescriptor()
  {
    return true;
  }
  /**
   * {@inheritDoc}
   */
  protected String getCommandLinePath()
  {
    return null;
  }
  /**
   * {@inheritDoc}
   */
  protected ArrayList<String> getCommandLineArguments()
  {
    return new ArrayList<String>();
  }
  /**
   * Returns the command-line arguments to be used to cancel the task.
   * @param task the task to be canceled.
   * @return the command-line arguments to be used to cancel the task.
   */
  private ArrayList<String> getCommandLineArguments(TaskEntry task)
  {
    ArrayList<String> args = new ArrayList<String>();
    args.add("--cancel");
    args.add(task.getId());
    args.addAll(getConnectionCommandLineArguments());
    args.add(getNoPropertiesFileArgument());
    return args;
  }
  /**
   * {@inheritDoc}
   */
  public boolean canLaunch(Task taskToBeLaunched,
      Collection<Message> incompatibilityReasons)
  {
    boolean canLaunch = true;
    if (!isServerRunning())
    {
      if (state == State.RUNNING)
      {
        // All the operations are incompatible if they apply to this
        // backend for safety.  This is a short operation so the limitation
        // has not a lot of impact.
        Set<String> backends =
          new TreeSet<String>(taskToBeLaunched.getBackends());
        backends.retainAll(getBackends());
        if (backends.size() > 0)
        {
          incompatibilityReasons.add(getIncompatibilityMessage(this,
              taskToBeLaunched));
          canLaunch = false;
        }
      }
    }
    return canLaunch;
  }
  /**
   * {@inheritDoc}
   */
  public void runTask()
  {
    state = State.RUNNING;
    lastException = null;
    try
    {
      final int totalNumber = tasks.size();
      int numberCanceled = 0;
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
        {
          getProgressDialog().getProgressBar().setIndeterminate(true);
        }
      });
      for (final TaskEntry task : tasks)
      {
        final ArrayList<String> arguments = getCommandLineArguments(task);
        final boolean isFirst = numberCanceled == 0;
        SwingUtilities.invokeLater(new Runnable()
        {
          public void run()
          {
            if (isFirst)
            {
              getProgressDialog().appendProgressHtml("<br><br>");
            }
            ArrayList<String> args = new ArrayList<String>();
            args.add(getCommandLinePath("manage-tasks"));
            args.addAll(getObfuscatedCommandLineArguments(arguments));
            StringBuilder sb = new StringBuilder();
            for (String arg : args)
            {
              sb.append(" "+CommandBuilder.escapeValue(arg));
            }
            getProgressDialog().appendProgressHtml(Utilities.applyFont(
                INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_CANCEL_TASK.get(task.getId())+
                "<br><b>"+sb.toString()+"</b><br><br>",
                ColorAndFontConstants.progressFont));
          }
        });
        String[] args = new String[arguments.size()];
        arguments.toArray(args);
        returnCode = ManageTasks.mainTaskInfo(args, System.in,
            outPrintStream, errorPrintStream);
        if (returnCode != 0)
        {
          break;
        }
        else
        {
          numberCanceled ++;
          final int fNumberCanceled = numberCanceled;
          SwingUtilities.invokeLater(new Runnable()
          {
            public void run()
            {
              if (fNumberCanceled == 1)
              {
                getProgressDialog().getProgressBar().setIndeterminate(false);
              }
              getProgressDialog().getProgressBar().setValue(
                  (fNumberCanceled * 100) / totalNumber);
            }
          });
        }
      }
      if (returnCode != 0)
      {
        state = State.FINISHED_WITH_ERROR;
      }
      else
      {
        state = State.FINISHED_SUCCESSFULLY;
      }
    }
    catch (Throwable t)
    {
      lastException = t;
      state = State.FINISHED_WITH_ERROR;
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/BackupPanel.java
@@ -60,9 +60,11 @@
import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
import org.opends.guitools.controlpanel.datamodel.BackupDescriptor;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.datamodel.ScheduleType;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.task.Task;
import org.opends.guitools.controlpanel.ui.components.ScheduleSummaryPanel;
import org.opends.guitools.controlpanel.util.BackgroundTask;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
@@ -100,6 +102,8 @@
  private boolean backupIDInitialized = false;
  private ScheduleSummaryPanel schedulePanel;
  private static final Logger LOG =
    Logger.getLogger(BackupPanel.class.getName());
@@ -251,20 +255,27 @@
        INFO_CTRL_PANEL_BACKUP_OPTIONS_LABEL.get());
    add(lBackupOptions, gbc);
    compressData = Utilities.createCheckBox(
        INFO_CTRL_PANEL_COMPRESS_DATA_LABEL.get());
    compressData.setSelected(false);
    schedulePanel = new ScheduleSummaryPanel(
        INFO_CTRL_PANEL_BACKUP_TASK_NAME.get().toString());
    schedulePanel.setSchedule(ScheduleType.createLaunchNow());
    gbc.insets.left = 10;
    gbc.gridx = 1;
    gbc.gridwidth = 2;
    add(schedulePanel, gbc);
    compressData = Utilities.createCheckBox(
        INFO_CTRL_PANEL_COMPRESS_DATA_LABEL.get());
    compressData.setSelected(false);
    gbc.gridy ++;
    gbc.insets.top = 5;
    add(compressData, gbc);
    encryptData = Utilities.createCheckBox(
        INFO_CTRL_PANEL_ENCRYPT_DATA_LABEL.get());
    gbc.gridy ++;
    gbc.insets.top = 5;
    add(encryptData, gbc);
    encryptData.setSelected(false);
    generateMessageDigest = Utilities.createCheckBox(
@@ -351,6 +362,7 @@
    setPrimaryValid(lPath);
    setPrimaryValid(lAvailableBackups);
    setPrimaryValid(lParentID);
    setPrimaryValid(lBackupOptions);
    backupIDInitialized = false;
    final LinkedHashSet<Message> errors = new LinkedHashSet<Message>();
@@ -434,6 +446,8 @@
      }
    }
    addScheduleErrors(getSchedule(), errors, lBackupOptions);
    // Check that there is not a backup with the provided ID
    final JComponent[] components =
    {
@@ -578,6 +592,11 @@
    }
  }
  private ScheduleType getSchedule()
  {
    return schedulePanel.getSchedule();
  }
  /**
   * {@inheritDoc}
   */
@@ -586,6 +605,7 @@
    setPrimaryValid(lBackend);
    setPrimaryValid(lPath);
    setPrimaryValid(lAvailableBackups);
    setPrimaryValid(lBackupOptions);
    super.cancelClicked();
  }
@@ -824,6 +844,8 @@
      args.addAll(getConnectionCommandLineArguments());
      args.addAll(getScheduleArgs(getSchedule()));
      if (isServerRunning())
      {
        args.addAll(getConfigCommandLineArguments());
opends/src/guitools/org/opends/guitools/controlpanel/ui/ConnectionHandlerMonitoringPanel.java
@@ -52,7 +52,6 @@
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
@@ -76,7 +75,8 @@
import org.opends.guitools.controlpanel.datamodel.ConnectionHandlerDescriptor.
 State;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.ui.renderer.CustomListCellRenderer;
import org.opends.guitools.controlpanel.ui.renderer.
 NoLeftInsetCategoryComboBoxRenderer;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.guitools.controlpanel.util.ViewPositions;
import org.opends.messages.Message;
@@ -193,7 +193,7 @@
      }
    });
    connectionHandlers.setRenderer(
        new CustomComboBoxCellRenderer(connectionHandlers));
        new NoLeftInsetCategoryComboBoxRenderer(connectionHandlers));
    gbc.gridx ++;
    viewOptions.add(connectionHandlers, gbc);
    gbc.gridx ++;
@@ -313,7 +313,7 @@
          });
    for (ConnectionHandlerDescriptor ch : chs)
    {
      if (ch.getProtocol() != ConnectionHandlerDescriptor.Protocol.LDIF)
      if (protocolHasMonitoring(ch))
      {
        sortedChs.add(ch);
      }
@@ -355,7 +355,7 @@
    {
      MessageBuilder mb = new MessageBuilder();
      mb.append(INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(
          server.getHostname()));
      server.getHostname()));
      mb.append("<br><br>"+getAuthenticateHTML());
      errorDetails = mb.toMessage();
      errorTitle = INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_SUMMARY.get();
@@ -555,7 +555,7 @@
        {
          for (ConnectionHandlerDescriptor ch : server.getConnectionHandlers())
          {
            if (ch.getProtocol() != Protocol.LDIF)
            if (protocolHasMonitoring(ch))
            {
              cchs.add(ch);
            }
@@ -588,6 +588,14 @@
    return cchs;
  }
  private boolean protocolHasMonitoring(ConnectionHandlerDescriptor ch)
  {
    return (ch.getProtocol() == Protocol.LDAP) ||
    (ch.getProtocol() == Protocol.LDAPS) ||
    (ch.getProtocol() == Protocol.LDAP_STARTTLS) ||
    (ch.getProtocol() == Protocol.OTHER);
  }
  /**
   * The specific menu bar of this panel.
   *
@@ -650,43 +658,5 @@
      return menu;
    }
  }
  /**
   *  This class is used simply to avoid an inset on the left for the
   *  elements of the combo box.
   *  Since this item is a CategorizedComboBoxElement of type
   *  CategorizedComboBoxElement.Type.REGULAR, it has by default an inset on
   *  the left.
   */
  class CustomComboBoxCellRenderer extends CustomListCellRenderer
  {
    /**
     * The constructor.
     * @param combo the combo box to be rendered.
     */
    CustomComboBoxCellRenderer(JComboBox combo)
    {
      super(combo);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Component getListCellRendererComponent(JList list, Object value,
        int index, boolean isSelected, boolean cellHasFocus)
    {
      Component comp = super.getListCellRendererComponent(list, value, index,
          isSelected, cellHasFocus);
      if (value instanceof CategorizedComboBoxElement)
      {
        CategorizedComboBoxElement element = (CategorizedComboBoxElement)value;
        String name = getStringValue(element);
        ((JLabel)comp).setText(name);
      }
      comp.setFont(defaultFont);
      return comp;
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/ExportLDIFPanel.java
@@ -54,10 +54,12 @@
import javax.swing.event.DocumentListener;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.datamodel.ScheduleType;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.event.BrowseActionListener;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.task.Task;
import org.opends.guitools.controlpanel.ui.components.ScheduleSummaryPanel;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.server.tools.ExportLDIF;
@@ -89,6 +91,8 @@
  private DocumentListener documentListener;
  private ScheduleSummaryPanel schedulePanel;
  /**
   * Default constructor.
   *
@@ -238,13 +242,21 @@
      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_EXPORT_OPTIONS.get());
    add(lExportOptions, gbc);
    compressData = Utilities.createCheckBox(
        INFO_CTRL_PANEL_COMPRESS_DATA_LABEL.get());
    compressData.setSelected(false);
    schedulePanel = new ScheduleSummaryPanel(
        INFO_CTRL_PANEL_EXPORT_LDIF_TITLE.get().toString());
    schedulePanel.setSchedule(ScheduleType.createLaunchNow());
    gbc.insets.left = 10;
    gbc.gridx = 1;
    gbc.gridwidth = 3;
    add(schedulePanel, gbc);
    compressData = Utilities.createCheckBox(
        INFO_CTRL_PANEL_COMPRESS_DATA_LABEL.get());
    compressData.setSelected(false);
    gbc.gridy ++;
    gbc.insets.top = 5;
    add(compressData, gbc);
    encryptData = Utilities.createCheckBox(
@@ -384,6 +396,7 @@
      }
    }
    addScheduleErrors(getSchedule(), errors, lExportOptions);
    if (wrapText.isSelected())
    {
      String cols = wrapColumn.getText();
@@ -391,7 +404,12 @@
      int maxValue = 1000;
      Message errMsg = ERR_CTRL_PANEL_INVALID_WRAP_COLUMN.get(minValue,
      maxValue);
      int size1 = errors.size();
      checkIntValue(errors, cols, minValue, maxValue, errMsg);
      if (errors.size() > size1)
      {
        setPrimaryInvalid(lExportOptions);
      }
    }
    updateIncludeExclude(errors, backendName);
@@ -448,6 +466,11 @@
    super.cancelClicked();
  }
  private ScheduleType getSchedule()
  {
    return schedulePanel.getSchedule();
  }
  /**
   * The class that performs the export.
   *
@@ -589,6 +612,8 @@
      args.addAll(super.getCommandLineArguments());
      args.addAll(getScheduleArgs(getSchedule()));
      if (isServerRunning())
      {
        args.addAll(getConfigCommandLineArguments());
opends/src/guitools/org/opends/guitools/controlpanel/ui/MainActionsPane.java
@@ -217,7 +217,8 @@
          {
            INFO_CTRL_PANEL_CATEGORY_MONITORING.get(),
            INFO_CTRL_PANEL_BROWSE_GENERAL_MONITORING.get(),
            INFO_CTRL_PANEL_CONNECTION_HANDLER_MONITORING.get()
            INFO_CTRL_PANEL_CONNECTION_HANDLER_MONITORING.get(),
            INFO_CTRL_PANEL_MANAGE_TASKS.get()
          },
          {
            INFO_CTRL_PANEL_CATEGORY_RUNTIME_OPTIONS.get(),
@@ -251,7 +252,8 @@
          {
            INFO_CTRL_PANEL_CATEGORY_MONITORING.get(),
            INFO_CTRL_PANEL_BROWSE_GENERAL_MONITORING.get(),
            INFO_CTRL_PANEL_CONNECTION_HANDLER_MONITORING.get()
            INFO_CTRL_PANEL_CONNECTION_HANDLER_MONITORING.get(),
            INFO_CTRL_PANEL_MANAGE_TASKS.get()
          },
          {
            INFO_CTRL_PANEL_CATEGORY_RUNTIME_OPTIONS.get(),
@@ -273,6 +275,7 @@
    classes.add(RebuildIndexPanel.class);
    classes.add(BrowseGeneralMonitoringPanel.class);
    classes.add(ConnectionHandlerMonitoringPanel.class);
    classes.add(ManageTasksPanel.class);
    classes.add(JavaPropertiesPanel.class);
    if (Utilities.isWindows())
    {
opends/src/guitools/org/opends/guitools/controlpanel/ui/ManageTasksPanel.java
New file
@@ -0,0 +1,939 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.ui;
import static org.opends.messages.AdminToolMessages.*;
import static org.opends.server.util.StaticUtils.toLowerCase;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.datamodel.TaskTableModel;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.task.CancelTaskTask;
import org.opends.guitools.controlpanel.task.Task;
import org.opends.guitools.controlpanel.ui.renderer.TaskCellRenderer;
import org.opends.guitools.controlpanel.util.ConfigFromFile;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.quicksetup.util.Utils;
import org.opends.server.core.DirectoryServer;
import org.opends.server.tools.tasks.TaskEntry;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeBuilder;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.AttributeValues;
import org.opends.server.types.ByteString;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.OpenDsException;
/**
 * The panel displaying the list of scheduled tasks.
 *
 */
public class ManageTasksPanel extends StatusGenericPanel
{
  private static final long serialVersionUID = -8034784684412532193L;
  private JLabel lNoTasksFound;
  /**
   * Remove task button.
   */
  private JButton cancelTask;
  /**
   * The scroll that contains the list of tasks (actually is a table).
   */
  private JScrollPane tableScroll;
  /**
   * The table of tasks.
   */
  private JTable taskTable;
  /**
   * The model of the table.
   */
  private TaskTableModel tableModel;
  private ManageTasksMenuBar menuBar;
  private MonitoringAttributesViewPanel<Message> operationViewPanel;
  private GenericDialog operationViewDlg;
  private JPanel detailsPanel;
  private JLabel noDetailsLabel;
  // The panel containing all the labels and values of the details.
  private JPanel detailsSubpanel;
  private static final Logger LOG =
    Logger.getLogger(ManageTasksPanel.class.getName());
  /**
   * Default constructor.
   *
   */
  public ManageTasksPanel()
  {
    super();
    createLayout();
  }
  /**
   * {@inheritDoc}
   */
  public Message getTitle()
  {
    return INFO_CTRL_PANEL_TASK_TO_SCHEDULE_LIST_TITLE.get();
  }
  /**
   * {@inheritDoc}
   */
  public boolean requiresScroll()
  {
    return false;
  }
  /**
   * {@inheritDoc}
   */
  public GenericDialog.ButtonType getButtonType()
  {
    return GenericDialog.ButtonType.CLOSE;
  }
  /**
   * {@inheritDoc}
   */
  public void okClicked()
  {
    // Nothing to do, it only contains a close button.
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public JMenuBar getMenuBar()
  {
    if (menuBar == null)
    {
      menuBar = new ManageTasksMenuBar(getInfo());
    }
    return menuBar;
  }
  /**
   * {@inheritDoc}
   */
  public Component getPreferredFocusComponent()
  {
    return taskTable;
  }
  /**
   * Returns the selected cancelable tasks in the list.
   * @param onlyCancelable add only the cancelable tasks.
   * @return the selected cancelable tasks in the list.
   */
  private List<TaskEntry> getSelectedTasks(boolean onlyCancelable)
  {
    ArrayList<TaskEntry> tasks = new ArrayList<TaskEntry>();
    int[] rows = taskTable.getSelectedRows();
    for (int row : rows)
    {
      if (row != -1)
      {
        TaskEntry task = tableModel.get(row);
        if (!onlyCancelable || task.isCancelable())
        {
          tasks.add(task);
        }
      }
    }
    return tasks;
  }
  /**
   * Creates the components and lays them in the panel.
   * @param gbc the grid bag constraints to be used.
   */
  private void createLayout()
  {
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.anchor = GridBagConstraints.WEST;
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.gridwidth = 2;
    addErrorPane(gbc);
    gbc.weightx = 0.0;
    gbc.gridy ++;
    gbc.anchor = GridBagConstraints.WEST;
    gbc.weightx = 0.0;
    gbc.fill = GridBagConstraints.NONE;
    gbc.gridwidth = 2;
    gbc.insets.left = 0;
    gbc.gridx = 0;
    gbc.gridy = 0;
    lNoTasksFound = Utilities.createDefaultLabel(
        INFO_CTRL_PANEL_NO_TASKS_FOUND.get());
    gbc.gridy ++;
    gbc.anchor = GridBagConstraints.CENTER;
    gbc.gridheight = 2;
    add(lNoTasksFound, gbc);
    lNoTasksFound.setVisible(false);
    gbc.gridwidth = 1;
    gbc.weightx = 1.0;
    gbc.weighty = 1.0;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.insets.top = 10;
    gbc.anchor = GridBagConstraints.NORTHWEST;
    // Done to provide a good size to the table.
    tableModel = new TaskTableModel();
    tableModel.setData(createDummyTaskList());
    taskTable =
      Utilities.createSortableTable(tableModel, new TaskCellRenderer());
    taskTable.getSelectionModel().setSelectionMode(
        ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    tableScroll = Utilities.createScrollPane(taskTable);
    gbc.anchor = GridBagConstraints.NORTHWEST;
    add(tableScroll, gbc);
    updateTableSizes();
    gbc.gridx = 1;
    gbc.gridheight = 1;
    gbc.anchor = GridBagConstraints.EAST;
    gbc.fill = GridBagConstraints.NONE;
    gbc.weightx = 0.0;
    gbc.weighty = 0.0;
    cancelTask = Utilities.createButton(
        INFO_CTRL_PANEL_CANCEL_TASK_BUTTON_LABEL.get());
    cancelTask.setOpaque(false);
    gbc.insets.left = 10;
    add(cancelTask, gbc);
    gbc.gridy ++;
    gbc.weighty = 1.0;
    gbc.fill = GridBagConstraints.VERTICAL;
    add(Box.createVerticalGlue(), gbc);
    cancelTask.addActionListener(new ActionListener()
    {
      /**
       * {@inheritDoc}
       */
      public void actionPerformed(ActionEvent ev)
      {
        cancelTaskClicked();
      }
    });
    gbc.gridy ++;
    gbc.gridx = 0;
    gbc.gridwidth = 2;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.weightx = 1.0;
    gbc.weighty = 0.7;
    gbc.insets.left = 0;
    createDetailsPanel();
    add(detailsPanel, gbc);
    ListSelectionListener listener = new ListSelectionListener()
    {
      /**
       * {@inheritDoc}
       */
      public void valueChanged(ListSelectionEvent ev)
      {
        tableSelected();
      }
    };
    taskTable.getSelectionModel().addListSelectionListener(listener);
    listener.valueChanged(null);
  }
  /**
   * Creates the details panel.
   *
   */
  private void createDetailsPanel()
  {
    detailsPanel = new JPanel(new GridBagLayout());
    detailsPanel.setOpaque(false);
    detailsPanel.setBorder(Utilities.makeTitledBorder(
        INFO_CTRL_PANEL_TASK_SPECIFIC_DETAILS.get()));
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = 1;
    gbc.gridy = 1;
    gbc.anchor = GridBagConstraints.CENTER;
    gbc.fill = GridBagConstraints.NONE;
    gbc.weightx = 1.0;
    gbc.weighty = 1.0;
    noDetailsLabel =
      Utilities.createDefaultLabel(INFO_CTRL_PANEL_NO_TASK_SELECTED.get());
    gbc.gridwidth = 2;
    detailsPanel.add(noDetailsLabel, gbc);
    detailsSubpanel = new JPanel(new GridBagLayout());
    detailsSubpanel.setOpaque(false);
    gbc.anchor = GridBagConstraints.NORTHWEST;
    gbc.fill = GridBagConstraints.BOTH;
    detailsPanel.add(Utilities.createBorderLessScrollBar(detailsSubpanel), gbc);
  }
  /**
   * Method called when the table is selected.
   *
   */
  private void tableSelected()
  {
    List<TaskEntry> tasks = getSelectedTasks(true);
    cancelTask.setEnabled(!tasks.isEmpty());
    detailsSubpanel.removeAll();
    tasks = getSelectedTasks(false);
    boolean displayContents = false;
    if (tasks.isEmpty())
    {
      noDetailsLabel.setText(INFO_CTRL_PANEL_NO_TASK_SELECTED.get().toString());
    }
    else if (tasks.size() > 1)
    {
      noDetailsLabel.setText(
          INFO_CTRL_PANEL_MULTIPLE_TASKS_SELECTED.get().toString());
    }
    else
    {
      TaskEntry taskEntry = tasks.iterator().next();
      Map<Message,List<String>> taskSpecificAttrs =
        taskEntry.getTaskSpecificAttributeValuePairs();
      if (taskSpecificAttrs.isEmpty())
      {
        noDetailsLabel.setText(
            INFO_CTRL_PANEL_NO_TASK_SPECIFIC_DETAILS.get().toString());
      }
      else
      {
        displayContents = true;
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridy = 1;
        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.NORTHWEST;
        gbc.insets.top = 10;
        for (Message label : taskSpecificAttrs.keySet())
        {
          List<String> values = taskSpecificAttrs.get(label);
          gbc.gridx = 0;
          gbc.insets.left = 10;
          gbc.insets.right = 0;
          detailsSubpanel.add(Utilities.createPrimaryLabel(
              INFO_CTRL_PANEL_OPERATION_NAME_AS_LABEL.get(label.toString())),
              gbc);
          gbc.gridx = 1;
          gbc.insets.right = 10;
          Message msg;
          String s = Utils.getStringFromCollection(values, "<br>");
          if (values.size() > 1)
          {
            msg = Message.raw(
                "<html>"+Utilities.applyFont(s,
                    ColorAndFontConstants.defaultFont));
          }
          else
          {
            msg = Message.raw(s);
          }
          detailsSubpanel.add(Utilities.createDefaultLabel(msg), gbc);
          gbc.gridy ++;
        }
        gbc.gridx = 0;
        gbc.insets = new Insets(0, 0, 0, 0);
        detailsSubpanel.add(Box.createVerticalStrut(10), gbc);
        gbc.gridx = 1;
        gbc.weightx = 1.0;
        gbc.weighty = 1.0;
        gbc.fill = GridBagConstraints.BOTH;
        detailsSubpanel.add(Box.createGlue(), gbc);
      }
    }
    noDetailsLabel.setVisible(!displayContents);
    revalidate();
    repaint();
  }
  /**
   * Creates a list with task descriptors.  This is done simply to have a good
   * initial size for the table.
   * @return a list with bogus task descriptors.
   */
  private Set<TaskEntry> createRandomTasksList()
  {
    Set<TaskEntry> list = new HashSet<TaskEntry>();
    Random r = new Random();
    int numberTasks = r.nextInt(10);
    for (int i= 0; i<numberTasks; i++)
    {
      CustomSearchResult csr =
        new CustomSearchResult("cn=mytask"+i+",cn=tasks");
      String p = "ds-task-";
      String[] attrNames =
      {
          p + "id",
          p + "class-name",
          p + "state",
          p + "scheduled-start-time",
          p + "actual-start-time",
          p + "completion-time",
          p + "dependency-id",
          p + "failed-dependency-action",
          p + "log-message",
          p + "notify-on-error",
          p + "notify-on-completion",
          p + "ds-recurring-task-schedule"
      };
      String[] values =
      {
          "ID",
          "TheClassName",
          "TheState",
          "Schedule Start Time",
          "Actual Start Time",
          "Completion Time",
          "Dependency ID",
          "Failed Dependency Action",
          "Log Message.                              Should be pretty long"+
          "Log Message.                              Should be pretty long"+
          "Log Message.                              Should be pretty long"+
          "Log Message.                              Should be pretty long"+
          "Log Message.                              Should be pretty long",
          "Notify On Error",
          "Notify On Completion",
          "Recurring Task Schedule"
      };
      for (int j=0; j < attrNames.length; j++)
      {
        Set<Object> attrValues = new HashSet<Object>(1);
        attrValues.add(values[j] + r.nextInt());
        csr.set(attrNames[j], attrValues);
      }
      try
      {
        Entry entry = getEntry(csr);
        TaskEntry task = new TaskEntry(entry);
        list.add(task);
      }
      catch (Throwable t)
      {
        LOG.log(Level.SEVERE, "Error getting entry '"+csr.getDN()+"': "+t, t);
      }
    }
    return list;
  }
  /**
   * Creates a list with task descriptors.  This is done simply to have a good
   * initial size for the table.
   * @return a list with bogus task descriptors.
   */
  private Set<TaskEntry> createDummyTaskList()
  {
    Set<TaskEntry> list = new HashSet<TaskEntry>();
    for (int i= 0; i<10; i++)
    {
      CustomSearchResult csr =
        new CustomSearchResult("cn=mytask"+i+",cn=tasks");
      String p = "ds-task-";
      String[] attrNames =
      {
          p + "id",
          p + "class-name",
          p + "state",
          p + "scheduled-start-time",
          p + "actual-start-time",
          p + "completion-time",
          p + "dependency-id",
          p + "failed-dependency-action",
          p + "log-message",
          p + "notify-on-error",
          p + "notify-on-completion",
          p + "ds-recurring-task-schedule"
      };
      String[] values =
      {
          "A very 29-backup - Sun Mar 29 00:00:00 MET 2009",
          "A long task type",
          "A very long task status",
          "Schedule Start Time",
          "Actual Start Time",
          "Completion Time",
          "Dependency ID",
          "Failed Dependency Action",
          "Log Message.                              Should be pretty long\n"+
          "Log Message.                              Should be pretty long\n"+
          "Log Message.                              Should be pretty long\n"+
          "Log Message.                              Should be pretty long\n"+
          "Log Message.                              Should be pretty long\n",
          "Notify On Error",
          "Notify On Completion",
          "Recurring Task Schedule"
      };
      for (int j=0; j < attrNames.length; j++)
      {
        Set<Object> attrValues = new HashSet<Object>(1);
        attrValues.add(values[j]);
        csr.set(attrNames[j], attrValues);
      }
      try
      {
        Entry entry = getEntry(csr);
        TaskEntry task = new TaskEntry(entry);
        list.add(task);
      }
      catch (Throwable t)
      {
        LOG.log(Level.SEVERE, "Error getting entry '"+csr.getDN()+"': "+t, t);
      }
    }
    return list;
  }
  private void cancelTaskClicked()
  {
    ArrayList<Message> errors = new ArrayList<Message>();
    ProgressDialog dlg = new ProgressDialog(
        Utilities.getParentDialog(this),
        INFO_CTRL_PANEL_CANCEL_TASK_TITLE.get(), getInfo());
    List<TaskEntry> tasks = getSelectedTasks(true);
    CancelTaskTask newTask = new CancelTaskTask(getInfo(), dlg, tasks);
    for (Task task : getInfo().getTasks())
    {
      task.canLaunch(newTask, errors);
    }
    if (errors.size() == 0)
    {
      boolean confirmed = displayConfirmationDialog(
          INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
          INFO_CTRL_PANEL_CANCEL_TASK_MSG.get());
      if (confirmed)
      {
        launchOperation(newTask,
            INFO_CTRL_PANEL_CANCELING_TASK_SUMMARY.get(),
            INFO_CTRL_PANEL_CANCELING_TASK_COMPLETE.get(),
            INFO_CTRL_PANEL_CANCELING_TASK_SUCCESSFUL.get(),
            ERR_CTRL_PANEL_CANCELING_TASK_ERROR_SUMMARY.get(),
            ERR_CTRL_PANEL_CANCELING_TASK_ERROR_DETAILS.get(),
            null,
            dlg);
        dlg.setVisible(true);
      }
    }
  }
  /**
   * Gets the Entry object equivalent to the provided CustomSearchResult.
   * The method assumes that the schema in DirectoryServer has been initialized.
   * @param csr the search result.
   * @return the Entry object equivalent to the provided CustomSearchResult.
   * @throws OpenDsException if there is an error parsing the DN or retrieving
   * the attributes definition and objectclasses in the schema of the server.
   * TODO: move somewhere better.
   */
  public static Entry getEntry(CustomSearchResult csr) throws OpenDsException
  {
    DN dn = DN.decode(csr.getDN());
    Map<ObjectClass,String> objectClasses = new HashMap<ObjectClass,String>();
    Map<AttributeType,List<Attribute>> userAttributes =
      new HashMap<AttributeType,List<Attribute>>();
    Map<AttributeType,List<Attribute>> operationalAttributes =
      new HashMap<AttributeType,List<Attribute>>();
    for (String wholeName : csr.getAttributeNames())
    {
      final Attribute attribute = parseAttrDescription(wholeName);
      final String attrName = attribute.getName();
      final String lowerName = toLowerCase(attrName);
      // See if this is an objectclass or an attribute.  Then get the
      // corresponding definition and add the value to the appropriate hash.
      if (lowerName.equals("objectclass"))
      {
        for (Object value : csr.getAttributeValues(attrName))
        {
          String ocName = value.toString().trim();
          String lowerOCName = toLowerCase(ocName);
          ObjectClass objectClass =
            DirectoryServer.getObjectClass(lowerOCName);
          if (objectClass == null)
          {
            objectClass = DirectoryServer.getDefaultObjectClass(ocName);
          }
          objectClasses.put(objectClass, ocName);
        }
      }
      else
      {
        AttributeType attrType = DirectoryServer.getAttributeType(lowerName);
        if (attrType == null)
        {
          attrType = DirectoryServer.getDefaultAttributeType(attrName);
        }
        AttributeBuilder builder = new AttributeBuilder(attribute, true);
        for (Object value : csr.getAttributeValues(attrName))
        {
          ByteString bs;
          if (value instanceof byte[])
          {
            bs = ByteString.wrap((byte[])value);
          }
          else
          {
            bs = ByteString.valueOf(value.toString());
          }
          AttributeValue attributeValue =
            AttributeValues.create(attrType, bs);
          builder.add(attributeValue);
        }
        List<Attribute> attrList = new ArrayList<Attribute>(1);
        attrList.add(builder.toAttribute());
        if (attrType.isOperational())
        {
          operationalAttributes.put(attrType, attrList);
        }
        else
        {
          userAttributes.put(attrType, attrList);
        }
      }
    }
    return new Entry(dn, objectClasses, userAttributes, operationalAttributes);
  }
  /**
   * Parse an AttributeDescription (an attribute type name and its
   * options).
   * TODO: make this method in LDIFReader public.
   *
   * @param attrDescr
   *          The attribute description to be parsed.
   * @return A new attribute with no values, representing the
   *         attribute type and its options.
   */
  private static Attribute parseAttrDescription(String attrDescr)
  {
    AttributeBuilder builder;
    int semicolonPos = attrDescr.indexOf(';');
    if (semicolonPos > 0)
    {
      builder = new AttributeBuilder(attrDescr.substring(0, semicolonPos));
      int nextPos = attrDescr.indexOf(';', semicolonPos + 1);
      while (nextPos > 0)
      {
        String option = attrDescr.substring(semicolonPos + 1, nextPos);
        if (option.length() > 0)
        {
          builder.setOption(option);
          semicolonPos = nextPos;
          nextPos = attrDescr.indexOf(';', semicolonPos + 1);
        }
      }
      String option = attrDescr.substring(semicolonPos + 1);
      if (option.length() > 0)
      {
        builder.setOption(option);
      }
    }
    else
    {
      builder = new AttributeBuilder(attrDescr);
    }
    if(builder.getAttributeType().isBinary())
    {
      //resetting doesn't hurt and returns false.
      builder.setOption("binary");
    }
    return builder.toAttribute();
  }
  /**
   * The main method to test this panel.
   * @param args the arguments.
   */
  public static void main(String[] args)
  {
    // This is a hack to initialize configuration
    new ConfigFromFile();
    final ManageTasksPanel p = new ManageTasksPanel();
    Thread t = new Thread(new Runnable()
    {
      public void run()
      {
        try
        {
          // To let the dialog to be displayed
          Thread.sleep(5000);
        }
        catch (Throwable t)
        {
          t.printStackTrace();
        }
        while (p.isVisible())
        {
          try
          {
            SwingUtilities.invokeLater(new Runnable(){
              public void run()
              {
                Set<TaskEntry> tasks = p.createRandomTasksList();
                p.tableModel.setData(tasks);
                boolean visible = p.tableModel.getRowCount() > 0;
                if (visible)
                {
                  p.updateTableSizes();
                }
                p.tableModel.fireTableDataChanged();
                p.lNoTasksFound.setVisible(!visible);
                p.tableScroll.setVisible(visible);
                p.cancelTask.setVisible(visible);
              }
            });
            Thread.sleep(5000);
          }
          catch (Exception ex)
          {
            ex.printStackTrace();
          }
        }
      }
    });
    t.start();
    SwingUtilities.invokeLater(new Runnable(){
      public void run()
      {
        GenericDialog dlg = new GenericDialog(new JFrame(), p);
        dlg.setModal(true);
        dlg.pack();
        dlg.setVisible(true);
      }
    });
    t = null;
  }
  /**
   * Displays a dialog allowing the user to select which operations to display.
   *
   */
  private void operationViewClicked()
  {
    if (operationViewDlg == null)
    {
      operationViewPanel = MonitoringAttributesViewPanel.createMessageInstance(
          tableModel.getAllAttributes());
      operationViewDlg = new GenericDialog(Utilities.getFrame(this),
          operationViewPanel);
      Utilities.centerGoldenMean(operationViewDlg,
          Utilities.getParentDialog(this));
      operationViewDlg.setModal(true);
    }
    operationViewPanel.setSelectedAttributes(
        tableModel.getDisplayedAttributes());
    operationViewDlg.setVisible(true);
    if (!operationViewPanel.isCancelled())
    {
      LinkedHashSet<Message> displayedAttributes =
        operationViewPanel.getAttributes();
      setAttributesToDisplay(displayedAttributes);
      updateTableSizes();
    }
  }
  /**
   * {@inheritDoc}
   */
  public void configurationChanged(ConfigurationChangeEvent ev)
  {
    updateErrorPaneIfServerRunningAndAuthRequired(ev.getNewDescriptor(),
        INFO_CTRL_PANEL_SCHEDULED_TASK_LIST_REQUIRES_SERVER_RUNNING.get(),
        INFO_CTRL_PANEL_SCHEDULED_TASK_LIST_AUTHENTICATION.get());
    ServerDescriptor server = ev.getNewDescriptor();
    final Set<TaskEntry> tasks = server.getTaskEntries();
    boolean changed = tableModel.getRowCount() != tasks.size();
    if (!changed)
    {
      for (int i=0; i<tableModel.getRowCount(); i++)
      {
        if (!tasks.contains(tableModel.get(i)))
        {
          changed = true;
          break;
        }
      }
    }
    if (changed)
    {
      SwingUtilities.invokeLater(new Runnable()
      {
        /**
         * {@inheritDoc}
         */
        public void run()
        {
          tableModel.setData(tasks);
          boolean visible = tableModel.getRowCount() > 0;
          if (visible)
          {
            updateTableSizes();
          }
          tableModel.fireTableDataChanged();
          lNoTasksFound.setVisible(!visible &&
              !errorPane.isVisible());
          tableScroll.setVisible(visible);
          cancelTask.setVisible(visible);
        }
      });
    }
  }
  private void updateTableSizes()
  {
    Utilities.updateTableSizes(taskTable, 8);
    Utilities.updateScrollMode(tableScroll, taskTable);
  }
  private void setAttributesToDisplay(LinkedHashSet<Message> attributes)
  {
    tableModel.setAttributes(attributes);
    tableModel.forceDataStructureChange();
  }
  /**
   * The specific menu bar of this panel.
   *
   */
  class ManageTasksMenuBar extends MainMenuBar
  {
    private static final long serialVersionUID = 5051878116443370L;
    /**
     * structor.
     * @param info the control panel info.
     */
    public ManageTasksMenuBar(ControlPanelInfo info)
    {
      super(info);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected void addMenus()
    {
      add(createViewMenuBar());
      add(createHelpMenuBar());
    }
    /**
     * Creates the view menu bar.
     * @return the view menu bar.
     */
    @Override
    protected JMenu createViewMenuBar()
    {
      JMenu menu = Utilities.createMenu(
          INFO_CTRL_PANEL_CONNECTION_HANDLER_VIEW_MENU.get(),
          INFO_CTRL_PANEL_CONNECTION_HANDLER_VIEW_MENU_DESCRIPTION.get());
      menu.setMnemonic(KeyEvent.VK_V);
      final JMenuItem viewOperations = Utilities.createMenuItem(
          INFO_CTRL_PANEL_OPERATIONS_VIEW.get());
      menu.add(viewOperations);
      viewOperations.addActionListener(new ActionListener()
      {
        public void actionPerformed(ActionEvent ev)
        {
          operationViewClicked();
        }
      });
      return menu;
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/MonitoringAttributesViewPanel.java
@@ -91,7 +91,8 @@
  * Creates an instance of this panel that uses MonitoringAttributes as
  * attributes.
  * @param attributes the list of possible attributes.
  * @return an instance of this panel that uses String as attributes.
  * @return an instance of this panel that uses MonitoringAttributes as
  * attributes.
  */
 public static MonitoringAttributesViewPanel<MonitoringAttributes>
 createMonitoringAttributesInstance(
@@ -101,6 +102,18 @@
 }
 /**
  * Creates an instance of this panel that uses Message as
  * attributes.
  * @param attributes the list of possible attributes.
  * @return an instance of this panel that uses Message as attributes.
  */
 public static MonitoringAttributesViewPanel<Message>
 createMessageInstance(LinkedHashSet<Message> attributes)
 {
   return new MonitoringAttributesViewPanel<Message>(attributes);
 }
 /**
  * {@inheritDoc}
  */
 @Override
@@ -354,6 +367,10 @@
   {
     m = ((MonitoringAttributes)operation).getMessage();
   }
   else if (operation instanceof Message)
   {
     m = (Message)operation;
   }
   else
   {
     m = Message.raw(operation.toString());
opends/src/guitools/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java
@@ -42,8 +42,11 @@
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
@@ -77,6 +80,7 @@
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
import org.opends.guitools.controlpanel.datamodel.MonitoringAttributes;
import org.opends.guitools.controlpanel.datamodel.ScheduleType;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.event.*;
import org.opends.guitools.controlpanel.task.RebuildIndexTask;
@@ -147,6 +151,9 @@
  private boolean sizeSet = false;
  private boolean focusSet = false;
  private static DateFormat taskDateFormat =
    new SimpleDateFormat("yyyyMMddHHmmss");
  /**
   * Returns the title that will be used as title of the dialog.
   * @return the title that will be used as title of the dialog.
@@ -2183,4 +2190,58 @@
    return INFO_CTRL_PANEL_OPERATION_NAME_AS_LABEL.get(
        attr.getMessage().toString());
  }
  /**
   * Returns the command-line arguments associated with the provided schedule.
   * @param schedule the schedule.
   * @return the command-line arguments associated with the provided schedule.
   */
  protected List<String> getScheduleArgs(ScheduleType schedule)
  {
    List<String> args = new ArrayList<String>(2);
    switch (schedule.getType())
    {
    case LAUNCH_LATER:
      args.add("--start");
      args.add(getStartTimeForTask(schedule.getLaunchLaterDate()));
      break;
    case LAUNCH_PERIODICALLY:
      args.add("--recurringTask");
      args.add(schedule.getCronValue());
      break;
    }
    return args;
  }
  /**
   * Checks whether the server is running or not and depending on the schedule
   * updates the list of errors with the errors found.
   * @param schedule the schedule.
   * @param errors the list of errors.
   * @param label the label to be marked as invalid if errors where encountered.
   */
  protected void addScheduleErrors(ScheduleType schedule,
      Collection<Message> errors, JLabel label)
  {
    if (!isServerRunning())
    {
      ScheduleType.Type type = schedule.getType();
      if (type == ScheduleType.Type.LAUNCH_LATER)
      {
        errors.add(ERR_CTRL_PANEL_LAUNCH_LATER_REQUIRES_SERVER_RUNNING.get());
        setPrimaryInvalid(label);
      }
      else if (type == ScheduleType.Type.LAUNCH_PERIODICALLY)
      {
        errors.add(
            ERR_CTRL_PANEL_LAUNCH_SCHEDULE_REQUIRES_SERVER_RUNNING.get());
        setPrimaryInvalid(label);
      }
    }
  }
  private String getStartTimeForTask(Date date)
  {
    return taskDateFormat.format(date);
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/TaskToSchedulePanel.java
New file
@@ -0,0 +1,1178 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.ui;
import static org.opends.messages.AdminToolMessages.*;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.swing.Box;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.text.PlainDocument;
import org.opends.guitools.controlpanel.datamodel.CategorizedComboBoxElement;
import org.opends.guitools.controlpanel.datamodel.ScheduleType;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.ui.components.
 NumericLimitedSizeDocumentFilter;
import org.opends.guitools.controlpanel.ui.components.TimeDocumentFilter;
import org.opends.guitools.controlpanel.ui.renderer.
 NoLeftInsetCategoryComboBoxRenderer;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.server.backends.task.RecurringTask;
/**
 * The panel that allows the user to specify when a task will be launched.
 *
 */
public class TaskToSchedulePanel extends StatusGenericPanel
{
  private static final long serialVersionUID = 6855081932432566784L;
  private String taskName;
  private JComboBox scheduleType;
  private JTextField time;
  private JTextField day;
  private JComboBox month;
  private JComboBox year;
  private JLabel lTime;
  private JLabel lDay;
  private JLabel lMonth;
  private JLabel lYear;
  private JLabel lDailyTime;
  private JTextField dailyTime;
  private JLabel lWeeklyTime;
  private JLabel lWeeklyDays;
  private JTextField weeklyTime;
  private JCheckBox sunday, monday, tuesday, wednesday, thursday, friday,
  saturday;
  {
    sunday =
      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_SUNDAY.get());
    monday =
      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_MONDAY.get());
    tuesday =
      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TUESDAY.get());
    wednesday =
      Utilities.createCheckBox(
          INFO_CTRL_PANEL_TASK_TO_SCHEDULE_WEDNESDAY.get());
    thursday =
      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_THURSDAY.get());
    friday =
      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_FRIDAY.get());
    saturday =
      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_SATURDAY.get());
  }
  JCheckBox[] weekDays =
  {
      sunday, monday, tuesday, wednesday, thursday, friday, saturday
  };
  private JLabel lMonthlyTime;
  private JLabel lMonthlyDays;
  private JTextField monthlyTime;
  private JCheckBox[] monthDays = new JCheckBox[31];
  private JLabel lCronMinute;
  private JLabel lCronHour;
  private JLabel lCronWeekDay;
  private JLabel lCronMonthDay;
  private JLabel lCronMonth;
  private JTextField cronMinute;
  private JTextField cronHour;
  private JTextField cronWeekDay;
  private JTextField cronMonthDay;
  private JTextField cronMonth;
  private Component launchLaterPanel;
  private Component dailyPanel;
  private Component weeklyPanel;
  private Component monthlyPanel;
  private Component cronPanel;
  private Message LAUNCH_NOW = INFO_CTRL_PANEL_LAUNCH_NOW.get();
  private Message LAUNCH_LATER = INFO_CTRL_PANEL_LAUNCH_LATER.get();
  private Message LAUNCH_DAILY = INFO_CTRL_PANEL_TASK_TO_SCHEDULE_DAILY.get();
  private Message LAUNCH_WEEKLY = INFO_CTRL_PANEL_TASK_TO_SCHEDULE_WEEKLY.get();
  private Message LAUNCH_MONTHLY =
    INFO_CTRL_PANEL_TASK_TO_SCHEDULE_MONTHLY.get();
  private Message CRON = INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON.get();
  private ScheduleType schedule;
  /**
   * Default constructor.
   * @param taskName the name of the task to be scheduled.
   */
  public TaskToSchedulePanel(String taskName)
  {
    super();
    this.taskName = taskName;
    createLayout();
  }
  /**
   * Creates the layout of the panel (but the contents are not populated here).
   */
  private void createLayout()
  {
    GridBagConstraints gbc = new GridBagConstraints();
    JEditorPane explanation = Utilities.makeHtmlPane(
        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_SUMMARY.get(taskName).toString(),
        ColorAndFontConstants.defaultFont);
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.gridwidth = 1;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    add(explanation, gbc);
    gbc.gridy ++;
    gbc.insets.top = 10;
    scheduleType = Utilities.createComboBox();
    scheduleType.setModel(new DefaultComboBoxModel());
    ArrayList<Object> newElements = new ArrayList<Object>();
    newElements.add(new CategorizedComboBoxElement(LAUNCH_NOW,
        CategorizedComboBoxElement.Type.REGULAR));
    newElements.add(COMBO_SEPARATOR);
    newElements.add(new CategorizedComboBoxElement(LAUNCH_LATER,
        CategorizedComboBoxElement.Type.REGULAR));
    newElements.add(COMBO_SEPARATOR);
    newElements.add(new CategorizedComboBoxElement(LAUNCH_DAILY,
        CategorizedComboBoxElement.Type.REGULAR));
    newElements.add(new CategorizedComboBoxElement(LAUNCH_WEEKLY,
        CategorizedComboBoxElement.Type.REGULAR));
    newElements.add(new CategorizedComboBoxElement(LAUNCH_MONTHLY,
        CategorizedComboBoxElement.Type.REGULAR));
    newElements.add(new CategorizedComboBoxElement(CRON,
        CategorizedComboBoxElement.Type.REGULAR));
    updateComboBoxModel(newElements,
        (DefaultComboBoxModel)scheduleType.getModel());
    scheduleType.setRenderer(
        new NoLeftInsetCategoryComboBoxRenderer(scheduleType));
    scheduleType.addItemListener(new IgnoreItemListener(scheduleType));
    gbc.weightx = 0.0;
    gbc.anchor = GridBagConstraints.NORTHWEST;
    gbc.fill = GridBagConstraints.NONE;
    add(scheduleType, gbc);
    launchLaterPanel = createLaunchLaterPanel();
    dailyPanel = createDailyPanel();
    weeklyPanel = createWeeklyPanel();
    monthlyPanel = createMonthlyPanel();
    cronPanel = createCronPanel();
    scheduleType.addItemListener(new ItemListener()
    {
      public void itemStateChanged(ItemEvent ev)
      {
        Object element = scheduleType.getSelectedItem();
        boolean launchLaterVisible = false;
        boolean launchDailyVisible = false;
        boolean launchWeeklyVisible = false;
        boolean launchMonthlyVisible = false;
        boolean cronVisible = false;
        if (element != null)
        {
          if (element instanceof CategorizedComboBoxElement)
          {
            element = ((CategorizedComboBoxElement)element).getValue();
          }
          launchLaterVisible = element == LAUNCH_LATER;
          launchDailyVisible = element == LAUNCH_DAILY;
          launchWeeklyVisible = element == LAUNCH_WEEKLY;
          launchMonthlyVisible = element == LAUNCH_MONTHLY;
          cronVisible = element == CRON;
        }
        launchLaterPanel.setVisible(launchLaterVisible);
        dailyPanel.setVisible(launchDailyVisible);
        weeklyPanel.setVisible(launchWeeklyVisible);
        monthlyPanel.setVisible(launchMonthlyVisible);
        cronPanel.setVisible(cronVisible);
      }
    });
    launchLaterPanel.setVisible(false);
    dailyPanel.setVisible(false);
    weeklyPanel.setVisible(false);
    monthlyPanel.setVisible(false);
    cronPanel.setVisible(false);
    int width = 0;
    int height = 0;
    Component[] comps =
    {launchLaterPanel, dailyPanel, weeklyPanel, monthlyPanel, cronPanel};
    for (Component comp : comps)
    {
      width = Math.max(width, comp.getPreferredSize().width);
      height = Math.max(height, comp.getPreferredSize().height);
    }
    gbc.gridy ++;
    gbc.gridwidth = 1;
    gbc.gridx = 0;
    gbc.weightx = 0.0;
    gbc.insets.left = 30;
    add(launchLaterPanel, gbc);
    add(dailyPanel, gbc);
    add(weeklyPanel, gbc);
    add(monthlyPanel, gbc);
    add(cronPanel, gbc);
    add(Box.createRigidArea(new Dimension(width, height)), gbc);
    gbc.gridy ++;
    gbc.gridx = 0;
    gbc.fill = GridBagConstraints.VERTICAL;
    gbc.weighty = 1.0;
    add(Box.createVerticalGlue(), gbc);
  }
  /**
   * {@inheritDoc}
   */
  public void toBeDisplayed(boolean visible)
  {
    // Reset the schedule
    if (visible)
    {
      schedule = null;
    }
  }
  /**
   * {@inheritDoc}
   */
  public Message getTitle()
  {
    return INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TITLE.get(taskName);
  }
  /**
   * {@inheritDoc}
   */
  public void okClicked()
  {
    schedule = null;
    ArrayList<Message> errorMessages = new ArrayList<Message>();
    updateErrorMessages(errorMessages);
    if (errorMessages.size() > 0)
    {
      displayErrorDialog(errorMessages);
    }
    else
    {
      schedule = createSchedule();
      Utilities.getParentDialog(this).setVisible(false);
    }
  }
  /**
   * Checks the validity of the provided information and updates the provided
   * collection of messages with the errors that have been found.
   * @param errorMessages the collection of messages to be updated.
   */
  private void updateErrorMessages(Collection<Message> errorMessages)
  {
    Object type =
      ((CategorizedComboBoxElement)scheduleType.getSelectedItem()).getValue();
    if (type == LAUNCH_LATER)
    {
      updateLaunchLaterErrorMessages(errorMessages);
    }
    else if (type == LAUNCH_DAILY)
    {
      updateLaunchDailyErrorMessages(errorMessages);
    }
    else if (type == LAUNCH_WEEKLY)
    {
      updateLaunchWeeklyErrorMessages(errorMessages);
    }
    else if (type == LAUNCH_MONTHLY)
    {
      updateLaunchMonthlyErrorMessages(errorMessages);
    }
    else if (type == CRON)
    {
      updateCronErrorMessages(errorMessages);
    }
  }
  /**
   * Checks the validity of the launch later information and updates
   * the provided collection of messages with the errors that have been found.
   * The associated labels are also updated.
   * @param errorMessages the collection of messages to be updated.
   */
  private void updateLaunchLaterErrorMessages(Collection<Message> errorMessages)
  {
    setPrimaryValid(lTime);
    setPrimaryValid(lDay);
    setPrimaryValid(lMonth);
    setPrimaryValid(lYear);
    int previousErrorNumber = errorMessages.size();
    int y = Integer.parseInt(year.getSelectedItem().toString());
    int d = -1;
    int m = month.getSelectedIndex();
    int[] h = {-1};
    int[] min = {-1};
    checkTime(time, lTime, h, min, errorMessages);
    try
    {
      d = Integer.parseInt(day.getText().trim());
      if ((d < 0) || (d > 31))
      {
        errorMessages.add(ERR_CTRL_PANEL_INVALID_DAY.get());
        setPrimaryInvalid(lDay);
      }
    }
    catch (Exception ex)
    {
      errorMessages.add(ERR_CTRL_PANEL_INVALID_DAY.get());
      setPrimaryInvalid(lDay);
    }
    if (errorMessages.size() == previousErrorNumber)
    {
      GregorianCalendar calendar = new GregorianCalendar(y, m, d, h[0], min[0]);
      Date date = calendar.getTime();
      // Check that the actual date's month date corresponds to a valid day
      // (for instance if user specifies 30th of February, the resulting date
      // is 2nd (or 1st depending of the year) of Mars.
      if (calendar.get(Calendar.MONTH) != m)
      {
        errorMessages.add(ERR_CTRL_PANEL_INVALID_DAY_IN_MONTH.get(d,
            month.getSelectedItem().toString()));
        setPrimaryInvalid(lDay);
        setPrimaryInvalid(lMonth);
      }
      else if (date.before(new Date()))
      {
        errorMessages.add(ERR_CTRL_PANEL_DATE_ALREADY_PASSED.get());
        setPrimaryInvalid(lTime);
        setPrimaryInvalid(lDay);
        setPrimaryInvalid(lMonth);
        setPrimaryInvalid(lYear);
      }
    }
  }
  /**
   * Checks the validity of the launch daily information and updates
   * the provided collection of messages with the errors that have been found.
   * The associated labels are also updated.
   * @param errorMessages the collection of messages to be updated.
   */
  private void updateLaunchDailyErrorMessages(Collection<Message> errorMessages)
  {
    setPrimaryValid(lDailyTime);
    int[] h = {-1};
    int[] min = {-1};
    checkTime(dailyTime, lDailyTime, h, min, errorMessages);
  }
  /**
   * Checks the validity of the launch weekly information and updates
   * the provided collection of messages with the errors that have been found.
   * The associated labels are also updated.
   * @param errorMessages the collection of messages to be updated.
   */
  private void updateLaunchWeeklyErrorMessages(
      Collection<Message> errorMessages)
  {
    setPrimaryValid(lWeeklyTime);
    setPrimaryValid(lWeeklyDays);
    int[] h = {-1};
    int[] min = {-1};
    checkTime(weeklyTime, lWeeklyTime, h, min, errorMessages);
    boolean oneSelected = false;
    for (JCheckBox cb : weekDays)
    {
      if (cb.isSelected())
      {
        oneSelected = true;
        break;
      }
    }
    if (!oneSelected)
    {
      errorMessages.add(ERR_CTRL_PANEL_NO_WEEK_DAY_SELECTED.get());
      setPrimaryInvalid(lWeeklyDays);
    }
  }
  /**
   * Checks the validity of the launch monthly information and updates
   * the provided collection of messages with the errors that have been found.
   * The associated labels are also updated.
   * @param errorMessages the collection of messages to be updated.
   */
  private void updateLaunchMonthlyErrorMessages(
      Collection<Message> errorMessages)
  {
    setPrimaryValid(lMonthlyTime);
    setPrimaryValid(lMonthlyDays);
    int[] h = {-1};
    int[] min = {-1};
    checkTime(monthlyTime, lMonthlyTime, h, min, errorMessages);
    boolean oneSelected = false;
    for (JCheckBox cb : monthDays)
    {
      if (cb.isSelected())
      {
        oneSelected = true;
        break;
      }
    }
    if (!oneSelected)
    {
      errorMessages.add(ERR_CTRL_PANEL_NO_MONTH_DAY_SELECTED.get());
      setPrimaryInvalid(lMonthlyDays);
    }
  }
  /**
   * Checks the validity of the cron schedule information and updates
   * the provided collection of messages with the errors that have been found.
   * The associated labels are also updated.
   * @param errorMessages the collection of messages to be updated.
   */
  private void updateCronErrorMessages(Collection<Message> errorMessages)
  {
    setPrimaryValid(lCronMinute);
    setPrimaryValid(lCronHour);
    setPrimaryValid(lCronMonthDay);
    setPrimaryValid(lCronMonth);
    setPrimaryValid(lCronWeekDay);
    String minute = cronMinute.getText().trim();
    String hour = cronHour.getText().trim();
    String monthDay = cronMonthDay.getText().trim();
    String month = cronMonth.getText().trim();
    String weekDay = cronWeekDay.getText().trim();
    updateCronErrorMessages(minute, lCronMinute,
        ERR_CTRL_PANEL_NO_CRON_MINUTE_PROVIDED.get(),
        ERR_CTRL_PANEL_NOT_VALID_CRON_MINUTE_PROVIDED.get(),
        0, 59,
        errorMessages);
    updateCronErrorMessages(hour, lCronHour,
        ERR_CTRL_PANEL_NO_CRON_HOUR_PROVIDED.get(),
        ERR_CTRL_PANEL_NOT_VALID_CRON_HOUR_PROVIDED.get(),
        0, 23,
        errorMessages);
    updateCronErrorMessages(weekDay, lCronWeekDay,
        ERR_CTRL_PANEL_NO_CRON_WEEK_DAY_PROVIDED.get(),
        ERR_CTRL_PANEL_NOT_VALID_CRON_WEEK_DAY_PROVIDED.get(),
        0, 6,
        errorMessages);
    updateCronErrorMessages(monthDay, lCronMonthDay,
        ERR_CTRL_PANEL_NO_CRON_MONTH_DAY_PROVIDED.get(),
        ERR_CTRL_PANEL_NOT_VALID_CRON_MONTH_DAY_PROVIDED.get(),
        1, 31,
        errorMessages);
    updateCronErrorMessages(month, lCronMonth,
        ERR_CTRL_PANEL_NO_CRON_MONTH_PROVIDED.get(),
        ERR_CTRL_PANEL_NOT_VALID_CRON_MONTH_PROVIDED.get(),
        1, 12,
        errorMessages);
  }
  /**
   * Checks the validity of the cron schedule information tab and updates
   * the provided collection of messages with the errors that have been found.
   * The associated labels are also updated.
   * @param value the value of the cron schedule tab.
   * @param label the label associated with the cron schedule tab.
   * @param errorIfEmpty the message to be displayed if the value tab is empty.
   * @param contentError the message to be displayed if the value tab is not
   * valid.
   * @param minValue the minimum value accepted.
   * @param maxValue the maximum value accepted.
   * @param errorMessages the collection of messages to be updated.
   */
  private void updateCronErrorMessages(String value, JLabel label,
      Message errorIfEmpty, Message contentError, int minValue, int maxValue,
      Collection<Message> errorMessages)
  {
    if (value.length() == 0)
    {
      errorMessages.add(errorIfEmpty);
      setPrimaryInvalid(label);
    }
    else
    {
      try
      {
        RecurringTask.parseTaskTabField(value, minValue, maxValue);
      }
      catch (Exception ex)
      {
        errorMessages.add(contentError);
        setPrimaryInvalid(label);
      }
    }
  }
  /**
   * Returns the schedule type corresponding to the input provided by user.
   * This method assumes that all the date provided by the user has been
   * validated.
   * @return the schedule type corresponding to the input provided by user.
   */
  private ScheduleType createSchedule()
  {
    ScheduleType schedule;
    Object type =
      ((CategorizedComboBoxElement)scheduleType.getSelectedItem()).getValue();
    if (type == LAUNCH_NOW)
    {
      schedule = ScheduleType.createLaunchNow();
    }
    else if (type == LAUNCH_LATER)
    {
      int y = Integer.parseInt(year.getSelectedItem().toString());
      int d = Integer.parseInt(day.getText().trim());
      int m = month.getSelectedIndex();
      String sTime = time.getText().trim();
      int index = sTime.indexOf(':');
      int h = Integer.parseInt(sTime.substring(0, index).trim());
      int min = Integer.parseInt(sTime.substring(index+1).trim());
      GregorianCalendar calendar = new GregorianCalendar(y, m, d, h, min);
      schedule = ScheduleType.createLaunchLater(calendar.getTime());
    }
    else if (type == LAUNCH_DAILY)
    {
      String sTime = dailyTime.getText().trim();
      int index = sTime.indexOf(':');
      int h = Integer.parseInt(sTime.substring(0, index).trim());
      int m = Integer.parseInt(sTime.substring(index+1).trim());
      String cron = m+" "+h+" * * *";
      schedule = ScheduleType.createCron(cron);
    }
    else if (type == LAUNCH_WEEKLY)
    {
      String sTime = weeklyTime.getText().trim();
      int index = sTime.indexOf(':');
      int h = Integer.parseInt(sTime.substring(0, index).trim());
      int m = Integer.parseInt(sTime.substring(index+1).trim());
      StringBuilder sb = new StringBuilder();
      sb.append(m+" "+h+" * * ");
      boolean oneDayAdded = false;
      for (int i=0; i<weekDays.length; i++)
      {
        if (weekDays[i].isSelected())
        {
          if (oneDayAdded)
          {
            sb.append(',');
          }
          sb.append(i);
          oneDayAdded = true;
        }
      }
      schedule = ScheduleType.createCron(sb.toString());
    }
    else if (type == LAUNCH_MONTHLY)
    {
      String sTime = monthlyTime.getText().trim();
      int index = sTime.indexOf(':');
      int h = Integer.parseInt(sTime.substring(0, index).trim());
      int m = Integer.parseInt(sTime.substring(index+1).trim());
      StringBuilder sb = new StringBuilder();
      sb.append(m+" "+h+" ");
      boolean oneDayAdded = false;
      for (int i=0; i<monthDays.length; i++)
      {
        if (monthDays[i].isSelected())
        {
          if (oneDayAdded)
          {
            sb.append(',');
          }
          sb.append(i+1);
          oneDayAdded = true;
        }
      }
      sb.append(" * *");
      schedule = ScheduleType.createCron(sb.toString());
    }
    else if (type == CRON)
    {
      String cron = cronMinute.getText().trim() + " "+
      cronHour.getText().trim() + " "+
      cronMonthDay.getText().trim() + " "+
      cronMonth.getText().trim() + " "+
      cronWeekDay.getText().trim();
      schedule = ScheduleType.createCron(cron);
    }
    else
    {
      throw new IllegalStateException("Unknown schedule type: "+type);
    }
    return schedule;
  }
  /**
   * Convenience method to retrieve the time specified by the user.
   * @param time the text field where the user specifies time.
   * @param lTime the label associated with the text field.
   * @param h an integer array of size 1 where the value of the hour specified
   * by the user will be set.
   * @param m an integer array of size 1 where the value of the minute specified
   * by the user will be set.
   * @param errorMessages the collection of error messages that will be updated
   * with the encountered problems.
   */
  private void checkTime(JTextField time, JLabel lTime, int[] h, int[] m,
      Collection<Message> errorMessages)
  {
    String sTime = time.getText().trim();
    int index = sTime.indexOf(':');
    try
    {
      h[0] = Integer.parseInt(sTime.substring(0, index).trim());
      m[0] = Integer.parseInt(sTime.substring(index+1).trim());
      if (h[0] < 0 || h[0] > 23)
      {
        errorMessages.add(ERR_CTRL_PANEL_INVALID_HOUR.get());
        setPrimaryInvalid(lTime);
      }
      if (m[0] < 0 || m[0] > 59)
      {
        errorMessages.add(ERR_CTRL_PANEL_INVALID_MINUTE.get());
        setPrimaryInvalid(lTime);
      }
    }
    catch (Exception ex)
    {
      errorMessages.add(ERR_CTRL_PANEL_INVALID_TIME.get());
      setPrimaryInvalid(lTime);
    }
  }
  /**
   * Tells whether the user chose to close the dialog discarding the provided
   * input.
   * @return <CODE>true</CODE> if the user chose to close the dialog discarding
   * the provided input and <CODE>false</CODE> otherwise.
   */
  public boolean isCancelled()
  {
    return schedule == null;
  }
  /**
   * {@inheritDoc}
   */
  public void configurationChanged(ConfigurationChangeEvent ev)
  {
  }
  /**
   * {@inheritDoc}
   */
  public Component getPreferredFocusComponent()
  {
    return scheduleType;
  }
  /**
   * Returns the schedule provided by the user.
   * @return the schedule provided by the user.
   */
  public ScheduleType getSchedule()
  {
    return schedule;
  }
  private Component createLaunchLaterPanel()
  {
    JPanel panel = new JPanel(new GridBagLayout());
    panel.setOpaque(false);
    GridBagConstraints gbc = new GridBagConstraints();
    Calendar calendar = Calendar.getInstance();
    int currentYear = calendar.get(Calendar.YEAR);
    int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
    int currentMinute = calendar.get(Calendar.MINUTE);
    int currentDay = calendar.get(Calendar.DAY_OF_MONTH);
    int currentMonth = calendar.get(Calendar.MONTH);
    time = Utilities.createShortTextField();
    PlainDocument plainTextDocument = new PlainDocument();
    time.setDocument(plainTextDocument);
    String sHour = currentHour >= 10 ?
        String.valueOf(currentHour) : "0"+currentHour;
    String sMinute = currentMinute >= 10 ?
        String.valueOf(currentMinute) : "0"+currentMinute;
    time.setText(sHour+":"+sMinute);
    plainTextDocument.setDocumentFilter(new TimeDocumentFilter(time));
    day = Utilities.createShortTextField();
    day.setColumns(4);
    plainTextDocument = new PlainDocument();
    day.setDocument(plainTextDocument);
    day.setText(String.valueOf(currentDay));
    plainTextDocument.setDocumentFilter(
        new NumericLimitedSizeDocumentFilter(day, 2));
    month = Utilities.createComboBox();
    year = Utilities.createComboBox();
    int[][] maxMin =
    {
        {currentYear, currentYear + 5}
    };
    JComboBox[] numericBoxes =
    {
        year
    };
    int[] currentValues =
    {
        currentYear
    };
    for (int i=0; i<maxMin.length; i++)
    {
      int min = maxMin[i][0];
      int max = maxMin[i][1];
      DefaultComboBoxModel model = new DefaultComboBoxModel();
      int selectedIndex = 0;
      int index = 0;
      for (int j=min; j<=max; j++)
      {
        String s;
        if (j < 10)
        {
          s = "0"+j;
        }
        else
        {
          s = String.valueOf(j);
        }
        model.addElement(s);
        if (j == currentValues[i])
        {
          selectedIndex= index;
        }
        index++;
      }
      numericBoxes[i].setModel(model);
      if (selectedIndex != 0)
      {
        numericBoxes[i].setSelectedIndex(selectedIndex);
      }
    }
    DefaultComboBoxModel model = new DefaultComboBoxModel();
    month.setModel(model);
    Message[] monthMessages =
    {
        INFO_CTRL_PANEL_JANUARY.get(),
        INFO_CTRL_PANEL_FEBRUARY.get(),
        INFO_CTRL_PANEL_MARS.get(),
        INFO_CTRL_PANEL_APRIL.get(),
        INFO_CTRL_PANEL_MAY.get(),
        INFO_CTRL_PANEL_JUNE.get(),
        INFO_CTRL_PANEL_JULY.get(),
        INFO_CTRL_PANEL_AUGUST.get(),
        INFO_CTRL_PANEL_SEPTEMBER.get(),
        INFO_CTRL_PANEL_OCTOBER.get(),
        INFO_CTRL_PANEL_NOVEMBER.get(),
        INFO_CTRL_PANEL_DECEMBER.get(),
    };
    for (Message msg : monthMessages)
    {
      model.addElement(msg.toString());
    }
    month.setSelectedIndex(currentMonth);
    lTime = Utilities.createPrimaryLabel(
        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME.get());
    lDay = Utilities.createPrimaryLabel(
        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_DAY.get());
    lMonth = Utilities.createPrimaryLabel(
        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_MONTH.get());
    lYear = Utilities.createPrimaryLabel(
        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_YEAR.get());
    gbc.gridy = 0;
    JLabel[] labels = {lTime, lDay, lMonth, lYear};
    Component[] comps = {time, day, month, year};
    gbc.gridwidth = 1;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    for (int i=0; i<labels.length; i++)
    {
      gbc.gridx = 0;
      gbc.weightx = 0.0;
      panel.add(labels[i], gbc);
      gbc.gridx = 1;
      gbc.insets.left = 10;
      panel.add(comps[i], gbc);
      gbc.gridx = 2;
      gbc.weightx = 1.0;
      gbc.insets.left = 0;
      panel.add(Box.createHorizontalGlue(), gbc);
      gbc.insets.top = 10;
      gbc.gridy ++;
    }
    gbc.insets.top = 0;
    gbc.weighty = 1.0;
    gbc.fill = GridBagConstraints.VERTICAL;
    panel.add(Box.createVerticalGlue(), gbc);
    return panel;
  }
  private Component createDailyPanel()
  {
    JPanel panel = new JPanel(new GridBagLayout());
    panel.setOpaque(false);
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = 0;
    gbc.weightx = 0.0;
    lDailyTime =
      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME.get());
    dailyTime = Utilities.createShortTextField();
    PlainDocument plainTextDocument = new PlainDocument();
    dailyTime.setDocument(plainTextDocument);
    dailyTime.setColumns(4);
    dailyTime.setText("00:00");
    plainTextDocument.setDocumentFilter(new TimeDocumentFilter(dailyTime));
    panel.add(lDailyTime, gbc);
    gbc.gridx = 1;
    gbc.insets.left = 10;
    gbc.fill = GridBagConstraints.NONE;
    panel.add(dailyTime, gbc);
    gbc.gridx = 2;
    gbc.weightx = 1.0;
    gbc.insets.left = 0;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    panel.add(Box.createHorizontalGlue(), gbc);
    return panel;
  }
  private Component createWeeklyPanel()
  {
    JPanel panel = new JPanel(new GridBagLayout());
    panel.setOpaque(false);
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.weightx = 0.0;
    lWeeklyTime =
      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME.get());
    weeklyTime = Utilities.createShortTextField();
    PlainDocument plainTextDocument = new PlainDocument();
    weeklyTime.setDocument(plainTextDocument);
    weeklyTime.setColumns(4);
    weeklyTime.setText("00:00");
    plainTextDocument.setDocumentFilter(new TimeDocumentFilter(weeklyTime));
    lWeeklyDays = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_DAYS.get());
    for (JCheckBox cb : weekDays)
    {
      cb.setFont(ColorAndFontConstants.inlineHelpFont);
    }
    sunday.setSelected(true);
    wednesday.setSelected(true);
    gbc.anchor = GridBagConstraints.WEST;
    panel.add(lWeeklyTime, gbc);
    gbc.gridx = 1;
    gbc.insets.left = 10;
    gbc.gridwidth = weekDays.length;
    gbc.fill = GridBagConstraints.NONE;
    panel.add(weeklyTime, gbc);
    gbc.gridx = 2;
    gbc.weightx = 1.0;
    gbc.insets.left = 0;
    gbc.gridwidth = 1;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    panel.add(Box.createHorizontalGlue(), gbc);
    gbc.gridx = 0;
    gbc.gridy ++;
    gbc.insets.top = 10;
    gbc.weightx = 1.0;
    panel.add(lWeeklyDays, gbc);
    gbc.insets.left = 10;
    gbc.gridwidth = 1;
    for (JCheckBox cb : weekDays)
    {
      gbc.gridx ++;
      panel.add(cb, gbc);
    }
    gbc.weightx = 1.0;
    gbc.insets.left = 0;
    gbc.gridwidth = 1;
    gbc.gridx ++;
    panel.add(Box.createHorizontalGlue(), gbc);
    return panel;
  }
  private Component createMonthlyPanel()
  {
    JPanel panel = new JPanel(new GridBagLayout());
    panel.setOpaque(false);
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.weightx = 0.0;
    lMonthlyTime =
      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME.get());
    monthlyTime = Utilities.createShortTextField();
    PlainDocument plainTextDocument = new PlainDocument();
    monthlyTime.setDocument(plainTextDocument);
    monthlyTime.setColumns(4);
    monthlyTime.setText("00:00");
    plainTextDocument.setDocumentFilter(new TimeDocumentFilter(monthlyTime));
    lMonthlyDays = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_DAYS.get());
    gbc.anchor = GridBagConstraints.WEST;
    panel.add(lMonthlyTime, gbc);
    gbc.gridx = 1;
    gbc.insets.left = 10;
    gbc.fill = GridBagConstraints.NONE;
    gbc.gridwidth = 7;
    panel.add(monthlyTime, gbc);
    gbc.gridx = 2;
    gbc.weightx = 1.0;
    gbc.insets.left = 0;
    gbc.gridwidth = 1;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    panel.add(Box.createHorizontalGlue(), gbc);
    gbc.gridx = 0;
    gbc.gridy ++;
    gbc.insets.top = 10;
    gbc.weightx = 1.0;
    gbc.gridwidth = 1;
    panel.add(lMonthlyDays, gbc);
    gbc.insets.left = 10;
    gbc.gridwidth = 1;
    for (int i=0 ; i<monthDays.length; i++)
    {
      monthDays[i] = Utilities.createCheckBox(Message.raw(String.valueOf(i+1)));
      monthDays[i].setFont(ColorAndFontConstants.inlineHelpFont);
      int x = i % 7;
      if (x == 0 && i != 0)
      {
        gbc.gridy ++;
        gbc.insets.top = 5;
      }
      if (x != 0)
      {
        gbc.insets.left = 5;
      }
      else
      {
        gbc.insets.left = 10;
      }
      gbc.gridx = x + 1;
      panel.add(monthDays[i], gbc);
    }
    monthDays[0].setSelected(true);
    gbc.weightx = 1.0;
    gbc.insets.left = 0;
    gbc.gridwidth = 1;
    gbc.gridx ++;
    panel.add(Box.createHorizontalGlue(), gbc);
    return panel;
  }
  private Component createCronPanel()
  {
    JPanel panel = new JPanel(new GridBagLayout());
    panel.setOpaque(false);
    GridBagConstraints gbc = new GridBagConstraints();
    JEditorPane explanation = Utilities.makeHtmlPane(
        INFO_CTRL_PANEL_CRON_HELP.get().toString(),
        ColorAndFontConstants.inlineHelpFont);
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.gridwidth = 2;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    panel.add(explanation, gbc);
    gbc.gridy ++;
    gbc.insets.top = 10;
    gbc.gridwidth = 1;
    lCronMinute = Utilities.createPrimaryLabel(
        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_MINUTE.get());
    lCronHour = Utilities.createPrimaryLabel(
        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_HOUR.get());
    lCronWeekDay = Utilities.createPrimaryLabel(
        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_WEEK_DAY.get());
    lCronMonthDay = Utilities.createPrimaryLabel(
        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_MONTH_DAY.get());
    lCronMonth = Utilities.createPrimaryLabel(
        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_MONTH.get());
    cronMinute = Utilities.createShortTextField();
    cronMinute.setText("*");
    cronHour = Utilities.createShortTextField();
    cronHour.setText("*");
    cronWeekDay = Utilities.createShortTextField();
    cronWeekDay.setText("*");
    cronMonthDay = Utilities.createShortTextField();
    cronMonthDay.setText("*");
    cronMonth = Utilities.createShortTextField();
    cronMonth.setText("*");
    JLabel[] labels = {lCronMinute, lCronHour, lCronWeekDay, lCronMonthDay,
        lCronMonth};
    Component[] comps = {cronMinute, cronHour, cronWeekDay, cronMonthDay,
        cronMonth};
    Message[] help =
    {
      INFO_CTRL_PANEL_CRON_MINUTE_HELP.get(),
      INFO_CTRL_PANEL_CRON_HOUR_HELP.get(),
      INFO_CTRL_PANEL_CRON_WEEK_DAY_HELP.get(),
      INFO_CTRL_PANEL_CRON_MONTH_DAY_HELP.get(),
      INFO_CTRL_PANEL_CRON_MONTH_HELP.get(),
    };
    gbc.gridwidth = 1;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    for (int i=0; i<labels.length; i++)
    {
      gbc.gridx = 0;
      gbc.weightx = 0.0;
      gbc.insets.left = 0;
      panel.add(labels[i], gbc);
      gbc.gridx = 1;
      gbc.insets.left = 10;
      panel.add(comps[i], gbc);
      gbc.gridx = 2;
      gbc.weightx = 1.0;
      gbc.insets.left = 0;
      panel.add(Box.createHorizontalGlue(), gbc);
      if (help[i] != null)
      {
        gbc.insets.top = 3;
        gbc.insets.left = 10;
        gbc.gridy ++;
        gbc.gridx = 1;
        panel.add(Utilities.createInlineHelpLabel(help[i]), gbc);
      }
      gbc.insets.top = 10;
      gbc.gridy ++;
    }
    gbc.insets.top = 0;
    gbc.weighty = 1.0;
    gbc.fill = GridBagConstraints.VERTICAL;
    panel.add(Box.createVerticalGlue(), gbc);
    return panel;
  }
  /**
   * The main method to test this panel.
   * @param args the arguments.
   */
  public static void main(String[] args)
  {
    while (true)
    {
      TaskToSchedulePanel p = new TaskToSchedulePanel("TEST TASK");
      GenericDialog dlg = new GenericDialog(new JFrame(), p);
      dlg.setModal(true);
      dlg.setVisible(true);
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/components/NumericLimitedSizeDocumentFilter.java
New file
@@ -0,0 +1,116 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.ui.components;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.JTextComponent;
/**
 * Document filter used to update properly a text component displaying a
 * numeric field with a limited size.
 */
public class NumericLimitedSizeDocumentFilter extends DocumentFilter
{
  private JTextComponent tf;
  private int maxSize;
  /**
   * Constructor.
   * @param tf the text component associated with the document.
   * @param maxSize the maximum size.
   */
  public NumericLimitedSizeDocumentFilter(JTextComponent tf, int maxSize)
  {
    this.tf = tf;
    this.maxSize = maxSize;
  }
  /**
   * {@inheritDoc}
   */
  public void insertString(DocumentFilter.FilterBypass fb, int offset,
      String text, AttributeSet attr)
  throws BadLocationException
  {
    int previousLength = fb.getDocument().getLength();
    String newText = text.replaceAll("[^0-9]", "");
    if (newText.length() > maxSize)
    {
      newText = newText.substring(0, maxSize);
    }
    if (newText.length() + previousLength > maxSize)
    {
      if (offset + newText.length() > maxSize)
      {
        int newOffset = offset + newText.length() - maxSize;
        fb.remove(0, newOffset);
        fb.insertString(newOffset, newText, attr);
      }
      else
      {
        fb.insertString(offset, newText, attr);
        fb.remove(maxSize, newText.length() + previousLength - maxSize);
      }
    }
    else
    {
      fb.insertString(offset, newText, attr);
    }
    updateCaretPosition(fb);
  }
  /**
   * {@inheritDoc}
   */
  public void replace(DocumentFilter.FilterBypass fb, int offset,
      int length, String text, AttributeSet attr)
  throws BadLocationException
  {
    if (length > 0)
    {
      fb.remove(offset, length);
    }
    insertString(fb, offset, text, attr);
  }
  private void updateCaretPosition(DocumentFilter.FilterBypass fb)
  throws BadLocationException
  {
    int totalLength = fb.getDocument().getLength();
    int caretPosition = tf.getCaretPosition();
    if ((totalLength >= maxSize) &&
        (caretPosition == fb.getDocument().getLength()))
    {
      tf.setCaretPosition(0);
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/components/ScheduleSummaryPanel.java
New file
@@ -0,0 +1,182 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.ui.components;
import static org.opends.messages.AdminToolMessages.*;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.util.Date;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.opends.guitools.controlpanel.datamodel.ScheduleType;
import org.opends.guitools.controlpanel.ui.GenericDialog;
import org.opends.guitools.controlpanel.ui.TaskToSchedulePanel;
import org.opends.guitools.controlpanel.util.Utilities;
/**
 * A class used as component displaying the string representation of a schedule
 * and the possibility of updating it clicking a button.
 */
public class ScheduleSummaryPanel extends JPanel
{
  private static final long serialVersionUID = 3111141404599060028L;
  private ScheduleType schedule = ScheduleType.createLaunchNow();
  private JLabel label;
  private JButton change;
  private TaskToSchedulePanel schedulePanel;
  private GenericDialog scheduleDlg;
  private String taskName;
  private DateFormat formatter =
    DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.SHORT);
  /**
   * Default constructor.
   * @param taskName the name of the task to be scheduled.
   */
  public ScheduleSummaryPanel(String taskName)
  {
    super(new GridBagLayout());
    setOpaque(false);
    this.taskName = taskName;
    createLayout();
  }
  /**
   * Returns the schedule represented by this panel.
   * @return the schedule represented by this panel.
   */
  public ScheduleType getSchedule()
  {
    return schedule;
  }
  /**
   * Sets the schedule represented by this panel.
   * @param schedule the schedule represented by this panel.
   */
  public void setSchedule(ScheduleType schedule)
  {
    this.schedule = schedule;
    updateLabel(schedule);
  }
  /**
   * Returns whether the change button is enabled or not.
   * @return <CODE>true</CODE> if the change button is enabled and
   * <CODE>false</CODE> otherwise.
   */
  public boolean isChangeEnabled()
  {
    return change.isEnabled();
  }
  /**
   * Sets the enable state of the change button.
   * @param enable whether the change button must be enabled or not.
   */
  public void setChangeEnabled(boolean enable)
  {
    change.setEnabled(enable);
  }
  private void createLayout()
  {
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = 0;
    gbc.gridy = 0;
    label = Utilities.createDefaultLabel();
    change = Utilities.createButton(INFO_CTRL_PANEL_CHANGE_SCHEDULE.get());
    change.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent ev)
      {
        changeButtonClicked();
      }
    });
    updateLabel(schedule);
    gbc.fill = GridBagConstraints.NONE;
    add(label, gbc);
    gbc.gridx ++;
    gbc.insets.left = 10;
    add(change, gbc);
    gbc.gridx ++;
    gbc.weightx = 1.0;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    gbc.insets.left = 0;
    add(Box.createHorizontalGlue(), gbc);
  }
  private void updateLabel(ScheduleType schedule)
  {
    ScheduleType.Type type = schedule.getType();
    if (type == ScheduleType.Type.LAUNCH_NOW)
    {
      label.setText(INFO_CTRL_PANEL_LAUNCH_NOW_SUMMARY.get().toString());
    }
    else if (type == ScheduleType.Type.LAUNCH_LATER)
    {
      Date date = schedule.getLaunchLaterDate();
      String sDate = formatter.format(date);
      label.setText(INFO_CTRL_PANEL_LAUNCH_LATER_SUMMARY.get(sDate).toString());
    }
    else if (type == ScheduleType.Type.LAUNCH_PERIODICALLY)
    {
      String cron = schedule.getCronValue();
      label.setText(
          INFO_CTRL_PANEL_LAUNCH_PERIODICALLY_SUMMARY.get(cron).toString());
    }
    else
    {
      throw new IllegalStateException("Unknown schedule type: "+type);
    }
  }
  private void changeButtonClicked()
  {
    if (schedulePanel == null)
    {
      schedulePanel = new TaskToSchedulePanel(taskName);
      scheduleDlg = new GenericDialog(Utilities.getFrame(this), schedulePanel);
      Utilities.centerGoldenMean(scheduleDlg, Utilities.getParentDialog(this));
      scheduleDlg.setModal(true);
    }
    scheduleDlg.setVisible(true);
    if (!schedulePanel.isCancelled())
    {
      setSchedule(schedulePanel.getSchedule());
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/components/TimeDocumentFilter.java
New file
@@ -0,0 +1,198 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.ui.components;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.JTextComponent;
/**
 * Document filter used to update properly a text component displaying a
 * time.
 */
public class TimeDocumentFilter extends DocumentFilter
{
  private JTextComponent tf;
  /**
   * Constructor.
   * @param tf the text component associated with the document.
   */
  public TimeDocumentFilter(JTextComponent tf)
  {
    this.tf = tf;
  }
  /**
   * {@inheritDoc}
   */
  public void insertString(DocumentFilter.FilterBypass fb, int offset,
      String text, AttributeSet attr)
  throws BadLocationException
  {
    int previousLength = fb.getDocument().getLength();
    fb.insertString(offset, text.replaceAll("[^0-9]", ""), attr);
    trimPosition(fb, text, offset, previousLength);
  }
  /**
   * {@inheritDoc}
   */
  public void remove(DocumentFilter.FilterBypass fb, int offset,
      int length)
  throws BadLocationException
  {
    String text = fb.getDocument().getText(offset, length);
    int index = text.indexOf(":");
    if (index == -1)
    {
      fb.remove(offset, length);
    }
    else
    {
      // index value is relative to offset
      if (index > 0)
      {
        fb.remove(offset, index);
      }
      if (index < length - 1)
      {
        fb.remove(offset + index + 1, length - index -1);
      }
    }
    updateCaretPosition(fb);
  }
  /**
   * {@inheritDoc}
   */
  public void replace(DocumentFilter.FilterBypass fb, int offset,
      int length, String text, AttributeSet attr)
  throws BadLocationException
  {
    int previousLength = fb.getDocument().getLength();
    String t = fb.getDocument().getText(offset, length);
    int index = t.indexOf(":");
    fb.replace(offset, length, text.replaceAll("[^0-9]", ""), attr);
    if (index != -1)
    {
      if (fb.getDocument().getLength() >= 2)
      {
        fb.insertString(2, ":", attr);
      }
      else
      {
        fb.insertString(fb.getDocument().getLength(), ":", attr);
      }
    }
    trimPosition(fb, text, offset, previousLength);
  }
  private void trimPosition(DocumentFilter.FilterBypass fb, String newText,
      int offset, int previousLength)
  throws BadLocationException
  {
    String allText =
      fb.getDocument().getText(0, fb.getDocument().getLength());
    int index = allText.indexOf(':');
    if ((index != -1) && (newText.length() == 1))
    {
      int minuteLength = allText.length() - index - 1;
      int hourLength = index;
      if ((minuteLength > 2) || (hourLength > 2))
      {
        if (offset < previousLength)
        {
          fb.remove(offset + 1, 1);
        }
        else
        {
          fb.remove(previousLength, 1);
        }
      }
    }
    updateCaretPosition(fb);
  }
  private void updateCaretPosition(DocumentFilter.FilterBypass fb)
  throws BadLocationException
  {
    String allText =
      fb.getDocument().getText(0, fb.getDocument().getLength());
    int index = allText.indexOf(':');
    if (index != -1)
    {
      int minuteLength = allText.length() - index - 1;
      int hourLength = index;
      int caretPosition = tf.getCaretPosition();
      if ((minuteLength >= 2) &&
          (caretPosition == allText.length()))
      {
        tf.setCaretPosition(0);
      }
      else if (hourLength == caretPosition)
      {
        if (hourLength >= 2)
        {
          tf.setCaretPosition(3);
        }
        else if (hourLength == 1)
        {
          char c = allText.charAt(0);
          if (c != '0' && c != '1' && c != '2')
          {
            tf.setCaretPosition(2);
          }
        }
      }
      else if (hourLength + 1 == caretPosition)
      {
        if (hourLength == 1)
        {
          char c = allText.charAt(0);
          if (c == '0' || c == '1' || c == '2')
          {
            tf.setCaretPosition(caretPosition - 1);
          }
        }
        else if (hourLength == 0)
        {
          tf.setCaretPosition(caretPosition - 1);
        }
      }
    }
    if (allText.length() == 1)
    {
      tf.setCaretPosition(0);
    }
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/renderer/NoLeftInsetCategoryComboBoxRenderer.java
New file
@@ -0,0 +1,71 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.ui.renderer;
import java.awt.Component;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import org.opends.guitools.controlpanel.datamodel.CategorizedComboBoxElement;
/**
 *  This class is used simply to avoid an inset on the left for the
 *  elements of the combo box.
 *  Since this item is a CategorizedComboBoxElement of type
 *  CategorizedComboBoxElement.Type.REGULAR, it has by default an inset on
 *  the left.
 */
public class NoLeftInsetCategoryComboBoxRenderer extends CustomListCellRenderer
{
  /**
   * The constructor.
   * @param combo the combo box to be rendered.
   */
  public NoLeftInsetCategoryComboBoxRenderer(JComboBox combo)
  {
    super(combo);
  }
  /**
   * {@inheritDoc}
   */
  public Component getListCellRendererComponent(JList list, Object value,
      int index, boolean isSelected, boolean cellHasFocus)
  {
    Component comp = super.getListCellRendererComponent(list, value, index,
        isSelected, cellHasFocus);
    if (value instanceof CategorizedComboBoxElement)
    {
      CategorizedComboBoxElement element = (CategorizedComboBoxElement)value;
      String name = getStringValue(element);
      ((JLabel)comp).setText(name);
    }
    comp.setFont(defaultFont);
    return comp;
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/renderer/TaskCellRenderer.java
New file
@@ -0,0 +1,95 @@
/*
 * 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
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.guitools.controlpanel.ui.renderer;
import java.awt.Component;
import javax.swing.BorderFactory;
import javax.swing.JTable;
import javax.swing.border.Border;
import javax.swing.table.DefaultTableCellRenderer;
import org.opends.guitools.controlpanel.ui.ColorAndFontConstants;
/**
 * Class used to render the task tables.
 */
public class TaskCellRenderer extends DefaultTableCellRenderer
{
  private static final long serialVersionUID = -84332267021523835L;
  /**
   * The border of the first column.
   * TODO: modify CustomCellRenderer to make this public.
   */
  protected final static Border column0Border =
    BorderFactory.createCompoundBorder(
      BorderFactory.createMatteBorder(0, 1, 0, 0,
          ColorAndFontConstants.gridColor),
          BorderFactory.createEmptyBorder(4, 4, 4, 4));
  /**
   * The default border.
   */
  public final static Border defaultBorder = CustomCellRenderer.defaultBorder;
  /**
   * Default constructor.
   */
  public TaskCellRenderer()
  {
    setFont(ColorAndFontConstants.tableFont);
    setOpaque(true);
    setBackground(ColorAndFontConstants.treeBackground);
    setForeground(ColorAndFontConstants.treeForeground);
  }
  /**
   * {@inheritDoc}
   */
  public Component getTableCellRendererComponent(JTable table, Object value,
      boolean isSelected, boolean hasFocus, int row, int column) {
    super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
        row, column);
    if (hasFocus)
    {
      setBorder(
          CustomCellRenderer.getDefaultFocusBorder(table, value, isSelected,
              row, column));
    }
    else if (column == 0)
    {
      setBorder(column0Border);
    }
    else
    {
      setBorder(defaultBorder);
    }
    return this;
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/util/ConfigFromDirContext.java
@@ -33,6 +33,7 @@
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -67,7 +68,9 @@
import org.opends.server.admin.client.ldap.LDAPManagementContext;
import org.opends.server.admin.std.client.*;
import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn.IndexType;
import org.opends.server.config.ConfigConstants;
import org.opends.server.core.DirectoryServer;
import org.opends.server.tools.tasks.TaskEntry;
import org.opends.server.types.DN;
import org.opends.server.types.OpenDsException;
import org.opends.server.util.ServerConstants;
@@ -238,6 +241,7 @@
      new HashSet<ConnectionHandlerDescriptor>();
    Set<BackendDescriptor> bs = new HashSet<BackendDescriptor>();
    Set<DN> as = new HashSet<DN>();
    Set<TaskEntry> ts = new HashSet<TaskEntry>();
    rootMonitor = null;
    jvmMemoryUsage = null;
@@ -528,11 +532,23 @@
    }
    catch (Throwable t)
    {
      LOG.log(Level.WARNING, "Error reading configuration: "+t, t);
      LOG.log(Level.WARNING, "Error reading monitoring: "+t, t);
      OnlineUpdateException oupe = new OnlineUpdateException(
          ERR_READING_CONFIG_LDAP.get(t.toString()), t);
      ex.add(oupe);
    }
    try
    {
      updateTaskInformation(ctx, ex, ts);
    }
    catch (Throwable t)
    {
      LOG.log(Level.WARNING, "Error reading task information: "+t, t);
      OnlineUpdateException oupe = new OnlineUpdateException(
          ERR_READING_CONFIG_LDAP.get(t.toString()), t);
      ex.add(oupe);
    }
    taskEntries = Collections.unmodifiableSet(ts);
    for (ConnectionHandlerDescriptor ch : getConnectionHandlers())
    {
      ch.setMonitoringEntries(getMonitoringEntries(ch));
@@ -762,6 +778,33 @@
    }
  }
  /**
   * Takes the provided search result and updates the task information
   * accordingly.
   * @param sr the search result.
   * @param searchBaseDN the base search.
   * @param taskEntries the collection of TaskEntries to be updated.
   * @throws NamingException if there is an error retrieving the values of the
   * search result.
   */
  protected void handleTaskSearchResult(SearchResult sr, String searchBaseDN,
      Collection<TaskEntry> taskEntries)
  throws NamingException
  {
    CustomSearchResult csr = new CustomSearchResult(sr, searchBaseDN);
    try
    {
      if (isTaskEntry(csr))
      {
        taskEntries.add(new TaskEntry(csr.getEntry()));
      }
    }
    catch (OpenDsException ode)
    {
      exceptions.add(ode);
    }
  }
  private void updateMonitorInformation(InitialLdapContext ctx,
      List<OpenDsException> ex)
  {
@@ -796,6 +839,37 @@
    }
  }
  private void updateTaskInformation(InitialLdapContext ctx,
      List<OpenDsException> ex, Collection<TaskEntry> ts)
  {
    // Read monitoring information: since it is computed, it is faster
    // to get everything in just one request.
    SearchControls ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    ctls.setReturningAttributes(
        getMonitoringAttributes());
    String filter = "(objectclass=ds-task)";
    try
    {
      LdapName jndiName = new LdapName(ConfigConstants.DN_TASK_ROOT);
      NamingEnumeration taskEntries = ctx.search(jndiName, filter, ctls);
      while (taskEntries.hasMore())
      {
        SearchResult sr = (SearchResult)taskEntries.next();
        handleTaskSearchResult(sr, ConfigConstants.DN_TASK_ROOT, ts);
      }
    }
    catch (NamingException ne)
    {
      OnlineUpdateException oue = new OnlineUpdateException(
          ERR_READING_CONFIG_LDAP.get(ne.getMessage().toString()), ne);
      ex.add(oue);
    }
  }
  private ConnectionHandlerDescriptor getConnectionHandler(
      ConnectionHandlerCfgClient connHandler, String name)
  throws OpenDsException
@@ -962,6 +1036,24 @@
    return isConnectionHandler;
  }
  private boolean isTaskEntry(CustomSearchResult csr) throws OpenDsException
  {
    boolean isTaskEntry = false;
    Set<Object> vs = csr.getAttributeValues("objectclass");
    if ((vs != null) && !vs.isEmpty())
    {
      for (Object oc : vs)
      {
        if (oc.toString().equalsIgnoreCase("ds-task"))
        {
          isTaskEntry = true;
          break;
        }
      }
    }
    return isTaskEntry;
  }
  /**
   * Commodity method to get the string representation to be used in the
   * hash maps as key.
@@ -977,11 +1069,33 @@
      ConnectionHandlerDescriptor ch)
  {
    Set<CustomSearchResult> monitorEntries = new HashSet<CustomSearchResult>();
    for (String key : hmConnectionHandlersMonitor.keySet())
    if (ch.getState() == ConnectionHandlerDescriptor.State.ENABLED)
    {
      if (key.indexOf(getKey(ch.getName())) != -1)
      for (String key : hmConnectionHandlersMonitor.keySet())
      {
        monitorEntries.add(hmConnectionHandlersMonitor.get(key));
        // The name of the connection handler does not appear necessarily in the
        // key (which is based on the DN of the monitoring entry).  In general
        // the DN contains the String specified in
        // LDAPConnectionHandler.DEFAULT_FRIENDLY_NAME, so we have to check that
        // this connection handler is the right one.
        // See org.opends.server.protocols.ldap.LDAPConnectionHandler to see
        // how the DN of the monitoring entry is generated.
        if (key.indexOf(getKey("port "+ch.getPort())) != -1)
        {
          boolean hasAllAddresses = true;
          for (InetAddress a : ch.getAddresses())
          {
            if (key.indexOf(getKey(a.getHostAddress())) == -1)
            {
              hasAllAddresses = false;
              break;
            }
          }
          if (hasAllAddresses)
          {
            monitorEntries.add(hmConnectionHandlersMonitor.get(key));
          }
        }
      }
    }
opends/src/guitools/org/opends/guitools/controlpanel/util/ConfigReader.java
@@ -46,6 +46,7 @@
import org.opends.server.admin.std.meta.AdministrationConnectorCfgDefn;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.tools.tasks.TaskEntry;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryEnvironmentConfig;
import org.opends.server.types.DirectoryException;
@@ -166,6 +167,11 @@
  protected Schema schema;
  /**
   * The task entries.
   **/
  protected Set<TaskEntry> taskEntries = Collections.emptySet();
  /**
   * Returns the Administrative User DNs found in the config.ldif.  The set
   * must be unmodifiable (the inheriting classes must take care of this).
   * @return the Administrative User DNs found in the config.ldif.
@@ -280,6 +286,15 @@
  }
  /**
   * Returns the task entries.
   * @return the task entries.
   */
  public Set<TaskEntry> getTaskEntries()
  {
    return taskEntries;
  }
  /**
   * Reads the schema from the files.
   * @throws ConfigException if an error occurs reading the schema.
   * @throws InitializationException if an error occurs initializing
opends/src/guitools/org/opends/guitools/controlpanel/util/Utilities.java
@@ -993,6 +993,12 @@
    }
    JEditorPane pane2 = makeHtmlPane(wrappedText, font);
    pane.setPreferredSize(pane2.getPreferredSize());
    JFrame frame = getFrame(pane);
    if ((frame != null) && frame.isVisible())
    {
      frame.getRootPane().revalidate();
      frame.getRootPane().repaint();
    }
  }
  /**
opends/src/messages/messages/admin_tool.properties
@@ -1325,6 +1325,7 @@
MILD_ERR_CTRL_PANEL_RUN_BACKUP_ERROR_SUMMARY=Error during Backup
MILD_ERR_CTRL_PANEL_RUN_BACKUP_ERROR_DETAILS=An error occurred during the \
 backup.  Error code: %d.
INFO_CTRL_PANEL_BACKUP_TASK_NAME=Backup
INFO_CTRL_PANEL_OTHER_BASE_DN_TITLE=Other Base DN
MILD_ERR_CTRL_PANEL_NO_BASE_DN_PROVIDED=You must provide a base DN.
@@ -2551,3 +2552,132 @@
SEVERE_ERR_VERSION_IN_REMOTE_SERVER_NOT_FOUND=Could not find version \
 information in the remote server.  The remote LDAP server does not seem to be \
 manageable remotely by the control panel.
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TITLE='%s' Task Schedule
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_SUMMARY=Specify when the task '%s' will be \
 launched.
INFO_CTRL_PANEL_LAUNCH_NOW=Launch Now
INFO_CTRL_PANEL_LAUNCH_LATER=Launch Later
INFO_CTRL_PANEL_DAYS=Days:
INFO_CTRL_PANEL_JANUARY=January
INFO_CTRL_PANEL_FEBRUARY=February
INFO_CTRL_PANEL_MARS=Mars
INFO_CTRL_PANEL_APRIL=April
INFO_CTRL_PANEL_MAY=May
INFO_CTRL_PANEL_JUNE=June
INFO_CTRL_PANEL_JULY=July
INFO_CTRL_PANEL_AUGUST=August
INFO_CTRL_PANEL_SEPTEMBER=September
INFO_CTRL_PANEL_OCTOBER=October
INFO_CTRL_PANEL_NOVEMBER=November
INFO_CTRL_PANEL_DECEMBER=December
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME=Time:
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_DAY=Day:
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_MONTH=Month:
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_YEAR=Year:
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_DAILY=Launch Periodically using a Daily \
 Schedule
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_WEEKLY=Launch Periodically using a Weekly \
 Schedule
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_MONTHLY=Launch Periodically using a Monthly \
 Schedule
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_SUNDAY=Sun
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_MONDAY=Mon
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TUESDAY=Tue
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_WEDNESDAY=Wed
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_THURSDAY=Thu
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_FRIDAY=Fri
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_SATURDAY=Sat
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON=Launch Periodically using a CRON \
 Schedule
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_MINUTE=Minute:
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_HOUR=Hour:
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_WEEK_DAY=Day of Week:
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_MONTH_DAY=Day of Month:
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_MONTH=Month:
INFO_CTRL_PANEL_CRON_MINUTE_HELP=Valid values from 0 to 59
INFO_CTRL_PANEL_CRON_HOUR_HELP=Valid values from 0 to 23
INFO_CTRL_PANEL_CRON_WEEK_DAY_HELP=Valid values from 0 to 6 (0 is Sunday, \
 1 is Monday...)
INFO_CTRL_PANEL_CRON_MONTH_DAY_HELP=From 1 to 31
INFO_CTRL_PANEL_CRON_MONTH_HELP=Valid values from 1 to 12 (1 is January, \
 2 is February...)
#
# Note that the following property contains line breaks in HTML format (<br>).
#
INFO_CTRL_PANEL_CRON_HELP=Use ',' to separate values. For example: \
 '1,4,5'.<br>Use '-' to indicate intervals.  For example '1-5'.\<br>Use '*' to \
 indicate any value.
SEVERE_ERR_CTRL_PANEL_INVALID_HOUR=The provided hour value is not valid.
SEVERE_ERR_CTRL_PANEL_INVALID_MINUTE=The provided minute value is not valid.
SEVERE_ERR_CTRL_PANEL_INVALID_DAY=The provided day value is not valid.
SEVERE_ERR_CTRL_PANEL_INVALID_TIME=The provided time value is not valid.
SEVERE_ERR_CTRL_PANEL_INVALID_DAY_IN_MONTH=The day '%d' does not exist in \
 %s.
SEVERE_ERR_CTRL_PANEL_NO_WEEK_DAY_SELECTED=You must select at least one \
 day of the week.
SEVERE_ERR_CTRL_PANEL_NO_MONTH_DAY_SELECTED=You must select at least one \
 day of the month.
SEVERE_ERR_CTRL_PANEL_DATE_ALREADY_PASSED=The provided date already passed.
SEVERE_ERR_CTRL_PANEL_NO_CRON_MINUTE_PROVIDED=No minute provided.  Use '*' \
 to indicate any value.
SEVERE_ERR_CTRL_PANEL_NO_CRON_HOUR_PROVIDED=No hour provided.  Use '*' \
 to indicate any value.
SEVERE_ERR_CTRL_PANEL_NO_CRON_MONTH_DAY_PROVIDED=No day of month \
 provided.  Use '*' to indicate any value.
SEVERE_ERR_CTRL_PANEL_NO_CRON_MONTH_PROVIDED=No month provided.  Use '*' \
 to indicate any value.
SEVERE_ERR_CTRL_PANEL_NO_CRON_WEEK_DAY_PROVIDED=No day of week provided.  \
 Use '*' to indicate any value.
SEVERE_ERR_CTRL_PANEL_NOT_VALID_CRON_MINUTE_PROVIDED=The minute value \
 provided is not valid.
SEVERE_ERR_CTRL_PANEL_NOT_VALID_CRON_HOUR_PROVIDED=The hour value \
 provided is not valid.
SEVERE_ERR_CTRL_PANEL_NOT_VALID_CRON_MONTH_DAY_PROVIDED=The day of month \
 value provided is not valid.
SEVERE_ERR_CTRL_PANEL_NOT_VALID_CRON_MONTH_PROVIDED=The month value \
 provided is not valid.
SEVERE_ERR_CTRL_PANEL_NOT_VALID_CRON_WEEK_DAY_PROVIDED=The day of week \
 value provided is not valid.
INFO_CTRL_PANEL_TASK_TO_SCHEDULE_LIST_TITLE=Scheduled Tasks
INFO_CTRL_PANEL_NO_TASKS_FOUND=- No Tasks Found -
INFO_CTRL_PANEL_CANCEL_TASK_BUTTON_LABEL=Cancel Task
INFO_CTRL_PANEL_SCHEDULED_TASK_LIST_REQUIRES_SERVER_RUNNING=To see the \
 list of scheduled tasks the server must be running and you must provide \
 authentication.
INFO_CTRL_PANEL_SCHEDULED_TASK_LIST_AUTHENTICATION=To see the list of \
 scheduled tasks you must provide authentication.
INFO_CTRL_PANEL_CANCEL_TASK_MSG=Are you sure you want to cancel the \
 selected tasks?
INFO_CTRL_PANEL_CANCEL_TASK_DESCRIPTION=Cancel Selected Tasks.
INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_CANCEL_TASK=Equivalent command-line to \
 cancel task '%s':
INFO_CTRL_PANEL_TASK_CANCELABLE=Is Cancelable
INFO_CTRL_PANEL_CANCELING_TASK_SUMMARY=Canceling Tasks...
INFO_CTRL_PANEL_CANCELING_TASK_COMPLETE=The tasks were successfully \
 canceled.
INFO_CTRL_PANEL_CANCELING_TASK_SUCCESSFUL=The tasks were successfully \
 canceled.
MILD_ERR_CTRL_PANEL_CANCELING_TASK_ERROR_SUMMARY=Error canceling task
MILD_ERR_CTRL_PANEL_CANCELING_TASK_ERROR_DETAILS=An error occurred \
 canceling the selected tasks.
INFO_CTRL_PANEL_CANCEL_TASK_TITLE=Cancel Tasks
INFO_CTRL_PANEL_TASK_IS_CANCELABLE=Cancelable
INFO_CTRL_PANEL_TASK_IS_NOT_CANCELABLE=Not Cancelable
INFO_CTRL_PANEL_MANAGE_TASKS=Manage Tasks
INFO_CTRL_PANEL_CHANGE_SCHEDULE=Change...
INFO_CTRL_PANEL_LAUNCH_NOW_SUMMARY=Launch now
INFO_CTRL_PANEL_LAUNCH_LATER_SUMMARY=Launch on %s
INFO_CTRL_PANEL_LAUNCH_PERIODICALLY_SUMMARY=Launch periodically with CRON \
 schedule '%s'
MILD_ERR_CTRL_PANEL_LAUNCH_LATER_REQUIRES_SERVER_RUNNING=To be able to launch \
 tasks on a future date, the server must be running.
MILD_ERR_CTRL_PANEL_LAUNCH_SCHEDULE_REQUIRES_SERVER_RUNNING=To be able to \
 launch tasks periodically, the server must be running.
INFO_CTRL_PANEL_TASK_SPECIFIC_DETAILS=Task Specific Details
INFO_CTRL_PANEL_NO_TASK_SELECTED=-No Task Selected-
INFO_CTRL_PANEL_MULTIPLE_TASKS_SELECTED=-Multiple Tasks Selected-
INFO_CTRL_PANEL_NO_TASK_SPECIFIC_DETAILS=-No Task Specific Details-
opends/src/server/org/opends/server/backends/task/RecurringTask.java
@@ -521,7 +521,7 @@
   *         the schedule field.
   * @throws IllegalArgumentException if tab field is invalid.
   */
  private boolean[] parseTaskTabField(String tabField,
  public static boolean[] parseTaskTabField(String tabField,
    int minValue, int maxValue) throws IllegalArgumentException
  {
    boolean[] valueList = new boolean[maxValue + 1];
opends/src/server/org/opends/server/tools/tasks/TaskEntry.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.tools.tasks;
@@ -66,6 +66,7 @@
  private static Map<String, Message> mapAttrToDisplayName =
          new HashMap<String, Message>();
  private int hashCode;
  // These attributes associated with the ds-task object
  // class are all handled explicitly below in the constructor
@@ -154,6 +155,68 @@
        }
      }
    }
    hashCode += id.hashCode();
    hashCode += className.hashCode();
    hashCode += state.hashCode();
    hashCode += schedStart.hashCode();
    hashCode += actStart.hashCode();
    hashCode += compTime.hashCode();
    hashCode += depends.hashCode();
    hashCode += depFailAct.hashCode();
    hashCode += logs.hashCode();
    hashCode += notifyErr.hashCode();
    hashCode += notifyComp.hashCode();
    hashCode += schedTab.hashCode();
    hashCode += taskSpecificAttrValues.hashCode();
  }
  /**
   * Retrieves a hash code for this task entry.
   *
   * @return  The hash code for this task entry.
   */
  @Override()
  public int hashCode()
  {
    return hashCode;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean equals(Object o)
  {
    if (this == o)
    {
      return true;
    }
    if (o == null)
    {
      return false;
    }
    if (! (o instanceof TaskEntry))
    {
      return false;
    }
    TaskEntry e = (TaskEntry) o;
    return e.id.equals(id) &&
    e.className.equals(className) &&
    e.state.equals(state) &&
    e.schedStart.equals(schedStart) &&
    e.actStart.equals(actStart) &&
    e.compTime.equals(compTime) &&
    e.depends.equals(depends) &&
    e.depFailAct.equals(depFailAct) &&
    e.logs.equals(logs) &&
    e.notifyErr.equals(notifyErr) &&
    e.notifyComp.equals(notifyComp) &&
    e.schedTab.equals(schedTab) &&
    e.taskSpecificAttrValues.equals(taskSpecificAttrValues);
  }
  /**
opends/src/server/org/opends/server/util/LDIFReader.java
@@ -1235,7 +1235,7 @@
   * @return A new attribute with no values, representing the
   *         attribute type and its options.
   */
  private static Attribute parseAttrDescription(String attrDescr)
  public static Attribute parseAttrDescription(String attrDescr)
  {
    AttributeBuilder builder;
    int semicolonPos = attrDescr.indexOf(';');