001/* 002 * Copyright (c) 2006-2012 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Nuxeo - initial API and implementation 011 * 012 */ 013package org.nuxeo.ecm.platform.audit.api.document; 014 015import java.util.Calendar; 016import java.util.GregorianCalendar; 017import java.util.HashMap; 018import java.util.List; 019import java.util.Map; 020 021import org.nuxeo.ecm.core.api.CoreSession; 022import org.nuxeo.ecm.core.api.DocumentModel; 023import org.nuxeo.ecm.core.api.DocumentModelList; 024import org.nuxeo.ecm.core.api.IdRef; 025import org.nuxeo.ecm.core.api.event.DocumentEventTypes; 026import org.nuxeo.ecm.platform.audit.api.AuditReader; 027import org.nuxeo.ecm.platform.audit.api.FilterMapEntry; 028import org.nuxeo.ecm.platform.audit.api.LogEntry; 029import org.nuxeo.runtime.api.Framework; 030 031/** 032 * Audit log stores event related to the "live" DocumentModel. This means that when retrieving the Audit Log for a 033 * version or a proxy, we must merge part of the "live" document history with the history of the proxy or version. This 034 * helper class fetches the additional parameters that must be used to retrieve history of a version or of a proxy. 035 * 036 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a> 037 */ 038public class DocumentAuditHelper { 039 040 @SuppressWarnings({ "unchecked", "boxing" }) 041 public static AdditionalDocumentAuditParams getAuditParamsForUUID(String uuid, CoreSession session) { 042 043 IdRef ref = new IdRef(uuid); 044 if (!session.exists(ref)) { 045 return null; 046 } 047 DocumentModel doc = session.getDocument(ref); 048 if (!doc.isProxy() && !doc.isVersion()) { 049 return null; 050 } 051 SourceDocumentResolver resolver = new SourceDocumentResolver(session, doc); 052 resolver.runUnrestricted(); 053 if (resolver.sourceDocument == null) { 054 return null; 055 } 056 String targetUUID = resolver.sourceDocument.getId(); 057 // now get from Audit Logs the creation date of 058 // the version / proxy 059 AuditReader reader = Framework.getLocalService(AuditReader.class); 060 FilterMapEntry filter = new FilterMapEntry(); 061 filter.setColumnName("eventId"); 062 filter.setOperator("="); 063 filter.setQueryParameterName("eventId"); 064 filter.setObject(DocumentEventTypes.DOCUMENT_CREATED); 065 Map<String, FilterMapEntry> filters = new HashMap<String, FilterMapEntry>(); 066 filters.put("eventId", filter); 067 List<LogEntry> entries = reader.getLogEntriesFor(uuid, filters, false); 068 AdditionalDocumentAuditParams result; 069 if (entries != null && entries.size() > 0) { 070 result = new AdditionalDocumentAuditParams(); 071 result.maxDate = entries.get(0).getEventDate(); 072 result.targetUUID = targetUUID; 073 result.eventId = entries.get(0).getId(); 074 } else { 075 // we have no entry in audit log to get the maxDate 076 // fallback to repository timestamp 077 // this code is here only for compatibility so that it works before version events were added to 078 // the audit log 079 if (doc.getPropertyValue("dc:modified") == null) { 080 return null; 081 } 082 result = new AdditionalDocumentAuditParams(); 083 Calendar estimatedDate = ((Calendar) doc.getPropertyValue("dc:modified")); 084 085 // We can not directly use the repo timestamp because Audit and VCS can be in separated DB 086 // => try to find the matching TS in Audit 087 StringBuilder queryString = new StringBuilder(); 088 queryString.append("from LogEntry log where log.docUUID in ("); 089 queryString.append("'" + targetUUID + "'"); 090 if (doc.isVersion()) { 091 DocumentModelList proxies = session.getProxies(doc.getRef(), null); 092 for (DocumentModel proxy : proxies) { 093 queryString.append(",'" + proxy.getId() + "'"); 094 } 095 } 096 queryString.append(",'" + doc.getId() + "'"); 097 queryString.append(") AND log.eventId IN ("); 098 queryString.append("'" + DocumentEventTypes.DOCUMENT_CREATED + "'"); 099 queryString.append(",'" + DocumentEventTypes.DOCUMENT_CHECKEDIN + "'"); 100 queryString.append(") AND log.eventDate >= :minDate "); 101 queryString.append(" order by log.eventId asc"); 102 103 estimatedDate.add(Calendar.MILLISECOND, -500); 104 Map<String, Object> params = new HashMap<String, Object>(); 105 params.put("minDate", estimatedDate.getTime()); 106 107 List<LogEntry> dateEntries = (List<LogEntry>) reader.nativeQuery(queryString.toString(), 108 params, 0, 20); 109 if (dateEntries.size() > 0) { 110 result.targetUUID = targetUUID; 111 Calendar maxDate = new GregorianCalendar(); 112 maxDate.setTime(dateEntries.get(0).getEventDate()); 113 maxDate.add(Calendar.MILLISECOND, -500); 114 result.maxDate = maxDate.getTime(); 115 } else { 116 // no other choice : use the VCS TS 117 // results may be truncated in some DB config 118 result.targetUUID = targetUUID; 119 result.maxDate = ((Calendar) doc.getPropertyValue("dc:modified")).getTime(); 120 } 121 } 122 return result; 123 } 124 125}