View Javadoc

1   /*******************************************************************************
2    * Copyright (c) 2007, 2014 Massimiliano Ziccardi
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *******************************************************************************/
16  package it.jnrpe.utils.thresholds;
17  
18  import it.jnrpe.utils.BadThresholdException;
19  
20  import java.io.IOException;
21  import java.io.PushbackReader;
22  import java.io.StringReader;
23  import java.math.BigDecimal;
24  
25  /**
26   * Utility class for evaluating thresholds. This class represent a Threshold
27   * specified using the old Nagios syntax.
28   * 
29   * @author Massimiliano Ziccardi
30   */
31  public class LegacyRange {
32  	/**
33  	 * When the current state is 'MINVAL', that means that the value we are
34  	 * parsing is the definition of the minimum value.
35  	 */
36  	private static final int MINVAL = 0;
37  
38  	/**
39  	 * When the current state is 'MAXVAL', that means that the value we are is
40  	 * the definition of the maximum value.
41  	 */
42  	private static final int MAXVAL = 1;
43  
44  	/**
45  	 * When the current state is 'END', that means that we have finished parsing
46  	 * the threshold definition.
47  	 */
48  	private static final int END = 99;
49  
50  	/**
51  	 * The mimimum value as parsed from the threshold definition.
52  	 */
53  	private BigDecimal minVal = null;
54  
55  	/**
56  	 * The maximum value as parsed from the threshold definition.
57  	 */
58  	private BigDecimal maxVal = null;
59  
60  	/**
61  	 * <code>true</code> if the threshold is negated.
62  	 */
63  	private boolean negateThreshold = false;
64  
65  	/**
66  	 * The current state of the threshold parser.
67  	 */
68  	private int curState = MINVAL;
69  
70  	/**
71  	 * The unparsed threshold string.
72  	 */
73  	private final String thresholdString;
74  
75  	/**
76  	 * Builds the object with the specified range.
77  	 * 
78  	 * @param threshold
79  	 *            The range
80  	 * @throws BadThresholdException
81  	 *             -
82  	 */
83  	public LegacyRange(final String threshold) throws BadThresholdException {
84  		thresholdString = threshold;
85  		parseRange();
86  	}
87  
88  	/**
89  	 * Parses the range definition to evaluate the minimum and maximum
90  	 * thresholds.
91  	 * 
92  	 * @throws BadThresholdException
93  	 *             -
94  	 */
95  	private void parseRange() throws BadThresholdException {
96  
97  		PushbackReader reader = new PushbackReader(new StringReader(
98  				thresholdString));
99  
100 		StringBuffer currentParsedBuffer = new StringBuffer();
101 
102 		byte b = 0;
103 
104 		try {
105 			while ((b = (byte) reader.read()) != -1) {
106 				currentParsedBuffer.append((char) b);
107 				if (b == '@') {
108 					if (curState != MINVAL) {
109 						throw new BadThresholdException(
110 								"Unparsable threshold '" + thresholdString
111 										+ "'. Error at char "
112 										+ currentParsedBuffer.length()
113 										+ ": the '@' should not be there.");
114 					}
115 					negateThreshold = true;
116 					continue;
117 				}
118 				if (b == ':') {
119 
120 					switch (curState) {
121 					case MINVAL:
122 						if (minVal == null) {
123 							minVal = new BigDecimal(0);
124 						}
125 						curState = MAXVAL;
126 						currentParsedBuffer = new StringBuffer();
127 						continue;
128 					case MAXVAL:
129 						throw new BadThresholdException(
130 								"Unparsable threshold '" + thresholdString
131 										+ "'. Error at char "
132 										+ currentParsedBuffer.length()
133 										+ ": the ':' should not be there.");
134 						// m_iCurState = END;
135 						// continue;
136 					default:
137 						curState = MAXVAL;
138 					}
139 				}
140 				if (b == '~') {
141 					switch (curState) {
142 					case MINVAL:
143 						minVal = new BigDecimal(Integer.MIN_VALUE);
144 						currentParsedBuffer = new StringBuffer();
145 						// m_iCurState = MAXVAL;
146 						continue;
147 					case MAXVAL:
148 						maxVal = new BigDecimal(Integer.MAX_VALUE);
149 						curState = END;
150 						currentParsedBuffer = new StringBuffer();
151 						continue;
152 					default:
153 					}
154 
155 				}
156 
157 				StringBuffer numberBuffer = new StringBuffer();
158 
159 				// while (i < vBytes.length &&
160 				// Character.isDigit((char)vBytes[i]))
161 
162 				do {
163 					numberBuffer.append((char) b);
164 				} while (((b = (byte) reader.read()) != -1)
165 						&& (Character.isDigit((char) b) || b == '+' || b == '-' || b == '.'));
166 
167 				if (b != -1) {
168 					reader.unread(b);
169 				}
170 
171 				String numberString = numberBuffer.toString();
172 				if (numberString.trim().length() == 0
173 						|| numberString.equals("+") || numberString.equals("-")) {
174 					throw new BadThresholdException(
175 							"A number was expected after '"
176 									+ currentParsedBuffer.toString()
177 									+ "', but an empty string was found");
178 				}
179 
180 				switch (curState) {
181 				case MINVAL:
182 					try {
183 						minVal = new BigDecimal(numberString.trim());
184 					} catch (NumberFormatException nfe) {
185 						throw new BadThresholdException(
186 								"Expected a number but found '" + numberString
187 										+ "' instead [" + thresholdString + "]");
188 					}
189 					currentParsedBuffer = new StringBuffer();
190 					continue;
191 				case MAXVAL:
192 					try {
193 						maxVal = new BigDecimal(numberString.trim());
194 					} catch (NumberFormatException nfe) {
195 						throw new BadThresholdException(
196 								"Expected a number but found '" + numberString
197 										+ "' instead");
198 					}
199 					currentParsedBuffer = new StringBuffer();
200 					continue;
201 				default:
202 					curState = END;
203 					currentParsedBuffer = new StringBuffer();
204 				}
205 				// if (i < vBytes.length)
206 				// i-=2;
207 			}
208 		} catch (IOException ioe) {
209 			// Intentionally empty...
210 		}
211 
212 		if (curState == MINVAL) {
213 			maxVal = minVal;
214 			minVal = new BigDecimal(0);
215 		}
216 
217 		if (curState == MAXVAL && maxVal == null
218 				&& thresholdString.startsWith(":")) {
219 			throw new BadThresholdException(
220 					"At least one of maximum or minimum "
221 							+ "value must me specified.");
222 		}
223 
224 	}
225 
226 	/**
227 	 * Returns <code>true</code> if the value falls inside the range.
228 	 * 
229 	 * @param value
230 	 *            The value
231 	 * @return <code>true</code> if the value falls inside the range.
232 	 *         <code>false</code> otherwise.
233 	 */
234 	public final boolean isValueInside(final BigDecimal value) {
235 		return isValueInside(value, null);
236 	}
237 
238 	/**
239 	 * Returns <code>true</code> if the value falls inside the range.
240 	 * 
241 	 * @param value
242 	 *            The value
243 	 * @param prefix
244 	 *            The prefix that identifies the multiplier
245 	 * @return <code>true</code> if the value falls inside the range.
246 	 *         <code>false</code> otherwise.
247 	 */
248 	public final boolean isValueInside(final BigDecimal value,
249 			final Prefixes prefix) {
250 		boolean bRes = true;
251 		// Sets the minimum value of the range
252 		if (minVal != null) {
253 			bRes = bRes && (value.compareTo(minVal) >= 0);
254 		}
255 		// Sets the maximum value of the range
256 		if (maxVal != null) {
257 			bRes = bRes && (value.compareTo(maxVal) <= 0);
258 		}
259 		if (negateThreshold) {
260 			return !bRes;
261 		}
262 		return bRes;
263 	}
264 
265 	/**
266 	 * Returns <code>true</code> if the value falls inside the range.
267 	 * 
268 	 * @param value
269 	 *            The value
270 	 * @return <code>true</code> if the value falls inside the range.
271 	 *         <code>false</code> otherwise.
272 	 */
273 	public final boolean isValueInside(final int value) {
274 		return isValueInside(new BigDecimal(value));
275 	}
276 
277 	/**
278 	 * Returns <code>true</code> if the value falls inside the range.
279 	 * 
280 	 * @param value
281 	 *            The value
282 	 * @return <code>true</code> if the value falls inside the range.
283 	 *         <code>false</code> otherwise.
284 	 */
285 	public final boolean isValueInside(final long value) {
286 		return isValueInside(new BigDecimal(value));
287 	}
288 
289 	/**
290 	 * @return The original unparsed threshold string.
291 	 */
292 	final String getThresholdString() {
293 		return thresholdString;
294 	}
295 }