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

com.liferay.osgi.service.tracker.collections.internal.map.ServiceTrackerMapImpl Maven / Gradle / Ivy

There is a newer version: 8.1.0
Show newest version
/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.osgi.service.tracker.collections.internal.map;

import com.liferay.osgi.service.tracker.collections.EagerServiceTrackerCustomizer;
import com.liferay.osgi.service.tracker.collections.internal.ServiceTrackerManager;
import com.liferay.osgi.service.tracker.collections.internal.ServiceTrackerUtil;
import com.liferay.osgi.service.tracker.collections.map.KeyedServiceReferenceServiceTuple;
import com.liferay.osgi.service.tracker.collections.map.ServiceReferenceMapper;
import com.liferay.osgi.service.tracker.collections.map.ServiceTrackerBucket;
import com.liferay.osgi.service.tracker.collections.map.ServiceTrackerBucketFactory;
import com.liferay.osgi.service.tracker.collections.map.ServiceTrackerMap;
import com.liferay.osgi.service.tracker.collections.map.ServiceTrackerMapListener;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

/**
 * @author Carlos Sierra Andrés
 */
public class ServiceTrackerMapImpl
	implements ServiceTrackerMap {

	public ServiceTrackerMapImpl(
		BundleContext bundleContext, Class clazz, String filterString,
		ServiceReferenceMapper serviceReferenceMapper,
		ServiceTrackerCustomizer serviceTrackerCustomizer,
		ServiceTrackerBucketFactory serviceTrackerMapBucketFactory,
		ServiceTrackerMapListener serviceTrackerMapListener) {

		_serviceReferenceMapper = serviceReferenceMapper;
		_serviceTrackerCustomizer = serviceTrackerCustomizer;
		_serviceTrackerMapBucketFactory = serviceTrackerMapBucketFactory;
		_serviceTrackerMapListener = serviceTrackerMapListener;

		_serviceTracker = ServiceTrackerUtil.createServiceTracker(
			bundleContext, clazz, filterString,
			new ServiceReferenceServiceTrackerCustomizer());

		boolean trackAllServices = false;

		if (clazz == null) {
			trackAllServices = true;
		}

		_serviceTrackerManager = new ServiceTrackerManager(
			_serviceTracker, trackAllServices);

		if (_serviceTrackerCustomizer instanceof
				EagerServiceTrackerCustomizer) {

			_serviceTrackerManager.open();
		}
	}

	@Override
	public void close() {
		_serviceTrackerManager.close();
	}

	@Override
	public boolean containsKey(K key) {
		_serviceTrackerManager.open();

		return _serviceTrackerBuckets.containsKey(key);
	}

	@Override
	public R getService(K key) {
		_serviceTrackerManager.open();

		ServiceTrackerBucket serviceTrackerBucket =
			_serviceTrackerBuckets.get(key);

		if (serviceTrackerBucket == null) {
			return null;
		}

		return serviceTrackerBucket.getContent();
	}

	@Override
	public Set keySet() {
		_serviceTrackerManager.open();

		return Collections.unmodifiableSet(_serviceTrackerBuckets.keySet());
	}

	@Override
	public Collection values() {
		_serviceTrackerManager.open();

		return Collections.unmodifiableCollection(_getServices());
	}

	private Collection _getServices() {
		Collection services = new ArrayList<>();

		for (ServiceTrackerBucket serviceTrackerBucket :
				_serviceTrackerBuckets.values()) {

			services.add(serviceTrackerBucket.getContent());
		}

		return services;
	}

	private void _removeKeys(
		KeyedServiceReferenceServiceTuple
			keyedServiceReferenceServiceTuple) {

		List emittedKeys =
			keyedServiceReferenceServiceTuple.getEmittedKeys();

		for (K emittedKey : emittedKeys) {
			ServiceTrackerBucket serviceTrackerBucket =
				_serviceTrackerBuckets.get(emittedKey);

			if (serviceTrackerBucket == null) {
				continue;
			}

			serviceTrackerBucket.remove(keyedServiceReferenceServiceTuple);

			if (serviceTrackerBucket.isDisposable()) {
				_serviceTrackerBuckets.remove(emittedKey);
			}

			if (_serviceTrackerMapListener != null) {
				_serviceTrackerMapListener.keyRemoved(
					ServiceTrackerMapImpl.this, emittedKey,
					keyedServiceReferenceServiceTuple.getService(),
					serviceTrackerBucket.getContent());
			}
		}

		emittedKeys.clear();
	}

	private void _storeKey(
		K key,
		KeyedServiceReferenceServiceTuple
			keyedServiceReferenceServiceTuple) {

		ServiceTrackerBucket serviceTrackerBucket =
			_serviceTrackerBuckets.get(key);

		if (serviceTrackerBucket == null) {
			ServiceTrackerBucket newServiceTrackerBucket =
				_serviceTrackerMapBucketFactory.create();

			serviceTrackerBucket = _serviceTrackerBuckets.putIfAbsent(
				key, newServiceTrackerBucket);

			if (serviceTrackerBucket == null) {
				serviceTrackerBucket = newServiceTrackerBucket;
			}
		}

		serviceTrackerBucket.store(keyedServiceReferenceServiceTuple);

		keyedServiceReferenceServiceTuple.addEmittedKey(key);
	}

	private final ServiceReferenceMapper _serviceReferenceMapper;
	private final ServiceTracker
		> _serviceTracker;
	private final ConcurrentMap>
		_serviceTrackerBuckets = new ConcurrentHashMap<>();
	private final ServiceTrackerCustomizer _serviceTrackerCustomizer;
	private final ServiceTrackerManager _serviceTrackerManager;
	private final ServiceTrackerBucketFactory
		_serviceTrackerMapBucketFactory;
	private final ServiceTrackerMapListener
		_serviceTrackerMapListener;

	private class DefaultEmitter implements ServiceReferenceMapper.Emitter {

		public DefaultEmitter(ServiceReference serviceReference) {
			_serviceReference = serviceReference;
		}

		@Override
		public void emit(K key) {
			if (_keyedServiceReferenceServiceTuple == null) {
				if (!_invokedServiceTrackerCustomizer) {
					TS service = _serviceTrackerCustomizer.addingService(
						_serviceReference);

					_invokedServiceTrackerCustomizer = true;

					if (service == null) {
						return;
					}

					_keyedServiceReferenceServiceTuple =
						new KeyedServiceReferenceServiceTuple<>(
							_serviceReference, service);
				}
				else {
					return;
				}
			}

			_storeKey(key, _keyedServiceReferenceServiceTuple);

			if (_serviceTrackerMapListener != null) {
				ServiceTrackerBucket serviceTrackerBucket =
					_serviceTrackerBuckets.get(key);

				_serviceTrackerMapListener.keyEmitted(
					ServiceTrackerMapImpl.this, key,
					_keyedServiceReferenceServiceTuple.getService(),
					serviceTrackerBucket.getContent());
			}
		}

		public KeyedServiceReferenceServiceTuple
			getServiceReferenceServiceTuple() {

			return _keyedServiceReferenceServiceTuple;
		}

		private boolean _invokedServiceTrackerCustomizer;
		private KeyedServiceReferenceServiceTuple
			_keyedServiceReferenceServiceTuple;
		private final ServiceReference _serviceReference;

	}

	private class ServiceReferenceServiceTrackerCustomizer
		implements ServiceTrackerCustomizer
			> {

		@Override
		@SuppressWarnings({"rawtypes", "unchecked"})
		public KeyedServiceReferenceServiceTuple addingService(
			ServiceReference serviceReference) {

			DefaultEmitter defaultEmitter = new DefaultEmitter(
				serviceReference);

			_serviceReferenceMapper.map(
				(ServiceReference)serviceReference, defaultEmitter);

			return defaultEmitter.getServiceReferenceServiceTuple();
		}

		@Override
		@SuppressWarnings({"rawtypes", "unchecked"})
		public void modifiedService(
			ServiceReference serviceReference,
			final KeyedServiceReferenceServiceTuple
				keyedServiceReferenceServiceTuple) {

			_removeKeys(keyedServiceReferenceServiceTuple);

			_serviceTrackerCustomizer.modifiedService(
				serviceReference,
				keyedServiceReferenceServiceTuple.getService());

			_serviceReferenceMapper.map(
				(ServiceReference)serviceReference,
				new ServiceReferenceMapper.Emitter() {

					@Override
					public void emit(K key) {
						_storeKey(key, keyedServiceReferenceServiceTuple);
					}

				});
		}

		@Override
		public void removedService(
			ServiceReference serviceReference,
			KeyedServiceReferenceServiceTuple
				keyedServiceReferenceServiceTuple) {

			_removeKeys(keyedServiceReferenceServiceTuple);

			_serviceTrackerCustomizer.removedService(
				serviceReference,
				keyedServiceReferenceServiceTuple.getService());
		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy