View Javadoc
1   /*
2    * To change this license header, choose License Headers in Project Properties.
3    * To change this template file, choose Tools | Templates
4    * and open the template in the editor.
5    */
6   package org.miloss.fgsms.sla.actions;
7   
8   import java.net.DatagramPacket;
9   import java.net.InetAddress;
10  import java.net.MulticastSocket;
11  import java.util.ArrayList;
12  import java.util.List;
13  import java.util.concurrent.atomic.AtomicReference;
14  import org.apache.log4j.Level;
15  import org.miloss.fgsms.common.Constants;
16  import org.miloss.fgsms.common.DBSettingsLoader;
17  import org.miloss.fgsms.common.Logger;
18  import org.miloss.fgsms.common.SLAUtils;
19  import org.miloss.fgsms.common.Utility;
20  import org.miloss.fgsms.plugins.sla.AlertContainer;
21  import org.miloss.fgsms.plugins.sla.SLAActionInterface;
22  import org.miloss.fgsms.services.interfaces.common.NameValuePair;
23  import org.miloss.fgsms.services.interfaces.common.PolicyType;
24  import org.miloss.fgsms.services.interfaces.policyconfiguration.KeyNameValueEnc;
25  
26  /**
27   * This is an super simple UDP Multicast alerting mechanism. It transmits an XML
28   * WSDN alert over the specified Multicast group and port.
29   *
30   * Because it sends XML formatted messages, it is not recommended to forward
31   * this particular multicast group over metered or low bandwidth networks.
32   *
33   * @author AO
34   */
35  public class SimpleMulticastAlerter implements SLAActionInterface {
36  
37      private static final String KEY = "MulticastAlerting";
38      static final Logger log = Logger.getLogger("fgsms.MulticastAlerting");
39      private static boolean isconfigured = false;
40      
41      private static String ConnectionURL = "";
42      
43      private static long LastConfigRefresh = 0;
44      
45  
46      /**
47       * Returns true if the message was delivered successfully
48       *
49       * @param alert
50       * @return
51       */
52      private boolean ProcessActionRet(AlertContainer alert) {
53  
54          boolean pooled = alert.isPooled();
55          String XmlMessage = SLAUtils.WSDMtoXmlString((SLAUtils.createWSDMEvent(alert)));
56          NameValuePair nvpConnectionURL = Utility.getNameValuePairByName(alert.getSlaActionBaseType().getParameterNameValue(), "ConnectionURL");
57          String url = null;
58          if (nvpConnectionURL != null) {
59              if (nvpConnectionURL.isEncrypted()) {
60                  url = (Utility.DE(nvpConnectionURL.getValue()));
61              } else {
62                  url = (nvpConnectionURL.getValue());
63              }
64          }
65  
66          if (!isconfigured) {
67              configure(pooled);
68              LastConfigRefresh = System.currentTimeMillis();
69          }
70          if (!isconfigured) {
71              log.log(Level.ERROR, "Not configured");
72              return false;
73          }
74          if ((System.currentTimeMillis() - 5 * 60 * 1000) > LastConfigRefresh) {
75              log.log(Level.INFO, "Config refreshed");
76              configure(pooled);
77              LastConfigRefresh = System.currentTimeMillis();
78          }
79  
80  
81          boolean ok = false;
82          MulticastSocket socket = null;
83          try {
84              //expecting udp://IP:PORT
85              String[] ipport = ConnectionURL.replace("udp://", "").split("\\:");
86              int port = Integer.parseInt(ipport[1]);
87              String ipaddress = ipport[0];
88              InetAddress group = InetAddress.getByName(ipaddress);
89  
90              byte[] buf = XmlMessage.getBytes(Constants.CHARSET);
91  
92              DatagramPacket packet;
93              packet = new DatagramPacket(buf, buf.length, group, port);
94              socket = new MulticastSocket(port);
95              socket.send(packet);
96              socket.close();
97          } catch (Exception ex) {
98              log.log(Level.WARN, "Failed to tx multicast alert", ex);
99  
100         } finally {
101             if (socket != null) {
102                 try {
103                     socket.close();
104                 } catch (Exception ex) {
105                     log.log(Level.DEBUG, null, ex);
106                 }
107             }
108         }
109         return ok;
110     }
111 
112     private static String configure(boolean pooled) {
113         String errors = null;
114         boolean ok = true;
115         KeyNameValueEnc p = DBSettingsLoader.GetPropertiesFromDB(pooled, KEY, "ConnectionURL");
116         if (p != null && p.getKeyNameValue() != null) {
117             ConnectionURL = p.getKeyNameValue().getPropertyValue();
118         }
119 
120         //validate config
121         if (Utility.stringIsNullOrEmpty(ConnectionURL)) {
122             ok = false;
123             errors += "ConnectionURL is invalid. ";
124         }
125         if (!ConnectionURL.startsWith("udp://")) {
126             ok = false;
127             errors += "ConnectionURL does not start with udp:/// ";
128         } else {
129             String[] ipport = ConnectionURL.replace("udp://", "").split("\\:");
130             if (ipport.length == 2) {
131                 try {
132                     int port = Integer.parseInt(ipport[1]);
133                     if (port <= 0 || port >= 65500) {
134                         errors += "Port is invalid";
135                         ok = false;
136                     }
137                 } catch (Exception ex) {
138                     errors += "Port is invalid";
139                     ok = false;
140                 }
141                 try {
142                     String ipaddress = ipport[0];
143                     InetAddress byName = InetAddress.getByName(ipaddress);
144                     if (!byName.isMulticastAddress()) {
145                         errors += "IP is not a multicast address";
146                         ok = false;
147                     }
148                 } catch (Exception ex) {
149                     errors += "IP is invalid";
150                     ok = false;
151                 }
152             }
153 
154         }
155 
156         if (ok) {
157             isconfigured = true;
158         } else {
159             isconfigured = false;
160         }
161         return errors;
162     }
163 
164     @Override
165     public List<NameValuePair> GetRequiredParameters() {
166         List<NameValuePair> r = new ArrayList<NameValuePair>();
167         return r;
168     }
169 
170     @Override
171     public List<NameValuePair> GetOptionalParameters() {
172         List<NameValuePair> r = new ArrayList<NameValuePair>();
173         r.add(Utility.newNameValuePair("ConnectionURL", null, false, false));
174 
175         return r;
176     }
177 
178     @Override
179     public boolean ValidateConfiguration(List<NameValuePair> params, AtomicReference<String> outError) {
180         if (outError == null) {
181             outError = new AtomicReference<String>();
182         }
183         String msg = configure(true);
184 
185         if (isconfigured) {
186             return true;
187         } else {
188             outError.set("The administrator hasn't configured the default settings yet using General Settings. Multicast Alerts won't be available until then." + outError.get() + msg);
189             return false;
190         }
191 
192     }
193 
194     @Override
195     public String GetHtmlFormattedHelp() {
196         return "Sends a WSDM Alert via UDP Multicast<br>This will send a WSDM formatted XML message that corresponds to the type of rule that was triggered."
197                 + "Most settings are configured via the <b>General Settings</b> page, however they can be overridden using optional parameters."
198                 + "<ul>"
199                 + "<li>ConnectionURL - delivers alerts to a different (IP:PORT) other than the administrator defined one."
200                 + "Example: udp://224.1.1.1:5000</li>"
201                 + "</ul>";
202     }
203 
204     @Override
205     public String GetDisplayName() {
206         return "Simple UDP Multicast Alert";
207     }
208 
209     @Override
210     public void ProcessAction(AlertContainer alert, List<NameValuePair> params) {
211         ProcessActionRet(alert);
212     }
213 
214     @Override
215     public List<PolicyType> GetAppliesTo() {
216         return Utility.getAllPolicyTypes();
217     }
218 }