View Javadoc

1   /*
2    * $HeadURL: $
3    * $Date: $
4    * $Revision: $
5    * $Author: $
6    * 
7    * Copyright (c) 2005 MindTree Consulting Ltd. 
8    * 
9    * This file is part of Insight.
10   * 
11   * Insight is free software: you can redistribute it and/or modify it under the 
12   * terms of the GNU General Public License as published by the Free Software 
13   * Foundation, either version 3 of the License, or (at your option) any later 
14   * version.
15   * 
16   * Insight is distributed in the hope that it will be useful, but 
17   * WITHOUT ANY WARRANTY; without even the implied warranty of 
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General 
19   * Public License for more details.
20   * 
21   * You should have received a copy of the GNU General Public License along with 
22   * Insight.  If not, see <http://www.gnu.org/licenses/>.
23   */
24  
25  package com.mindtree.techworks.insight.eventsearch;
26  
27  import java.util.ArrayList;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.regex.Matcher;
31  import java.util.regex.Pattern;
32  import java.util.regex.PatternSyntaxException;
33  
34  import com.mindtree.techworks.insight.InsightConstants;
35  import com.mindtree.techworks.insight.gui.EventDetailsPresentation;
36  import com.mindtree.techworks.insight.gui.Insight;
37  import com.mindtree.techworks.insight.gui.widgets.StatusBar;
38  import com.mindtree.techworks.insight.model.ILogEventModelMutator;
39  import com.mindtree.techworks.insight.model.IMutatorListener;
40  import com.mindtree.techworks.insight.model.LogEventModel;
41  import com.mindtree.techworks.insight.pagination.IPage;
42  import com.mindtree.techworks.insight.pagination.PageSet;
43  import com.mindtree.techworks.insight.spi.LogEvent;
44  
45  
46  /**
47   * Provides the Event Search functionality to Insight, based on the search
48   * criteria selected by the user.
49   * 
50   * @see com.mindtree.techworks.insight.gui.action.SearchAction SearchAction
51   * @see com.mindtree.techworks.insight.gui.search.SearchEventsFrame SearchEventsFrame
52   * @author Bindul Bhowmik
53   * @version $Revision: 27 $ $Date: 2007-12-16 04:58:03 -0700 (Sun, 16 Dec 2007) $
54   */
55  public class EventSearchProvider extends Thread implements
56  		ILogEventModelMutator {
57  
58  	//
59  	// Instance variables
60  	//
61  
62  	/**
63  	 * Whether to indicate the progress of the search in the status bar.
64  	 */
65  	private boolean indicateProgress = true;
66  
67  	/**
68  	 * Holds a reference to the current instance of <code>Insight</code>
69  	 */
70  	private Insight insightInstance;
71  
72  	/**
73  	 * The EventDetailsPresentation whose contents will be searched
74  	 */
75  	private EventDetailsPresentation eventDetailsPresentation;
76  
77  	/**
78  	 * The instance of status bar to notify to
79  	 */
80  	private StatusBar statusBar;
81  
82  	/**
83  	 * Flag to indicate whether to stop the search
84  	 */
85  	private boolean stopSearch = false;
86  
87  	/**
88  	 * Counts the number of matches
89  	 */
90  	private long matchCount = 0;
91  
92  	/**
93  	 * Holds a reference to the current search criteria.
94  	 */
95  	private SearchCriteria searchCriteria;
96  
97  	/**
98  	 * Stores the current search pattern
99  	 */
100 	private Pattern searchPattern;
101 
102 	/**
103 	 * Stores the matcher for the search string.
104 	 */
105 	private Matcher searchMatcher;
106 
107 	/**
108 	 * Listeners of this mutating operation
109 	 */
110 	private List mutatorListeners = new ArrayList();
111 
112 	//
113 	// Search Criteria type indicators
114 	//
115 	/**
116 	 * Indicates to search in the thread field
117 	 */
118 	private boolean searchThread = false;
119 
120 	/**
121 	 * Indicates to search in the category field
122 	 */
123 	private boolean searchCategory = false;
124 
125 	/**
126 	 * Indicates to search in the message field
127 	 */
128 	private boolean searchMessage = false;
129 
130 	/**
131 	 * Indicates to search in the exception class name field
132 	 */
133 	private boolean searchExceptionClassName = false;
134 
135 	/**
136 	 * Indicates to search in the throwable stack trace
137 	 */
138 	private boolean searchThrowable = false;
139 
140 	/**
141 	 * Indicates to search in priority field
142 	 */
143 	private boolean searchPriority = false;
144 
145 	/**
146 	 * Indicates to search in the namespace string representation
147 	 */
148 	private boolean searchNamespace = false;
149 
150 	//
151 	// Constructor
152 	//
153 
154 	/**
155 	 * Constructor for the class.
156 	 * 
157 	 * @param insightInstance The current instance of <code>Insight</code>.
158 	 * @param indicateProgress Whether to indicate the progress of the search in
159 	 *            the status bar.
160 	 * @param eventDetailsPresentation The event details presentation used for
161 	 *            highlighting
162 	 */
163 	public EventSearchProvider (Insight insightInstance,
164 			boolean indicateProgress,
165 			EventDetailsPresentation eventDetailsPresentation) {
166 
167 		this.insightInstance = insightInstance;
168 		this.eventDetailsPresentation = eventDetailsPresentation;
169 		this.indicateProgress = indicateProgress;
170 		statusBar = StatusBar.getInstance();
171 		this.addMutatorListener(insightInstance.getController());
172 		
173 	  	// explicitly set the priority to normal. Otherwise
174 	  	// this thread will inherit the priority of the creator thread
175 	  	// i.e the AWT event dispatch thread that runs with max priority
176 		this.setPriority(Thread.NORM_PRIORITY);		
177 	}
178 
179 	//
180 	// Public Methods
181 	//
182 
183 	/**
184 	 * Searches the passed pageSet for the search criteria
185 	 * 
186 	 * @param currentSearchCriteria The {@link SearchCriteria SearchCriteria}
187 	 *            object containing the data to search.
188 	 */
189 	public void searchLogEvents (SearchCriteria currentSearchCriteria) {
190 
191 		// Set the search criteria
192 		this.searchCriteria = currentSearchCriteria;
193 		try {
194 			searchPattern = Pattern.compile(searchCriteria.getSearchString(),
195 					Pattern.CASE_INSENSITIVE | Pattern.DOTALL
196 							| Pattern.MULTILINE | Pattern.CANON_EQ
197 							| Pattern.UNICODE_CASE);
198 		} catch (PatternSyntaxException e) {
199 			statusBar.setDisplayText(0, InsightConstants
200 					.getLiteral("ERROR_INVALID_REGEX_PATTERN"), false);
201 			return;
202 		}
203 
204 		// Set the type of search
205 		int type = searchCriteria.getSearchType();
206 		if ((type & SearchCriteria.MESSAGE_SEARCH) == SearchCriteria.MESSAGE_SEARCH) {
207 			searchMessage = true;
208 		}
209 
210 		if ((type & SearchCriteria.CATEGORY_SEARCH) == SearchCriteria.CATEGORY_SEARCH) {
211 			searchCategory = true;
212 		}
213 
214 		if ((type & SearchCriteria.EXCEPTION_CLASS_NAME_SEARCH) == SearchCriteria.EXCEPTION_CLASS_NAME_SEARCH) {
215 			searchExceptionClassName = true;
216 		}
217 
218 		if ((type & SearchCriteria.THREAD_SEARCH) == SearchCriteria.THREAD_SEARCH) {
219 			searchThread = true;
220 		}
221 
222 		if ((type & SearchCriteria.THROWABLE_SEARCH) == SearchCriteria.THROWABLE_SEARCH) {
223 			searchThrowable = true;
224 		}
225 
226 		if ((type & SearchCriteria.PRIORITY_SEARCH) == SearchCriteria.PRIORITY_SEARCH) {
227 			searchPriority = true;
228 		}
229 
230 		if ((type & SearchCriteria.NAMESPACE_SEARCH) == SearchCriteria.NAMESPACE_SEARCH) {
231 			searchNamespace = true;
232 		}
233 
234 		this.start();
235 	}
236 
237 	//
238 	// Methods from Runnable
239 	//
240 
241 	/**
242 	 * @see java.lang.Runnable#run()
243 	 */
244 	public void run () {
245 
246 		// Get the current model.
247 		LogEventModel logEventModel = insightInstance.getController()
248 				.getCurrentLogEventModel();
249 		if (null == logEventModel) {
250 			statusBar.setDisplayText(0, InsightConstants
251 					.getLiteral("ERROR_NO_MODEL_LOADED"), false);
252 		} else {
253 
254 			// Notify all listeners
255 			for (Iterator mutatorListenerItr = mutatorListeners.iterator(); mutatorListenerItr
256 					.hasNext();) {
257 				((IMutatorListener) mutatorListenerItr.next()).startMutating(ILogEventModelMutator.NON_TAILING_MUTATOR);
258 			}
259 
260 			boolean firstPageProcessed = false;
261 
262 			// Get the Page Set
263 			PageSet pageSet = logEventModel.getPageSet();
264 			Iterator pageSetIterator = pageSet.getPageSetIterator();
265 
266 			// Create the search result object and set it in the log event model
267 			SearchResults searchResults = new SearchResults(insightInstance
268 					.getController(), searchCriteria,
269 					this.eventDetailsPresentation);
270 			logEventModel.setSearchResults(searchResults);
271 
272 			if (indicateProgress) {
273 				statusBar.setDisplayText(1, InsightConstants
274 						.getLiteral("SEARCHING")
275 						+ this.searchCriteria.getSearchString(), true);
276 			}
277 
278 			// Process each page
279 			long pageNum = 1;
280 			long runningSerial = 0;
281 			while (pageSetIterator.hasNext() && !stopSearch) {
282 				IPage currentPage = (IPage) pageSetIterator.next();
283 				List logEvents = currentPage.getLogEventList();
284 
285 				// Search each log event
286 
287 				for (Iterator logEventsIterator = logEvents.iterator(); logEventsIterator
288 						.hasNext();) {
289 					LogEvent logEvent = (LogEvent) logEventsIterator.next();
290 					runningSerial++ ;
291 					boolean matchFound = false;
292 
293 					if (searchCategory) {
294 						if (matchString(logEvent.getLoggerName()) == true) {
295 							matchFound = true;
296 						}
297 					}
298 
299 					if (searchExceptionClassName) {
300 						if (matchString(logEvent.getExceptionName()) == true) {
301 							matchFound = true;
302 						}
303 					}
304 
305 					if (searchMessage) {
306 						if (matchString(logEvent.getMessage().toString()) == true) {
307 							matchFound = true;
308 						}
309 					}
310 
311 					if (searchThread) {
312 						if (matchString(logEvent.getThreadName()) == true) {
313 							matchFound = true;
314 						}
315 					}
316 
317 					if (searchThrowable) {
318 						String [] throwableString = logEvent
319 								.getThrowableStrRep();
320 						for (int i = 0; i < throwableString.length; i++ ) {
321 							if (matchString(throwableString[i]) == true) {
322 								matchFound = true;
323 								break;
324 							}
325 						}
326 					}
327 
328 					if (searchPriority) {
329 						if (matchString(logEvent.getLevel().toString()) == true) {
330 							matchFound = true;
331 						}
332 					}
333 
334 					if (searchNamespace) {
335 						if (matchString(logEvent.getNamespace()
336 								.getNamespaceAsString()) == true) {
337 							matchFound = true;
338 						}
339 					}
340 
341 					// If a match if found, update status bar, add this to
342 					// cache.
343 					if (matchFound) {
344 						if (indicateProgress) {
345 							statusBar.setDisplayText(1, InsightConstants
346 									.getLiteral("SEARCHING")
347 									+ this.searchCriteria.getSearchString(),
348 									true);
349 						}
350 						searchResults.addMatcingLogEvent(new MatchingLogEvent(
351 								pageNum, runningSerial));
352 					}
353 				}
354 
355 				// If completed processing the first page, display that if
356 				// matches found
357 				if (!firstPageProcessed && matchCount > 0) {
358 					// Set the display to the first page
359 					searchResults.navigate(InsightConstants
360 							.getLiteral("FIRST_SEARCH_MATCH"));
361 					firstPageProcessed = true;
362 				}
363 
364 				// The following line may degrade performance!
365 				insightInstance.getController().setStatus();
366 
367 				// Go to the next page.
368 				pageNum++ ;
369 			}
370 
371 			// Clear the status bar progress
372 			statusBar.clearDisplay(1);
373 
374 			if (matchCount == 0) {
375 				if (indicateProgress) {
376 					statusBar.setDisplayText(0, InsightConstants
377 							.getLiteral("NO_MATCHES_FOUND"), false);
378 				}
379 			} else {
380 				if (indicateProgress) {
381 					statusBar.setDisplayText(0, InsightConstants
382 							.getLiteral("SEARCH_COMPLETE")
383 							+ searchResults.getCountOfMatchingLogEvents(),
384 							false);
385 				}
386 			}
387 
388 			// Notify all listeners
389 			for (Iterator mutatorListenerItr = mutatorListeners.iterator(); 
390 					mutatorListenerItr.hasNext();) {
391 				// The Event search provider returns a success message to all
392 				// mutator listeners, irrespective of the presence of any match.
393 				// This is because Event Search Provider is not strictly a
394 				// mutator, and not finding a search match is not actually a
395 				// failure.
396 				((IMutatorListener) mutatorListenerItr.next())
397 						.endMutating(ILogEventModelMutator.SUCCESS);
398 			}
399 		}
400 	}
401 
402 	/**
403 	 * Searches the string passed for the pattern.
404 	 * 
405 	 * @param stringToMatch String to match
406 	 * @return <code>true</code> if a match is found, else <code>false</code>.
407 	 */
408 	private boolean matchString (String stringToMatch) {
409 
410 		boolean matchFound = false;
411 		if (null == searchMatcher) {
412 			searchMatcher = searchPattern.matcher(stringToMatch);
413 		} else {
414 			searchMatcher.reset(stringToMatch);
415 		}
416 
417 		while (searchMatcher.find()) {
418 			matchFound = true;
419 			matchCount++ ;
420 		}
421 
422 		return matchFound;
423 	}
424 
425 	/**
426 	 * @see com.mindtree.techworks.insight.model.ILogEventModelMutator#addMutatorListener(com.mindtree.techworks.insight.model.IMutatorListener)
427 	 */
428 	public void addMutatorListener (IMutatorListener mutatorListener) {
429 
430 		mutatorListeners.add(mutatorListener);
431 
432 	}
433 
434 	/**
435 	 * @see com.mindtree.techworks.insight.model.ILogEventModelMutator#removeMutatorListener(com.mindtree.techworks.insight.model.IMutatorListener)
436 	 */
437 	public void removeMutatorListener (IMutatorListener mutatorListener) {
438 
439 		mutatorListeners.remove(mutatorListener);
440 
441 	}
442 
443 }