/******************************************************************************
* Copyright (c) 2006, 2010 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
* is available at http://www.opensource.org/licenses/apache2.0.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* VMware Inc.
*****************************************************************************/
package org.eclipse.gemini.blueprint.extender.internal.blueprint.event;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.Version;
import org.osgi.service.blueprint.container.BlueprintEvent;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.eclipse.gemini.blueprint.util.OsgiBundleUtils;
import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
import org.springframework.util.ObjectUtils;
/**
* Actual {@link EventAdmin} dispatcher. Implemented as a package-protected generic class that can be further configured
* by the user-facing classes. The additional benefit is that being a separate class, this class can be used only when
* the org.osgi.service.event package is available, w/o triggering runtime class loading.
*
* @author Costin Leau
*/
class OsgiEventDispatcher implements EventDispatcher, BlueprintConstants {
/** logger */
private static final Log log = LogFactory.getLog(OsgiEventDispatcher.class);
private static final String EVENT_ADMIN = "org.osgi.service.event.EventAdmin";
private final BundleContext bundleContext;
private final PublishType publisher;
public OsgiEventDispatcher(BundleContext bundleContext, PublishType publisher) {
this.bundleContext = bundleContext;
this.publisher = publisher;
}
public void afterClose(BlueprintEvent event) {
Dictionary<String, Object> props = init(event);
sendEvent(new Event(TOPIC_DESTROYED, props));
}
public void afterRefresh(BlueprintEvent event) {
Dictionary<String, Object> props = init(event);
sendEvent(new Event(TOPIC_CREATED, props));
}
public void beforeClose(BlueprintEvent event) {
Dictionary<String, Object> props = init(event);
sendEvent(new Event(TOPIC_DESTROYING, props));
}
public void beforeRefresh(BlueprintEvent event) {
Dictionary<String, Object> props = init(event);
sendEvent(new Event(TOPIC_CREATING, props));
}
public void refreshFailure(BlueprintEvent event) {
Dictionary<String, Object> props = init(event);
Throwable th = event.getCause();
props.put(EXCEPTION, th);
props.put(CAUSE, th);
props.put(EXCEPTION_CLASS, th.getClass().getName());
String msg = th.getMessage();
props.put(EXCEPTION_MESSAGE, (msg != null ? msg : ""));
initDependencies(props, event);
sendEvent(new Event(TOPIC_FAILURE, props));
}
public void grace(BlueprintEvent event) {
Dictionary<String, Object> props = init(event);
initDependencies(props, event);
sendEvent(new Event(TOPIC_GRACE, props));
}
public void waiting(BlueprintEvent event) {
Dictionary<String, Object> props = init(event);
initDependencies(props, event);
sendEvent(new Event(TOPIC_WAITING, props));
}
private void initDependencies(Dictionary<String, Object> props, BlueprintEvent event) {
String[] deps = event.getDependencies();
if (!ObjectUtils.isEmpty(deps)) {
props.put(DEPENDENCIES, deps);
// props.put(SERVICE_FILTER, deps[0]);
// props.put(SERVICE_FILTER_2, deps[0]);
// props.put(SERVICE_OBJECTCLASS, extractObjectClassFromFilter(deps[0]));
props.put(ALL_DEPENDENCIES, deps);
}
}
private Dictionary<String, Object> init(BlueprintEvent event) {
Dictionary<String, Object> props = new Hashtable<String, Object>();
Bundle bundle = event.getBundle();
// common properties
props.put(TIMESTAMP, System.currentTimeMillis());
props.put(EVENT, event);
props.put(TYPE, Integer.valueOf(event.getType()));
props.put(BUNDLE, event.getBundle());
props.put(BUNDLE_ID, bundle.getBundleId());
// name (under two keys)
String name = OsgiStringUtils.nullSafeName(bundle);
props.put(BUNDLE_NAME, name);
props.put(Constants.BUNDLE_NAME, name);
// sym name (under two keys)
String symName = OsgiStringUtils.nullSafeSymbolicName(bundle);
props.put(BUNDLE_SYM_NAME, symName);
props.put(Constants.BUNDLE_SYMBOLICNAME, symName);
// version (as well under two keys)
Version version = OsgiBundleUtils.getBundleVersion(bundle);
props.put(BUNDLE_VERSION, version);
props.put(Constants.BUNDLE_VERSION, version);
// extender bundle info
Bundle extenderBundle = event.getExtenderBundle();
props.put(EXTENDER_BUNDLE, extenderBundle);
props.put(EXTENDER_BUNDLE_ID, extenderBundle.getBundleId());
props.put(EXTENDER_BUNDLE_SYM_NAME, extenderBundle.getSymbolicName());
Version extenderVersion = OsgiBundleUtils.getBundleVersion(extenderBundle);
props.put(EXTENDER_BUNDLE_VERSION, extenderVersion);
return props;
}
private void sendEvent(Event osgiEvent) {
boolean trace = log.isTraceEnabled();
ServiceReference ref = bundleContext.getServiceReference(EVENT_ADMIN);
if (ref != null) {
EventAdmin eventAdmin = (EventAdmin) bundleContext.getService(ref);
if (eventAdmin != null) {
if (trace) {
StringBuilder sb = new StringBuilder();
String[] names = osgiEvent.getPropertyNames();
sb.append("{");
for (int i = 0; i < names.length; i++) {
String name = names[i];
sb.append(name);
sb.append("=");
Object value = osgiEvent.getProperty(name);
sb.append(ObjectUtils.getDisplayString(value));
if (i < names.length - 1)
sb.append(",");
}
sb.append("}");
log.trace("Broadcasting OSGi event " + osgiEvent + " w/ props " + sb.toString());
}
publisher.publish(eventAdmin, osgiEvent);
}
} else {
log.trace("No event admin found for broadcasting event " + osgiEvent);
}
}
}