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