/******************************************************************************
 * 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.activator;

import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.service.blueprint.container.BlueprintEvent;
import org.osgi.service.blueprint.container.BlueprintListener;
import org.springframework.beans.factory.DisposableBean;
import org.eclipse.gemini.blueprint.service.importer.OsgiServiceLifecycleListener;
import org.eclipse.gemini.blueprint.service.importer.support.Availability;
import org.eclipse.gemini.blueprint.service.importer.support.CollectionType;
import org.eclipse.gemini.blueprint.service.importer.support.OsgiServiceCollectionProxyFactoryBean;
import org.eclipse.gemini.blueprint.util.BundleDelegatingClassLoader;

/**
 * Management class sending notifications to ModuleContextListener services. The class deals with the management of the
 * listener services.
 * 
 * @author Costin Leau
 * 
 */
class BlueprintListenerManager implements BlueprintListener, DisposableBean {

	/** logger */
	private static final Log log = LogFactory.getLog(BlueprintListenerManager.class);

	private volatile DisposableBean cleanupHook;
	private volatile List<BlueprintListener> listeners;
	private volatile ReplayEventManager replayManager;

	private class RegistrationReplayDelivery implements OsgiServiceLifecycleListener {

		public void bind(Object service, Map properties) throws Exception {
			BlueprintListener listener = (BlueprintListener) service;
			replayManager.dispatchReplayEvents(listener);
		}

		public void unbind(Object service, Map properties) throws Exception {
		}
	}

	public BlueprintListenerManager(BundleContext context) {
		this.replayManager = new ReplayEventManager(context);

		OsgiServiceCollectionProxyFactoryBean fb = new OsgiServiceCollectionProxyFactoryBean();
		fb.setBundleContext(context);
		fb.setAvailability(Availability.OPTIONAL);
		fb.setCollectionType(CollectionType.LIST);
		fb.setInterfaces(new Class[] { BlueprintListener.class });
		fb.setBeanClassLoader(BundleDelegatingClassLoader.createBundleClassLoaderFor(context.getBundle()));
		fb.setListeners(new OsgiServiceLifecycleListener[] { new RegistrationReplayDelivery() });
		fb.afterPropertiesSet();

		cleanupHook = fb;
		listeners = (List) fb.getObject();
	}

	public void destroy() {
		replayManager.destroy();

		if (cleanupHook != null) {
			try {
				cleanupHook.destroy();
			} catch (Exception ex) {
				// just log
				log.warn("Cannot destroy listeners collection", ex);
			}
			cleanupHook = null;
		}
	}

	public void blueprintEvent(BlueprintEvent event) {
		replayManager.addEvent(event);

		for (BlueprintListener listener : listeners) {
			try {
				listener.blueprintEvent(event);
			} catch (Exception ex) {
				log.warn("exception encountered when calling listener " + System.identityHashCode(listener), ex);
			}
		}
	}
}