Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 95e063ba02ae36d8222b6c5c92ceb2fc37198b48 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*******************************************************************************
 * Copyright (c) 2005, 2010 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.equinox.internal.event;

import java.security.Permission;
import java.util.Map;
import java.util.Set;
import org.eclipse.osgi.framework.eventmgr.*;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.BundleContext;
import org.osgi.service.event.*;
import org.osgi.service.log.LogService;

/**
 * Implementation of org.osgi.service.event.EventAdmin. EventAdminImpl uses
 * org.eclipse.osgi.framework.eventmgr.EventManager. It is assumed
 * org.eclipse.osgi.framework.eventmgr package is exported by some other bundle.
 */
public class EventAdminImpl implements EventAdmin {
	private final LogTracker log;
	private final EventHandlerTracker handlers;
	private volatile EventManager eventManager;

	/**
	 * Constructor for EventAdminImpl.
	 * 
	 * @param context BundleContext
	 */
	EventAdminImpl(BundleContext context) {
		super();
		log = new LogTracker(context, System.out);
		handlers = new EventHandlerTracker(context, log);
	}

	/**
	 * This method should be called before registering EventAdmin service
	 */
	void start() {
		log.open();
		ThreadGroup eventGroup = new ThreadGroup("Equinox Event Admin"); //$NON-NLS-1$
		eventGroup.setDaemon(true);
		eventManager = new EventManager(EventAdminMsg.EVENT_ASYNC_THREAD_NAME, eventGroup);
		handlers.open();
	}

	/**
	 * This method should be called after unregistering EventAdmin service
	 */
	void stop() {
		handlers.close();
		eventManager.close();
		eventManager = null; // signify we have stopped
		log.close();
	}

	/**
	 * @param event
	 * @see org.osgi.service.event.EventAdmin#postEvent(org.osgi.service.event.Event)
	 */
	public void postEvent(Event event) {
		dispatchEvent(event, true);
	}

	/**
	 * @param event
	 * @see org.osgi.service.event.EventAdmin#sendEvent(org.osgi.service.event.Event)
	 */
	public void sendEvent(Event event) {
		dispatchEvent(event, false);
	}

	/**
	 * Internal main method for sendEvent() and postEvent(). Dispatching an
	 * event to EventHandler. All exceptions are logged except when dealing with
	 * LogEntry.
	 * 
	 * @param event to be delivered
	 * @param isAsync must be set to true for synchronous event delivery, false
	 *        for asynchronous delivery.
	 */
	private void dispatchEvent(Event event, boolean isAsync) {
		// keep a local copy in case we are stopped in the middle of dispatching
		EventManager currentManager = eventManager;
		if (currentManager == null) {
			// EventAdmin is stopped
			return;
		}
		if (event == null) {
			log.log(LogService.LOG_ERROR, EventAdminMsg.EVENT_NULL_EVENT);
			// continue from here will result in an NPE below; the spec for EventAdmin does not allow for null here
		}

		String topic = event.getTopic();

		try {
			checkTopicPermissionPublish(topic);
		} catch (SecurityException e) {
			String msg = NLS.bind(EventAdminMsg.EVENT_NO_TOPICPERMISSION_PUBLISH, event.getTopic());
			log.log(LogService.LOG_ERROR, msg);
			// must throw a security exception here according to the EventAdmin spec
			throw e;
		}

		Set<EventHandlerWrapper> eventHandlers = handlers.getHandlers(topic);
		// If there are no handlers, then we are done
		if (eventHandlers.isEmpty()) {
			return;
		}

		SecurityManager sm = System.getSecurityManager();
		Permission perm = (sm == null) ? null : new TopicPermission(topic, TopicPermission.SUBSCRIBE);

		Map<EventHandlerWrapper, Permission> listeners = new CopyOnWriteIdentityMap<EventHandlerWrapper, Permission>();
		for (EventHandlerWrapper wrapper : eventHandlers)
			listeners.put(wrapper, perm);

		// Create the listener queue for this event delivery
		ListenerQueue<EventHandlerWrapper, Permission, Event> listenerQueue = new ListenerQueue<EventHandlerWrapper, Permission, Event>(currentManager);
		// Add the listeners to the queue and associate them with the event
		// dispatcher
		listenerQueue.queueListeners(listeners.entrySet(), handlers);
		// Deliver the event to the listeners.
		if (isAsync) {
			listenerQueue.dispatchEventAsynchronous(0, event);
		} else {
			listenerQueue.dispatchEventSynchronous(0, event);
		}
	}

	/**
	 * Checks if the caller bundle has right PUBLISH TopicPermision.
	 * 
	 * @param topic
	 * @throws SecurityException if the caller does not have the right to PUBLISH TopicPermission
	 */
	private void checkTopicPermissionPublish(String topic) throws SecurityException {
		SecurityManager sm = System.getSecurityManager();
		if (sm == null)
			return;
		sm.checkPermission(new TopicPermission(topic, TopicPermission.PUBLISH));
	}

}

Back to the top