| package autotest.afe; |
| |
| import autotest.afe.create.CreateJobViewPresenter.JobCreateListener; |
| import autotest.common.CustomHistory.HistoryToken; |
| import autotest.common.SimpleCallback; |
| import autotest.common.Utils; |
| import autotest.common.table.DataSource; |
| import autotest.common.table.DataSource.DataCallback; |
| import autotest.common.table.DataSource.Query; |
| import autotest.common.table.DataSource.SortDirection; |
| import autotest.common.table.DataTable; |
| import autotest.common.table.DatetimeSegmentFilter; |
| import autotest.common.table.DynamicTable; |
| import autotest.common.table.DynamicTable.DynamicTableListener; |
| import autotest.common.table.JSONObjectSet; |
| import autotest.common.table.RpcDataSource; |
| import autotest.common.table.SelectionManager; |
| import autotest.common.table.SimpleFilter; |
| import autotest.common.table.TableDecorator; |
| import autotest.common.ui.ContextMenu; |
| import autotest.common.ui.DetailView; |
| import autotest.common.ui.NotifyManager; |
| import autotest.common.ui.TableActionsPanel.TableActionsListener; |
| |
| import com.google.gwt.event.dom.client.ClickEvent; |
| import com.google.gwt.event.dom.client.ClickHandler; |
| import com.google.gwt.event.dom.client.KeyCodes; |
| import com.google.gwt.event.dom.client.KeyPressEvent; |
| import com.google.gwt.event.dom.client.KeyPressHandler; |
| import com.google.gwt.event.logical.shared.ValueChangeEvent; |
| import com.google.gwt.event.logical.shared.ValueChangeHandler; |
| import com.google.gwt.json.client.JSONArray; |
| import com.google.gwt.json.client.JSONBoolean; |
| import com.google.gwt.json.client.JSONNumber; |
| import com.google.gwt.json.client.JSONObject; |
| import com.google.gwt.json.client.JSONString; |
| import com.google.gwt.json.client.JSONValue; |
| import com.google.gwt.user.client.Command; |
| import com.google.gwt.user.client.ui.Button; |
| import com.google.gwt.user.client.ui.CheckBox; |
| import com.google.gwt.user.client.ui.TextBox; |
| |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| public class HostDetailView extends DetailView implements DataCallback, TableActionsListener { |
| private static final String[][] HOST_JOBS_COLUMNS = { |
| {DataTable.WIDGET_COLUMN, ""}, {"type", "Type"}, {"job__id", "Job ID"}, |
| {"job_owner", "Job Owner"}, {"job_name", "Job Name"}, {"started_on", "Time started"}, |
| {"status", "Status"} |
| }; |
| public static final int JOBS_PER_PAGE = 20; |
| |
| public interface HostDetailListener { |
| public void onJobSelected(int jobId); |
| } |
| |
| private static class HostQueueEntryDataSource extends RpcDataSource { |
| public HostQueueEntryDataSource() { |
| super("get_host_queue_entries", "get_num_host_queue_entries"); |
| } |
| |
| @Override |
| protected List<JSONObject> handleJsonResult(JSONValue result) { |
| List<JSONObject> resultArray = super.handleJsonResult(result); |
| for (JSONObject row : resultArray) { |
| // get_host_queue_entries() doesn't return type, so fill it in for consistency with |
| // get_host_queue_entries_and_special_tasks() |
| row.put("type", new JSONString("Job")); |
| } |
| return resultArray; |
| } |
| } |
| |
| private static class HostJobsTable extends DynamicTable { |
| private static final DataSource normalDataSource = new HostQueueEntryDataSource(); |
| private static final DataSource dataSourceWithSpecialTasks = |
| new RpcDataSource("get_host_queue_entries_and_special_tasks", |
| "get_num_host_queue_entries_and_special_tasks"); |
| |
| private SimpleFilter hostFilter = new SimpleFilter(); |
| private String hostId; |
| private String startTime; |
| private String endTime; |
| |
| public HostJobsTable() { |
| super(HOST_JOBS_COLUMNS, normalDataSource); |
| addFilter(hostFilter); |
| } |
| |
| public void setHostId(String hostId) { |
| this.hostId = hostId; |
| updateFilter(); |
| } |
| |
| public void setStartTime(String startTime) { |
| this.startTime = startTime; |
| updateFilter(); |
| } |
| |
| public void setEndTime(String endTime) { |
| this.endTime = endTime; |
| updateFilter(); |
| } |
| |
| private void updateFilter() { |
| if (getDataSource() == normalDataSource) { |
| sortOnColumn("job__id", SortDirection.DESCENDING); |
| } else { |
| clearSorts(); |
| } |
| |
| hostFilter.clear(); |
| hostFilter.setParameter("host", |
| new JSONNumber(Double.parseDouble(hostId))); |
| if (startTime != null && startTime != "") |
| hostFilter.setParameter("start_time", new JSONString(startTime)); |
| if (endTime != null && endTime != "") |
| hostFilter.setParameter("end_time", new JSONString(endTime)); |
| } |
| |
| public void setSpecialTasksEnabled(boolean enabled) { |
| if (enabled) { |
| setDataSource(dataSourceWithSpecialTasks); |
| } else { |
| setDataSource(normalDataSource); |
| } |
| |
| updateFilter(); |
| } |
| |
| @Override |
| protected void preprocessRow(JSONObject row) { |
| JSONObject job = row.get("job").isObject(); |
| JSONString blank = new JSONString(""); |
| JSONString jobId = blank, owner = blank, name = blank; |
| if (job != null) { |
| int id = (int) job.get("id").isNumber().doubleValue(); |
| jobId = new JSONString(Integer.toString(id)); |
| owner = job.get("owner").isString(); |
| name = job.get("name").isString(); |
| } |
| |
| row.put("job__id", jobId); |
| row.put("job_owner", owner); |
| row.put("job_name", name); |
| } |
| } |
| |
| private String hostname = ""; |
| private String hostId = ""; |
| private DataSource hostDataSource = new HostDataSource(); |
| private HostJobsTable jobsTable = new HostJobsTable(); |
| private TableDecorator tableDecorator = new TableDecorator(jobsTable); |
| private HostDetailListener hostDetailListener = null; |
| private JobCreateListener jobCreateListener = null; |
| private SelectionManager selectionManager; |
| |
| private JSONObject currentHostObject; |
| |
| private Button lockButton = new Button(); |
| private Button reverifyButton = new Button("Reverify"); |
| private Button repairButton = new Button("Repair"); |
| private CheckBox showSpecialTasks = new CheckBox(); |
| private DatetimeSegmentFilter startedTimeFilter = new DatetimeSegmentFilter(); |
| private TextBox hostnameInput = new TextBox(); |
| private Button hostnameFetchButton = new Button("Go"); |
| private TextBox lockReasonInput = new TextBox(); |
| |
| public HostDetailView(HostDetailListener hostDetailListener, |
| JobCreateListener jobCreateListener) { |
| this.hostDetailListener = hostDetailListener; |
| this.jobCreateListener = jobCreateListener; |
| } |
| |
| @Override |
| public String getElementId() { |
| return "view_host"; |
| } |
| |
| @Override |
| protected String getFetchControlsElementId() { |
| return "view_host_fetch_controls"; |
| } |
| |
| private String getFetchByHostnameControlsElementId() { |
| return "view_host_fetch_by_hostname_controls"; |
| } |
| |
| @Override |
| protected String getDataElementId() { |
| return "view_host_data"; |
| } |
| |
| @Override |
| protected String getTitleElementId() { |
| return "view_host_title"; |
| } |
| |
| @Override |
| protected String getNoObjectText() { |
| return "No host selected"; |
| } |
| |
| @Override |
| protected String getObjectId() { |
| return hostId; |
| } |
| |
| protected String getHostname() { |
| return hostname; |
| } |
| |
| @Override |
| protected void setObjectId(String id) { |
| if (id.length() == 0) { |
| throw new IllegalArgumentException(); |
| } |
| this.hostId = id; |
| } |
| |
| @Override |
| protected void fetchData() { |
| JSONObject params = new JSONObject(); |
| params.put("id", new JSONString(getObjectId())); |
| fetchDataCommmon(params); |
| } |
| |
| private void fetchDataByHostname(String hostname) { |
| JSONObject params = new JSONObject(); |
| params.put("hostname", new JSONString(hostname)); |
| fetchDataCommmon(params); |
| } |
| |
| private void fetchDataCommmon(JSONObject params) { |
| params.put("valid_only", JSONBoolean.getInstance(false)); |
| hostDataSource.query(params, this); |
| } |
| |
| private void fetchByHostname(String hostname) { |
| fetchDataByHostname(hostname); |
| updateHistory(); |
| } |
| |
| @Override |
| public void handleTotalResultCount(int totalCount) {} |
| |
| @Override |
| public void onQueryReady(Query query) { |
| query.getPage(null, null, null, this); |
| } |
| |
| public void handlePage(List<JSONObject> data) { |
| try { |
| currentHostObject = Utils.getSingleObjectFromList(data); |
| } |
| catch (IllegalArgumentException exc) { |
| NotifyManager.getInstance().showError("No such host found"); |
| resetPage(); |
| return; |
| } |
| |
| setObjectId(currentHostObject.get("id").toString()); |
| |
| String lockedText = Utils.jsonToString(currentHostObject.get(HostDataSource.LOCKED_TEXT)); |
| if (currentHostObject.get("locked").isBoolean().booleanValue()) { |
| String lockedBy = Utils.jsonToString(currentHostObject.get("locked_by")); |
| String lockedTime = Utils.jsonToString(currentHostObject.get("lock_time")); |
| String lockReasonText = Utils.jsonToString(currentHostObject.get("lock_reason")); |
| lockedText += ", by " + lockedBy + " on " + lockedTime; |
| lockedText += ", reason: " + lockReasonText; |
| } |
| |
| showField(currentHostObject, "status", "view_host_status"); |
| showField(currentHostObject, "platform", "view_host_platform"); |
| showField(currentHostObject, HostDataSource.HOST_ACLS, "view_host_acls"); |
| showField(currentHostObject, HostDataSource.OTHER_LABELS, "view_host_labels"); |
| showText(lockedText, "view_host_locked"); |
| String shard_url = Utils.jsonToString(currentHostObject.get("shard")).trim(); |
| String host_id = Utils.jsonToString(currentHostObject.get("id")).trim(); |
| if (shard_url.equals("<null>")){ |
| shard_url = ""; |
| } else { |
| shard_url = "http://" + shard_url; |
| } |
| shard_url = shard_url + "/afe/#tab_id=view_host&object_id=" + host_id; |
| showField(currentHostObject, "shard", "view_host_shard"); |
| getElementById("view_host_shard").setAttribute("href", shard_url); |
| |
| String job_id = Utils.jsonToString(currentHostObject.get("current_job")).trim(); |
| if (!job_id.equals("<null>")){ |
| String job_url = "#tab_id=view_job&object_id=" + job_id; |
| showField(currentHostObject, "current_job", "view_host_current_job"); |
| getElementById("view_host_current_job").setAttribute("href", job_url); |
| } |
| hostname = currentHostObject.get("hostname").isString().stringValue(); |
| |
| String task = Utils.jsonToString(currentHostObject.get("current_special_task")).trim(); |
| if (!task.equals("<null>")){ |
| String task_url = Utils.getRetrieveLogsUrl("hosts/" + hostname + "/" + task); |
| showField(currentHostObject, "current_special_task", "view_host_current_special_task"); |
| getElementById("view_host_current_special_task").setAttribute("href", task_url); |
| } |
| |
| showField(currentHostObject, "protection", "view_host_protection"); |
| String pageTitle = "Host " + hostname; |
| hostnameInput.setText(hostname); |
| hostnameInput.setWidth("240px"); |
| updateLockButton(); |
| updateLockReasonInput(); |
| displayObjectData(pageTitle); |
| |
| jobsTable.setHostId(getObjectId()); |
| jobsTable.refresh(); |
| } |
| |
| @Override |
| public void initialize() { |
| super.initialize(); |
| |
| // Replace fetch by id with fetch by hostname |
| addWidget(hostnameInput, getFetchByHostnameControlsElementId()); |
| addWidget(hostnameFetchButton, getFetchByHostnameControlsElementId()); |
| |
| hostnameInput.addKeyPressHandler(new KeyPressHandler() { |
| public void onKeyPress (KeyPressEvent event) { |
| if (event.getCharCode() == (char) KeyCodes.KEY_ENTER) |
| fetchByHostname(hostnameInput.getText()); |
| } |
| }); |
| hostnameFetchButton.addClickHandler(new ClickHandler() { |
| public void onClick(ClickEvent event) { |
| fetchByHostname(hostnameInput.getText()); |
| } |
| }); |
| |
| jobsTable.setRowsPerPage(JOBS_PER_PAGE); |
| jobsTable.setClickable(true); |
| jobsTable.addListener(new DynamicTableListener() { |
| public void onRowClicked(int rowIndex, JSONObject row, boolean isRightClick) { |
| if (isJobRow(row)) { |
| JSONObject job = row.get("job").isObject(); |
| int jobId = (int) job.get("id").isNumber().doubleValue(); |
| hostDetailListener.onJobSelected(jobId); |
| } else { |
| String resultsPath = Utils.jsonToString(row.get("execution_path")); |
| Utils.openUrlInNewWindow(Utils.getRetrieveLogsUrl(resultsPath)); |
| } |
| } |
| |
| public void onTableRefreshed() {} |
| }); |
| tableDecorator.addPaginators(); |
| selectionManager = tableDecorator.addSelectionManager(false); |
| jobsTable.setWidgetFactory(selectionManager); |
| tableDecorator.addTableActionsPanel(this, true); |
| tableDecorator.addControl("Show verifies, repairs, cleanups and resets", |
| showSpecialTasks); |
| tableDecorator.addFilter("Filter by time started:", |
| startedTimeFilter); |
| addWidget(tableDecorator, "view_host_jobs_table"); |
| |
| showSpecialTasks.addClickHandler(new ClickHandler() { |
| public void onClick(ClickEvent event) { |
| selectionManager.deselectAll(); |
| jobsTable.setSpecialTasksEnabled(showSpecialTasks.getValue()); |
| jobsTable.refresh(); |
| } |
| }); |
| |
| startedTimeFilter.addValueChangeHandler( |
| new ValueChangeHandler() { |
| public void onValueChange(ValueChangeEvent event) { |
| String value = (String) event.getValue(); |
| jobsTable.setStartTime(value); |
| if (value == "") |
| startedTimeFilter.setStartTimeToPlaceHolderValue(); |
| jobsTable.refresh(); |
| } |
| }, |
| new ValueChangeHandler() { |
| public void onValueChange(ValueChangeEvent event) { |
| String value = (String) event.getValue(); |
| jobsTable.setEndTime(value); |
| if (value == "") |
| startedTimeFilter.setEndTimeToPlaceHolderValue(); |
| jobsTable.refresh(); |
| } |
| } |
| ); |
| |
| addWidget(lockButton, "view_host_lock_button"); |
| addWidget(lockReasonInput, "view_host_lock_reason_input"); |
| |
| lockButton.addClickHandler(new ClickHandler() { |
| public void onClick(ClickEvent event) { |
| boolean locked = currentHostObject.get("locked").isBoolean().booleanValue(); |
| changeLock(!locked); |
| } |
| }); |
| lockReasonInput.addKeyPressHandler(new KeyPressHandler() { |
| public void onKeyPress (KeyPressEvent event) { |
| if (event.getCharCode() == (char) KeyCodes.KEY_ENTER) { |
| boolean locked = currentHostObject.get("locked").isBoolean().booleanValue(); |
| changeLock(!locked); |
| } |
| } |
| }); |
| |
| reverifyButton.addClickHandler(new ClickHandler() { |
| public void onClick(ClickEvent event) { |
| JSONObject params = new JSONObject(); |
| |
| params.put("id", currentHostObject.get("id")); |
| AfeUtils.callReverify(params, new SimpleCallback() { |
| public void doCallback(Object source) { |
| refresh(); |
| } |
| }, "Host " + hostname); |
| } |
| }); |
| addWidget(reverifyButton, "view_host_reverify_button"); |
| |
| repairButton.addClickHandler(new ClickHandler() { |
| public void onClick(ClickEvent event) { |
| JSONObject params = new JSONObject(); |
| |
| params.put("id", currentHostObject.get("id")); |
| AfeUtils.callRepair(params, new SimpleCallback() { |
| public void doCallback(Object source) { |
| refresh(); |
| } |
| }, "Host " + hostname); |
| } |
| }); |
| addWidget(repairButton, "view_host_repair_button"); |
| } |
| |
| public void onError(JSONObject errorObject) { |
| // RPC handler will display error |
| } |
| |
| public ContextMenu getActionMenu() { |
| ContextMenu menu = new ContextMenu(); |
| menu.addItem("Abort", new Command() { |
| public void execute() { |
| abortSelectedQueueEntriesAndSpecialTasks(); |
| } |
| }); |
| if (selectionManager.isEmpty()) |
| menu.setEnabled(false); |
| return menu; |
| } |
| |
| private void abortSelectedQueueEntriesAndSpecialTasks() { |
| Set<JSONObject> selectedEntries = selectionManager.getSelectedObjects(); |
| Set<JSONObject> selectedQueueEntries = new JSONObjectSet<JSONObject>(); |
| JSONArray selectedSpecialTaskIds = new JSONArray(); |
| for (JSONObject entry : selectedEntries) { |
| if (isJobRow(entry)) |
| selectedQueueEntries.add(entry); |
| else |
| selectedSpecialTaskIds.set(selectedSpecialTaskIds.size(), |
| entry.get("oid")); |
| } |
| if (!selectedQueueEntries.isEmpty()) { |
| AfeUtils.abortHostQueueEntries(selectedQueueEntries, new SimpleCallback() { |
| public void doCallback(Object source) { |
| refresh(); |
| } |
| }); |
| } |
| if (selectedSpecialTaskIds.size() > 0) { |
| AfeUtils.abortSpecialTasks(selectedSpecialTaskIds, new SimpleCallback() { |
| public void doCallback(Object source) { |
| refresh(); |
| } |
| }); |
| } |
| } |
| |
| private void updateLockButton() { |
| boolean locked = currentHostObject.get("locked").isBoolean().booleanValue(); |
| if (locked) { |
| lockButton.setText("Unlock"); |
| } else { |
| lockButton.setText("Lock"); |
| } |
| } |
| |
| private void updateLockReasonInput() { |
| boolean locked = currentHostObject.get("locked").isBoolean().booleanValue(); |
| if (locked) { |
| lockReasonInput.setText(""); |
| lockReasonInput.setEnabled(false); |
| } else { |
| lockReasonInput.setEnabled(true); |
| } |
| } |
| |
| private void changeLock(final boolean lock) { |
| JSONArray hostIds = new JSONArray(); |
| hostIds.set(0, currentHostObject.get("id")); |
| |
| AfeUtils.changeHostLocks(hostIds, lock, lockReasonInput.getText(), |
| "Host " + hostname, new SimpleCallback() { |
| public void doCallback(Object source) { |
| refresh(); |
| } |
| }); |
| } |
| |
| private boolean isJobRow(JSONObject row) { |
| String type = Utils.jsonToString(row.get("type")); |
| return type.equals("Job"); |
| } |
| |
| public boolean isRowSelectable(JSONObject row) { |
| return isJobRow(row); |
| } |
| |
| @Override |
| public void handleHistoryArguments(Map<String, String> arguments) { |
| String hostname = arguments.get("hostname"); |
| String objectId = arguments.get("object_id"); |
| |
| if (objectId != null) { |
| try { |
| updateObjectId(objectId); |
| } |
| catch (IllegalArgumentException exc) { |
| return; |
| } |
| } else if (hostname != null) { |
| fetchDataByHostname(hostname); |
| } else { |
| resetPage(); |
| } |
| } |
| } |