001/*
002 * (C) Copyright 2006-2016 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 *     Nuxeo - initial API and implementation
018 *
019 * $Id$
020 */
021
022package org.nuxeo.ecm.platform.audit.service;
023
024import java.util.ArrayList;
025import java.util.HashMap;
026import java.util.HashSet;
027import java.util.List;
028import java.util.Map;
029import java.util.Set;
030
031import org.apache.commons.logging.Log;
032import org.apache.commons.logging.LogFactory;
033import org.nuxeo.ecm.platform.audit.api.DocumentHistoryReader;
034import org.nuxeo.ecm.platform.audit.api.document.DocumentHistoryReaderImpl;
035import org.nuxeo.ecm.platform.audit.service.extension.AdapterDescriptor;
036import org.nuxeo.ecm.platform.audit.service.extension.AuditBackendDescriptor;
037import org.nuxeo.ecm.platform.audit.service.extension.AuditBulkerDescriptor;
038import org.nuxeo.ecm.platform.audit.service.extension.EventDescriptor;
039import org.nuxeo.ecm.platform.audit.service.extension.ExtendedInfoDescriptor;
040import org.nuxeo.runtime.RuntimeServiceEvent;
041import org.nuxeo.runtime.RuntimeServiceListener;
042import org.nuxeo.runtime.api.Framework;
043import org.nuxeo.runtime.model.ComponentContext;
044import org.nuxeo.runtime.model.ComponentInstance;
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<ExtendedInfoDescriptor>();
076
077    protected final Map<String, List<ExtendedInfoDescriptor>> eventExtendedInfoDescriptors = new HashMap<String, List<ExtendedInfoDescriptor>>();
078
079    // the adapters that will injected in the EL context for extended
080    // information
081    protected final Set<AdapterDescriptor> documentAdapters = new HashSet<AdapterDescriptor>();
082
083    protected final Set<String> eventNames = new HashSet<String>();
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    @Override
094    public int getApplicationStartedOrder() {
095        return backendConfig.getApplicationStartedOrder();
096    }
097
098    @Override
099    public void applicationStarted(ComponentContext context) {
100        backend = backendConfig.newInstance(this);
101        backend.onApplicationStarted();
102        bulker = bulkerConfig.newInstance(backend);
103        bulker.onApplicationStarted();
104        Framework.addListener(new RuntimeServiceListener() {
105
106            @Override
107            public void handleEvent(RuntimeServiceEvent event) {
108                if (event.id != RuntimeServiceEvent.RUNTIME_STOPPED) {
109                    return;
110                }
111                Framework.removeListener(this);
112                try {
113                    backend.onShutdown();
114                } finally {
115                    try {
116                        bulker.onShutdown();
117                    } finally {
118                        bulker = null;
119                    }
120                    backend = null;
121                }
122            }
123        });
124    }
125
126    protected void doRegisterAdapter(AdapterDescriptor desc) {
127        if (log.isDebugEnabled()) {
128            log.debug("Registered adapter : " + desc.getName());
129        }
130        documentAdapters.add(desc);
131    }
132
133    protected void doRegisterEvent(EventDescriptor desc) {
134        String eventName = desc.getName();
135        boolean eventEnabled = desc.getEnabled();
136        if (eventEnabled) {
137            eventNames.add(eventName);
138            if (log.isDebugEnabled()) {
139                log.debug("Registered event: " + eventName);
140            }
141            for (ExtendedInfoDescriptor extInfoDesc : desc.getExtendedInfoDescriptors()) {
142                if (extInfoDesc.getEnabled()) {
143                    if (eventExtendedInfoDescriptors.containsKey(eventName)) {
144                        eventExtendedInfoDescriptors.get(eventName).add(extInfoDesc);
145                    } else {
146                        List<ExtendedInfoDescriptor> toBeAdded = new ArrayList<ExtendedInfoDescriptor>();
147                        toBeAdded.add(extInfoDesc);
148                        eventExtendedInfoDescriptors.put(eventName, toBeAdded);
149                    }
150                } else {
151                    if (eventExtendedInfoDescriptors.containsKey(eventName)) {
152                        eventExtendedInfoDescriptors.get(eventName).remove(extInfoDesc);
153                    }
154                }
155            }
156        } else if (eventNames.contains(eventName) && !eventEnabled) {
157            doUnregisterEvent(desc);
158        }
159    }
160
161    protected void doRegisterExtendedInfo(ExtendedInfoDescriptor desc) {
162        if (log.isDebugEnabled()) {
163            log.debug("Registered extended info mapping : " + desc.getKey());
164        }
165        extendedInfoDescriptors.add(desc);
166    }
167
168    protected void doUnregisterAdapter(AdapterDescriptor desc) {
169        // FIXME: this doesn't look right
170        documentAdapters.remove(desc.getName());
171        if (log.isDebugEnabled()) {
172            log.debug("Unregistered adapter: " + desc.getName());
173        }
174    }
175
176    protected void doUnregisterEvent(EventDescriptor desc) {
177        eventNames.remove(desc.getName());
178        eventExtendedInfoDescriptors.remove(desc.getName());
179        if (log.isDebugEnabled()) {
180            log.debug("Unregistered event: " + desc.getName());
181        }
182    }
183
184    protected void doUnregisterExtendedInfo(ExtendedInfoDescriptor desc) {
185        // FIXME: this doesn't look right
186        extendedInfoDescriptors.remove(desc.getKey());
187        if (log.isDebugEnabled()) {
188            log.debug("Unregistered extended info: " + desc.getKey());
189        }
190    }
191
192    @Override
193    public <T> T getAdapter(Class<T> adapter) {
194        if (adapter.getCanonicalName().equals(DocumentHistoryReader.class.getCanonicalName())) {
195            return adapter.cast(new DocumentHistoryReaderImpl());
196        } else {
197            if (backend != null) {
198                return adapter.cast(backend);
199            } else {
200                log.error("Can not provide service " + adapter.getCanonicalName() + " since backend is undefined");
201                return null;
202            }
203        }
204    }
205
206    public Set<String> getAuditableEventNames() {
207        return eventNames;
208    }
209
210    public AuditBackend getBackend() {
211        return backend;
212    }
213
214    public Set<AdapterDescriptor> getDocumentAdapters() {
215        return documentAdapters;
216    }
217
218    /**
219     * @since 7.4
220     */
221    public Map<String, List<ExtendedInfoDescriptor>> getEventExtendedInfoDescriptors() {
222        return eventExtendedInfoDescriptors;
223    }
224
225    public Set<ExtendedInfoDescriptor> getExtendedInfoDescriptors() {
226        return extendedInfoDescriptors;
227    }
228
229    @Override
230    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
231        if (extensionPoint.equals(EVENT_EXT_POINT)) {
232            doRegisterEvent((EventDescriptor) contribution);
233        } else if (extensionPoint.equals(EXTENDED_INFO_EXT_POINT)) {
234            doRegisterExtendedInfo((ExtendedInfoDescriptor) contribution);
235        } else if (extensionPoint.equals(ADAPTER_POINT)) {
236            doRegisterAdapter((AdapterDescriptor) contribution);
237        } else if (contribution instanceof AuditBackendDescriptor) {
238            backendConfig = (AuditBackendDescriptor)contribution;
239        }  else if (contribution instanceof AuditBulkerDescriptor) {
240            bulkerConfig = (AuditBulkerDescriptor)contribution;
241        }
242    }
243
244    @Override
245    public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
246        if (extensionPoint.equals(EVENT_EXT_POINT)) {
247            doUnregisterEvent((EventDescriptor) contribution);
248        } else if (extensionPoint.equals(EXTENDED_INFO_EXT_POINT)) {
249            doUnregisterExtendedInfo((ExtendedInfoDescriptor) contribution);
250        } else if (extensionPoint.equals(ADAPTER_POINT)) {
251            doUnregisterAdapter((AdapterDescriptor) contribution);
252        }
253    }
254
255}