blob: 3ba8a3e201899d040ca4d819d964a98e5d99d9cf [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.ranger.solr;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.apache.log4j.Logger;
import org.apache.ranger.common.MessageEnums;
import org.apache.ranger.common.PropertiesUtil;
import org.apache.ranger.common.RESTErrorUtil;
import org.apache.ranger.common.SearchCriteria;
import org.apache.ranger.common.SearchField;
import org.apache.ranger.common.SortField;
import org.apache.ranger.common.StringUtil;
import org.apache.ranger.common.SearchField.SEARCH_TYPE;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.client.solrj.SolrRequest.METHOD;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SolrUtil {
private static final Logger logger = Logger.getLogger(SolrUtil.class);
@Autowired
RESTErrorUtil restErrorUtil;
@Autowired
StringUtil stringUtil;
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss'Z'");
public SolrUtil() {
String timeZone = PropertiesUtil.getProperty("xa.solr.timezone");
if (timeZone != null) {
logger.info("Setting timezone to " + timeZone);
try {
dateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
} catch (Throwable t) {
logger.error("Error setting timezone. TimeZone = " + timeZone);
}
}
}
public QueryResponse runQuery(SolrClient solrClient, SolrQuery solrQuery) throws Throwable {
if (solrQuery != null) {
try {
QueryRequest req = new QueryRequest(solrQuery, METHOD.POST);
String username = PropertiesUtil.getProperty("ranger.solr.audit.user");
String password = PropertiesUtil.getProperty("ranger.solr.audit.user.password");
if (username != null && password != null) {
req.setBasicAuthCredentials(username, password);
}
return req.process(solrClient);
} catch (Throwable e) {
logger.error("Error from Solr server. ", e);
throw e;
}
}
return null;
}
public QueryResponse searchResources(SearchCriteria searchCriteria,
List<SearchField> searchFields, List<SortField> sortFieldList,
SolrClient solrClient) {
SolrQuery query = new SolrQuery();
query.setQuery("*:*");
if (searchCriteria.getParamList() != null) {
// For now assuming there is only date field where range query will
// be done. If we there are more than one, then we should create a
// hashmap for each field name
Date fromDate = null;
Date toDate = null;
String dateFieldName = null;
for (SearchField searchField : searchFields) {
Object paramValue = searchCriteria.getParamValue(searchField.getClientFieldName());
if (paramValue == null || paramValue.toString().isEmpty()) {
continue;
}
String fieldName = searchField.getFieldName();
if (paramValue instanceof Collection) {
String fq = orList(fieldName, (Collection<?>) paramValue);
if (fq != null) {
query.addFilterQuery(fq);
}
} else if (searchField.getDataType() == SearchField.DATA_TYPE.DATE) {
if (!(paramValue instanceof Date)) {
logger.error("Search field is not a Java Date Object, paramValue = " + paramValue);
} else {
if (searchField.getSearchType() == SEARCH_TYPE.GREATER_EQUAL_THAN
|| searchField.getSearchType() == SEARCH_TYPE.GREATER_THAN) {
fromDate = (Date) paramValue;
dateFieldName = fieldName;
} else if (searchField.getSearchType() == SEARCH_TYPE.LESS_EQUAL_THAN
|| searchField.getSearchType() == SEARCH_TYPE.LESS_THAN) {
toDate = (Date) paramValue;
dateFieldName = fieldName;
}
}
} else if (searchField.getSearchType() == SEARCH_TYPE.GREATER_EQUAL_THAN
|| searchField.getSearchType() == SEARCH_TYPE.GREATER_THAN
|| searchField.getSearchType() == SEARCH_TYPE.LESS_EQUAL_THAN
|| searchField.getSearchType() == SEARCH_TYPE.LESS_THAN) { //NOPMD
// TODO: Need to handle range here
} else {
String fq = setField(fieldName, paramValue);
if (searchField.getSearchType() == SEARCH_TYPE.PARTIAL) {
fq = setFieldForPartialSearch(fieldName, paramValue);
}
if (fq != null) {
query.addFilterQuery(fq);
}
}
}
if (fromDate != null || toDate != null) {
String fq = setDateRange(dateFieldName, fromDate, toDate);
if (fq != null) {
query.addFilterQuery(fq);
}
}
}
setSortClause(searchCriteria, sortFieldList, query);
query.setStart(searchCriteria.getStartIndex());
query.setRows(searchCriteria.getMaxRows());
// Fields to get
// query.setFields("myClassType", "id", "score", "globalId");
if (logger.isDebugEnabled()) {
logger.debug("SOLR QUERY = " + query);
}
QueryResponse response = null;
try {
response = runQuery(solrClient, query);
} catch (Throwable e) {
logger.error("Error running solr query. Query = " + query
+ ", response = " + response);
throw restErrorUtil.createRESTException(
"Error running solr query, please check solr configs. "
+ e.getMessage(), MessageEnums.ERROR_SYSTEM);
}
if (response == null || response.getStatus() != 0) {
logger.error("Error running solr query. Query = " + query
+ ", response = " + response);
throw restErrorUtil.createRESTException(
"Unable to connect to Audit store !!",
MessageEnums.ERROR_SYSTEM);
}
return response;
}
private String setFieldForPartialSearch(String fieldName, Object value) {
if (value == null || value.toString().trim().length() == 0) {
return null;
}
return fieldName + ":*" + ClientUtils.escapeQueryChars(value.toString().trim().toLowerCase()) + "*";
}
public String setField(String fieldName, Object value) {
if (value == null || value.toString().trim().length() == 0) {
return null;
}
return fieldName
+ ":"
+ ClientUtils.escapeQueryChars(value.toString().trim()
.toLowerCase());
}
public String setDateRange(String fieldName, Date fromDate, Date toDate) {
String fromStr = "*";
String toStr = "NOW";
if (fromDate != null) {
fromStr = dateFormat.format(fromDate);
}
if (toDate != null) {
toStr = dateFormat.format(toDate);
}
return fieldName + ":[" + fromStr + " TO " + toStr + "]";
}
public String orList(String fieldName, Collection<?> valueList) {
if (valueList == null || valueList.isEmpty()) {
return null;
}
String expr = "";
int count = -1;
for (Object value : valueList) {
count++;
if (count > 0) {
expr += " OR ";
}
expr += fieldName
+ ":"
+ ClientUtils.escapeQueryChars(value.toString()
.toLowerCase());
}
if (valueList.isEmpty()) {
return expr;
} else {
return "(" + expr + ")";
}
}
public String andList(String fieldName, Collection<?> valueList) {
if (valueList == null || valueList.isEmpty()) {
return null;
}
String expr = "";
int count = -1;
for (Object value : valueList) {
count++;
if (count > 0) {
expr += " AND ";
}
expr += fieldName
+ ":"
+ ClientUtils.escapeQueryChars(value.toString()
.toLowerCase());
}
if (valueList.isEmpty()) {
return expr;
} else {
return "(" + expr + ")";
}
}
public void setSortClause(SearchCriteria searchCriteria,
List<SortField> sortFields, SolrQuery query) {
// TODO: We are supporting single sort field only for now
String sortBy = searchCriteria.getSortBy();
String querySortBy = null;
if (!stringUtil.isEmpty(sortBy)) {
sortBy = sortBy.trim();
for (SortField sortField : sortFields) {
if (sortBy.equalsIgnoreCase(sortField.getParamName())) {
querySortBy = sortField.getFieldName();
// Override the sortBy using the normalized value
searchCriteria.setSortBy(sortField.getParamName());
break;
}
}
}
if (querySortBy == null) {
for (SortField sortField : sortFields) {
if (sortField.isDefault()) {
querySortBy = sortField.getFieldName();
// Override the sortBy using the default value
searchCriteria.setSortBy(sortField.getParamName());
searchCriteria.setSortType(sortField.getDefaultOrder()
.name());
break;
}
}
}
if (querySortBy != null) {
// Add sort type
String sortType = searchCriteria.getSortType();
ORDER order = ORDER.asc;
if (sortType != null && "desc".equalsIgnoreCase(sortType)) {
order = ORDER.desc;
}
query.addSort(querySortBy, order);
}
}
// Utility methods
public int toInt(Object value) {
if (value == null) {
return 0;
}
if (value instanceof Integer) {
return (Integer) value;
}
if (value.toString().isEmpty()) {
return 0;
}
try {
return Integer.valueOf(value.toString());
} catch (Throwable t) {
logger.error("Error converting value to integer. Value = " + value, t);
}
return 0;
}
public long toLong(Object value) {
if (value == null) {
return 0;
}
if (value instanceof Long) {
return (Long) value;
}
if (value.toString().isEmpty()) {
return 0;
}
try {
return Long.valueOf(value.toString());
} catch (Throwable t) {
logger.error("Error converting value to long. Value = " + value, t);
}
return 0;
}
public Date toDate(Object value) {
if (value == null) {
return null;
}
if (value instanceof Date) {
return (Date) value;
}
try {
// TODO: Do proper parsing based on Solr response value
return new Date(value.toString());
} catch (Throwable t) {
logger.error("Error converting value to date. Value = " + value, t);
}
return null;
}
}