001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.guitools.controlpanel.datamodel;
028
029import static org.forgerock.util.Utils.*;
030import static org.opends.messages.AdminToolMessages.*;
031import static org.opends.messages.ToolMessages.*;
032
033import java.util.ArrayList;
034import java.util.Comparator;
035import java.util.HashSet;
036import java.util.LinkedHashSet;
037import java.util.List;
038import java.util.Set;
039import java.util.TreeSet;
040
041import org.opends.guitools.controlpanel.ui.ColorAndFontConstants;
042import org.opends.guitools.controlpanel.util.Utilities;
043import org.forgerock.i18n.LocalizableMessage;
044import org.opends.server.backends.task.TaskState;
045import org.opends.server.tools.tasks.TaskEntry;
046
047/**
048 * The table used to display the tasks.
049 *
050 */
051public class TaskTableModel  extends SortableTableModel
052implements Comparator<TaskEntry>
053{
054  private static final long serialVersionUID = -351142550147124L;
055  private Set<TaskEntry> data = new HashSet<>();
056  private ArrayList<TaskEntry> dataSourceArray = new ArrayList<>();
057
058  LinkedHashSet<LocalizableMessage> displayedAttributes = new LinkedHashSet<>();
059  final LinkedHashSet<LocalizableMessage> defaultAttributes = new LinkedHashSet<>();
060  {
061    defaultAttributes.add(INFO_TASKINFO_FIELD_ID.get());
062    defaultAttributes.add(INFO_TASKINFO_FIELD_TYPE.get());
063    defaultAttributes.add(INFO_TASKINFO_FIELD_STATUS.get());
064    defaultAttributes.add(INFO_CTRL_PANEL_TASK_CANCELABLE.get());
065  }
066  LinkedHashSet<LocalizableMessage> allAttributes = new LinkedHashSet<>();
067  {
068    allAttributes.addAll(defaultAttributes);
069    allAttributes.add(INFO_TASKINFO_FIELD_SCHEDULED_START.get());
070    allAttributes.add(INFO_TASKINFO_FIELD_ACTUAL_START.get());
071    allAttributes.add(INFO_TASKINFO_FIELD_COMPLETION_TIME.get());
072    allAttributes.add(INFO_TASKINFO_FIELD_DEPENDENCY.get());
073    allAttributes.add(INFO_TASKINFO_FIELD_FAILED_DEPENDENCY_ACTION.get());
074    allAttributes.add(INFO_TASKINFO_FIELD_NOTIFY_ON_COMPLETION.get());
075    allAttributes.add(INFO_TASKINFO_FIELD_NOTIFY_ON_ERROR.get());
076  }
077
078  private String[] columnNames = {};
079
080  /**
081   * The sort column of the table.
082   */
083  private int sortColumn;
084  /**
085   * Whether the sorting is ascending or descending.
086   */
087  private boolean sortAscending = true;
088
089  /**
090   * Default constructor.
091   */
092  public TaskTableModel()
093  {
094    super();
095    setAttributes(defaultAttributes);
096  }
097
098  /**
099   * Sets the data for this table model.
100   * @param newData the data for this table model.
101   */
102  public void setData(Set<TaskEntry> newData)
103  {
104    if (!newData.equals(data))
105    {
106      data.clear();
107      data.addAll(newData);
108      updateDataArray();
109      fireTableDataChanged();
110    }
111  }
112
113  /**
114   * Updates the table model contents and sorts its contents depending on the
115   * sort options set by the user.
116   */
117  public void forceResort()
118  {
119    updateDataArray();
120    fireTableDataChanged();
121  }
122
123  /**
124   * Updates the table model contents, sorts its contents depending on the
125   * sort options set by the user and updates the column structure.
126   */
127  public void forceDataStructureChange()
128  {
129    updateDataArray();
130    fireTableStructureChanged();
131    fireTableDataChanged();
132  }
133
134  /**
135   * Updates the array data.  This includes resorting it.
136   */
137  private void updateDataArray()
138  {
139    TreeSet<TaskEntry> sortedSet = new TreeSet<>(this);
140    sortedSet.addAll(data);
141    dataSourceArray.clear();
142    dataSourceArray.addAll(sortedSet);
143  }
144
145  /**
146   * Sets the operations displayed by this table model.
147   * @param attributes the attributes displayed by this table model.
148   */
149  public void setAttributes(LinkedHashSet<LocalizableMessage> attributes)
150  {
151    if (!allAttributes.containsAll(attributes))
152    {
153      throw new IllegalArgumentException(
154          "Some of the provided attributes are not valid.");
155    }
156    this.displayedAttributes.clear();
157    this.displayedAttributes.addAll(attributes);
158    int columnCount = attributes.size();
159    columnNames = new String[columnCount];
160    int i = 0;
161    for (LocalizableMessage attribute : attributes)
162    {
163      columnNames[i] = getHeader(attribute, 15);
164      i++;
165    }
166  }
167
168  /** {@inheritDoc} */
169  public Class<?> getColumnClass(int column)
170  {
171    return LocalizableMessage.class;
172  }
173
174  /** {@inheritDoc} */
175  public String getColumnName(int col) {
176    return columnNames[col];
177  }
178
179  /** {@inheritDoc} */
180  public Object getValueAt(int row, int column)
181  {
182    LocalizableMessage value;
183    column = getFixedOrderColumn(column);
184    TaskEntry taskEntry = get(row);
185    switch (column)
186    {
187    case 0:
188      return LocalizableMessage.raw(taskEntry.getId());
189    case 1:
190      return taskEntry.getType();
191    case 2:
192      return taskEntry.getState();
193    case 3:
194      return taskEntry.isCancelable()
195          ? INFO_CTRL_PANEL_TASK_IS_CANCELABLE.get()
196          : INFO_CTRL_PANEL_TASK_IS_NOT_CANCELABLE.get();
197    case 4:
198      if (TaskState.isRecurring(get(row).getTaskState()))
199      {
200        return taskEntry.getScheduleTab();
201      }
202
203      value = taskEntry.getScheduledStartTime();
204      if (value == null || value.equals(LocalizableMessage.EMPTY))
205      {
206        return INFO_TASKINFO_IMMEDIATE_EXECUTION.get();
207      }
208      return value;
209    case 5:
210      return taskEntry.getActualStartTime();
211    case 6:
212      return taskEntry.getCompletionTime();
213    case 7:
214      return getValue(taskEntry.getDependencyIds(),
215          INFO_TASKINFO_NONE_SPECIFIED.get());
216    case 8:
217      value = taskEntry.getFailedDependencyAction();
218      if (value != null)
219      {
220        return value;
221      }
222      return INFO_TASKINFO_NONE.get();
223    case 9:
224      return getValue(taskEntry.getCompletionNotificationEmailAddresses(),
225          INFO_TASKINFO_NONE_SPECIFIED.get());
226    case 10:
227      return getValue(taskEntry.getErrorNotificationEmailAddresses(),
228          INFO_TASKINFO_NONE_SPECIFIED.get());
229    default:
230      throw new IllegalArgumentException("Invalid column: "+column);
231    }
232  }
233
234  /**
235   * Returns the row count.
236   * @return the row count.
237   */
238  public int getRowCount()
239  {
240    return dataSourceArray.size();
241  }
242
243  /**
244   * Returns the column count.
245   * @return the column count.
246   */
247  public int getColumnCount()
248  {
249    return columnNames.length;
250  }
251
252  /**
253   * Gets the TaskDescriptor in a given row.
254   * @param row the row.
255   * @return the TaskDescriptor in a given row.
256   */
257  public TaskEntry get(int row)
258  {
259    return dataSourceArray.get(row);
260  }
261
262  /**
263   * Returns the set of attributes ordered.
264   * @return the set of attributes ordered.
265   */
266  public LinkedHashSet<LocalizableMessage> getDisplayedAttributes()
267  {
268    return displayedAttributes;
269  }
270
271  /**
272   * Returns the set of attributes ordered.
273   * @return the set of attributes ordered.
274   */
275  public LinkedHashSet<LocalizableMessage> getAllAttributes()
276  {
277    return allAttributes;
278  }
279
280  /** {@inheritDoc} */
281  public int compare(TaskEntry desc1, TaskEntry desc2)
282  {
283    int result;
284    ArrayList<Integer> possibleResults = new ArrayList<>();
285
286    possibleResults.add(desc1.getId().compareTo(desc2.getId()));
287    possibleResults.add(desc1.getType().compareTo(desc2.getType()));
288    possibleResults.add(desc1.getState().compareTo(desc2.getState()));
289    possibleResults.add(String.valueOf(desc1.isCancelable()).compareTo(
290        String.valueOf(desc2.isCancelable())));
291
292    result = possibleResults.get(getSortColumn());
293    if (result == 0)
294    {
295      for (int i : possibleResults)
296      {
297        if (i != 0)
298        {
299          result = i;
300          break;
301        }
302      }
303    }
304    if (!isSortAscending())
305    {
306      result = -result;
307    }
308    return result;
309  }
310
311  /**
312   * Returns whether the sort is ascending or descending.
313   * @return <CODE>true</CODE> if the sort is ascending and <CODE>false</CODE>
314   * otherwise.
315   */
316  public boolean isSortAscending()
317  {
318    return sortAscending;
319  }
320
321  /**
322   * Sets whether to sort ascending of descending.
323   * @param sortAscending whether to sort ascending or descending.
324   */
325  public void setSortAscending(boolean sortAscending)
326  {
327    this.sortAscending = sortAscending;
328  }
329
330  /**
331   * Returns the column index used to sort.
332   * @return the column index used to sort.
333   */
334  public int getSortColumn()
335  {
336    return sortColumn;
337  }
338
339  /**
340   * Sets the column index used to sort.
341   * @param sortColumn column index used to sort..
342   */
343  public void setSortColumn(int sortColumn)
344  {
345    this.sortColumn = sortColumn;
346  }
347
348  private int getFixedOrderColumn(int column)
349  {
350    int fixedOrderColumn = 0;
351    int i=0;
352    LocalizableMessage colMsg = null;
353    for (LocalizableMessage msg : displayedAttributes)
354    {
355      if (i == column)
356      {
357        colMsg = msg;
358        break;
359      }
360      i++;
361    }
362    for (LocalizableMessage msg : allAttributes)
363    {
364      if (msg.equals(colMsg))
365      {
366        break;
367      }
368      fixedOrderColumn++;
369    }
370    return fixedOrderColumn;
371  }
372
373  private LocalizableMessage getValue(List<String> values, LocalizableMessage valueIfEmpty)
374  {
375    LocalizableMessage msg;
376    if (values.isEmpty())
377    {
378      msg = valueIfEmpty;
379    }
380    else
381    {
382      String s = joinAsString("<br>", values);
383      if (values.size() > 1)
384      {
385        msg = LocalizableMessage.raw(
386            "<html>"+Utilities.applyFont(s, ColorAndFontConstants.tableFont));
387      }
388      else
389      {
390        msg = LocalizableMessage.raw(s);
391      }
392    }
393    return msg;
394  }
395}