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