modules/core/domain/src/main/java/org/rhq/core/domain/operation/bean/OperationSchedule.java | 11 modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/DiscoveredResourceDetails.java | 2 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java | 5 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UserEditView.java | 5 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/AbstractRecordEditor.java | 6 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/SubjectRecordCellFormatter.java | 34 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/Table.java | 31 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/trigger/JobTriggerEditor.java | 632 +++++++--- modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/OperationGWTService.java | 4 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleDataSource.java | 121 + modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleListView.java | 18 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/ResourceOperationScheduleDetailsView.java | 125 + modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/operation/schedule/ResourceOperationScheduleDataSource.java | 36 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/OperationGWTServiceImpl.java | 20 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerBean.java | 11 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerLocal.java | 20 16 files changed, 868 insertions(+), 213 deletions(-)
New commits: commit f05066c5da6e3579c8a3b81bd2a754c5cdb59daa Author: Ian Springer ian.springer@redhat.com Date: Wed Jan 12 17:38:37 2011 -0500
add Next Fire Time field to op schedule list and details views; improve validation of start and end times on op schedule details view; various other improvements and fixes to Resource Operations > Schedule subtab
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/bean/OperationSchedule.java b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/bean/OperationSchedule.java index 70f6a36..da52024 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/bean/OperationSchedule.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/bean/OperationSchedule.java @@ -19,6 +19,7 @@ package org.rhq.core.domain.operation.bean;
import java.io.Serializable; +import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -39,6 +40,7 @@ import org.rhq.core.domain.operation.JobId; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public abstract class OperationSchedule implements Serializable { + private static final long serialVersionUID = 1L;
private int id; @@ -50,6 +52,7 @@ public abstract class OperationSchedule implements Serializable { private Subject subject; private String description; private JobTrigger jobTrigger; + private Date nextFireTime;
public OperationSchedule() { } @@ -143,6 +146,14 @@ public abstract class OperationSchedule implements Serializable { this.jobTrigger = jobTrigger; }
+ public Date getNextFireTime() { + return nextFireTime; + } + + public void setNextFireTime(Date nextFireTime) { + this.nextFireTime = nextFireTime; + } + /** * The single job ID which identifies the operation. It can later be parsed via {@link JobId#JobId(String)}. Note * that this job ID only identifies the scheduled operation; it does not identify any specific invocation of that diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/trigger/JobTriggerEditor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/trigger/JobTriggerEditor.java index 4fc86f8..efcf37e 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/trigger/JobTriggerEditor.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/trigger/JobTriggerEditor.java @@ -20,6 +20,7 @@ package org.rhq.enterprise.gui.coregui.client.components.trigger;
import java.util.Date; +import java.util.EnumSet; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -46,6 +47,8 @@ import com.smartgwt.client.widgets.form.validator.RegExpValidator; import com.smartgwt.client.widgets.tab.Tab; import com.smartgwt.client.widgets.tab.TabSet; import org.rhq.core.domain.common.JobTrigger; +import org.rhq.enterprise.gui.coregui.client.CoreGUI; +import org.rhq.enterprise.gui.coregui.client.util.message.Message; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout;
@@ -775,12 +778,42 @@ public class JobTriggerEditor extends LocatableVLayout { }
public boolean validate() { + // TODO (ips, 01/12/11): Use custom validators to do the startTime / endTime validation instead of the code + // below; that way field-specific validation errors will be used, rather than messages in + // the message bar. boolean isValid = true; + Date currentTime = new Date(); + Date startTime = getStartTime(); + Date endTime = getEndTime(); if (this.isStartLater) { isValid = isValid && this.laterForm.validate(); + if (startTime != null) { + if (startTime.before(currentTime)) { + Message message = new Message("Start time must be in the future.", Message.Severity.Error, + EnumSet.of(Message.Option.Transient)); + CoreGUI.getMessageCenter().notify(message); + isValid = false; + } + if (this.isRecurring && endTime != null) { + if (endTime.before(startTime)) { + Message message = new Message("End time must be after start time.", Message.Severity.Error, + EnumSet.of(Message.Option.Transient)); + CoreGUI.getMessageCenter().notify(message); + isValid = false; + } + } + } } if (this.isRecurring) { isValid = isValid && this.repeatForm.validate(); + if (endTime != null) { + if (endTime.before(currentTime)) { + Message message = new Message("End time must be in the future.", Message.Severity.Error, + EnumSet.of(Message.Option.Transient)); + CoreGUI.getMessageCenter().notify(message); + isValid = false; + } + } } return isValid; } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleDataSource.java index 024f1e6..ec95731 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleDataSource.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleDataSource.java @@ -26,12 +26,12 @@ import java.util.Set;
import com.smartgwt.client.data.DataSourceField; import com.smartgwt.client.data.Record; +import com.smartgwt.client.data.fields.DataSourceDateTimeField; import com.smartgwt.client.data.fields.DataSourceIntegerField; import com.smartgwt.client.data.fields.DataSourceTextField; import com.smartgwt.client.types.FieldType; import com.smartgwt.client.widgets.grid.ListGridRecord;
-import org.apache.tools.ant.types.selectors.TypeSelector; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.common.JobTrigger; import org.rhq.core.domain.configuration.Configuration; @@ -56,6 +56,7 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e public static final String PARAMETERS = "parameters"; public static final String SUBJECT = "subject"; public static final String DESCRIPTION = "description"; + public static final String NEXT_FIRE_TIME = "nextFireTime";
// job trigger fields public static final String START_TIME = "startTime"; @@ -86,10 +87,12 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e idField.setCanEdit(false); fields.add(idField);
- DataSourceTextField operationNameField = createTextField(Field.OPERATION_NAME, "Operation Name", null, 100, true); + DataSourceTextField operationNameField = createTextField(Field.OPERATION_NAME, "Operation Name", null, 100, + true); fields.add(operationNameField);
- DataSourceTextField operationDisplayNameField = createTextField(Field.OPERATION_DISPLAY_NAME, "Operation", null, 100, true); + DataSourceTextField operationDisplayNameField = createTextField(Field.OPERATION_DISPLAY_NAME, "Operation", null, + 100, true); fields.add(operationDisplayNameField);
Set<OperationDefinition> operationDefinitions = this.resourceType.getOperationDefinitions(); @@ -106,6 +109,10 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e DataSourceTextField descriptionField = createTextField(Field.DESCRIPTION, "Notes", null, 100, false); fields.add(descriptionField);
+ DataSourceDateTimeField nextFireTimeField = new DataSourceDateTimeField(Field.NEXT_FIRE_TIME, + "Next Scheduled Execution"); + nextFireTimeField.setCanEdit(false); + return fields; }
@@ -124,6 +131,7 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e to.setOperationName(from.getAttribute(Field.OPERATION_NAME)); to.setOperationDisplayName(from.getAttribute(Field.OPERATION_DISPLAY_NAME)); to.setDescription(from.getAttribute(Field.DESCRIPTION)); + to.setNextFireTime(from.getAttributeAsDate(Field.NEXT_FIRE_TIME));
to.setJobTrigger(createJobTrigger(from.getAttributeAsRecord("jobTrigger")));
@@ -143,6 +151,7 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e to.setAttribute(Field.OPERATION_NAME, from.getOperationName()); to.setAttribute(Field.OPERATION_DISPLAY_NAME, from.getOperationDisplayName()); to.setAttribute(Field.DESCRIPTION, from.getDescription()); + to.setAttribute(Field.NEXT_FIRE_TIME, from.getNextFireTime());
JobTrigger jobTrigger = from.getJobTrigger(); Record jobTriggerRecord = new ListGridRecord(); @@ -206,11 +215,11 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e return jobTrigger; }
- public class SubjectRecord extends ListGridRecord { + public static class SubjectRecord extends ListGridRecord { static final String FIELD_ID = "id"; static final String FIELD_NAME = "name";
- SubjectRecord(Subject subject) { + public SubjectRecord(Subject subject) { setAttribute(FIELD_ID, subject.getId()); setAttribute(FIELD_NAME, subject.getName()); } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleListView.java index 71d943e..3d8fd6d 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleListView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleListView.java @@ -43,16 +43,19 @@ public abstract class OperationScheduleListView extends TableSection<OperationSc protected void configureTable() { super.configureTable();
- ListGridField operationField = new ListGridField(OperationScheduleDataSource.Field.OPERATION_DISPLAY_NAME, 150); + ListGridField operationField = new ListGridField(OperationScheduleDataSource.Field.OPERATION_DISPLAY_NAME, 180);
- ListGridField subjectField = new ListGridField(OperationScheduleDataSource.Field.SUBJECT, 150); + ListGridField subjectField = new ListGridField(OperationScheduleDataSource.Field.SUBJECT, 110); subjectField.setCellFormatter(new SubjectRecordCellFormatter());
//ListGridField jobTriggerField = new ListGridField(OperationScheduleDataSource.Field.JOB_TRIGGER, 300);
+ ListGridField nextFireTimeField = new ListGridField(OperationScheduleDataSource.Field.NEXT_FIRE_TIME, + "Next Scheduled Execution", 190); + ListGridField descriptionField = new ListGridField(OperationScheduleDataSource.Field.DESCRIPTION);
- setListGridFields(operationField, subjectField, descriptionField); + setListGridFields(operationField, subjectField, nextFireTimeField, descriptionField);
addTableAction(extendLocatorId("New"), MSG.common_button_new(), new TableAction() { public boolean isEnabled(ListGridRecord[] selection) { diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/ResourceOperationScheduleDetailsView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/ResourceOperationScheduleDetailsView.java index f7362ad..bc405b1 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/ResourceOperationScheduleDetailsView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/ResourceOperationScheduleDetailsView.java @@ -138,10 +138,22 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { this.notesForm = new EnhancedDynamicForm(extendLocatorId("NotesForm"), isReadOnly(), isNewRecord()); this.notesForm.setWidth100(); + + List<FormItem> notesFields = new ArrayList<FormItem>(); + + if (!isNewRecord()) { + StaticTextItem nextFireTimeItem = new StaticTextItem(ResourceOperationScheduleDataSource.Field.NEXT_FIRE_TIME, + "Next Scheduled Execution"); + notesFields.add(nextFireTimeItem); + } + TextAreaItem notesItem = new TextAreaItem(ResourceOperationScheduleDataSource.Field.DESCRIPTION, "Notes"); notesItem.setWidth(450); notesItem.setHeight(150); - this.notesForm.setFields(notesItem); + notesFields.add(notesItem); + + this.notesForm.setFields(notesFields.toArray(new FormItem[notesFields.size()])); + contentPane.addMember(this.notesForm);
return contentPane; @@ -163,7 +175,9 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { protected Record createNewRecord() { Record record = super.createNewRecord(); Subject sessionSubject = UserSessionManager.getSessionSubject(); - record.setAttribute(ResourceOperationScheduleDataSource.Field.SUBJECT, sessionSubject); + OperationScheduleDataSource.SubjectRecord subjectRecord = + new OperationScheduleDataSource.SubjectRecord(sessionSubject); + record.setAttribute(ResourceOperationScheduleDataSource.Field.SUBJECT, subjectRecord); return record; }
@@ -172,6 +186,11 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { refreshOperationDescriptionItem(); refreshOperationParametersItem();
+ if (!isNewRecord()) { + FormItem nextFireTimeItem = this.notesForm.getField(ResourceOperationScheduleDataSource.Field.NEXT_FIRE_TIME); + nextFireTimeItem.setValue(getForm().getValue(ResourceOperationScheduleDataSource.Field.NEXT_FIRE_TIME)); + } + FormItem notesItem = this.notesForm.getField(ResourceOperationScheduleDataSource.Field.DESCRIPTION); notesItem.setValue(getForm().getValue(ResourceOperationScheduleDataSource.Field.DESCRIPTION));
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerBean.java index 827d365..8bfa5cd 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerBean.java @@ -485,6 +485,7 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan Trigger trigger = getTriggerOfJob(jobDetail); JobTrigger jobTrigger = convertToJobTrigger(trigger); sched.setJobTrigger(jobTrigger); + sched.setNextFireTime(trigger.getNextFireTime());
return sched; }
commit 8a956b6b6e5d13f8ec7cf4a58b40af2f2474f85f Author: Ian Springer ian.springer@redhat.com Date: Tue Jan 11 20:07:05 2011 -0500
initial fully functional impl of Resource Operations > Schedule tab - list, detail, and create views
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/DiscoveredResourceDetails.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/DiscoveredResourceDetails.java index f5350fd..d178390 100644 --- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/DiscoveredResourceDetails.java +++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/DiscoveredResourceDetails.java @@ -207,7 +207,7 @@ public class DiscoveredResourceDetails { if (resourceVersion.length() > RESOURCE_VERSION_MAX_LENGTH) { log.warn("Plugin error: Resource version [" + resourceVersion + "] specified by [" + this.resourceType + "] discovery component is longer than the maximum length (" + RESOURCE_VERSION_MAX_LENGTH - + " - truncating it to " + RESOURCE_VERSION_MAX_LENGTH + " characters..."); + + ") - truncating it to " + RESOURCE_VERSION_MAX_LENGTH + " characters..."); this.resourceVersion = resourceVersion.substring(0, RESOURCE_VERSION_MAX_LENGTH); } else { this.resourceVersion = resourceVersion; diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java index 3d63160..0264d3b 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Set;
import com.google.gwt.user.client.rpc.AsyncCallback; +import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.Record; import com.smartgwt.client.types.Overflow; import com.smartgwt.client.widgets.Canvas; @@ -313,7 +314,7 @@ public class RoleEditView extends AbstractRecordEditor<RolesDataSource> implemen }
@Override - protected void save() { + protected void save(DSRequest requestProperties) { // Grab the currently assigned sets from each of the selectors and stick them into the corresponding canvas // items on the form, so when the form is saved, they'll get submitted along with the rest of the simple fields // to the datasource's add or update methods. @@ -333,7 +334,7 @@ public class RoleEditView extends AbstractRecordEditor<RolesDataSource> implemen }
// Submit the form values to the datasource. - super.save(); + super.save(requestProperties); }
@Override diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UserEditView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UserEditView.java index 04bc1b3..ffd8517 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UserEditView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UserEditView.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Set;
+import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.Record; import com.smartgwt.client.widgets.form.fields.FormItem; import com.smartgwt.client.widgets.form.fields.PasswordItem; @@ -193,7 +194,7 @@ public class UserEditView extends AbstractRecordEditor<UsersDataSource> { }
@Override - protected void save() { + protected void save(DSRequest requestProperties) { // Grab the currently assigned roles from the selector and stick them into the corresponding canvas // item on the form, so when the form is saved, they'll get submitted along with the rest of the simple fields // to the datasource's add or update methods. @@ -203,7 +204,7 @@ public class UserEditView extends AbstractRecordEditor<UsersDataSource> { }
// Submit the form values to the datasource. - super.save(); + super.save(requestProperties); }
@Override diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/AbstractRecordEditor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/AbstractRecordEditor.java index c134b69..b2a45b7 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/AbstractRecordEditor.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/AbstractRecordEditor.java @@ -249,7 +249,7 @@ public abstract class AbstractRecordEditor<DS extends RPCDataSource> extends Loc this.form.resetValues(); }
- protected void save() { + protected void save(DSRequest requestProperties) { if (!this.form.validate()) { Message message = new Message(MSG.widget_recordEditor_warn_validation(this.dataTypeName), Message.Severity.Warning, EnumSet.of(Message.Option.Transient)); @@ -308,7 +308,7 @@ public abstract class AbstractRecordEditor<DS extends RPCDataSource> extends Loc CoreGUI.getMessageCenter().notify(message); } } - }); + }, requestProperties); }
protected void editNewRecord() { @@ -451,7 +451,7 @@ public abstract class AbstractRecordEditor<DS extends RPCDataSource> extends Loc saveButton.setDisabled(true); saveButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { - save(); + save(new DSRequest()); } }); hLayout.addMember(saveButton); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/SubjectRecordCellFormatter.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/SubjectRecordCellFormatter.java new file mode 100644 index 0000000..7a45f5a --- /dev/null +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/SubjectRecordCellFormatter.java @@ -0,0 +1,34 @@ +package org.rhq.enterprise.gui.coregui.client.components.table; + +import com.google.gwt.core.client.JavaScriptObject; +import com.smartgwt.client.data.Record; +import com.smartgwt.client.widgets.grid.CellFormatter; +import com.smartgwt.client.widgets.grid.ListGridRecord; +import org.rhq.core.domain.auth.Subject; +import org.rhq.enterprise.gui.coregui.client.ImageManager; +import org.rhq.enterprise.gui.coregui.client.inventory.common.detail.operation.schedule.OperationScheduleDataSource; + +/** + * Formats a {@link org.rhq.enterprise.gui.coregui.client.inventory.common.detail.operation.schedule.OperationScheduleDataSource.SubjectRecord} + * (the SmartGWT {@link Record} representation of a {@link Subject}). + * + * @author Ian Springer + */ +public class SubjectRecordCellFormatter implements CellFormatter { + + public String format(Object value, ListGridRecord record, int rowNum, int colNum) { + String result; + if (value == null) { + result = ""; + } else if (value instanceof JavaScriptObject) { + JavaScriptObject javaScriptObject = (JavaScriptObject) value; + Record subjectRecord = new ListGridRecord(javaScriptObject); + result = subjectRecord.getAttribute("name"); // the Subject's username + } else { + throw new IllegalArgumentException("value parameter is not a SubjectRecord - it is a " + + value.getClass().getName() + "."); + } + return result; + } + +} diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/Table.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/Table.java index 78fb5db..7cfb393 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/Table.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/Table.java @@ -686,20 +686,27 @@ public class Table<DS extends RPCDataSource> extends LocatableHLayout implements }
protected void deleteSelectedRecords() { - getListGrid().removeSelectedData(new DSCallback() { + ListGrid listGrid = getListGrid(); + final int selectedRecordCount = listGrid.getSelection().length; + final List<String> deletedRecordNames = new ArrayList<String>(selectedRecordCount); + listGrid.removeSelectedData(new DSCallback() { public void execute(DSResponse response, Object rawData, DSRequest request) { - Record[] deletedRecords = response.getData(); - List<String> recordNames = new ArrayList<String>(deletedRecords.length); - for (Record deletedRecord : deletedRecords) { - String name = deletedRecord.getAttribute(getTitleFieldName()); - recordNames.add(name); + if (response.getStatus() == DSResponse.STATUS_SUCCESS) { + Record[] deletedRecords = response.getData(); + for (Record deletedRecord : deletedRecords) { + String name = deletedRecord.getAttribute(getTitleFieldName()); + deletedRecordNames.add(name); + } + if (deletedRecordNames.size() == selectedRecordCount) { + // all selected schedules were successfully deleted. + Message message = new Message(MSG.widget_recordEditor_info_recordsDeletedConcise(String + .valueOf(deletedRecordNames.size()), getDataTypeNamePlural()), MSG + .widget_recordEditor_info_recordsDeletedDetailed(String.valueOf(deletedRecordNames.size()), + getDataTypeNamePlural(), deletedRecordNames.toString())); + CoreGUI.getMessageCenter().notify(message); + } } - - Message message = new Message(MSG.widget_recordEditor_info_recordsDeletedConcise(String - .valueOf(deletedRecords.length), getDataTypeNamePlural()), MSG - .widget_recordEditor_info_recordsDeletedDetailed(String.valueOf(deletedRecords.length), - getDataTypeNamePlural(), recordNames.toString())); - CoreGUI.getMessageCenter().notify(message); + // TODO: Print error messages for failures or partial failures. } }, null); } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/trigger/JobTriggerEditor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/trigger/JobTriggerEditor.java index fc9aef4..4fc86f8 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/trigger/JobTriggerEditor.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/trigger/JobTriggerEditor.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright 2010, Red Hat Middleware LLC, and individual contributors + * Copyright 2010-2011, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * @@ -25,21 +25,28 @@ import java.util.LinkedHashMap; import java.util.Map;
import com.smartgwt.client.types.Visibility; +import com.smartgwt.client.util.SC; +import com.smartgwt.client.widgets.HTMLFlow; +import com.smartgwt.client.widgets.Img; +import com.smartgwt.client.widgets.events.ClickEvent; +import com.smartgwt.client.widgets.events.ClickHandler; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.fields.DateTimeItem; import com.smartgwt.client.widgets.form.fields.FormItem; +import com.smartgwt.client.widgets.form.fields.FormItemIcon; import com.smartgwt.client.widgets.form.fields.RadioGroupItem; import com.smartgwt.client.widgets.form.fields.SpacerItem; import com.smartgwt.client.widgets.form.fields.TextItem; -import com.smartgwt.client.widgets.form.fields.events.BlurEvent; -import com.smartgwt.client.widgets.form.fields.events.BlurHandler; import com.smartgwt.client.widgets.form.fields.events.ChangedEvent; import com.smartgwt.client.widgets.form.fields.events.ChangedHandler; -import com.smartgwt.client.widgets.form.fields.events.FocusEvent; -import com.smartgwt.client.widgets.form.fields.events.FocusHandler; +import com.smartgwt.client.widgets.form.fields.events.IconClickEvent; +import com.smartgwt.client.widgets.form.fields.events.IconClickHandler; import com.smartgwt.client.widgets.form.validator.RegExpValidator;
+import com.smartgwt.client.widgets.tab.Tab; +import com.smartgwt.client.widgets.tab.TabSet; import org.rhq.core.domain.common.JobTrigger; +import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout;
/** @@ -50,11 +57,17 @@ import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout; */ public class JobTriggerEditor extends LocatableVLayout {
+ // Field Names private static final String FIELD_REPEAT_INTERVAL = "repeatInterval"; private static final String FIELD_REPEAT_DURATION = "repeatDuration"; private static final String FIELD_END_TIME = "endTime"; + private static final String FIELD_START_TYPE = "startType"; + private static final String FIELD_START_TIME = "startTime"; + private static final String FIELD_START_DELAY = "startDelay"; + private static final String FIELD_RECURRENCE_TYPE = "recurrenceType"; + private static final String FIELD_CRON_EXPRESSION = "cronExpression";
- private static final Map<String, Long> UNITS_TO_MILLIS_MULTIPLIER_MAP = new HashMap(); + private static final Map<String, Long> UNITS_TO_MILLIS_MULTIPLIER_MAP = new HashMap<String, Long>(); static { UNITS_TO_MILLIS_MULTIPLIER_MAP.put("seconds", 1000L); UNITS_TO_MILLIS_MULTIPLIER_MAP.put("s", 1000L); @@ -78,6 +91,7 @@ public class JobTriggerEditor extends LocatableVLayout {
private DynamicForm laterForm; private DynamicForm repeatForm; + private LocatableDynamicForm cronForm;
// These flags allow us to determine the trigger type. private boolean isCronMode; @@ -87,10 +101,6 @@ public class JobTriggerEditor extends LocatableVLayout { private boolean isEndTime; private boolean isStartDelay; private boolean isStartTime; - private static final String FIELD_START_TYPE = "startType"; - private static final String FIELD_START_TIME = "startTime"; - private static final String FIELD_START_DELAY = "startDelay"; - private static final String FIELD_RECURRENCE_TYPE = "recurrenceType";
/** * Create a new job trigger. @@ -131,6 +141,8 @@ public class JobTriggerEditor extends LocatableVLayout { modeForm.setFields(modeItem); addMember(modeForm);
+ final LocatableVLayout calendarModeLayout = new LocatableVLayout(extendLocatorId("CalendarModeLayout")); + calendarModeLayout.setVisible(false);
final DynamicForm calendarTypeForm = new DynamicForm();
@@ -146,24 +158,349 @@ public class JobTriggerEditor extends LocatableVLayout { calendarTypeItem.setVertical(false);
calendarTypeForm.setFields(calendarTypeItem); - calendarTypeForm.setVisible(false);
- addMember(calendarTypeForm); + calendarModeLayout.addMember(calendarTypeForm); + addMember(calendarModeLayout); + + final LocatableVLayout cronModeLayout = new LocatableVLayout(extendLocatorId("CronModeLayout")); + cronModeLayout.setVisible(false); + + this.cronForm = new LocatableDynamicForm(cronModeLayout.extendLocatorId("Form")); + + TextItem cronExpressionItem = new TextItem(FIELD_CRON_EXPRESSION, "Cron Expression"); + cronExpressionItem.setRequired(true); + cronExpressionItem.setWidth(340); + + this.cronForm.setFields(cronExpressionItem); + + cronModeLayout.addMember(this.cronForm); + + final TabSet cronHelpTabSet = new TabSet(); + cronHelpTabSet.setWidth100(); + cronHelpTabSet.setHeight(200); + Img closeIcon = new Img("[SKIN]/headerIcons/close.png", 16, 16); + closeIcon.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + cronHelpTabSet.hide(); + } + }); + cronHelpTabSet.setTabBarControls(closeIcon); + + Tab formatTab = new Tab("Format"); + HTMLFlow formatPane = new HTMLFlow(); + formatPane.setWidth100(); + formatPane.setContents("<p>A cron expression is a string comprised of 6 or 7 fields separated by white space. Fields can contain any of the\n" + + "allowed values, along with various combinations of the allowed special characters for that field. The fields are as\n" + + "follows:</p>\n" + + "<table cellpadding="3" cellspacing="1">\n" + + " <tbody>\n" + + "\n" + + " <tr>\n" + + " <th>Field Name</th>\n" + + " <th>Mandatory</th>\n" + + " <th>Allowed Values</th>\n" + + " <th>Allowed Special Characters</th>\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td>Seconds</td>\n" + + " <td>YES</td>\n" + + "\n" + + " <td>0-59</td>\n" + + " <td>, - * /</td>\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td>Minutes</td>\n" + + " <td>YES</td>\n" + + " <td>0-59</td>\n" + + "\n" + + " <td>, - * /</td>\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td>Hours</td>\n" + + " <td>YES</td>\n" + + " <td>0-23</td>\n" + + " <td>, - * /</td>\n" + + "\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td>Day of month</td>\n" + + " <td>YES</td>\n" + + " <td>1-31</td>\n" + + " <td>, - * ? / L W<br clear="all" />\n" + + " </td>\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td>Month</td>\n" + + " <td>YES</td>\n" + + " <td>1-12 or JAN-DEC</td>\n" + + " <td>, - * /</td>\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td>Day of week</td>\n" + + "\n" + + " <td>YES</td>\n" + + " <td>1-7 or SUN-SAT</td>\n" + + " <td>, - * ? / L #</td>\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td>Year</td>\n" + + " <td>NO</td>\n" + + "\n" + + " <td>empty, 1970-2099</td>\n" + + " <td>, - * /</td>\n" + + " </tr>\n" + + " </tbody>\n" + + "\n" + + "</table>\n" + + "<p>So cron expressions can be as simple as this: <tt>* * * * ? *</tt><br />\n" + + "or more complex, like this: <tt>0/5 14,18,3-39,52 * ? JAN,MAR,SEP MON-FRI 2002-2010</tt></p>\n" + + "\n" + + "<h2><a name="CronTriggersTutorial-Specialcharacters"></a>Special Characters</h2>\n" + + "\n" + + "<ul>\n" + + " <li><tt><b>*</b></tt> (<em>"all values"</em>) - used to select all values within a field. For example, "*"\n" + + " in the minute field means <em>"every minute"</em>.</li>\n" + + "\n" + + "</ul>\n" + + "\n" + + "\n" + + "<ul>\n" + + " <li><tt><b>?</b></tt> (<em>"no specific value"</em>) - useful when you need to specify something in one of the\n" + + " two fields in which the character is allowed, but not the other. For example, if I want my trigger to fire on a\n" + + " particular day of the month (say, the 10th), but don't care what day of the week that happens to be, I would put\n" + + " "10" in the day-of-month field, and "?" in the day-of-week field. See the examples below for clarification.</li>\n" + + "\n" + + "</ul>\n" + + "\n" + + "\n" + + "<ul>\n" + + " <li><tt><b>-</b></tt> - used to specify ranges. For example, "10-12" in the hour field means <em>"the\n" + + " hours 10, 11 and 12"</em>.</li>\n" + + "\n" + + "</ul>\n" + + "\n" + + "\n" + + "<ul>\n" + + " <li><tt><b>,</b></tt> - used to specify additional values. For example, "MON,WED,FRI" in the day-of-week\n" + + " field means <em>"the days Monday, Wednesday, and Friday"</em>.</li>\n" + + "\n" + + "</ul>\n" + + "\n" + + "\n" + + "<ul>\n" + + "\n" + + " <li><tt><b>/</b></tt> - used to specify increments. For example, "0/15" in the seconds field means <em>"the\n" + + " seconds 0, 15, 30, and 45"</em>. And "5/15" in the seconds field means <em>"the seconds 5, 20, 35, and 50"</em>. You can\n" + + " also specify '/' after the '<b>' character - in this case '</b>' is equivalent to having '0' before the '/'. '1/3'\n" + + " in the day-of-month field means <em>"fire every 3 days starting on the first day of the month"</em>.</li>\n" + + "\n" + + "</ul>\n" + + "\n" + + "<ul>\n" + + " <li><tt><b>L</b></tt> (<em>"last"</em>) - has different meaning in each of the two fields in which it is\n" + + " allowed. For example, the value "L" in the day-of-month field means <em>"the last day of the month"</em> - day\n" + + " 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, it simply means\n" + + " "7" or "SAT". But if used in the day-of-week field after another value, it means <em>"the last xxx day of the\n" + + " month"</em> - for example "6L" means <em>"the last friday of the month"</em>. When using the 'L' option, it is\n" + + " important not to specify lists, or ranges of values, as you'll get confusing results.</li>\n" + + "\n" + + "</ul>\n" + + "\n" + + "\n" + + "<ul>\n" + + " <li><tt><b>W</b></tt> (<em>"weekday"</em>) - used to specify the weekday (Monday-Friday) nearest the given day.\n" + + " As an example, if you were to specify "15W" as the value for the day-of-month field, the meaning is: <em>"the\n" + + " nearest weekday to the 15th of the month"</em>. So if the 15th is a Saturday, the trigger will fire on Friday the 14th.\n" + + " If the 15th is a Sunday, the trigger will fire on Monday the 16th. If the 15th is a Tuesday, then it will fire on\n" + + " Tuesday the 15th. However if you specify "1W" as the value for day-of-month, and the 1st is a Saturday, the trigger\n" + + " will fire on Monday the 3rd, as it will not 'jump' over the boundary of a month's days. The 'W' character can only\n" + + " be specified when the day-of-month is a single day, not a range or list of days.\n" + + " <div class="tip">\n" + + " The 'L' and 'W' characters can also be combined in the day-of-month field to yield 'LW', which\n" + + " translates to <em>"last weekday of the month"</em>.\n" + + " </div>\n" + + "\n" + + " </li>\n" + + "\n" + + " <li><tt><b>#</b></tt> - used to specify "the nth" XXX day of the month. For example, the value of "6#3"\n" + + " in the day-of-week field means <em>"the third Friday of the month"</em> (day 6 = Friday and "#3" = the 3rd one in\n" + + " the month). Other examples: "2#1" = the first Monday of the month and "4#5" = the fifth Wednesday of the month. Note\n" + + " that if you specify "#5" and there is not 5 of the given day-of-week in the month, then no firing will occur that\n" + + " month.\n" + + " <div class="tip">\n" + + " The legal characters and the names of months and days of the week are not case sensitive. <tt>MON</tt>\n" + + " is the same as <tt>mon</tt>.\n" + + " </div>\n" + + "\n" + + " </li>\n" + + "</ul>" + + "<h2><a name="CronTriggersTutorial-Notes"></a>Notes</h2>\n" + + "\n" + + "<ul>\n" + + " <li>Support for specifying both a day-of-week and a day-of-month value is not complete (you must currently use\n" + + " the '?' character in one of these fields).</li>\n" + + " <li>Be careful when setting fire times between mid-night and 1:00 AM - "daylight savings" can cause a skip or a\n" + + " repeat depending on whether the time moves back or jumps forward.</li>\n" + + "\n" + + "</ul>"); + formatTab.setPane(formatPane); + + Tab examplesTab = new Tab("Examples"); + HTMLFlow examplesPane = new HTMLFlow(); + examplesPane.setWidth100(); + examplesPane.setContents("<table cellpadding="3" cellspacing="1">\n" + + " <tbody>\n" + + " <tr>\n" + + " <th>Expression</th>\n" + + "\n" + + " <th>Meaning</th>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 0 12 * * ?</tt></td>\n" + + "\n" + + " <td>Fire at 12pm (noon) every day</td>\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td><tt>0 15 10 ? * *</tt></td>\n" + + " <td>Fire at 10:15am every day</td>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 15 10 * * ?</tt></td>\n" + + "\n" + + " <td>Fire at 10:15am every day</td>\n" + + "\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 15 10 * * ? *</tt></td>\n" + + " <td>Fire at 10:15am every day</td>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 15 10 * * ? 2005</tt></td>\n" + + "\n" + + " <td>Fire at 10:15am every day during the year 2005</td>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 * 14 * * ?</tt></td>\n" + + " <td>Fire every minute starting at 2pm and ending at 2:59pm, every day</td>\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td><tt>0 0/5 14 * * ?</tt></td>\n" + + "\n" + + " <td>Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day</td>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 0/5 14,18 * * ?</tt></td>\n" + + " <td>Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5\n" + + " minutes starting at 6pm and ending at 6:55pm, every day</td>\n" + + "\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 0-5 14 * * ?</tt></td>\n" + + "\n" + + " <td>Fire every minute starting at 2pm and ending at 2:05pm, every day</td>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 10,44 14 ? 3 WED</tt></td>\n" + + "\n" + + " <td>Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.</td>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 15 10 ? * MON-FRI</tt></td>\n" + + "\n" + + " <td>Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday</td>\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td><tt>0 15 10 15 * ?</tt></td>\n" + + " <td>Fire at 10:15am on the 15th day of every month</td>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 15 10 L * ?</tt></td>\n" + + "\n" + + " <td>Fire at 10:15am on the last day of every month</td>\n" + + "\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 15 10 ? * 6L</tt></td>\n" + + " <td>Fire at 10:15am on the last Friday of every month</td>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 15 10 ? * 6L</tt></td>\n" + + "\n" + + " <td>Fire at 10:15am on the last Friday of every month</td>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 15 10 ? * 6L 2002-2005</tt></td>\n" + + " <td>Fire at 10:15am on every last friday of every month during the years 2002,\n" + + " 2003, 2004 and 2005</td>\n" + + " </tr>\n" + + " <tr>\n" + + "\n" + + " <td><tt>0 15 10 ? * 6#3</tt></td>\n" + + "\n" + + " <td>Fire at 10:15am on the third Friday of every month</td>\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 0 12 1/5 * ?</tt></td>\n" + + " <td>Fire at 12pm (noon) every 5 days every month, starting on the first day of the\n" + + " month.</td>\n" + + "\n" + + " </tr>\n" + + " <tr>\n" + + " <td><tt>0 11 11 11 11 ?</tt></td>\n" + + "\n" + + " <td>Fire every November 11th at 11:11am.</td>\n" + + " </tr>\n" + + " </tbody>\n" + + "</table>"); + examplesTab.setPane(examplesPane); + + cronHelpTabSet.addTab(formatTab); + cronHelpTabSet.addTab(examplesTab); + + cronHelpTabSet.setVisible(false); + + FormItemIcon helpIcon = new FormItemIcon(); + helpIcon.setSrc("[SKIN]/actions/help.png"); + cronExpressionItem.setIcons(helpIcon); + cronExpressionItem.addIconClickHandler(new IconClickHandler() { + public void onIconClick(IconClickEvent event) { + cronHelpTabSet.show(); + } + }); + + cronModeLayout.addMember(cronHelpTabSet); + addMember(cronModeLayout);
modeItem.addChangedHandler(new ChangedHandler() { public void onChanged(ChangedEvent event) { if (event.getValue().equals("calendar")) { JobTriggerEditor.this.isCronMode = false; - calendarTypeForm.show(); + calendarModeLayout.show(); + cronModeLayout.hide(); + } else { + // cron mode + JobTriggerEditor.this.isCronMode = true; + calendarModeLayout.hide(); + cronModeLayout.show(); } } });
this.laterForm = createLaterForm(); - addMember(this.laterForm); + calendarModeLayout.addMember(this.laterForm);
this.repeatForm = createRepeatForm(); - addMember(this.repeatForm); + calendarModeLayout.addMember(this.repeatForm);
calendarTypeItem.addChangedHandler(new ChangedHandler() { public void onChanged(ChangedEvent event) { @@ -204,21 +541,13 @@ public class JobTriggerEditor extends LocatableVLayout { TextItem repeatIntervalItem = new TextItem(FIELD_REPEAT_INTERVAL, "Run now and every"); repeatIntervalItem.setRequired(true);
- // Configure hint. - repeatIntervalItem.setHint("N UNITS (where N is a positive integer and UNITS is "seconds", "minutes", "hours", "days", "weeks", "months", "quarters", or "years", e.g. "30 seconds" or "6 weeks")"); - repeatIntervalItem.setShowHint(false); - repeatIntervalItem.addFocusHandler(new FocusHandler() { - public void onFocus(FocusEvent event) { - repeatForm.setColWidths(130, 400, 130, 130, 130); - event.getItem().setShowHint(true); - repeatForm.markForRedraw(); - } - }); - repeatIntervalItem.addBlurHandler(new BlurHandler() { - public void onBlur(BlurEvent event) { - repeatForm.setColWidths(130, 130, 130, 130, 130); - event.getItem().setShowHint(false); - repeatForm.markForRedraw(); + // Configure context-sensitive help. + FormItemIcon helpIcon = new FormItemIcon(); + helpIcon.setSrc("[SKIN]/actions/help.png"); + repeatIntervalItem.setIcons(helpIcon); + repeatIntervalItem.addIconClickHandler(new IconClickHandler() { + public void onIconClick(IconClickEvent event) { + SC.say("N UNITS (where N is a positive integer and UNITS is "seconds", "minutes", "hours", "days", "weeks", "months", "quarters", or "years", e.g. "30 seconds" or "6 weeks")"); } });
@@ -228,6 +557,7 @@ public class JobTriggerEditor extends LocatableVLayout { repeatIntervalItem.setValidateOnExit(true);
RadioGroupItem recurrenceTypeItem = new RadioGroupItem(FIELD_RECURRENCE_TYPE); + recurrenceTypeItem.setRequired(true); recurrenceTypeItem.setShowTitle(false); LinkedHashMap<String, String> recurrenceTypeValueMap = new LinkedHashMap<String, String>(); recurrenceTypeValueMap.put("for", "For"); @@ -239,21 +569,13 @@ public class JobTriggerEditor extends LocatableVLayout { repeatDurationItem.setShowTitle(false); repeatDurationItem.setVisible(false);
- // Configure hint. - repeatDurationItem.setHint("N UNITS (where N is a positive integer and UNITS is "times", "seconds", "minutes", "hours", "days", "weeks", "months", "quarters", or "years", e.g. "30 seconds" or "5 repetitions")"); - repeatDurationItem.setShowHint(false); - repeatDurationItem.addFocusHandler(new FocusHandler() { - public void onFocus(FocusEvent event) { - repeatForm.setColWidths(130, 130, 400, 130, 130); - event.getItem().setShowHint(true); - repeatForm.markForRedraw(); - } - }); - repeatDurationItem.addBlurHandler(new BlurHandler() { - public void onBlur(BlurEvent event) { - repeatForm.setColWidths(130, 130, 130, 130, 130); - event.getItem().setShowHint(false); - repeatForm.markForRedraw(); + // Configure context-sensitive help. + helpIcon = new FormItemIcon(); + helpIcon.setSrc("[SKIN]/actions/help.png"); + repeatDurationItem.setIcons(helpIcon); + repeatDurationItem.addIconClickHandler(new IconClickHandler() { + public void onIconClick(IconClickEvent event) { + SC.say("N UNITS (where N is a positive integer and UNITS is "times", "seconds", "minutes", "hours", "days", "weeks", "months", "quarters", or "years", e.g. "30 seconds" or "5 repetitions")"); } });
@@ -321,21 +643,13 @@ public class JobTriggerEditor extends LocatableVLayout { startDelayItem.setShowTitle(false); startDelayItem.setVisible(false);
- // Configure hint. - startDelayItem.setHint("N UNITS (where N is a positive integer and UNITS is "seconds", "minutes", "hours", "days", "weeks", "months", "quarters", or "years", e.g. "30 seconds" or "6 weeks")"); - startDelayItem.setShowHint(false); - startDelayItem.addFocusHandler(new FocusHandler() { - public void onFocus(FocusEvent event) { - laterForm.setColWidths(130, 130, 400); - event.getItem().setShowHint(true); - laterForm.markForRedraw(); - } - }); - startDelayItem.addBlurHandler(new BlurHandler() { - public void onBlur(BlurEvent event) { - laterForm.setColWidths(130, 130, 130); - event.getItem().setShowHint(false); - laterForm.markForRedraw(); + // Configure context-sensitive help. + FormItemIcon icon = new FormItemIcon(); + icon.setSrc("[SKIN]/actions/help.png"); + startDelayItem.setIcons(icon); + startDelayItem.addIconClickHandler(new IconClickHandler() { + public void onIconClick(IconClickEvent event) { + SC.say("N UNITS (where N is a positive integer and UNITS is "seconds", "minutes", "hours", "days", "weeks", "months", "quarters", or "years", e.g. "30 seconds" or "6 weeks")"); } });
@@ -378,108 +692,97 @@ public class JobTriggerEditor extends LocatableVLayout { return laterForm; }
- public JobTrigger getJobTrigger() throws Exception { - JobTrigger jobTrigger = null; - - if (this.isCronMode) { - // TODO + public Date getStartTime() { + Date startTime; + if (this.isStartDelay) { + // start delay - computer start time + String startDelay = this.laterForm.getValueAsString(FIELD_START_DELAY); + Duration startDelayDuration = parseDurationString(startDelay); + long delay = startDelayDuration.count * startDelayDuration.multiplier; + long startTimestamp = System.currentTimeMillis() + delay; + startTime = new Date(startTimestamp); } else { - // calendar mode + // start time + DateTimeItem startTimeItem = (DateTimeItem)this.laterForm.getField(FIELD_START_TIME); + startTime = startTimeItem.getValueAsDate(); + } + return startTime; + }
- // Validate first. - boolean isValid = true; - if (this.isStartLater) { - isValid = isValid && this.laterForm.validate(); - } - if (this.isRecurring) { - isValid = isValid && this.repeatForm.validate(); - } - if (!isValid) { - throw new Exception("The specified schedule is not valid."); - } + public Long getRepeatInterval() { + Long intervalMillis; + if (this.isRecurring) { + String repeatInterval = this.repeatForm.getValueAsString(FIELD_REPEAT_INTERVAL); + Duration intervalDuration = parseDurationString(repeatInterval); + intervalMillis = intervalDuration.count * intervalDuration.multiplier; + } else { + intervalMillis = null; + } + return intervalMillis; + }
- if (this.isStartLater) { - Date startDate; - if (this.isStartDelay) { - // start delay - computer start time - String startDelay = this.laterForm.getValueAsString(FIELD_START_DELAY); - Duration startDelayDuration = parseDurationString(startDelay); - long delay = startDelayDuration.count * startDelayDuration.multiplier; - long startTime = System.currentTimeMillis() + delay; - startDate = new Date(startTime); + public Integer getRepeatCount() { + Integer repetitions; + if (this.isRecurring) { + if (this.isRepeatDuration) { + String repeatDurationString = this.repeatForm.getValueAsString(FIELD_REPEAT_DURATION); + Duration repeatDuration = parseDurationString(repeatDurationString); + if (repeatDuration.multiplier == null) { + // n repetitions + repetitions = repeatDuration.count; } else { - // start time - DateTimeItem startTimeItem = (DateTimeItem)this.laterForm.getField(FIELD_START_TIME); - startDate = startTimeItem.getValueAsDate(); + // n units of time - compute end time + repetitions = null; } + } else { + repetitions = null; + } + } else { + repetitions = null; + } + return repetitions; + }
- if (this.isRecurring) { - // LATER AND REPEAT - - String repeatInterval = this.repeatForm.getValueAsString(FIELD_REPEAT_INTERVAL); - Duration intervalDuration = parseDurationString(repeatInterval); - long intervalMillis = intervalDuration.count * intervalDuration.multiplier; - - if (this.isRepeatDuration) { - String repeatDurationString = this.repeatForm.getValueAsString(FIELD_REPEAT_DURATION); - Duration repeatDuration = parseDurationString(repeatDurationString); - if (repeatDuration.multiplier == null) { - // n repetitions - int repetitions = repeatDuration.count; - jobTrigger = JobTrigger.createLaterAndRepeatTrigger(startDate, intervalMillis, repetitions); - } else { - // n units of time - compute end time - long delay = repeatDuration.count * repeatDuration.multiplier; - long endTime = System.currentTimeMillis() + delay; - Date endDate = new Date(endTime); - jobTrigger = JobTrigger.createLaterAndRepeatTrigger(startDate, intervalMillis, endDate); - } - } else if (this.isEndTime) { - DateTimeItem endTimeItem = (DateTimeItem)this.repeatForm.getField(FIELD_END_TIME); - Date endDate = endTimeItem.getValueAsDate(); - jobTrigger = JobTrigger.createLaterAndRepeatTrigger(startDate, intervalMillis, endDate); - } + public Date getEndTime() { + Date endTime; + if (this.isRecurring) { + if (this.isRepeatDuration) { + String repeatDurationString = this.repeatForm.getValueAsString(FIELD_REPEAT_DURATION); + Duration repeatDuration = parseDurationString(repeatDurationString); + if (repeatDuration.multiplier == null) { + // n repetitions + endTime = null; } else { - // LATER - - jobTrigger = JobTrigger.createLaterTrigger(startDate); + // n units of time - compute end time + long delay = repeatDuration.count * repeatDuration.multiplier; + long endTimestamp = System.currentTimeMillis() + delay; + endTime = new Date(endTimestamp); } + } else if (this.isEndTime) { + DateTimeItem endTimeItem = (DateTimeItem)this.repeatForm.getField(FIELD_END_TIME); + endTime = endTimeItem.getValueAsDate(); } else { - if (this.isRecurring) { - // NOW AND REPEAT - - String repeatInterval = this.repeatForm.getValueAsString(FIELD_REPEAT_INTERVAL); - Duration intervalDuration = parseDurationString(repeatInterval); - long intervalMillis = intervalDuration.count * intervalDuration.multiplier; - - if (this.isRepeatDuration) { - String repeatDurationString = this.repeatForm.getValueAsString(FIELD_REPEAT_DURATION); - Duration repeatDuration = parseDurationString(repeatDurationString); - if (repeatDuration.multiplier == null) { - // n repetitions - int repetitions = repeatDuration.count; - jobTrigger = JobTrigger.createNowAndRepeatTrigger(intervalMillis, repetitions); - } else { - // n units of time - compute end time - long delay = repeatDuration.count * repeatDuration.multiplier; - long endTime = System.currentTimeMillis() + delay; - Date endDate = new Date(endTime); - jobTrigger = JobTrigger.createNowAndRepeatTrigger(intervalMillis, endDate); - } - } else if (this.isEndTime) { - DateTimeItem endTimeItem = (DateTimeItem)this.repeatForm.getField(FIELD_END_TIME); - Date endDate = endTimeItem.getValueAsDate(); - jobTrigger = JobTrigger.createNowAndRepeatTrigger(intervalMillis, endDate); - } - } else { - // NOW - - jobTrigger = JobTrigger.createNowTrigger(); - } + endTime = null; } + } else { + endTime = null; } + return endTime; + } + + public String getCronExpression() { + return this.cronForm.getValueAsString(FIELD_CRON_EXPRESSION); + }
- return jobTrigger; + public boolean validate() { + boolean isValid = true; + if (this.isStartLater) { + isValid = isValid && this.laterForm.validate(); + } + if (this.isRecurring) { + isValid = isValid && this.repeatForm.validate(); + } + return isValid; }
private static Duration parseDurationString(String durationString) { diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/OperationGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/OperationGWTService.java index dd52adc..0ddc80b 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/OperationGWTService.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/OperationGWTService.java @@ -54,6 +54,10 @@ public interface OperationGWTService extends RemoteService { void invokeResourceOperation(int resourceId, String operationName, Configuration parameters, String description, int timeout) throws RuntimeException;
+ int scheduleResourceOperation(ResourceOperationSchedule resourceOperationSchedule) throws RuntimeException; + + void unscheduleResourceOperation(ResourceOperationSchedule resourceOperationSchedule) throws RuntimeException; + void scheduleResourceOperation(int resourceId, String operationName, Configuration parameters, String description, int timeout, String cronString) throws RuntimeException;
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleDataSource.java index 8450214..024f1e6 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleDataSource.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleDataSource.java @@ -19,6 +19,7 @@ */ package org.rhq.enterprise.gui.coregui.client.inventory.common.detail.operation.schedule;
+import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Set; @@ -27,8 +28,10 @@ import com.smartgwt.client.data.DataSourceField; import com.smartgwt.client.data.Record; import com.smartgwt.client.data.fields.DataSourceIntegerField; import com.smartgwt.client.data.fields.DataSourceTextField; +import com.smartgwt.client.types.FieldType; import com.smartgwt.client.widgets.grid.ListGridRecord;
+import org.apache.tools.ant.types.selectors.TypeSelector; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.common.JobTrigger; import org.rhq.core.domain.configuration.Configuration; @@ -53,7 +56,13 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e public static final String PARAMETERS = "parameters"; public static final String SUBJECT = "subject"; public static final String DESCRIPTION = "description"; - public static final String JOB_TRIGGER = "jobTrigger"; + + // job trigger fields + public static final String START_TIME = "startTime"; + public static final String REPEAT_INTERVAL = "repeatInterval"; + public static final String REPEAT_COUNT = "repeatCount"; + public static final String END_TIME = "endTime"; + public static final String CRON_EXPRESSION = "cronExpression"; }
protected OperationGWTServiceAsync operationService = GWTServiceLookup.getOperationService(); @@ -90,16 +99,13 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e } operationNameField.setValueMap(valueMap);
- DataSourceTextField subjectField = createTextField(Field.SUBJECT, "Owner", null, 100, true); + DataSourceField subjectField = new DataSourceField(Field.SUBJECT, FieldType.ANY, "Owner"); subjectField.setCanEdit(false); fields.add(subjectField);
DataSourceTextField descriptionField = createTextField(Field.DESCRIPTION, "Notes", null, 100, false); fields.add(descriptionField);
- DataSourceTextField jobTriggerField = createTextField(Field.JOB_TRIGGER, "Schedule", null, 100, true); - fields.add(jobTriggerField); - return fields; }
@@ -112,13 +118,15 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e to.setId(from.getAttributeAsInt(Field.ID)); to.setJobName(from.getAttribute(Field.JOB_NAME)); to.setJobGroup(from.getAttribute(Field.JOB_GROUP)); - to.setJobTrigger((JobTrigger)from.getAttributeAsObject(Field.JOB_TRIGGER)); - to.setSubject((Subject)from.getAttributeAsObject(Field.SUBJECT)); + SubjectRecord subjectRecord = (SubjectRecord) from.getAttributeAsRecord(Field.SUBJECT); + to.setSubject(subjectRecord.toSubject()); to.setParameters((Configuration)from.getAttributeAsObject(Field.PARAMETERS)); to.setOperationName(from.getAttribute(Field.OPERATION_NAME)); to.setOperationDisplayName(from.getAttribute(Field.OPERATION_DISPLAY_NAME)); to.setDescription(from.getAttribute(Field.DESCRIPTION));
+ to.setJobTrigger(createJobTrigger(from.getAttributeAsRecord("jobTrigger"))); + return to; }
@@ -129,14 +137,98 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e to.setAttribute(Field.ID, from.getId()); to.setAttribute(Field.JOB_NAME, from.getJobName()); to.setAttribute(Field.JOB_GROUP, from.getJobGroup()); - to.setAttribute(Field.JOB_TRIGGER, from.getJobTrigger()); - to.setAttribute(Field.SUBJECT, from.getSubject()); + SubjectRecord subjectRecord = new SubjectRecord(from.getSubject()); + to.setAttribute(Field.SUBJECT, subjectRecord); to.setAttribute(Field.PARAMETERS, from.getParameters()); to.setAttribute(Field.OPERATION_NAME, from.getOperationName()); to.setAttribute(Field.OPERATION_DISPLAY_NAME, from.getOperationDisplayName()); to.setAttribute(Field.DESCRIPTION, from.getDescription());
+ JobTrigger jobTrigger = from.getJobTrigger(); + Record jobTriggerRecord = new ListGridRecord(); + jobTriggerRecord.setAttribute(Field.START_TIME, jobTrigger.getStartDate()); + jobTriggerRecord.setAttribute(Field.REPEAT_INTERVAL, jobTrigger.getRepeatInterval()); + jobTriggerRecord.setAttribute(Field.REPEAT_COUNT, jobTrigger.getRepeatCount()); + jobTriggerRecord.setAttribute(Field.END_TIME, jobTrigger.getEndDate()); + jobTriggerRecord.setAttribute(Field.CRON_EXPRESSION, jobTrigger.getCronExpression()); + to.setAttribute("jobTrigger", jobTriggerRecord); + return to; }
+ public JobTrigger createJobTrigger(Record jobTriggerRecord) { + JobTrigger jobTrigger; + + String cronExpression = jobTriggerRecord.getAttribute(Field.CRON_EXPRESSION); + if (cronExpression != null) { + jobTrigger = JobTrigger.createCronTrigger(cronExpression); + } else { + // calendar mode + Date startTime = jobTriggerRecord.getAttributeAsDate(Field.START_TIME); + Long repeatInterval = (Long)jobTriggerRecord.getAttributeAsObject(Field.REPEAT_INTERVAL); + Integer repeatCount = jobTriggerRecord.getAttributeAsInt(Field.REPEAT_COUNT); + Date endTime = jobTriggerRecord.getAttributeAsDate(Field.END_TIME); + + if (startTime != null) { + // LATER + + if (repeatInterval != null) { + // LATER AND REPEAT + + if (repeatCount != null) { + jobTrigger = JobTrigger.createLaterAndRepeatTrigger(startTime, repeatInterval, repeatCount); + } else { + jobTrigger = JobTrigger.createLaterAndRepeatTrigger(startTime, repeatInterval, endTime); + } + } else { + // LATER ONCE + + jobTrigger = JobTrigger.createLaterTrigger(startTime); + } + } else { + // NOW + if (repeatInterval != null) { + // NOW AND REPEAT + + if (repeatCount != null) { + jobTrigger = JobTrigger.createNowAndRepeatTrigger(repeatInterval, repeatCount); + } else { + jobTrigger = JobTrigger.createNowAndRepeatTrigger(repeatInterval, endTime); + } + } else { + // NOW ONCE + + jobTrigger = JobTrigger.createNowTrigger(); + } + } + } + + return jobTrigger; + } + + public class SubjectRecord extends ListGridRecord { + static final String FIELD_ID = "id"; + static final String FIELD_NAME = "name"; + + SubjectRecord(Subject subject) { + setAttribute(FIELD_ID, subject.getId()); + setAttribute(FIELD_NAME, subject.getName()); + } + + public int getId() { + return getAttributeAsInt(FIELD_ID); + } + + public String getName() { + return getAttribute(FIELD_NAME); + } + + public Subject toSubject() { + Subject subject = new Subject(); + subject.setId(getId()); + subject.setName(getName()); + return subject; + } + } + } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleListView.java index d615316..71d943e 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleListView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleListView.java @@ -22,6 +22,7 @@ package org.rhq.enterprise.gui.coregui.client.inventory.common.detail.operation. import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord;
+import org.rhq.enterprise.gui.coregui.client.components.table.SubjectRecordCellFormatter; import org.rhq.enterprise.gui.coregui.client.components.table.TableAction; import org.rhq.enterprise.gui.coregui.client.components.table.TableSection;
@@ -44,13 +45,14 @@ public abstract class OperationScheduleListView extends TableSection<OperationSc
ListGridField operationField = new ListGridField(OperationScheduleDataSource.Field.OPERATION_DISPLAY_NAME, 150);
- //ListGridField subjectField = new ListGridField(OperationScheduleDataSource.Field.SUBJECT, 150); + ListGridField subjectField = new ListGridField(OperationScheduleDataSource.Field.SUBJECT, 150); + subjectField.setCellFormatter(new SubjectRecordCellFormatter());
//ListGridField jobTriggerField = new ListGridField(OperationScheduleDataSource.Field.JOB_TRIGGER, 300);
ListGridField descriptionField = new ListGridField(OperationScheduleDataSource.Field.DESCRIPTION);
- setListGridFields(operationField, descriptionField); + setListGridFields(operationField, subjectField, descriptionField);
addTableAction(extendLocatorId("New"), MSG.common_button_new(), new TableAction() { public boolean isEnabled(ListGridRecord[] selection) { @@ -70,9 +72,14 @@ public abstract class OperationScheduleListView extends TableSection<OperationSc }
public void executeAction(ListGridRecord[] selection, Object actionValue) { - // TODO: unschedule the selected schedule items + deleteSelectedRecords(); } }); }
+ @Override + protected String getDetailsLinkColumnName() { + return OperationScheduleDataSource.Field.OPERATION_DISPLAY_NAME; + } + } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/ResourceOperationScheduleDetailsView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/ResourceOperationScheduleDetailsView.java index 1a87bd3..f7362ad 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/ResourceOperationScheduleDetailsView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/ResourceOperationScheduleDetailsView.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright 2010, Red Hat Middleware LLC, and individual contributors + * Copyright 2010-2011, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * @@ -20,12 +20,16 @@ package org.rhq.enterprise.gui.coregui.client.inventory.common.detail.operation.schedule;
import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set;
+import com.smartgwt.client.data.DSRequest; +import com.smartgwt.client.data.Record; import com.smartgwt.client.widgets.Canvas; +import com.smartgwt.client.widgets.HTMLFlow; import com.smartgwt.client.widgets.form.fields.FormItem; import com.smartgwt.client.widgets.form.fields.SelectItem; import com.smartgwt.client.widgets.form.fields.StaticTextItem; @@ -33,20 +37,20 @@ import com.smartgwt.client.widgets.form.fields.TextAreaItem; import com.smartgwt.client.widgets.form.fields.events.ChangedEvent; import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
-import org.rhq.core.domain.common.JobTrigger; +import com.smartgwt.client.widgets.grid.ListGridRecord; +import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; import org.rhq.core.domain.operation.OperationDefinition; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.resource.composite.ResourceComposite; -import org.rhq.enterprise.gui.coregui.client.CoreGUI; +import org.rhq.enterprise.gui.coregui.client.UserSessionManager; import org.rhq.enterprise.gui.coregui.client.ViewPath; import org.rhq.enterprise.gui.coregui.client.components.configuration.ConfigurationEditor; import org.rhq.enterprise.gui.coregui.client.components.form.AbstractRecordEditor; import org.rhq.enterprise.gui.coregui.client.components.form.EnhancedDynamicForm; import org.rhq.enterprise.gui.coregui.client.components.trigger.JobTriggerEditor; import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.operation.schedule.ResourceOperationScheduleDataSource; -import org.rhq.enterprise.gui.coregui.client.util.message.Message; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableHLayout; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout;
@@ -62,11 +66,12 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { private Map<String, String> operationNameToDescriptionMap = new HashMap<String, String>(); private Map<String, ConfigurationDefinition> operationNameToParametersDefinitionMap = new HashMap<String, ConfigurationDefinition>(); - private SelectItem operationNameItem; private StaticTextItem operationDescriptionItem; private StaticTextItem operationParametersItem; private LocatableHLayout operationParametersConfigurationHolder; private JobTriggerEditor triggerEditor; + private Configuration parameters; + private EnhancedDynamicForm notesForm;
public ResourceOperationScheduleDetailsView(String locatorId, ResourceComposite resourceComposite, int scheduleId) { super(locatorId, new ResourceOperationScheduleDataSource(resourceComposite), scheduleId, "Scheduled Operation", null); @@ -94,9 +99,9 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { protected List<FormItem> createFormItems(EnhancedDynamicForm form) { List<FormItem> items = new ArrayList<FormItem>();
- this.operationNameItem = new SelectItem(ResourceOperationScheduleDataSource.Field.OPERATION_NAME); - items.add(this.operationNameItem); - this.operationNameItem.addChangedHandler(new ChangedHandler() { + SelectItem operationNameItem = new SelectItem(ResourceOperationScheduleDataSource.Field.OPERATION_NAME); + items.add(operationNameItem); + operationNameItem.addChangedHandler(new ChangedHandler() { public void onChanged(ChangedEvent event) { refreshOperationDescriptionItem(); refreshOperationParametersItem(); @@ -120,18 +125,24 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { this.operationParametersConfigurationHolder.setVisible(false); contentPane.addMember(this.operationParametersConfigurationHolder);
+ HTMLFlow hr = new HTMLFlow("<p/><hr/><p/>"); + contentPane.addMember(hr); + if (isNewRecord()) { this.triggerEditor = new JobTriggerEditor(extendLocatorId("TriggerEditor")); contentPane.addMember(this.triggerEditor); + hr = new HTMLFlow("<p/><hr/><p/>"); + contentPane.addMember(hr); } - - EnhancedDynamicForm notesForm = new EnhancedDynamicForm(extendLocatorId("NotesForm"), isReadOnly(), + + this.notesForm = new EnhancedDynamicForm(extendLocatorId("NotesForm"), isReadOnly(), isNewRecord()); + this.notesForm.setWidth100(); TextAreaItem notesItem = new TextAreaItem(ResourceOperationScheduleDataSource.Field.DESCRIPTION, "Notes"); - notesItem.setStartRow(true); - notesItem.setColSpan(4); - notesForm.setFields(notesItem); - contentPane.addMember(notesForm); + notesItem.setWidth(450); + notesItem.setHeight(150); + this.notesForm.setFields(notesItem); + contentPane.addMember(this.notesForm);
return contentPane; } @@ -149,22 +160,61 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { }
@Override - protected void save() { - try { - JobTrigger trigger = this.triggerEditor.getJobTrigger(); - System.out.println(trigger); - } - catch (Exception e) { - e.printStackTrace(); - CoreGUI.getMessageCenter().notify(new Message(e.getMessage(), Message.Severity.Warning)); + protected Record createNewRecord() { + Record record = super.createNewRecord(); + Subject sessionSubject = UserSessionManager.getSessionSubject(); + record.setAttribute(ResourceOperationScheduleDataSource.Field.SUBJECT, sessionSubject); + return record; + } + + @Override + protected void editRecord(Record record) { + refreshOperationDescriptionItem(); + refreshOperationParametersItem(); + + FormItem notesItem = this.notesForm.getField(ResourceOperationScheduleDataSource.Field.DESCRIPTION); + notesItem.setValue(getForm().getValue(ResourceOperationScheduleDataSource.Field.DESCRIPTION)); + + super.editRecord(record); + } + + @Override + protected void save(DSRequest requestProperties) { + requestProperties.setAttribute("parameters", this.parameters); + + if (!this.triggerEditor.validate()) { + // TODO: print error Message return; } + EnhancedDynamicForm form = getForm(); + + Record jobTriggerRecord = new ListGridRecord(); + + Date startTime = this.triggerEditor.getStartTime(); + jobTriggerRecord.setAttribute(ResourceOperationScheduleDataSource.Field.START_TIME, startTime); + + Date endTime = this.triggerEditor.getEndTime(); + jobTriggerRecord.setAttribute(ResourceOperationScheduleDataSource.Field.END_TIME, endTime); + + Integer repeatCount = this.triggerEditor.getRepeatCount(); + jobTriggerRecord.setAttribute(ResourceOperationScheduleDataSource.Field.REPEAT_COUNT, repeatCount);
- super.save(); + Long repeatInterval = this.triggerEditor.getRepeatInterval(); + jobTriggerRecord.setAttribute(ResourceOperationScheduleDataSource.Field.REPEAT_INTERVAL, repeatInterval); + + String cronExpression = this.triggerEditor.getCronExpression(); + jobTriggerRecord.setAttribute(ResourceOperationScheduleDataSource.Field.CRON_EXPRESSION, cronExpression); + + form.setValue("jobTrigger", jobTriggerRecord); + + FormItem notesItem = this.notesForm.getField(ResourceOperationScheduleDataSource.Field.DESCRIPTION); + form.setValue(ResourceOperationScheduleDataSource.Field.DESCRIPTION, (String)notesItem.getValue()); + + super.save(requestProperties); }
private void refreshOperationDescriptionItem() { - String operationName = this.operationNameItem.getValueAsString(); + String operationName = getSelectedOperationName(); String value; if (operationName == null) { value = "<i>Select an operation.</i>"; @@ -175,7 +225,7 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { }
private void refreshOperationParametersItem() { - String operationName = this.operationNameItem.getValueAsString(); + String operationName = getSelectedOperationName(); String value; if (operationName == null) { value = "<i>Select an operation.</i>"; @@ -189,7 +239,7 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { } this.operationParametersConfigurationHolder.hide(); } else { - value = "<i>Enter parameters below...</i>"; + value = isNewRecord() ? "<i>Enter parameters below...</i>" : "";
for (Canvas child : this.operationParametersConfigurationHolder.getChildren()) { child.destroy(); @@ -199,6 +249,7 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { ConfigurationEditor configurationEditor = new ConfigurationEditor("ParametersEditor", parametersDefinition, defaultConfiguration); configurationEditor.setReadOnly(isReadOnly()); + this.parameters = configurationEditor.getConfiguration(); this.operationParametersConfigurationHolder.addMember(configurationEditor); this.operationParametersConfigurationHolder.show(); } @@ -206,4 +257,9 @@ public class ResourceOperationScheduleDetailsView extends AbstractRecordEditor { this.operationParametersItem.setValue(value); }
+ private String getSelectedOperationName() { + FormItem operationNameItem = getForm().getField(ResourceOperationScheduleDataSource.Field.OPERATION_NAME); + return (String)operationNameItem.getValue(); + } + } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/operation/schedule/ResourceOperationScheduleDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/operation/schedule/ResourceOperationScheduleDataSource.java index 0adfdc3..c122bfb 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/operation/schedule/ResourceOperationScheduleDataSource.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/operation/schedule/ResourceOperationScheduleDataSource.java @@ -26,6 +26,7 @@ import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.DSResponse; import com.smartgwt.client.data.Record;
+import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.operation.bean.ResourceOperationSchedule; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.composite.ResourceComposite; @@ -47,7 +48,9 @@ public class ResourceOperationScheduleDataSource extends OperationScheduleDataSo
@Override protected ResourceOperationSchedule createOperationSchedule() { - return new ResourceOperationSchedule(); + ResourceOperationSchedule resourceOperationSchedule = new ResourceOperationSchedule(); + resourceOperationSchedule.setResource(this.resourceComposite.getResource()); + return resourceOperationSchedule; }
@Override @@ -68,7 +71,34 @@ public class ResourceOperationScheduleDataSource extends OperationScheduleDataSo }
@Override - protected void executeAdd(Record recordToAdd, DSRequest request, DSResponse response) { - //operationService.scheduleResourceOperation(); + protected void executeAdd(Record recordToAdd, final DSRequest request, final DSResponse response) { + Configuration parameters = (Configuration) request.getAttributeAsObject("parameters"); + recordToAdd.setAttribute(Field.PARAMETERS, parameters); + final ResourceOperationSchedule scheduleToAdd = copyValues(recordToAdd); + operationService.scheduleResourceOperation(scheduleToAdd, new AsyncCallback<Integer>() { + public void onSuccess(Integer scheduleId) { + scheduleToAdd.setId(scheduleId); + sendSuccessResponse(request, response, scheduleToAdd); + } + + public void onFailure(Throwable caught) { + throw new RuntimeException("Failed to add " + scheduleToAdd, caught); + } + }); + } + + @Override + protected void executeRemove(Record recordToRemove, final DSRequest request, final DSResponse response) { + final ResourceOperationSchedule scheduleToRemove = copyValues(recordToRemove); + + operationService.unscheduleResourceOperation(scheduleToRemove, new AsyncCallback<Void>() { + public void onSuccess(Void result) { + sendSuccessResponse(request, response, scheduleToRemove); + } + + public void onFailure(Throwable caught) { + throw new RuntimeException(caught); + } + }); } } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/OperationGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/OperationGWTServiceImpl.java index 8d15f3c..6db4693 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/OperationGWTServiceImpl.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/OperationGWTServiceImpl.java @@ -38,6 +38,7 @@ import org.rhq.core.util.IntExtractor; import org.rhq.core.util.exception.ThrowableUtil; import org.rhq.enterprise.gui.coregui.client.gwt.OperationGWTService; import org.rhq.enterprise.gui.coregui.server.util.SerialUtility; +import org.rhq.enterprise.server.exception.UnscheduleException; import org.rhq.enterprise.server.operation.OperationManagerLocal; import org.rhq.enterprise.server.resource.ResourceManagerLocal; import org.rhq.enterprise.server.resource.disambiguation.DefaultDisambiguationUpdateStrategies; @@ -92,6 +93,25 @@ public class OperationGWTServiceImpl extends AbstractGWTServiceImpl implements O } }
+ public int scheduleResourceOperation(ResourceOperationSchedule resourceOperationSchedule) throws RuntimeException { + try { + return operationManager.scheduleResourceOperation(getSessionSubject(), resourceOperationSchedule); + } catch (RuntimeException e) { + e.printStackTrace(); + throw new RuntimeException(ThrowableUtil.getAllMessages(e)); + } + } + + public void unscheduleResourceOperation(ResourceOperationSchedule resourceOperationSchedule) throws RuntimeException { + try { + operationManager.unscheduleResourceOperation(getSessionSubject(), resourceOperationSchedule.getJobId().toString(), + resourceOperationSchedule.getResource().getId()); + } catch (RuntimeException e) { + e.printStackTrace(); + throw new RuntimeException(ThrowableUtil.getAllMessages(e)); + } + } + /** Find recently completed operations, disambiguate them and return that list. * */ diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerBean.java index 3c71dd4..827d365 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerBean.java @@ -166,12 +166,15 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan } }
- public ResourceOperationSchedule scheduleResourceOperation(Subject subject, ResourceOperationSchedule schedule) + public int scheduleResourceOperation(Subject subject, ResourceOperationSchedule schedule) throws ScheduleException { JobTrigger jobTrigger = schedule.getJobTrigger(); Trigger trigger = convertToTrigger(jobTrigger); try { - return scheduleResourceOperation(subject, schedule.getResource().getId(), schedule.getOperationName(), schedule.getParameters(), trigger, schedule.getDescription()); + ResourceOperationSchedule resourceOperationSchedule = scheduleResourceOperation(subject, + schedule.getResource().getId(), schedule.getOperationName(), schedule.getParameters(), trigger, + schedule.getDescription()); + return resourceOperationSchedule.getId(); } catch (SchedulerException e) { throw new ScheduleException(e); @@ -200,6 +203,7 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan
jobDataMap.putAsString(ResourceOperationJob.DATAMAP_INT_SUBJECT_ID, subject.getId()); jobDataMap.putAsString(ResourceOperationJob.DATAMAP_INT_RESOURCE_ID, resource.getId()); + jobDataMap.put("description", notes);
JobDetail jobDetail = new JobDetail(); jobDetail.setName(uniqueJobId); @@ -445,7 +449,7 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan
String jobName = jobDetail.getName(); String jobGroup = jobDetail.getGroup(); - String description = jobDetail.getDescription(); + String description = jobDataMap.getString("description"); String operationName = jobDataMap.getString(ResourceOperationJob.DATAMAP_STRING_OPERATION_NAME); String displayName = jobDataMap.getString(ResourceOperationJob.DATAMAP_STRING_OPERATION_DISPLAY_NAME); int subjectId = jobDataMap.getIntFromString(ResourceOperationJob.DATAMAP_INT_SUBJECT_ID); diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerLocal.java index d74a88c..a48a385 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerLocal.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerLocal.java @@ -52,9 +52,28 @@ import org.rhq.enterprise.server.exception.UnscheduleException;
@Local public interface OperationManagerLocal { + + /** + * TODO + * + * @param groupId + * + * @return + */ public List<IntegerOptionItem> getResourceNameOptionItems(int groupId);
/** + * Schedules a Resource operation for execution. + * + * @param subject the user who is asking to schedule the job + * @param schedule the information describing the operation to be scheduled along with the schedule to be used + * + * @return the id of the {@link org.rhq.core.domain.operation.ResourceOperationScheduleEntity} created to track the + * scheduled operation + */ + int scheduleResourceOperation(Subject subject, ResourceOperationSchedule schedule); + + /** * Schedules an operation for execution on the given resource. * * @param subject the user who is asking to schedule the job @@ -610,4 +629,5 @@ public interface OperationManagerLocal {
PageList<GroupOperationHistory> findGroupOperationHistoriesByCriteria(Subject subject, GroupOperationHistoryCriteria criteria); + } \ No newline at end of file
rhq-commits@lists.fedorahosted.org