001/* 002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Stephane Lacoin (Nuxeo EP Software Engineer) 016 */ 017 018package org.nuxeo.ecm.platform.audit.service; 019 020import java.util.Date; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Map.Entry; 025import java.util.Set; 026 027import javax.persistence.EntityManager; 028import javax.persistence.Query; 029 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032import org.nuxeo.ecm.platform.audit.api.FilterMapEntry; 033import org.nuxeo.ecm.platform.audit.api.LogEntry; 034import org.nuxeo.ecm.platform.audit.api.query.AuditQueryException; 035import org.nuxeo.ecm.platform.audit.api.query.DateRangeParser; 036import org.nuxeo.ecm.platform.audit.impl.LogEntryImpl; 037 038public class LogEntryProvider implements BaseLogEntryProvider { 039 040 private static final Log log = LogFactory.getLog(LogEntryProvider.class); 041 042 protected final EntityManager em; 043 044 private LogEntryProvider(EntityManager em) { 045 this.em = em; 046 } 047 048 public static LogEntryProvider createProvider(EntityManager em) { 049 return new LogEntryProvider(em); 050 } 051 052 protected void doPersist(LogEntry entry) { 053 // Set the log date in java right before saving to the database. We 054 // cannot set a static column definition to 055 // "TIMESTAMP DEFAULT CURRENT_TIMESTAMP" as MS SQL Server does not 056 // support the TIMESTAMP column type and generating a dynamic 057 // persistence configuration that would depend on the database is too 058 // complicated. 059 entry.setLogDate(new Date()); 060 em.persist(entry); 061 } 062 063 protected List<?> doPublishIfEntries(List<?> entries) { 064 if (entries == null || entries.size() == 0) { 065 return entries; 066 } 067 Object entry = entries.get(0); 068 if (entry instanceof LogEntry) { 069 for (Object logEntry : entries) { 070 doPublish((LogEntry) logEntry); 071 } 072 } 073 return entries; 074 } 075 076 protected List<LogEntry> doPublish(List<LogEntry> entries) { 077 for (LogEntry entry : entries) { 078 doPublish(entry); 079 } 080 return entries; 081 } 082 083 protected LogEntry doPublish(LogEntry entry) { 084 if (entry.getExtendedInfos() != null) { 085 entry.getExtendedInfos().size(); // force lazy loading 086 } 087 return entry; 088 } 089 090 /* 091 * (non-Javadoc) 092 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#addLogEntry(org 093 * .nuxeo.ecm.platform.audit.api.LogEntry) 094 */ 095 @Override 096 public void addLogEntry(LogEntry entry) { 097 doPersist(entry); 098 } 099 100 public void addLogEntries(List<LogEntry> entries) { 101 for (LogEntry entry : entries) { 102 doPersist(entry); 103 } 104 } 105 106 @SuppressWarnings("unchecked") 107 public List<LogEntry> getLogEntriesFor(String uuid) { 108 if (log.isDebugEnabled()) { 109 log.debug("getLogEntriesFor() UUID=" + uuid); 110 } 111 Query query = em.createNamedQuery("LogEntry.findByDocument"); 112 query.setParameter("docUUID", uuid); 113 return doPublish(query.getResultList()); 114 } 115 116 @SuppressWarnings("unchecked") 117 @Deprecated 118 public List<LogEntry> getLogEntriesFor(String uuid, Map<String, FilterMapEntry> filterMap, boolean doDefaultSort) { 119 if (log.isDebugEnabled()) { 120 log.debug("getLogEntriesFor() UUID=" + uuid); 121 } 122 123 if (filterMap == null) { 124 filterMap = new HashMap<String, FilterMapEntry>(); 125 } 126 127 StringBuilder queryStr = new StringBuilder(); 128 queryStr.append(" FROM LogEntry log WHERE log.docUUID=:uuid "); 129 130 Set<String> filterMapKeySet = filterMap.keySet(); 131 for (String currentKey : filterMapKeySet) { 132 FilterMapEntry currentFilterMapEntry = filterMap.get(currentKey); 133 String currentOperator = currentFilterMapEntry.getOperator(); 134 String currentQueryParameterName = currentFilterMapEntry.getQueryParameterName(); 135 String currentColumnName = currentFilterMapEntry.getColumnName(); 136 137 if ("LIKE".equals(currentOperator)) { 138 queryStr.append(" AND log.").append(currentColumnName).append(" LIKE :").append( 139 currentQueryParameterName).append(" "); 140 } else { 141 queryStr.append(" AND log.").append(currentColumnName).append(currentOperator).append(":").append( 142 currentQueryParameterName).append(" "); 143 } 144 } 145 146 if (doDefaultSort) { 147 queryStr.append(" ORDER BY log.eventDate DESC"); 148 } 149 150 Query query = em.createQuery(queryStr.toString()); 151 152 query.setParameter("uuid", uuid); 153 154 for (String currentKey : filterMapKeySet) { 155 FilterMapEntry currentFilterMapEntry = filterMap.get(currentKey); 156 String currentOperator = currentFilterMapEntry.getOperator(); 157 String currentQueryParameterName = currentFilterMapEntry.getQueryParameterName(); 158 Object currentObject = currentFilterMapEntry.getObject(); 159 160 if ("LIKE".equals(currentOperator)) { 161 query.setParameter(currentQueryParameterName, "%" + currentObject + "%"); 162 } else { 163 query.setParameter(currentQueryParameterName, currentObject); 164 } 165 } 166 167 return doPublish(query.getResultList()); 168 } 169 170 /* 171 * (non-Javadoc) 172 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#getLogEntryByID (long) 173 */ 174 public LogEntry getLogEntryByID(long id) { 175 if (log.isDebugEnabled()) { 176 log.debug("getLogEntriesFor() logID=" + id); 177 } 178 return doPublish(em.find(LogEntryImpl.class, id)); 179 } 180 181 /* 182 * (non-Javadoc) 183 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#nativeQueryLogs (java.lang.String, int, int) 184 */ 185 @SuppressWarnings("unchecked") 186 public List<LogEntry> nativeQueryLogs(String whereClause, int pageNb, int pageSize) { 187 Query query = em.createQuery("from LogEntry log where " + whereClause); 188 if (pageNb > 1) { 189 query.setFirstResult((pageNb - 1) * pageSize); 190 } 191 query.setMaxResults(pageSize); 192 return doPublish(query.getResultList()); 193 } 194 195 /* 196 * (non-Javadoc) 197 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#nativeQuery(java .lang.String, int, int) 198 */ 199 public List<?> nativeQuery(String queryString, int pageNb, int pageSize) { 200 Query query = em.createQuery(queryString); 201 if (pageNb > 1) { 202 query.setFirstResult((pageNb - 1) * pageSize); 203 } 204 query.setMaxResults(pageSize); 205 return doPublishIfEntries(query.getResultList()); 206 } 207 208 /* 209 * (non-Javadoc) 210 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#nativeQuery(java .lang.String, java.util.Map, int, 211 * int) 212 */ 213 public List<?> nativeQuery(String queryString, Map<String, Object> params, int pageNb, int pageSize) { 214 if (pageSize <= 0) { 215 pageSize = 1000; 216 } 217 Query query = em.createQuery(queryString); 218 for (Entry<String, Object> en : params.entrySet()) { 219 query.setParameter(en.getKey(), en.getValue()); 220 } 221 if (pageNb > 1) { 222 query.setFirstResult((pageNb - 1) * pageSize); 223 } 224 query.setMaxResults(pageSize); 225 return doPublishIfEntries(query.getResultList()); 226 } 227 228 /* 229 * (non-Javadoc) 230 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#queryLogs(java. lang.String[], java.lang.String) 231 */ 232 @SuppressWarnings("unchecked") 233 public List<LogEntry> queryLogs(String[] eventIds, String dateRange) { 234 Date limit; 235 try { 236 limit = DateRangeParser.parseDateRangeQuery(new Date(), dateRange); 237 } catch (AuditQueryException aqe) { 238 aqe.addInfo("Wrong date range query. Query was " + dateRange); 239 throw aqe; 240 } 241 242 String queryStr = ""; 243 if (eventIds == null || eventIds.length == 0) { 244 queryStr = "from LogEntry log" + " where log.eventDate >= :limit" + " ORDER BY log.eventDate DESC"; 245 } else { 246 String inClause = "("; 247 for (String eventId : eventIds) { 248 inClause += "'" + eventId + "',"; 249 } 250 inClause = inClause.substring(0, inClause.length() - 1); 251 inClause += ")"; 252 253 queryStr = "from LogEntry log" + " where log.eventId in " + inClause + " AND log.eventDate >= :limit" 254 + " ORDER BY log.eventDate DESC"; 255 } 256 257 if (log.isDebugEnabled()) { 258 log.debug("queryLogs() =" + queryStr); 259 } 260 Query query = em.createQuery(queryStr); 261 query.setParameter("limit", limit); 262 263 return doPublish(query.getResultList()); 264 } 265 266 /* 267 * (non-Javadoc) 268 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#queryLogsByPage (java.lang.String[], java.lang.String, 269 * java.lang.String[], java.lang.String, int, int) 270 */ 271 public List<LogEntry> queryLogsByPage(String[] eventIds, String dateRange, String[] categories, String path, 272 int pageNb, int pageSize) { 273 Date limit = null; 274 try { 275 limit = DateRangeParser.parseDateRangeQuery(new Date(), dateRange); 276 } catch (AuditQueryException aqe) { 277 aqe.addInfo("Wrong date range query. Query was " + dateRange); 278 throw aqe; 279 } 280 return queryLogsByPage(eventIds, limit, categories, path, pageNb, pageSize); 281 } 282 283 /* 284 * (non-Javadoc) 285 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#queryLogsByPage (java.lang.String[], java.util.Date, 286 * java.lang.String[], java.lang.String, int, int) 287 */ 288 @SuppressWarnings("unchecked") 289 public List<LogEntry> queryLogsByPage(String[] eventIds, Date limit, String[] categories, String path, int pageNb, 290 int pageSize) { 291 if (eventIds == null) { 292 eventIds = new String[0]; 293 } 294 if (categories == null) { 295 categories = new String[0]; 296 } 297 298 StringBuilder queryString = new StringBuilder(); 299 300 queryString.append("from LogEntry log where "); 301 302 if (eventIds.length > 0) { 303 String inClause = "("; 304 for (String eventId : eventIds) { 305 inClause += "'" + eventId + "',"; 306 } 307 inClause = inClause.substring(0, inClause.length() - 1); 308 inClause += ")"; 309 310 queryString.append(" log.eventId IN ").append(inClause); 311 queryString.append(" AND "); 312 } 313 if (categories.length > 0) { 314 String inClause = "("; 315 for (String cat : categories) { 316 inClause += "'" + cat + "',"; 317 } 318 inClause = inClause.substring(0, inClause.length() - 1); 319 inClause += ")"; 320 queryString.append(" log.category IN ").append(inClause); 321 queryString.append(" AND "); 322 } 323 324 if (path != null && !"".equals(path.trim())) { 325 queryString.append(" log.docPath LIKE '").append(path).append("%'"); 326 queryString.append(" AND "); 327 } 328 329 queryString.append(" log.eventDate >= :limit"); 330 queryString.append(" ORDER BY log.eventDate DESC"); 331 332 Query query = em.createQuery(queryString.toString()); 333 334 query.setParameter("limit", limit); 335 336 if (pageNb > 1) { 337 query.setFirstResult((pageNb - 1) * pageSize); 338 } 339 query.setMaxResults(pageSize); 340 341 return doPublish(query.getResultList()); 342 } 343 344 /* 345 * (non-Javadoc) 346 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#removeEntries(java .lang.String, java.lang.String) 347 */ 348 @Override 349 @SuppressWarnings("unchecked") 350 public int removeEntries(String eventId, String pathPattern) { 351 // TODO extended info cascade delete does not work using HQL, so we 352 // have to delete each 353 // entry by hand. 354 Query query = em.createNamedQuery("LogEntry.findByEventIdAndPath"); 355 query.setParameter("eventId", eventId); 356 query.setParameter("pathPattern", pathPattern + "%"); 357 int count = 0; 358 for (LogEntry entry : (List<LogEntry>) query.getResultList()) { 359 em.remove(entry); 360 count += 1; 361 } 362 if (log.isDebugEnabled()) { 363 log.debug("removed " + count + " entries from " + pathPattern); 364 } 365 return count; 366 } 367 368 /* 369 * (non-Javadoc) 370 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#countEventsById (java.lang.String) 371 */ 372 public Long countEventsById(String eventId) { 373 Query query = em.createNamedQuery("LogEntry.countEventsById"); 374 query.setParameter("eventId", eventId); 375 return (Long) query.getSingleResult(); 376 } 377 378 /* 379 * (non-Javadoc) 380 * @see org.nuxeo.ecm.platform.audit.service.LogEntryProvider#findEventIds() 381 */ 382 @SuppressWarnings("unchecked") 383 public List<String> findEventIds() { 384 Query query = em.createNamedQuery("LogEntry.findEventIds"); 385 return (List<String>) query.getResultList(); 386 } 387 388}