/****************************************************************************** * 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.compendium.internal.cm; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Dictionary; import java.util.Iterator; import java.util.Map; import java.util.Properties; import org.eclipse.gemini.blueprint.util.OsgiBundleUtils; import org.eclipse.gemini.blueprint.util.OsgiServiceUtils; import org.eclipse.gemini.blueprint.util.OsgiStringUtils; import org.eclipse.gemini.blueprint.util.internal.MapBasedDictionary; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.cm.ConfigurationEvent; import org.osgi.service.cm.ConfigurationListener; import org.osgi.service.cm.ManagedService; import org.springframework.beans.BeanWrapper; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.support.AbstractBeanFactory; import org.springframework.util.StringUtils; /** * Utility class for the Configuration Admin package. * * @author Costin Leau */ public abstract class CMUtils { /** * Injects the properties from the given Map to the given object. Additionally, a bean factory can be passed in for * copying property editors inside the injector. * * @param instance bean instance to configure * @param properties * @param beanFactory */ public static void applyMapOntoInstance(Object instance, Map<String, ?> properties, AbstractBeanFactory beanFactory) { if (properties != null && !properties.isEmpty()) { BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(instance); // configure bean wrapper (using method from Spring 2.5.6) if (beanFactory != null) { beanFactory.copyRegisteredEditorsTo(beanWrapper); } for (Iterator<?> iterator = properties.entrySet().iterator(); iterator.hasNext();) { Map.Entry<String, ?> entry = (Map.Entry<String, ?>) iterator.next(); String propertyName = entry.getKey(); if (beanWrapper.isWritableProperty(propertyName)) { beanWrapper.setPropertyValue(propertyName, entry.getValue()); } } } } public static void bulkUpdate(UpdateCallback callback, Collection<?> instances, Map<?, ?> properties) { for (Iterator<?> iterator = instances.iterator(); iterator.hasNext();) { Object instance = iterator.next(); callback.update(instance, properties); } } public static UpdateCallback createCallback(boolean autowireOnUpdate, String methodName, BeanFactory beanFactory) { UpdateCallback beanManaged = null, containerManaged = null; if (autowireOnUpdate) { containerManaged = new ContainerManagedUpdate(beanFactory); } if (StringUtils.hasText(methodName)) { beanManaged = new BeanManagedUpdate(methodName); } // if both strategies are present, return a chain if (containerManaged != null && beanManaged != null) return new ChainedManagedUpdate(new UpdateCallback[] { containerManaged, beanManaged }); // otherwise return the non-null one return (containerManaged != null ? containerManaged : beanManaged); } /** * Returns a map containing the Configuration Admin entry with given pid. Waits until a non-null (initialized) * object is returned if initTimeout is bigger then 0. * * @param bundleContext * @param pid * @param initTimeout * @return * @throws IOException */ public static Map getConfiguration(BundleContext bundleContext, final String pid, long initTimeout) throws IOException { ServiceReference ref = bundleContext.getServiceReference(ConfigurationAdmin.class.getName()); if (ref != null) { ConfigurationAdmin cm = (ConfigurationAdmin) bundleContext.getService(ref); if (cm != null) { Dictionary dict = cm.getConfiguration(pid).getProperties(); // if there are properties or no timeout, return as is if (dict != null || initTimeout == 0) { return new MapBasedDictionary(dict); } // no valid props, register a listener and start waiting final Object monitor = new Object(); Properties props = new Properties(); props.put(Constants.SERVICE_PID, pid); ServiceRegistration reg = bundleContext.registerService(ConfigurationListener.class.getName(), new ConfigurationListener() { public void configurationEvent(ConfigurationEvent event) { if (ConfigurationEvent.CM_UPDATED == event.getType() && pid.equals(event.getPid())) { synchronized (monitor) { monitor.notify(); } } } }, props); try { // try to get the configuration one more time (in case the update was fired before the service was // registered) dict = cm.getConfiguration(pid).getProperties(); if (dict != null) { return new MapBasedDictionary(dict); } // start waiting synchronized (monitor) { try { monitor.wait(initTimeout); } catch (InterruptedException ie) { // consider the timeout has passed } } // return whatever is available (either we timed out or an update occured) return new MapBasedDictionary(cm.getConfiguration(pid).getProperties()); } finally { OsgiServiceUtils.unregisterService(reg); } } } return Collections.EMPTY_MAP; } public static ServiceRegistration registerManagedService(BundleContext bundleContext, ManagedService listener, String pid) { Properties props = new Properties(); props.put(Constants.SERVICE_PID, pid); Bundle bundle = bundleContext.getBundle(); props.put(Constants.BUNDLE_SYMBOLICNAME, OsgiStringUtils.nullSafeSymbolicName(bundle)); props.put(Constants.BUNDLE_VERSION, OsgiBundleUtils.getBundleVersion(bundle)); return bundleContext.registerService(ManagedService.class.getName(), listener, props); } }