13.5.1-15 baseline

Former-commit-id: c6dc1817e7 [formerly dbf9107f9c775f9a1df759bc341c0722f5fc92f2]
Former-commit-id: 53e96e21db
This commit is contained in:
Steve Harris 2013-08-14 10:24:26 -04:00
parent b848317203
commit 535218c676
13 changed files with 1034 additions and 189 deletions

View file

@ -20,6 +20,8 @@
package com.raytheon.viz.gfe.vtec;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import com.google.common.base.Strings;
@ -44,6 +46,9 @@ import com.raytheon.viz.texteditor.util.VtecUtil;
* Jul 19, 2013 #1842 dgilling Use VtecUtil.replaceFirstVtecString()
* to ensure start times of in progress
* events aren't set to the wrong time.
* Aug 07, 2013 #1842 dgilling Fix ETN assignment for products with
* multiple NEW segments with the same
* phensig.
*
* </pre>
*
@ -82,6 +87,13 @@ public class GFEVtecUtil {
return message;
}
// With GFE VTEC products, it's possible to have multiple segments with
// NEW vtec action codes and the same phensig. For this reason,
// HazardsTable.py implemented a "cache" that would ensure all NEWs for
// the same phensig would be assigned the same ETN. This Map replicates
// that legacy behavior.
Map<String, Integer> etnCache = new HashMap<String, Integer>();
Matcher vtecMatcher = VtecUtil.VTEC_REGEX.matcher(message);
StringBuffer finalOutput = new StringBuffer();
while (vtecMatcher.find()) {
@ -93,8 +105,13 @@ public class GFEVtecUtil {
&& ((!NATIONAL_PHENSIGS.contains(vtec.getPhensig())) || (IGNORE_NATIONAL_ETN
.contains(vtec.getOffice()) && TROPICAL_PHENSIGS
.contains(vtec.getPhensig())))) {
int newEtn = VtecUtil.getNextEtn(vtec.getOffice(),
String cacheKey = vtec.getPhensig();
Integer newEtn = etnCache.get(cacheKey);
if (newEtn == null) {
newEtn = VtecUtil.getNextEtn(vtec.getOffice(),
vtec.getPhensig(), true);
etnCache.put(cacheKey, newEtn);
}
vtec.setSequence(newEtn);
}
vtecMatcher

View file

@ -37,6 +37,7 @@ import com.raytheon.uf.common.time.util.TimeUtil;
* ------------ ---------- ----------- --------------------------
* Initial creation
* May 7, 2013 1973 rferrel Changes to properly display Issue Time.
* Aug 7, 2013 2243 jsanchez Set all the attributes of an AbstractWarningRecord and added an expiration string.
*
* </pre>
*
@ -50,22 +51,25 @@ public class FollowupData extends WarningRecord {
/**
* String displayed in the drop down update list.
*/
public String displayString;
private String displayString;
/**
* String used to test if this object is equivalent to one of the updated
* items in the drop down.
*/
public String equvialentString;
private String equvialentString;
/**
* Information string used when the follow up is no longer valid or allowed.
*/
private String expirationString;
public FollowupData(WarningAction action, AbstractWarningRecord record) {
super((WarningRecord) record);
setAct(action.toString());
setOfficeid(record.getOfficeid());
setPhen(record.getPhen());
setSig(record.getSig());
setEtn(record.getEtn());
displayString = getDisplayString(action, record);
displayString = createDisplayString(action, record);
expirationString = createExpirationString(action);
}
/**
@ -76,7 +80,7 @@ public class FollowupData extends WarningRecord {
* @param record
* @return
*/
private String getDisplayString(WarningAction status,
private String createDisplayString(WarningAction status,
AbstractWarningRecord record) {
StringBuilder rval = new StringBuilder();
if (record.getProductClass().equals("T")) {
@ -98,6 +102,29 @@ public class FollowupData extends WarningRecord {
return rval.toString();
}
/**
* Creates the expiration string based on the action. The expiration string
* provides an explanation of why the follow up data is no longer valid.
*
* @param action
* @return
*/
private String createExpirationString(WarningAction action) {
String message = null;
if (action == WarningAction.NEW) {
message = "Reissue no longer allowed; after 30 minutes of warning expiration.";
} else if (action == WarningAction.COR) {
message = "Correction no longer allowed; after 10 minutes of warning issuance.";
} else if (action == WarningAction.CAN) {
message = "Cancellation no longer allowed; within 10 minutes of warning expiration.";
} else if (action == WarningAction.CON) {
message = "Continuation no longer allowed; within 5 minutes of warning expiration.";
} else if (action == WarningAction.EXP) {
message = "Expiration no longer allowed; after 10 minutes of warning expiration.";
}
return message;
}
/**
* Builds a string informing the user when a product was issued or when it
* will expire. This is appended to the product in the "Update List"
@ -143,4 +170,16 @@ public class FollowupData extends WarningRecord {
&& this.getEtn().equals(obj.getEtn());
}
public String getDisplayString() {
return displayString;
}
public String getEquvialentString() {
return equvialentString;
}
public String getExpirationString() {
return expirationString;
}
}

View file

@ -69,7 +69,6 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.SimulatedTime;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.viz.core.IDisplayPaneContainer;
import com.raytheon.uf.viz.core.VizApp;
import com.raytheon.uf.viz.core.exception.VizException;
@ -142,6 +141,7 @@ import com.vividsolutions.jts.geom.Polygon;
* Jun 24, 2013 DR 16317 D. Friedman Handle "motionless" track.
* Jul 16, 2013 DR 16387 Qinglu Lin Reset totalSegments for each followup product.
* Jul 29, 2013 DR 16352 D. Friedman Move 'result' to okPressed().
* Aug 6, 2013 2243 jsanchez Refreshed the follow up list every minute.
* </pre>
*
* @author chammack
@ -274,9 +274,9 @@ public class WarngenDialog extends CaveSWTDialog implements
private Group productType;
private IWarngenObserver wed = new WarningSender();
private boolean invalidFollowUpAction = false;
private TimeRange timeRange = null;
private IWarngenObserver wed = new WarningSender();
public WarngenDialog(Shell parentShell, WarngenLayer layer) {
super(parentShell, SWT.CLOSE | SWT.MODELESS | SWT.BORDER | SWT.TITLE,
@ -823,6 +823,9 @@ public class WarngenDialog extends CaveSWTDialog implements
|| warngenLayer.getPolygon().isEmpty()) {
str += WarngenConstants.INSTRUCTION_NO_SHADED_AREA;
createTextButtonEnabled = false;
} else if (invalidFollowUpAction) {
str += "Select a different follow up item";
createTextButtonEnabled = false;
}
if (okButton != null) {
okButton.setEnabled(createTextButtonEnabled);
@ -831,8 +834,8 @@ public class WarngenDialog extends CaveSWTDialog implements
if (warngenLayer.getWarningArea() == null) {
str = "Area selected has no overlap with current area of responsibility";
} else {
if (warngenLayer.getStormTrackState().isInitiallyMotionless() &&
! warngenLayer.getStormTrackState().isNonstationary()) {
if (warngenLayer.getStormTrackState().isInitiallyMotionless()
&& !warngenLayer.getStormTrackState().isNonstationary()) {
str += WarngenConstants.INSTRUCTION_DRAG_STORM + "\n";
} else if (warngenLayer.getStormTrackState().trackVisible) {
str += "Adjust Centroid in any Frame" + "\n";
@ -880,7 +883,7 @@ public class WarngenDialog extends CaveSWTDialog implements
if (FollowUpUtil.checkApplicable(site,
warngenLayer.getConfiguration(), warnings.get(i), act)) {
FollowupData data = new FollowupData(act, warnings.get(i));
updateListCbo.setData(data.displayString, data);
updateListCbo.setData(data.getDisplayString(), data);
if (act == WarningAction.NEW) {
newYes = true;
} else if (act == WarningAction.EXT) {
@ -892,7 +895,7 @@ public class WarngenDialog extends CaveSWTDialog implements
} else if (act == WarningAction.COR) {
corYes = true;
}
dropDownItems.add(data.displayString);
dropDownItems.add(data.getDisplayString());
}
}
}
@ -930,19 +933,54 @@ public class WarngenDialog extends CaveSWTDialog implements
updateListCbo.add(dropDownItems.get(i));
}
// Select the previously selected item.
invalidFollowUpAction = false;
if (currentSelection != null) {
boolean isValid = false;
for (int i = 0; i < updateListCbo.getItemCount(); i++) {
if (updateListCbo.getItem(i).startsWith(
currentSelection.equvialentString)) {
currentSelection.getEquvialentString())) {
updateListCbo.select(i);
isValid = true;
break;
}
}
if (!isValid) {
invalidFollowUpAction = true;
preventFollowUpAction(currentSelection);
}
} else {
updateListCbo.select(0);
}
}
/**
* Prevents the user from creating text when the current selection is no
* longer valid or available in the update list. The polygon will also be
* locked from being modified and return to it's last issued state if the
* polygon was temporarily modified.
*
* @param currentSelection
*/
private void preventFollowUpAction(FollowupData currentSelection) {
try {
warngenLayer.createPolygonFromRecord(currentSelection);
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM,
"Error resetting the polygon\n", e);
}
bulletList.setEnabled(false);
setPolygonLocked(true);
setTrackLocked(true);
refreshDisplay();
// Provide an info message when this situation occurs
statusHandler.handle(Priority.PROBLEM,
currentSelection.getExpirationString());
}
/**
* Set the possible durations
*
@ -995,8 +1033,8 @@ public class WarngenDialog extends CaveSWTDialog implements
return;
}
if (followupData != null && WarningAction.valueOf(followupData
.getAct()) == WarningAction.NEW) {
if (followupData != null
&& WarningAction.valueOf(followupData.getAct()) == WarningAction.NEW) {
redrawFromWarned();
}
@ -1021,9 +1059,10 @@ public class WarngenDialog extends CaveSWTDialog implements
try {
monitor.beginTask("Generating product", 1);
long t0 = System.currentTimeMillis();
String result = TemplateRunner.runTemplate(warngenLayer,
startTime.getTime(), endTime.getTime(),
selectedBullets, followupData, backupData);
String result = TemplateRunner.runTemplate(
warngenLayer, startTime.getTime(),
endTime.getTime(), selectedBullets,
followupData, backupData);
resultContainer[0] = result;
Matcher m = FollowUpUtil.vtecPtrn.matcher(result);
totalSegments = 0;
@ -1123,15 +1162,7 @@ public class WarngenDialog extends CaveSWTDialog implements
// again after a product was issued.AWIPS I does not auto update their
// update list, this is their solution.
if (followupData != null && totalSegments > 1) {
multiSegmentMessage(followupData.equvialentString);
return false;
}
if (timeRange != null
&& timeRange.contains(SimulatedTime.getSystemTime().getTime()) == false) {
// The action is no longer available in the follow up/update list
statusHandler.handle(Priority.PROBLEM,
"Follow up product has nothing to follow up.");
multiSegmentMessage(followupData.getEquvialentString());
return false;
}
@ -1188,7 +1219,6 @@ public class WarngenDialog extends CaveSWTDialog implements
bulletList.setEnabled(true);
recreateUpdates();
damBreakInstruct = null;
timeRange = null;
extEndTime = null;
totalSegments = 0;
bulletListManager.recreateBullets(warngenLayer.getConfiguration()
@ -1425,7 +1455,6 @@ public class WarngenDialog extends CaveSWTDialog implements
warngenLayer.state.followupData = null;
warngenLayer.getStormTrackState().endTime = null;
damBreakInstruct = null;
timeRange = null;
extEndTime = null;
totalSegments = 0;
@ -1448,6 +1477,8 @@ public class WarngenDialog extends CaveSWTDialog implements
changeBtn.setEnabled(!enableDuration);
recreateDurations(durationList);
// Current selection doesn't matter anymore
updateListCbo.select(0);
// update list
recreateUpdates();
@ -1571,7 +1602,8 @@ public class WarngenDialog extends CaveSWTDialog implements
.valueOf(warngenLayer.state.followupData
.getAct()) == WarningAction.CON
&& totalSegments > 1) {
sameProductMessage(warngenLayer.state.followupData.equvialentString);
sameProductMessage(warngenLayer.state.followupData
.getEquvialentString());
}
return;
}
@ -1581,7 +1613,8 @@ public class WarngenDialog extends CaveSWTDialog implements
// Sets the updatelist with the last selected vtec option
for (int i = 0; i < updateListCbo.getItemCount(); i++) {
String item = updateListCbo.getItem(i);
if (item.equals(warngenLayer.state.followupData.displayString)) {
if (item.equals(warngenLayer.state.followupData
.getDisplayString())) {
updateListCbo.select(i);
updateListCbo.setText(item);
data = warngenLayer.state.followupData;
@ -1823,6 +1856,32 @@ public class WarngenDialog extends CaveSWTDialog implements
}
timer.schedule(updateTimeTask, delay, delay);
TimerTask recreateUpdatesTask = new TimerTask() {
@Override
public void run() {
getDisplay().syncExec(new Runnable() {
public void run() {
try {
recreateUpdates();
} catch (Exception e) {
statusHandler.handle(Priority.PROBLEM,
"WarnGen Error", e);
}
}
});
}
};
// Update the follow up list every minute
long currentTimeInSeconds = SimulatedTime.getSystemTime().getMillis() / 1000;
long secondsToNextMinute = 0;
if (currentTimeInSeconds % 60 != 0) {
secondsToNextMinute = 60 - (currentTimeInSeconds % 60);
}
timer.schedule(recreateUpdatesTask, secondsToNextMinute * 1000,
60 * 1000);
}
/**
@ -1897,7 +1956,7 @@ public class WarngenDialog extends CaveSWTDialog implements
statusHandler.handle(Priority.PROBLEM,
"Error creating polygon from the record\n", e);
}
timeRange = FollowUpUtil.getTimeRange(WarningAction.CON, newWarn);
return newWarn;
}
@ -1943,7 +2002,7 @@ public class WarngenDialog extends CaveSWTDialog implements
"Error creating polygon from the record\n", e);
}
}
timeRange = FollowUpUtil.getTimeRange(WarningAction.COR, newWarn);
return newWarn;
}
@ -1981,7 +2040,7 @@ public class WarngenDialog extends CaveSWTDialog implements
statusHandler.handle(Priority.PROBLEM,
"Error creating polygon from the record\n", e);
}
timeRange = FollowUpUtil.getTimeRange(WarningAction.EXP, newWarn);
return newWarn;
}
@ -2019,7 +2078,7 @@ public class WarngenDialog extends CaveSWTDialog implements
statusHandler.handle(Priority.PROBLEM,
"Error creating polygon from the record\n", e);
}
timeRange = FollowUpUtil.getTimeRange(WarningAction.CAN, newWarn);
return newWarn;
}
@ -2044,7 +2103,7 @@ public class WarngenDialog extends CaveSWTDialog implements
statusHandler.handle(Priority.PROBLEM,
"Error creating polygon from the record\n", e);
}
timeRange = null;
return newWarn;
}
@ -2087,7 +2146,7 @@ public class WarngenDialog extends CaveSWTDialog implements
statusHandler.handle(Priority.PROBLEM,
"Error creating polygon from the record\n", e);
}
timeRange = FollowUpUtil.getTimeRange(WarningAction.EXT, newWarn);
return newWarn;
}

View file

@ -29,6 +29,7 @@ import com.raytheon.viz.warngen.text.ICommonPatterns;
* Jul 22, 2008 #1284 bwoodle Initial creation
* Oct 18, 2012 15332 jsanchez Fixed refactor bugs.
* Mar 13, 2013 DR 15892 D. Friedman Handle SMW format in canceledAreasFromText
* Aug 6, 2013 2243 jsanchez Updated the time ranges to be removed from the follow up list correctly.
*
* </pre>
*
@ -202,7 +203,8 @@ public class FollowUpUtil {
headline += line;
}
}
String[] ugcs = FipsUtil.getListCounties(ugcLine).toArray(new String[0]);
String[] ugcs = FipsUtil.getListCounties(ugcLine)
.toArray(new String[0]);
String[] names;
boolean smwAreas = false;
if (namesLine.length() > 0)
@ -242,7 +244,8 @@ public class FollowUpUtil {
if (i < names.length) {
if (!smwAreas && names[i].length() >= 3) {
name = names[i].substring(0, names[i].length() - 3);
stateAbbreviation = names[i].substring(names[i].length() - 2);
stateAbbreviation = names[i]
.substring(names[i].length() - 2);
} else {
name = names[i];
}
@ -314,48 +317,54 @@ public class FollowUpUtil {
TimeRange rval = null;
// The time ranges are offset by 1 minute so that after a refresh and on
// the final minute of the time range the follow up data will be
// removed. For example, if a CON is only a available until 5 minutes
// before a warnings expiration, when the time reaches 5 minutes the
// follow up data for a CON is correctly removed.
if (action == WarningAction.NEW) {
/* Calculate NEW Time Range */
start.setTime(record.getEndTime().getTime());
start.add(Calendar.MINUTE, -20);
start.add(Calendar.MINUTE, -21);
end.setTime(record.getEndTime().getTime());
end.add(Calendar.MINUTE, 30);
end.add(Calendar.MINUTE, 29);
rval = new TimeRange(start, end);
} else if (action == WarningAction.COR) {
/* Calculate COR Time Range */
end.setTime(record.getIssueTime().getTime());
end.add(Calendar.MINUTE, 10);
end.add(Calendar.MINUTE, 9);
rval = new TimeRange(record.getStartTime(), end);
} else if (action == WarningAction.CAN) {
/* Calculate CAN Time Range */
end.setTime(record.getEndTime().getTime());
end.add(Calendar.MINUTE, -10);
end.add(Calendar.MINUTE, -11);
rval = new TimeRange(record.getStartTime(), end);
} else if (action == WarningAction.CON) {
/* Calculate CON Time Range */
end.setTime(record.getEndTime().getTime());
end.add(Calendar.MINUTE, -5);
end.add(Calendar.MINUTE, -6);
rval = new TimeRange(record.getStartTime(), end);
} else if (action == WarningAction.EXP) {
/* Calculate EXP Time Range */
start.setTime(record.getEndTime().getTime());
start.add(Calendar.MINUTE, -10);
start.add(Calendar.MINUTE, -11);
end.setTime(record.getEndTime().getTime());
end.add(Calendar.MINUTE, 10);
end.add(Calendar.MINUTE, 9);
rval = new TimeRange(start, end);
} else if (action == WarningAction.EXT) {
/* Calculate EXT Time Range */
start.setTime(record.getStartTime().getTime());
end.setTime(record.getEndTime().getTime());
end.add(Calendar.MINUTE, -5);
end.add(Calendar.MINUTE, -6);
rval = new TimeRange(start, end);
}
return rval;
}
/** Parses the canceled areas of an SMW, which have a different format
* from other products.
/**
* Parses the canceled areas of an SMW, which have a different format from
* other products.
*/
private static String[] parseSMWCanceledAreas(String[] splitLines) {
StringBuilder text = new StringBuilder(64);

View file

@ -24,6 +24,7 @@
<parameter name="staElev" queryName="location.elevation" type="FLOAT" unit="m" />
<parameter name="rptType" queryName="reportType" type="INT" />
<parameter name="dataURI" queryName="dataURI" type="STRING" />
<parameter name="stationId" queryName="location.stationId" type="STRING" />
<parameter name="validTime" queryName="validTime" numDims="1" type="LONG" unit="ms" />
<parameter name="relTime" queryName="validTime" numDims="1" type="LONG" unit="ms" />
<parameter name="refTime" queryName="dataTime.refTime" numDims="1" type="LONG" unit="ms" />

View file

@ -93,6 +93,8 @@ import com.raytheon.uf.edex.database.query.DatabaseQuery;
* 05/22/13 #2025 dgilling Re-implement functions needed by
* GetLatestDbTimeRequest and GetLatestModelDbIdRequest.
* 05/20/13 #2127 rjpeter Set session's to read only and switched to stateless where possible.
* 08/08/13 DR16485 ryu Remove call to getDatabaseId() from getMaxInsertTimeByDbId()
* so new GFE databases aren't accidentally created.
* </pre>
*
* @author bphillip
@ -1126,7 +1128,13 @@ public class GFEDao extends DefaultPluginDao {
public Date getMaxInsertTimeByDbId(final DatabaseID dbId)
throws DataAccessLayerException {
DatabaseQuery query = new DatabaseQuery(this.daoClass);
query.addQueryParam("parmId.dbId", getDatabaseId(dbId),
query.addQueryParam("parmId.dbId.siteId", dbId.getSiteId(),
QueryOperand.EQUALS);
query.addQueryParam("parmId.dbId.format", dbId.getFormat(),
QueryOperand.EQUALS);
query.addQueryParam("parmId.dbId.modelName", dbId.getModelName(),
QueryOperand.EQUALS);
query.addQueryParam("parmId.dbId.modelTime", dbId.getModelTime(),
QueryOperand.EQUALS);
query.addReturnedField("insertTime");
query.addOrder("insertTime", false);

View file

@ -28,6 +28,8 @@ import java.util.TreeMap;
import javax.persistence.Transient;
import com.raytheon.uf.common.dataplugin.ffmp.collections.ArrayBackedMap;
import com.raytheon.uf.common.dataplugin.ffmp.collections.BasinMapFactory;
import com.raytheon.uf.common.serialization.ISerializableObject;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
@ -48,6 +50,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
* TreeMap creation to the tertiary loader.
* Apr 26, 2013 1954 bsteffen Minor code cleanup throughout FFMP.
* Jul 15, 2013 2184 dhladky Remove all HUC's for storage except ALL
* Jul 31, 2013 2242 bsteffen Optimize FFMP NavigableMap memory.
*
* </pre>
*
@ -71,6 +74,13 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
@Transient
protected NavigableMap<Date, Float> values;
/**
* Set to either the values map or the BasinMapFactory that was used to
* create it to enable correct synchronization.
*/
@Transient
protected Object valuesSynchronization;
/** object used for serialization **/
@DynamicSerializeElement
public float[] serializedValues;
@ -172,9 +182,9 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
Date prevDate = null;
// map ordered newest first, so grab from newest date to oldest date
if (afterDate.before(beforeDate) && (values.size() > 0)) {
if (afterDate.before(beforeDate) && (!values.isEmpty())) {
synchronized (values) {
synchronized (valuesSynchronization) {
float factor = 0.0f;
@ -226,7 +236,7 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
*/
public Float getValue(Date afterDate, Date beforeDate) {
Float val = 0.0f;
synchronized (values) {
synchronized (valuesSynchronization) {
Date checkDate = values.ceilingKey(afterDate);
if ((checkDate != null) && checkDate.before(beforeDate)) {
val = values.get(checkDate);
@ -260,7 +270,7 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
Float val = 0.0f;
int i = 0;
synchronized (values) {
synchronized (valuesSynchronization) {
for (Date date : values.keySet()) {
if (date.before(beforeDate) && date.after(afterDate)) {
@ -290,7 +300,7 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
public Float getMaxValue(Date afterDate, Date beforeDate) {
Float val = 0.0f;
synchronized (values) {
synchronized (valuesSynchronization) {
for (Date date : values.keySet()) {
if (date.before(beforeDate) && date.after(afterDate)) {
@ -312,13 +322,7 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
* @param value
*/
public void setValue(Date date, Float dvalue) {
synchronized (values) {
if (!(values instanceof TreeMap) && !values.containsKey(dvalue)) {
// ArrayBackedMap may have been used if this basin was
// deserialized. It is much faster to do inserts on a TreeMap so
// convert now.
values = new TreeMap<Date, Float>(values);
}
synchronized (valuesSynchronization) {
values.put(date, dvalue);
}
}
@ -339,6 +343,7 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
*/
public void setValues(TreeMap<Date, Float> values) {
this.values = values;
this.valuesSynchronization = values;
}
/**
@ -347,6 +352,7 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
public FFMPBasin() {
values = new TreeMap<Date, Float>(Collections.reverseOrder());
valuesSynchronization = values;
}
/**
@ -358,6 +364,15 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
setPfaf(pfaf);
setAggregated(aggregated);
values = new TreeMap<Date, Float>(Collections.reverseOrder());
valuesSynchronization = values;
}
public FFMPBasin(Long pfaf, boolean aggregated,
BasinMapFactory<Date> mapFactory) {
setPfaf(pfaf);
setAggregated(aggregated);
values = mapFactory.getMap();
valuesSynchronization = mapFactory;
}
/**
@ -365,16 +380,16 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
*
* @param times
*/
public void deserialize(long[] times) {
public void deserialize(long[] times, BasinMapFactory<Date> mapFactory) {
// safe to avoid Array Index Exceptions / shouldn't happen but.....
if (serializedValues != null
&& (times.length == serializedValues.length)) {
NavigableMap<Date, Float> fastMap = new ArrayBackedMap(times,
serializedValues);
values = fastMap.descendingMap();
// values = new TreeMap<Date, Float>(fastMap.descendingMap());
values = mapFactory.getMap(fastMap.descendingMap());
valuesSynchronization = mapFactory;
}
serializedValues = null;
}
@ -401,7 +416,7 @@ public class FFMPBasin implements ISerializableObject, Cloneable {
*/
public void purgeData(Date date) {
if (values != null) {
synchronized (values) {
synchronized (valuesSynchronization) {
ArrayList<Date> removes = new ArrayList<Date>();
for (Date mdate : values.keySet()) {
if (mdate.before(date)) {

View file

@ -22,6 +22,7 @@ package com.raytheon.uf.common.dataplugin.ffmp;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
@ -29,6 +30,7 @@ import java.util.List;
import java.util.Map;
import com.raytheon.uf.common.dataplugin.ffmp.FFMPDataRecordLoader.LoadTask;
import com.raytheon.uf.common.dataplugin.ffmp.collections.BasinMapFactory;
import com.raytheon.uf.common.datastorage.DataStoreFactory;
import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
import com.raytheon.uf.common.monitor.config.FFMPSourceConfigurationManager;
@ -55,6 +57,8 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
* 07/09/13 2152 njensen Ensure purgeData() does not load data
* Jul 15, 2013 2184 dhladky Remove all HUC's for storage except ALL
* 07/16/13 2197 njensen Added hasAnyBasins() and moved getBasins() calls out of loops
* Jul 31, 2013 2242 bsteffen Optimize FFMP NavigableMap memory.
*
*
* </pre>
*
@ -83,6 +87,20 @@ public class FFMPBasinData implements ISerializableObject {
*/
private final Map<String, FFMPBasin[]> orderedBasinsCache = new HashMap<String, FFMPBasin[]>();
/**
* Shared factory for efficient storage of data in basins.
*/
private BasinMapFactory<Date> mapFactory = null;
/**
* Public one arg constructor
*
* @param huc_level
*/
public FFMPBasinData(String hucLevel) {
setHucLevel(hucLevel);
}
/**
* No arg hibernate constructor
*/
@ -673,12 +691,17 @@ public class FFMPBasinData implements ISerializableObject {
*/
public void populate(List<Long> times) {
if (mapFactory == null) {
mapFactory = new BasinMapFactory<Date>(Collections.reverseOrder(),
getBasins().size());
}
long[] timesArr = new long[times.size()];
for (int i = 0; i < timesArr.length; i += 1) {
timesArr[i] = times.get(i);
}
for (FFMPBasin basin : getBasins().values()) {
basin.deserialize(timesArr);
basin.deserialize(timesArr, mapFactory);
}
}
@ -736,7 +759,12 @@ public class FFMPBasinData implements ISerializableObject {
if (guidance) {
basin = new FFMPGuidanceBasin(pfaf, aggregate);
} else {
basin = new FFMPBasin(pfaf, aggregate);
if (mapFactory == null) {
mapFactory = new BasinMapFactory<Date>(
Collections.reverseOrder(),
orderedPfafs.size());
}
basin = new FFMPBasin(pfaf, aggregate, mapFactory);
}
this.basins.put(pfaf, basin);
}

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.dataplugin.ffmp;
package com.raytheon.uf.common.dataplugin.ffmp.collections;
import java.util.AbstractMap;
import java.util.AbstractSet;
@ -34,7 +34,6 @@ import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
/**
@ -67,6 +66,8 @@ import java.util.TreeMap;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 18, 2013 bsteffen Initial creation
* Jul 31, 2013 2242 bsteffen Extracted NavigableKeySet to its own
* file and moved to collections package.
*
* </pre>
*
@ -264,7 +265,7 @@ public class ArrayBackedMap extends AbstractMap<Date, Float> implements
@Override
public NavigableSet<Date> navigableKeySet() {
return new NavigableKeySet(this);
return new NavigableKeySet<Date>(this);
}
private int lowerIndex(Date key, boolean inclusive) {
@ -592,113 +593,7 @@ public class ArrayBackedMap extends AbstractMap<Date, Float> implements
}
private static class NavigableKeySet extends AbstractSet<Date> implements
NavigableSet<Date> {
private final NavigableMap<Date, Float> map;
public NavigableKeySet(NavigableMap<Date, Float> map) {
this.map = map;
}
@Override
public Iterator<Date> iterator() {
return map.keySet().iterator();
}
@Override
public int size() {
return map.size();
}
@Override
public Comparator<? super Date> comparator() {
return map.comparator();
}
@Override
public Date first() {
return map.firstKey();
}
@Override
public Date last() {
return map.lastKey();
}
@Override
public Date lower(Date e) {
return map.lowerKey(e);
}
@Override
public Date floor(Date e) {
return map.floorKey(e);
}
@Override
public Date ceiling(Date e) {
return map.ceilingKey(e);
}
@Override
public Date higher(Date e) {
return map.higherKey(e);
}
@Override
public Date pollFirst() {
return map.pollFirstEntry().getKey();
}
@Override
public Date pollLast() {
return map.pollLastEntry().getKey();
}
@Override
public NavigableSet<Date> descendingSet() {
return map.descendingKeySet();
}
@Override
public Iterator<Date> descendingIterator() {
return descendingSet().iterator();
}
@Override
public NavigableSet<Date> subSet(Date fromElement,
boolean fromInclusive, Date toElement, boolean toInclusive) {
return map.subMap(fromElement, fromInclusive, toElement,
toInclusive).navigableKeySet();
}
@Override
public NavigableSet<Date> headSet(Date toElement, boolean inclusive) {
return map.headMap(toElement, inclusive).navigableKeySet();
}
@Override
public NavigableSet<Date> tailSet(Date fromElement, boolean inclusive) {
return map.tailMap(fromElement, inclusive).navigableKeySet();
}
@Override
public SortedSet<Date> subSet(Date fromElement, Date toElement) {
return subSet(fromElement, true, toElement, false);
}
@Override
public SortedSet<Date> headSet(Date toElement) {
return headSet(toElement, false);
}
@Override
public SortedSet<Date> tailSet(Date fromElement) {
return tailSet(fromElement, true);
}
}
private class SubMap extends AbstractMap<Date, Float> implements
NavigableMap<Date, Float> {
@ -854,7 +749,7 @@ public class ArrayBackedMap extends AbstractMap<Date, Float> implements
@Override
public NavigableSet<Date> navigableKeySet() {
return new NavigableKeySet(this);
return new NavigableKeySet<Date>(this);
}
@Override
@ -1066,7 +961,7 @@ public class ArrayBackedMap extends AbstractMap<Date, Float> implements
@Override
public NavigableSet<Date> navigableKeySet() {
return new NavigableKeySet(this);
return new NavigableKeySet<Date>(this);
}
@Override

View file

@ -0,0 +1,621 @@
/**
* 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.dataplugin.ffmp.collections;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Set;
import java.util.TreeMap;
/**
* Factory for constructing maps to use in FFMPBasins for organizing values.
*
* Each basin in FFMP requires a NavigableMap<Date,Float> in order to achieve
* fast dynamic calculations. Unfortunately due to the large number of basins
* TreeMaps require too much memory. This factory produces maps that have the
* same performance as TreeMaps but are much more memory efficient.
*
* This factory achieves efficiency by taking advantage of the fact that all
* basins will have data for the same times, so it can use a single TreeMap as
* the backing map for all basins. Each NavigableMap returned from this factory
* is simply a view into the backing map.
*
* Because all maps returned from this factory use the same backing map, they
* cannot be synchronized individually. Internally all map modifications are
* synchronized on the factory object to prevent concurrent modification. If any
* iterators are being used from any maps then the iteration should also be
* synchronized on the factory.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 30, 2013 2242 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class BasinMapFactory<K> {
/*
* How much to grow the backing arrays to make room for new maps, this is
* much more conservative than the algorithms used by ArrayList or HashMap
* because typically growth will occur very briefly during initialization
* and the extra overhead of a slower growth rate is minimal. Once all
* basins are created, growth will stop and a conservative growth algorithm
* limits wasted memory after the initial growth phase.
*/
private static final int GROWTH_RATE = 32;
/* The amount of space allocated in each value. */
protected volatile int allocated_size;
/* The number of indices used in maps so far. */
private volatile int used_size;
/* This is the real navigable map, responsible for all real work. */
private final NavigableMap<K, MultiValue> backingMap;
/**
* Create a new factory
*
* @param comparator
* the comparator to use for map keys
* @param initialSize
* the amount of space to preallocate for basin maps.
*/
public BasinMapFactory(Comparator<? super K> comparator, int initialSize) {
allocated_size = initialSize;
used_size = 0;
this.backingMap = new TreeMap<K, MultiValue>(comparator);
}
/**
* Get a new map from this factory.
*
* @return
*/
public NavigableMap<K, Float> getMap() {
return new MapView<K>(this, getNextIndex(),
backingMap);
}
/**
* Get a new map from this factory, populated with all the values from m. If
* m has the same keyset as other maps in this factory than this will
* populate the new map faster than putAll.
*
* @param m
* NavigableMap, must have the same comparator as this factory.
* @return
*/
public NavigableMap<K, Float> getMap(NavigableMap<K, Float> m) {
Comparator<? super K> bc = backingMap.comparator();
Comparator<? super K> mc = m.comparator();
if (mc != bc && (mc == null || !mc.equals(bc))) {
throw new IllegalArgumentException(
"Maps can only be constructed if the compators are the same.");
}
int index = getNextIndex();
Iterator<Entry<K, MultiValue>> bit = backingMap.entrySet().iterator();
Iterator<Entry<K, Float>> mit = m.entrySet().iterator();
NavigableMap<K, Float> r = new MapView<K>(this, index,
backingMap);
/*
* If both maps have the same keys, then iterating both simultaneously
* is faster than multiple puts because it avoids doing multiple lookups
*/
while (bit.hasNext() && mit.hasNext()) {
Entry<K, MultiValue> bent = bit.next();
Entry<K, Float> ment = mit.next();
if (ment.getKey().equals(bent.getKey())) {
bent.getValue().put(index, ment.getValue());
} else {
/* It turns out keys are not equals */
r.put(ment.getKey(), ment.getValue());
break;
}
}
/*
* This loop is only used if the backingMap was empty or if for some
* reason the backingMap and the new map do not have the same keys.
*/
while (mit.hasNext()) {
Entry<K, Float> ment = mit.next();
r.put(ment.getKey(), ment.getValue());
}
return r;
}
/* get the next free index for use in a MapView */
private int getNextIndex() {
synchronized (this) {
int index = used_size;
used_size += 1;
if (used_size >= allocated_size) {
allocated_size += GROWTH_RATE;
for (MultiValue v : backingMap.values()) {
v.grow(allocated_size);
}
}
return index;
}
}
/**
* Value within the backing map. This contains the raw data values for each
* basin. In addition it contains a boolean for each basin indicating if the
* value has been set. While most of the time all basins will be set, the
* extra boolean is needed to allow different views to function as
* independent maps, which is needed while new data is getting added.
*/
private static class MultiValue {
/* actual values for all basins. */
private float[] data;
/* booleans indicating whether a value has been set yet for a basin */
private BitSet occupied;
/*
* The number of occupied basins for this time, when its zero the time
* can be removed from the backing map.
*/
private int size = 0;
public MultiValue(int allocated_size) {
this.data = new float[allocated_size];
this.occupied = new BitSet(allocated_size);
}
public void grow(int allocated_size) {
data = Arrays.copyOf(data, allocated_size);
BitSet occupied = new BitSet(allocated_size);
occupied.or(this.occupied);
this.occupied = occupied;
}
public Float put(int index, float value) {
Float oldValue = null;
if (occupied.get(index)) {
oldValue = data[index];
} else {
occupied.set(index);
size += 1;
}
data[index] = value;
return oldValue;
}
public Float get(int index) {
if (occupied.get(index)) {
return data[index];
} else {
return null;
}
}
public boolean contains(int index) {
return occupied.get(index);
}
public Float remove(int index) {
if (occupied.get(index)) {
occupied.clear(index);
size -= 1;
return data[index];
}
return null;
}
public boolean isEmpty() {
return size == 0;
}
}
/**
* NavigableMap implementation which provides a view into the backingMap at
* a specific index. This class can map any NavigableMap<K, MultiValue>
* which simplifies creating sub maps or descending map because all that is
* required is getting new maps from the backingMap and wrapping them in a
* new MapView.
*/
private static class MapView<K> extends AbstractMap<K, Float> implements
NavigableMap<K, Float> {
/* Factory, for syncronization */
private final BasinMapFactory<K> factory;
/* index into the MultiValue */
private final int index;
/* backingMap where all the data really lives. */
private final NavigableMap<K, MultiValue> backingMap;
public MapView(BasinMapFactory<K> factory, int index,
NavigableMap<K, MultiValue> backingMap) {
this.factory = factory;
this.index = index;
this.backingMap = backingMap;
}
@Override
public Float put(K key, Float value) {
synchronized (factory) {
MultiValue v = backingMap.get(key);
if (v == null) {
v = new MultiValue(factory.allocated_size);
backingMap.put(key, v);
}
return v.put(index, value);
}
}
@Override
public boolean containsKey(Object key) {
MultiValue v = backingMap.get(key);
if (v != null) {
return v.contains(index);
} else {
return false;
}
}
@Override
public Float get(Object key) {
MultiValue v = backingMap.get(key);
if (v != null) {
return v.get(index);
} else {
return null;
}
}
@Override
public Float remove(Object key) {
Float oldValue = null;
MultiValue v = backingMap.get(key);
if (v != null) {
synchronized (factory) {
oldValue = v.remove(index);
if (v.isEmpty()) {
backingMap.remove(key);
}
}
}
return oldValue;
}
@Override
public boolean isEmpty() {
/*
* The default implementation uses size() which will iterate over
* all elements, this is much faster.
*/
return !entrySet().iterator().hasNext();
}
@Override
public Comparator<? super K> comparator() {
return backingMap.comparator();
}
@Override
public K firstKey() {
Entry<K, Float> e = firstEntry();
if (e != null) {
return e.getKey();
}
return null;
}
@Override
public K lastKey() {
Entry<K, Float> e = lastEntry();
if (e != null) {
return e.getKey();
}
return null;
}
@Override
public Entry<K, Float> lowerEntry(K key) {
return headMap(key).lastEntry();
}
@Override
public K lowerKey(K key) {
return headMap(key).lastKey();
}
@Override
public Entry<K, Float> floorEntry(K key) {
return headMap(key, true).lastEntry();
}
@Override
public K floorKey(K key) {
return headMap(key, true).lastKey();
}
@Override
public Entry<K, Float> ceilingEntry(K key) {
return tailMap(key).firstEntry();
}
@Override
public K ceilingKey(K key) {
return tailMap(key).firstKey();
}
@Override
public Entry<K, Float> higherEntry(K key) {
return tailMap(key, false).firstEntry();
}
@Override
public K higherKey(K key) {
return tailMap(key, false).firstKey();
}
@Override
public Entry<K, Float> firstEntry() {
for (Entry<K, Float> e : entrySet()) {
return e;
}
return null;
}
@Override
public Entry<K, Float> lastEntry() {
return descendingMap().firstEntry();
}
@Override
public Entry<K, Float> pollFirstEntry() {
Iterator<Entry<K, Float>> it = entrySet().iterator();
if (it.hasNext()) {
Entry<K, Float> e = it.next();
it.remove();
return e;
}
return null;
}
@Override
public Entry<K, Float> pollLastEntry() {
return descendingMap().pollFirstEntry();
}
@Override
public NavigableMap<K, Float> descendingMap() {
return new MapView<K>(factory, index, backingMap.descendingMap());
}
@Override
public NavigableSet<K> navigableKeySet() {
return new NavigableKeySet<K>(this);
}
@Override
public NavigableSet<K> descendingKeySet() {
return descendingMap().navigableKeySet();
}
@Override
public NavigableMap<K, Float> subMap(K fromKey, boolean fromInclusive,
K toKey, boolean toInclusive) {
return new MapView<K>(factory, index, backingMap.subMap(fromKey,
fromInclusive, toKey, toInclusive));
}
@Override
public NavigableMap<K, Float> headMap(K toKey, boolean inclusive) {
return new MapView<K>(factory, index, backingMap.headMap(toKey,
inclusive));
}
@Override
public NavigableMap<K, Float> tailMap(K fromKey, boolean inclusive) {
return new MapView<K>(factory, index, backingMap.tailMap(fromKey,
inclusive));
}
@Override
public NavigableMap<K, Float> subMap(K fromKey, K toKey) {
return new MapView<K>(factory, index, backingMap.subMap(fromKey,
true, toKey, false));
}
@Override
public NavigableMap<K, Float> headMap(K toKey) {
return new MapView<K>(factory, index, backingMap.headMap(toKey,
false));
}
@Override
public NavigableMap<K, Float> tailMap(K fromKey) {
return new MapView<K>(factory, index, backingMap.headMap(fromKey,
true));
}
@Override
public Set<Entry<K, Float>> entrySet() {
return new EntrySet<K>(index, backingMap.entrySet());
}
}
/**
* Entry set for a MapView, just a wrapper over a Set<Entry<K, MultiValue>>
*/
private static class EntrySet<K> extends AbstractSet<Entry<K, Float>> {
private final int index;
private final Set<Entry<K, MultiValue>> backingSet;
public EntrySet(int index, Set<Entry<K, MultiValue>> backingSet) {
this.index = index;
this.backingSet = backingSet;
}
@Override
public Iterator<Entry<K, Float>> iterator() {
return new EntryIterator<K>(index, backingSet.iterator());
}
@Override
public int size() {
Iterator<Entry<K, Float>> it = iterator();
int i = 0;
while (it.hasNext()) {
it.next();
i += 1;
}
return i;
}
}
/**
* Iterator implementation for an EntrySet, This wraps an Iterator<Entry<K,
* MultiValue>> but has extra logic for skipping over values that exist in
* the backingSet but are not occupied within the MultiValue.
*/
private static class EntryIterator<K> implements Iterator<Entry<K, Float>> {
private final int index;
private final Iterator<Entry<K, MultiValue>> backingIterator;
/* The next valid entry in the backingMap */
private transient Entry<K, MultiValue> next;
/* Previous Value returned by next() */
private transient Entry<K, MultiValue> previous;
public EntryIterator(int index,
Iterator<Entry<K, MultiValue>> backingIterator) {
this.index = index;
this.backingIterator = backingIterator;
}
private Entry<K, MultiValue> checkNext() {
if (next == null) {
while (backingIterator.hasNext()) {
Entry<K, MultiValue> e = backingIterator.next();
previous = null;
MultiValue v = e.getValue();
if (v.contains(index)) {
next = e;
return next;
}
}
}
return next;
}
@Override
public boolean hasNext() {
return checkNext() != null;
}
@Override
public Entry<K, Float> next() {
Entry<K, MultiValue> next = checkNext();
previous = next;
if (next == null) {
return null;
} else {
this.next = null;
return new EntryImpl<K>(index, next);
}
}
@Override
public void remove() {
if (previous == null) {
throw new IllegalStateException(
"Cannot remove from iterator because next() was not called.");
}
MultiValue v = previous.getValue();
previous = null;
v.remove(index);
if (v.isEmpty()) {
backingIterator.remove();
}
}
}
/**
* Entry for a MapView, just a wrapper over a Entry<K, MultiValue>.
*/
private static class EntryImpl<K> implements Entry<K, Float> {
private final int index;
private final Entry<K, MultiValue> backingEntry;
public EntryImpl(int index, Entry<K, MultiValue> timeEntry) {
this.index = index;
this.backingEntry = timeEntry;
}
@Override
public K getKey() {
return backingEntry.getKey();
}
@Override
public Float getValue() {
return backingEntry.getValue().get(index);
}
@Override
public Float setValue(Float value) {
return backingEntry.getValue().put(index, value);
}
}
}

View file

@ -0,0 +1,153 @@
/**
* 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.dataplugin.ffmp.collections;
import java.util.AbstractSet;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.SortedSet;
/**
*
* Generic NavigableSet which is implemented by wrapping a fully implemented
* NavigableMap. Very useful for custom NavigableMap implementations.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 31, 2013 2242 bsteffen Extracted from ArrayBackedMap
*
* </pre>
*
* @author bsteffen
* @version 1.0
* @param <K>
*/
class NavigableKeySet<K> extends AbstractSet<K> implements NavigableSet<K> {
private final NavigableMap<K, ?> map;
public NavigableKeySet(NavigableMap<K, ?> map) {
this.map = map;
}
@Override
public Iterator<K> iterator() {
return map.keySet().iterator();
}
@Override
public int size() {
return map.size();
}
@Override
public Comparator<? super K> comparator() {
return map.comparator();
}
@Override
public K first() {
return map.firstKey();
}
@Override
public K last() {
return map.lastKey();
}
@Override
public K lower(K e) {
return map.lowerKey(e);
}
@Override
public K floor(K e) {
return map.floorKey(e);
}
@Override
public K ceiling(K e) {
return map.ceilingKey(e);
}
@Override
public K higher(K e) {
return map.higherKey(e);
}
@Override
public K pollFirst() {
return map.pollFirstEntry().getKey();
}
@Override
public K pollLast() {
return map.pollLastEntry().getKey();
}
@Override
public NavigableSet<K> descendingSet() {
return map.descendingKeySet();
}
@Override
public Iterator<K> descendingIterator() {
return descendingSet().iterator();
}
@Override
public NavigableSet<K> subSet(K fromElement, boolean fromInclusive,
K toElement, boolean toInclusive) {
return map.subMap(fromElement, fromInclusive, toElement,
toInclusive).navigableKeySet();
}
@Override
public NavigableSet<K> headSet(K toElement, boolean inclusive) {
return map.headMap(toElement, inclusive).navigableKeySet();
}
@Override
public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
return map.tailMap(fromElement, inclusive).navigableKeySet();
}
@Override
public SortedSet<K> subSet(K fromElement, K toElement) {
return subSet(fromElement, true, toElement, false);
}
@Override
public SortedSet<K> headSet(K toElement) {
return headSet(toElement, false);
}
@Override
public SortedSet<K> tailSet(K fromElement) {
return tailSet(fromElement, true);
}
}

View file

@ -52,6 +52,7 @@ import com.vividsolutions.jts.geom.Geometry;
* 03/12/2007 1003 bwoodle initial creation
* 04/12/2013 1857 bgonzale Added SequenceGenerator annotation.
* 05/02/2013 1949 rjpeter Moved ugcZones to be a column inside table.
* 08/08/2013 2243 jsanchez Removed super method in copy constructor.
* </pre>
*
* @author bwoodle
@ -233,7 +234,6 @@ public abstract class AbstractWarningRecord extends PluginDataObject {
* The text of the message
*/
public AbstractWarningRecord(AbstractWarningRecord old) {
super((String) old.getMessageData());
this.setCountyheader(old.getCountyheader());
this.setDataTime(old.getDataTime());
this.setForecaster(old.getForecaster());