View Javadoc
1   /**
2    * This Source Code Form is subject to the terms of the Mozilla Public
3    * License, v. 2.0. If a copy of the MPL was not distributed with this
4    * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5    *
6    * If it is not possible or desirable to put the notice in a particular
7    * file, then You may include the notice in a location (such as a LICENSE
8    * file in a relevant directory) where a recipient would be likely to look
9    * for such a notice.
10  
11   * 
12   */
13   
14  /*  ---------------------------------------------------------------------------
15   *  U.S. Government, Department of the Army
16   *  Army Materiel Command
17   *  Research Development Engineering Command
18   *  Communications Electronics Research Development and Engineering Center
19   *  ---------------------------------------------------------------------------
20   */
21  package org.miloss.fgsms.sla.actions;
22  
23  import java.io.File;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.concurrent.atomic.AtomicReference;
27  import javax.xml.ws.BindingProvider;
28  import org.apache.log4j.Level;
29  import org.miloss.fgsms.common.DBSettingsLoader;
30  import org.miloss.fgsms.common.Logger;
31  import org.miloss.fgsms.common.SLAUtils;
32  import org.miloss.fgsms.common.Utility;
33  import org.miloss.fgsms.plugins.sla.AlertContainer;
34  import org.miloss.fgsms.plugins.sla.SLAActionInterface;
35  import org.miloss.fgsms.services.interfaces.common.NameValuePair;
36  import org.miloss.fgsms.services.interfaces.common.PolicyType;
37  import org.miloss.fgsms.services.interfaces.policyconfiguration.KeyNameValueEnc;
38  import org.miloss.fgsms.sla.SLACommon;
39  import org.miloss.fgsms.wsn.WSNConstants;
40  import org.oasis_open.docs.wsn.b_2.NotificationMessageHolderType;
41  import org.oasis_open.docs.wsn.b_2.NotificationMessageHolderType.Message;
42  import org.oasis_open.docs.wsn.b_2.Notify;
43  import org.oasis_open.docs.wsn.b_2.TopicExpressionType;
44  import org.oasis_open.docs.wsn.br_2.RegisterPublisher;
45  import org.oasis_open.docs.wsn.br_2.RegisterPublisherResponse;
46  import org.oasis_open.docs.wsn.brw_2.NotificationBroker;
47  import org.oasis_open.docs.wsn.client.NotificationService;
48  
49  import org.w3c.dom.Element;
50  
51  /**
52   * Sends alerts via WS-Notification
53   *
54   * @author AO
55   * @since 6.0
56   */
57  public class WSNotificationAlerter implements SLAActionInterface {
58  
59      private static final String KEY = "WSNAlerts";
60      static final Logger log = Logger.getLogger("fgsms.WSNAlerting");
61      private static boolean isconfigured = false;
62      private static String configuredWSN_DIALECT = null;
63      private static String topic = null;
64      private static String username = "";
65      private static String encryptedpassword = "";
66      private static String brokerurl = "";
67      private static String keystore = "";
68      private static String keystorepass = "";
69      private static boolean isMainTopicRegistered = true;
70      private static String truststore = "";
71      private static String truststorepass = "";
72      private static NotificationBroker notificationPort = null;
73      //private static org.oasis_open.docs.wsn.brw_2.NotificationService ns = null;
74      private static long LastConfigRefresh = 0;
75  
76      public static void SendAlert(AlertContainer alert, Element xmlalert) {
77          boolean pooled = alert.isPooled();
78  
79          if (!isconfigured) {
80              Configure(pooled);
81              LastConfigRefresh = System.currentTimeMillis();
82          }
83          if (!isconfigured) {
84              log.log(org.apache.log4j.Level.ERROR, SLACommon.getBundleString("ErrorWSNNotConfigured"));
85              return;
86          }
87          if ((System.currentTimeMillis() - 5 * 60 * 1000) > LastConfigRefresh) {
88              log.log(Level.INFO, SLACommon.getBundleString("ErrorWSNRefresh"));
89              Configure(pooled);
90              LastConfigRefresh = System.currentTimeMillis();
91          }
92  
93          boolean RegisterPublisher = false;
94          String dialect = null;
95          String Destination = null;
96          String uname = null;
97          String pwd = null;
98          String BrokerURL = null;
99  
100         NameValuePair nvpRegisterPublisher = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "RegisterPublisher");
101         NameValuePair nvpBrokerURL = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "BrokerURL");
102         NameValuePair nvpdialect = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "dialect");
103         NameValuePair nvpDestination = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "Destination");
104         NameValuePair nvpusername = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "username");
105         NameValuePair nvppassword = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "password");
106         if (nvpRegisterPublisher != null) {
107             if (nvpRegisterPublisher.isEncrypted()) {
108                 RegisterPublisher = Boolean.parseBoolean(Utility.DE(nvpRegisterPublisher.getValue()));
109             } else {
110                 RegisterPublisher = Boolean.parseBoolean(nvpRegisterPublisher.getValue());
111             }
112         }
113 
114         if (nvpusername != null) {
115             if (nvpusername.isEncrypted()) {
116                 uname = Utility.DE(nvpusername.getValue());
117             } else {
118                 uname = (nvpusername.getValue());
119             }
120         }
121         if (nvppassword != null) {
122             if (nvppassword.isEncrypted()) {
123                 pwd = Utility.DE(nvppassword.getValue());
124             } else {
125                 pwd = (nvppassword.getValue());
126             }
127         }
128 
129 
130         if (nvpBrokerURL != null) {
131             if (nvpBrokerURL.isEncrypted()) {
132                 BrokerURL = Utility.DE(nvpBrokerURL.getValue());
133             } else {
134                 BrokerURL = (nvpBrokerURL.getValue());
135             }
136         }
137         if (nvpdialect != null) {
138             if (nvpdialect.isEncrypted()) {
139                 dialect = Utility.DE(nvpdialect.getValue());
140             } else {
141                 dialect = (nvpdialect.getValue());
142             }
143         }
144         if (nvpDestination != null) {
145             if (nvpDestination.isEncrypted()) {
146                 Destination = Utility.DE(nvpDestination.getValue());
147             } else {
148                 Destination = (nvpDestination.getValue());
149             }
150         }
151 
152         BindingProvider bp = (BindingProvider) notificationPort;
153         if (BrokerURL != null) {
154             bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, BrokerURL);
155         } else {
156             bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, brokerurl);
157         }
158 
159 
160         if (!Utility.stringIsNullOrEmpty(uname) && !Utility.stringIsNullOrEmpty(pwd)) {
161             bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, pwd);
162             bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, (uname));
163         } else {
164             if (!Utility.stringIsNullOrEmpty(username) && !Utility.stringIsNullOrEmpty(encryptedpassword)) {
165                 bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, (Utility.DE(encryptedpassword)));
166                 bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, (username));
167             }
168         }
169 
170 
171 
172         Notify notify = new Notify();
173         NotificationMessageHolderType msg = new NotificationMessageHolderType();
174 
175         TopicExpressionType tet = new TopicExpressionType();
176         if (Utility.stringIsNullOrEmpty(configuredWSN_DIALECT) && Utility.stringIsNullOrEmpty(dialect)) {
177             tet.setDialect(WSNConstants.WST_TOPICEXPRESSION_SIMPLE);
178         } else {
179             if (!Utility.stringIsNullOrEmpty(dialect)) {
180                 tet.setDialect(dialect);
181             } else {
182                 tet.setDialect(configuredWSN_DIALECT);
183             }
184         }
185         if (Utility.stringIsNullOrEmpty(Destination) && Utility.stringIsNullOrEmpty(topic)) {
186             tet.getContent().add("fgsmsAlerts");
187         } else if (!Utility.stringIsNullOrEmpty(Destination)) {
188             tet.getContent().add(Destination);
189         } else {
190             tet.getContent().add(topic);
191         }
192         if (RegisterPublisher) {
193             RegisterProducer((String) tet.getContent().get(0));
194         }
195         msg.setTopic((tet));
196         Message m = new Message();
197 
198         m.setAny(xmlalert);
199 
200         msg.setMessage(m);
201         notify.getNotificationMessage().add(msg);
202         try {
203 
204             notificationPort.notify(notify);
205 	    log.log(Level.INFO, "Alert delivered");
206         } catch (Exception ex) {
207             log.log(Level.WARN, SLACommon.getBundleString("ErrorWSNDelivery"), ex);
208         }
209     }
210 
211     private static void Configure(boolean pooled) {
212         boolean ok = true;
213         KeyNameValueEnc p = null;
214 
215         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "BrokerURL");
216         if (p != null && p.getKeyNameValue() != null) {
217             brokerurl = p.getKeyNameValue().getPropertyValue();
218         }
219 
220         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "username");
221         if (p != null && p.getKeyNameValue() != null) {
222             username =
223                     p.getKeyNameValue().getPropertyValue();
224         } else {
225             username = null;
226         }
227         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "password");
228         if (p != null && p.getKeyNameValue() != null) {
229             encryptedpassword =
230                     p.getKeyNameValue().getPropertyValue();
231         } else {
232             encryptedpassword =
233                     null;
234         }
235         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "dialect");
236         if (p != null && p.getKeyNameValue() != null) {
237             configuredWSN_DIALECT =
238                     p.getKeyNameValue().getPropertyValue();
239         } else {
240             configuredWSN_DIALECT = null;
241         }
242         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "Destination");
243         if (p != null && p.getKeyNameValue() != null) {
244             topic = p.getKeyNameValue().getPropertyValue();
245         } else {
246             topic = null;
247         }
248 
249 
250         p = DBSettingsLoader.GetPropertiesFromDB(pooled, "defaults", "truststore");
251         if (p != null && p.getKeyNameValue() != null) {
252             try {
253                 truststore = p.getKeyNameValue().getPropertyValue();
254             } catch (Exception ex) {
255             }
256         } else {
257             truststore = null;
258         }
259         p = DBSettingsLoader.GetPropertiesFromDB(pooled, "defaults", "truststorepass");
260         if (p != null && p.getKeyNameValue() != null) {
261             try {
262                 truststorepass = p.getKeyNameValue().getPropertyValue();
263             } catch (Exception ex) {
264             }
265         } else {
266             truststorepass = null;
267         }
268         boolean RegisterPublisher = false;
269         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "RegisterPublisher");
270         if (p != null && p.getKeyNameValue() != null) {
271             try {
272                 RegisterPublisher = Boolean.parseBoolean(p.getKeyNameValue().getPropertyValue());
273             } catch (Exception ex) {
274                 RegisterPublisher = false;
275             }
276         } else {
277             RegisterPublisher = false;
278         }
279 //validate config
280 
281         if (Utility.stringIsNullOrEmpty(brokerurl)) {
282             ok = false;
283         }
284         if (Utility.stringIsNullOrEmpty(topic)) {
285             ok = false;
286         }
287 
288         if (ok) {
289             String tmp = System.getProperty("jboss.server.config.url");
290             if (Utility.stringIsNullOrEmpty(tmp)) {
291                 //FIX for Jboss 7
292                 try {
293                     tmp = System.getProperty("jboss.server.config.dir");
294                     File f = new File(tmp);
295                     tmp = f.toURI().toURL().toString();
296                     tmp += File.separator;
297                 } catch (Exception e) {
298                 }
299             }
300             //fix for OpenJDK/linux issues
301             tmp = File.separator + tmp;
302             NotificationService svc = new NotificationService();
303             notificationPort = svc.getNotificationPort();
304             BindingProvider bp = (BindingProvider) notificationPort;
305             bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, brokerurl);
306             if (!Utility.stringIsNullOrEmpty(username) && !Utility.stringIsNullOrEmpty(encryptedpassword)) {
307                 bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, (Utility.DE(encryptedpassword)));
308                 bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, (username));
309             }
310             if (brokerurl.toLowerCase().startsWith(("https://"))) {
311                 if (!Utility.stringIsNullOrEmpty(truststorepass) && !Utility.stringIsNullOrEmpty(truststore)) {
312                     bp.getRequestContext().put("javax.net.ssl.trustStorePassword", Utility.DE(truststorepass));
313                     bp.getRequestContext().put("javax.net.ssl.trustStore", tmp + truststore);
314                 }
315                 if (!Utility.stringIsNullOrEmpty(keystorepass) && !Utility.stringIsNullOrEmpty(keystore)) {
316                     bp.getRequestContext().put("javax.net.ssl.keyStorePassword", Utility.DE(keystorepass));
317                     bp.getRequestContext().put("javax.net.ssl.keyStore", tmp + keystore);
318                 }
319             }
320             isconfigured = true;
321         } else {
322             isconfigured = false;
323         }
324 
325 
326         if (RegisterPublisher && !isMainTopicRegistered) {
327             RegisterProducer(topic);
328         }
329 
330     }
331 
332     private static void RegisterProducer(String t) {
333         try {
334             RegisterPublisher req = new RegisterPublisher();
335             TopicExpressionType localtopic = new TopicExpressionType();
336             if (Utility.stringIsNullOrEmpty(configuredWSN_DIALECT)) {
337                 localtopic.setDialect(WSNConstants.WST_TOPICEXPRESSION_SIMPLE);
338             } else {
339                 localtopic.setDialect(configuredWSN_DIALECT);
340             }
341             if (Utility.stringIsNullOrEmpty(t)) {
342                 localtopic.getContent().add("fgsmsAlerts");
343             } else {
344                 localtopic.getContent().add(t);
345             }
346             req.getTopic().add(localtopic);
347 
348             RegisterPublisherResponse registerPublisher =
349                     notificationPort.registerPublisher(req);
350             log.log(Level.INFO, String.format(SLACommon.getBundleString("WSNTopicRegisteredSuccess"), t));
351             isMainTopicRegistered = true;
352         } catch (Exception ex) {
353             log.log(Level.ERROR, String.format(SLACommon.getBundleString("WSNTopicRegisteredFailed"), t), ex);
354 
355         }
356     }
357 
358     /**
359      * Strips off the xml declaration
360      *
361      * @param xmlalert
362      * @return
363      */
364     public static String StripXmlHeader(String xmlalert) {
365         if (xmlalert.startsWith("<?xml")) {
366             int trimat = xmlalert.indexOf("?>", 0);
367             xmlalert = xmlalert.substring(trimat + 2);
368             log.log(Level.DEBUG, "XML header trimmed " + xmlalert);
369         }
370         return xmlalert;
371     }
372 
373     @Override
374     public List<NameValuePair> GetRequiredParameters() {
375         List<NameValuePair> r = new ArrayList<NameValuePair>();
376 
377         return r;
378     }
379 
380     @Override
381     public List<NameValuePair> GetOptionalParameters() {
382         List<NameValuePair> r = new ArrayList<NameValuePair>();
383         r.add(Utility.newNameValuePair("RegisterPublisher", null, false, false));
384         r.add(Utility.newNameValuePair("dialect", null, false, false));
385         r.add(Utility.newNameValuePair("Destination", null, false, false));
386         r.add(Utility.newNameValuePair("username", null, false, false));
387         r.add(Utility.newNameValuePair("password", null, false, true));
388         r.add(Utility.newNameValuePair("BrokerURL", null, false, false));
389         return r;
390     }
391 
392     @Override
393     public boolean ValidateConfiguration(List<NameValuePair> params, AtomicReference<String> outError) {
394         if (outError == null) {
395             outError = new AtomicReference<String>();
396         }
397         Configure(true);
398         if (isconfigured) {
399             return true;
400         } else {
401             outError.set("The administrator hasn't configured the default settings yet using General Settings. WSN Alerts won't be available until then." + outError.get());
402             return false;
403         }
404         //TODO validate true/false arguments
405     }
406 
407     @Override
408     public String GetHtmlFormattedHelp() {
409         return "Sends a WSDM formatted XML message to a WS-Notification message broker. Optional parameters:"
410                 + "<ul>"
411                 + "<li>RegisterPublisher - this will cause fgsms to register itself as a message publisher within the broker instance. Not all brokers support it. Valid values are true or false. Default is false.</li>"
412                 + "<li>dialect - Some brokers need a custom dialect. Use this to override to the default, which is " + WSNConstants.WST_TOPICEXPRESSION_SIMPLE + "</li>"
413                 + "<li>Destination - This is the name of the queue or topic that the messages are delivered to and that clients subscribe to</li>"
414                 + "<li>username -  for this instance only, overriding the administrator defined setting.</li>"
415                 + "<li>password -  for this instance only, overriding the administrator defined setting. This should be encrypted</li>"
416                 + "<li>BrokerURL - use this to change the URL of the broker for this instance only, overriding the administrator defined setting.</li>"
417                 + "</ul>";
418     }
419 
420     @Override
421     public String GetDisplayName() {
422         return "WS-Notification Alert";
423     }
424 
425     @Override
426     public void ProcessAction(AlertContainer alert, List<NameValuePair> params) {
427         WSNotificationAlerter.SendAlert(alert, SLAUtils.WSDMAlertToDomElement(SLAUtils.createWSDMEvent(alert)));
428     }
429 
430     @Override
431     public List<PolicyType> GetAppliesTo() {
432         return Utility.getAllPolicyTypes();
433     }
434 }