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  
22  package org.miloss.fgsms.sla.rules;
23  
24  import java.util.ArrayList;
25  import java.util.GregorianCalendar;
26  import java.util.List;
27  import java.util.concurrent.atomic.AtomicReference;
28  import javax.xml.datatype.DatatypeConfigurationException;
29  import javax.xml.datatype.DatatypeFactory;
30  import java.util.Calendar;
31  import org.miloss.fgsms.common.DBSettingsLoader;
32  import org.miloss.fgsms.common.Utility;
33  import org.miloss.fgsms.plugins.sla.AlertType;
34  import org.miloss.fgsms.plugins.sla.SLARuleInterface;
35  import org.miloss.fgsms.services.interfaces.common.MachinePerformanceData;
36  import org.miloss.fgsms.services.interfaces.common.NameValuePair;
37  import org.miloss.fgsms.services.interfaces.common.PolicyType;
38  import org.miloss.fgsms.services.interfaces.common.ProcessPerformanceData;
39  import org.miloss.fgsms.services.interfaces.datacollector.AddDataRequestMsg;
40  import org.miloss.fgsms.services.interfaces.datacollector.BrokerData;
41  import org.miloss.fgsms.services.interfaces.policyconfiguration.KeyNameValueEnc;
42  import org.miloss.fgsms.services.interfaces.policyconfiguration.ServicePolicy;
43  import org.miloss.fgsms.services.interfaces.status.SetStatusRequestMsg;
44  import org.miloss.fgsms.sla.NonTransactionalSLAProcessor;
45  import org.miloss.fgsms.sla.SLACommon;
46  
47  /**
48   * This rule is triggered when data becomes stale. I.e. an agent stopped
49   * responding or functioning, a server went offline. This behaves different
50   * depending on what the policy type of the item is Transactional Web
51   * Service:with bueller or health check enabled, triggered when bueller or
52   * health check fails and stops running Statistical Message Broker, triggered
53   * when the machine goes offine (Qpid Py only), all others, when the agent is no
54   * longer configured to access the component or if the agent stops
55   * Process/Machine, triggered when the machine goes offline or the agent is
56   * stopped
57   *
58   * @author AO
59   */
60  public class StaleData implements SLARuleInterface {
61  
62      @Override
63      public boolean CheckTransactionalRule(SetStatusRequestMsg req, List<NameValuePair> params, AtomicReference<String> nullableFaultMsg) {
64          return false;
65      }
66  
67      @Override
68      public boolean CheckTransactionalRule(ProcessPerformanceData req, List<NameValuePair> params, AtomicReference<String> nullableFaultMsg) {
69          return false;
70      }
71  
72      @Override
73      public boolean CheckTransactionalRule(MachinePerformanceData req, List<NameValuePair> params, AtomicReference<String> nullableFaultMsg) {
74          return false;
75      }
76  
77      @Override
78      public boolean CheckTransactionalRule(AddDataRequestMsg req, List<NameValuePair> params, AtomicReference<String> nullableFaultMsg) {
79          return false;
80      }
81  
82      @Override
83      public boolean CheckTransactionalRule(String url, List<BrokerData> data, List<NameValuePair> params, AtomicReference<String> nullableFaultMsg) {
84          return false;
85      }
86  
87      @Override
88      public boolean CheckNonTransactionalRule(ServicePolicy pol, List<NameValuePair> params, AtomicReference<String> nullableFaultMsg, boolean pooled) {
89  
90          if (nullableFaultMsg == null) {
91              nullableFaultMsg = new AtomicReference<String>();
92          }
93          StringBuilder faultMsg = new StringBuilder();
94          NameValuePair val = Utility.getNameValuePairByName(params, "value");
95          long threshold = 0;
96          if (val != null) {
97              if (val.isEncrypted()) {
98                  threshold = Long.parseLong(Utility.DE(val.getValue()));
99              } else {
100                 threshold = Long.parseLong(val.getValue());
101             }
102         } else {
103             KeyNameValueEnc GetPropertiesFromDB = DBSettingsLoader.GetPropertiesFromDB(pooled, "NTSLAProcessor", "StaleDataThreshold");
104             if (GetPropertiesFromDB != null && GetPropertiesFromDB.getKeyNameValue() != null && GetPropertiesFromDB.getKeyNameValue().getPropertyValue() != null) {
105                 try {
106                     if (GetPropertiesFromDB.isShouldEncrypt()) {
107                         threshold = Long.parseLong(Utility.DE(GetPropertiesFromDB.getKeyNameValue().getPropertyValue()));
108                     } else {
109                         threshold = Long.parseLong(GetPropertiesFromDB.getKeyNameValue().getPropertyValue());
110                     }
111                 } catch (Exception x) {
112                 }
113             }
114         }
115         if (threshold < 1) {
116             threshold = 300000; //default of 5 minutes
117         }
118 
119         long NTSLAInterval = 300000;
120         KeyNameValueEnc GetPropertiesFromDB = DBSettingsLoader.GetPropertiesFromDB(pooled, "NTSLAProcessor", "Interval");
121         if (GetPropertiesFromDB != null && GetPropertiesFromDB.getKeyNameValue() != null && GetPropertiesFromDB.getKeyNameValue().getPropertyValue() != null) {
122             try {
123                 NTSLAInterval = Long.parseLong(GetPropertiesFromDB.getKeyNameValue().getPropertyValue());
124             } catch (Exception x) {
125             }
126         }
127         //find the oldest status record
128         AtomicReference<Boolean> status = new AtomicReference<Boolean>(false);
129         long laststatusat = NonTransactionalSLAProcessor.GetLastKnownStatus(pol.getURL(), pooled, status);
130         if (System.currentTimeMillis() - laststatusat > threshold) {
131 
132             if ((System.currentTimeMillis() - NTSLAInterval) > threshold) {
133                 //TODO this is wrong
134                 //no need to process alerts if the delta is greater than the threshold + NTSLA runner (assuming NTSLA runner is 100% uptime)
135                 //this means that the alert was previously processed, skip it to prevent mail bombs
136                 return false;
137             }
138             DatatypeFactory df;
139             try {
140                 df = DatatypeFactory.newInstance();
141                 GregorianCalendar gcal = new GregorianCalendar();
142                 gcal.setTimeInMillis(laststatusat);
143                 Calendar xcal = gcal;
144                 faultMsg.append(SLACommon.getBundleString("ConsideredStale")).append(" ").append(xcal.toString()).append(" which was ").append(Utility.durationToString(df.newDuration(System.currentTimeMillis() - laststatusat))).append(" ago.");
145             } catch (Exception ex) {
146                 java.util.logging.Logger.getLogger(NonTransactionalSLAProcessor.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
147                 faultMsg.append(SLACommon.getBundleString("ConsideredStale")).append(" ").append(laststatusat).append("ms (Epoch) ago.");
148             }
149 
150             nullableFaultMsg.set(faultMsg.toString() + ", " + nullableFaultMsg.get());
151             return true;
152         }
153         return false;
154     }
155 
156     @Override
157     public String GetDisplayName() {
158         return "Stale Data";
159     }
160 
161     @Override
162     public String GetHtmlFormattedHelp() {
163         return "The Stale Data rule is used to help alert people that there is either a problem with an agent, or a problem with the computer hosting the agent."
164                 + "This typically triggers when a time threshold is reached when no data has been received by the agent. The threshold is administrator"
165                 + "controlled via General Settings. Applies to all policy types. If the administator has not defined the default value, 300000 (5 minutes) is used.<br><br>"
166                 + "Optional Parameter:"
167                 + "<ul>"
168                 + "<li>value - overrides the administrator defined default (time in ms)</li>"
169                 + "</ul>";
170     }
171 
172     @Override
173     public List<NameValuePair> GetRequiredParameters() {
174         return new ArrayList<NameValuePair>();
175     }
176 
177     @Override
178     public List<NameValuePair> GetOptionalParameters() {
179         List<NameValuePair> arrayList = new ArrayList<NameValuePair>();
180         arrayList.add(Utility.newNameValuePair("value", null, false, false));
181         return arrayList;
182     }
183 
184     @Override
185     public boolean ValidateConfiguration(List<NameValuePair> params, AtomicReference<String> outError, ServicePolicy sp) {
186         return true;
187     }
188 
189     @Override
190     public AlertType GetType() {
191         return AlertType.Status;
192     }
193 
194     @Override
195     public String GetHtmlFormattedDisplay(List<NameValuePair> params) {
196         NameValuePair mc = Utility.getNameValuePairByName(params, "value");
197         String item = UNDEFINED_VALUE;
198         if (mc != null) {
199             item = mc.getValue();
200             if (mc.isEncrypted() || mc.isEncryptOnSave()) {
201                 item = ENCRYPTED_MASK;
202             }
203         }
204         if (item == null) {
205             KeyNameValueEnc GetPropertiesFromDB = DBSettingsLoader.GetPropertiesFromDB(true, "NTSLAProcessor", "Interval");
206             if (GetPropertiesFromDB != null) {
207                 if (GetPropertiesFromDB.isShouldEncrypt()) {
208                     item = ENCRYPTED_MASK;
209                 } else {
210                     item = GetPropertiesFromDB.getKeyNameValue().getPropertyValue();
211                 }
212             }
213         }
214         if (Utility.stringIsNullOrEmpty(item)) {
215             item = "300000";
216         }
217         return GetDisplayName() + " older than " + Utility.encodeHTML(item) + " ms";
218     }
219     
220            @Override
221     public List<PolicyType> GetAppliesTo() {
222         return Utility.getAllPolicyTypes();
223     }
224 }