Omaha #3157: Refactor TPCWatchSrv, SPCWatchSrv, and WCLWatchSrv to correctly handle multiple active GFE sites. Update active table code to allow multiple configured SPC and TPC sites from VTECPartners.py.

Change-Id: Ie7565f0932054477580baf7e06e26357916fd746

Former-commit-id: 9185eea7409452fe004185dfa51d78f5adb656d4
This commit is contained in:
David Gillingham 2014-05-14 16:51:22 -05:00
parent d1a6be5011
commit 1f1db083ca
19 changed files with 737 additions and 536 deletions

View file

@ -24,9 +24,9 @@
<constructor-arg ref="smartInitSrv"/> <constructor-arg ref="smartInitSrv"/>
</bean> </bean>
<bean id="spcWatch" class="com.raytheon.edex.plugin.gfe.spc.SPCWatchSrv"/> <bean id="spcWatch" class="com.raytheon.edex.plugin.gfe.watch.SPCWatchSrv"/>
<bean id="tpcWatch" class="com.raytheon.edex.plugin.gfe.tpc.TPCWatchSrv"/> <bean id="tpcWatch" class="com.raytheon.edex.plugin.gfe.watch.TPCWatchSrv"/>
<bean id="wclWatch" class="com.raytheon.edex.plugin.gfe.wcl.WCLWatchSrv"/> <bean id="wclWatch" class="com.raytheon.edex.plugin.gfe.watch.WCLWatchSrv"/>
<bean id="vtecChangeListener" class="com.raytheon.edex.plugin.gfe.server.notify.VTECTableChangeListener"/> <bean id="vtecChangeListener" class="com.raytheon.edex.plugin.gfe.server.notify.VTECTableChangeListener"/>
@ -36,7 +36,7 @@
<route id="SPCWatch"> <route id="SPCWatch">
<from uri="vm:gfe.spcWatch"/> <from uri="vm:gfe.spcWatch"/>
<doTry> <doTry>
<bean ref="spcWatch" method="handleSpcWatch"/> <bean ref="spcWatch" method="handleWatch"/>
<doCatch> <doCatch>
<exception>java.lang.Throwable</exception> <exception>java.lang.Throwable</exception>
<to <to
@ -48,7 +48,7 @@
<route id="TPCWatch"> <route id="TPCWatch">
<from uri="vm:gfe.tpcWatch"/> <from uri="vm:gfe.tpcWatch"/>
<doTry> <doTry>
<bean ref="tpcWatch" method="handleTpcWatch"/> <bean ref="tpcWatch" method="handleWatch"/>
<doCatch> <doCatch>
<exception>java.lang.Throwable</exception> <exception>java.lang.Throwable</exception>
<to <to

View file

@ -74,6 +74,7 @@ import com.raytheon.uf.edex.site.notify.SendSiteActivationNotifications;
* Jun 13, 2013 #2044 randerso Refactored to use IFPServer * Jun 13, 2013 #2044 randerso Refactored to use IFPServer
* Oct 16, 2013 #2475 dgilling Better error handling for IRT activation. * Oct 16, 2013 #2475 dgilling Better error handling for IRT activation.
* Mar 21, 2014 2726 rjpeter Updated wait for running loop. * Mar 21, 2014 2726 rjpeter Updated wait for running loop.
* May 15, 2014 #3157 dgilling Mark getActiveSites() as deprecated.
* </pre> * </pre>
* *
* @author njensen * @author njensen
@ -430,8 +431,13 @@ public class GFESiteActivation implements ISiteActivationListener {
* Returns the currently active GFE sites the server is running * Returns the currently active GFE sites the server is running
* *
* @return the active sites * @return the active sites
*
* @deprecated It is preferred that you use the method
* {@link IFPServer#getActiveSites()} to retrieve the list of
* GFE active sites.
*/ */
@Override @Override
@Deprecated
public Set<String> getActiveSites() { public Set<String> getActiveSites() {
return IFPServerConfigManager.getActiveSites(); return IFPServerConfigManager.getActiveSites();
} }

View file

@ -1,151 +0,0 @@
/**
* 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.edex.plugin.gfe.spc;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.raytheon.edex.plugin.gfe.config.GFESiteActivation;
import com.raytheon.edex.plugin.gfe.util.SendNotifications;
import com.raytheon.uf.common.activetable.VTECPartners;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.gfe.server.notify.UserMessageNotification;
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.edex.core.EdexException;
import com.raytheon.uf.edex.core.props.EnvProperties;
import com.raytheon.uf.edex.core.props.PropertiesFactory;
/**
* Watches ingested warnings for WOU products from the SPC (Storm Prediction
* Center). If the warning is a WOU, then it looks to see if the site is in the
* ATTN...WFO... line, and if so, sends a user message to GFE to alert users.
*
* <pre>
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 3, 2008 njensen Initial creation
* Jul 10, 2009 #2590 njensen Added multiple site support
* </pre>
*
* @author njensen
* @version 1.0
*/
public class SPCWatchSrv {
private static final Pattern ATTN_WFO = Pattern
.compile("ATTN\\.\\.\\.WFO\\.\\.\\.([A-Z]{3}\\.\\.\\.)+");
protected transient Log logger = LogFactory.getLog(getClass());
public void handleSpcWatch(List<PluginDataObject> pdos)
throws EdexException {
// create the appropriate SPC notification, returns null if not
// needed.
EnvProperties env = PropertiesFactory.getInstance().getEnvProperties();
String primarySite = env.getEnvValue("SITENAME");
String spcSite = (String) VTECPartners.getInstance(primarySite)
.getattr("VTEC_SPC_SITE", "KWNS");
for (PluginDataObject pdo : pdos) {
AbstractWarningRecord warn = (AbstractWarningRecord) pdo;
if (!warn.getPil().equals("WOU")) {
logger.debug("SPC notification: not WOU product");
return;
}
// find the first record from KWNS, SV.A, TO.A in this product
// action code must be "NEW"
if (warn.getOfficeid().equals(spcSite)
&& warn.getSig().equals("A")
&& (warn.getPhen().equals("TO") || warn.getPhen().equals(
"SV")) && warn.getAct().equals("NEW")) {
// decode the ATTN line, which tells us which WFOs are affected
List<String> wfos = getAttnWfos(warn.getRawmessage());
for (String siteid : GFESiteActivation.getInstance()
.getActiveSites()) {
if (!wfos.contains(siteid)) {
logger.debug("SPC notification: my site not in ATTN list");
continue; // not my WFO
}
// create the message
String txt = "";
if (warn.getPhen().equals("TO")) {
txt = "Tornado Watch";
} else if (warn.getPhen().equals("SV")) {
txt = "Severe Thunderstorm Watch";
}
String testText = "";
if (warn.getVtecstr().charAt(1) == 'T') {
testText = " This is a TEST watch. Please restart the GFE "
+ "in TEST mode before issuing WCN. ";
}
String msg = "Alert: "
+ txt
+ " "
+ warn.getEtn()
+ " has arrived. "
+ "Check for 'red' locks (owned by others) on your Hazard grid and resolve them. "
+ "If hazards are separated into temporary grids, please run MergeHazards. "
+ "Next...save Hazards grid. Finally, select PlotSPCWatches from the Hazards menu.";
msg = msg + testText;
UserMessageNotification notification = new UserMessageNotification(
msg, Priority.CRITICAL, "GFE", siteid);
SendNotifications.send(notification);
}
} else {
logger.debug("SPC notification: "
+ "no SV.A, TO.A vtec lines, or not NEW action code");
}
}
}
private static List<String> getAttnWfos(String rawMessage) {
List<String> list = new ArrayList<String>();
// decode the ATTN line, which tells us which WFOs are affected
// only used for WCL and WOU products
Matcher m = ATTN_WFO.matcher(rawMessage);
if (m.find()) {
String found = m.group();
// eliminate ATTN...WFO...
found = found.substring(13);
if (found != null) {
String[] wfos = found.split("\\.\\.\\.");
for (String s : wfos) {
list.add(s);
}
}
}
return list;
}
}

View file

@ -1,205 +0,0 @@
/**
* 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.edex.plugin.gfe.tpc;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.raytheon.edex.plugin.gfe.config.GFESiteActivation;
import com.raytheon.edex.plugin.gfe.util.SendNotifications;
import com.raytheon.uf.common.activetable.VTECPartners;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.gfe.server.notify.UserMessageNotification;
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.edex.core.EdexException;
import com.raytheon.uf.edex.core.props.EnvProperties;
import com.raytheon.uf.edex.core.props.PropertiesFactory;
/**
* Watches ingested warnings for WOU products from the SPC (Storm Prediction
* Center). If the warning is a WOU, then it looks to see if the site is in the
* ATTN...WFO... line, and if so, sends a user message to GFE to alert users.
*
* <pre>
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 3, 2008 njensen Initial creation
* Jul 10, 2009 #2590 njensen Added multiple site support
* </pre>
*
* @author njensen
* @version 1.0
*/
public class TPCWatchSrv {
private static final Pattern ATTN_WFO = Pattern
.compile("ATTN\\.\\.\\.WFO\\.\\.\\.([A-Z]{3}\\.\\.\\.)+");
private static final Map<String, String> phensigMap;
private static final Map<String, String> actMap;
static {
Map<String, String> phensigMapTemp = new HashMap<String, String>();
phensigMapTemp.put("HU.A", "Hurricane Watch");
phensigMapTemp.put("HU.S", "Hurricane Local Statement");
phensigMapTemp.put("HU.W", "Hurricane Warning");
phensigMap = Collections.unmodifiableMap(phensigMapTemp);
Map<String, String> actMapTemp = new HashMap<String, String>();
actMapTemp.put("CON", "Continued");
actMapTemp.put("CAN", "Cancelled");
actMapTemp.put("NEW", "New");
actMap = Collections.unmodifiableMap(actMapTemp);
}
private static final String alertTxt = "Alert: {0} has arrived from TPC. "
+ "Check for 'red' locks (owned by others) on your Hazard grid and resolve them. "
+ "If hazards are separated into temporary grids, please run Mergehazards. "
+ "Next...save Hazards grid. Finally, select PlotTPCEvents from Hazards menu.";
protected transient Log logger = LogFactory.getLog(getClass());
public void handleTpcWatch(List<PluginDataObject> pdos)
throws EdexException {
EnvProperties env = PropertiesFactory.getInstance().getEnvProperties();
String primarySite = env.getEnvValue("SITENAME");
String tpcSite = (String) VTECPartners.getInstance(primarySite)
.getattr("VTEC_TPC_SITE", "KNHC");
Set<String> activeSites = GFESiteActivation.getInstance()
.getActiveSites();
AbstractWarningRecord ourWarn = null;
String ourSite = null;
// create the appropriate TPC notification, returns null if not
// needed.
Map<String, Set<String>> phensigStormAct = new HashMap<String, Set<String>>();
for (PluginDataObject pdo : pdos) {
AbstractWarningRecord warn = (AbstractWarningRecord) pdo;
if (!warn.getPil().startsWith("TCV")) {
logger.debug("TPC notification: not TCV product");
return;
}
// The warning is a TPC, but for us?
List<String> wfos = getAttnWfos(warn.getRawmessage());
wfos.retainAll(activeSites);
if (wfos.size() == 0) {
logger.debug("TPC notification: my site not in ATTN list");
continue;
}
if (ourWarn == null) {
ourWarn = warn;
ourSite = wfos.get(0);
}
// Collect action codes by phensig and storm #
if (tpcSite.equals(warn.getOfficeid())) {
String phensig = warn.getPhen() + "." + warn.getSig();
String storm = warn.getEtn();
String act = warn.getAct();
Set<String> psActs = phensigStormAct.get(phensig + ":" + storm);
if (psActs == null) {
psActs = new TreeSet<String>();
phensigStormAct.put(phensig + ":" + storm, psActs);
}
psActs.add(act);
}
}
if (phensigStormAct.size() == 0) {
logger.debug("TPC Notification: no HU/TR vtec lines, or not NEW action code");
return;
}
// Build the notification message
StringBuilder msg = new StringBuilder();
msg.append(MessageFormat.format(alertTxt, ourWarn.getPil()));
for (String phensigStorm : phensigStormAct.keySet()) {
Collection<String> acts = phensigStormAct.get(phensigStorm);
String[] splitKey = phensigStorm.split(":");
String phensig = splitKey[0];
String storm = splitKey[1];
String t1 = phensigMap.get(phensig);
if (t1 == null) {
t1 = phensig;
}
msg.append(t1 + ": #" + storm + "(");
String sep = "";
for (String a : acts) {
String a1 = actMap.get(a);
if (a1 == null) {
a1 = a;
}
msg.append(sep).append(a1);
sep = ",";
}
msg.append("). ");
}
UserMessageNotification notification = new UserMessageNotification(
msg.toString(), Priority.CRITICAL, "GFE", ourSite);
SendNotifications.send(notification);
}
private static List<String> getAttnWfos(String rawMessage) {
List<String> list = new ArrayList<String>();
// decode the ATTN line, which tells us which WFOs are affected
// only used for WCL and WOU products
Matcher m = ATTN_WFO.matcher(rawMessage);
if (m.find()) {
String found = m.group();
// eliminate ATTN...WFO...
found = found.substring(13);
if (found != null) {
String[] wfos = found.split("\\.\\.\\.");
for (String s : wfos) {
list.add(s);
}
}
}
return list;
}
}

View file

@ -0,0 +1,173 @@
/**
* 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.edex.plugin.gfe.watch;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.raytheon.edex.plugin.gfe.server.IFPServer;
import com.raytheon.edex.plugin.gfe.util.SendNotifications;
import com.raytheon.uf.common.activetable.VTECPartners;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.gfe.server.message.ServerResponse;
import com.raytheon.uf.common.dataplugin.gfe.server.notify.GfeNotification;
import com.raytheon.uf.common.dataplugin.gfe.server.notify.UserMessageNotification;
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
/**
* Base class for a bean that accepts a {@code List} of
* {@code AbstractWarningRecord}s and generates a set of notifications for the
* GFE user if the storm affects their WFO.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 12, 2014 #3157 dgilling Initial creation
*
* </pre>
*
* @author dgilling
* @version 1.0
*/
public abstract class AbstractWatchNotifierSrv {
protected final IUFStatusHandler statusHandler = UFStatus
.getHandler(getClass());
protected final String watchType;
protected final String supportedPIL;
protected AbstractWatchNotifierSrv(String watchType, String supportedPIL) {
this.watchType = watchType;
this.supportedPIL = supportedPIL;
}
/**
* Processes the warning records and generates a notification for each
* currently activated GFE site if the storm affects the site.
*
* @param pdos
* A list of {@code PluginDataObject}s that are assumed to be
* {@code AbstractWarningRecord}s all decoded from a common
* warning product.
*/
public final void handleWatch(List<PluginDataObject> pdos) {
List<AbstractWarningRecord> warningRecs = filterIncomingRecordsByPIL(pdos);
if (warningRecs.isEmpty()) {
String logMsg = String.format("%s notification: not %s product",
watchType, supportedPIL);
statusHandler.debug(logMsg);
return;
}
/*
* We are making an assumption that all PDOs came from the same source
* product. This is a safe assumption because WarningDecoder processes
* records one product at a time and the plugin notifier code that sends
* those records to us does not do any additional grouping or batching.
*
* Hence, any of the remaining records' raw message will be the same as
* the rest and we can just use the first record's copy.
*/
String productText = warningRecs.get(0).getRawmessage();
Collection<String> wfos = WatchProductUtil.findAttnWFOs(productText);
for (String siteid : IFPServer.getActiveSites()) {
if (!wfos.contains(siteid)) {
String logMsg = String.format(
"%s notification: my site %s not in ATTN list",
watchType, siteid);
statusHandler.debug(logMsg);
continue;
}
VTECPartners partnersConfig = VTECPartners.getInstance(siteid);
String msg = buildNotification(warningRecs, partnersConfig);
if (msg != null) {
sendNotification(msg, siteid);
}
}
}
/**
* Given a list of {@code PluginDataObject}s that are actually
* {@code AbstractWarningRecord}s, filters the list for only those records
* which have the right PIL code.
*
* @param pdos
* List of {@code AbstractWarningRecord}s to filter.
* @return The list of supported {@code AbstractWarningRecord}s as defined
* by {@code getSupportedPIL}.
*/
protected List<AbstractWarningRecord> filterIncomingRecordsByPIL(
List<PluginDataObject> pdos) {
List<AbstractWarningRecord> warningRecords = new ArrayList<AbstractWarningRecord>();
for (PluginDataObject pdo : pdos) {
AbstractWarningRecord warning = (AbstractWarningRecord) pdo;
if (warning.getPil().startsWith(supportedPIL)) {
warningRecords.add(warning);
}
}
return warningRecords;
}
/**
* Takes the specified list of warning records and {@code VTECPartners}
* configuration data and builds a notification message to send.
*
* @param decodedVTEC
* The warning records.
* @param partnersConfig
* The {@code VTECPartners} configuration data.
* @return The notification message to send to the users for the site, or
* {@code null} if no notification applies.
*/
protected abstract String buildNotification(
List<AbstractWarningRecord> decodedVTEC, VTECPartners partnersConfig);
/**
* Sends the specified notification message as an AletViz alert to all GFE
* users connected as the specified site.
*
* @param message
* The notification message text to send.
* @param siteId
* The site identifier that will receive the message.
* @return A {@code ServerResponse} containing error message if sending the
* notification message failed.
*/
protected ServerResponse<?> sendNotification(String message, String siteId) {
GfeNotification notification = new UserMessageNotification(message,
Priority.CRITICAL, "GFE", siteId);
return SendNotifications.send(notification);
}
}

View file

@ -0,0 +1,118 @@
/**
* 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.edex.plugin.gfe.watch;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.raytheon.uf.common.activetable.VTECPartners;
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
/**
* Watches ingested warnings for WOU products from the SPC (Storm Prediction
* Center). If the warning is a WOU, then it looks to see if the site is in the
* ATTN...WFO... line, and if so, sends a user message to GFE to alert users.
*
* <pre>
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 03, 2008 njensen Initial creation
* Jul 10, 2009 #2590 njensen Added multiple site support
* May 12, 2014 #3157 dgilling Re-factor based on AbstractWatchNotifierSrv.
* </pre>
*
* @author njensen
* @version 1.0
*/
public final class SPCWatchSrv extends AbstractWatchNotifierSrv {
private static final String SPC_WATCH_TYPE = "SPC";
private static final String SPC_SUPPORTED_PIL = "WOU";
private static final String DEFAULT_SPC_SITE = "KNHC";
private static final String TEST_TEXT_MSG = " This is a TEST watch. Please restart the GFE in TEST mode before issuing WCN. ";
private static final String ALERT_MSG = "Alert: %s %s has arrived. "
+ "Check for 'red' locks (owned by others) on your Hazard grid and resolve them. "
+ "If hazards are separated into temporary grids, please run MergeHazards. "
+ "Next...save Hazards grid. Finally, select PlotSPCWatches from the Hazards menu.";
private static final Map<String, String> phenTextMap;
static {
Map<String, String> phenTextMapTemp = new HashMap<String, String>(2, 1f);
phenTextMapTemp.put("TO", "Tornado Watch");
phenTextMapTemp.put("SV", "Severe Thunderstorm Watch");
phenTextMap = Collections.unmodifiableMap(phenTextMapTemp);
}
public SPCWatchSrv() {
super(SPC_WATCH_TYPE, SPC_SUPPORTED_PIL);
}
/*
* (non-Javadoc)
*
* @see com.raytheon.edex.plugin.gfe.warning.AbstractWarningNotifierSrv#
* buildNotification(java.util.List, java.lang.String,
* com.raytheon.uf.common.activetable.VTECPartners)
*/
@Override
protected String buildNotification(List<AbstractWarningRecord> decodedVTEC,
VTECPartners partnersConfig) {
Collection<String> spcSites = partnersConfig
.getSpcSites(DEFAULT_SPC_SITE);
// find the first record from our configured list of issuing sites.
// Also this product must be a NEW SV.A or TO.A
AbstractWarningRecord matchRecord = null;
for (AbstractWarningRecord e : decodedVTEC) {
if (spcSites.contains(e.getOfficeid())
&& e.getSig().equals("A")
&& ((e.getPhen().equals("TO")) || (e.getPhen().equals("SV")))
&& e.getAct().equals("NEW")) {
matchRecord = e;
break;
}
}
if (matchRecord == null) {
statusHandler.debug("SPC notification: "
+ "no SV.A, TO.A vtec lines, or not NEW action code");
return null;
}
// create the message
String eventType = phenTextMap.get(matchRecord.getPhen());
StringBuilder msg = new StringBuilder(String.format(ALERT_MSG,
eventType, matchRecord.getEtn()));
if (matchRecord.getVtecstr().charAt(1) == 'T') {
msg.append(TEST_TEXT_MSG);
}
return msg.toString();
}
}

View file

@ -0,0 +1,151 @@
/**
* 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.edex.plugin.gfe.watch;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import com.raytheon.uf.common.activetable.VTECPartners;
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
/**
* Watches ingested warnings for WOU products from the SPC (Storm Prediction
* Center). If the warning is a WOU, then it looks to see if the site is in the
* ATTN...WFO... line, and if so, sends a user message to GFE to alert users.
*
* <pre>
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 03, 2008 njensen Initial creation
* Jul 10, 2009 #2590 njensen Added multiple site support
* May 12, 2014 #3157 dgilling Re-factor based on AbstractWatchNotifierSrv.
* </pre>
*
* @author njensen
* @version 1.0
*/
public final class TPCWatchSrv extends AbstractWatchNotifierSrv {
private static final String TPC_WATCH_TYPE = "TPC";
private static final String TPC_SUPPORTED_PIL = "TCV";
private static final String DEFAULT_TPC_SITE = "KNHC";
private static final String ALERT_TXT = "Alert: %s has arrived from TPC. "
+ "Check for 'red' locks (owned by others) on your Hazard grid and resolve them. "
+ "If hazards are separated into temporary grids, please run Mergehazards. "
+ "Next...save Hazards grid. Finally, select PlotTPCEvents from Hazards menu.";
private static final Map<String, String> phensigMap;
private static final Map<String, String> actMap;
static {
Map<String, String> phensigMapTemp = new HashMap<String, String>(5, 1f);
phensigMapTemp.put("HU.A", "Hurricane Watch");
phensigMapTemp.put("HU.S", "Hurricane Local Statement");
phensigMapTemp.put("HU.W", "Hurricane Warning");
phensigMapTemp.put("TR.A", "Tropical Storm Watch");
phensigMapTemp.put("TR.W", "Tropical Storm Warning");
phensigMap = Collections.unmodifiableMap(phensigMapTemp);
Map<String, String> actMapTemp = new HashMap<String, String>(3, 1f);
actMapTemp.put("CON", "Continued");
actMapTemp.put("CAN", "Cancelled");
actMapTemp.put("NEW", "New");
actMap = Collections.unmodifiableMap(actMapTemp);
}
public TPCWatchSrv() {
super(TPC_WATCH_TYPE, TPC_SUPPORTED_PIL);
}
/*
* (non-Javadoc)
*
* @see com.raytheon.edex.plugin.gfe.warning.AbstractWarningNotifierSrv#
* buildNotification(java.util.List,
* com.raytheon.uf.common.activetable.VTECPartners)
*/
@Override
protected String buildNotification(List<AbstractWarningRecord> decodedVTEC,
VTECPartners partnersConfig) {
Collection<String> tpcSites = partnersConfig
.getTpcSites(DEFAULT_TPC_SITE);
// get all VTEC records, assemble unique list of phen/sig and storm#
Map<String, Set<String>> phensigStormAct = new HashMap<String, Set<String>>();
for (AbstractWarningRecord e : decodedVTEC) {
if (tpcSites.contains(e.getOfficeid())) {
String phensig = e.getPhensig();
String storm = e.getEtn();
String act = e.getAct();
Set<String> psActs = phensigStormAct.get(phensig + ":" + storm);
if (psActs == null) {
psActs = new TreeSet<String>();
phensigStormAct.put(phensig + ":" + storm, psActs);
}
psActs.add(act);
}
}
if (phensigStormAct.isEmpty()) {
statusHandler
.debug("TPC Notification: no HU/TR vtec lines, or not NEW action code");
return null;
}
// create the message
StringBuilder msg = new StringBuilder(String.format(ALERT_TXT,
supportedPIL));
for (String phensigStorm : phensigStormAct.keySet()) {
Collection<String> acts = phensigStormAct.get(phensigStorm);
String[] splitKey = phensigStorm.split(":");
String phensig = splitKey[0];
String storm = splitKey[1];
String t1 = phensigMap.get(phensig);
if (t1 == null) {
t1 = phensig;
}
msg.append(t1 + ": #" + storm + "(");
String sep = "";
for (String a : acts) {
String a1 = actMap.get(a);
if (a1 == null) {
a1 = a;
}
msg.append(sep).append(a1);
sep = ",";
}
msg.append("). ");
}
return msg.toString();
}
}

View file

@ -20,51 +20,66 @@
/** /**
* *
*/ */
package com.raytheon.edex.plugin.gfe.wcl; package com.raytheon.edex.plugin.gfe.watch;
import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileWriter;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.Writer;
import java.nio.channels.FileChannel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.logging.Log; import com.raytheon.edex.plugin.gfe.server.IFPServer;
import org.apache.commons.logging.LogFactory;
import com.raytheon.edex.plugin.gfe.config.GFESiteActivation;
import com.raytheon.edex.plugin.gfe.util.SendNotifications; import com.raytheon.edex.plugin.gfe.util.SendNotifications;
import com.raytheon.uf.common.dataplugin.gfe.server.notify.GfeNotification;
import com.raytheon.uf.common.dataplugin.gfe.server.notify.UserMessageNotification; import com.raytheon.uf.common.dataplugin.gfe.server.notify.UserMessageNotification;
import com.raytheon.uf.common.localization.IPathManager; import com.raytheon.uf.common.localization.IPathManager;
import com.raytheon.uf.common.localization.LocalizationContext; import com.raytheon.uf.common.localization.LocalizationContext;
import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel; import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel;
import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType; import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType;
import com.raytheon.uf.common.localization.PathManagerFactory; import com.raytheon.uf.common.localization.PathManagerFactory;
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.status.UFStatus.Priority;
import com.raytheon.uf.common.time.SimulatedTime; import com.raytheon.uf.common.time.SimulatedTime;
import com.raytheon.uf.common.util.CollectionUtil;
import com.raytheon.uf.common.util.FileUtil;
import com.raytheon.uf.edex.core.EdexException; import com.raytheon.uf.edex.core.EdexException;
/** /**
* @author wldougher * If a WCL (watch county list) is ingested, this class will send a notification
* to the GFE users alerting them that their WFO may be in the path of an
* upcoming TO.A or SV.A.
* *
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* ??? ??, 20?? wldougher Initial creation
* May 14, 2014 #3157 dgilling Ensure code works in multi-domain scenarios,
* code cleanup.
*
* </pre>
*
* @author wldougher
* @version 1.0
*/ */
public class WCLWatchSrv { public final class WCLWatchSrv {
private static final String ALERT_FORM = "Alert: " + "%1$s has arrived. " private static final String ALERT_FORM = "Alert: " + "%1$s has arrived. "
+ "Please select ViewWCL and use %1$s. (Hazards menu)"; + "Please select ViewWCL and use %1$s. (Hazards menu)";
private static final Pattern ATTN_PATTERN = Pattern.compile("^"
+ Pattern.quote("ATTN...WFO..."));
private static final Pattern EXPIRE_TIME_PATTERN = Pattern private static final Pattern EXPIRE_TIME_PATTERN = Pattern
.compile("(\\d{2})(\\d{2})(\\d{2})\\-"); .compile("(\\d{2})(\\d{2})(\\d{2})\\-");
@ -81,36 +96,8 @@ public class WCLWatchSrv {
private static final Pattern UGC_PATTERN = Pattern.compile("\\d{3}\\-"); private static final Pattern UGC_PATTERN = Pattern.compile("\\d{3}\\-");
protected transient Log logger = LogFactory.getLog(getClass()); private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(WCLWatchSrv.class);
/**
* Get the WFOs from the ATTN line.
*
* @param lines
* The lines in the warning file
* @return the WFOs from the WFO attention line, as a set of Strings.
*/
protected Set<String> attnWFOs(List<String> lines) {
StringBuilder wfoLine = new StringBuilder();
boolean attnFound = false;
if (lines != null) {
for (String line : lines) {
attnFound = attnFound || ATTN_PATTERN.matcher(line).lookingAt();
if (attnFound) {
wfoLine.append(line);
}
}
}
Set<String> wfosR = new HashSet<String>();
if (wfoLine.length() > 13) {
String[] wfos = wfoLine.substring(13).split(Pattern.quote("..."));
for (String wfo : wfos) {
wfosR.add(wfo.trim());
}
}
return wfosR;
}
/** /**
* Process a WCL watch, partially parsed and passed as a WclInfo object. * Process a WCL watch, partially parsed and passed as a WclInfo object.
@ -130,20 +117,23 @@ public class WCLWatchSrv {
* or when there are problems generating the WCL script file. * or when there are problems generating the WCL script file.
*/ */
public void handleWclWatch(WclInfo wclInfo) throws EdexException { public void handleWclWatch(WclInfo wclInfo) throws EdexException {
logger.debug("handleWclWatch started"); statusHandler.debug("handleWclWatch started");
UserMessageNotification notice = null; List<GfeNotification> notifications = Collections.emptyList();
String completeProductPil = wclInfo.getCompleteProductPil(); String completeProductPil = wclInfo.getCompleteProductPil();
Set<String> wfos = attnWFOs(wclInfo.getLines()); Collection<String> wfos = WatchProductUtil.findAttnWFOs(wclInfo
.getLines());
Set<String> siteIDs = getSiteIDs(); Set<String> siteIDs = getSiteIDs();
wfos.retainAll(siteIDs); // Keep shared IDs wfos.retainAll(siteIDs); // Keep shared IDs
if (!wfos.isEmpty()) { if (!wfos.isEmpty()) {
// Get the first matching site ID notifications = new ArrayList<GfeNotification>(wfos.size());
String siteID = wfos.toArray(new String[1])[0];
String msg = String.format(ALERT_FORM, completeProductPil); String msg = String.format(ALERT_FORM, completeProductPil);
notice = new UserMessageNotification(msg, Priority.CRITICAL, "GFE",
siteID); for (String siteID : wfos) {
GfeNotification notice = new UserMessageNotification(msg,
Priority.CRITICAL, "GFE", siteID);
notifications.add(notice);
}
} }
// Process the WCL regardless of whether we are sending a notice // Process the WCL regardless of whether we are sending a notice
@ -163,22 +153,19 @@ public class WCLWatchSrv {
// Create a dummy Procedure for export // Create a dummy Procedure for export
String wclStr = makeWclStr(finalUGCList, expireTime, issueTime, String wclStr = makeWclStr(finalUGCList, expireTime, issueTime,
watchType); watchType);
logger.debug("WCLData: " + wclStr); statusHandler.debug("WCLData: " + wclStr);
// Write dummy procedure to temp file // write the WCL file to <wclDir>/<completeProductPil>
File tmpFile = createTempWclFile(wclStr); makePermanent(wclStr, completeProductPil);
// Move the file to the wcl folder if ((wclInfo.getNotify())
// Rename it to <wclDir>/<completeProductPil> && (!CollectionUtil.isNullOrEmpty(notifications))) {
makePermanent(tmpFile, completeProductPil); SendNotifications.send(notifications);
if (notice == null || !wclInfo.getNotify()) {
logger.info("Notification of WCL skipped");
} else { } else {
SendNotifications.send(notice); statusHandler.info("Notification of WCL skipped");
} }
logger.debug("handleWclWatch() ending"); statusHandler.debug("handleWclWatch() ending");
return; return;
} }
@ -188,96 +175,46 @@ public class WCLWatchSrv {
* that method returns a boolean success flag rather than throwing an error, * that method returns a boolean success flag rather than throwing an error,
* so all we can do is tell the user that the rename failed, not why. * so all we can do is tell the user that the rename failed, not why.
* *
* @param tmpFile * @param wclData
* The temporary file (may be null) * WCL data to write to file.
* @param completeProductPil * @param completeProductPil
* The simple name of the file. * The simple name of the file.
* @throws EdexException
* if tmpFile cannot be renamed.
*/
protected void makePermanent(File tmpFile, String completeProductPil)
throws EdexException {
logger.debug("makePermanent(" + tmpFile + "," + completeProductPil
+ ") started");
if (tmpFile != null) {
File wclDir = getWclDir();
File dest = new File(wclDir, completeProductPil);
// Try to do things with renameTo() because it's quick if it works.
if (!tmpFile.renameTo(dest)) {
// renameTo() can fail for a variety of reasons.
// Try to do a copy-and-delete.
FileChannel temp = null;
FileChannel perm = null;
IOException firstFail = null;
try {
temp = new FileInputStream(tmpFile).getChannel();
perm = new FileOutputStream(dest).getChannel();
// should file range be locked before copy?
temp.transferTo(0, temp.size(), perm);
temp.close();
tmpFile.delete();
} catch (IOException e) {
throw new EdexException("Renaming \""
+ tmpFile.getAbsolutePath() + "\" to \""
+ dest.getAbsolutePath() + "\" failed.", e);
} finally {
if (temp != null && temp.isOpen()) {
try {
temp.close();
logger.debug(temp.toString() + " closed");
} catch (IOException e) {
firstFail = e;
}
}
if (perm != null && perm.isOpen()) {
try {
perm.close();
logger.debug(perm.toString() + " closed");
} catch (IOException e) {
if (firstFail == null) {
firstFail = e;
}
}
}
}
if (firstFail != null) {
throw new EdexException("Error closing file", firstFail);
}
}
// If we got to here, claim success!
logger.info("" + tmpFile.getAbsolutePath() + " renamed to "
+ dest.getAbsolutePath());
}
logger.debug("makePermanent(" + tmpFile + "," + completeProductPil
+ ") ending");
}
/**
* Create a temporary file with the prefix "wcl" and the default suffix in
* the default temporary file directory. Write all of wclStr into it.
* *
* @param wclStr
* the String containing the contents to write to the file
* @return the File created.
* @throws EdexException * @throws EdexException
* if the file cannot be written * if WCL file cannot be opened, written, or closed.
*/ */
protected File createTempWclFile(String wclStr) throws EdexException { protected void makePermanent(String wclData, String completeProductPil)
File tmpFile = null; throws EdexException {
PrintStream wclOut = null; statusHandler.debug("makePermanent for [" + completeProductPil
+ "] started");
File wclDir = getWclDir();
File dest = new File(wclDir, completeProductPil);
Writer output = null;
try { try {
tmpFile = File.createTempFile("wcl", null, null); output = new BufferedWriter(new FileWriter(dest));
wclOut = new PrintStream(tmpFile); output.write(wclData);
wclOut.println(wclStr); output.write("\n");
// If we got to here, claim success!
statusHandler.info("Wrote new WCL to " + dest.getAbsolutePath());
} catch (IOException e) { } catch (IOException e) {
throw new EdexException("Error writing parsed WCL to file \"" throw new EdexException("Could not write new WCL file "
+ tmpFile.getAbsolutePath() + "\"", e); + dest.getAbsolutePath(), e);
} finally { } finally {
if (wclOut != null) { if (output != null) {
wclOut.close(); try {
output.close();
} catch (IOException e) {
throw new EdexException("Could not close new WCL file "
+ dest.getAbsolutePath(), e);
}
} }
} }
return tmpFile; statusHandler.debug("makePermanent for [" + completeProductPil
+ "] ending");
} }
/** /**
@ -436,7 +373,7 @@ public class WCLWatchSrv {
* @return a Set of Strings representing the site IDs. * @return a Set of Strings representing the site IDs.
*/ */
protected Set<String> getSiteIDs() { protected Set<String> getSiteIDs() {
Set<String> siteIDs = GFESiteActivation.getInstance().getActiveSites(); Set<String> siteIDs = IFPServer.getActiveSites();
return siteIDs; return siteIDs;
} }
@ -451,13 +388,14 @@ public class WCLWatchSrv {
IPathManager pathManager = PathManagerFactory.getPathManager(); IPathManager pathManager = PathManagerFactory.getPathManager();
LocalizationContext ctx = pathManager.getContext( LocalizationContext ctx = pathManager.getContext(
LocalizationType.CAVE_STATIC, LocalizationLevel.SITE); LocalizationType.CAVE_STATIC, LocalizationLevel.SITE);
String wclName = "gfe" + File.separator + "wcl"; String wclName = FileUtil.join("gfe", "wcl");
File wclDir = pathManager.getFile(ctx, wclName); File wclDir = pathManager.getFile(ctx, wclName);
if (wclDir == null) { if (wclDir == null) {
logger.error("Path manager could not locate " + wclName); statusHandler.error("Path manager could not locate " + wclName);
} else if (!wclDir.exists()) { } else if (!wclDir.exists()) {
wclDir.mkdir(); wclDir.mkdir();
logger.info("Directory " + wclDir.getAbsolutePath() + " created."); statusHandler.info("Directory " + wclDir.getAbsolutePath()
+ " created.");
} }
return wclDir; return wclDir;
} }

View file

@ -0,0 +1,96 @@
/**
* 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.edex.plugin.gfe.watch;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.raytheon.uf.common.util.StringUtil;
/**
* Common methods for dealing with watch products that are received from
* national centers.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 14, 2014 #3157 dgilling Initial creation.
*
* </pre>
*
* @author dgilling
* @version 1.0
*/
public class WatchProductUtil {
private static final Pattern ATTN_PATTERN = Pattern
.compile("\\QATTN...WFO...\\E((?:[A-Z]{3}\\Q...\\E)+)");
private WatchProductUtil() {
throw new AssertionError();
}
/**
* Searches the specified watch product text for a "ATTN...WFO..." line and
* returns a collection of WFOs that appeared in that line of the product.
*
* @param lines
* The lines that comprise the watch product.
* @return The list of WFOs that appear in the "ATTN...WFO..." line of the
* product.
*/
public static Collection<String> findAttnWFOs(List<String> lines) {
return findAttnWFOs(StringUtil.join(lines, '\n'));
}
/**
* Searches the specified watch product text for a "ATTN...WFO..." line and
* returns a collection of WFOs that appeared in that line of the product.
*
* @param rawMessage
* The full text of the watch product in a single String.
* @returnThe list of WFOs that appear in the "ATTN...WFO..." line of the
* product.
*/
public static Collection<String> findAttnWFOs(String rawMessage) {
Collection<String> retVal = Collections.emptySet();
// decode the ATTN line, which tells us which WFOs are affected
// only used for WCL and WOU products
Matcher m = WatchProductUtil.ATTN_PATTERN.matcher(rawMessage);
if (m.find()) {
// eliminate ATTN...WFO...
String found = m.group(1);
String[] wfos = found.split(Pattern.quote("..."));
retVal = new HashSet<String>(Arrays.asList(wfos));
}
return retVal;
}
}

View file

@ -20,7 +20,7 @@
/** /**
* *
*/ */
package com.raytheon.edex.plugin.gfe.wcl; package com.raytheon.edex.plugin.gfe.watch;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;

View file

@ -42,6 +42,7 @@
# start time from file's timestamp. # start time from file's timestamp.
# Oct 03, 2013 2402 bsteffen Make PythonDecoder more extendable. # Oct 03, 2013 2402 bsteffen Make PythonDecoder more extendable.
# May 15, 2014 2536 bclement moved WMO time parsing to WMOTimeParser # May 15, 2014 2536 bclement moved WMO time parsing to WMOTimeParser
# May 15, 2014 3157 dgilling Update location of WclInfo class.
# </pre> # </pre>
# #
@ -176,7 +177,7 @@ class StdWarningDecoder():
if self._productPil[0:3] == "WCL": if self._productPil[0:3] == "WCL":
endpoint = "WCLWatch" endpoint = "WCLWatch"
# build a Java object for the warning # build a Java object for the warning
from com.raytheon.edex.plugin.gfe.wcl import WclInfo from com.raytheon.edex.plugin.gfe.watch import WclInfo
import JUtil import JUtil
lines = JUtil.pyValToJavaObj(self._lines) lines = JUtil.pyValToJavaObj(self._lines)
warning = WclInfo(long(self._issueTime * 1000), warning = WclInfo(long(self._issueTime * 1000),

View file

@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2 Bundle-ManifestVersion: 2
Bundle-Name: Activetable Plug-in Bundle-Name: Activetable Plug-in
Bundle-SymbolicName: com.raytheon.uf.common.activetable Bundle-SymbolicName: com.raytheon.uf.common.activetable
Bundle-Version: 1.12.1174.qualifier Bundle-Version: 1.14.0.qualifier
Bundle-Vendor: RAYTHEON Bundle-Vendor: RAYTHEON
Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Eclipse-RegisterBuddy: com.raytheon.uf.common.serialization Eclipse-RegisterBuddy: com.raytheon.uf.common.serialization
@ -12,8 +12,7 @@ Import-Package: com.raytheon.uf.common.dataplugin.annotations,
com.raytheon.uf.common.serialization.comm, com.raytheon.uf.common.serialization.comm,
com.vividsolutions.jts.geom, com.vividsolutions.jts.geom,
javax.persistence, javax.persistence,
org.hibernate.annotations, org.hibernate.annotations
org.springframework.beans.factory.annotation
Export-Package: com.raytheon.uf.common.activetable, Export-Package: com.raytheon.uf.common.activetable,
com.raytheon.uf.common.activetable.request, com.raytheon.uf.common.activetable.request,
com.raytheon.uf.common.activetable.response com.raytheon.uf.common.activetable.response
@ -22,4 +21,5 @@ Require-Bundle: com.raytheon.uf.common.serialization,
com.raytheon.uf.common.localization;bundle-version="1.12.1174", com.raytheon.uf.common.localization;bundle-version="1.12.1174",
com.raytheon.uf.common.python;bundle-version="1.12.1174", com.raytheon.uf.common.python;bundle-version="1.12.1174",
org.jep;bundle-version="1.0.0", org.jep;bundle-version="1.0.0",
com.raytheon.uf.common.util;bundle-version="1.12.1174" com.raytheon.uf.common.util;bundle-version="1.12.1174",
com.raytheon.uf.common.status

View file

@ -21,7 +21,11 @@ package com.raytheon.uf.common.activetable;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -34,6 +38,8 @@ import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType;
import com.raytheon.uf.common.localization.PathManagerFactory; import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.python.PyUtil; import com.raytheon.uf.common.python.PyUtil;
import com.raytheon.uf.common.python.PythonScript; import com.raytheon.uf.common.python.PythonScript;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
/** /**
* This wraps the VTECPartners.py file, loading it as a Map<String, Object> in * This wraps the VTECPartners.py file, loading it as a Map<String, Object> in
@ -46,7 +52,9 @@ import com.raytheon.uf.common.python.PythonScript;
* SOFTWARE HISTORY * SOFTWARE HISTORY
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Jul 8, 2010 wldougher Initial creation * Jul 08, 2010 wldougher Initial creation
* May 15, 2010 #3157 dgilling Add convenience methods for retrieving
* TPC and SPC sites.
* *
* </pre> * </pre>
* *
@ -58,6 +66,9 @@ public class VTECPartners {
private static final String CONFIG_PATH = "config" + File.separator + "gfe"; private static final String CONFIG_PATH = "config" + File.separator + "gfe";
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(VTECPartners.class);
private static Map<String, VTECPartners> instanceMap; private static Map<String, VTECPartners> instanceMap;
private Map<String, Object> simpleObjects; private Map<String, Object> simpleObjects;
@ -187,4 +198,49 @@ public class VTECPartners {
} }
return obj; return obj;
} }
public Collection<String> getSpcSites() {
return getSpcSites(null);
}
public Collection<String> getSpcSites(String defaultSite) {
return getSupportedIssuingSites("VTEC_SPC_SITE", defaultSite);
}
public Collection<String> getTpcSites() {
return getTpcSites(null);
}
public Collection<String> getTpcSites(String defaultSite) {
return getSupportedIssuingSites("VTEC_TPC_SITE", defaultSite);
}
protected Collection<String> getSupportedIssuingSites(String settingName,
String defaultValue) {
Object pyObject = getattr(settingName, defaultValue);
if (pyObject == null) {
String msg = String
.format("VTECPartners setting [%s] not configured. Check your localVTECPartners settings.",
settingName);
statusHandler.warn(msg);
} else if (pyObject instanceof String) {
String singleSite = (String) pyObject;
return new HashSet<String>(Arrays.asList(singleSite));
} else if (pyObject instanceof Collection) {
Collection<?> siteList = (Collection<?>) pyObject;
Collection<String> retVal = new HashSet<String>(siteList.size(), 1f);
for (Object siteObj : siteList) {
retVal.add(siteObj.toString());
}
return retVal;
} else {
String msg = String
.format("Unsupported value for setting [%s]: %s. Check your localVTECPartners settings.",
pyObject.toString(), settingName);
statusHandler.warn(msg);
}
return Collections.emptySet();
}
} }

View file

@ -83,6 +83,8 @@ import com.raytheon.uf.edex.database.query.DatabaseQuery;
* Mar 06, 2014 2883 randerso Pass siteId into python code * Mar 06, 2014 2883 randerso Pass siteId into python code
* Apr 10, 2014 3004 dgilling Remove ActiveTableMode parameter from * Apr 10, 2014 3004 dgilling Remove ActiveTableMode parameter from
* clearPracticeTable(). * clearPracticeTable().
* May 15, 2014 3157 dgilling Add support for multiple TPC and SPC
* issuing sites.
* *
* </pre> * </pre>
* *
@ -199,12 +201,8 @@ public class ActiveTable {
List<String> wfoList = (List<String>) vtecPartners List<String> wfoList = (List<String>) vtecPartners
.getattr("VTEC_DECODER_SITES"); .getattr("VTEC_DECODER_SITES");
wfoSet.addAll(wfoList); wfoSet.addAll(wfoList);
String spcSite = (String) vtecPartners wfoSet.addAll(vtecPartners.getSpcSites());
.getattr("VTEC_SPC_SITE"); wfoSet.addAll(vtecPartners.getTpcSites());
wfoSet.add(spcSite);
String tpcSite = (String) vtecPartners
.getattr("VTEC_TPC_SITE");
wfoSet.add(tpcSite);
} }
wfoSet.add(siteId); wfoSet.add(siteId);
wfos = wfoSet.toArray(new String[0]); wfos = wfoSet.toArray(new String[0]);

View file

@ -28,6 +28,7 @@
# 06/11/13 #2083 randerso Log active table changes, save backups # 06/11/13 #2083 randerso Log active table changes, save backups
# 03/06/14 #2883 randerso Pass siteId into mergeFromJava # 03/06/14 #2883 randerso Pass siteId into mergeFromJava
# 03/25/14 #2884 randerso Added xxxid to VTECChange # 03/25/14 #2884 randerso Added xxxid to VTECChange
# 05/15/14 #3157 dgilling Support multiple TPC and SPC sites.
# #
import time import time
@ -35,10 +36,12 @@ import copy
import os import os
import VTECTableUtil, VTECTableSqueeze, VTECPartners import VTECTableUtil, VTECTableSqueeze, VTECPartners
import LogStream, ActiveTableVtec, ActiveTableRecord import LogStream, ActiveTableVtec, ActiveTableRecord
import JUtil
from java.util import ArrayList from java.util import ArrayList
from com.raytheon.uf.common.localization import PathManagerFactory from com.raytheon.uf.common.localization import PathManagerFactory
from com.raytheon.uf.common.localization import LocalizationContext_LocalizationType as LocalizationType from com.raytheon.uf.common.localization import LocalizationContext_LocalizationType as LocalizationType
from com.raytheon.uf.common.localization import LocalizationContext_LocalizationLevel as LocalizationLevel from com.raytheon.uf.common.localization import LocalizationContext_LocalizationLevel as LocalizationLevel
from com.raytheon.uf.common.activetable import VTECPartners as JavaVTECPartners
class ActiveTable(VTECTableUtil.VTECTableUtil): class ActiveTable(VTECTableUtil.VTECTableUtil):
@ -257,8 +260,10 @@ def mergeFromJava(siteId, activeTable, newRecords, logger, mode, offsetSecs=0):
decoderSites = VTECPartners.VTEC_DECODER_SITES decoderSites = VTECPartners.VTEC_DECODER_SITES
decoderSites.append(VTECPartners.get4ID(siteId)) decoderSites.append(VTECPartners.get4ID(siteId))
decoderSites.append(VTECPartners.VTEC_SPC_SITE) spcSites = JUtil.javaObjToPyVal(JavaVTECPartners.getInstance(siteId).getSpcSites())
decoderSites.append(VTECPartners.VTEC_TPC_SITE) decoderSites.extend(spcSites)
tpcSites = JUtil.javaObjToPyVal(JavaVTECPartners.getInstance(siteId).getTpcSites())
decoderSites.extend(tpcSites)
backup = False backup = False
pyNew = [] pyNew = []

View file

@ -34,6 +34,7 @@
# 06/11/13 #2083 randerso Move backups to edex_static # 06/11/13 #2083 randerso Move backups to edex_static
# 01/24/14 #2504 randerso change to use iscUtil.getLogger for consistency # 01/24/14 #2504 randerso change to use iscUtil.getLogger for consistency
# 03/25/14 #2884 randerso Added xxxid to VTECChange # 03/25/14 #2884 randerso Added xxxid to VTECChange
# 05/15/14 #3157 dgilling Support multiple TPC and SPC sites.
# #
@ -49,6 +50,7 @@ import siteConfig
import VTECPartners import VTECPartners
import VTECTableSqueeze import VTECTableSqueeze
import VTECTableUtil import VTECTableUtil
import JUtil
from java.util import ArrayList from java.util import ArrayList
from com.raytheon.uf.common.activetable import MergeResult from com.raytheon.uf.common.activetable import MergeResult
@ -56,6 +58,7 @@ from com.raytheon.uf.common.activetable import VTECChange
from com.raytheon.uf.common.localization import PathManagerFactory from com.raytheon.uf.common.localization import PathManagerFactory
from com.raytheon.uf.common.localization import LocalizationContext_LocalizationType as LocalizationType from com.raytheon.uf.common.localization import LocalizationContext_LocalizationType as LocalizationType
from com.raytheon.uf.common.site import SiteMap from com.raytheon.uf.common.site import SiteMap
from com.raytheon.uf.common.activetable import VTECPartners as JavaVTECPartners
class MergeVTEC(VTECTableUtil.VTECTableUtil): class MergeVTEC(VTECTableUtil.VTECTableUtil):
@ -90,8 +93,8 @@ class MergeVTEC(VTECTableUtil.VTECTableUtil):
VTECTableUtil.VTECTableUtil.__init__(self, fileName) VTECTableUtil.VTECTableUtil.__init__(self, fileName)
# get the SPC site id from the configuration file # get the SPC site id from the configuration file
self._spcSite = getattr(VTECPartners, "VTEC_SPC_SITE", "KWNS") self._spcSite = JUtil.javaObjToPyVal(JavaVTECPartners.getInstance(siteConfig.GFESUITE_SITEID).getSpcSites("KWNS"))
self._tpcSite = getattr(VTECPartners, "VTEC_TPC_SITE", "KNHC") self._tpcSite = JUtil.javaObjToPyVal(JavaVTECPartners.getInstance(siteConfig.GFESUITE_SITEID).getTpcSites("KNHC"))
# get our site # get our site
siteid = siteConfig.GFESUITE_SITEID siteid = siteConfig.GFESUITE_SITEID
@ -393,8 +396,8 @@ class MergeVTEC(VTECTableUtil.VTECTableUtil):
sites = getattr(VTECPartners, "VTEC_MERGE_SITES", []) sites = getattr(VTECPartners, "VTEC_MERGE_SITES", [])
if sites is None: if sites is None:
return None return None
sites.append(self._spcSite) sites.extend(self._spcSite)
sites.append(self._tpcSite) sites.extend(self._tpcSite)
sites.append(self._ourSite) sites.append(self._ourSite)
self._log.debug("Filter Sites: %s", sites) self._log.debug("Filter Sites: %s", sites)
return sites return sites

View file

@ -37,8 +37,8 @@
VTEC_TABLE_REQUEST_SITES = [] VTEC_TABLE_REQUEST_SITES = []
# Name of site identifier for SPC and TCV bulletins. 4-characters. # Name of site identifier for SPC and TCV bulletins. 4-characters.
VTEC_SPC_SITE = 'KWNS' VTEC_SPC_SITE = ['KWNS']
VTEC_TPC_SITE = 'KNHC' VTEC_TPC_SITE = ['KNHC']
# The following list is a set of office identifiers which is used # The following list is a set of office identifiers which is used
# in the ingestAT/MergeVTEC software to filter out records from offices # in the ingestAT/MergeVTEC software to filter out records from offices

View file

@ -27,7 +27,8 @@
# Date Ticket# Engineer Description # Date Ticket# Engineer Description
# ------------ ---------- ----------- -------------------------- # ------------ ---------- ----------- --------------------------
# 02/06/13 1447 dgilling Initial Creation. # 02/06/13 1447 dgilling Initial Creation.
# 01/24/14 2504 randerso change to use iscUtil.getLogger for consistency # 01/24/14 2504 randerso change to use iscUtil.getLogger for consistency
# 05/15/14 #3157 dgilling Support multiple TPC and SPC sites.
# #
# #
@ -42,10 +43,12 @@ import IrtAccess
import siteConfig import siteConfig
import VTECPartners import VTECPartners
import iscUtil import iscUtil
import JUtil
from com.raytheon.uf.common.activetable import ActiveTableMode from com.raytheon.uf.common.activetable import ActiveTableMode
from com.raytheon.uf.common.time.util import TimeUtil from com.raytheon.uf.common.time.util import TimeUtil
from com.raytheon.uf.edex.activetable import ActiveTable from com.raytheon.uf.edex.activetable import ActiveTable
from com.raytheon.uf.common.activetable import VTECPartners as JavaVTECPartners
@ -73,8 +76,11 @@ def execute_request_at(serverHost, serverPort, serverProtocol, mhsid, siteID, an
mysite4 = "PAFC" mysite4 = "PAFC"
else: else:
mysite4 = "K" + siteID mysite4 = "K" + siteID
otherSites = [mysite4, VTECPartners.VTEC_SPC_SITE, otherSites = [mysite4]
VTECPartners.VTEC_TPC_SITE] tpcSites = JUtil.javaObjToPyVal(JavaVTECPartners.getInstance(siteID).getTpcSites())
spcSites = JUtil.javaObjToPyVal(JavaVTECPartners.getInstance(siteID).getSpcSites())
otherSites.extend(tpcSites)
otherSites.extend(spcSites)
# determine the MHS WMO id for this message # determine the MHS WMO id for this message
wmoid = "TTAA00 " + mysite4 wmoid = "TTAA00 " + mysite4

View file

@ -27,7 +27,8 @@
# Date Ticket# Engineer Description # Date Ticket# Engineer Description
# ------------ ---------- ----------- -------------------------- # ------------ ---------- ----------- --------------------------
# 02/08/13 1447 dgilling Initial Creation. # 02/08/13 1447 dgilling Initial Creation.
# 01/24/14 2504 randerso change to use iscUtil.getLogger for consistency # 01/24/14 2504 randerso change to use iscUtil.getLogger for consistency
# 05/15/14 #3157 dgilling Support multiple TPC and SPC sites.
# #
# #
@ -48,6 +49,9 @@ import VTECPartners
import VTECTableSqueeze import VTECTableSqueeze
import iscUtil import iscUtil
from com.raytheon.uf.common.activetable import VTECPartners as JavaVTECPartners
# Configuration Item for Test Purposes # Configuration Item for Test Purposes
FORCE_SEND = False #Set to True to always send even if no updates required. FORCE_SEND = False #Set to True to always send even if no updates required.
@ -88,10 +92,12 @@ def execute_send_at(myServerHost, myServerPort, myServerProtocol,
filtTable = [] filtTable = []
# filter by sites listing # filter by sites listing
if filterSites: if filterSites:
tpcSites = JUtil.javaObjToPyVal(JavaVTECPartners.getInstance(myServerSite).getTpcSites())
spcSites = JUtil.javaObjToPyVal(JavaVTECPartners.getInstance(myServerSite).getSpcSites())
for t in table: for t in table:
if t['oid'] in filterSites or t['oid'][1:4] in sites or \ if t['oid'] in filterSites or t['oid'][1:4] in sites or \
t['oid'] == VTECPartners.VTEC_SPC_SITE or \ t['oid'] in tpcSites or t['oid'] in spcSites:
t['oid'] == VTECPartners.VTEC_TPC_SITE:
filtTable.append(t) filtTable.append(t)
else: else:
filtTable = table #no filtering filtTable = table #no filtering