001/* 002 * (C) Copyright 2006-2007 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 * 016 * 017 * $Id: $ 018 */ 019package org.nuxeo.ecm.platform.audit.io; 020 021import java.io.ByteArrayInputStream; 022import java.io.ByteArrayOutputStream; 023import java.io.IOException; 024import java.io.InputStream; 025import java.io.OutputStream; 026import java.text.DateFormat; 027import java.text.ParseException; 028import java.text.SimpleDateFormat; 029import java.util.ArrayList; 030import java.util.Date; 031import java.util.Iterator; 032import java.util.List; 033 034import org.apache.commons.beanutils.BeanUtils; 035import org.apache.commons.logging.Log; 036import org.apache.commons.logging.LogFactory; 037import org.dom4j.Document; 038import org.dom4j.DocumentException; 039import org.dom4j.DocumentFactory; 040import org.dom4j.Element; 041import org.dom4j.io.OutputFormat; 042import org.dom4j.io.SAXReader; 043import org.dom4j.io.XMLWriter; 044import org.nuxeo.common.utils.FileUtils; 045import org.nuxeo.ecm.core.api.DocumentRef; 046import org.nuxeo.ecm.core.api.NuxeoException; 047import org.nuxeo.ecm.platform.audit.api.AuditLogger; 048import org.nuxeo.ecm.platform.audit.api.LogEntry; 049import org.nuxeo.runtime.api.Framework; 050 051/** 052 * Audit log entry importer/exporter. 053 * <p> 054 * Could be overridden to externalize additional information of a redefined LogEntry. 055 * 056 * @author DM 057 */ 058// FIXME: design issue - this is a utility class (only static methods) with no subclasses (misleading name). 059public class IOLogEntryBase { 060 061 private static final Log log = LogFactory.getLog(IOLogEntryBase.class); 062 063 public static final String DOCUMENT_TAG = "documentLogs"; 064 065 public static final String LOGENTRY_TAG = "logEntry"; 066 067 public static void write(List<LogEntry> logEntries, OutputStream out) throws IOException { 068 Document jdoc = writeDocument(logEntries); 069 writeXML(jdoc, out); 070 } 071 072 private static Document writeDocument(List<LogEntry> logEntries) { 073 Document document = DocumentFactory.getInstance().createDocument(); 074 document.setName("logEntries"); 075 076 Element rootElement = document.addElement(DOCUMENT_TAG); 077 for (LogEntry logEntry : logEntries) { 078 Element logEntryElement = rootElement.addElement(LOGENTRY_TAG); 079 writeLogEntry(logEntryElement, logEntry); 080 } 081 082 return document; 083 } 084 085 /** 086 * Could be overridden to put other (additional) data. 087 */ 088 protected static void writeLogEntry(Element logEntryElement, LogEntry logEntry) { 089 logEntryElement.addAttribute("category", logEntry.getCategory()); 090 logEntryElement.addAttribute("comment", logEntry.getComment()); 091 logEntryElement.addAttribute("docLifeCycle", logEntry.getDocLifeCycle()); 092 logEntryElement.addAttribute("docPath", logEntry.getDocPath()); 093 logEntryElement.addAttribute("docType", logEntry.getDocType()); 094 logEntryElement.addAttribute("docUUID", logEntry.getDocUUID()); 095 logEntryElement.addAttribute("repoId", logEntry.getRepositoryId()); 096 097 String creationDate = getDateFormat().format(logEntry.getEventDate()); 098 logEntryElement.addAttribute("creationDate", creationDate); 099 logEntryElement.addAttribute("eventId", logEntry.getEventId()); 100 logEntryElement.addAttribute("principalName", logEntry.getPrincipalName()); 101 } 102 103 public static List<LogEntry> read(InputStream in) throws IOException { 104 Document jDoc = loadXML(in); 105 return readDocument(jDoc); 106 } 107 108 /** 109 * Will translate from a jdoc to a list of LogEntry objects. 110 */ 111 @SuppressWarnings({ "unchecked" }) 112 protected static List<LogEntry> readDocument(Document doc) { 113 List<LogEntry> logEntries = new ArrayList<LogEntry>(); 114 115 AuditLogger audit = Framework.getLocalService(AuditLogger.class); 116 117 Element rootElement = doc.getRootElement(); 118 Iterator<Element> it = rootElement.elementIterator(); 119 while (it.hasNext()) { 120 Element logEntryElement = it.next(); 121 122 LogEntry logEntry = readLogEntry(audit, logEntryElement); 123 logEntries.add(logEntry); 124 } 125 126 return logEntries; 127 } 128 129 /** 130 * Could be overridden to get other (additional) data. 131 * 132 * @param logEntryElement 133 */ 134 protected static LogEntry readLogEntry(AuditLogger audit, Element logEntryElement) { 135 LogEntry logEntry = audit.newLogEntry(); 136 137 logEntry.setCategory(logEntryElement.attributeValue("category")); 138 logEntry.setComment(logEntryElement.attributeValue("comment")); 139 logEntry.setDocLifeCycle(logEntryElement.attributeValue("docLifeCycle")); 140 logEntry.setDocPath(logEntryElement.attributeValue("docPath")); 141 logEntry.setDocType(logEntryElement.attributeValue("docType")); 142 logEntry.setDocUUID(logEntryElement.attributeValue("docUUID")); 143 logEntry.setRepositoryId(logEntryElement.attributeValue("repoId")); 144 145 try { 146 Date creationDate = getDateFormat().parse(logEntryElement.attributeValue("creationDate")); 147 logEntry.setEventDate(creationDate); 148 } catch (ParseException e) { 149 log.error(e, e); 150 } 151 logEntry.setEventId(logEntryElement.attributeValue("eventId")); 152 logEntry.setPrincipalName(logEntryElement.attributeValue("principalName")); 153 154 return logEntry; 155 } 156 157 /** 158 * Specifies date-string conversion. 159 */ 160 protected static DateFormat getDateFormat() { 161 return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 162 } 163 164 protected static void writeXML(Document doc, OutputStream out) throws IOException { 165 OutputFormat format = OutputFormat.createPrettyPrint(); 166 XMLWriter writer = new XMLWriter(out, format); 167 writer.write(doc); 168 } 169 170 private static Document loadXML(InputStream in) throws IOException { 171 try { 172 // the SAXReader is closing the stream so that we need to copy the 173 // content somewhere 174 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 175 FileUtils.copy(in, baos); 176 return new SAXReader().read(new ByteArrayInputStream(baos.toByteArray())); 177 } catch (DocumentException e) { 178 IOException ioe = new IOException("Failed to read log entry " + ": " + e.getMessage()); 179 ioe.setStackTrace(e.getStackTrace()); 180 throw ioe; 181 } 182 } 183 184 public static List<LogEntry> translate(List<LogEntry> docLogs, DocumentRef newRef) { 185 List<LogEntry> newList = new ArrayList<LogEntry>(); 186 for (LogEntry logEntry : docLogs) { 187 LogEntry newLogEntry = translate(logEntry, newRef); 188 newList.add(newLogEntry); 189 } 190 return newList; 191 } 192 193 /** 194 * Should be overridden if log data structure is changed. 195 */ 196 private static LogEntry translate(LogEntry logEntry, DocumentRef newRef) { 197 LogEntry newLogEntry; 198 try { 199 newLogEntry = (LogEntry) BeanUtils.cloneBean(logEntry); 200 } catch (ReflectiveOperationException e) { 201 throw new NuxeoException("cannot clone bean " + logEntry, e); 202 } 203 newLogEntry.setDocUUID(newRef); 204 return newLogEntry; 205 } 206 207}