Merge remote-tracking branch 'asm/asm_16.2.1' into master_16.2.1

Former-commit-id: 70338bff91bc02d5b0e2b2286164073afd85ed3c
This commit is contained in:
Shawn.Hooper 2016-04-26 07:21:57 -04:00
commit 44c2a22f93
6 changed files with 504 additions and 288 deletions

View file

@ -21,61 +21,84 @@ package com.raytheon.rcm.message;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/**
* Represents the contents of an ORPG General Status Message.
*
* <pre>
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 2009 dfriedman Initial version
* 2016-04-22 DR 18909 dfriedman Read fields of expanded GSM.
* </pre>
*/
public class GSM extends Message { public class GSM extends Message {
public static final int OP_MODE_MAINTENANCE = 0; public static final int OP_MODE_MAINTENANCE = 0;
public static final int OP_MODE_CLEAR_AIR = 1; public static final int OP_MODE_CLEAR_AIR = 1;
public static final int OP_MODE_STORM = 2; public static final int OP_MODE_STORM = 2;
public int opMode; public int opMode;
public int rdaOpStatus; public int rdaOpStatus;
public int vcp; public int vcp;
public int[] cuts; // in tenths of degrees public int[] cuts; // in tenths of degrees
public int rdaStatus; public int rdaStatus;
public int rdaAlarms; public int rdaAlarms;
public int dataAvailability; // "DTE" public int dataAvailability; // "DTE"
public int rpgOpStatus; public int rpgOpStatus;
public int rpgAlarms; public int rpgAlarms;
public int rpgStatus; public int rpgStatus;
public int rpgNarrowbandStatus; public int rpgNarrowbandStatus;
public int rcc; public int rcc;
public int productAvailability; public int productAvailability;
public int superResCuts; public int superResCuts;
public int rdaVersion; public int rdaVersion;
public int rdaChannel; public int rdaChannel;
public int rpgVersion; public int rpgVersion;
public int vcpSupplemental;
public static GSM decode(byte[] msg) { public static GSM decode(byte[] msg) {
return (GSM) MD.decode(msg); return (GSM) MD.decode(msg);
} }
protected void decodeBlock(int index, ByteBuffer buf) { protected void decodeBlock(int index, ByteBuffer buf) {
if (index != 1) if (index != 1)
return; return;
opMode = buf.getShort(); opMode = buf.getShort();
rdaOpStatus = buf.getShort(); rdaOpStatus = buf.getShort();
vcp = buf.getShort(); vcp = buf.getShort();
int nCuts = buf.getShort(); int nCuts = buf.getShort();
cuts = new int[nCuts]; cuts = new int[nCuts];
for (int i = 0; i < 20; ++i) { for (int i = 0; i < 20; ++i) {
if (i < cuts.length) short cut = buf.getShort();
cuts[i] = buf.getShort(); if (i < cuts.length) {
else cuts[i] = cut;
buf.getShort(); }
} }
rdaStatus = buf.getShort(); rdaStatus = buf.getShort();
rdaAlarms = buf.getShort(); rdaAlarms = buf.getShort();
dataAvailability = buf.getShort(); dataAvailability = buf.getShort();
rpgOpStatus = buf.getShort(); rpgOpStatus = buf.getShort();
rpgAlarms = buf.getShort(); rpgAlarms = buf.getShort();
rpgStatus = buf.getShort(); rpgStatus = buf.getShort();
rpgNarrowbandStatus = buf.getShort(); rpgNarrowbandStatus = buf.getShort();
rcc = buf.getShort(); rcc = buf.getShort();
productAvailability = buf.getShort(); productAvailability = buf.getShort();
superResCuts = buf.getShort(); superResCuts = buf.getShort();
buf.position(buf.position() + 4); buf.position(buf.position() + 4);
rdaVersion = buf.getShort(); rdaVersion = buf.getShort();
rdaChannel = buf.getShort(); rdaChannel = buf.getShort();
buf.position(buf.position() + 4); buf.position(buf.position() + 4);
rpgVersion = buf.getShort(); rpgVersion = buf.getShort();
} if (buf.remaining() < 12) {
return;
}
for (int i = 20; i < 25; ++i) {
short cut = buf.getShort();
if (i < cuts.length) {
cuts[i] = cut;
}
}
vcpSupplemental = buf.getShort();
}
} }

View file

@ -22,10 +22,12 @@ package com.raytheon.rcm.otrmgr;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import com.raytheon.rcm.config.RadarConfig; import com.raytheon.rcm.config.RadarConfig;
import com.raytheon.rcm.config.RadarType;
import com.raytheon.rcm.config.RcmUtil; import com.raytheon.rcm.config.RcmUtil;
import com.raytheon.rcm.event.OtrEvent; import com.raytheon.rcm.event.OtrEvent;
import com.raytheon.rcm.event.RadarEvent; import com.raytheon.rcm.event.RadarEvent;
@ -39,6 +41,7 @@ import com.raytheon.rcm.message.MessageFormatException;
import com.raytheon.rcm.message.MessageInfo; import com.raytheon.rcm.message.MessageInfo;
import com.raytheon.rcm.message.ProductRequest; import com.raytheon.rcm.message.ProductRequest;
import com.raytheon.rcm.message.RequestResponse; import com.raytheon.rcm.message.RequestResponse;
import com.raytheon.rcm.products.ElevationInfo;
import com.raytheon.rcm.request.Filter; import com.raytheon.rcm.request.Filter;
import com.raytheon.rcm.request.Request; import com.raytheon.rcm.request.Request;
import com.raytheon.rcm.request.Sequence; import com.raytheon.rcm.request.Sequence;
@ -55,9 +58,18 @@ import com.raytheon.rcm.server.RadarServer;
/** /**
* Manages One Time Requests for the RPGs. * Manages One Time Requests for the RPGs.
* <p> * <p>
* Does not actually do much except provide a place to queue up requests while * Implements a queue for pending requests to the RPGs. Performs some coalescing
* waiting to connect to the RPG. Does do some coalescing of duplicate * of duplicate requests.
* requests. *
* <pre>
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 2009 dfriedman Initial version
* 2016-04-22 DR 18909 dfriedman Accurately calculate the number of expected
* responses for multiple-elevation requests.
* </pre>
*/ */
public class OTRManager extends RadarEventAdapter { public class OTRManager extends RadarEventAdapter {
@ -69,7 +81,7 @@ public class OTRManager extends RadarEventAdapter {
*/ */
protected boolean isReady; protected boolean isReady;
protected List<Req> requests = new ArrayList<Req>(); protected List<Req> requests = new ArrayList<>();
protected GSM lastGSM; protected GSM lastGSM;
@ -226,7 +238,7 @@ public class OTRManager extends RadarEventAdapter {
private void trySendingRequests() { private void trySendingRequests() {
if (isReady()) { if (isReady()) {
ArrayList<Request> requestsToSend = new ArrayList<Request>(); ArrayList<Request> requestsToSend = new ArrayList<>();
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
synchronized (this.requests) { synchronized (this.requests) {
for (Req r : requests) { for (Req r : requests) {
@ -319,31 +331,55 @@ public class OTRManager extends RadarEventAdapter {
&& request.getElevationSelection() != Request.SPECIFIC_ELEVATION) { && request.getElevationSelection() != Request.SPECIFIC_ELEVATION) {
if (lastGSM != null) { if (lastGSM != null) {
if (request.getElevationSelection() == Request.ALL_ELEVATIONS) { if (request.getElevationSelection() == Request.ALL_ELEVATIONS) {
/* RadarType radarType = RcmUtil.getRadarType(getRadarConfig());
* We do not get information about duplicate int[] completeElevationList;
* elevations. Could put in TDWR-specific knowledge.
* If vcp==80 && is-low-elevation...
*
* But probably needs something like.
* nExpectedUnknown = true and (if nExpectedUnknown
* then connMgr.idleDisconnectRadar(...)
*/
// if is tdwr and vcp80...
exactCountUnknown = true;
nElevations = request.getElevationAngle() == 0 ? lastGSM.cuts.length if (radarType == RadarType.WSR
: 1; || (radarType == RadarType.TDWR && lastGSM.rpgVersion >= 80)) {
/*
* When MESO-SAILS was added to WSR-88D, the
* expanded GSM was already available and it
* contained the complete list of elevations
* including extra SAILS elevations. Therefore,
* we can always rely on a WSR-88D's GSM for the
* list of elevation angles.
*
* Later version of the SPG contain the complete
* list of angles in an expected GSM.
*/
completeElevationList = lastGSM.cuts;
} else if (radarType == RadarType.TDWR && lastGSM.rpgVersion < 80) {
/*
* Earlier versions of the SPG do not list the
* extra low angle elevations scans. We can use
* the static elevation list instead.
*/
completeElevationList = ElevationInfo
.getInstance().getScanElevations(
radarID, lastGSM.vcp);
} else {
/*
* No choice but to guess based on the list of
* elevations from the GSM.
*/
completeElevationList = lastGSM.cuts;
exactCountUnknown = true;
}
int elevationAngle = request.getElevationAngle();
nElevations = elevationAngle == 0 ? uniqueCount(completeElevationList)
: matchCount(elevationAngle, completeElevationList);
} else if (request.getElevationSelection() == Request.N_ELEVATIONS) { } else if (request.getElevationSelection() == Request.N_ELEVATIONS) {
nElevations = Math.min(lastGSM.cuts.length, nElevations = Math.min(uniqueCount(lastGSM.cuts),
request.getElevationAngle()); request.getElevationAngle());
} else if (request.getElevationSelection() == Request.LOWER_ELEVATIONS) { } else if (request.getElevationSelection() == Request.LOWER_ELEVATIONS) {
HashSet<Integer> seenAngles = new HashSet<>();
nElevations = 0; nElevations = 0;
int reqEA = request.getElevationAngle(); int reqEA = request.getElevationAngle();
for (int ea : lastGSM.cuts) { for (int ea : lastGSM.cuts) {
if (ea <= reqEA) if (ea <= reqEA && !seenAngles.contains(ea)) {
++nElevations; ++nElevations;
else seenAngles.add(ea);
break; }
} }
} else } else
exactCountUnknown = true; exactCountUnknown = true;
@ -356,9 +392,41 @@ public class OTRManager extends RadarEventAdapter {
nExpected = request.count * nElevations; nExpected = request.count * nElevations;
} }
private int uniqueCount(int[] angles) {
HashSet<Integer> uniqueAngles = new HashSet<>();
for (int a : angles) {
uniqueAngles.add(a);
}
return uniqueAngles.size();
}
private int matchCount(int angle, int[] angles) {
int matchedAngle = findClosestAngle(angle, angles);
int count = 0;
for (int a : angles) {
if (a == matchedAngle) {
++count;
}
}
return count;
}
private int findClosestAngle(int angle, int[] angles) {
int result = Integer.MIN_VALUE;
int bestDiff = Integer.MAX_VALUE;
for (int a : angles) {
int diff = Math.abs(a - angle);
if (result == -1 || diff < bestDiff) {
result = a;
bestDiff = diff;
}
}
return result;
}
public void addHandler(OTRHandler handler) { public void addHandler(OTRHandler handler) {
if (handlers == null) if (handlers == null)
handlers = new ArrayList<OTRHandler>(); handlers = new ArrayList<>();
handlers.add(handler); handlers.add(handler);
} }
@ -387,7 +455,7 @@ public class OTRManager extends RadarEventAdapter {
RadarServer radarServer; RadarServer radarServer;
// ArrayList<Req> requests = new ArrayList<Req>(); // ArrayList<Req> requests = new ArrayList<Req>();
HashMap<String, RadarStatus> state = new HashMap<String, RadarStatus>(); HashMap<String, RadarStatus> state = new HashMap<>();
public OTRManager(RadarServer radarServer) { public OTRManager(RadarServer radarServer) {
this.radarServer = radarServer; this.radarServer = radarServer;

View file

@ -31,184 +31,198 @@ import com.raytheon.rcm.message.GraphicProduct.PDB;
/** /**
* A radar server component that logs various radar events. * A radar server component that logs various radar events.
*
* <pre>
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 2009 dfriedma Initial version
* 2016-04-22 DR 18909 dfriedma Log fields of expanded GSM.
* </pre>
*/ */
public class EventLogger extends RadarEventAdapter { public class EventLogger extends RadarEventAdapter {
public EventLogger() { public EventLogger() {
} }
@Override @Override
public void handleRadarEvent(RadarEvent event) { public void handleRadarEvent(RadarEvent event) {
switch (event.getType()) { switch (event.getType()) {
case RadarEvent.CONNECTION_UP: case RadarEvent.CONNECTION_UP:
Log.eventf("%s: connected", event.getRadarID()); Log.eventf("%s: connected", event.getRadarID());
break; break;
case RadarEvent.CONNECTION_DOWN: case RadarEvent.CONNECTION_DOWN:
Log.eventf("%s: disconnected", event.getRadarID()); Log.eventf("%s: disconnected", event.getRadarID());
break; break;
case RadarEvent.MESSAGE_RECEIVED: case RadarEvent.MESSAGE_RECEIVED:
{ {
StringBuilder s = new StringBuilder(); StringBuilder s = new StringBuilder();
byte[] msg = event.getMessageData(); byte[] msg = event.getMessageData();
int messageCode = Message.messageCodeOf(msg); int messageCode = Message.messageCodeOf(msg);
s.append("code=" + messageCode); s.append("code=" + messageCode);
s.append(" size=" + msg.length); s.append(" size=" + msg.length);
if (messageCode == Message.GSM) { if (messageCode == Message.GSM) {
s.append(' '); s.append(' ');
GSM gsm = null; GSM gsm = null;
try { try {
gsm = GSM.decode(msg); gsm = GSM.decode(msg);
} catch (Exception e) { } catch (Exception e) {
s.append("(Message decoding failed)"); s.append("(Message decoding failed)");
} }
if (gsm != null) if (gsm != null)
s.append(formatGSM(gsm)); s.append(formatGSM(gsm));
} else if (messageCode == Message.REQUEST_RESPONSE) { } else if (messageCode == Message.REQUEST_RESPONSE) {
s.append(' '); s.append(' ');
RequestResponse rr = null; RequestResponse rr = null;
try { try {
rr = RequestResponse.decode(msg); rr = RequestResponse.decode(msg);
} catch (Exception e) { } catch (Exception e) {
s.append("(Message decoding failed)"); s.append("(Message decoding failed)");
} }
if (rr != null) if (rr != null)
s.append(formatPRR(rr)); s.append(formatPRR(rr));
} else if (messageCode >= 16) { } else if (messageCode >= 16) {
PDB pdb = null; PDB pdb = null;
s.append(' '); s.append(' ');
try { try {
pdb = GraphicProduct.pdbOfMessage(msg); pdb = GraphicProduct.pdbOfMessage(msg);
} catch (Exception e) { } catch (Exception e) {
s.append("(Message decoding failed)"); s.append("(Message decoding failed)");
} }
if (pdb != null) if (pdb != null)
s.append(String.format("elev=%.1f sequence=%d"+ s.append(String.format("elev=%.1f sequence=%d"+
" vs=%3$tY-%3$tm-%3$td %3$tH:%3$tM:%3$tS #%4$d", " vs=%3$tY-%3$tm-%3$td %3$tH:%3$tM:%3$tS #%4$d",
pdb.getElevationAngle() / 10.0, pdb.sequence, pdb.getElevationAngle() / 10.0, pdb.sequence,
pdb.volumeScanTime, pdb.volumeScan)); pdb.volumeScanTime, pdb.volumeScan));
} }
Log.eventf("%s: message %s", event.getRadarID(), s.toString()); Log.eventf("%s: message %s", event.getRadarID(), s.toString());
break; break;
} }
} }
} }
protected final String[] rdaOpStatusStr = { protected final String[] rdaOpStatusStr = {
"auto-calib-disab", "online", "maint-req", "maint-mand", "cmd-shutdown", "auto-calib-disab", "online", "maint-req", "maint-mand", "cmd-shutdown",
"inoperable", null, "wideband-disconn" "inoperable", null, "wideband-disconn"
}; };
protected final String[] rdaStatusStr = { protected final String[] rdaStatusStr = {
null, "startup", "standby", "restart", "operate", null, "offline-op" null, "startup", "standby", "restart", "operate", null, "offline-op"
}; };
protected final String[] rdaAlarmStr = { protected final String[] rdaAlarmStr = {
"indeterminate", "tower", "pedestal", "transmitter", "receiver", "control", "comms" "indeterminate", "tower", "pedestal", "transmitter", "receiver", "control", "comms"
}; };
protected final String[] dteStr = { protected final String[] dteStr = {
null, "none", "refl", "vel", "sw", "dual-pol" null, "none", "refl", "vel", "sw", "dual-pol"
}; };
protected final String[] rpgOpStr = { protected final String[] rpgOpStr = {
"load-shed", "online", "maint-req", "maint-mand", "cmd-shutdown" "load-shed", "online", "maint-req", "maint-mand", "cmd-shutdown"
}; };
protected final String[] rpgAlarmStr = { protected final String[] rpgAlarmStr = {
"none", "node-conn", null, "ctl-task-fail", "db-fail", null, "input-load-shed", "none", "node-conn", null, "ctl-task-fail", "db-fail", null, "input-load-shed",
null, "store-load-shed", null, null, null, "link-fail", "redundant-channel-error", null, "store-load-shed", null, null, null, "link-fail", "redundant-channel-error",
"task-fail", "media-fail" "task-fail", "media-fail"
}; };
protected final String[] rpgStatusStr = { protected final String[] rpgStatusStr = {
"restart", "operate", "standby", null, "test-mode" "restart", "operate", "standby", null, "test-mode"
}; };
protected final String[] productAvailStr = { protected final String[] productAvailStr = {
"avail", "degraded", "not-avail" "avail", "degraded", "not-avail"
}; };
protected final String[] prrStr = { protected final String[] prrStr = {
"no-such-msg", "no-such-prod", "not-gen", "proc-fault", "no-such-msg", "no-such-prod", "not-gen", "proc-fault",
"narrowband-loadshed", "illegal-req", "mem-loadshed", "cpu-loadshed", "narrowband-loadshed", "illegal-req", "mem-loadshed", "cpu-loadshed",
"slot-unavail", "task-failed", "task-unavail", "avail-next-scan", "slot-unavail", "task-failed", "task-unavail", "avail-next-scan",
"moment-disabled", "invalid-password", null, "aborted-scan", "moment-disabled", "invalid-password", null, "aborted-scan",
"inval-prod-param", "data-seq-error", "task-term" "inval-prod-param", "data-seq-error", "task-term"
}; };
protected final String[] vcpSupplementalStr = {
"AVSET", "SAILS", "site-specific-vcp", "RxRN", "CBT"
};
protected String formatBits(short bits, String[] strings) { protected String formatBits(short bits, String[] strings) {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
if ((bits & (1 << i)) != 0) { if ((bits & (1 << i)) != 0) {
if (result.length() > 0) if (result.length() > 0)
result.append(','); result.append(',');
String s = null; String s = null;
if (i < strings.length) if (i < strings.length)
s = strings[i]; s = strings[i];
if (s == null) if (s == null)
s = "unk" + Integer.toString(15 - i); s = "unk" + Integer.toString(15 - i);
result.append(s); result.append(s);
} }
} }
return result.toString(); return result.toString();
} }
protected String formatPrrBits(int bits, String[] strings) { protected String formatPrrBits(int bits, String[] strings) {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
// PRR bits are defined from the MSB on down, so // PRR bits are defined from the MSB on down, so
// note the (31-i) // note the (31-i)
if ((bits & (1 << (31-i))) != 0) { if ((bits & (1 << (31-i))) != 0) {
if (result.length() > 0) if (result.length() > 0)
result.append(','); result.append(',');
String s = null; String s = null;
if (i < strings.length) if (i < strings.length)
s = strings[i]; s = strings[i];
if (s == null) if (s == null)
s = "unk" + Integer.toString(31 - i); s = "unk" + Integer.toString(31 - i);
result.append(s); result.append(s);
} }
} }
return result.toString(); return result.toString();
} }
protected String formatGSM(GSM gsm) { protected String formatGSM(GSM gsm) {
StringBuilder o = new StringBuilder(); StringBuilder o = new StringBuilder();
String s; String s;
switch (gsm.opMode) { switch (gsm.opMode) {
case GSM.OP_MODE_CLEAR_AIR: s = "clear-air"; break; case GSM.OP_MODE_CLEAR_AIR: s = "clear-air"; break;
case GSM.OP_MODE_STORM: s = "storm"; break; case GSM.OP_MODE_STORM: s = "storm"; break;
case GSM.OP_MODE_MAINTENANCE: s = "maintenance"; break; case GSM.OP_MODE_MAINTENANCE: s = "maintenance"; break;
default: s = "(" +Integer.toString(gsm.opMode) + ")"; default: s = "(" +Integer.toString(gsm.opMode) + ")";
} }
o.append("opMode=" + s); o.append("opMode=" + s);
o.append(" vcp=" + gsm.vcp); o.append(" vcp=" + gsm.vcp);
o.append(" cuts=" + Arrays.toString(gsm.cuts)); o.append(" cuts=" + Arrays.toString(gsm.cuts));
o.append(String.format(" rdaOp=%s rdaStat=%s rdaAlarm=%s dte=%s rpgOp=%s rpgStat=%s rpgAlarm=%s", o.append(String.format(" rdaOp=%s rdaStat=%s rdaAlarm=%s dte=%s rpgOp=%s rpgStat=%s rpgAlarm=%s",
formatBits((short) gsm.rdaOpStatus, rdaOpStatusStr), formatBits((short) gsm.rdaOpStatus, rdaOpStatusStr),
formatBits((short) gsm.rdaStatus, rdaStatusStr), formatBits((short) gsm.rdaStatus, rdaStatusStr),
formatBits((short) gsm.rdaAlarms, rdaAlarmStr), formatBits((short) gsm.rdaAlarms, rdaAlarmStr),
formatBits((short) gsm.dataAvailability, dteStr), formatBits((short) gsm.dataAvailability, dteStr),
formatBits((short) gsm.rpgOpStatus, rpgOpStr), formatBits((short) gsm.rpgOpStatus, rpgOpStr),
formatBits((short) gsm.rpgStatus, rpgStatusStr), formatBits((short) gsm.rpgStatus, rpgStatusStr),
formatBits((short) gsm.rpgAlarms, rpgAlarmStr))); formatBits((short) gsm.rpgAlarms, rpgAlarmStr)));
o.append(String.format(" avail=%s", o.append(String.format(" avail=%s",
formatBits((short) gsm.productAvailability, productAvailStr))); formatBits((short) gsm.productAvailability, productAvailStr)));
o.append(String.format(" rdaVer=%.1f rpgVer=%.1f", gsm.rdaVersion/10.0, gsm.rpgVersion/10.)); o.append(String.format(" suppl=%s",
formatBits((short) gsm.vcpSupplemental, vcpSupplementalStr)));
return o.toString(); o.append(String.format(" rdaVer=%.1f rpgVer=%.1f", gsm.rdaVersion/10.0, gsm.rpgVersion/10.));
}
protected String formatPRR(RequestResponse rr) { return o.toString();
StringBuilder o = new StringBuilder(); }
o.append(String.format("productCode=%d sequence=%d elev=%d flags=%s", protected String formatPRR(RequestResponse rr) {
rr.productCode, StringBuilder o = new StringBuilder();
rr.sequence,
rr.elevationAngle,
formatPrrBits(rr.errorCode, prrStr)));
return o.toString(); o.append(String.format("productCode=%d sequence=%d elev=%d flags=%s",
} rr.productCode,
rr.sequence,
rr.elevationAngle,
formatPrrBits(rr.errorCode, prrStr)));
return o.toString();
}
} }

View file

@ -369,6 +369,7 @@ import com.raytheon.viz.ui.simulatedtime.SimulatedTimeOperations;
* 06Jan2016 5225 randerso Fix problem with mixed case not getting converted to upper case * 06Jan2016 5225 randerso Fix problem with mixed case not getting converted to upper case
* when multiple text editors are open on the same product. * when multiple text editors are open on the same product.
* Mar 17, 2016 RM 18727 D. Friedman Fix use of verification listener when entering and exiting editor. * Mar 17, 2016 RM 18727 D. Friedman Fix use of verification listener when entering and exiting editor.
* Apr 15, 2016 RM 18870 D. Friedman Replace commas with ellipses only at start of edit and then word-wrap.
* *
* </pre> * </pre>
* *
@ -4254,20 +4255,19 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
// section // section
setCurrentHeaderAndBody(); setCurrentHeaderAndBody();
// if product is a WarnGen product and is not enabled for mixed case
// transmission, replace all commas with ellipses
if ((product != null) && warngenPils.contains(product.getNnnid())
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
textEditor.setText(textEditor.getText()
.replaceAll(", {0,1}", "..."));
}
// Mark the uneditable warning text // Mark the uneditable warning text
if (markUneditableText(textEditor)) { if (markUneditableText(textEditor)) {
// Enable listener to monitor attempt to edit locked text // Enable listener to monitor attempt to edit locked text
verifyUndeditableText = true; verifyUndeditableText = true;
} }
// if product is a WarnGen product and is not enabled for mixed case
// transmission, replace all commas with ellipses
if ((product != null) && warngenPils.contains(product.getNnnid())
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
replaceCommasWithEllipses(product);
}
// Set the menu buttons to reflect the edit mode. // Set the menu buttons to reflect the edit mode.
editorButtonMenuStates(inEditMode); editorButtonMenuStates(inEditMode);
@ -4295,6 +4295,60 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
editHeader("warning", true); editHeader("warning", true);
} }
private void replaceCommasWithEllipses(StdTextProduct product) {
boolean wasVerifying = verifyUndeditableText;
try {
verifyUndeditableText = false;
/*
* Performing wrapping as few times as possible to reduce the
* chances of breaking the product format. Also, the location list
* does not wrap properly unless all commas in the paragraph have
* been changed to ellipses.
*/
Pattern p = Pattern.compile(", {0,1}");
int pendingParagraphLineStart = -1;
while (true) {
String text = textEditor.getText();
Matcher m = p.matcher(text);
if (! m.find())
break;
int line = textEditor.getLineAtOffset(m.start());
int paragraphLineStart = findParagraphStart(line);
String lineText = textEditor.getLine(line);
boolean lineNeedsWrap = lineText.length()
- (m.end() - m.start()) + 3 > charWrapCol;
if (pendingParagraphLineStart >= 0
&& paragraphLineStart != pendingParagraphLineStart
&& lineNeedsWrap) {
wrapWholeParagraphAtLine(pendingParagraphLineStart);
pendingParagraphLineStart = -1;
// Line numbers may have changed so restart.
continue;
}
textEditor.replaceTextRange(m.start(), m.end() - m.start(), "...");
if (lineNeedsWrap) {
pendingParagraphLineStart = paragraphLineStart;
}
}
if (pendingParagraphLineStart >= 0) {
wrapWholeParagraphAtLine(pendingParagraphLineStart);
}
} finally {
verifyUndeditableText = wasVerifying;
}
}
void wrapWholeParagraphAtLine(int paragraphLineStart) {
String line = textEditor.getLine(paragraphLineStart);
// Avoid rewrapInternal early bailout check.
if (line.length() < charWrapCol
&& line.indexOf("...") == line.lastIndexOf("...")) {
paragraphLineStart++;
}
int offset = textEditor.getOffsetAtLine(paragraphLineStart);
rewrap(offset, offset);
}
/** /**
* Cancel the editor mode. * Cancel the editor mode.
* *
@ -4402,16 +4456,6 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
textEditor.setText(originalText); textEditor.setText(originalText);
} }
// if product is a WarnGen product and is not enabled for mixed case
// transmission, replace all commas with ellipses
StdTextProduct product = TextDisplayModel.getInstance()
.getStdTextProduct(token);
if ((product != null) && warngenPils.contains(product.getNnnid())
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
textEditor.setText(textEditor.getText()
.replaceAll(", {0,1}", "..."));
}
markUneditableText(textEditor); markUneditableText(textEditor);
// Disable the lockable text listener since the application is no // Disable the lockable text listener since the application is no
@ -7109,14 +7153,6 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
textEditor.append(textProduct); textEditor.append(textProduct);
// if product is a WarnGen product and is not enabled for mixed case
// transmission, replace all commas with ellipses
if (warngenPils.contains(product.getNnnid())
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
textEditor.setText(textEditor.getText()
.replaceAll(", {0,1}", "..."));
}
markUneditableText(textEditor); markUneditableText(textEditor);
// Update text display model with the product that was // Update text display model with the product that was
@ -8038,7 +8074,10 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
paragraphStart = paragraphStart.toUpperCase(); paragraphStart = paragraphStart.toUpperCase();
// is this the locations paragraph? // is this the locations paragraph?
if (paragraphStart.startsWith("* LOCATIONS")) { if (paragraphStart.startsWith("* LOCATIONS")
|| paragraphStart.startsWith(("* SOME LOCATIONS"))
|| paragraphStart.startsWith(("LOCATIONS IMPACTED"))
|| paragraphStart.startsWith(("SOME LOCATIONS THAT"))) {
inLocations = true; inLocations = true;
} }
@ -8079,7 +8118,7 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
} }
if (line.length() <= charWrapCol) { if (line.length() <= charWrapCol) {
extendShortLine(lineNumber, padding); extendShortLine(lineNumber, padding, inLocations);
if (textEditor.getLine(lineNumber).length() <= charWrapCol) { if (textEditor.getLine(lineNumber).length() <= charWrapCol) {
// extended line is still short enough do not wrap // extended line is still short enough do not wrap
if (lineNumber < endWrapLine) { if (lineNumber < endWrapLine) {
@ -8110,8 +8149,9 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
* *
* @param lineNumber * @param lineNumber
* @param padding * @param padding
* @param inLocations
*/ */
private void extendShortLine(int lineNumber, final String padding) { private void extendShortLine(int lineNumber, final String padding, boolean inLocations) {
// if the line is too short move the next line up // if the line is too short move the next line up
// if there is a next line // if there is a next line
String line = textEditor.getLine(lineNumber); String line = textEditor.getLine(lineNumber);
@ -8190,10 +8230,12 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
String wordSpace = ""; String wordSpace = "";
if (noSeparatorPattern.matcher(endLine).matches() if (noSeparatorPattern.matcher(endLine).matches()
&& noSeparatorPattern.matcher(startNextLine) && noSeparatorPattern.matcher(startNextLine)
.matches()) { .matches()
&& (!inLocations || !line.endsWith("..."))) {
// Put a space between words when merging the lines. // Put a space between words when merging the lines.
wordSpace = " "; wordSpace = " ";
} }
textEditor.replaceTextRange(newlinePosition, deleteLen, textEditor.replaceTextRange(newlinePosition, deleteLen,
wordSpace); wordSpace);
String afterReplace = textEditor.getText(); String afterReplace = textEditor.getText();
@ -8207,7 +8249,7 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
// is this line still too short? // is this line still too short?
if (textEditor.getLine(lineNumber).length() <= charWrapCol) { if (textEditor.getLine(lineNumber).length() <= charWrapCol) {
extendShortLine(lineNumber, padding); extendShortLine(lineNumber, padding, inLocations);
} }
} }
} }
@ -8460,7 +8502,7 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
private void recompileRegex() { private void recompileRegex() {
this.standardWrapRegex = Pattern.compile("( |..).{1," this.standardWrapRegex = Pattern.compile("( |..).{1,"
+ (charWrapCol - 3) + "}(\\s|-)"); + (charWrapCol - 3) + "}(\\s|-)");
this.locationsFirstRegex = Pattern.compile("^\\* LOCATIONS [^\\.]{1," this.locationsFirstRegex = Pattern.compile("^(?:\\* (?:SOME )?LOCATIONS|LOCATIONS IMPACTED|SOME LOCATIONS THAT) [^\\.]{1,"
+ (charWrapCol - 13) + "}\\s"); + (charWrapCol - 13) + "}\\s");
this.locationsBodyRegex = Pattern.compile("(( |..).{1," this.locationsBodyRegex = Pattern.compile("(( |..).{1,"
+ (charWrapCol - 5) + "}\\.\\.\\.)|(( |..).{1," + (charWrapCol - 5) + "}\\.\\.\\.)|(( |..).{1,"

View file

@ -1,19 +1,39 @@
package com.raytheon.viz.warnings.rsc; package com.raytheon.viz.warnings.rsc;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord; import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
import com.raytheon.uf.common.dataquery.requests.DbQueryRequest;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
import com.raytheon.uf.common.dataquery.responses.DbQueryResponse;
import com.raytheon.uf.viz.core.RecordFactory;
import com.raytheon.uf.viz.core.alerts.AbstractAlertMessageParser;
import com.raytheon.uf.viz.core.alerts.AlertMessage;
import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.requests.ThriftClient;
import com.raytheon.uf.viz.core.rsc.AbstractRequestableResourceData;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource; import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.uf.viz.core.rsc.LoadProperties; import com.raytheon.uf.viz.core.rsc.LoadProperties;
/**
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Apr 21, 2016 DR 18905 Qinglu Lin Added code to handle no SPS auto-update issue.
*
*/
@XmlAccessorType(XmlAccessType.NONE) @XmlAccessorType(XmlAccessType.NONE)
public class CWASPSResourceData extends WWAResourceData { public class CWASPSResourceData extends WWAResourceData {
private static AlertMessageToPDOParserSPS alertParser = new AlertMessageToPDOParserSPS();
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@ -34,4 +54,42 @@ public class CWASPSResourceData extends WWAResourceData {
return new CWASPSResource(this, loadProperties); return new CWASPSResource(this, loadProperties);
} }
@Override
public AbstractAlertMessageParser getAlertParser() {
return alertParser;
}
private static class AlertMessageToPDOParserSPS extends AbstractAlertMessageParser {
@Override
public Object parseAlertMessage(AlertMessage message,
AbstractRequestableResourceData reqResourceData) throws VizException {
Object objectToSend = null;
Map<String, Object> attribs = new HashMap<>(message.decodedAlert);
if (reqResourceData.isUpdatingOnMetadataOnly()) {
PluginDataObject record = RecordFactory.getInstance()
.loadRecordFromMap(attribs);
objectToSend = record;
} else {
/*
* TODO avoid requesting data that will not be used, for example
* when time matching won't allow the frame to be displayed.
*/
attribs.remove(PluginDataObject.DATAURI_ID);
DbQueryRequest request = new DbQueryRequest(
RequestConstraint.toConstraintMappingExcludeNull(attribs));
request.setLimit(1);
DbQueryResponse response = (DbQueryResponse) ThriftClient
.sendRequest(request);
PluginDataObject[] pdos = response
.getEntityObjects(PluginDataObject.class);
if (pdos.length > 0) {
objectToSend = pdos[0];
}
}
return objectToSend;
}
}
} }

View file

@ -62,6 +62,7 @@ import com.raytheon.uf.common.wmo.WMOTimeParser;
* Jun 19, 2014 3226 bclement added validator callback * Jun 19, 2014 3226 bclement added validator callback
* Jul 07, 2015 4581 skorolev Corrected decodeStrikes to avoid BufferUnderflowException. * Jul 07, 2015 4581 skorolev Corrected decodeStrikes to avoid BufferUnderflowException.
* Apr 07, 2016 DR18763 mgamazaychikov Switched to using LightningWMOHeader. * Apr 07, 2016 DR18763 mgamazaychikov Switched to using LightningWMOHeader.
* Apr 21, 2016 DR18849 mgamazaychikov Decrypt all data in decrypt method.
* *
* </pre> * </pre>
* *
@ -200,9 +201,19 @@ public class TotalLightningDecoder {
*/ */
private PluginDataObject[] decodeInternal(LightningWMOHeader wmoHdr, private PluginDataObject[] decodeInternal(LightningWMOHeader wmoHdr,
String fileName, byte[] pdata) throws DecoderException { String fileName, byte[] pdata) throws DecoderException {
if (!validFlashPacket(pdata, COMBINATION_PACKET_HEADER_SIZE)) { byte[] pdataPreDecrypt = pdata;
/* assume data is encrypted if we can't understand it */ // determine if the data is encrypted or not based on comparing
pdata = decrypt(wmoHdr, fileName, pdata); // checksums for flash packet
pdata = decrypt(wmoHdr, fileName, pdata);
boolean isDecryptedValid = validFlashPacket(pdata,
COMBINATION_PACKET_HEADER_SIZE);
boolean isPreDecryptedValid = validFlashPacket(pdataPreDecrypt,
COMBINATION_PACKET_HEADER_SIZE);
// assume that all data is encrypted, so decrypt it
if (!isDecryptedValid && isPreDecryptedValid) {
// this means that data is not encrypted, proceed without
// decryption
pdata = pdataPreDecrypt;
} }
List<LightningStrikePoint> strikes = decodeStrikes(fileName, pdata); List<LightningStrikePoint> strikes = decodeStrikes(fileName, pdata);
if (!strikes.isEmpty()) { if (!strikes.isEmpty()) {