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