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

com.liferay.registry.BasicRegistryImpl Maven / Gradle / Ivy

There is a newer version: 7.4.3.112-ga112
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.registry;

import com.liferay.registry.dependency.ServiceDependencyManager;
import com.liferay.registry.util.StringPlus;
import com.liferay.registry.util.UnmodifiableCaseInsensitiveMapDictionary;

import java.lang.reflect.Array;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;

/**
 * @author Raymond Augé
 */
public class BasicRegistryImpl implements Registry {

	@Override
	public  R callService(
		Class serviceClass, Function function) {

		return callService(serviceClass.getName(), function);
	}

	@Override
	public  R callService(String className, Function function) {
		Filter filter = getFilter("(objectClass=" + className + ")");

		for (Map.Entry, Object> entry :
				_services.entrySet()) {

			if (filter.matches(entry.getKey())) {
				return function.apply((S)entry.getValue());
			}
		}

		return null;
	}

	@Override
	public Filter getFilter(String filterString) throws RuntimeException {
		return new BasicFilter(filterString);
	}

	@Override
	public Registry getRegistry() throws SecurityException {
		return this;
	}

	/**
	 * @deprecated As of Judson (7.1.x), with no direct replacement
	 */
	@Deprecated
	@Override
	public  T getService(Class clazz) {
		return getService(clazz.getName());
	}

	@Override
	public  T getService(ServiceReference serviceReference) {
		BasicServiceReference basicServiceReference =
			(BasicServiceReference)serviceReference;

		for (Map.Entry, Object> entry :
				_services.entrySet()) {

			if (basicServiceReference.matches(entry.getKey())) {
				return (T)entry.getValue();
			}
		}

		return null;
	}

	/**
	 * @deprecated As of Judson (7.1.x), with no direct replacement
	 */
	@Deprecated
	@Override
	public  T getService(String className) {
		Filter filter = getFilter("(objectClass=" + className + ")");

		for (Map.Entry, Object> entry :
				_services.entrySet()) {

			if (filter.matches(entry.getKey())) {
				return (T)entry.getValue();
			}
		}

		return null;
	}

	@Override
	public Collection getServiceDependencyManagers() {
		return Collections.unmodifiableCollection(_serviceDependencyManagers);
	}

	@Override
	public  ServiceReference getServiceReference(Class clazz) {
		return getServiceReference(clazz.getName());
	}

	@Override
	public  ServiceReference getServiceReference(String className) {
		Filter filter = getFilter("(objectClass=" + className + ")");

		for (Map.Entry, Object> entry :
				_services.entrySet()) {

			if (filter.matches(entry.getKey())) {
				return (ServiceReference)entry.getKey();
			}
		}

		return null;
	}

	@Override
	public  Collection> getServiceReferences(
			Class clazz, String filterString)
		throws Exception {

		ServiceReference[] serviceReferences = getServiceReferences(
			clazz.getName(), filterString);

		if (serviceReferences == null) {
			return Collections.emptyList();
		}

		return Arrays.asList(serviceReferences);
	}

	@Override
	public  ServiceReference[] getServiceReferences(
			String className, String filterString)
		throws Exception {

		List> serviceReferences = new ArrayList<>();

		Filter filter = new BasicFilter(filterString);

		for (Map.Entry, Object> entry :
				_services.entrySet()) {

			if (filter.matches(entry.getKey())) {
				serviceReferences.add((ServiceReference)entry.getKey());
			}
		}

		if (serviceReferences.isEmpty()) {
			return null;
		}

		return serviceReferences.toArray(new ServiceReference[0]);
	}

	@Override
	public  ServiceRegistrar getServiceRegistrar(Class clazz) {
		return new ServiceRegistrar<>(this, clazz);
	}

	@Override
	public  Collection getServices(Class clazz, String filterString)
		throws Exception {

		T[] services = getServices(clazz.getName(), filterString);

		if (services == null) {
			return Collections.emptyList();
		}

		return Arrays.asList(services);
	}

	@Override
	public  T[] getServices(String className, String filterString)
		throws Exception {

		List services = new ArrayList<>();

		if ((filterString == null) || filterString.equals("")) {
			filterString = "(objectClass=" + className + ")";
		}

		Filter filter = new BasicFilter(filterString);

		for (Map.Entry, Object> entry :
				_services.entrySet()) {

			if (filter.matches(entry.getKey())) {
				services.add((T)entry.getValue());
			}
		}

		if (services.isEmpty()) {
			return null;
		}

		T service = services.get(0);

		Class clazz = service.getClass();

		T[] array = (T[])Array.newInstance(clazz, services.size());

		return services.toArray(array);
	}

	@Override
	public String getSymbolicName(ClassLoader classLoader) {
		return null;
	}

	@Override
	public  ServiceRegistration registerService(
		Class clazz, T service) {

		BasicServiceReference basicServiceReference =
			new BasicServiceReference<>(
				clazz.getName(), _serviceIdCounter.incrementAndGet(), 0,
				new HashMap());

		_addingService(basicServiceReference, service);

		return new BasicServiceRegistration<>(basicServiceReference);
	}

	@Override
	public  ServiceRegistration registerService(
		Class clazz, T service, Map properties) {

		Integer serviceRanking = (Integer)properties.get("service.ranking");

		if (serviceRanking == null) {
			serviceRanking = Integer.valueOf(0);
		}

		BasicServiceReference basicServiceReference =
			new BasicServiceReference<>(
				clazz.getName(), _serviceIdCounter.incrementAndGet(),
				serviceRanking.intValue(), properties);

		_addingService(basicServiceReference, service);

		return new BasicServiceRegistration<>(basicServiceReference);
	}

	@Override
	public  ServiceRegistration registerService(
		String className, T service) {

		BasicServiceReference basicServiceReference =
			new BasicServiceReference<>(
				className, _serviceIdCounter.incrementAndGet(), 0,
				new HashMap());

		_addingService(basicServiceReference, service);

		return new BasicServiceRegistration<>(basicServiceReference);
	}

	@Override
	public  ServiceRegistration registerService(
		String className, T service, Map properties) {

		Integer serviceRanking = (Integer)properties.get("service.ranking");

		if (serviceRanking == null) {
			serviceRanking = Integer.valueOf(0);
		}

		BasicServiceReference basicServiceReference =
			new BasicServiceReference<>(
				className, _serviceIdCounter.incrementAndGet(),
				serviceRanking.intValue(), properties);

		_addingService(basicServiceReference, service);

		return new BasicServiceRegistration<>(basicServiceReference);
	}

	@Override
	public  ServiceRegistration registerService(
		String[] classNames, T service) {

		if ((classNames == null) || (classNames.length == 0)) {
			throw new IllegalArgumentException();
		}

		Map properties = new HashMap<>();

		properties.put("objectClass", classNames);

		BasicServiceReference basicServiceReference =
			new BasicServiceReference<>(
				classNames[0], _serviceIdCounter.incrementAndGet(), 0,
				properties);

		_addingService(basicServiceReference, service);

		return new BasicServiceRegistration<>(basicServiceReference);
	}

	@Override
	public  ServiceRegistration registerService(
		String[] classNames, T service, Map properties) {

		if ((classNames == null) || (classNames.length == 0)) {
			throw new IllegalArgumentException();
		}

		properties.put("objectClass", classNames);

		Integer serviceRanking = (Integer)properties.get("service.ranking");

		if (serviceRanking == null) {
			serviceRanking = Integer.valueOf(0);
		}

		BasicServiceReference basicServiceReference =
			new BasicServiceReference<>(
				classNames[0], _serviceIdCounter.incrementAndGet(),
				serviceRanking.intValue(), properties);

		_addingService(basicServiceReference, service);

		return new BasicServiceRegistration<>(basicServiceReference);
	}

	@Override
	public synchronized void registerServiceDependencyManager(
		ServiceDependencyManager serviceDependencyManager) {

		_serviceDependencyManagers.add(serviceDependencyManager);
	}

	@Override
	public Registry setRegistry(Registry registry) throws SecurityException {
		return registry;
	}

	@Override
	public  ServiceTracker trackServices(Class clazz) {
		Filter filter = new BasicFilter(
			"(objectClass=" + clazz.getName() + ")");

		return new BasicServiceTracker<>(filter);
	}

	@Override
	public  ServiceTracker trackServices(
		Class clazz,
		ServiceTrackerCustomizer serviceTrackerCustomizer) {

		Filter filter = new BasicFilter(
			"(objectClass=" + clazz.getName() + ")");

		return new BasicServiceTracker<>(filter, serviceTrackerCustomizer);
	}

	@Override
	public  ServiceTracker trackServices(Filter filter) {
		return new BasicServiceTracker<>(filter);
	}

	@Override
	public  ServiceTracker trackServices(
		Filter filter,
		ServiceTrackerCustomizer serviceTrackerCustomizer) {

		return new BasicServiceTracker<>(filter, serviceTrackerCustomizer);
	}

	@Override
	public  ServiceTracker trackServices(String className) {
		return new BasicServiceTracker<>(
			new BasicFilter("(objectClass=" + className + ")"));
	}

	@Override
	public  ServiceTracker trackServices(
		String className,
		ServiceTrackerCustomizer serviceTrackerCustomizer) {

		Filter filter = new BasicFilter("(objectClass=" + className + ")");

		return new BasicServiceTracker<>(filter, serviceTrackerCustomizer);
	}

	@Override
	public  boolean ungetService(ServiceReference serviceReference) {
		return true;
	}

	@Override
	public void unregisterServiceDependencyManager(
		ServiceDependencyManager serviceDependencyManager) {

		_serviceDependencyManagers.remove(serviceDependencyManager);
	}

	private  void _addingService(
		BasicServiceReference basicServiceReference, S service) {

		_services.put(basicServiceReference, service);

		for (Map.Entry, Filter> entry :
				_serviceTrackers.entrySet()) {

			Filter filter = entry.getValue();

			if (!filter.matches(basicServiceReference)) {
				continue;
			}

			ServiceTracker serviceTracker =
				(ServiceTracker)entry.getKey();

			try {
				serviceTracker.addingService(basicServiceReference);
			}
			catch (Throwable t) {
				t.printStackTrace();
			}
		}
	}

	private  void _modifiedService(
		BasicServiceReference basicServiceReference) {

		for (Map.Entry, Filter> entry :
				_serviceTrackers.entrySet()) {

			Filter filter = entry.getValue();

			if (!filter.matches(basicServiceReference)) {
				continue;
			}

			ServiceTracker serviceTracker =
				(ServiceTracker)entry.getKey();

			T service = serviceTracker.getService(basicServiceReference);

			if (service == null) {
				continue;
			}

			try {
				serviceTracker.modifiedService(basicServiceReference, service);
			}
			catch (Throwable t) {
				t.printStackTrace();
			}
		}
	}

	private  void _removedService(
		BasicServiceReference basicServiceReference) {

		for (Map.Entry, Filter> entry :
				_serviceTrackers.entrySet()) {

			Filter filter = entry.getValue();

			if (!filter.matches(basicServiceReference)) {
				continue;
			}

			ServiceTracker serviceTracker =
				(ServiceTracker)entry.getKey();

			try {
				serviceTracker.remove(basicServiceReference);
			}
			catch (Throwable t) {
				t.printStackTrace();
			}
		}
	}

	private final Set _serviceDependencyManagers =
		new HashSet<>();
	private final AtomicLong _serviceIdCounter = new AtomicLong();
	private final Map, Object> _services =
		new ConcurrentSkipListMap<>();
	private final Map, Filter> _serviceTrackers =
		new ConcurrentHashMap<>();

	private static class BasicFilter implements Filter {

		public BasicFilter(String filterString) {
			_filter = new aQute.lib.filter.Filter(filterString);
		}

		@Override
		public boolean matches(Map properties) {
			Dictionary dictionary =
				new UnmodifiableCaseInsensitiveMapDictionary<>(properties);

			return _filter.match(dictionary);
		}

		@Override
		public boolean matches(ServiceReference serviceReference) {
			BasicServiceReference basicServiceReference =
				(BasicServiceReference)serviceReference;

			Dictionary dictionary =
				new UnmodifiableCaseInsensitiveMapDictionary<>(
					basicServiceReference._properties);

			return _filter.match(dictionary);
		}

		@Override
		public boolean matchesCase(Map properties) {
			return matches(properties);
		}

		@Override
		public String toString() {
			return _filter.toString();
		}

		private aQute.lib.filter.Filter _filter;

	}

	private static class LowerCaseKeyTreeMap extends TreeMap {

		@Override
		public Object put(String key, Object value) {
			return super.put(key.toLowerCase(), value);
		}

	}

	private class BasicServiceReference implements ServiceReference {

		public BasicServiceReference(
			String className, long id, int ranking,
			Map properties) {

			_properties.put("service.id", id);
			_properties.put("service.ranking", ranking);

			List classNames = new ArrayList<>();

			classNames.add(className);
			classNames.addAll(StringPlus.asList(properties.get("objectClass")));

			_properties.putAll(properties);

			_properties.put("objectClass", classNames);
		}

		@Override
		public int compareTo(Object serviceReference) {
			BasicServiceReference otherServiceReference =
				(BasicServiceReference)serviceReference;

			int thisServiceRanking = (Integer)_properties.get(
				"service.ranking");

			Map otherProperties =
				otherServiceReference._properties;

			int otherServiceRanking = (Integer)otherProperties.get(
				"service.ranking");

			if (thisServiceRanking != otherServiceRanking) {
				if (thisServiceRanking < otherServiceRanking) {
					return 1;
				}

				return -1;
			}

			long thisServiceId = (Long)_properties.get("service.id");
			long otherServiceId = (Long)otherProperties.get("service.id");

			if (thisServiceId == otherServiceId) {
				return 0;
			}

			if (thisServiceId < otherServiceId) {
				return 1;
			}

			return -1;
		}

		@Override
		public Map getProperties() {
			return new HashMap<>(_properties);
		}

		@Override
		public Object getProperty(String key) {
			return _properties.get(key.toLowerCase());
		}

		@Override
		public String[] getPropertyKeys() {
			Set set = _properties.keySet();

			return set.toArray(new String[set.size()]);
		}

		public boolean matches(ServiceReference serviceReference) {
			Filter filter = new BasicFilter(toString());

			return filter.matches(serviceReference);
		}

		@Override
		public String toString() {
			StringBuilder stringBuilder = new StringBuilder();

			Set> entrySet = _properties.entrySet();

			if (entrySet.size() > 1) {
				stringBuilder.append('(');
				stringBuilder.append('&');
			}

			for (Map.Entry entry : entrySet) {
				String key = entry.getKey();
				Object value = entry.getValue();

				Object[] array = null;

				Class clazz = value.getClass();

				if (clazz.isArray()) {
					array = (Object[])value;
				}
				else if (value instanceof Collection) {
					Collection collection = (Collection)value;

					array = collection.toArray();
				}
				else {
					array = new Object[] {value};
				}

				if (array.length > 0) {
					for (Object object : array) {
						stringBuilder.append('(');
						stringBuilder.append(key);
						stringBuilder.append('=');
						stringBuilder.append(object);
						stringBuilder.append(')');
					}
				}
			}

			if (entrySet.size() > 1) {
				stringBuilder.append(')');
			}

			return stringBuilder.toString();
		}

		private final Map _properties =
			new LowerCaseKeyTreeMap();

	}

	private class BasicServiceRegistration
		implements ServiceRegistration {

		public BasicServiceRegistration(
			BasicServiceReference basicServiceReference) {

			_basicServiceReference = basicServiceReference;
		}

		@Override
		public ServiceReference getServiceReference() {
			return _basicServiceReference;
		}

		@Override
		public void setProperties(Map properties) {
			_basicServiceReference._properties.putAll(properties);

			_modifiedService(_basicServiceReference);
		}

		@Override
		public void unregister() {
			_services.remove(_basicServiceReference);

			_removedService(_basicServiceReference);
		}

		private final BasicServiceReference _basicServiceReference;

	}

	private class BasicServiceTracker implements ServiceTracker {

		public BasicServiceTracker(Filter filter) {
			this(filter, null);
		}

		public BasicServiceTracker(
			Filter filter,
			ServiceTrackerCustomizer serviceTrackerCustomizer) {

			_filter = filter;
			_serviceTrackerCustomizer = serviceTrackerCustomizer;
		}

		@Override
		public T addingService(ServiceReference serviceReference) {
			T service = null;

			try {
				if (_serviceTrackerCustomizer != null) {
					service = _serviceTrackerCustomizer.addingService(
						serviceReference);
				}
				else {
					service = (T)BasicRegistryImpl.this.getService(
						serviceReference);
				}

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

				_trackedServices.put(serviceReference, service);

				return service;
			}
			finally {
				if (service != null) {
					_stateCounter.incrementAndGet();
					_countDownLatch.countDown();
				}
			}
		}

		@Override
		public void close() {
			_serviceTrackers.remove(this);

			Set, T>> set =
				_trackedServices.entrySet();

			Iterator, T>> iterator =
				set.iterator();

			while (iterator.hasNext()) {
				Map.Entry, T> entry = iterator.next();

				iterator.remove();

				removedService(entry.getKey(), entry.getValue());
			}

			_trackedServices.clear();
		}

		@Override
		public T getService() {
			Optional, T>> optionalEntry =
				ServiceRankingUtil.getHighestRankingEntry(_trackedServices);

			Optional optionalTrackedService = optionalEntry.map(
				Map.Entry::getValue);

			return optionalTrackedService.orElse(null);
		}

		@Override
		public T getService(ServiceReference serviceReference) {
			BasicServiceReference basicServiceReference =
				(BasicServiceReference)serviceReference;

			for (Map.Entry, T> entry :
					_trackedServices.entrySet()) {

				if (basicServiceReference.matches(entry.getKey())) {
					return entry.getValue();
				}
			}

			return null;
		}

		@Override
		public ServiceReference getServiceReference() {
			Optional, T>> optionalEntry =
				ServiceRankingUtil.getHighestRankingEntry(_trackedServices);

			Optional> optionalServiceReference =
				optionalEntry.map(Map.Entry::getKey);

			return optionalServiceReference.orElse(null);
		}

		@Override
		public ServiceReference[] getServiceReferences() {
			Set set = (Set)_trackedServices.keySet();

			return set.toArray(new ServiceReference[_trackedServices.size()]);
		}

		@Override
		public Object[] getServices() {
			Collection values = _trackedServices.values();

			return values.toArray();
		}

		@Override
		public T[] getServices(T[] services) {
			Collection values = _trackedServices.values();

			return values.toArray(services);
		}

		@Override
		public SortedMap, T> getTrackedServiceReferences() {
			return _trackedServices;
		}

		@Override
		public int getUpdateMarker() {
			return _stateCounter.get();
		}

		@Override
		public boolean isEmpty() {
			return _trackedServices.isEmpty();
		}

		@Override
		public void modifiedService(
			ServiceReference serviceReference, T service) {

			try {
				if (_serviceTrackerCustomizer != null) {
					_serviceTrackerCustomizer.modifiedService(
						serviceReference, service);
				}
			}
			finally {
				_stateCounter.incrementAndGet();
			}
		}

		@Override
		public void open() {
			_serviceTrackers.put(this, _filter);

			Set, Object>> set =
				_services.entrySet();

			Iterator, Object>> iterator =
				set.iterator();

			while (iterator.hasNext()) {
				Map.Entry, Object> entry = iterator.next();

				BasicServiceReference basicServiceReference =
					(BasicServiceReference)entry.getKey();

				if (_filter.matches(basicServiceReference._properties)) {
					ServiceReference serviceReference =
						(ServiceReference)entry.getKey();

					addingService(serviceReference);
				}
			}
		}

		@Override
		public void open(boolean trackAllServices) {
			open();
		}

		@Override
		public void remove(ServiceReference serviceReference) {
			T service = _trackedServices.remove(serviceReference);

			if (_trackedServices.isEmpty()) {
				_countDownLatch = new CountDownLatch(1);
			}

			removedService(serviceReference, service);
		}

		@Override
		public void removedService(
			ServiceReference serviceReference, T service) {

			try {
				if (_serviceTrackerCustomizer != null) {
					_serviceTrackerCustomizer.removedService(
						serviceReference, service);
				}
			}
			finally {
				_stateCounter.incrementAndGet();
			}
		}

		@Override
		public int size() {
			return _trackedServices.size();
		}

		@Override
		public T waitForService(long timeout) throws InterruptedException {
			_countDownLatch.await(timeout, TimeUnit.MILLISECONDS);

			return getService();
		}

		private volatile CountDownLatch _countDownLatch = new CountDownLatch(1);
		private Filter _filter;
		private final ServiceTrackerCustomizer _serviceTrackerCustomizer;
		private final AtomicInteger _stateCounter = new AtomicInteger();
		private final NavigableMap, T> _trackedServices =
			new ConcurrentSkipListMap<>();

	}

}