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.net.URLEncoder;
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.concurrent.atomic.AtomicReference;
28  import javax.jms.*;
29  import javax.naming.Context;
30  import org.apache.log4j.Level;
31  import org.miloss.fgsms.common.Logger;;
32  import org.apache.qpid.client.AMQConnection;
33  import org.miloss.fgsms.common.DBSettingsLoader;
34  import org.miloss.fgsms.common.SLAUtils;
35  import org.miloss.fgsms.common.Utility;
36  import org.miloss.fgsms.plugins.sla.AlertContainer;
37  import org.miloss.fgsms.plugins.sla.SLAActionInterface;
38  import org.miloss.fgsms.services.interfaces.common.NameValuePair;
39  import org.miloss.fgsms.services.interfaces.common.PolicyType;
40  import org.miloss.fgsms.services.interfaces.policyconfiguration.KeyNameValueEnc;
41  import org.miloss.fgsms.sla.SLACommon;
42  
43  /**
44   * Uses the Qpid AMQP client library to publish alerts
45   *
46   * @author AO
47   * @since 5.0, major refactor since 6.3
48   */
49  public class AMQPAlerter implements SLAActionInterface {
50  
51      private static final String KEY = "AMQPAlerts";
52      static final Logger log = Logger.getLogger("fgsms.AMQPAlerting");
53      private static boolean isconfigured = false;
54      private static boolean Topic = true;    //if false, queue
55      private static String ConnectionURL = "";
56      private static String Destination = "";
57      private static String INITIAL_CONTEXT_FACTORY = "";
58      private static String username = "";
59      private static String encryptedpassword = "";
60      private static long LastConfigRefresh = 0;
61      private static String keystore = "";
62      private static String keystorepass = "";
63      private static String truststore = "";
64      private static String truststorepass = "";
65  
66      /**
67       * sends an alert using the AMQP APIs (not JMS) Calls
68       * ProcessActionRet(alert)
69       */
70     // @Override
71      public void ProcessAction(AlertContainer alert) {
72          ProcessActionRet(alert);
73      }
74  
75      /**
76       * Returns true if the message was delivered successfully
77       *
78       * @param alert
79       * @return
80       */
81      public boolean ProcessActionRet(AlertContainer alert) {
82  
83          boolean pooled = alert.isPooled();
84          String XmlMessage = SLAUtils.WSDMtoXmlString((SLAUtils.createWSDMEvent(alert)));
85          NameValuePair nvpdestinationOverride = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "destinationOverride");
86          NameValuePair nvpisTopicOverride = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "isTopicOverride");
87          NameValuePair nvpConnectionURL = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "ConnectionURL");
88          NameValuePair nvpusername = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "username");
89          NameValuePair nvppassword = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "password");
90          String destinationOverride = null;
91          boolean isTopicOverride = false;
92          String url = null;
93          String uname = null;
94          String pwd = null;
95          if (nvpdestinationOverride != null) {
96              if (nvpdestinationOverride.isEncrypted()) {
97                  destinationOverride = Utility.DE(nvpdestinationOverride.getValue());
98              } else {
99                  destinationOverride = (nvpdestinationOverride.getValue());
100             }
101         }
102         if (nvpisTopicOverride != null) {
103             if (nvpisTopicOverride.isEncrypted()) {
104                 isTopicOverride = Boolean.parseBoolean(Utility.DE(nvpdestinationOverride.getValue()));
105             } else {
106                 isTopicOverride = Boolean.parseBoolean(nvpdestinationOverride.getValue());
107             }
108         }
109         if (nvpConnectionURL != null) {
110             if (nvpConnectionURL.isEncrypted()) {
111                 url = (Utility.DE(nvpConnectionURL.getValue()));
112             } else {
113                 url = (nvpConnectionURL.getValue());
114             }
115         }
116         if (nvpusername != null) {
117             if (nvpusername.isEncrypted()) {
118                 uname = (Utility.DE(nvpusername.getValue()));
119             } else {
120                 uname = (nvpusername.getValue());
121             }
122         }
123         if (nvppassword != null) {
124             if (nvppassword.isEncrypted()) {
125                 pwd = (Utility.DE(nvppassword.getValue()));
126             } else {
127                 pwd = (nvppassword.getValue());
128             }
129         }
130 
131 
132 
133 
134 
135         if (!isconfigured) {
136             Configure(pooled);
137             LastConfigRefresh = System.currentTimeMillis();
138         }
139         if (!isconfigured) {
140             log.log(Level.ERROR, SLACommon.getBundleString("ErrorAMQPConfig"));
141             return false;
142         }
143         if ((System.currentTimeMillis() - 5 * 60 * 1000) > LastConfigRefresh) {
144             log.log(Level.INFO, SLACommon.getBundleString("ErrorAMQPRefresh"));
145             Configure(pooled);
146             LastConfigRefresh = System.currentTimeMillis();
147         }
148         Context ic = null;
149 
150         if (url == null) {
151             url = ConnectionURL;
152         }
153         int parametercount = GetParameterCount(url);
154 
155         String tmp = System.getProperty("jboss.server.config.url");
156         if (Utility.stringIsNullOrEmpty(tmp)) {
157             //FIX for Jboss 7
158             try {
159                 tmp = System.getProperty("jboss.server.config.dir");
160                 File f = new File(tmp);
161                 tmp = f.toURI().toURL().toString();
162                 tmp += File.separator;
163             } catch (Exception e) {
164                 log.log(Level.DEBUG, null, e);
165             }
166         }
167         //fix for OpenJDK/linux issues
168         tmp = File.separator + tmp;
169 
170         if (uname == null) {
171             uname = username;
172         }
173         if (pwd == null) {
174             pwd = Utility.DE(encryptedpassword);
175         }
176         //username/password only
177         if (parametercount == 2) {
178             url = String.format(url, uname, URLEncoder.encode(pwd));
179         }
180         //username/password with SSL
181         if (parametercount == 4) {
182             url = String.format(url, uname, URLEncoder.encode(pwd), tmp + truststore, URLEncoder.encode(Utility.DE(truststorepass)));
183         }
184         //username/password with SSL
185         if (parametercount == 6) {
186             url = String.format(url, uname, URLEncoder.encode(pwd), tmp + truststore, URLEncoder.encode(Utility.DE(truststorepass)), tmp + keystore, URLEncoder.encode(Utility.DE(keystorepass)));
187         }
188         boolean ok = false;
189         AMQConnection con = null;
190         try {
191             boolean topic_ = Topic;
192             String use = Destination;
193             if (!Utility.stringIsNullOrEmpty(destinationOverride)) {
194                 use = destinationOverride;
195                 topic_ = isTopicOverride;
196             }
197             //amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'
198 
199             con = new AMQConnection(url);
200             Session s = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
201 
202             if (topic_) {
203                 Topic topic = s.createTopic(use);
204                 MessageProducer pub = s.createProducer(topic);
205                 javax.jms.TextMessage msg = s.createTextMessage(XmlMessage);
206                 pub.send(msg);
207                 log.log(Level.INFO, String.format(SLACommon.getBundleString("AMQPSuccessTopic"), topic.getTopicName(), use));
208             } else {
209                 Queue topic = s.createQueue(use);
210                 MessageProducer pub = s.createProducer(topic);
211                 javax.jms.TextMessage msg = s.createTextMessage(XmlMessage);
212                 pub.send(msg);
213                 log.log(Level.INFO, String.format(SLACommon.getBundleString("AMQPSuccessQueue"), topic.getQueueName(), use));
214             }
215             ok = true;
216 
217         } catch (Exception ex) {
218             log.log(Level.WARN, SLACommon.getBundleString("AMQPFailure"), ex);
219         } finally {
220             if (ic != null) {
221                 try {
222                     ic.close();
223                 } catch (Exception e) {
224                     log.log(Level.DEBUG, SLACommon.getBundleString("ErrorClosingResource"), e);
225                 }
226             }
227             if (con != null) {
228                 try {
229                     con.close();
230                 } catch (JMSException ex) {
231                     log.log(Level.DEBUG, SLACommon.getBundleString("ErrorClosingResource"), ex);
232                 }
233             }
234         }
235         return ok;
236     }
237 
238     private static void Configure(boolean pooled) {
239         boolean ok = true;
240         KeyNameValueEnc p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "ConnectionURL");
241         if (p != null && p.getKeyNameValue() != null) {
242             ConnectionURL = p.getKeyNameValue().getPropertyValue();
243         }
244         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "DestinationType");
245         if (p != null && p.getKeyNameValue() != null) {
246             String t = p.getKeyNameValue().getPropertyValue();
247             if (!Utility.stringIsNullOrEmpty(t)) {
248                 Topic = t.equalsIgnoreCase("topic");
249             }
250         }
251         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "Destination");
252         if (p != null && p.getKeyNameValue() != null) {
253             Destination = p.getKeyNameValue().getPropertyValue();
254         }
255 
256 
257         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "INITIAL_CONTEXT_FACTORY");
258         if (p != null && p.getKeyNameValue() != null) {
259             INITIAL_CONTEXT_FACTORY = p.getKeyNameValue().getPropertyValue();
260         }
261 
262 
263         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "username");
264         if (p != null && p.getKeyNameValue() != null) {
265             username = p.getKeyNameValue().getPropertyValue();
266         } else {
267             username = null;
268         }
269         p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "password");
270         if (p != null && p.getKeyNameValue() != null) {
271             encryptedpassword = p.getKeyNameValue().getPropertyValue();
272         } else {
273             encryptedpassword = null;
274         }
275 
276 
277         p = DBSettingsLoader.GetPropertiesFromDB(pooled, "defaults", "truststorepass");
278         if (p != null && p.getKeyNameValue() != null) {
279             truststorepass = p.getKeyNameValue().getPropertyValue();
280         } else {
281             truststorepass = null;
282         }
283         p = DBSettingsLoader.GetPropertiesFromDB(pooled, "defaults", "truststore");
284         if (p != null && p.getKeyNameValue() != null) {
285             truststore = p.getKeyNameValue().getPropertyValue();
286         } else {
287             truststore = null;
288         }
289 
290         p = DBSettingsLoader.GetPropertiesFromDB(pooled, "defaults", "keystore");
291         if (p != null && p.getKeyNameValue() != null) {
292             keystore = p.getKeyNameValue().getPropertyValue();
293         } else {
294             keystore = null;
295         }
296         p = DBSettingsLoader.GetPropertiesFromDB(pooled, "defaults", "keystorepass");
297         if (p != null && p.getKeyNameValue() != null) {
298             keystorepass = p.getKeyNameValue().getPropertyValue();
299         } else {
300             keystorepass = null;
301         }
302 
303 //validate config
304 
305         if (Utility.stringIsNullOrEmpty(Destination)) {
306             ok = false;
307         }
308         if (Utility.stringIsNullOrEmpty(ConnectionURL)) {
309             ok = false;
310         }
311         if (ok) {
312             isconfigured = true;
313         } else {
314             isconfigured = false;
315         }
316     }
317 
318     private static int GetParameterCount(String ConnectionURL) {
319         int count = 0;
320         int idx = 0;
321         while (idx < ConnectionURL.length()) {
322             int indexOf = ConnectionURL.indexOf("%s", idx);
323             if (indexOf == -1) {
324                 return count;
325             }
326             count++;
327             idx = indexOf + 1;
328         }
329         return count;
330     }
331 
332     @Override
333     public List<NameValuePair> GetRequiredParameters() {
334         List<NameValuePair> r = new ArrayList<NameValuePair>();
335         return r;
336     }
337 
338     @Override
339     public List<NameValuePair> GetOptionalParameters() {
340         List<NameValuePair> r = new ArrayList<NameValuePair>();
341         r.add(Utility.newNameValuePair("destinationOverride", null, false, false));
342         r.add(Utility.newNameValuePair("isTopicOverride", null, false, false));
343         r.add(Utility.newNameValuePair("ConnectionURL", null, false, false));
344         //r.add(Utility.newNameValuePair("DestinationType", null, false, false));
345         //r.add(Utility.newNameValuePair("Destination", null, false, false));
346         //r.add(Utility.newNameValuePair("INITIAL_CONTEXT_FACTORY", null, false, false));
347         r.add(Utility.newNameValuePair("username", null, false, false));
348         r.add(Utility.newNameValuePair("password", null, false, true));
349         return r;
350     }
351 
352     @Override
353     public boolean ValidateConfiguration(List<NameValuePair> params, AtomicReference<String> outError) {
354         if (outError == null) {
355             outError = new AtomicReference<String>();
356         }
357         Configure(true);
358         if (isconfigured) {
359             return true;
360         } else {
361             outError.set("The administrator hasn't configured the default settings yet using General Settings. AMQP Alerts won't be available until then." + outError.get());
362             return false;
363         }
364         //TODO this could use some more validation
365     }
366 
367     @Override
368     public String GetHtmlFormattedHelp() {
369         return "Sends a WSDM Alert via AMQP<br>This will send a WSDM formatted XML message that corresponds to the type of rule that was triggered."
370                 + "Most settings are configured via the <b>General Settings</b> page, however they can be overridden using optional parameters."
371                 + "<ul>"
372                 + "<li>destinationOverride - delivers alerts to a different topic/queue other than the administrator defined one.</li>"
373                 + "<li>isTopicOverride - true/false, set to true when the destinationOverride is a topic, otherwise false. </li>"
374                 + "<li>ConnectionURL - delivers alerts to a different AMQP server or URL other than the administrator defined one. Uses the same formatting rules as in <b>General Settings</b> (%s for credentials and key stores)</li>"
375                 + "<li>username - use a different username other than the administrator defined one</li>"
376                 + "<li>password - user a different password other than the administrator defined one. This should be encrypted</li>";
377     }
378 
379     @Override
380     public String GetDisplayName() {
381         return "Apache Qpid/Redhat MRG Alert";
382     }
383 
384     @Override
385     public void ProcessAction(AlertContainer alert, List<NameValuePair> params) {
386            ProcessActionRet(alert);
387     }
388 
389     @Override
390     public List<PolicyType> GetAppliesTo() {
391         return Utility.getAllPolicyTypes();
392     }
393 }