/*******************************************************************************
* ALMA - Atacama Large Millimeter Array
* Copyright (c) COSYLAB - Control System Laboratory, 2011
* (in the framework of the ALMA collaboration).
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*******************************************************************************/
/*
* Created on Jul 8, 2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package com.cosylab.logging.search;
import java.text.FieldPosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.cosylab.logging.engine.log.ILogEntry;
import com.cosylab.logging.engine.log.LogField;
import alma.acs.logging.table.LogEntryTable;
import alma.acs.logging.table.LogTableDataModel;
import alma.acs.util.IsoDateFormat;
/**
* @author acaproni
*
* Objects of this class search the logs for a string
* The method that activates the search is find (overloaded)
*/
public class SearchEngine {
/**
* The reference to the table data model
*/
private LogTableDataModel logTableDataModel;
/**
* The JTable of the logs
*/
private LogEntryTable logEntryTable;
/**
* The constructor
*
* @param ltdm The LogTableDataModel of the main window
*/
public SearchEngine(LogEntryTable let) {
this.logEntryTable=let;
this.logTableDataModel=let.getLCModel();
}
/**
* Search the logs for a string
*
* @param searchString The string to look for in the logs
* @param caseSensitive If true performs a CaseSensitive search
* @param wholeWord If true look for the whole word int the column
* @param forwardSearch If true search forward otherwise backward
* @param cols The columns of each log tool for the string
* @return -1 if no log is found otherwise the row containing the log
*/
public int find(
String searchString,
boolean caseSensitive,
boolean wholeWord,
boolean forwardSearch,
boolean[] cols) {
return find(null,searchString,caseSensitive,wholeWord,forwardSearch,cols);
}
/**
* Search the log for a regular expression
*
* @param regExp The regular expression to look for in the logs
* @param forwardSearch If true search forward otherwise backward
* @param cols The columns of each log tool for the string
* @return -1 if no log is found otherwise the row containing the log
*/
public int find (
Pattern regExp,
boolean forwardSearch,
boolean[] cols) {
return find(regExp,null,true,true,forwardSearch,cols);
}
/**
* The method executes the search for both the public overloaded
* find methods.
*
* @param regExp The regular expression to look for in the logs
* null if the method search for a string
* @param searchString The string to look for in the logs
* null if the method search for a reg exp
* @param caseSensitive If true performs a CaseSensitive search
* Ignored for reg exp searchs (it is coded
* in the Pattern)
* @param wholeWord If true look for the whole word int the column
* Ignored for reg exp searchs
* @param forwardSearch If true search forward otherwise backward
* @param cols The columns of each log tool for the string
* @return -1 if no log is found otherwise the row containing the string/reg exp
*/
private int find(
Pattern regExp,
String searchString,
boolean caseSensitive,
boolean wholeWord,
boolean forwardSearch,
boolean[] cols) {
// I want only one loop for both forward and backward searches
// For that I calculate the interval of valid rows to scan
// [a,b] where a<=b i.e. this interval is independedent from the
// direction of the search
// Then I use a cursor to navigate the rows, decreasing or
// increasing its value depending of the direction of the search
// Get the starting and the ending row for the search
int startingRow=getStartingRow(forwardSearch);
int endRow = (forwardSearch)?logEntryTable.getRowCount()-1:0;
// The position where the SimpleDate must be written
FieldPosition pos = new java.text.FieldPosition(0);
// A temporary buffer
StringBuffer tempSB = new StringBuffer();
// The variable used to browse the rows
int cursor = startingRow;
// Order end and start rown in growing order
if (endRow<startingRow) {
int temp=startingRow;
startingRow=endRow;
endRow=temp;
}
int foundRow=-1;
while (cursor>=startingRow && cursor<=endRow && foundRow==-1) {
// cols contains one entry for each field of a log entry
// plus one entry for the additional data
ILogEntry log = logTableDataModel.getVisibleLogEntry(logEntryTable.convertRowIndexToModel(cursor));
String string=null; // The value of the field
for (int t=0; t<cols.length-1; t++) {
Object obj = log.getField(LogField.values()[t]);
if (obj==null) {
continue;
}
if (cols[t]) {
switch (LogField.values()[t]) {
case TIMESTAMP: {
SimpleDateFormat df = new IsoDateFormat();
Date dt = new Date((Long)obj);
tempSB.delete(0,tempSB.length());
df.format(dt,tempSB,pos);
string=tempSB.toString();
break;
}
case ENTRYTYPE:
case LINE:
case PRIORITY:
case STACKLEVEL: {
string=obj.toString();
break;
}
default: {
string = obj.toString();
break;
}
}
if (matches(string,regExp,searchString,caseSensitive,wholeWord) ) {
if ((forwardSearch && cursor!=startingRow) || (!forwardSearch && cursor!=endRow)) {
foundRow=cursor;
if (forwardSearch) {
cursor++;
} else {
cursor--;
}
return foundRow;
}
}
}
}
// Look into the additional data: here we have to search for each key and value
// (we can't build a big striung with everything inside because it would fail
// searching for regular espressions
if (cols[cols.length-1] && log.hasDatas()) {
Vector<ILogEntry.AdditionalData> addData = log.getAdditionalData();
for (int t=0; t<addData.size(); t++) {
ILogEntry.AdditionalData data = addData.elementAt(t);
string = data.name;
if (matches(string,regExp,searchString,caseSensitive,wholeWord) ) {
if ((forwardSearch && cursor!=startingRow) || (!forwardSearch && cursor!=endRow)) {
foundRow=cursor;
if (forwardSearch) {
cursor++;
} else {
cursor--;
}
return foundRow;
}
}
string = data.value;
if (matches(string,regExp,searchString,caseSensitive,wholeWord) ) {
if ((forwardSearch && cursor!=startingRow) || (!forwardSearch && cursor!=endRow)) {
foundRow=cursor;
if (forwardSearch) {
cursor++;
} else {
cursor--;
}
return foundRow;
}
}
}
}
if (forwardSearch) {
cursor++;
} else {
cursor--;
}
}
return foundRow;
}
/**
* Check if the given object matches the search criteria
*
* @param obj The object to check (it should be a string or a way to convert
* the obj to a string must be known)
* @param regExp The regular expression to look for in the logs
* null if the method search for a string
* @param searchString The string to look for in the logs
* null if the method search for a reg exp
* @param caseSensitive If true performs a CaseSensitive search
* Ignored for reg exp searchs (it is coded
* in the Pattern)
* @param wholeWord If true look for the whole word int the column
* Ignored for reg exp searchs
* @return true if the object matches the serach criteria
*/
private boolean matches(Object obj,
Pattern regExp,
String searchString,
boolean caseSensitive,
boolean wholeWord) {
if (obj==null) {
return false;
}
// Convert the object to a String
String str;
try {
str = obj.toString();
} catch (Exception e) {
// This should never happen but...
System.err.println("Impossible to convert this object to a String: "+obj);
return false;
}
if (regExp==null) {
// Check the strings
if (wholeWord) {
if (caseSensitive) {
return str.compareTo(searchString)==0;
} else {
return str.compareToIgnoreCase(searchString)==0;
}
} else {
if (caseSensitive) {
return str.indexOf(searchString)!=-1;
} else {
String upperStr=str.toUpperCase();
String searchStrUpper=searchString.toUpperCase();
return upperStr.indexOf(searchStrUpper)!=-1;
}
}
} else {
// Check the regular expression
Matcher matcher = regExp.matcher(str);
return matcher.matches();
}
}
/**
* Get the starting row number for a search.
*
* @return The selected row in the table of the main window or
* the first/last row if no row is selected by the user
* (depending if the search is backward or forward)
*/
private int getStartingRow(boolean forward) {
int ret = logEntryTable.getSelectedRow();
if (ret==-1) {
if (forward) {
ret=0;
} else {
ret=logEntryTable.getRowCount()-1;
}
}
return ret;
}
}