All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dynamicextensionsalfresco.proxy.Tracker Maven / Gradle / Ivy

Go to download

Adds an OSGi container to alfresco repository supporting dynamic code reloading, classpath isolation and a bunch of other useful features

There is a newer version: 3.1.0
Show newest version
package com.github.dynamicextensionsalfresco.proxy;

import com.github.dynamicextensionsalfresco.osgi.FrameworkManager;
import com.github.dynamicextensionsalfresco.osgi.FrameworkService;
import org.osgi.framework.Filter;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Tracks services within the embedded OSGi context using interface matching or a custom {@link Filter}.
 * When {@link #invokeUsing(ServiceInvoker)} is called, the {@link ServiceInvoker} receives the sole matching instance.
 * This pattern is used so that we can avoid keeping a reference to the service. (dynamic nature of service discovery)
 *
 * @author Laurent Van der Linden
 */
public class Tracker {
	private final static Logger logger = LoggerFactory.getLogger(Tracker.class);

	private final FilterModel filterModel;
	private final FrameworkService frameworkService;

	private volatile ServiceTracker serviceTracker;
	private volatile FrameworkManager frameworkManager;

	public Tracker(FilterModel filterModel, FrameworkService frameworkService) {
		this.filterModel = filterModel;
		this.frameworkService = frameworkService;
	}

	/**
	 * Perform an action on a service.
	 * @param serviceInvoker action to receive a reference to the service
	 * @param  the target service type
	 * @return result from the service invocation
	 * @throws IllegalStateException if an exact service match is not possible
	 */
	@SuppressWarnings("unchecked")
	public  Object invokeUsing(ServiceInvoker serviceInvoker) throws Throwable {
		try {
			if (frameworkManager != null && frameworkManager != frameworkService.getFrameworkManager()) {
				// the OSGi context was restarted, discard any references
				closeServiceTracker();
				frameworkManager = null;
			}
			if (serviceTracker == null) {
				synchronized (this) {
					if (serviceTracker == null) {
						if (frameworkManager == null) {
							frameworkManager = frameworkService.getFrameworkManager();
						}
						serviceTracker = new ServiceTracker(
							frameworkManager.getFramework().getBundleContext(),
							filterModel.getServiceFilter(), null)
						;
						serviceTracker.open(true);
						logger.debug("Opened servicetracker using filter {}.", filterModel.getServiceFilter());
					}
				}
			}
		} catch (IllegalStateException e) {
			throw new IllegalStateException("OSGi Framework is not ready yet.", e);
		}

		final ServiceReference[] serviceReferences = serviceTracker.getServiceReferences();
		if (serviceReferences == null) {
			throw new IllegalStateException(
				String.format("No Dynamic service found using filter %s.", filterModel.getServiceFilter())
			);
		}
		if (serviceReferences.length != 1) {
			throw new IllegalStateException(
				String.format("More then 1 service found using filter %s.", filterModel.getServiceFilter())
			);
		}
		final ServiceReference soleReference = serviceReferences[0];
		final Object service = serviceTracker.getService(soleReference);
		try {
			return serviceInvoker.invokeService((T) service);
		} finally {
			serviceTracker.removedService(soleReference, service);
		}
	}

	private synchronized void closeServiceTracker() {
		if (serviceTracker != null) {
			serviceTracker.close();
			serviceTracker = null;
			logger.debug("Closed servicetracker using filter {}.", filterModel.getServiceFilter());
		}
	}

	public FilterModel getFilterModel() {
		// add a hook to reset the ServiceTracker
		return new FilterModel() {
			@Override
			public Filter getServiceFilter() {
				return filterModel.getServiceFilter();
			}

			@Override
			public void setServiceFilter(Filter serviceFilter) {
				filterModel.setServiceFilter(serviceFilter);
				closeServiceTracker();
			}

			@Override
			public void setServiceFilterString(String ldapFilter) {
				filterModel.setServiceFilterString(ldapFilter);
				closeServiceTracker();
			}
		};
	}
}