modules/core/dbutils/pom.xml | 2 modules/core/dbutils/src/main/java/org/rhq/core/db/upgrade/OperationScheduleIdSetterUpgradeTask.java | 60 ++++++++++ modules/core/dbutils/src/main/scripts/dbsetup/operation-schema.xml | 19 +-- modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml | 19 +++ modules/core/domain/src/main/java/org/rhq/core/domain/operation/GroupOperationScheduleEntity.java | 2 modules/core/domain/src/main/java/org/rhq/core/domain/operation/OperationScheduleEntity.java | 31 ++++- modules/core/domain/src/main/java/org/rhq/core/domain/operation/ResourceOperationScheduleEntity.java | 5 modules/core/domain/src/main/java/org/rhq/core/domain/operation/ScheduleJobId.java | 6 - modules/core/domain/src/main/java/org/rhq/core/domain/operation/bean/OperationSchedule.java | 9 + modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/GroupOperationScheduleComposite.java | 8 - modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/OperationScheduleComposite.java | 24 ++-- modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/ResourceOperationScheduleComposite.java | 8 - modules/core/domain/src/test/java/org/rhq/core/domain/operation/test/JobIdTest.java | 7 + modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/OperationScheduleDataSource.java | 23 ++- modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationJob.java | 2 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationManagerBean.java | 50 +++++++- 16 files changed, 220 insertions(+), 55 deletions(-)
New commits: commit 28b070f78cac12c2c2f58194361133d3cc0b2e2d Author: Ian Springer ian.springer@redhat.com Date: Fri Dec 17 15:52:12 2010 -0500
add ID field to RHQ_OPERATION_SCHEDULE and make it the primary key
diff --git a/modules/core/dbutils/pom.xml b/modules/core/dbutils/pom.xml index c6bdebd..2d8d1fc 100644 --- a/modules/core/dbutils/pom.xml +++ b/modules/core/dbutils/pom.xml @@ -22,7 +22,7 @@
<properties> <scm.module.path>modules/core/dbutils/</scm.module.path> - <db.schema.version>2.101</db.schema.version> + <db.schema.version>2.102</db.schema.version> </properties>
<dependencies> diff --git a/modules/core/dbutils/src/main/java/org/rhq/core/db/upgrade/OperationScheduleIdSetterUpgradeTask.java b/modules/core/dbutils/src/main/java/org/rhq/core/db/upgrade/OperationScheduleIdSetterUpgradeTask.java new file mode 100644 index 0000000..58692c9 --- /dev/null +++ b/modules/core/dbutils/src/main/java/org/rhq/core/db/upgrade/OperationScheduleIdSetterUpgradeTask.java @@ -0,0 +1,60 @@ +/* + * RHQ Management Platform + * Copyright 2010, 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. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.core.db.upgrade; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.rhq.core.db.DatabaseType; + +/** + * Sets values on the id column for all rows in RHQ_OPERATION_SCHEDULE. The id's are set, starting at 10001, in the + * order that the rows were created. This is done by parsing the value of the JOB_NAME column, which includes the + * creation time. + * + * @author Ian Springer + */ +public class OperationScheduleIdSetterUpgradeTask implements DatabaseUpgradeTask { + + @Override + public void execute(DatabaseType databaseType, Connection connection) throws SQLException { + String selectSQL = "SELECT job_name FROM rhq_operation_schedule;"; + System.out.println("Executing: " + selectSQL); + List<Object[]> results = databaseType.executeSelectSql(connection, selectSQL); + Map<Long, String> sortedJobNames = new TreeMap<Long, String>(); + for (Object[] result : results) { + String jobName = (String)result[0]; // e.g.: rhq-resource-10001--121207376-1292542028679 + // last portion is the job's creation time, e.g.: 1292542028679 + Long ctime = Long.valueOf(jobName.substring(jobName.lastIndexOf('-') + 1)); + sortedJobNames.put(ctime, jobName); + } + int id = 10001; + for (String jobName : sortedJobNames.values()) { + String updateSQL = "UPDATE rhq_operation_schedule SET id = " + (id++) + " WHERE job_name = '" + jobName + + "';"; + System.out.println("Executing: " + updateSQL); + databaseType.executeSql(connection, updateSQL); + } + } + +} diff --git a/modules/core/dbutils/src/main/scripts/dbsetup/operation-schema.xml b/modules/core/dbutils/src/main/scripts/dbsetup/operation-schema.xml index 2e34094..68b3274 100644 --- a/modules/core/dbutils/src/main/scripts/dbsetup/operation-schema.xml +++ b/modules/core/dbutils/src/main/scripts/dbsetup/operation-schema.xml @@ -71,6 +71,8 @@ code special conditions into the session bean, we'll allow a short-lived NULL next fire time row. --> <table name="RHQ_OPERATION_SCHEDULE"> + <column name="ID" type="INTEGER" required="true" default="sequence-only" initial="10001" primarykey="true"/> + <column name="JOB_NAME" type="VARCHAR2" required="true" size="100"/> <column name="JOB_GROUP" type="VARCHAR2" required="true" size="100"/> <column name="DTYPE" type="VARCHAR2" required="true" size="8"/> @@ -83,16 +85,15 @@ <column name="GROUP_ID" type="INTEGER" required="false" references="RHQ_RESOURCE_GROUP"/>
<!-- - Note that this is the same primary key that Quartz uses for its schedules (RHQ_qrtz_job_details). - We do not need to add DTYPE to the key, because we ensure the name/group are unique - across resource/group schedules + Note, this is the same as the primary key that Quartz uses for its schedules (RHQ_QRTZ_JOB_DETAILS). + We do not need to add DTYPE to the key, because we ensure the name/group are unique across resource/group + schedules --> - <constraint name="RHQ_OPERATION_SCHEDULE_KEY"> - <primaryKey> - <field ref="JOB_NAME"/> - <field ref="JOB_GROUP"/> - </primaryKey> - </constraint> + <!-- === business key (JOB_NAME + JOB_GROUP) === --> + <index name="RHQ_OPERATION_SCHEDULE_KEY_IDX" unique="true"> + <field ref="JOB_NAME"/> + <field ref="JOB_GROUP"/> + </index> </table>
</dbsetup> diff --git a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml index d9f63c0..975c778 100644 --- a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml +++ b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml @@ -3277,6 +3277,25 @@ </schema-directSQL> <schema-alterColumn table="RHQ_RESOURCE_TYPE" column="DELETED" nullable="FALSE" /> </schemaSpec> + + <schemaSpec version="2.102"> + <!-- Create the ID column nullable. --> + <schema-addColumn table="RHQ_OPERATION_SCHEDULE" column="ID" columnType="INTEGER" /> + <!-- Set values for ID column on all existing rows. --> + <schema-javaTask className="OperationScheduleIdSetterUpgradeTask" /> + <!-- Now that all existing rows have IDs, switch the column to non-nullable. --> + <schema-alterColumn table="RHQ_OPERATION_SCHEDULE" column="ID" nullable="FALSE" /> + <!-- Finally, make ID the primary key, rather than (JOB_NAME, JOB_GROUP), and make + (JOB_NAME, JOB_GROUP) a unique index instead. --> + <schema-directSQL> + <statement desc="Changing primary key of RHQ_OPERATION_SCHEDULE to ID..."> + ALTER TABLE RHQ_OPERATION_SCHEDULE DROP CONSTRAINT RHQ_OPERATION_SCHEDULE_KEY; + ALTER TABLE RHQ_OPERATION_SCHEDULE ADD PRIMARY KEY (ID); + CREATE UNIQUE INDEX RHQ_OPERATION_SCHEDULE_KEY_IDX ON RHQ_OPERATION_SCHEDULE (JOB_NAME, JOB_GROUP); + </statement> + </schema-directSQL> + </schemaSpec> + </dbupgrade> </target> </project> diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/GroupOperationScheduleEntity.java b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/GroupOperationScheduleEntity.java index 39f85d2..3f545bd 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/GroupOperationScheduleEntity.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/GroupOperationScheduleEntity.java @@ -36,6 +36,7 @@ import org.rhq.core.domain.resource.group.ResourceGroup; @NamedQueries( { @NamedQuery(name = GroupOperationScheduleEntity.QUERY_FIND_BY_GROUP_ID, query = "SELECT s " + " FROM GroupOperationScheduleEntity s " + " WHERE s.group.id = :groupId ") }) public class GroupOperationScheduleEntity extends OperationScheduleEntity { + public static final String QUERY_FIND_BY_GROUP_ID = "GroupOperationScheduleEntity.findByGroupId";
private static final long serialVersionUID = 1L; @@ -68,4 +69,5 @@ public class GroupOperationScheduleEntity extends OperationScheduleEntity { str.append("]"); return str.toString(); } + } \ No newline at end of file diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/OperationScheduleEntity.java b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/OperationScheduleEntity.java index 7da39d1..6eea462 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/OperationScheduleEntity.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/OperationScheduleEntity.java @@ -28,12 +28,14 @@ import java.util.Date; import javax.persistence.Column; import javax.persistence.DiscriminatorColumn; import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; -import javax.persistence.IdClass; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; +import javax.persistence.SequenceGenerator; import javax.persistence.Table;
/** @@ -45,10 +47,8 @@ import javax.persistence.Table; * * @author John Mazzitelli */ - @DiscriminatorColumn(name = "DTYPE") @Entity -@IdClass(ScheduleJobId.class) @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @NamedQueries( { @NamedQuery(name = OperationScheduleEntity.QUERY_FIND_BY_JOB_ID, query = "" // @@ -58,6 +58,7 @@ import javax.persistence.Table; + " AND s.jobGroup = :jobGroup "), @NamedQuery(name = OperationScheduleEntity.QUERY_GET_SCHEDULE_RESOURCE_ADMIN, query = "" // + "SELECT DISTINCT new org.rhq.core.domain.operation.composite.ResourceOperationScheduleComposite( " + + " ro.id, " // + " ro.jobName, " // + " ro.jobGroup, " // + " '', " // @@ -69,6 +70,7 @@ import javax.persistence.Table; + " WHERE ro.nextFireTime IS NOT NULL "), // @NamedQuery(name = OperationScheduleEntity.QUERY_GET_SCHEDULE_RESOURCE, query = "" // + "SELECT DISTINCT new org.rhq.core.domain.operation.composite.ResourceOperationScheduleComposite( " + + " ro.id, " // + " ro.jobName, " // + " ro.jobGroup, " // + " '', " // @@ -84,6 +86,7 @@ import javax.persistence.Table; + " AND s = :subject "), // @NamedQuery(name = OperationScheduleEntity.QUERY_GET_SCHEDULE_GROUP_ADMIN, query = "" // + "SELECT DISTINCT new org.rhq.core.domain.operation.composite.GroupOperationScheduleComposite( " + + " go.id, " // + " go.jobName, " // + " go.jobGroup, " // + " '', " // @@ -95,6 +98,7 @@ import javax.persistence.Table; + " WHERE go.nextFireTime IS NOT NULL "), // @NamedQuery(name = OperationScheduleEntity.QUERY_GET_SCHEDULE_GROUP, query = "" // + "SELECT DISTINCT new org.rhq.core.domain.operation.composite.GroupOperationScheduleComposite( " + + " go.id, " // + " go.jobName, " // + " go.jobGroup, " // + " '', " // @@ -108,8 +112,10 @@ import javax.persistence.Table; + " JOIN r.subjects s " // + " WHERE go.nextFireTime IS NOT NULL " // + " AND s = :subject ") }) +@SequenceGenerator(name = "id", sequenceName = "RHQ_OPERATION_SCHEDULE_ID_SEQ") @Table(name = "RHQ_OPERATION_SCHEDULE") public abstract class OperationScheduleEntity implements Serializable { + public static final String QUERY_FIND_BY_JOB_ID = "OperationScheduleEntity.findByJobId"; public static final String QUERY_GET_SCHEDULE_RESOURCE = "OperationScheduleEntity.getScheduleResource"; public static final String QUERY_GET_SCHEDULE_RESOURCE_ADMIN = "OperationScheduleEntity.getScheduleResource_admin"; @@ -118,10 +124,15 @@ public abstract class OperationScheduleEntity implements Serializable {
private static final long serialVersionUID = 1L;
+ @Column(name = "ID", nullable = false) + @GeneratedValue(strategy = GenerationType.AUTO, generator = "id") @Id + private int id; + + @Column(name = "JOB_NAME", nullable = false) private String jobName;
- @Id + @Column(name = "JOB_GROUP", nullable = false) private String jobGroup;
@Column(name = "NEXT_FIRE_TIME", nullable = true) @@ -136,6 +147,10 @@ public abstract class OperationScheduleEntity implements Serializable { this.nextFireTime = (nextFireTime == null) ? null : nextFireTime.getTime(); }
+ public int getId() { + return id; + } + /** * The single job ID which identifies this specific schedule. It can later be parsed via * {@link ScheduleJobId#ScheduleJobId(String)}. @@ -184,9 +199,10 @@ public abstract class OperationScheduleEntity implements Serializable { @Override public String toString() { StringBuilder buf = new StringBuilder(); - buf.append("job-name=[" + jobName); - buf.append("], job-group=[" + jobGroup); - buf.append("], next-fire-time=[" + ((nextFireTime == null) ? "never" : new Date(nextFireTime))); + buf.append("id=" + id); + buf.append(", jobName=" + jobName); + buf.append(", jobGroup=" + jobGroup); + buf.append(", nextFireTime=" + ((nextFireTime == null) ? "never" : new Date(nextFireTime)));
return buf.toString(); } @@ -210,4 +226,5 @@ public abstract class OperationScheduleEntity implements Serializable {
return this.getJobId().equals(other.getJobId()); } + } \ No newline at end of file diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/ResourceOperationScheduleEntity.java b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/ResourceOperationScheduleEntity.java index b7be10a..46dc63e 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/ResourceOperationScheduleEntity.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/ResourceOperationScheduleEntity.java @@ -34,11 +34,10 @@ import javax.persistence.NamedQuery; import org.rhq.core.domain.resource.Resource;
/** - * Information on a specific operation schedule on a particular resource. + * Information on a specific operation schedule on a particular Resource. * * @author John Mazzitelli */ - @DiscriminatorValue("resource") @Entity @NamedQueries( { @@ -47,6 +46,7 @@ import org.rhq.core.domain.resource.Resource; @NamedQuery(name = ResourceOperationScheduleEntity.QUERY_DELETE_BY_RESOURCES, query = "DELETE FROM ResourceOperationScheduleEntity s " + " WHERE s.resource.id IN ( :resourceIds ) )") }) public class ResourceOperationScheduleEntity extends OperationScheduleEntity { + public static final String QUERY_DELETE_BY_RESOURCES = "ResourceOperationScheduleEntity.QUERY_DELETE_BY_RESOURCES"; public static final String QUERY_FIND_BY_RESOURCE_ID = "ResourceOperationScheduleEntity.findByResourceId";
@@ -80,4 +80,5 @@ public class ResourceOperationScheduleEntity extends OperationScheduleEntity { str.append("]"); return str.toString(); } + } \ No newline at end of file diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/ScheduleJobId.java b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/ScheduleJobId.java index 0d29a76..bc6641b 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/ScheduleJobId.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/ScheduleJobId.java @@ -23,8 +23,10 @@ package org.rhq.core.domain.operation;
/** - * This class is a mutable version of {@link JobId} and is used as the primary key to the - * {@link OperationScheduleEntity} entities. + * This class is a mutable version of {@link JobId}, which represents the unique identifier of the Quartz job + * for a scheduled RHQ operation. + * + * NOTE: It is no longer used as the primary key to the {@link OperationScheduleEntity} entities. * * @author John Mazzitelli */ 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 c638b31..70f6a36 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 @@ -41,6 +41,7 @@ import org.rhq.core.domain.operation.JobId; public abstract class OperationSchedule implements Serializable { private static final long serialVersionUID = 1L;
+ private int id; private String jobName; private String jobGroup; private String operationName; @@ -53,6 +54,14 @@ public abstract class OperationSchedule implements Serializable { public OperationSchedule() { }
+ public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + public String getJobGroup() { return jobGroup; } diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/GroupOperationScheduleComposite.java b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/GroupOperationScheduleComposite.java index b5fba55..1107b06 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/GroupOperationScheduleComposite.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/GroupOperationScheduleComposite.java @@ -22,8 +22,6 @@ */ package org.rhq.core.domain.operation.composite;
-import org.rhq.core.domain.operation.ScheduleJobId; - /** * Provides some information on a compatible group's scheduled operation. * @@ -31,15 +29,15 @@ import org.rhq.core.domain.operation.ScheduleJobId; */ public class GroupOperationScheduleComposite extends OperationScheduleComposite {
- private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L;
private final int groupId; private final String groupName; private final String groupResourceTypeName;
- public GroupOperationScheduleComposite(String jobName, String jobGroup, String operationName, + public GroupOperationScheduleComposite(int id, String jobName, String jobGroup, String operationName, long operationNextFireTime, int groupId, String groupName, String groupResourceTypeName) { - super(new ScheduleJobId(jobName, jobGroup), operationName, operationNextFireTime); + super(id, jobName, jobGroup, operationName, operationNextFireTime); this.groupId = groupId; this.groupName = groupName; this.groupResourceTypeName = groupResourceTypeName; diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/OperationScheduleComposite.java b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/OperationScheduleComposite.java index dc99113..f80811a 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/OperationScheduleComposite.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/OperationScheduleComposite.java @@ -25,31 +25,37 @@ package org.rhq.core.domain.operation.composite; import java.io.Serializable; import java.util.Date;
-import org.rhq.core.domain.operation.ScheduleJobId; +import org.rhq.core.domain.operation.JobId;
public abstract class OperationScheduleComposite implements Serializable {
- private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L;
- private ScheduleJobId operationJobId; + private int id; + private JobId jobId; private String operationName; private long operationNextFireTime;
//no args constructor for serialization purposes not to be used. protected OperationScheduleComposite() { this.operationNextFireTime = -1; - this.operationJobId = null; + this.id = 0; this.operationName = "(uninitialized)"; }
- public OperationScheduleComposite(ScheduleJobId operationJobId, String operationName, long operationNextFireTime) { - this.operationJobId = operationJobId; + public OperationScheduleComposite(int id, String jobName, String jobGroup, String operationName, long operationNextFireTime) { + this.id = id; + this.jobId = new JobId(jobName, jobGroup); this.operationName = operationName; this.operationNextFireTime = operationNextFireTime; }
- public ScheduleJobId getOperationJobId() { - return operationJobId; + public int getId() { + return id; + } + + public JobId getJobId() { + return jobId; }
public String getOperationName() { @@ -72,7 +78,7 @@ public abstract class OperationScheduleComposite implements Serializable { @Override public String toString() { StringBuilder str = new StringBuilder(); - str.append("operation-job-id=[" + operationJobId); + str.append("operation-job-id=[" + id); str.append("], operation-name=[" + operationName); str.append("], operation-next-fire-time=[" + new Date(operationNextFireTime)); str.append("]"); diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/ResourceOperationScheduleComposite.java b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/ResourceOperationScheduleComposite.java index a0996a7..7ddd0d1 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/ResourceOperationScheduleComposite.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/operation/composite/ResourceOperationScheduleComposite.java @@ -22,11 +22,9 @@ */ package org.rhq.core.domain.operation.composite;
-import org.rhq.core.domain.operation.ScheduleJobId; - public class ResourceOperationScheduleComposite extends OperationScheduleComposite {
- private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L;
private int resourceId; private String resourceName; @@ -40,9 +38,9 @@ public class ResourceOperationScheduleComposite extends OperationScheduleComposi this.resourceId = 0; }
- public ResourceOperationScheduleComposite(String jobName, String jobGroup, String operationName, + public ResourceOperationScheduleComposite(int id, String jobName, String jobGroup, String operationName, long operationNextFireTime, int resourceId, String resourceName, String resourceTypeName) { - super(new ScheduleJobId(jobName, jobGroup), operationName, operationNextFireTime); + super(id, jobName, jobGroup, operationName, operationNextFireTime); this.resourceId = resourceId; this.resourceName = resourceName; this.resourceTypeName = resourceTypeName; diff --git a/modules/core/domain/src/test/java/org/rhq/core/domain/operation/test/JobIdTest.java b/modules/core/domain/src/test/java/org/rhq/core/domain/operation/test/JobIdTest.java index 48ff284..8cb8ca7 100644 --- a/modules/core/domain/src/test/java/org/rhq/core/domain/operation/test/JobIdTest.java +++ b/modules/core/domain/src/test/java/org/rhq/core/domain/operation/test/JobIdTest.java @@ -22,13 +22,17 @@ */ package org.rhq.core.domain.operation.test;
+import org.rhq.core.domain.operation.ScheduleJobId; import org.testng.annotations.Test; import org.rhq.core.domain.operation.HistoryJobId; import org.rhq.core.domain.operation.JobId; -import org.rhq.core.domain.operation.ScheduleJobId;
+ /** + * Test the equals() and hashCode() methods on {@link JobId}, {@link HistoryJobId}, and {@link ScheduleJobId}. + */ @Test public class JobIdTest { + public void testJobIdEquals() { JobId one; JobId two; @@ -170,4 +174,5 @@ public class JobIdTest { assert !one.equals(two); assert one.hashCode() != two.hashCode(); } + } \ No newline at end of file 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 65fe51f..06e68e5 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 @@ -23,6 +23,7 @@ import java.util.List;
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.widgets.grid.ListGridRecord;
@@ -40,6 +41,7 @@ import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource; public abstract class OperationScheduleDataSource<T extends OperationSchedule> extends RPCDataSource<T> {
public static abstract class Field { + public static final String ID = "id"; public static final String JOB_NAME = "jobName"; public static final String JOB_GROUP = "jobGroup"; public static final String OPERATION_NAME = "operationName"; @@ -63,6 +65,11 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e protected List<DataSourceField> addDataSourceFields() { List<DataSourceField> fields = super.addDataSourceFields();
+ DataSourceIntegerField idField = new DataSourceIntegerField(Field.ID, "ID"); + idField.setPrimaryKey(true); + idField.setCanEdit(false); + fields.add(idField); + DataSourceTextField operationDisplayNameField = createTextField(Field.OPERATION_DISPLAY_NAME, "Operation", null, 100, true); fields.add(operationDisplayNameField);
@@ -84,14 +91,15 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e public T copyValues(Record from) { T to = createOperationSchedule();
+ 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.setDescription(from.getAttribute(Field.DESCRIPTION)); - to.setOperationDisplayName(from.getAttribute(Field.OPERATION_DISPLAY_NAME)); - to.setOperationName(from.getAttribute(Field.OPERATION_NAME)); - to.setParameters((Configuration)from.getAttributeAsObject(Field.PARAMETERS)); to.setSubject((Subject)from.getAttributeAsObject(Field.SUBJECT)); + 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));
return to; } @@ -100,14 +108,15 @@ public abstract class OperationScheduleDataSource<T extends OperationSchedule> e public ListGridRecord copyValues(T from) { ListGridRecord to = new ListGridRecord();
+ 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.OPERATION_DISPLAY_NAME, from.getOperationDisplayName()); - to.setAttribute(Field.OPERATION_NAME, from.getOperationName()); to.setAttribute(Field.SUBJECT, from.getSubject()); - to.setAttribute(Field.DESCRIPTION, from.getDescription()); 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());
return to; } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationJob.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationJob.java index f5988e3..db58484 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationJob.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/operation/OperationJob.java @@ -39,6 +39,8 @@ public abstract class OperationJob implements Job { public static final String DATAMAP_STRING_OPERATION_DISPLAY_NAME = "operationDisplayName"; public static final String DATAMAP_INT_PARAMETERS_ID = "parametersId"; // the configuration ID public static final String DATAMAP_INT_SUBJECT_ID = "subjectId"; + // id of the associated OperationScheduleEntity - may be null for jobs created prior to upgrading to RHQ 4.0 + public static final String DATAMAP_INT_ENTITY_ID = "entityId";
/** * For security purposes, we need to provide a subject with a valid login session. This creates such a subject by 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 a1fc704..5d62695 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 @@ -203,13 +203,16 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan trigger.setJobName(jobDetail.getName()); trigger.setJobGroup(jobDetail.getGroup());
- // we need to create our own schedule tracking entity + // We need to create our own schedule tracking entity. ResourceOperationScheduleEntity schedule; schedule = new ResourceOperationScheduleEntity(jobDetail.getName(), jobDetail.getGroup(), trigger .getStartTime(), resource); entityManager.persist(schedule);
- // now actually schedule it + // Add the id of the entity bean, so we can easily map the Quartz job to the associated entity bean. + jobDataMap.put(ResourceOperationJob.DATAMAP_INT_ENTITY_ID, String.valueOf(schedule.getId())); + + // Now actually schedule it. Date next = scheduler.scheduleJob(jobDetail, trigger); ResourceOperationSchedule newSchedule = getResourceOperationSchedule(subject, jobDetail);
@@ -283,6 +286,9 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan group); entityManager.persist(schedule);
+ // Add the id of the entity bean, so we can easily map the Quartz job to the associated entity bean. + jobDataMap.put(ResourceOperationJob.DATAMAP_INT_ENTITY_ID, String.valueOf(schedule.getId())); + // now actually schedule it Date next = scheduler.scheduleJob(jobDetail, trigger); GroupOperationSchedule newSchedule = getGroupOperationSchedule(subject, jobDetail); @@ -424,6 +430,8 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan public ResourceOperationSchedule getResourceOperationSchedule(Subject whoami, JobDetail jobDetail) { JobDataMap jobDataMap = jobDetail.getJobDataMap();
+ String jobName = jobDetail.getName(); + String jobGroup = jobDetail.getGroup(); String description = jobDetail.getDescription(); String operationName = jobDataMap.getString(ResourceOperationJob.DATAMAP_STRING_OPERATION_NAME); String displayName = jobDataMap.getString(ResourceOperationJob.DATAMAP_STRING_OPERATION_DISPLAY_NAME); @@ -438,6 +446,8 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan int resourceId = jobDataMap.getIntFromString(ResourceOperationJob.DATAMAP_INT_RESOURCE_ID); Resource resource = getResourceIfAuthorized(whoami, resourceId);
+ Integer entityId = getOperationScheduleEntityId(jobDetail); + // note that we throw an exception if the subject does not exist! // this is by design to avoid a malicious user creating a dummy subject in the database, // scheduling a very bad operation, and deleting that subject thus removing all traces @@ -445,8 +455,9 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan // will need to be deleted and rescheduled.
ResourceOperationSchedule sched = new ResourceOperationSchedule(); - sched.setJobName(jobDetail.getName()); - sched.setJobGroup(jobDetail.getGroup()); + sched.setId(entityId); + sched.setJobName(jobName); + sched.setJobGroup(jobGroup); sched.setResource(resource); sched.setOperationName(operationName); sched.setOperationDisplayName(displayName); @@ -461,6 +472,25 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan return sched; }
+ private int getOperationScheduleEntityId(JobDetail jobDetail) { + JobDataMap jobDataMap = jobDetail.getJobDataMap(); + Object entityIdObj = jobDataMap.get(ResourceOperationJob.DATAMAP_INT_ENTITY_ID); + int entityId; + if (entityIdObj != null) { + // for jobs created using RHQ 4.0 or later, the map will contain an entityId entry + entityId = Integer.valueOf((String)entityIdObj); + } else { + // for jobs created prior to upgrading to RHQ 4.0, the map will not contain an entityId entry, + // so we'll need to lookup the entity id from the DB. + String jobName = jobDetail.getName(); + String jobGroup = jobDetail.getGroup(); + ScheduleJobId jobId = new ScheduleJobId(jobName, jobGroup); + OperationScheduleEntity operationScheduleEntity = findOperationScheduleEntity(jobId); + entityId = operationScheduleEntity.getId(); + } + return entityId; + } + public ResourceOperationSchedule getResourceOperationSchedule(Subject subject, String jobId) throws SchedulerException { JobId jobIdObject = new JobId(jobId); @@ -1430,7 +1460,7 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan Subject overlord = subjectManager.getOverlord(); for (ResourceOperationScheduleComposite composite : results) { try { - ResourceOperationSchedule sched = getResourceOperationSchedule(subject, composite.getOperationJobId() + ResourceOperationSchedule sched = getResourceOperationSchedule(subject, composite.getJobId() .toString()); OperationDefinition def = getSupportedResourceOperation(overlord, composite.getResourceId(), sched .getOperationName(), false); @@ -1484,7 +1514,7 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan Subject overlord = subjectManager.getOverlord(); for (GroupOperationScheduleComposite composite : results) { try { - GroupOperationSchedule sched = getGroupOperationSchedule(subject, composite.getOperationJobId() + GroupOperationSchedule sched = getGroupOperationSchedule(subject, composite.getJobId() .toString()); OperationDefinition def = getSupportedGroupOperation(overlord, composite.getGroupId(), sched .getOperationName(), false); @@ -1765,7 +1795,13 @@ public class OperationManagerBean implements OperationManagerLocal, OperationMan */ private OperationScheduleEntity findOperationScheduleEntity(ScheduleJobId jobId) { OperationScheduleEntity entity = entityManager.find(OperationScheduleEntity.class, jobId); - return entity; + Query query = entityManager.createNamedQuery(OperationScheduleEntity.QUERY_FIND_BY_JOB_ID); + String jobName = jobId.getJobName(); + query.setParameter("jobName", jobName); + String jobGroup = jobId.getJobGroup(); + query.setParameter("jobGroup", jobGroup); + OperationScheduleEntity operationScheduleEntity = (OperationScheduleEntity)query.getSingleResult(); + return operationScheduleEntity; }
public GroupOperationSchedule scheduleGroupOperation(Subject subject, int groupId, int[] executionOrderResourceIds,