diff --git a/RadarServer/com.raytheon.rcm.lib/src/com/raytheon/rcm/message/GSM.java b/RadarServer/com.raytheon.rcm.lib/src/com/raytheon/rcm/message/GSM.java index ec91d0a165..a2eb2b7da5 100755 --- a/RadarServer/com.raytheon.rcm.lib/src/com/raytheon/rcm/message/GSM.java +++ b/RadarServer/com.raytheon.rcm.lib/src/com/raytheon/rcm/message/GSM.java @@ -21,61 +21,84 @@ package com.raytheon.rcm.message; import java.nio.ByteBuffer; +/** + * Represents the contents of an ORPG General Status Message. + * + *
+ *  SOFTWARE HISTORY
+ *
+ *  Date         Ticket#     Engineer    Description
+ *  ------------ ----------  ----------- --------------------------
+ *  2009                     dfriedman   Initial version
+ *  2016-04-22   DR 18909    dfriedman   Read fields of expanded GSM.
+ * 
+ */ public class GSM extends Message { - public static final int OP_MODE_MAINTENANCE = 0; - public static final int OP_MODE_CLEAR_AIR = 1; - public static final int OP_MODE_STORM = 2; - - public int opMode; - public int rdaOpStatus; - public int vcp; - public int[] cuts; // in tenths of degrees - public int rdaStatus; - public int rdaAlarms; - public int dataAvailability; // "DTE" - public int rpgOpStatus; - public int rpgAlarms; - public int rpgStatus; - public int rpgNarrowbandStatus; - public int rcc; - public int productAvailability; - public int superResCuts; - public int rdaVersion; - public int rdaChannel; - public int rpgVersion; - - public static GSM decode(byte[] msg) { - return (GSM) MD.decode(msg); - } + public static final int OP_MODE_MAINTENANCE = 0; + public static final int OP_MODE_CLEAR_AIR = 1; + public static final int OP_MODE_STORM = 2; - protected void decodeBlock(int index, ByteBuffer buf) { - if (index != 1) - return; - opMode = buf.getShort(); - rdaOpStatus = buf.getShort(); - vcp = buf.getShort(); - int nCuts = buf.getShort(); - cuts = new int[nCuts]; - for (int i = 0; i < 20; ++i) { - if (i < cuts.length) - cuts[i] = buf.getShort(); - else - buf.getShort(); - } - rdaStatus = buf.getShort(); - rdaAlarms = buf.getShort(); - dataAvailability = buf.getShort(); - rpgOpStatus = buf.getShort(); - rpgAlarms = buf.getShort(); - rpgStatus = buf.getShort(); - rpgNarrowbandStatus = buf.getShort(); - rcc = buf.getShort(); - productAvailability = buf.getShort(); - superResCuts = buf.getShort(); - buf.position(buf.position() + 4); - rdaVersion = buf.getShort(); - rdaChannel = buf.getShort(); - buf.position(buf.position() + 4); - rpgVersion = buf.getShort(); - } + public int opMode; + public int rdaOpStatus; + public int vcp; + public int[] cuts; // in tenths of degrees + public int rdaStatus; + public int rdaAlarms; + public int dataAvailability; // "DTE" + public int rpgOpStatus; + public int rpgAlarms; + public int rpgStatus; + public int rpgNarrowbandStatus; + public int rcc; + public int productAvailability; + public int superResCuts; + public int rdaVersion; + public int rdaChannel; + public int rpgVersion; + public int vcpSupplemental; + + public static GSM decode(byte[] msg) { + return (GSM) MD.decode(msg); + } + + protected void decodeBlock(int index, ByteBuffer buf) { + if (index != 1) + return; + opMode = buf.getShort(); + rdaOpStatus = buf.getShort(); + vcp = buf.getShort(); + int nCuts = buf.getShort(); + cuts = new int[nCuts]; + for (int i = 0; i < 20; ++i) { + short cut = buf.getShort(); + if (i < cuts.length) { + cuts[i] = cut; + } + } + rdaStatus = buf.getShort(); + rdaAlarms = buf.getShort(); + dataAvailability = buf.getShort(); + rpgOpStatus = buf.getShort(); + rpgAlarms = buf.getShort(); + rpgStatus = buf.getShort(); + rpgNarrowbandStatus = buf.getShort(); + rcc = buf.getShort(); + productAvailability = buf.getShort(); + superResCuts = buf.getShort(); + buf.position(buf.position() + 4); + rdaVersion = buf.getShort(); + rdaChannel = buf.getShort(); + buf.position(buf.position() + 4); + 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(); + } } diff --git a/RadarServer/com.raytheon.rcm.server/src/com/raytheon/rcm/otrmgr/OTRManager.java b/RadarServer/com.raytheon.rcm.server/src/com/raytheon/rcm/otrmgr/OTRManager.java index 07e713c2a1..61c705e967 100755 --- a/RadarServer/com.raytheon.rcm.server/src/com/raytheon/rcm/otrmgr/OTRManager.java +++ b/RadarServer/com.raytheon.rcm.server/src/com/raytheon/rcm/otrmgr/OTRManager.java @@ -22,10 +22,12 @@ package com.raytheon.rcm.otrmgr; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import com.raytheon.rcm.config.RadarConfig; +import com.raytheon.rcm.config.RadarType; import com.raytheon.rcm.config.RcmUtil; import com.raytheon.rcm.event.OtrEvent; 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.ProductRequest; import com.raytheon.rcm.message.RequestResponse; +import com.raytheon.rcm.products.ElevationInfo; import com.raytheon.rcm.request.Filter; import com.raytheon.rcm.request.Request; import com.raytheon.rcm.request.Sequence; @@ -55,9 +58,18 @@ import com.raytheon.rcm.server.RadarServer; /** * Manages One Time Requests for the RPGs. *

- * Does not actually do much except provide a place to queue up requests while - * waiting to connect to the RPG. Does do some coalescing of duplicate - * requests. + * Implements a queue for pending requests to the RPGs. Performs some coalescing + * of duplicate requests. + * + *

+ *  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.
+ * 
*/ public class OTRManager extends RadarEventAdapter { @@ -69,7 +81,7 @@ public class OTRManager extends RadarEventAdapter { */ protected boolean isReady; - protected List requests = new ArrayList(); + protected List requests = new ArrayList<>(); protected GSM lastGSM; @@ -226,7 +238,7 @@ public class OTRManager extends RadarEventAdapter { private void trySendingRequests() { if (isReady()) { - ArrayList requestsToSend = new ArrayList(); + ArrayList requestsToSend = new ArrayList<>(); long now = System.currentTimeMillis(); synchronized (this.requests) { for (Req r : requests) { @@ -319,31 +331,55 @@ public class OTRManager extends RadarEventAdapter { && request.getElevationSelection() != Request.SPECIFIC_ELEVATION) { if (lastGSM != null) { if (request.getElevationSelection() == Request.ALL_ELEVATIONS) { - /* - * We do not get information about duplicate - * 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; + RadarType radarType = RcmUtil.getRadarType(getRadarConfig()); + int[] completeElevationList; - nElevations = request.getElevationAngle() == 0 ? lastGSM.cuts.length - : 1; + if (radarType == RadarType.WSR + || (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) { - nElevations = Math.min(lastGSM.cuts.length, + nElevations = Math.min(uniqueCount(lastGSM.cuts), request.getElevationAngle()); } else if (request.getElevationSelection() == Request.LOWER_ELEVATIONS) { + HashSet seenAngles = new HashSet<>(); nElevations = 0; int reqEA = request.getElevationAngle(); for (int ea : lastGSM.cuts) { - if (ea <= reqEA) + if (ea <= reqEA && !seenAngles.contains(ea)) { ++nElevations; - else - break; + seenAngles.add(ea); + } } } else exactCountUnknown = true; @@ -356,9 +392,41 @@ public class OTRManager extends RadarEventAdapter { nExpected = request.count * nElevations; } + private int uniqueCount(int[] angles) { + HashSet 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) { if (handlers == null) - handlers = new ArrayList(); + handlers = new ArrayList<>(); handlers.add(handler); } @@ -387,7 +455,7 @@ public class OTRManager extends RadarEventAdapter { RadarServer radarServer; // ArrayList requests = new ArrayList(); - HashMap state = new HashMap(); + HashMap state = new HashMap<>(); public OTRManager(RadarServer radarServer) { this.radarServer = radarServer; diff --git a/RadarServer/com.raytheon.rcm.server/src/com/raytheon/rcm/server/EventLogger.java b/RadarServer/com.raytheon.rcm.server/src/com/raytheon/rcm/server/EventLogger.java index d412a27481..16ca88c28e 100755 --- a/RadarServer/com.raytheon.rcm.server/src/com/raytheon/rcm/server/EventLogger.java +++ b/RadarServer/com.raytheon.rcm.server/src/com/raytheon/rcm/server/EventLogger.java @@ -31,184 +31,198 @@ import com.raytheon.rcm.message.GraphicProduct.PDB; /** * A radar server component that logs various radar events. + * + *
+ *  SOFTWARE HISTORY
+ *
+ *  Date         Ticket#     Engineer    Description
+ *  ------------ ----------  ----------- --------------------------
+ *  2009                     dfriedma    Initial version
+ *  2016-04-22   DR 18909    dfriedma    Log fields of expanded GSM.
+ * 
*/ public class EventLogger extends RadarEventAdapter { - - public EventLogger() { - - } - @Override - public void handleRadarEvent(RadarEvent event) { - switch (event.getType()) { - case RadarEvent.CONNECTION_UP: - Log.eventf("%s: connected", event.getRadarID()); - break; - case RadarEvent.CONNECTION_DOWN: - Log.eventf("%s: disconnected", event.getRadarID()); - break; - case RadarEvent.MESSAGE_RECEIVED: - { - StringBuilder s = new StringBuilder(); - byte[] msg = event.getMessageData(); - int messageCode = Message.messageCodeOf(msg); - s.append("code=" + messageCode); - s.append(" size=" + msg.length); - if (messageCode == Message.GSM) { - s.append(' '); - GSM gsm = null; - try { - gsm = GSM.decode(msg); - } catch (Exception e) { - s.append("(Message decoding failed)"); - } - if (gsm != null) - s.append(formatGSM(gsm)); - } else if (messageCode == Message.REQUEST_RESPONSE) { - s.append(' '); - RequestResponse rr = null; - try { - rr = RequestResponse.decode(msg); - } catch (Exception e) { - s.append("(Message decoding failed)"); - } - if (rr != null) - s.append(formatPRR(rr)); - } else if (messageCode >= 16) { - PDB pdb = null; - - s.append(' '); - try { - pdb = GraphicProduct.pdbOfMessage(msg); - } catch (Exception e) { - s.append("(Message decoding failed)"); - } - if (pdb != null) - s.append(String.format("elev=%.1f sequence=%d"+ - " vs=%3$tY-%3$tm-%3$td %3$tH:%3$tM:%3$tS #%4$d", - pdb.getElevationAngle() / 10.0, pdb.sequence, - pdb.volumeScanTime, pdb.volumeScan)); - } - - Log.eventf("%s: message %s", event.getRadarID(), s.toString()); - break; - } - } - } + public EventLogger() { - protected final String[] rdaOpStatusStr = { - "auto-calib-disab", "online", "maint-req", "maint-mand", "cmd-shutdown", - "inoperable", null, "wideband-disconn" - }; - protected final String[] rdaStatusStr = { - null, "startup", "standby", "restart", "operate", null, "offline-op" - }; - protected final String[] rdaAlarmStr = { - "indeterminate", "tower", "pedestal", "transmitter", "receiver", "control", "comms" - }; - protected final String[] dteStr = { - null, "none", "refl", "vel", "sw", "dual-pol" - }; - protected final String[] rpgOpStr = { - "load-shed", "online", "maint-req", "maint-mand", "cmd-shutdown" - }; - protected final String[] rpgAlarmStr = { - "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", - "task-fail", "media-fail" - }; - protected final String[] rpgStatusStr = { - "restart", "operate", "standby", null, "test-mode" - }; - protected final String[] productAvailStr = { - "avail", "degraded", "not-avail" - }; - protected final String[] prrStr = { - "no-such-msg", "no-such-prod", "not-gen", "proc-fault", - "narrowband-loadshed", "illegal-req", "mem-loadshed", "cpu-loadshed", - "slot-unavail", "task-failed", "task-unavail", "avail-next-scan", - "moment-disabled", "invalid-password", null, "aborted-scan", - "inval-prod-param", "data-seq-error", "task-term" - }; - - protected String formatBits(short bits, String[] strings) { - StringBuilder result = new StringBuilder(); - for (int i = 0; i < 16; i++) { - if ((bits & (1 << i)) != 0) { - if (result.length() > 0) - result.append(','); - String s = null; - if (i < strings.length) - s = strings[i]; - if (s == null) - s = "unk" + Integer.toString(15 - i); - result.append(s); - } - } - return result.toString(); - } - - protected String formatPrrBits(int bits, String[] strings) { - StringBuilder result = new StringBuilder(); - for (int i = 0; i < 32; i++) { - // PRR bits are defined from the MSB on down, so - // note the (31-i) - if ((bits & (1 << (31-i))) != 0) { - if (result.length() > 0) - result.append(','); - String s = null; - if (i < strings.length) - s = strings[i]; - if (s == null) - s = "unk" + Integer.toString(31 - i); - result.append(s); - } - } - return result.toString(); - } - - protected String formatGSM(GSM gsm) { - StringBuilder o = new StringBuilder(); - String s; + } - switch (gsm.opMode) { - case GSM.OP_MODE_CLEAR_AIR: s = "clear-air"; break; - case GSM.OP_MODE_STORM: s = "storm"; break; - case GSM.OP_MODE_MAINTENANCE: s = "maintenance"; break; - default: s = "(" +Integer.toString(gsm.opMode) + ")"; - } - o.append("opMode=" + s); - - o.append(" vcp=" + gsm.vcp); - 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", - formatBits((short) gsm.rdaOpStatus, rdaOpStatusStr), - formatBits((short) gsm.rdaStatus, rdaStatusStr), - formatBits((short) gsm.rdaAlarms, rdaAlarmStr), - formatBits((short) gsm.dataAvailability, dteStr), - formatBits((short) gsm.rpgOpStatus, rpgOpStr), - formatBits((short) gsm.rpgStatus, rpgStatusStr), - formatBits((short) gsm.rpgAlarms, rpgAlarmStr))); - - o.append(String.format(" avail=%s", - formatBits((short) gsm.productAvailability, productAvailStr))); - - o.append(String.format(" rdaVer=%.1f rpgVer=%.1f", gsm.rdaVersion/10.0, gsm.rpgVersion/10.)); - - return o.toString(); - } - - protected String formatPRR(RequestResponse rr) { - StringBuilder o = new StringBuilder(); - - 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(); - } + @Override + public void handleRadarEvent(RadarEvent event) { + switch (event.getType()) { + case RadarEvent.CONNECTION_UP: + Log.eventf("%s: connected", event.getRadarID()); + break; + case RadarEvent.CONNECTION_DOWN: + Log.eventf("%s: disconnected", event.getRadarID()); + break; + case RadarEvent.MESSAGE_RECEIVED: + { + StringBuilder s = new StringBuilder(); + byte[] msg = event.getMessageData(); + int messageCode = Message.messageCodeOf(msg); + s.append("code=" + messageCode); + s.append(" size=" + msg.length); + if (messageCode == Message.GSM) { + s.append(' '); + GSM gsm = null; + try { + gsm = GSM.decode(msg); + } catch (Exception e) { + s.append("(Message decoding failed)"); + } + if (gsm != null) + s.append(formatGSM(gsm)); + } else if (messageCode == Message.REQUEST_RESPONSE) { + s.append(' '); + RequestResponse rr = null; + try { + rr = RequestResponse.decode(msg); + } catch (Exception e) { + s.append("(Message decoding failed)"); + } + if (rr != null) + s.append(formatPRR(rr)); + } else if (messageCode >= 16) { + PDB pdb = null; + s.append(' '); + try { + pdb = GraphicProduct.pdbOfMessage(msg); + } catch (Exception e) { + s.append("(Message decoding failed)"); + } + if (pdb != null) + s.append(String.format("elev=%.1f sequence=%d"+ + " vs=%3$tY-%3$tm-%3$td %3$tH:%3$tM:%3$tS #%4$d", + pdb.getElevationAngle() / 10.0, pdb.sequence, + pdb.volumeScanTime, pdb.volumeScan)); + } + + Log.eventf("%s: message %s", event.getRadarID(), s.toString()); + break; + } + } + } + + protected final String[] rdaOpStatusStr = { + "auto-calib-disab", "online", "maint-req", "maint-mand", "cmd-shutdown", + "inoperable", null, "wideband-disconn" + }; + protected final String[] rdaStatusStr = { + null, "startup", "standby", "restart", "operate", null, "offline-op" + }; + protected final String[] rdaAlarmStr = { + "indeterminate", "tower", "pedestal", "transmitter", "receiver", "control", "comms" + }; + protected final String[] dteStr = { + null, "none", "refl", "vel", "sw", "dual-pol" + }; + protected final String[] rpgOpStr = { + "load-shed", "online", "maint-req", "maint-mand", "cmd-shutdown" + }; + protected final String[] rpgAlarmStr = { + "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", + "task-fail", "media-fail" + }; + protected final String[] rpgStatusStr = { + "restart", "operate", "standby", null, "test-mode" + }; + protected final String[] productAvailStr = { + "avail", "degraded", "not-avail" + }; + protected final String[] prrStr = { + "no-such-msg", "no-such-prod", "not-gen", "proc-fault", + "narrowband-loadshed", "illegal-req", "mem-loadshed", "cpu-loadshed", + "slot-unavail", "task-failed", "task-unavail", "avail-next-scan", + "moment-disabled", "invalid-password", null, "aborted-scan", + "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) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < 16; i++) { + if ((bits & (1 << i)) != 0) { + if (result.length() > 0) + result.append(','); + String s = null; + if (i < strings.length) + s = strings[i]; + if (s == null) + s = "unk" + Integer.toString(15 - i); + result.append(s); + } + } + return result.toString(); + } + + protected String formatPrrBits(int bits, String[] strings) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < 32; i++) { + // PRR bits are defined from the MSB on down, so + // note the (31-i) + if ((bits & (1 << (31-i))) != 0) { + if (result.length() > 0) + result.append(','); + String s = null; + if (i < strings.length) + s = strings[i]; + if (s == null) + s = "unk" + Integer.toString(31 - i); + result.append(s); + } + } + return result.toString(); + } + + protected String formatGSM(GSM gsm) { + StringBuilder o = new StringBuilder(); + String s; + + switch (gsm.opMode) { + case GSM.OP_MODE_CLEAR_AIR: s = "clear-air"; break; + case GSM.OP_MODE_STORM: s = "storm"; break; + case GSM.OP_MODE_MAINTENANCE: s = "maintenance"; break; + default: s = "(" +Integer.toString(gsm.opMode) + ")"; + } + o.append("opMode=" + s); + + o.append(" vcp=" + gsm.vcp); + 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", + formatBits((short) gsm.rdaOpStatus, rdaOpStatusStr), + formatBits((short) gsm.rdaStatus, rdaStatusStr), + formatBits((short) gsm.rdaAlarms, rdaAlarmStr), + formatBits((short) gsm.dataAvailability, dteStr), + formatBits((short) gsm.rpgOpStatus, rpgOpStr), + formatBits((short) gsm.rpgStatus, rpgStatusStr), + formatBits((short) gsm.rpgAlarms, rpgAlarmStr))); + + o.append(String.format(" avail=%s", + formatBits((short) gsm.productAvailability, productAvailStr))); + + o.append(String.format(" suppl=%s", + formatBits((short) gsm.vcpSupplemental, vcpSupplementalStr))); + + o.append(String.format(" rdaVer=%.1f rpgVer=%.1f", gsm.rdaVersion/10.0, gsm.rpgVersion/10.)); + + return o.toString(); + } + + protected String formatPRR(RequestResponse rr) { + StringBuilder o = new StringBuilder(); + + 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(); + } } diff --git a/cave/com.raytheon.viz.texteditor/src/com/raytheon/viz/texteditor/dialogs/TextEditorDialog.java b/cave/com.raytheon.viz.texteditor/src/com/raytheon/viz/texteditor/dialogs/TextEditorDialog.java index d6f089c59f..2c0ffe9bac 100644 --- a/cave/com.raytheon.viz.texteditor/src/com/raytheon/viz/texteditor/dialogs/TextEditorDialog.java +++ b/cave/com.raytheon.viz.texteditor/src/com/raytheon/viz/texteditor/dialogs/TextEditorDialog.java @@ -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 * 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. + * Apr 15, 2016 RM 18870 D. Friedman Replace commas with ellipses only at start of edit and then word-wrap. * * * @@ -4254,20 +4255,19 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener, // section 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 if (markUneditableText(textEditor)) { // Enable listener to monitor attempt to edit locked text 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. editorButtonMenuStates(inEditMode); @@ -4295,6 +4295,60 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener, 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. * @@ -4402,16 +4456,6 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener, 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); // Disable the lockable text listener since the application is no @@ -7109,14 +7153,6 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener, 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); // Update text display model with the product that was @@ -8038,7 +8074,10 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener, paragraphStart = paragraphStart.toUpperCase(); // 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; } @@ -8079,7 +8118,7 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener, } if (line.length() <= charWrapCol) { - extendShortLine(lineNumber, padding); + extendShortLine(lineNumber, padding, inLocations); if (textEditor.getLine(lineNumber).length() <= charWrapCol) { // extended line is still short enough do not wrap if (lineNumber < endWrapLine) { @@ -8110,8 +8149,9 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener, * * @param lineNumber * @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 there is a next line String line = textEditor.getLine(lineNumber); @@ -8190,10 +8230,12 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener, String wordSpace = ""; if (noSeparatorPattern.matcher(endLine).matches() && noSeparatorPattern.matcher(startNextLine) - .matches()) { + .matches() + && (!inLocations || !line.endsWith("..."))) { // Put a space between words when merging the lines. wordSpace = " "; } + textEditor.replaceTextRange(newlinePosition, deleteLen, wordSpace); String afterReplace = textEditor.getText(); @@ -8207,7 +8249,7 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener, // is this line still too short? 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() { this.standardWrapRegex = Pattern.compile("( |..).{1," + (charWrapCol - 3) + "}(\\s|-)"); - this.locationsFirstRegex = Pattern.compile("^\\* LOCATIONS [^\\.]{1," + this.locationsFirstRegex = Pattern.compile("^(?:\\* (?:SOME )?LOCATIONS|LOCATIONS IMPACTED|SOME LOCATIONS THAT) [^\\.]{1," + (charWrapCol - 13) + "}\\s"); this.locationsBodyRegex = Pattern.compile("(( |..).{1," + (charWrapCol - 5) + "}\\.\\.\\.)|(( |..).{1," diff --git a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/CWASPSResourceData.java b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/CWASPSResourceData.java index eda8307c04..662cf4cbce 100644 --- a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/CWASPSResourceData.java +++ b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/CWASPSResourceData.java @@ -1,19 +1,39 @@ package com.raytheon.viz.warnings.rsc; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import com.raytheon.uf.common.dataplugin.PluginDataObject; 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.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.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) public class CWASPSResourceData extends WWAResourceData { + private static AlertMessageToPDOParserSPS alertParser = new AlertMessageToPDOParserSPS(); + /* * (non-Javadoc) * @@ -34,4 +54,42 @@ public class CWASPSResourceData extends WWAResourceData { 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 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; + } + } } diff --git a/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/total/TotalLightningDecoder.java b/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/total/TotalLightningDecoder.java index 7b85cc9ec8..7e33c05a25 100644 --- a/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/total/TotalLightningDecoder.java +++ b/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/total/TotalLightningDecoder.java @@ -62,6 +62,7 @@ import com.raytheon.uf.common.wmo.WMOTimeParser; * Jun 19, 2014 3226 bclement added validator callback * Jul 07, 2015 4581 skorolev Corrected decodeStrikes to avoid BufferUnderflowException. * Apr 07, 2016 DR18763 mgamazaychikov Switched to using LightningWMOHeader. + * Apr 21, 2016 DR18849 mgamazaychikov Decrypt all data in decrypt method. * * * @@ -200,9 +201,19 @@ public class TotalLightningDecoder { */ private PluginDataObject[] decodeInternal(LightningWMOHeader wmoHdr, String fileName, byte[] pdata) throws DecoderException { - if (!validFlashPacket(pdata, COMBINATION_PACKET_HEADER_SIZE)) { - /* assume data is encrypted if we can't understand it */ - pdata = decrypt(wmoHdr, fileName, pdata); + byte[] pdataPreDecrypt = pdata; + // determine if the data is encrypted or not based on comparing + // 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 strikes = decodeStrikes(fileName, pdata); if (!strikes.isEmpty()) {