diff --git a/build/deploy.edex.awips2/esb/conf/logback-activeTableChange.xml b/build/deploy.edex.awips2/esb/conf/logback-activeTableChange.xml new file mode 100644 index 0000000000..4d8a393a23 --- /dev/null +++ b/build/deploy.edex.awips2/esb/conf/logback-activeTableChange.xml @@ -0,0 +1,18 @@ + + + + + activeTableChange + + + + + + + + + + + + + diff --git a/build/deploy.edex.awips2/esb/conf/logback-ingest.xml b/build/deploy.edex.awips2/esb/conf/logback-ingest.xml index baa19b2839..680c7ee748 100644 --- a/build/deploy.edex.awips2/esb/conf/logback-ingest.xml +++ b/build/deploy.edex.awips2/esb/conf/logback-ingest.xml @@ -11,16 +11,7 @@ - - - activeTableChange - - - - - - - + @@ -89,11 +80,6 @@ - - - - - diff --git a/build/deploy.edex.awips2/esb/conf/logback-request.xml b/build/deploy.edex.awips2/esb/conf/logback-request.xml index 3ca6e1f224..16afccc484 100644 --- a/build/deploy.edex.awips2/esb/conf/logback-request.xml +++ b/build/deploy.edex.awips2/esb/conf/logback-request.xml @@ -60,6 +60,10 @@ + + + + diff --git a/build/deploy.edex.awips2/esb/conf/logback.xml b/build/deploy.edex.awips2/esb/conf/logback.xml index 2ab98fb8f3..9311daf089 100644 --- a/build/deploy.edex.awips2/esb/conf/logback.xml +++ b/build/deploy.edex.awips2/esb/conf/logback.xml @@ -5,24 +5,6 @@ - - - - activeTableChange - - - - - - - - - - - - - - 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):