blob: 9f50b3ad9ee3acb68650df63da8c377ad752c63e [file] [log] [blame]
/*
* Copyright 2005 The Apache Software Foundation
*
* 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.apache.felix.eventadmin.impl.handler;
import java.util.ArrayList;
import java.util.List;
import org.apache.felix.eventadmin.impl.security.TopicPermissions;
import org.apache.felix.eventadmin.impl.tasks.HandlerTask;
import org.apache.felix.eventadmin.impl.tasks.HandlerTaskImpl;
import org.apache.felix.eventadmin.impl.util.LogWrapper;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
/**
* This class is an implementation of the HandlerTasks interface that does provide
* blacklisting of event handlers. Furthermore, handlers are determined from the
* framework on any call to <tt>createHandlerTasks()</tt> hence, there is no
* book-keeping of <tt>EventHandler</tt> services while they come and go but a
* query for each sent event. In order to do this, an ldap-filter is created that
* will match applicable <tt>EventHandler</tt> references. In order to ease some of
* the overhead pains of this approach some light caching is going on.
*
* @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
*/
public class BlacklistingHandlerTasks implements HandlerTasks
{
// The blacklist that holds blacklisted event handler service references
private final BlackList m_blackList;
// The context of the bundle used to get the actual event handler services
private final BundleContext m_context;
// Used to create the filters that can determine applicable event handlers for
// a given event
private final TopicHandlerFilters m_topicHandlerFilters;
// Used to create the filters that are used to determine whether an applicable
// event handler is interested in a particular event
private final Filters m_filters;
// Used to create and possibly cache topic permissions
private final TopicPermissions m_topicPermissions;
/**
* The constructor of the factory.
*
* @param context The context of the bundle
* @param blackList The set to use for keeping track of blacklisted references
* @param topicHandlerFilters The factory for topic handler filters
* @param filters The factory for <tt>Filter</tt> objects
* @param topicPermissions The factory for permission objects of type PUBLISH
*/
public BlacklistingHandlerTasks(final BundleContext context,
final BlackList blackList,
final TopicHandlerFilters topicHandlerFilters, final Filters filters,
final TopicPermissions topicPermissions)
{
checkNull(context, "Context");
checkNull(blackList, "BlackList");
checkNull(topicHandlerFilters, "TopicHandlerFilters");
checkNull(filters, "Filters");
checkNull(topicPermissions, "TopicPermissions");
m_context = context;
m_blackList = blackList;
m_topicHandlerFilters = topicHandlerFilters;
m_filters = filters;
m_topicPermissions = topicPermissions;
}
/**
* Create the handler tasks for the event. All matching event handlers are
* determined and delivery tasks for them returned.
*
* @param event The event for which' handlers delivery tasks must be created
*
* @return A delivery task for each handler that matches the given event
*
* @see org.apache.felix.eventadmin.impl.handler.HandlerTasks#createHandlerTasks(org.osgi.service.event.Event)
*/
public HandlerTask[] createHandlerTasks(final Event event)
{
final List result = new ArrayList();
ServiceReference[] handlerRefs = new ServiceReference[0];
try
{
handlerRefs = m_context.getServiceReferences(EventHandler.class
.getName(), m_topicHandlerFilters.createFilterForTopic(event
.getTopic()));
} catch (InvalidSyntaxException e)
{
LogWrapper.getLogger().log(LogWrapper.LOG_WARNING,
"Invalid EVENT_TOPIC [" + event.getTopic() + "]", e);
}
if(null == handlerRefs)
{
handlerRefs = new ServiceReference[0];
}
for (int i = 0; i < handlerRefs.length; i++)
{
if (!m_blackList.contains(handlerRefs[i])
&& handlerRefs[i].getBundle().hasPermission(
m_topicPermissions.createTopicPermission(event.getTopic())))
{
try
{
if (event.matches(m_filters.createFilter(
(String) handlerRefs[i]
.getProperty(EventConstants.EVENT_FILTER),
Filters.TRUE_FILTER)))
{
result.add(new HandlerTaskImpl(handlerRefs[i],
event, this));
}
} catch (InvalidSyntaxException e)
{
LogWrapper.getLogger().log(
handlerRefs[i],
LogWrapper.LOG_WARNING,
"Invalid EVENT_FILTER - Blacklisting ServiceReference ["
+ handlerRefs[i] + " | Bundle("
+ handlerRefs[i].getBundle() + ")]", e);
m_blackList.add(handlerRefs[i]);
}
}
}
return (HandlerTaskImpl[]) result
.toArray(new HandlerTaskImpl[result.size()]);
}
/**
* Blacklist the given service reference. This is a private method and only
* public due to its usage in a friend class.
*
* @param handlerRef The service reference to blacklist
*/
public void blackList(final ServiceReference handlerRef)
{
m_blackList.add(handlerRef);
LogWrapper.getLogger().log(
LogWrapper.LOG_WARNING,
"Blacklisting ServiceReference [" + handlerRef + " | Bundle("
+ handlerRef.getBundle() + ")] due to timeout!");
}
/**
* Get the real EventHandler service for the handlerRef from the context in case
* the ref is not blacklisted and the service is not unregistered. The
* NullEventHandler object is returned otherwise. This is a private method and
* only public due to its usage in a friend class.
*
* @param handlerRef The service reference for which to get its service
* @return The service of the reference or a null object if the service is
* unregistered
*/
public EventHandler getEventHandler(final ServiceReference handlerRef)
{
final Object result = (m_blackList.contains(handlerRef)) ? null
: m_context.getService(handlerRef);
return (EventHandler) ((null != result) ? result : m_nullEventHandler);
}
/*
* This is a null object that is supposed to do nothing. This is used once an
* EventHandler is requested for a service reference that is either stale
* (i.e., unregistered) or blacklisted
*/
private final EventHandler m_nullEventHandler = new EventHandler()
{
/**
* This is a null object that is supposed to do nothing at this point.
*
* @param event an event that is not used
*/
public void handleEvent(final Event event)
{
// This is a null object that is supposed to do nothing at this
// point. This is used once a EventHandler is requested for a
// servicereference that is either stale (i.e., unregistered) or
// blacklisted.
}
};
/*
* This is a utility method that will throw a <tt>NullPointerException</tt>
* in case that the given object is null. The message will be of the form name +
* may not be null.
*/
private void checkNull(final Object object, final String name)
{
if(null == object)
{
throw new NullPointerException(name + " may not be null");
}
}
}