/* * 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 2008-2009 Sun Microsystems, Inc. */ package org.opends.server.tools.tasks; import org.opends.messages.Message; import org.opends.server.backends.task.Task; import org.opends.server.backends.task.TaskState; import org.opends.server.backends.task.FailedDependencyAction; import org.opends.server.types.Entry; import org.opends.server.types.AttributeType; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeValue; import org.opends.server.types.DN; import static org.opends.server.util.ServerConstants.*; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.HashSet; import java.util.List; import java.util.ArrayList; import java.util.TimeZone; import java.util.Date; import java.util.Collections; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.text.DateFormat; import java.text.ParseException; /** * Processes information from a task entry from the directory and * provides accessors for attribute information. In some cases the * data is formatted into more human-friendly formats. */ public class TaskEntry { private static Map<String, Message> mapClassToTypeName = new HashMap<String, Message>(); 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 private static Set<String> supAttrNames = new HashSet<String>(); static { supAttrNames.add("ds-task-id"); supAttrNames.add("ds-task-class-name"); supAttrNames.add("ds-task-state"); supAttrNames.add("ds-task-scheduled-start-time"); supAttrNames.add("ds-task-actual-start-time"); supAttrNames.add("ds-task-completion-time"); supAttrNames.add("ds-task-dependency-id"); supAttrNames.add("ds-task-failed-dependency-action"); supAttrNames.add("ds-task-log-message"); supAttrNames.add("ds-task-notify-on-completion"); supAttrNames.add("ds-task-notify-on-error"); supAttrNames.add("ds-recurring-task-id"); supAttrNames.add("ds-recurring-task-schedule"); } private String id; private String className; private String state; private String schedStart; private String actStart; private String compTime; private String schedTab; private List<String> depends; private String depFailAct; private List<String> logs; private List<String> notifyComp; private List<String> notifyErr; private DN dn; /** * Task of the same type that implements. Used for obtaining * task name and attribute display information. */ private Task task; private Map<Message, List<String>> taskSpecificAttrValues = new HashMap<Message, List<String>>(); /** * Creates a parameterized instance. * * @param entry to wrap */ public TaskEntry(Entry entry) { dn = entry.getDN(); String p = "ds-task-"; id = getSingleStringValue(entry, p + "id"); className = getSingleStringValue(entry, p + "class-name"); state = getSingleStringValue(entry, p + "state"); schedStart = getSingleStringValue(entry, p + "scheduled-start-time"); actStart = getSingleStringValue(entry, p + "actual-start-time"); compTime = getSingleStringValue(entry, p + "completion-time"); depends = getMultiStringValue(entry, p + "dependency-id"); depFailAct = getSingleStringValue(entry, p + "failed-dependency-action"); logs = getMultiStringValue(entry, p + "log-message"); notifyErr = getMultiStringValue(entry, p + "notify-on-error"); notifyComp = getMultiStringValue(entry, p + "notify-on-completion"); schedTab = getSingleStringValue(entry, "ds-recurring-task-schedule"); // Build a map of non-superior attribute value pairs for display Map<AttributeType, List<Attribute>> attrMap = entry.getUserAttributes(); for (AttributeType type : attrMap.keySet()) { String typeName = type.getNormalizedPrimaryName(); // See if we've handled it already above if (!supAttrNames.contains(typeName)) { Message attrTypeName = getAttributeDisplayName( type.getNormalizedPrimaryName()); List<Attribute> attrList = entry.getUserAttribute(type); for (Attribute attr : attrList) { for (AttributeValue av : attr) { List<String> valueList = taskSpecificAttrValues.get(attrTypeName); if (valueList == null) { valueList = new ArrayList<String>(); taskSpecificAttrValues.put(attrTypeName, valueList); } valueList.add(av.getValue().toString()); } } } } 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); } /** * Gets the DN of the wrapped entry. * * @return DN of entry */ public DN getDN() { return dn; } /** * Gets the ID of the task. * * @return String ID of the task */ public String getId() { return id; } /** * Gets the name of the class implementing the task represented here. * * @return String name of class */ public String getClassName() { return className; } /** * Gets the state of the task. * * @return Message representing state */ public Message getState() { Message m = Message.EMPTY; if (state != null) { TaskState ts = TaskState.fromString(state); if (ts != null) { m = ts.getDisplayName(); } } return m; } /** * Gets the human-friendly scheduled time. * * @return String time */ public Message getScheduledStartTime() { return formatTimeString(schedStart); } /** * Gets the human-friendly start time. * * @return String time */ public Message getActualStartTime() { return formatTimeString(actStart); } /** * Gets the human-friendly completion time. * * @return String time */ public Message getCompletionTime() { return formatTimeString(compTime); } /** * Gets recurring schedule tab. * * @return Message tab string */ public Message getScheduleTab() { return Message.raw(schedTab); } /** * Gets the IDs of tasks upon which this task depends. * * @return array of IDs */ public List<String> getDependencyIds() { return Collections.unmodifiableList(depends); } /** * Gets the action to take if this task fails. * * @return String action */ public Message getFailedDependencyAction() { Message m = null; if (depFailAct != null) { FailedDependencyAction fda = FailedDependencyAction.fromString(depFailAct); if (fda != null) { m = fda.getDisplayName(); } } return m; } /** * Gets the logs associated with this task's execution. * * @return array of log messages */ public List<Message> getLogMessages() { List<Message> formattedLogs = new ArrayList<Message>(); for (String aLog : logs) { formattedLogs.add(Message.raw(aLog)); } return Collections.unmodifiableList(formattedLogs); } /** * Gets the email messages that will be used for notifications * when the task completes. * * @return array of email addresses */ public List<String> getCompletionNotificationEmailAddresses() { return Collections.unmodifiableList(notifyComp); } /** * Gets the email messages that will be used for notifications * when the task encounters an error. * * @return array of email addresses */ public List<String> getErrorNotificationEmailAddresses() { return Collections.unmodifiableList(notifyErr); } /** * Gets a user presentable string indicating the type of this task. * * @return Message type */ public Message getType() { Message type = Message.EMPTY; if (className != null) { type = mapClassToTypeName.get(className); if (type == null) { Task task = getTask(); if (task != null) { try { Method m = Task.class.getMethod("getDisplayName"); Object oName = m.invoke(task); if (oName instanceof Message) { mapClassToTypeName.put(className, (Message) oName); type = (Message) oName; } } catch (Exception e) { // ignore; this is best effort } } } // If we still can't get the type just resort // to the class displayName if (type == null) { type = Message.raw(className); } } return type; } /** * Indicates whether or not this task supports a cancel operation. * * @return boolean where true means this task supports being canceled. */ public boolean isCancelable() { boolean cancelable = false; TaskState state = getTaskState(); if (state != null) { Task task = getTask(); cancelable = (TaskState.isPending(state) || TaskState.isRecurring(state) || (TaskState.isRunning(state) && task != null && task.isInterruptable())); } return cancelable; } /** * Gets a mapping of attributes that are specific to the implementing * task as opposed to the superior, or base, task. * * @return mapping of atribute field labels to lists of string values for * each field. */ public Map<Message, List<String>> getTaskSpecificAttributeValuePairs() { return taskSpecificAttrValues; } /** * Gets the task state. * * @return TaskState of task */ public TaskState getTaskState() { TaskState ts = null; if (state != null) { ts = TaskState.fromString(state); } return ts; } /** * Indicates whether or not this task is done. * * @return boolean where true means this task is done */ public boolean isDone() { TaskState ts = getTaskState(); return ts != null && TaskState.isDone(ts); } private String getSingleStringValue(Entry entry, String attrName) { List<Attribute> attrList = entry.getAttribute(attrName); if (attrList != null && attrList.size() == 1) { Attribute attr = attrList.get(0); if (!attr.isEmpty()) { return attr.iterator().next().getValue().toString(); } } return ""; } private List<String> getMultiStringValue(Entry entry, String attrName) { List<String> valuesList = new ArrayList<String>(); List<Attribute> attrList = entry.getAttribute(attrName); if (attrList != null) { for (Attribute attr : attrList) { for (AttributeValue value : attr) { valuesList.add(value.getValue().toString()); } } } return valuesList; } private Message getAttributeDisplayName(String attrName) { Message name = mapAttrToDisplayName.get(attrName); if (name == null) { Task task = getTask(); if (task != null) { try { Method m = Task.class.getMethod( "getAttributeDisplayName", String.class); Object o = m.invoke(task, attrName); if (o != null && Message.class.isAssignableFrom(o.getClass())) { name= (Message)o; mapAttrToDisplayName.put(attrName, name); } } catch (Exception e) { // ignore } } } if (name == null) { name = Message.raw(attrName); } return name; } /** * Formats a time string into a human friendly format. * @param timeString the is human hostile * @return string of time that is human friendly */ private Message formatTimeString(String timeString) { Message ret = Message.EMPTY; if (timeString != null && timeString.length() > 0) { try { SimpleDateFormat dateFormat; if (timeString.endsWith("Z")) { dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); } else { dateFormat = new SimpleDateFormat(DATE_FORMAT_COMPACT_LOCAL_TIME); } Date date = dateFormat.parse(timeString); DateFormat df = DateFormat.getDateTimeInstance( DateFormat.MEDIUM, DateFormat.LONG); String dateString = df.format(date); ret = Message.raw(dateString); } catch (ParseException pe){ ret = Message.raw(timeString); } } return ret; } private Task getTask() { if (task == null && className != null) { try { Class<?> clazz = Class.forName(className); Object o = clazz.newInstance(); if (Task.class.isAssignableFrom(o.getClass())) { this.task = (Task) o; } } catch (Exception e) { // ignore; this is best effort } } return task; } }