use of org.opennms.netmgt.filter.api.FilterParseException in project opennms by OpenNMS.
the class JdbcFilterDao method getIPAddressList.
private List<InetAddress> getIPAddressList(final String rule, final boolean filterDeleted, final String address) throws FilterParseException {
final List<InetAddress> resultList = new ArrayList<>();
final boolean filterByAddress = address != null && address.length() > 0;
String sqlString;
LOG.debug("Filter.getIPAddressList({})", rule);
// get the database connection
Connection conn = null;
final DBUtils d = new DBUtils(getClass());
try {
// parse the rule and get the sql select statement
sqlString = getSQLStatement(rule);
if (filterDeleted) {
if (!sqlString.contains("isManaged")) {
sqlString += " AND (ipInterface.isManaged != 'D' or ipInterface.isManaged IS NULL)";
}
}
if (filterByAddress) {
sqlString += " AND ipInterface.ipaddr = ?";
}
conn = getDataSource().getConnection();
d.watch(conn);
LOG.debug("Filter.getIPAddressList({}): SQL statement: {}", rule, sqlString);
// execute query and return the list of ip addresses
final ResultSet rset;
if (filterByAddress) {
final PreparedStatement preparedStatement = conn.prepareStatement(sqlString);
preparedStatement.setString(1, address);
d.watch(preparedStatement);
rset = preparedStatement.executeQuery();
} else {
final Statement stmt = conn.createStatement();
d.watch(stmt);
rset = stmt.executeQuery(sqlString);
}
d.watch(rset);
// fill up the array list if the result set has values
if (rset != null) {
// Iterate through the result and build the array list
while (rset.next()) {
resultList.add(addr(rset.getString(1)));
}
}
} catch (final FilterParseException e) {
LOG.warn("Filter Parse Exception occurred getting IP List.", e);
throw new FilterParseException("Filter Parse Exception occurred getting IP List: " + e.getLocalizedMessage(), e);
} catch (final SQLException e) {
LOG.warn("SQL Exception occurred getting IP List.", e);
throw new FilterParseException("SQL Exception occurred getting IP List: " + e.getLocalizedMessage(), e);
} catch (final Throwable e) {
LOG.error("Exception getting database connection.", e);
throw new UndeclaredThrowableException(e);
} finally {
d.cleanUp();
}
LOG.debug("Filter.getIPAddressList({}): resultList = {}", rule, resultList);
return resultList;
}
use of org.opennms.netmgt.filter.api.FilterParseException in project opennms by OpenNMS.
the class JdbcFilterDao method parseRule.
/**
* SQL Key Word regex
*
* Binary Logic / Operators - \\s+(?:AND|OR|(?:NOT )?(?:LIKE|IN)|IS (?:NOT )?DISTINCT FROM)\\s+
* Unary Operators - \\s+IS (?:NOT )?NULL(?!\\w)
* Typecasts - ::(?:TIMESTAMP|INET)(?!\\w)
* Unary Logic - (?<!\\w)NOT\\s+
* Functions - (?<!\\w)IPLIKE(?=\\()
*/
/**
* Generic method to parse and translate a rule into SQL.
*
* Only columns listed in database-schema.xml may be used in a filter
* (explicit "table.column" specification is not supported in filters)
*
* To differentiate column names from SQL key words (operators, functions, typecasts, etc)
* SQL_KEYWORD_REGEX must match any SQL key words that may be used in filters,
* and must not match any column names or prefixed values
*
* To make filter syntax more simple and intuitive than SQL
* - Filters support some aliases for common SQL key words / operators
* "&" or "&&" = "AND"
* "|" or "||" = "OR"
* "!" = "NOT"
* "==" = "="
* - "IPLIKE" may be used as an operator instead of a function in filters ("ipAddr IPLIKE '*.*.*.*'")
* When using "IPLIKE" as an operator, the value does not have to be quoted ("ipAddr IPLIKE *.*.*.*" is ok)
* - Some common SQL expressions may be generated by adding a (lower-case) prefix to an unquoted value in the filter
* "isVALUE" = "serviceName = VALUE"
* "notisVALUE" = interface does not support the specified service
* "catincVALUE" = node is in the specified category
* - Double-quoted (") strings in filters are converted to single-quoted (') strings in SQL
* SQL treats single-quoted strings as constants (values) and double-quoted strings as identifiers (columns, tables, etc)
* So, all quoted strings in filters are treated as constants, and filters don't support quoted identifiers
*
* This function does not do complete syntax/grammar checking - that is left to the database itself - do not assume the output is valid SQL
*
* @param tables
* a list to be populated with any tables referenced by the returned SQL
* @param rule
* the rule to parse
*
* @return an SQL WHERE clause
*
* @throws FilterParseException
* if any errors occur during parsing
*/
private String parseRule(final List<Table> tables, final String rule) throws FilterParseException {
if (rule != null && rule.length() > 0) {
final List<String> extractedStrings = new ArrayList<>();
String sqlRule = rule;
// Extract quoted strings from rule and convert double-quoted strings to single-quoted strings
// Quoted strings need to be extracted first to avoid accidentally matching/modifying anything within them
// As in SQL, pairs of quotes within a quoted string are treated as an escaped quote character:
// 'a''b' = a'b ; "a""b" = a"b ; 'a"b' = a"b ; "a'b" = a'b
Matcher regex = SQL_QUOTE_PATTERN.matcher(sqlRule);
StringBuffer tempStringBuff = new StringBuffer();
while (regex.find()) {
final String tempString = regex.group();
if (tempString.charAt(0) == '"') {
extractedStrings.add("'" + tempString.substring(1, tempString.length() - 1).replaceAll("\"\"", "\"").replaceAll("'", "''") + "'");
} else {
extractedStrings.add(regex.group());
}
regex.appendReplacement(tempStringBuff, "###@" + (extractedStrings.size() - 1) + "@###");
}
final int tempIndex = tempStringBuff.length();
regex.appendTail(tempStringBuff);
if (tempStringBuff.substring(tempIndex).indexOf('\'') > -1) {
final String message = "Unmatched ' in filter rule '" + rule + "'";
LOG.error(message);
throw new FilterParseException(message);
}
if (tempStringBuff.substring(tempIndex).indexOf('"') > -1) {
final String message = "Unmatched \" in filter rule '" + rule + "'";
LOG.error(message);
throw new FilterParseException(message);
}
sqlRule = tempStringBuff.toString();
// Translate filter-specific operators to SQL operators
sqlRule = sqlRule.replaceAll("\\s*(?:&|&&)\\s*", " AND ");
sqlRule = sqlRule.replaceAll("\\s*(?:\\||\\|\\|)\\s*", " OR ");
sqlRule = sqlRule.replaceAll("\\s*!(?!=)\\s*", " NOT ");
sqlRule = sqlRule.replaceAll("==", "=");
// Translate IPLIKE operators to IPLIKE() functions
// If IPLIKE is already used as a function in the filter, this regex should not match it
regex = SQL_IPLIKE_PATTERN.matcher(sqlRule);
tempStringBuff = new StringBuffer();
while (regex.find()) {
// Is the second argument already a quoted string?
if (regex.group().charAt(0) == '#') {
regex.appendReplacement(tempStringBuff, "IPLIKE($1, $2)");
} else {
regex.appendReplacement(tempStringBuff, "IPLIKE($1, '$2')");
}
}
regex.appendTail(tempStringBuff);
sqlRule = tempStringBuff.toString();
// Extract SQL key words to avoid identifying them as columns or prefixed values
regex = SQL_KEYWORD_PATTERN.matcher(sqlRule);
tempStringBuff = new StringBuffer();
while (regex.find()) {
extractedStrings.add(regex.group().toUpperCase());
regex.appendReplacement(tempStringBuff, "###@" + (extractedStrings.size() - 1) + "@###");
}
regex.appendTail(tempStringBuff);
sqlRule = tempStringBuff.toString();
// Identify prefixed values and columns
regex = SQL_VALUE_COLUMN_PATTERN.matcher(sqlRule);
tempStringBuff = new StringBuffer();
while (regex.find()) {
// Convert prefixed values to SQL expressions
if (regex.group().startsWith("is")) {
regex.appendReplacement(tempStringBuff, m_databaseSchemaConfigFactory.addColumn(tables, "serviceName") + " = '" + regex.group().substring(2) + "'");
} else if (regex.group().startsWith("notis")) {
regex.appendReplacement(tempStringBuff, m_databaseSchemaConfigFactory.addColumn(tables, "ipAddr") + " NOT IN (SELECT ifServices.ipAddr FROM ifServices, service WHERE service.serviceName ='" + regex.group().substring(5) + "' AND service.serviceID = ifServices.serviceID)");
} else if (regex.group().startsWith("catinc")) {
regex.appendReplacement(tempStringBuff, m_databaseSchemaConfigFactory.addColumn(tables, "nodeID") + " IN (SELECT category_node.nodeID FROM category_node, categories WHERE categories.categoryID = category_node.categoryID AND categories.categoryName = '" + regex.group().substring(6) + "')");
} else if (regex.group().matches(SQL_IPLIKE6_RHS_REGEX)) {
// Do nothing, it's apparently an IPv6 IPLIKE expression right-hand side
} else {
// Call m_databaseSchemaConfigFactory.addColumn() on each column
regex.appendReplacement(tempStringBuff, m_databaseSchemaConfigFactory.addColumn(tables, regex.group()));
}
}
regex.appendTail(tempStringBuff);
sqlRule = tempStringBuff.toString();
// Merge extracted strings back into expression
regex = SQL_ESCAPED_PATTERN.matcher(sqlRule);
tempStringBuff = new StringBuffer();
while (regex.find()) {
regex.appendReplacement(tempStringBuff, Matcher.quoteReplacement(extractedStrings.get(Integer.parseInt(regex.group(1)))));
}
regex.appendTail(tempStringBuff);
sqlRule = tempStringBuff.toString();
return "WHERE " + sqlRule;
}
return "";
}
use of org.opennms.netmgt.filter.api.FilterParseException in project opennms by OpenNMS.
the class DataManager method afterPropertiesSet.
/**
* Constructor. Parses categories from the categories.xml and populates them
* with 'RTCNode' objects created from data read from the database (services
* and outage tables)
*
* @exception SQLException
* if there is an error reading initial data from the
* database
* @exception FilterParseException
* if a rule in the categories.xml was incorrect
* @exception RTCException
* if the initialization/data reading does not go through
* @throws org.xml.sax.SAXException if any.
* @throws java.io.IOException if any.
* @throws java.sql.SQLException if any.
* @throws org.opennms.netmgt.filter.api.FilterParseException if any.
* @throws org.opennms.netmgt.rtc.RTCException if any.
*/
@Override
public void afterPropertiesSet() throws Exception {
// read the categories.xml to get all the categories
m_categories = RTCUtils.createCategoriesMap();
if (m_categories == null || m_categories.isEmpty()) {
throw new RTCException("No categories found in categories.xml");
}
LOG.debug("Number of categories read: {}", m_categories.size());
// create data holder
m_map = new RTCHashMap(30000);
m_transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
// Populate the nodes initially from the database
try {
populateNodesFromDB(null, null);
} catch (FilterParseException e) {
throw new IllegalStateException("Cannot load RTC data from the database: " + e.getMessage(), e);
} catch (SQLException e) {
throw new IllegalStateException("Cannot load RTC data from the database: " + e.getMessage(), e);
} catch (RTCException e) {
throw new IllegalStateException("Cannot load RTC data from the database: " + e.getMessage(), e);
}
}
});
}
Aggregations