/******************************************************************************* * Copyright (c) 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Jan S. Rellermeyer, IBM Research - initial API and implementation *******************************************************************************/ package org.eclipse.concierge.service.eventadmin; import java.util.ArrayList; import java.util.Arrays; import java.util.StringTokenizer; import org.osgi.framework.Filter; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import org.osgi.service.event.TopicPermission; /** * <p> * encapsulated the mapping between an {@link EventHandler} that has subscribed * and the topics it is interested it. Optionally, a {@link Filter} can be * provided that will be checked against the properties of incoming events. * </p> * * @author Jan S. Rellermeyer, ETH Zurich */ final class Subscription { /** * the <code>EventHandler</code>. */ private EventHandler handler; /** * an array of topics. */ private String[] topics; /** * a filter. */ private Filter filter; /** * hidden default constructor. */ private Subscription() { } /** * creates a new EventHandlerSubscription instance. * * @param handler * an <code>EventHandler</code> that wants to subscribe. * @param topics * an array of strings representing the topics. * @param filter * a <code>Filter</code> for matching event properties. */ Subscription(final EventHandler eventHandler, final String[] topics, final Filter filter) { // security check if (EventAdminImpl.security != null) { ArrayList checkedTopics = new ArrayList(topics.length); for (int i = 0; i < topics.length; i++) { try { EventAdminImpl.security .checkPermission(new TopicPermission(topics[i], TopicPermission.SUBSCRIBE)); checkedTopics.add(topics[i]); } catch (SecurityException se) { System.err .println("Bundle does not have permission for subscribing to " + topics[i]); } } this.topics = (String[]) checkedTopics .toArray(new String[checkedTopics.size()]); } else { this.topics = topics; } this.handler = eventHandler; this.filter = filter; } /** * sends an <code>Event</code> to the <code>EventHandler</code>. * * @param event * the <code>Event</code>. */ void sendEvent(final Event event) { try { handler.handleEvent(event); } catch (Exception shield) { shield.printStackTrace(); } } /** * get the handler. * * @return the handler. */ EventHandler getHandler() { return handler; } /** * checks if an event matches the subscribed topics and the filter, if * present. * * @param event * the <code>Event</code> * @return <code>true</code> for the case that the event matches, * <code>false</code> otherwise. */ boolean matches(final Event event) { if (topics != null && !stringMatch(topics, event.getTopic())) { return false; } if (filter != null && event.matches(filter)) { return false; } return true; } /** * checks if a string matches a pattern string. Either, the two strings must * be identical or the pattern must contain a wildcard and imply the topic. * * @param pattern * a pattern string. E.g. <code>ch/ethz/iks/*</code>. * @param topic * a topic. E.g. <code>ch/ethz/iks/SAMPLE_TOPIC</code>. * @return <code>true</code> if the topic matches the pattern string, * <code>false</code> otherwise. */ private static boolean stringMatch(final String pattern, final String topic) { final StringTokenizer strTokens = new StringTokenizer(pattern, "/"); final StringTokenizer topicTokens = new StringTokenizer(topic, "/"); while (strTokens.hasMoreTokens()) { String current = strTokens.nextToken(); if (!topicTokens.hasMoreTokens()) { return false; } if (current.equals("*") && !strTokens.hasMoreTokens()) { return true; } if (!current.equals(topicTokens.nextToken())) { return false; } } if (topicTokens.hasMoreTokens()) { return false; } return true; } /** * checks if a string matches one of the pattern strings. * * @param patterns * an array of pattern strings. * @param topic * a topic. E.g. <code>ch.ethz.iks.SampleTopic</code>. * @return <code>true</code> if the topic matches the pattern string, * <code>false</code> otherwise. */ private static boolean stringMatch(final String[] patterns, final String topic) { for (int i = 0; i < patterns.length; i++) { if (stringMatch(patterns[i], topic)) { return true; } } return false; } void update(final String[] topics, final Filter filter) { this.topics = topics; this.filter = filter; } /** * get a string representation of the <code>EventHandlerSubscription</code>. * * @return a <code>String</code> representation. * @see java.lang.Object#toString() */ public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[EventHandlerSubscription] "); buffer.append(handler.getClass().getName()); buffer.append(", topics "); if (topics != null) { buffer.append(Arrays.asList(topics)); } else { buffer.append("*"); } if (filter != null) { buffer.append(", filter '"); buffer.append(filter); buffer.append("'"); } return buffer.toString(); } }