001/* 002 * (C) Copyright 2006-2018 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 * Nuxeo - initial API and implementation 018 */ 019package org.nuxeo.ecm.platform.audit.service; 020 021import static org.nuxeo.ecm.platform.audit.listener.StreamAuditEventListener.STREAM_AUDIT_ENABLED_PROP; 022 023import java.util.ArrayList; 024import java.util.HashMap; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Map; 028import java.util.Map.Entry; 029import java.util.Set; 030 031import org.apache.logging.log4j.LogManager; 032import org.apache.logging.log4j.Logger; 033import org.nuxeo.ecm.platform.audit.api.AuditStorage; 034import org.nuxeo.ecm.platform.audit.api.DocumentHistoryReader; 035import org.nuxeo.ecm.platform.audit.api.document.DocumentHistoryReaderImpl; 036import org.nuxeo.ecm.platform.audit.service.extension.AdapterDescriptor; 037import org.nuxeo.ecm.platform.audit.service.extension.AuditBackendDescriptor; 038import org.nuxeo.ecm.platform.audit.service.extension.AuditBulkerDescriptor; 039import org.nuxeo.ecm.platform.audit.service.extension.AuditStorageDescriptor; 040import org.nuxeo.ecm.platform.audit.service.extension.EventDescriptor; 041import org.nuxeo.ecm.platform.audit.service.extension.ExtendedInfoDescriptor; 042import org.nuxeo.runtime.RuntimeMessage.Level; 043import org.nuxeo.runtime.RuntimeMessage.Source; 044import org.nuxeo.runtime.api.Framework; 045import org.nuxeo.runtime.logging.DeprecationLogger; 046import org.nuxeo.runtime.model.ComponentContext; 047import org.nuxeo.runtime.model.ComponentInstance; 048import org.nuxeo.runtime.model.ComponentManager; 049import org.nuxeo.runtime.model.ComponentManager.Listener; 050import org.nuxeo.runtime.model.ComponentName; 051import org.nuxeo.runtime.model.DefaultComponent; 052 053/** 054 * Event service configuration. 055 * 056 * @author <a href="mailto:ja@nuxeo.com">Julien Anguenot</a> 057 */ 058public class NXAuditEventsService extends DefaultComponent { 059 060 public static final ComponentName NAME = new ComponentName( 061 "org.nuxeo.ecm.platform.audit.service.NXAuditEventsService"); 062 063 private static final String EVENT_EXT_POINT = "event"; 064 065 private static final String EXTENDED_INFO_EXT_POINT = "extendedInfo"; 066 067 private static final String ADAPTER_POINT = "adapter"; 068 069 /** 070 * If passed as true on the event properties, event not logged 071 * 072 * @since 5.7 073 */ 074 public static final String DISABLE_AUDIT_LOGGER = "disableAuditLogger"; 075 076 protected static final Logger log = LogManager.getLogger(NXAuditEventsService.class); 077 078 protected final Set<ExtendedInfoDescriptor> extendedInfoDescriptors = new HashSet<>(); 079 080 protected final Map<String, List<ExtendedInfoDescriptor>> eventExtendedInfoDescriptors = new HashMap<>(); 081 082 // the adapters that will injected in the EL context for extended 083 // information 084 protected final Set<AdapterDescriptor> documentAdapters = new HashSet<>(); 085 086 protected final Set<String> eventNames = new HashSet<>(); 087 088 protected AuditBackend backend; 089 090 protected AuditBackendDescriptor backendConfig = new AuditBackendDescriptor(); 091 092 /** 093 * @deprecated since 10.10, audit bulker is now handled with nuxeo-stream, no replacement 094 */ 095 @Deprecated 096 protected AuditBulker bulker; 097 098 /** 099 * @deprecated since 10.10, audit bulker is now handled with nuxeo-stream, no replacement 100 */ 101 @Deprecated 102 protected AuditBulkerDescriptor bulkerConfig = new AuditBulkerDescriptor(); 103 104 protected Map<String, AuditStorageDescriptor> auditStorageDescriptors = new HashMap<>(); 105 106 protected Map<String, AuditStorage> auditStorages = new HashMap<>(); 107 108 @Override 109 public int getApplicationStartedOrder() { 110 return backendConfig.getApplicationStartedOrder(); 111 } 112 113 @Override 114 @SuppressWarnings("deprecation") 115 public void start(ComponentContext context) { 116 backend = backendConfig.newInstance(this); 117 backend.onApplicationStarted(); 118 if (Framework.isBooleanPropertyFalse(STREAM_AUDIT_ENABLED_PROP)) { 119 bulker = bulkerConfig.newInstance(backend); 120 bulker.onApplicationStarted(); 121 } 122 // init storages after runtime was started (as we don't have started order for storages which are backends) 123 Framework.getRuntime().getComponentManager().addListener(new Listener() { 124 125 @Override 126 public void afterStart(ComponentManager mgr, boolean isResume) { 127 for (Entry<String, AuditStorageDescriptor> descriptor : auditStorageDescriptors.entrySet()) { 128 AuditStorage storage = descriptor.getValue().newInstance(); 129 if (storage instanceof AuditBackend) { 130 ((AuditBackend) storage).onApplicationStarted(); 131 } 132 auditStorages.put(descriptor.getKey(), storage); 133 } 134 } 135 136 @Override 137 public void afterStop(ComponentManager mgr, boolean isStandby) { 138 uninstall(); 139 } 140 141 }); 142 } 143 144 @Override 145 @SuppressWarnings("deprecation") 146 public void stop(ComponentContext context) { 147 try { 148 if (bulker != null) { 149 bulker.onApplicationStopped(); 150 } 151 } finally { 152 backend.onApplicationStopped(); 153 // clear storages 154 auditStorages.values().forEach(storage -> { 155 if (storage instanceof AuditBackend) { 156 ((AuditBackend) storage).onApplicationStopped(); 157 } 158 }); 159 auditStorages.clear(); 160 } 161 } 162 163 protected void doRegisterAdapter(AdapterDescriptor desc) { 164 log.debug("Registered adapter : {}", desc::getName); 165 documentAdapters.add(desc); 166 } 167 168 protected void doRegisterEvent(EventDescriptor desc) { 169 String eventName = desc.getName(); 170 if (desc.getEnabled()) { 171 eventNames.add(eventName); 172 log.debug("Registered event: {}", eventName); 173 for (ExtendedInfoDescriptor extInfoDesc : desc.getExtendedInfoDescriptors()) { 174 if (extInfoDesc.getEnabled()) { 175 if (eventExtendedInfoDescriptors.containsKey(eventName)) { 176 eventExtendedInfoDescriptors.get(eventName).add(extInfoDesc); 177 } else { 178 List<ExtendedInfoDescriptor> toBeAdded = new ArrayList<>(); 179 toBeAdded.add(extInfoDesc); 180 eventExtendedInfoDescriptors.put(eventName, toBeAdded); 181 } 182 } else { 183 if (eventExtendedInfoDescriptors.containsKey(eventName)) { 184 eventExtendedInfoDescriptors.get(eventName).remove(extInfoDesc); 185 } 186 } 187 } 188 } else if (eventNames.contains(eventName)) { 189 doUnregisterEvent(desc); 190 } 191 } 192 193 protected void doRegisterExtendedInfo(ExtendedInfoDescriptor desc) { 194 log.debug("Registered extended info mapping : {}", desc::getKey); 195 extendedInfoDescriptors.add(desc); 196 } 197 198 protected void doUnregisterAdapter(AdapterDescriptor desc) { 199 // FIXME: this doesn't look right 200 documentAdapters.remove(desc); 201 log.debug("Unregistered adapter: {}", desc::getName); 202 } 203 204 protected void doUnregisterEvent(EventDescriptor desc) { 205 eventNames.remove(desc.getName()); 206 eventExtendedInfoDescriptors.remove(desc.getName()); 207 log.debug("Unregistered event: {}", desc::getName); 208 } 209 210 protected void doUnregisterExtendedInfo(ExtendedInfoDescriptor desc) { 211 // FIXME: this doesn't look right 212 extendedInfoDescriptors.remove(desc); 213 log.debug("Unregistered extended info: {}", desc::getKey); 214 } 215 216 @Override 217 public <T> T getAdapter(Class<T> adapter) { 218 if (adapter == NXAuditEventsService.class) { 219 return adapter.cast(this); 220 } else if (adapter.getCanonicalName().equals(DocumentHistoryReader.class.getCanonicalName())) { 221 return adapter.cast(new DocumentHistoryReaderImpl()); 222 } else { 223 if (backend != null) { 224 return adapter.cast(backend); 225 } else { 226 log.error("Can not provide service {} since backend is undefined", adapter::getCanonicalName); 227 return null; 228 } 229 } 230 } 231 232 public Set<String> getAuditableEventNames() { 233 return eventNames; 234 } 235 236 public AuditBackend getBackend() { 237 return backend; 238 } 239 240 public Set<AdapterDescriptor> getDocumentAdapters() { 241 return documentAdapters; 242 } 243 244 /** 245 * @since 7.4 246 */ 247 public Map<String, List<ExtendedInfoDescriptor>> getEventExtendedInfoDescriptors() { 248 return eventExtendedInfoDescriptors; 249 } 250 251 public Set<ExtendedInfoDescriptor> getExtendedInfoDescriptors() { 252 return extendedInfoDescriptors; 253 } 254 255 @Override 256 @SuppressWarnings("deprecation") 257 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 258 if (extensionPoint.equals(EVENT_EXT_POINT)) { 259 doRegisterEvent((EventDescriptor) contribution); 260 } else if (extensionPoint.equals(EXTENDED_INFO_EXT_POINT)) { 261 doRegisterExtendedInfo((ExtendedInfoDescriptor) contribution); 262 } else if (extensionPoint.equals(ADAPTER_POINT)) { 263 doRegisterAdapter((AdapterDescriptor) contribution); 264 } else if (contribution instanceof AuditBackendDescriptor) { 265 backendConfig = (AuditBackendDescriptor) contribution; 266 } else if (contribution instanceof AuditBulkerDescriptor) { 267 bulkerConfig = (AuditBulkerDescriptor) contribution; 268 ComponentName compName = contributor.getName(); 269 String message = String.format( 270 "AuditBulker on component %s is deprecated because it is now handled with nuxeo-stream, no replacement.", 271 compName); 272 DeprecationLogger.log(message, "10.10"); 273 addRuntimeMessage(Level.WARNING, message, Source.EXTENSION, compName.getName()); 274 } else if (contribution instanceof AuditStorageDescriptor) { 275 AuditStorageDescriptor auditStorageDesc = (AuditStorageDescriptor) contribution; 276 auditStorageDescriptors.put(auditStorageDesc.getId(), auditStorageDesc); 277 } 278 } 279 280 @Override 281 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 282 if (extensionPoint.equals(EVENT_EXT_POINT)) { 283 doUnregisterEvent((EventDescriptor) contribution); 284 } else if (extensionPoint.equals(EXTENDED_INFO_EXT_POINT)) { 285 doUnregisterExtendedInfo((ExtendedInfoDescriptor) contribution); 286 } else if (extensionPoint.equals(ADAPTER_POINT)) { 287 doUnregisterAdapter((AdapterDescriptor) contribution); 288 } 289 } 290 291 /** 292 * @since 9.3 293 */ 294 public AuditStorage getAuditStorage(String id) { 295 return auditStorages.get(id); 296 } 297 298}