/*
* (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed 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.
*
* Contributors:
* Nuxeo - initial API and implementation
*
* $Id$
*/
package org.nuxeo.elasticsearch.audit.pageprovider;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.NuxeoException;
import org.nuxeo.ecm.core.api.SortInfo;
import org.nuxeo.ecm.platform.audit.api.LogEntry;
import org.nuxeo.ecm.platform.audit.api.comment.CommentProcessorHelper;
import org.nuxeo.ecm.platform.audit.service.AuditBackend;
import org.nuxeo.ecm.platform.audit.service.NXAuditEventsService;
import org.nuxeo.ecm.platform.query.api.AbstractPageProvider;
import org.nuxeo.ecm.platform.query.api.PageProvider;
import org.nuxeo.ecm.platform.query.api.PageProviderDefinition;
import org.nuxeo.ecm.platform.query.api.QuickFilter;
import org.nuxeo.ecm.platform.query.api.WhereClauseDefinition;
import org.nuxeo.ecm.platform.query.nxql.NXQLQueryBuilder;
import org.nuxeo.elasticsearch.audit.ESAuditBackend;
import org.nuxeo.elasticsearch.audit.io.AuditEntryJSONReader;
import org.nuxeo.runtime.api.Framework;
public class ESAuditPageProvider extends AbstractPageProvider<LogEntry> implements PageProvider<LogEntry> {
private static final long serialVersionUID = 1L;
protected SearchRequestBuilder searchBuilder;
public static final String CORE_SESSION_PROPERTY = "coreSession";
public static final String UICOMMENTS_PROPERTY = "generateUIComments";
protected static String emptyQuery = "{ \"match_all\" : { }\n }";
@Override
public String toString() {
buildAuditQuery(true);
StringBuffer sb = new StringBuffer();
sb.append(searchBuilder.toString());
return sb.toString();
}
protected CoreSession getCoreSession() {
Object session = getProperties().get(CORE_SESSION_PROPERTY);
if (session != null && session instanceof CoreSession) {
return (CoreSession) session;
}
return null;
}
protected void preprocessCommentsIfNeeded(List<LogEntry> entries) {
Serializable preprocess = getProperties().get(UICOMMENTS_PROPERTY);
if (preprocess != null && "true".equalsIgnoreCase(preprocess.toString())) {
CoreSession session = getCoreSession();
if (session != null) {
CommentProcessorHelper cph = new CommentProcessorHelper(session);
cph.processComments(entries);
}
}
}
@Override
public List<LogEntry> getCurrentPage() {
buildAuditQuery(true);
searchBuilder.setFrom((int) (getCurrentPageIndex() * pageSize));
searchBuilder.setSize((int) getMinMaxPageSize());
for (SortInfo sortInfo : getSortInfos()) {
searchBuilder.addSort(sortInfo.getSortColumn(),
sortInfo.getSortAscending() ? SortOrder.ASC : SortOrder.DESC);
}
SearchResponse searchResponse = searchBuilder.execute().actionGet();
List<LogEntry> entries = new ArrayList<>();
SearchHits hits = searchResponse.getHits();
// set total number of hits ?
setResultsCount(hits.getTotalHits());
for (SearchHit hit : hits) {
try {
entries.add(AuditEntryJSONReader.read(hit.getSourceAsString()));
} catch (IOException e) {
log.error("Error while reading Audit Entry from ES", e);
}
}
preprocessCommentsIfNeeded(entries);
long t0 = System.currentTimeMillis();
CoreSession session = getCoreSession();
if (session != null) {
// send event for statistics !
fireSearchEvent(session.getPrincipal(), searchBuilder.toString(), entries, System.currentTimeMillis() - t0);
}
return entries;
}
protected boolean isNonNullParam(Object[] val) {
if (val == null) {
return false;
}
for (Object v : val) {
if (v != null) {
if (v instanceof String) {
if (!((String) v).isEmpty()) {
return true;
}
} else if (v instanceof String[]) {
if (((String[]) v).length > 0) {
return true;
}
} else {
return true;
}
}
}
return false;
}
protected String getFixedPart() {
if (getDefinition().getWhereClause() == null) {
return null;
} else {
String fixedPart = getDefinition().getWhereClause().getFixedPart();
if (fixedPart == null || fixedPart.isEmpty()) {
fixedPart = emptyQuery;
}
return fixedPart;
}
}
protected boolean allowSimplePattern() {
return true;
}
protected ESAuditBackend getESBackend() {
NXAuditEventsService audit = (NXAuditEventsService) Framework.getRuntime()
.getComponent(NXAuditEventsService.NAME);
AuditBackend backend = audit.getBackend();
if (backend instanceof ESAuditBackend) {
return (ESAuditBackend) backend;
}
throw new NuxeoException(
"Unable to use ESAuditPageProvider if audit service is not configured to run with ElasticSearch");
}
protected void buildAuditQuery(boolean includeSort) {
PageProviderDefinition def = getDefinition();
Object[] params = getParameters();
List<QuickFilter> quickFilters = getQuickFilters();
String quickFiltersClause = "";
if (quickFilters != null && !quickFilters.isEmpty()) {
for (QuickFilter quickFilter : quickFilters) {
String clause = quickFilter.getClause();
if (!quickFiltersClause.isEmpty() && clause != null) {
quickFiltersClause = NXQLQueryBuilder.appendClause(quickFiltersClause, clause);
} else {
quickFiltersClause = clause != null ? clause : "";
}
}
}
WhereClauseDefinition whereClause = def.getWhereClause();
if (whereClause == null) {
// Simple Pattern
if (!allowSimplePattern()) {
throw new UnsupportedOperationException("This page provider requires a explicit Where Clause");
}
String originalPattern = def.getPattern();
String pattern = quickFiltersClause.isEmpty() ? originalPattern
: StringUtils.containsIgnoreCase(originalPattern, " WHERE ")
? NXQLQueryBuilder.appendClause(originalPattern, quickFiltersClause)
: originalPattern + " WHERE " + quickFiltersClause;
String baseQuery = getESBackend().expandQueryVariables(pattern, params);
searchBuilder = getESBackend().buildQuery(baseQuery, null);
} else {
// Add the quick filters clauses to the fixed part
String fixedPart = getFixedPart();
if (!StringUtils.isBlank(quickFiltersClause)) {
fixedPart = (!StringUtils.isBlank(fixedPart))
? NXQLQueryBuilder.appendClause(fixedPart, quickFiltersClause) : quickFiltersClause;
}
// Where clause based on DocumentModel
String baseQuery = getESBackend().expandQueryVariables(fixedPart, params);
searchBuilder = getESBackend().buildSearchQuery(baseQuery, whereClause.getPredicates(),
getSearchDocumentModel());
}
}
@Override
public void refresh() {
setCurrentPageOffset(0);
super.refresh();
}
@Override
public long getResultsCount() {
return resultsCount;
}
@Override
public List<SortInfo> getSortInfos() {
// because ContentView can reuse PageProVider without redefining columns
// ensure compat for ContentView configured with JPA log.* sort syntax
List<SortInfo> sortInfos = super.getSortInfos();
for (SortInfo si : sortInfos) {
if (si.getSortColumn().startsWith("log.")) {
si.setSortColumn(si.getSortColumn().substring(4));
}
}
return sortInfos;
}
}