001/* 002 * (C) Copyright 2020 Nuxeo (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 * bdelbosc 018 */ 019package org.nuxeo.ecm.platform.audit.stream; 020 021import java.util.ArrayList; 022import java.util.List; 023import java.util.Map; 024 025import org.apache.logging.log4j.LogManager; 026import org.apache.logging.log4j.Logger; 027import org.nuxeo.ecm.core.event.Event; 028import org.nuxeo.ecm.core.event.stream.DomainEventProducer; 029import org.nuxeo.ecm.platform.audit.api.AuditLogger; 030import org.nuxeo.ecm.platform.audit.api.ExtendedInfo; 031import org.nuxeo.ecm.platform.audit.api.LogEntry; 032import org.nuxeo.lib.stream.codec.Codec; 033import org.nuxeo.lib.stream.computation.Record; 034import org.nuxeo.runtime.api.Framework; 035import org.nuxeo.runtime.codec.CodecService; 036 037import com.fasterxml.jackson.core.JsonProcessingException; 038import com.fasterxml.jackson.databind.ObjectMapper; 039 040/** 041 * Audit domain event producer. 042 * 043 * @since 11.4 044 */ 045public class AuditDomainEventProducer extends DomainEventProducer { 046 047 protected static final Logger log = LogManager.getLogger(AuditDomainEventProducer.class); 048 049 protected static final String SOURCE_NAME = "ADEP"; // Audit Domain Event Producer 050 051 protected static final ObjectMapper MAPPER = new ObjectMapper(); 052 053 protected static final String CODEC_NAME = "avroBinary"; 054 055 protected final List<Record> records = new ArrayList<>(); 056 057 protected final Codec<AuditDomainEvent> codec; 058 059 public AuditDomainEventProducer(String name, String stream) { 060 super(name, stream); 061 codec = Framework.getService(CodecService.class).getCodec(CODEC_NAME, AuditDomainEvent.class); 062 } 063 064 @Override 065 public void addEvent(Event event) { 066 AuditLogger logger = Framework.getService(AuditLogger.class); 067 if (logger == null || event == null) { 068 return; 069 } 070 if (logger.getAuditableEventNames().contains(event.getName())) { 071 LogEntry entry = logger.buildEntryFromEvent(event); 072 if (entry != null) { 073 records.add(buildRecordFromEvent(entry)); 074 } 075 } 076 } 077 078 protected Record buildRecordFromEvent(LogEntry entry) { 079 AuditDomainEvent event = new AuditDomainEvent(); 080 // entry.getId() is always null at this stage 081 // entry.logDate is always null at this stage 082 event.source = SOURCE_NAME; 083 event.name = entry.getEventId(); 084 event.category = entry.getCategory(); 085 event.docId = entry.getDocUUID(); 086 event.docRepository = entry.getRepositoryId(); 087 event.principalName = entry.getPrincipalName(); 088 event.docLifeCycle = entry.getDocLifeCycle(); 089 event.docType = entry.getDocType(); 090 event.docPath = entry.getDocPath(); 091 event.comment = entry.getComment(); 092 if (entry.getEventDate() != null) { 093 event.date = entry.getEventDate().getTime(); 094 } 095 Map<String, ExtendedInfo> extended = entry.getExtendedInfos(); 096 if (extended != null && !extended.isEmpty()) { 097 try { 098 event.extendedInfoAsJson = MAPPER.writeValueAsString(extended); 099 } catch (JsonProcessingException e) { 100 log.error("Skip invalid extended info: {}", event, e); 101 } 102 } 103 log.debug("event {} -> {}", entry, event); 104 return Record.of(event.name, codec.encode(event)); 105 } 106 107 @Override 108 public List<Record> getDomainEvents() { 109 return records; 110 } 111}