/*
 * Autopsy Forensic Browser
 *
 * Copyright 2011-2015 Basis Technology Corp.
 * Contact: carrier <at> sleuthkit <dot> org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.sleuthkit.autopsy.events;

import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;

/**
 * Provides thread-safe support for publishing events to registered subscribers
 * on this Autopsy node. Subscribers are constrained to be
 * PropertyChangeListeners to integrate with the legacy use of JavaBeans
 * PropertyChangeEvents and PropertyChangeListeners as an application event
 * system.
 */
final class LocalEventPublisher {

    private static final Logger logger = Logger.getLogger(LocalEventPublisher.class.getName());
    private final Map<String, Set<PropertyChangeListener>> subscribersByEvent;

    /**
     * Constructs an object for publishing events to registered subscribers on
     * this Autopsy node.
     */
    LocalEventPublisher() {
        subscribersByEvent = new ConcurrentHashMap<>();
    }

    /**
     * Adds an event subscriber to this publisher.
     *
     * @param eventNames The events the subscriber is interested in.
     * @param subscriber The subscriber to add.
     */
    void addSubscriber(Set<String> eventNames, PropertyChangeListener subscriber) {
        for (String eventName : eventNames) {
            addSubscriber(eventName, subscriber);
        }
    }

    /**
     * Adds an event subscriber to this publisher.
     *
     * @param eventName  The event the subscriber is interested in.
     * @param subscriber The subscriber to add.
     */
    void addSubscriber(String eventName, PropertyChangeListener subscriber) {
        subscribersByEvent.putIfAbsent(eventName, ConcurrentHashMap.<PropertyChangeListener>newKeySet());
        Set<PropertyChangeListener> subscribers = subscribersByEvent.get(eventName);
        subscribers.add(subscriber);
    }

    /**
     * Removes an event subscriber from this publisher.
     *
     * @param eventNames The events the subscriber is no longer interested in.
     * @param subscriber The subscriber to remove.
     */
    void removeSubscriber(Set<String> eventNames, PropertyChangeListener subscriber) {
        for (String eventName : eventNames) {
            removeSubscriber(eventName, subscriber);
        }
    }

    /**
     * Removes an event subscriber from this publisher.
     *
     * @param eventNames The event the subscriber is no longer interested in.
     * @param subscriber The subscriber to remove.
     */
    void removeSubscriber(String eventName, PropertyChangeListener subscriber) {
        Set<PropertyChangeListener> subscribers = subscribersByEvent.getOrDefault(eventName, null);
        if (null != subscribers) {
            subscribers.remove(subscriber);
        }
    }

    /**
     * Publishes an event to all registered subscribers, even if a subscriber
     * throws an exception.
     *
     * @param event The event to be published.
     */
    void publish(AutopsyEvent event) {
        Set<PropertyChangeListener> subscribers = subscribersByEvent.getOrDefault(event.getPropertyName(), null);
        if (null != subscribers) {
            for (PropertyChangeListener subscriber : subscribers) {
                try {
                    subscriber.propertyChange(event);
                } catch (Exception ex) {
                    logger.log(Level.SEVERE, "Exception thrown by subscriber", ex); //NON-NLS
                }
            }
        }
    }

}

@@ -52,9 +52,9 @@
 -201
-5
+7
  Bas
@@ -884,16 +884,63 @@
 .Level;%0A
+import javax.annotation.concurrent.ThreadSafe;%0A
 import o
@@ -1286,16 +1286,28 @@
 em.%0A */%0A
+@ThreadSafe%0A
 final cl
@@ -3889,49 +3889,29 @@
     
-for (PropertyChangeListener subscriber : 
+subscribers.forEach((
 subs
@@ -3908,34 +3908,36 @@
 Each((subscriber
-s
 )
+ -%3E
  %7B%0A             
@@ -4157,32 +4157,34 @@
  %7D%0A            %7D
+);
 %0A        %7D%0A    %7D

Improve documentation of LocalEventPublisher