/*
* (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.ecm.platform.audit.api;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.SortInfo;
import org.nuxeo.ecm.platform.audit.api.comment.CommentProcessorHelper;
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.PredicateDefinition;
import org.nuxeo.ecm.platform.query.api.PredicateFieldDefinition;
import org.nuxeo.runtime.api.Framework;
/**
* {@link PageProvider} implementation that returns {@link LogEntry} from Audit Service
*
* @author Tiry (tdelprat@nuxeo.com)
* @since 5.4.2
*/
public class AuditPageProvider extends AbstractPageProvider<LogEntry> implements PageProvider<LogEntry> {
private static final long serialVersionUID = 1L;
protected String auditQuery;
protected Map<String, Object> auditQueryParams;
public static final String CORE_SESSION_PROPERTY = "coreSession";
public static final String UICOMMENTS_PROPERTY = "generateUIComments";
public String toString() {
buildAuditQuery(true);
StringBuffer sb = new StringBuffer();
sb.append("\nquery : " + auditQuery);
sb.append("\nparams : ");
List<String> pNames = new ArrayList<String>(auditQueryParams.keySet());
Collections.sort(pNames);
for (String name : pNames) {
sb.append("\n ");
sb.append(name);
sb.append(" : ");
sb.append(auditQueryParams.get(name).toString());
}
return sb.toString();
}
protected void preprocessCommentsIfNeeded(List<LogEntry> entries) {
Serializable preprocess = getProperties().get(UICOMMENTS_PROPERTY);
CoreSession session = (CoreSession) getProperties().get(CORE_SESSION_PROPERTY);
if (session != null && preprocess != null && "true".equalsIgnoreCase(preprocess.toString())) {
CommentProcessorHelper cph = new CommentProcessorHelper(session);
cph.processComments(entries);
}
}
@SuppressWarnings("unchecked")
@Override
public List<LogEntry> getCurrentPage() {
AuditReader reader = Framework.getService(AuditReader.class);
buildAuditQuery(true);
List<LogEntry> entries = (List<LogEntry>) reader.nativeQuery(auditQuery, auditQueryParams,
(int) getCurrentPageIndex() + 1, (int) getMinMaxPageSize());
preprocessCommentsIfNeeded(entries);
return entries;
}
protected String getSortPart() {
StringBuffer sort = new StringBuffer();
if (getSortInfos() != null && getSortInfos().size() > 0) {
sort.append(" ORDER BY ");
}
int index = 0;
for (SortInfo si : getSortInfos()) {
if (index > 0) {
sort.append(" , ");
}
sort.append(si.getSortColumn());
if (si.getSortAscending()) {
sort.append(" ASC ");
} else {
sort.append(" DESC ");
}
index++;
}
return sort.toString();
}
protected Object convertParam(Object param) {
if (param == null) {
return null;
}
// Hibernate does not like Calendar type
if (param instanceof Calendar) {
return new Timestamp(((Calendar) param).getTime().getTime());
}
return param;
}
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 {
return getDefinition().getWhereClause().getFixedPart();
}
}
protected boolean allowSimplePattern() {
return true;
}
protected void buildAuditQuery(boolean includeSort) {
PageProviderDefinition def = getDefinition();
Object[] params = getParameters();
if (def.getWhereClause() == null) {
// Simple Pattern
if (!allowSimplePattern()) {
throw new UnsupportedOperationException("This page provider requires a explicit Where Clause");
}
String baseQuery = def.getPattern();
Map<String, Object> qParams = new HashMap<String, Object>();
for (int i = 0; i < params.length; i++) {
baseQuery = baseQuery.replaceFirst("\\?", ":param" + i);
qParams.put("param" + i, convertParam(params[i]));
}
if (includeSort) {
baseQuery = baseQuery + getSortPart();
}
auditQuery = baseQuery;
auditQueryParams = qParams;
} else {
// Where clause based on DocumentModel
StringBuilder baseQuery = new StringBuilder("from LogEntry log ");
// manage fixed part
String fixedPart = getFixedPart();
Map<String, Object> qParams = new HashMap<String, Object>();
int idxParam = 0;
if (fixedPart != null && !fixedPart.isEmpty()) {
while (fixedPart.indexOf("?") > 0) {
fixedPart = fixedPart.replaceFirst("\\?", ":param" + idxParam);
qParams.put("param" + idxParam, convertParam(params[idxParam]));
idxParam++;
}
baseQuery.append(" where ");
baseQuery.append(fixedPart);
}
// manages predicates
DocumentModel searchDocumentModel = getSearchDocumentModel();
if (searchDocumentModel != null) {
PredicateDefinition[] predicates = def.getWhereClause().getPredicates();
int idxPredicate = 0;
for (PredicateDefinition predicate : predicates) {
// extract data from DocumentModel
PredicateFieldDefinition[] fieldDef = predicate.getValues();
Object[] val = new Object[fieldDef.length];
for (int fidx = 0; fidx < fieldDef.length; fidx++) {
if (fieldDef[fidx].getXpath() != null) {
val[fidx] = searchDocumentModel.getPropertyValue(fieldDef[fidx].getXpath());
} else {
val[fidx] = searchDocumentModel.getProperty(fieldDef[fidx].getSchema(),
fieldDef[fidx].getName());
}
}
if (!isNonNullParam(val)) {
// skip predicate where all values are null
continue;
}
if (idxPredicate > 0 || idxParam > 0) {
baseQuery.append(" AND ");
} else {
baseQuery.append(" where ");
}
baseQuery.append(predicate.getParameter());
baseQuery.append(" ");
if (!predicate.getOperator().equalsIgnoreCase("BETWEEN")) {
// don't add the between operation for now
baseQuery.append(predicate.getOperator());
}
if (predicate.getOperator().equalsIgnoreCase("IN")) {
baseQuery.append(" (");
if (val[0] instanceof Iterable<?>) {
Iterable<?> vals = (Iterable<?>) val[0];
Iterator<?> valueIterator = vals.iterator();
while (valueIterator.hasNext()) {
Object v = valueIterator.next();
qParams.put("param" + idxParam, convertParam(v));
baseQuery.append(" :param" + idxParam);
idxParam++;
if (valueIterator.hasNext()) {
baseQuery.append(",");
}
}
} else if (val[0] instanceof Object[]) {
Object[] valArray = (Object[]) val[0];
for (int i = 0; i < valArray.length; i++) {
Object v = valArray[i];
qParams.put("param" + idxParam, convertParam(v));
baseQuery.append(" :param" + idxParam);
idxParam++;
if (i < valArray.length - 1) {
baseQuery.append(",");
}
}
}
baseQuery.append(" ) ");
} else if (predicate.getOperator().equalsIgnoreCase("BETWEEN")) {
Object startValue = convertParam(val[0]);
Object endValue = null;
if (val.length > 1) {
endValue = convertParam(val[1]);
}
if (startValue != null && endValue != null) {
baseQuery.append(predicate.getOperator());
baseQuery.append(" :param" + idxParam);
qParams.put("param" + idxParam, startValue);
idxParam++;
baseQuery.append(" AND :param" + idxParam);
qParams.put("param" + idxParam, endValue);
} else if (startValue == null) {
baseQuery.append("<=");
baseQuery.append(" :param" + idxParam);
qParams.put("param" + idxParam, endValue);
} else if (endValue == null) {
baseQuery.append(">=");
baseQuery.append(" :param" + idxParam);
qParams.put("param" + idxParam, startValue);
}
idxParam++;
} else {
baseQuery.append(" :param" + idxParam);
qParams.put("param" + idxParam, convertParam(val[0]));
idxParam++;
}
idxPredicate++;
}
}
if (includeSort) {
baseQuery.append(getSortPart());
}
auditQuery = baseQuery.toString();
auditQueryParams = qParams;
}
}
public void refresh() {
setCurrentPageOffset(0);
super.refresh();
}
@SuppressWarnings("unchecked")
@Override
public long getResultsCount() {
if (resultsCount == AbstractPageProvider.UNKNOWN_SIZE) {
buildAuditQuery(false);
AuditReader reader = Framework.getService(AuditReader.class);
List<Long> res = (List<Long>) reader.nativeQuery("select count(log.id) " + auditQuery, auditQueryParams, 1,
20);
resultsCount = res.get(0).longValue();
}
return resultsCount;
}
}