/* * (C) Copyright 2006-2008 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: * Stephane Lacoin (Nuxeo EP Software Engineer) */ package org.nuxeo.ecm.platform.audit.service; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.Query; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.ecm.platform.audit.api.FilterMapEntry; import org.nuxeo.ecm.platform.audit.api.LogEntry; import org.nuxeo.ecm.platform.audit.api.query.AuditQueryException; import org.nuxeo.ecm.platform.audit.api.query.DateRangeParser; import org.nuxeo.ecm.platform.audit.impl.LogEntryImpl; public class LogEntryProvider implements BaseLogEntryProvider { private static final Log log = LogFactory.getLog(LogEntryProvider.class); protected final EntityManager em; private LogEntryProvider(EntityManager em) { this.em = em; } public static LogEntryProvider createProvider(EntityManager em) { return new LogEntryProvider(em); } protected void doPersist(LogEntry entry) { // Set the log date in java right before saving to the database. We // cannot set a static column definition to // "TIMESTAMP DEFAULT CURRENT_TIMESTAMP" as MS SQL Server does not // support the TIMESTAMP column type and generating a dynamic // persistence configuration that would depend on the database is too // complicated. entry.setLogDate(new Date()); em.persist(entry); } protected List<?> doPublishIfEntries(List<?> entries) { if (entries == null || entries.size() == 0) { return entries; } Object entry = entries.get(0); if (entry instanceof LogEntry) { for (Object logEntry : entries) { doPublish((LogEntry) logEntry); } } return entries; } protected List<LogEntry> doPublish(List<LogEntry> entries) { for (LogEntry entry : entries) { doPublish(entry); } return entries; } protected LogEntry doPublish(LogEntry entry) { if (entry.getExtendedInfos() != null) { entry.getExtendedInfos().size(); // force lazy loading } return entry; } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#addLogEntry(org * .nuxeo.ecm.platform.audit.api.LogEntry) */ @Override public void addLogEntry(LogEntry entry) { doPersist(entry); } public void addLogEntries(List<LogEntry> entries) { for (LogEntry entry : entries) { doPersist(entry); } } @SuppressWarnings("unchecked") @Override public List<LogEntry> getLogEntriesFor(String uuid, String repositoryId) { if (log.isDebugEnabled()) { log.debug("getLogEntriesFor() UUID=" + uuid + " and repositoryId=" + repositoryId); } Query query = em.createNamedQuery("LogEntry.findByDocumentAndRepository"); query.setParameter("docUUID", uuid); query.setParameter("repositoryId", repositoryId); return doPublish(query.getResultList()); } @SuppressWarnings("unchecked") @Override public List<LogEntry> getLogEntriesFor(String uuid) { if (log.isDebugEnabled()) { log.debug("getLogEntriesFor() UUID=" + uuid); } Query query = em.createNamedQuery("LogEntry.findByDocument"); query.setParameter("docUUID", uuid); return doPublish(query.getResultList()); } @SuppressWarnings("unchecked") @Override public List<LogEntry> getLogEntriesFor(String uuid, Map<String, FilterMapEntry> filterMap, boolean doDefaultSort) { if (log.isDebugEnabled()) { log.debug("getLogEntriesFor() UUID=" + uuid); } if (filterMap == null) { filterMap = new HashMap<String, FilterMapEntry>(); } StringBuilder queryStr = new StringBuilder(); queryStr.append(" FROM LogEntry log WHERE log.docUUID=:uuid "); Set<String> filterMapKeySet = filterMap.keySet(); for (String currentKey : filterMapKeySet) { FilterMapEntry currentFilterMapEntry = filterMap.get(currentKey); String currentOperator = currentFilterMapEntry.getOperator(); String currentQueryParameterName = currentFilterMapEntry.getQueryParameterName(); String currentColumnName = currentFilterMapEntry.getColumnName(); if ("LIKE".equals(currentOperator)) { queryStr.append(" AND log.") .append(currentColumnName) .append(" LIKE :") .append(currentQueryParameterName) .append(" "); } else { queryStr.append(" AND log.") .append(currentColumnName) .append(currentOperator) .append(":") .append(currentQueryParameterName) .append(" "); } } if (doDefaultSort) { queryStr.append(" ORDER BY log.eventDate DESC"); } Query query = em.createQuery(queryStr.toString()); query.setParameter("uuid", uuid); for (String currentKey : filterMapKeySet) { FilterMapEntry currentFilterMapEntry = filterMap.get(currentKey); String currentOperator = currentFilterMapEntry.getOperator(); String currentQueryParameterName = currentFilterMapEntry.getQueryParameterName(); Object currentObject = currentFilterMapEntry.getObject(); if ("LIKE".equals(currentOperator)) { query.setParameter(currentQueryParameterName, "%" + currentObject + "%"); } else { query.setParameter(currentQueryParameterName, currentObject); } } return doPublish(query.getResultList()); } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#getLogEntryByID (long) */ public LogEntry getLogEntryByID(long id) { if (log.isDebugEnabled()) { log.debug("getLogEntriesFor() logID=" + id); } return doPublish(em.find(LogEntryImpl.class, id)); } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#nativeQueryLogs (java.lang.String, int, int) */ @SuppressWarnings("unchecked") public List<LogEntry> nativeQueryLogs(String whereClause, int pageNb, int pageSize) { Query query = em.createQuery("from LogEntry log where " + whereClause); if (pageNb > 1) { query.setFirstResult((pageNb - 1) * pageSize); } else if (pageNb == 0) { log.warn("Requested pageNb equals 0 but page index start at 1. Will fallback to fetch the first page"); } query.setMaxResults(pageSize); return doPublish(query.getResultList()); } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#nativeQuery(java .lang.String, int, int) */ public List<?> nativeQuery(String queryString, int pageNb, int pageSize) { Query query = em.createQuery(queryString); if (pageNb > 1) { query.setFirstResult((pageNb - 1) * pageSize); } query.setMaxResults(pageSize); return doPublishIfEntries(query.getResultList()); } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#nativeQuery(java .lang.String, java.util.Map, int, * int) */ public List<?> nativeQuery(String queryString, Map<String, Object> params, int pageNb, int pageSize) { if (pageSize <= 0) { pageSize = 1000; } Query query = em.createQuery(queryString); for (Entry<String, Object> en : params.entrySet()) { query.setParameter(en.getKey(), en.getValue()); } if (pageNb > 1) { query.setFirstResult((pageNb - 1) * pageSize); } query.setMaxResults(pageSize); return doPublishIfEntries(query.getResultList()); } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#queryLogs(java. lang.String[], java.lang.String) */ @SuppressWarnings("unchecked") public List<LogEntry> queryLogs(String[] eventIds, String dateRange) { Date limit; try { limit = DateRangeParser.parseDateRangeQuery(new Date(), dateRange); } catch (AuditQueryException aqe) { aqe.addInfo("Wrong date range query. Query was " + dateRange); throw aqe; } String queryStr = ""; if (eventIds == null || eventIds.length == 0) { queryStr = "from LogEntry log" + " where log.eventDate >= :limit" + " ORDER BY log.eventDate DESC"; } else { String inClause = "("; for (String eventId : eventIds) { inClause += "'" + eventId + "',"; } inClause = inClause.substring(0, inClause.length() - 1); inClause += ")"; queryStr = "from LogEntry log" + " where log.eventId in " + inClause + " AND log.eventDate >= :limit" + " ORDER BY log.eventDate DESC"; } if (log.isDebugEnabled()) { log.debug("queryLogs() =" + queryStr); } Query query = em.createQuery(queryStr); query.setParameter("limit", limit); return doPublish(query.getResultList()); } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#queryLogsByPage (java.lang.String[], java.lang.String, * java.lang.String[], java.lang.String, int, int) */ public List<LogEntry> queryLogsByPage(String[] eventIds, String dateRange, String[] categories, String path, int pageNb, int pageSize) { Date limit = null; try { limit = DateRangeParser.parseDateRangeQuery(new Date(), dateRange); } catch (AuditQueryException aqe) { aqe.addInfo("Wrong date range query. Query was " + dateRange); throw aqe; } return queryLogsByPage(eventIds, limit, categories, path, pageNb, pageSize); } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#queryLogsByPage (java.lang.String[], java.util.Date, * java.lang.String[], java.lang.String, int, int) */ @SuppressWarnings("unchecked") public List<LogEntry> queryLogsByPage(String[] eventIds, Date limit, String[] categories, String path, int pageNb, int pageSize) { if (eventIds == null) { eventIds = new String[0]; } if (categories == null) { categories = new String[0]; } StringBuilder queryString = new StringBuilder(); queryString.append("from LogEntry log where "); if (eventIds.length > 0) { String inClause = "("; for (String eventId : eventIds) { inClause += "'" + eventId + "',"; } inClause = inClause.substring(0, inClause.length() - 1); inClause += ")"; queryString.append(" log.eventId IN ").append(inClause); queryString.append(" AND "); } if (categories.length > 0) { String inClause = "("; for (String cat : categories) { inClause += "'" + cat + "',"; } inClause = inClause.substring(0, inClause.length() - 1); inClause += ")"; queryString.append(" log.category IN ").append(inClause); queryString.append(" AND "); } if (path != null && !"".equals(path.trim())) { queryString.append(" log.docPath LIKE '").append(path).append("%'"); queryString.append(" AND "); } queryString.append(" log.eventDate >= :limit"); queryString.append(" ORDER BY log.eventDate DESC"); Query query = em.createQuery(queryString.toString()); query.setParameter("limit", limit); if (pageNb > 1) { query.setFirstResult((pageNb - 1) * pageSize); } query.setMaxResults(pageSize); return doPublish(query.getResultList()); } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#removeEntries(java .lang.String, java.lang.String) */ @Override @SuppressWarnings("unchecked") public int removeEntries(String eventId, String pathPattern) { // TODO extended info cascade delete does not work using HQL, so we // have to delete each // entry by hand. Query query = em.createNamedQuery("LogEntry.findByEventIdAndPath"); query.setParameter("eventId", eventId); query.setParameter("pathPattern", pathPattern + "%"); int count = 0; for (LogEntry entry : (List<LogEntry>) query.getResultList()) { em.remove(entry); count += 1; } if (log.isDebugEnabled()) { log.debug("removed " + count + " entries from " + pathPattern); } return count; } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#countEventsById (java.lang.String) */ public Long countEventsById(String eventId) { Query query = em.createNamedQuery("LogEntry.countEventsById"); query.setParameter("eventId", eventId); return (Long) query.getSingleResult(); } /* * (non-Javadoc) * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#findEventIds() */ @SuppressWarnings("unchecked") public List<String> findEventIds() { Query query = em.createNamedQuery("LogEntry.findEventIds"); return (List<String>) query.getResultList(); } }