/* * (C) Copyright 2006-2007 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:ContentHistoryActionsBean.java 4487 2006-10-19 22:27:14Z janguenot $ */ package org.nuxeo.ecm.platform.audit.web.listener.ejb; import static org.jboss.seam.ScopeType.EVENT; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.seam.annotations.Factory; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.web.RequestParameter; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.NuxeoException; import org.nuxeo.ecm.core.api.SortInfo; import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner; import org.nuxeo.ecm.core.api.event.DocumentEventTypes; import org.nuxeo.ecm.platform.audit.api.BuiltinLogEntryData; import org.nuxeo.ecm.platform.audit.api.FilterMapEntry; import org.nuxeo.ecm.platform.audit.api.LogEntry; import org.nuxeo.ecm.platform.audit.api.Logs; import org.nuxeo.ecm.platform.audit.api.comment.CommentProcessorHelper; import org.nuxeo.ecm.platform.audit.api.comment.LinkedDocument; import org.nuxeo.ecm.platform.audit.web.listener.ContentHistoryActions; import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; import org.nuxeo.runtime.api.Framework; /** * Content history actions bean. * <p> * :XXX: http://jira.nuxeo.org/browse/NXP-514 * * @author <a href="mailto:ja@nuxeo.com">Julien Anguenot</a> */ @Name("contentHistoryActions") @Scope(EVENT) public class ContentHistoryActionsBean implements ContentHistoryActions { private static final long serialVersionUID = -6110545879809627627L; private static final String EVENT_DATE = "eventDate"; private static final Log log = LogFactory.getLog(ContentHistoryActionsBean.class); // @Out(required = false) protected List<LogEntry> logEntries; private Map<Long, String> logEntriesComments; private Map<Long, LinkedDocument> logEntriesLinkedDocs; // :FIXME: Should disappear with Seam 1.1 method params. // @Out(required = false) private List<LogEntry> latestLogEntries; // :FIXME: Hardcoded. See interface for more details about the reason protected final int nbLogEntries = 5; @In(create = true, required = false) protected transient CoreSession documentManager; @In(create = true) private transient NavigationContext navigationContext; @RequestParameter("sortColumn") protected String newSortColumn; protected SortInfo sortInfo; protected Map<String, FilterMapEntry> filterMap = Collections.emptyMap(); protected Comparator<LogEntry> comparator; public ContentHistoryActionsBean() { // init sorting information sortInfo = new SortInfo(EVENT_DATE, false); } @Factory(value = "latestLogEntries", scope = EVENT) public List<LogEntry> computeLatestLogEntries() { if (latestLogEntries == null) { if (logEntries == null) { logEntries = computeLogEntries(navigationContext.getCurrentDocument()); } if (logEntries != null) { if (logEntries.size() > nbLogEntries) { latestLogEntries = new ArrayList<LogEntry>(logEntries.subList(0, nbLogEntries)); } else { latestLogEntries = logEntries; } } } return latestLogEntries; } @Factory(value = "logEntries", scope = EVENT) public List<LogEntry> computeLogEntries() { if (logEntries == null) { logEntries = computeLogEntries(navigationContext.getCurrentDocument()); } return logEntries; } @Factory(value = "logEntriesComments", scope = EVENT) public Map<Long, String> computeLogEntriesComments() { if (logEntriesComments == null) { computeLogEntries(); postProcessComments(logEntries); } return logEntriesComments; } @Factory(value = "logEntriesLinkedDocs", scope = EVENT) public Map<Long, LinkedDocument> computeLogEntrieslinkedDocs() { if (logEntriesLinkedDocs == null) { computeLogEntries(); postProcessComments(logEntries); } return logEntriesLinkedDocs; } public List<LogEntry> computeLogEntries(DocumentModel document) { if (document == null) { return null; } else { Logs service = Framework.getLocalService(Logs.class); Logs logsBean = service; /* * In case the document is a proxy,meaning is the result of a publishing,to have the history of the document * from which this proxy was created,first we have to get to the version that was created when the document * was publish,and to which the proxy document indicates,and then from that version we have to get to the * root document. */ boolean doDefaultSort = comparator == null; if (document.isProxy()) { // all users should have access to logs GetVersionInfoForDocumentRunner runner = new GetVersionInfoForDocumentRunner(documentManager, document); runner.runUnrestricted(); if (runner.sourceDocForVersionId == null || runner.version == null) { String message = "An error occurred while grabbing log entries for " + document.getId(); throw new NuxeoException(message); } Date versionCreationDate = getCreationDateForVersion(logsBean, runner.version); // add all the logs from the source document until the // version was created addLogEntries(getLogsForDocUntilDate(logsBean, runner.sourceDocForVersionId, versionCreationDate, doDefaultSort)); // !! add the first publishing // event after the version is created; since the publishing // event is logged few milliseconds after the version is // created List<LogEntry> publishingLogs = getLogsForDocUntilDateWithEvent(logsBean, runner.sourceDocForVersionId, versionCreationDate, DocumentEventTypes.DOCUMENT_PUBLISHED, doDefaultSort); if (!publishingLogs.isEmpty()) { addLogEntry(publishingLogs.get(0)); } // add logs from the actual version filterMap = new HashMap<String, FilterMapEntry>(); addLogEntries(logsBean.getLogEntriesFor(runner.version.getId(), filterMap, doDefaultSort)); } else { addLogEntries(logsBean.getLogEntriesFor(document.getId(), filterMap, doDefaultSort)); } if (log.isDebugEnabled()) { log.debug("logEntries computed .................!"); } return logEntries; } } public String doSearch() { // toggle newOrderDirection if (StringUtils.isEmpty(newSortColumn)) { newSortColumn = EVENT_DATE; } String sortColumn = sortInfo.getSortColumn(); boolean sortAscending = sortInfo.getSortAscending(); if (newSortColumn.equals(sortColumn)) { sortAscending = !sortAscending; } else { sortColumn = newSortColumn; sortAscending = true; } sortInfo = new SortInfo(sortColumn, sortAscending); logEntries = null; return null; } /** * Post-process log entries comments to add links. e5e7b4ba-0ffb-492d-8bf2-f2f2e6683ae2 */ private void postProcessComments(List<LogEntry> logEntries) { logEntriesComments = new HashMap<Long, String>(); logEntriesLinkedDocs = new HashMap<Long, LinkedDocument>(); CommentProcessorHelper cph = new CommentProcessorHelper(documentManager); if (logEntries == null) { return; } for (LogEntry entry : logEntries) { logEntriesComments.put(entry.getId(), cph.getLogComment(entry)); LinkedDocument linkedDoc = cph.getLogLinkedDocument(entry); if (linkedDoc != null) { logEntriesLinkedDocs.put(entry.getId(), linkedDoc); } } } public SortInfo getSortInfo() { return sortInfo; } private Date getCreationDateForVersion(Logs logsService, DocumentModel version) { List<LogEntry> logs = logsService.getLogEntriesFor(version.getId(), filterMap, true); for (LogEntry logEntry : logs) { if (logEntry.getEventId().equals(DocumentEventTypes.DOCUMENT_CREATED)) { return logEntry.getEventDate(); } } return null; } private void addLogEntries(List<LogEntry> entries) { if (logEntries != null) { logEntries.addAll(entries); } else { logEntries = entries; } } private void addLogEntry(LogEntry entry) { if (logEntries != null) { logEntries.add(entry); } else { logEntries = new ArrayList<LogEntry>(); logEntries.add(entry); } } private static FilterMapEntry computeQueryForLogsOnDocUntilDate(Date date) { FilterMapEntry filterByDate = new FilterMapEntry(); filterByDate.setColumnName(BuiltinLogEntryData.LOG_EVENT_DATE); filterByDate.setOperator("<="); filterByDate.setQueryParameterName(BuiltinLogEntryData.LOG_EVENT_DATE); filterByDate.setObject(date); return filterByDate; } private static FilterMapEntry computeQueryForLogsOnDocAfterDate(Date date) { FilterMapEntry filterByDate = new FilterMapEntry(); filterByDate.setColumnName(BuiltinLogEntryData.LOG_EVENT_DATE); filterByDate.setOperator(">="); filterByDate.setQueryParameterName(BuiltinLogEntryData.LOG_EVENT_DATE); filterByDate.setObject(date); return filterByDate; } private static FilterMapEntry computeQueryForLogsWithEvent(String eventName) { FilterMapEntry filterByDate = new FilterMapEntry(); filterByDate.setColumnName(BuiltinLogEntryData.LOG_EVENT_ID); filterByDate.setOperator("LIKE"); filterByDate.setQueryParameterName(BuiltinLogEntryData.LOG_EVENT_ID); filterByDate.setObject(eventName); return filterByDate; } private List<LogEntry> getLogsForDocUntilDate(Logs logsService, String docId, Date date, boolean doDefaultSort) { filterMap = new HashMap<String, FilterMapEntry>(); filterMap.put(BuiltinLogEntryData.LOG_EVENT_DATE, computeQueryForLogsOnDocUntilDate(date)); return logsService.getLogEntriesFor(docId, filterMap, doDefaultSort); } private List<LogEntry> getLogsForDocUntilDateWithEvent(Logs logsService, String docId, Date date, String eventName, boolean doDefaultSort) { filterMap = new HashMap<String, FilterMapEntry>(); filterMap.put(BuiltinLogEntryData.LOG_EVENT_DATE, computeQueryForLogsOnDocAfterDate(date)); filterMap.put(BuiltinLogEntryData.LOG_EVENT_ID, computeQueryForLogsWithEvent(eventName)); return logsService.getLogEntriesFor(docId, filterMap, doDefaultSort); } private class GetVersionInfoForDocumentRunner extends UnrestrictedSessionRunner { public String sourceDocForVersionId; public DocumentModel version; DocumentModel document; public GetVersionInfoForDocumentRunner(CoreSession session, DocumentModel document) { super(session); this.document = document; } @Override public void run() { version = documentManager.getSourceDocument(document.getRef()); if (version != null) { sourceDocForVersionId = session.getSourceDocument(version.getRef()).getId(); } } } }