diff --git a/deltaScripts/15.1.1/DR4522/updateActiveTable.sh b/deltaScripts/15.1.1/DR4522/updateActiveTable.sh
new file mode 100644
index 0000000000..9b659010e4
--- /dev/null
+++ b/deltaScripts/15.1.1/DR4522/updateActiveTable.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+psql -h dx1 -U awips -d metadata -n awips -f updateActiveTable.sql
diff --git a/deltaScripts/15.1.1/DR4522/updateActiveTable.sql b/deltaScripts/15.1.1/DR4522/updateActiveTable.sql
new file mode 100644
index 0000000000..f1f0dc23e4
--- /dev/null
+++ b/deltaScripts/15.1.1/DR4522/updateActiveTable.sql
@@ -0,0 +1,94 @@
+BEGIN;
+-- first remove any duplicate records
+DROP TABLE IF EXISTS t_deleteIds;
+CREATE TEMP TABLE t_deleteIds (id int);
+
+INSERT INTO t_deleteIds(id) (
+SELECT id FROM (
+ SELECT id,
+ ROW_NUMBER() OVER(PARTITION BY officeid, phen, sig, etn, ugczone ORDER BY issuetime DESC) AS Row
+ FROM activetable
+) dups
+WHERE dups.Row > 1);
+
+DELETE FROM activetable a using t_deleteIds t WHERE a.id = t.id;
+COMMIT;
+
+BEGIN;
+-- drop the old id column as primary key
+ALTER TABLE activetable DROP CONSTRAINT IF EXISTS activetable_pkey;
+ALTER TABLE activetable DROP COLUMN IF EXISTS id;
+DROP SEQUENCE IF EXISTS activetableseq;
+
+-- set proper length on several columns
+ALTER TABLE activetable ALTER COLUMN act TYPE character varying(3);
+ALTER TABLE activetable ALTER COLUMN wmoid TYPE character varying(22);
+ALTER TABLE activetable ALTER COLUMN vtecstr TYPE character varying(48);
+ALTER TABLE activetable ALTER COLUMN productclass TYPE character varying(1);
+ALTER TABLE activetable ALTER COLUMN locationid TYPE character varying(5);
+ALTER TABLE activetable ALTER COLUMN floodseverity TYPE character varying(1);
+ALTER TABLE activetable ALTER COLUMN immediatecause TYPE character varying(2);
+ALTER TABLE activetable ALTER COLUMN officeid TYPE character varying(4);
+ALTER TABLE activetable ALTER COLUMN phen TYPE character varying(2);
+ALTER TABLE activetable ALTER COLUMN sig TYPE character varying(1);
+ALTER TABLE activetable ALTER COLUMN ugczone TYPE character varying(6);
+
+-- add new primary key
+ALTER TABLE activetable ALTER COLUMN officeid SET NOT NULL;
+ALTER TABLE activetable ALTER COLUMN phen SET NOT NULL;
+ALTER TABLE activetable ALTER COLUMN sig SET NOT NULL;
+ALTER TABLE activetable ALTER COLUMN etn SET NOT NULL;
+ALTER TABLE activetable ALTER COLUMN ugczone SET NOT NULL;
+ALTER TABLE activetable ADD CONSTRAINT activetable_pkey PRIMARY KEY (etn, officeid, phen, sig, ugczone);
+COMMIT;
+VACUUM FULL ANALYZE activetable;
+
+
+-- now do the same for the practice_activetable
+BEGIN;
+-- first remove any duplicate records
+DROP TABLE IF EXISTS t_deleteIds;
+CREATE TEMP TABLE t_deleteIds (id int);
+
+INSERT INTO t_deleteIds(id) (
+SELECT id FROM (
+ SELECT id,
+ ROW_NUMBER() OVER(PARTITION BY officeid, phen, sig, etn, ugczone ORDER BY issuetime DESC) AS Row
+ FROM practice_activetable
+) dups
+WHERE dups.Row > 1);
+
+DELETE FROM practice_activetable a using t_deleteIds t WHERE a.id = t.id;
+COMMIT;
+
+BEGIN;
+-- drop the old id column as primary key
+ALTER TABLE practice_activetable DROP CONSTRAINT IF EXISTS practice_activetable_pkey;
+ALTER TABLE practice_activetable DROP COLUMN IF EXISTS id;
+DROP SEQUENCE IF EXISTS practice_activetableseq;
+
+-- set proper length on several columns
+ALTER TABLE practice_activetable ALTER COLUMN act TYPE character varying(3);
+ALTER TABLE practice_activetable ALTER COLUMN wmoid TYPE character varying(22);
+ALTER TABLE practice_activetable ALTER COLUMN vtecstr TYPE character varying(48);
+ALTER TABLE practice_activetable ALTER COLUMN productclass TYPE character varying(1);
+ALTER TABLE practice_activetable ALTER COLUMN locationid TYPE character varying(5);
+ALTER TABLE practice_activetable ALTER COLUMN floodseverity TYPE character varying(1);
+ALTER TABLE practice_activetable ALTER COLUMN immediatecause TYPE character varying(2);
+ALTER TABLE practice_activetable ALTER COLUMN officeid TYPE character varying(4);
+ALTER TABLE practice_activetable ALTER COLUMN phen TYPE character varying(2);
+ALTER TABLE practice_activetable ALTER COLUMN sig TYPE character varying(1);
+ALTER TABLE practice_activetable ALTER COLUMN ugczone TYPE character varying(6);
+
+-- add new primary key
+ALTER TABLE practice_activetable ALTER COLUMN officeid SET NOT NULL;
+ALTER TABLE practice_activetable ALTER COLUMN phen SET NOT NULL;
+ALTER TABLE practice_activetable ALTER COLUMN sig SET NOT NULL;
+ALTER TABLE practice_activetable ALTER COLUMN etn SET NOT NULL;
+ALTER TABLE practice_activetable ALTER COLUMN ugczone SET NOT NULL;
+ALTER TABLE practice_activetable ADD CONSTRAINT practice_activetable_pkey PRIMARY KEY (etn, officeid, phen, sig, ugczone);
+COMMIT;
+VACUUM FULL ANALYZE practice_activetable;
+
+DROP TABLE IF EXISTS t_deleteIds;
+
diff --git a/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/ActiveTableKey.java b/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/ActiveTableKey.java
new file mode 100644
index 0000000000..3fd2d5c848
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/ActiveTableKey.java
@@ -0,0 +1,228 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.activetable;
+
+import javax.persistence.Column;
+
+import com.raytheon.uf.common.dataplugin.annotations.DataURI;
+import com.raytheon.uf.common.dataplugin.persist.PersistableDataObject;
+import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
+
+/**
+ * Primary key for ActiveTableRecord
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * 05/22/2015 4522 randerso Create proper primary key for ActiveTableRecord
+ *
+ *
+ *
+ * @author randerso
+ * @version 1.0
+ */
+public class ActiveTableKey extends PersistableDataObject {
+ @Column(length = 4)
+ @DynamicSerializeElement
+ protected String officeid;
+
+ @Column(length = 2)
+ @DynamicSerializeElement
+ protected String phen;
+
+ @Column(length = 1)
+ @DynamicSerializeElement
+ protected String sig;
+
+ @DataURI(position = 5)
+ @Column(length = 4)
+ @DynamicSerializeElement
+ protected String etn;
+
+ @Column(length = 6)
+ @DynamicSerializeElement
+ protected String ugcZone;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((etn == null) ? 0 : etn.hashCode());
+ result = (prime * result)
+ + ((officeid == null) ? 0 : officeid.hashCode());
+ result = (prime * result) + ((phen == null) ? 0 : phen.hashCode());
+ result = (prime * result) + ((sig == null) ? 0 : sig.hashCode());
+ result = (prime * result)
+ + ((ugcZone == null) ? 0 : ugcZone.hashCode());
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ ActiveTableKey other = (ActiveTableKey) obj;
+ if (etn == null) {
+ if (other.etn != null) {
+ return false;
+ }
+ } else if (!etn.equals(other.etn)) {
+ return false;
+ }
+ if (officeid == null) {
+ if (other.officeid != null) {
+ return false;
+ }
+ } else if (!officeid.equals(other.officeid)) {
+ return false;
+ }
+ if (phen == null) {
+ if (other.phen != null) {
+ return false;
+ }
+ } else if (!phen.equals(other.phen)) {
+ return false;
+ }
+ if (sig == null) {
+ if (other.sig != null) {
+ return false;
+ }
+ } else if (!sig.equals(other.sig)) {
+ return false;
+ }
+ if (ugcZone == null) {
+ if (other.ugcZone != null) {
+ return false;
+ }
+ } else if (!ugcZone.equals(other.ugcZone)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @return the officeid
+ */
+ public String getOfficeid() {
+ return officeid;
+ }
+
+ /**
+ * @param officeid
+ * the officeid to set
+ */
+ public void setOfficeid(String officeid) {
+ this.officeid = officeid;
+ }
+
+ /**
+ * @return the phen
+ */
+ public String getPhen() {
+ return phen;
+ }
+
+ /**
+ * @param phen
+ * the phen to set
+ */
+ public void setPhen(String phen) {
+ this.phen = phen;
+ }
+
+ /**
+ * @return the sig
+ */
+ public String getSig() {
+ return sig;
+ }
+
+ /**
+ * @param sig
+ * the sig to set
+ */
+ public void setSig(String sig) {
+ this.sig = sig;
+ }
+
+ /**
+ * @return the etn
+ */
+ public String getEtn() {
+ return etn;
+ }
+
+ /**
+ * @param etn
+ * the etn to set
+ */
+ public void setEtn(String etn) {
+ this.etn = etn;
+ }
+
+ /**
+ * @return the ugcZone
+ */
+ public String getUgcZone() {
+ return ugcZone;
+ }
+
+ /**
+ * @param ugcZone
+ * the ugcZone to set
+ */
+ public void setUgcZone(String ugcZone) {
+ this.ugcZone = ugcZone;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getOfficeid()).append(".").append(getPhen()).append(".")
+ .append(getSig()).append(".").append(getEtn()).append(" ")
+ .append(getUgcZone());
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/ActiveTableRecord.java b/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/ActiveTableRecord.java
index 8c60f6e2e6..72a69b6ae3 100644
--- a/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/ActiveTableRecord.java
+++ b/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/ActiveTableRecord.java
@@ -25,9 +25,7 @@ import java.util.Date;
import java.util.List;
import javax.persistence.Column;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
+import javax.persistence.EmbeddedId;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.MappedSuperclass;
@@ -58,6 +56,7 @@ import com.vividsolutions.jts.geom.Geometry;
* spatial
* 10/16/2014 3454 bphillip Upgrading to Hibernate 4
* 04/28/2015 4027 randerso Expunged Calendar from ActiveTableRecord
+ * 05/22/2015 4522 randerso Create proper primary key for ActiveTableRecord
*
*
* @author njensen
@@ -66,17 +65,15 @@ import com.vividsolutions.jts.geom.Geometry;
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DynamicSerialize
+// TODO: do we get anything from extending PersistableDataObject here?
public abstract class ActiveTableRecord extends PersistableDataObject {
-
protected static final long serialVersionUID = 1L;
- protected static final String ID_GEN = "idgen";
+ @EmbeddedId
+ @DynamicSerializeElement
+ protected ActiveTableKey key;
- @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = ID_GEN)
- @Id
- protected int id;
-
- @Column(length = 32)
+ @Column(length = 22)
@DynamicSerializeElement
protected String wmoid;
@@ -92,40 +89,19 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
@DynamicSerializeElement
protected String countyheader;
- @Column(length = 8)
- @DynamicSerializeElement
- protected String ugcZone;
-
- @Column(columnDefinition = "text")
+ @Column(length = 48)
@DynamicSerializeElement
protected String vtecstr;
- @Column(length = 4)
+ @Column(length = 1)
@DynamicSerializeElement
protected String productClass;
@DataURI(position = 4)
- @Column(length = 4)
+ @Column(length = 3)
@DynamicSerializeElement
protected String act;
- @Column(length = 8)
- @DynamicSerializeElement
- protected String officeid;
-
- @Column(length = 4)
- @DynamicSerializeElement
- protected String phen;
-
- @Column(length = 4)
- @DynamicSerializeElement
- protected String sig;
-
- @DataURI(position = 5)
- @Column(length = 4)
- @DynamicSerializeElement
- protected String etn;
-
/** vtec start time */
@DynamicSerializeElement
protected Date startTime;
@@ -142,7 +118,7 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
@DynamicSerializeElement
protected Date purgeTime;
- @Column(length = 8)
+ @Column
@DynamicSerializeElement
protected boolean ufn;
@@ -163,6 +139,7 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
@DynamicSerializeElement
protected Integer motspd;
+ // TODO: make this column a Geometry
@Column(columnDefinition = "text")
@DynamicSerializeElement
protected String loc;
@@ -194,14 +171,15 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
@DynamicSerializeElement
protected String segText;
- @Column(length = 8)
+ @Column(length = 5)
@DynamicSerializeElement
protected String locationID;
- @Column(length = 2)
+ @Column(length = 1)
@DynamicSerializeElement
protected String floodSeverity;
+ @Column(length = 2)
@DynamicSerializeElement
protected String immediateCause;
@@ -221,9 +199,18 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
@DynamicSerializeElement
protected Date floodEnd;
+ public ActiveTableRecord() {
+ this.key = new ActiveTableKey();
+ }
+
@Override
public abstract Object clone();
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -257,13 +244,6 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
} else if (!endTime.equals(other.endTime)) {
return false;
}
- if (etn == null) {
- if (other.etn != null) {
- return false;
- }
- } else if (!etn.equals(other.etn)) {
- return false;
- }
if (floodBegin == null) {
if (other.floodBegin != null) {
return false;
@@ -310,7 +290,7 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
if (other.geometry != null) {
return false;
}
- } else if (!geometry.equalsExact(other.geometry)) {
+ } else if (!geometry.equals(other.geometry)) {
return false;
}
if (immediateCause == null) {
@@ -327,6 +307,13 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
} else if (!issueTime.equals(other.issueTime)) {
return false;
}
+ if (key == null) {
+ if (other.key != null) {
+ return false;
+ }
+ } else if (!key.equals(other.key)) {
+ return false;
+ }
if (loc == null) {
if (other.loc != null) {
return false;
@@ -355,13 +342,6 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
} else if (!motspd.equals(other.motspd)) {
return false;
}
- if (officeid == null) {
- if (other.officeid != null) {
- return false;
- }
- } else if (!officeid.equals(other.officeid)) {
- return false;
- }
if (overviewText == null) {
if (other.overviewText != null) {
return false;
@@ -369,13 +349,6 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
} else if (!overviewText.equals(other.overviewText)) {
return false;
}
- if (phen == null) {
- if (other.phen != null) {
- return false;
- }
- } else if (!phen.equals(other.phen)) {
- return false;
- }
if (phensig == null) {
if (other.phensig != null) {
return false;
@@ -428,13 +401,6 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
} else if (!segText.equals(other.segText)) {
return false;
}
- if (sig == null) {
- if (other.sig != null) {
- return false;
- }
- } else if (!sig.equals(other.sig)) {
- return false;
- }
if (startTime == null) {
if (other.startTime != null) {
return false;
@@ -445,13 +411,6 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
if (ufn != other.ufn) {
return false;
}
- if (ugcZone == null) {
- if (other.ugcZone != null) {
- return false;
- }
- } else if (!ugcZone.equals(other.ugcZone)) {
- return false;
- }
if (vtecstr == null) {
if (other.vtecstr != null) {
return false;
@@ -476,6 +435,21 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
return true;
}
+ /**
+ * @return the key
+ */
+ public ActiveTableKey getKey() {
+ return key;
+ }
+
+ /**
+ * @param key
+ * the key to set
+ */
+ public void setKey(ActiveTableKey key) {
+ this.key = key;
+ }
+
/**
* @return the wmoid
*/
@@ -540,7 +514,7 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
* @return the ugcZone
*/
public String getUgcZone() {
- return ugcZone;
+ return key.ugcZone;
}
/**
@@ -548,7 +522,7 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
* the ugcZone to set
*/
public void setUgcZone(String ugcZone) {
- this.ugcZone = ugcZone;
+ this.key.ugcZone = ugcZone;
}
/**
@@ -600,7 +574,7 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
* @return the officeid
*/
public String getOfficeid() {
- return officeid;
+ return key.officeid;
}
/**
@@ -608,14 +582,14 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
* the officeid to set
*/
public void setOfficeid(String officeid) {
- this.officeid = officeid;
+ this.key.officeid = officeid;
}
/**
* @return the phen
*/
public String getPhen() {
- return phen;
+ return key.phen;
}
/**
@@ -623,14 +597,14 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
* the phen to set
*/
public void setPhen(String phen) {
- this.phen = phen;
+ this.key.phen = phen;
}
/**
* @return the sig
*/
public String getSig() {
- return sig;
+ return key.sig;
}
/**
@@ -638,14 +612,14 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
* the sig to set
*/
public void setSig(String sig) {
- this.sig = sig;
+ this.key.sig = sig;
}
/**
* @return the etn
*/
public String getEtn() {
- return etn;
+ return key.etn;
}
/**
@@ -653,7 +627,7 @@ public abstract class ActiveTableRecord extends PersistableDataObject {
* the etn to set
*/
public void setEtn(String etn) {
- this.etn = etn;
+ this.key.etn = etn;
}
/**
diff --git a/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/OperationalActiveTableRecord.java b/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/OperationalActiveTableRecord.java
index 44a7efcff6..2a3029e623 100644
--- a/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/OperationalActiveTableRecord.java
+++ b/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/OperationalActiveTableRecord.java
@@ -20,7 +20,6 @@
package com.raytheon.uf.common.activetable;
import javax.persistence.Entity;
-import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.Index;
@@ -28,7 +27,8 @@ import org.hibernate.annotations.Index;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
/**
- * Operational Active Table, separated so that practice and operational data go to separate tables.
+ * Operational Active Table, separated so that practice and operational data go
+ * to separate tables.
*
*
*
@@ -37,6 +37,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
* ------------ ---------- ----------- --------------------------
* Feb 10, 2010 njensen Initial creation
* May 10, 2013 1951 rjpeter Added own id sequence tagging and new index.
+ * May 22, 2015 4522 randerso Create proper primary key for ActiveTableRecord
*
*
* @author njensen
@@ -44,7 +45,6 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
*/
@Entity
-@SequenceGenerator(initialValue = 1, name = ActiveTableRecord.ID_GEN, sequenceName = "activetableseq")
@Table(name = "activetable")
@DynamicSerialize
@org.hibernate.annotations.Table(appliesTo = "activetable", indexes = { @Index(name = "activetable_officeid_phensig_idx", columnNames = {
diff --git a/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/PracticeActiveTableRecord.java b/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/PracticeActiveTableRecord.java
index fc419204be..53eaf8fa62 100644
--- a/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/PracticeActiveTableRecord.java
+++ b/edexOsgi/com.raytheon.uf.common.activetable/src/com/raytheon/uf/common/activetable/PracticeActiveTableRecord.java
@@ -20,7 +20,6 @@
package com.raytheon.uf.common.activetable;
import javax.persistence.Entity;
-import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.Index;
@@ -28,7 +27,8 @@ import org.hibernate.annotations.Index;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
/**
- * Practice Active Table, separated so that practice and operational data go to separate tables.
+ * Practice Active Table, separated so that practice and operational data go to
+ * separate tables.
*
*
*
@@ -37,6 +37,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
* ------------ ---------- ----------- --------------------------
* Feb 10, 2010 njensen Initial creation
* May 10, 2013 1951 rjpeter Added own id sequence tagging and new index.
+ * May 22, 2015 4522 randerso Create proper primary key for ActiveTableRecord
*
*
* @author njensen
@@ -44,7 +45,6 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
*/
@Entity
-@SequenceGenerator(initialValue = 1, name = ActiveTableRecord.ID_GEN, sequenceName = "practice_activetableseq")
@Table(name = "practice_activetable")
@DynamicSerialize
@org.hibernate.annotations.Table(appliesTo = "practice_activetable", indexes = { @Index(name = "practice_activetable_officeid_phensig_idx", columnNames = {
diff --git a/edexOsgi/com.raytheon.uf.edex.activetable/build.properties b/edexOsgi/com.raytheon.uf.edex.activetable/build.properties
index 5791d48d5f..73974cda80 100644
--- a/edexOsgi/com.raytheon.uf.edex.activetable/build.properties
+++ b/edexOsgi/com.raytheon.uf.edex.activetable/build.properties
@@ -2,4 +2,5 @@ source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
- res/
+ res/,\
+ utility/
diff --git a/edexOsgi/com.raytheon.uf.edex.activetable/src/com/raytheon/uf/edex/activetable/ActiveTable.java b/edexOsgi/com.raytheon.uf.edex.activetable/src/com/raytheon/uf/edex/activetable/ActiveTable.java
index 774b3514b8..a27e7c2b02 100644
--- a/edexOsgi/com.raytheon.uf.edex.activetable/src/com/raytheon/uf/edex/activetable/ActiveTable.java
+++ b/edexOsgi/com.raytheon.uf.edex.activetable/src/com/raytheon/uf/edex/activetable/ActiveTable.java
@@ -20,6 +20,7 @@
package com.raytheon.uf.edex.activetable;
import java.io.File;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
@@ -27,14 +28,17 @@ import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import jep.JepException;
import org.apache.log4j.Logger;
+import org.hibernate.NonUniqueObjectException;
import com.raytheon.edex.site.SiteUtil;
+import com.raytheon.uf.common.activetable.ActiveTableKey;
import com.raytheon.uf.common.activetable.ActiveTableMode;
import com.raytheon.uf.common.activetable.ActiveTableRecord;
import com.raytheon.uf.common.activetable.MergeResult;
@@ -111,6 +115,7 @@ import com.raytheon.uf.edex.database.query.DatabaseQuery;
* Mar 04, 2015 4129 randerso Pass active table change logger to ingestAt and/or MergeVTEC
* Apr 28, 2015 #4027 randerso Expunged Calendar from ActiveTableRecord,
* fixed next ETN query to query for >= Jan 1
+ * May 22, 2015 4522 randerso Create proper primary key for ActiveTableRecord
*
*
*
@@ -362,7 +367,7 @@ public class ActiveTable {
perfStat.logDuration("filterTable", timer.getElapsedTime());
timer.reset();
timer.start();
- updateTable(siteId, result, mode);
+ updateTable(result, mode);
timer.stop();
perfStat.logDuration("updateTable", timer.getElapsedTime());
} finally {
@@ -472,7 +477,7 @@ public class ActiveTable {
}
if (etn != null) {
- query.addQueryParam("etn", etn, "in");
+ query.addQueryParam("key.etn", etn, "in");
}
if (requestValidTimes && (currentTime != null)) {
@@ -491,7 +496,7 @@ public class ActiveTable {
query.setMaxResults(1);
}
- query.addQueryParam("officeid", siteId, "in");
+ query.addQueryParam("key.officeid", siteId, "in");
List result = null;
try {
@@ -504,21 +509,62 @@ public class ActiveTable {
}
/**
- * Replaces the active table for the site with the new active table
+ * Updates the active table
*
- * @param siteId
- * the four letter site id to replace
* @param changes
* the updated table followed by the purged records
*/
- private static void updateTable(String siteId, MergeResult changes,
- ActiveTableMode mode) {
+ private static void updateTable(MergeResult changes, ActiveTableMode mode) {
List updated = changes.updatedList;
List purged = changes.purgedList;
+ // Check for multiple updates for the same active table key
+ Map updatesMap = new HashMap<>(
+ updated.size(), 1.0f);
+ for (ActiveTableRecord rec : updated) {
+ ActiveTableRecord prevRec = updatesMap.get(rec.getKey());
+
+ // if multiple updates select the one with the latest issueTime
+ if ((prevRec == null)
+ || rec.getIssueTime().after(prevRec.getIssueTime())) {
+ updatesMap.put(rec.getKey(), rec);
+
+ if (prevRec != null) {
+ statusHandler.warn("Multiple updates received for: "
+ + rec.getKey().toString() + "\n "
+ + prevRec.getVtecstr() + " " + prevRec.getUgcZone()
+ + "\n " + rec.getVtecstr() + " "
+ + rec.getUgcZone());
+ }
+ }
+ }
+
+ // Don't try to delete purged records that are being updated
+ List toDelete = new ArrayList<>(purged.size());
+ for (ActiveTableRecord rec : purged) {
+ if (!updatesMap.containsKey(rec.getKey())) {
+ toDelete.add(rec);
+ }
+ }
+
CoreDao dao = (ActiveTableMode.OPERATIONAL.equals(mode)) ? operationalDao
: practiceDao;
- dao.bulkSaveOrUpdateAndDelete(updated, purged);
+ try {
+ dao.bulkSaveOrUpdateAndDelete(updated, toDelete);
+ } catch (NonUniqueObjectException e) {
+ StringBuilder msg = new StringBuilder(
+ "Error saving updates to activetable\nUpdates:");
+ for (ActiveTableRecord rec : updated) {
+ msg.append("\n").append(rec.getAct()).append(" ")
+ .append(rec.getKey());
+ }
+ msg.append("\nDeletes:");
+ for (ActiveTableRecord rec : toDelete) {
+ msg.append("\n").append(rec.getAct()).append(" ")
+ .append(rec.getKey());
+ }
+ statusHandler.error(msg.toString(), e);
+ }
}
/**
@@ -657,7 +703,7 @@ public class ActiveTable {
}
if (result != null) {
- updateTable(siteId, result, tableName);
+ updateTable(result, tableName);
}
} finally {
if (writeLock != null) {
diff --git a/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/ActiveTable.py b/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/ActiveTable.py
index adca264cc3..24e1529748 100644
--- a/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/ActiveTable.py
+++ b/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/ActiveTable.py
@@ -33,6 +33,7 @@
# to a separate thread in java.
# Added performance logging
# 02/05/15 #4099 randerso Changed log level of year-end issuance tweak
+# May 22, 2015 4522 randerso Create proper primary key for ActiveTableRecord
#
import time
@@ -53,8 +54,9 @@ perfStat = PerformanceStatus.getHandler("ActiveTable")
class ActiveTable(VTECTableUtil.VTECTableUtil):
- def __init__(self, activeTableMode):
+ def __init__(self, activeTableMode, logger=None):
self._time = time.time()
+ self._logger = logger
# create a dummy name to simplify the file access code in VTECTableUtil
pathMgr = PathManagerFactory.getPathManager()
@@ -218,6 +220,7 @@ class ActiveTable(VTECTableUtil.VTECTableUtil):
"OldRec: ", self.printEntry(rec),
"\nReassign action to: ", rec['act'])
newR['act'] = rec['act']
+ rec['state'] = "Replaced"
break
#due to above code, this should never execute
if newR['act'] == "COR":
@@ -280,12 +283,11 @@ class ActiveTable(VTECTableUtil.VTECTableUtil):
#strip out the "state" field
outTable = []
for r in updatedTable:
- if r['state'] not in ["Replaced", "Purged"]:
- del r['state']
- outTable.append(r)
+ if r['state'] == "Purged":
+ purgedRecords.append(r)
else:
- purgedRecords.append(r)
-
+ outTable.append(r)
+
return outTable, purgedRecords, changes, changedFlag
def mergeFromJava(siteId, activeTable, newRecords, logger, mode, offsetSecs=0):
@@ -304,7 +306,7 @@ def mergeFromJava(siteId, activeTable, newRecords, logger, mode, offsetSecs=0):
rec = ActiveTableRecord.ActiveTableRecord(newRecords.get(i))
pyNew.append(rec)
- active = ActiveTable(mode)
+ active = ActiveTable(mode, logger)
logger.info("Updating " + mode + " Active Table: new records\n" +
active.printActiveTable(pyNew, combine=1))
@@ -321,29 +323,29 @@ def mergeFromJava(siteId, activeTable, newRecords, logger, mode, offsetSecs=0):
logger.info("Updated " + mode + " Active Table: purged\n" +
active.printActiveTable(purgeRecords, combine=1))
- replaced = []
- decoded = []
- other = []
+ stateDict = {}
for r in updatedTable:
- if r['state'] == "Replaced":
- replaced.append(r)
- elif r['state'] == "Decoded":
- decoded.append(r)
- else:
- other.append(r)
+ recs = stateDict.get(r['state'], [])
+ recs.append(r)
+ stateDict[r['state']] = recs
+
+ keys = stateDict.keys()
+ keys.sort()
+ for key in keys:
+ if key == "Previous":
+ continue
- logger.info("Updated " + mode + " Active Table: replaced\n" +
- active.printActiveTable(replaced, combine=1))
- logger.info("Updated " + mode + " Active Table: decoded\n" +
- active.printActiveTable(decoded, combine=1))
+ logger.info("Updated " + mode + " Active Table: "+ key +"\n" +
+ active.printActiveTable(stateDict[key], combine=1))
updatedList = ArrayList(len(updatedTable))
- for x in updatedTable:
- updatedList.add(x.javaRecord())
+ for r in updatedTable:
+ if r['state'] not in ["Previous", "Replaced"]:
+ updatedList.add(r.javaRecord())
purgedList = ArrayList(len(purgeRecords))
- for x in purgeRecords:
- purgedList.add(x.javaRecord())
+ for r in purgeRecords:
+ purgedList.add(r.javaRecord())
changeList = ArrayList(len(changes))
if (changedFlag):
diff --git a/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/ActiveTableRecord.py b/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/ActiveTableRecord.py
index bb6d549c55..2b0fb192a1 100644
--- a/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/ActiveTableRecord.py
+++ b/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/ActiveTableRecord.py
@@ -31,6 +31,7 @@
# __ne__().
# 07/23/13 2212 dgilling Fix typo in __eq__().
# 04/28/2015 4027 randerso Expunged Calendar from ActiveTableRecord
+# 05/22/2015 4522 randerso Create proper primary key for ActiveTableRecord
#
#
@@ -145,6 +146,7 @@ class ActiveTableRecord(object):
raise KeyError
def __delitem__(self, key):
+ # TODO: implement this
pass
def __deepcopy__(self, memo):
diff --git a/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/MergeVTEC.py b/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/MergeVTEC.py
index 4637aa661f..1e639069d3 100644
--- a/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/MergeVTEC.py
+++ b/edexOsgi/com.raytheon.uf.edex.activetable/utility/common_static/base/vtec/MergeVTEC.py
@@ -37,6 +37,7 @@
# 05/15/14 #3157 dgilling Support multiple TPC and SPC sites.
# 03/04/2015 #4129 randerso Log the active table changes at info level
# in the active table change log
+# May 22, 2015 4522 randerso Create proper primary key for ActiveTableRecord
#
##
@@ -370,8 +371,6 @@ class MergeVTEC(VTECTableUtil.VTECTableUtil):
self.printActiveTable(ignoredOldReplaceAct, 1))
atChangeLog.info("Table Changes: " + str(changes))
- purges.extend(oldReplaceEntriesAct)
- purges.extend(oldReplaceEntriesPast)
return activeTable, purges, changes
def getMergeResults(self):