org.apache.felix.useradmin.impl.EventDispatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.felix.useradmin
Show all versions of org.apache.felix.useradmin
Provides an implementation for the UserAdmin OSGi
compendium service.
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.felix.useradmin.impl;
import java.util.Properties;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventConstants;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.UserAdminEvent;
import org.osgi.service.useradmin.UserAdminListener;
/**
* Provides an event dispatcher for delivering {@link UserAdminEvent}s asynchronously.
*/
public final class EventDispatcher implements Runnable {
private static final String TOPIC_BASE = "org/osgi/service/useradmin/UserAdmin/";
private final EventAdmin m_eventAdmin;
private final UserAdminListenerList m_listenerList;
private final BlockingQueue m_eventQueue;
private final Thread m_backgroundThread;
/**
* Creates a new {@link EventDispatcher} instance, and starts a background thread to deliver all events.
*
* @param eventAdmin the event admin to use, cannot be null
;
* @param listenerList the list with {@link UserAdminListener}s, cannot be null
.
* @throws IllegalArgumentException in case one of the given parameters was null
.
*/
public EventDispatcher(EventAdmin eventAdmin, UserAdminListenerList listenerList) {
if (eventAdmin == null) {
throw new IllegalArgumentException("EventAdmin cannot be null!");
}
if (listenerList == null) {
throw new IllegalArgumentException("ListenerList cannot be null!");
}
m_eventAdmin = eventAdmin;
m_listenerList = listenerList;
m_eventQueue = new LinkedBlockingQueue();
m_backgroundThread = new Thread(this, "UserAdmin event dispatcher");
}
/**
* Dispatches a given event for asynchronous delivery to all interested listeners,
* including those using the {@link EventAdmin} service.
*
* This method will perform a best-effort to dispatch the event to all listeners, i.e.,
* there is no guarantee that the listeners will actually obtain the event, nor any
* notification is given in case delivery fails.
*
*
* @param event the event to dispatch, cannot be null
.
* @throws IllegalStateException in case this dispatcher is already stopped.
*/
public void dispatch(UserAdminEvent event) {
if (!isRunning()) {
return;
}
try {
m_eventQueue.put(event);
} catch (InterruptedException e) {
// Restore interrupt flag...
Thread.currentThread().interrupt();
}
}
/**
* Starts this event dispatcher, allowing it to pick up events and deliver them.
*/
public void start() {
if (!isRunning()) {
m_backgroundThread.start();
}
}
/**
* Signals this event dispatcher to stop its work and clean up all running threads.
*/
public void stop() {
if (!isRunning()) {
return;
}
// Add poison object to queue to let the background thread terminate...
m_eventQueue.add(EventDispatcher.this);
try {
m_backgroundThread.join();
} catch (InterruptedException e) {
// We're already stopping; so don't bother...
}
}
/**
* Returns whether or not the background thread is running.
*
* @return true
if the background thread is running (alive), false
otherwise.
*/
final boolean isRunning() {
return m_backgroundThread.isAlive();
}
/**
* Provides the main event loop, which waits until an event is enqueued in order
* to deliver it to any interested listener.
*/
public void run() {
try {
while (true) {
// Blocks until a event is dispatched...
Object event = m_eventQueue.take();
if (event instanceof UserAdminEvent) {
// Got a "normal" user admin event; lets dispatch it further...
deliverEventSynchronously((UserAdminEvent) event);
} else {
// Got a "poison" object; this means we must stop running...
return;
}
}
} catch (InterruptedException e) {
// Restore interrupt flag, and terminate thread...
Thread.currentThread().interrupt();
}
}
/**
* Converts a given {@link UserAdminEvent} to a {@link Event} that can be
* dispatched through the {@link EventAdmin} service.
*
* @param event
* the event to convert, cannot be null
.
* @return a new {@link Event} instance containing the same set of
* information as the given event, never null
.
*/
private Event convertEvent(UserAdminEvent event) {
String topic = getTopicName(event.getType());
Role role = event.getRole();
ServiceReference serviceRef = event.getServiceReference();
Properties props = new Properties();
props.put(EventConstants.EVENT_TOPIC, TOPIC_BASE.concat(topic));
props.put(EventConstants.EVENT, event);
props.put("role", role);
props.put("role.name", role.getName());
props.put("role.type", new Integer(role.getType()));
if (serviceRef != null) {
props.put(EventConstants.SERVICE, serviceRef);
Object property;
property = serviceRef.getProperty(Constants.SERVICE_ID);
if (property != null) {
props.put(EventConstants.SERVICE_ID, property);
}
property = serviceRef.getProperty(Constants.OBJECTCLASS);
if (property != null) {
props.put(EventConstants.SERVICE_OBJECTCLASS, property);
}
property = serviceRef.getProperty(Constants.SERVICE_PID);
if (property != null) {
props.put(EventConstants.SERVICE_PID, property);
}
}
return new Event(topic, props);
}
/**
* Delivers the given event synchronously to all interested listeners.
*
* @param event the event to deliver, cannot be null
.
*/
private void deliverEventSynchronously(UserAdminEvent event) {
// Asynchronously deliver an event to the EventAdmin service...
m_eventAdmin.postEvent(convertEvent(event));
// Synchronously call all UserAdminListeners to deliver the event...
UserAdminListener[] listeners = m_listenerList.getListeners();
for (int i = 0; i < listeners.length; i++) {
listeners[i].roleChanged(event);
}
}
/**
* Converts a topic name for the given event-type.
*
* @param type the type of event to get the topic name for.
* @return a topic name, never null
.
*/
private String getTopicName(int type) {
switch (type) {
case UserAdminEvent.ROLE_CREATED:
return "ROLE_CREATED";
case UserAdminEvent.ROLE_CHANGED:
return "ROLE_CHANGED";
case UserAdminEvent.ROLE_REMOVED:
return "ROLE_REMOVED";
default:
return null;
}
}
}