/** * 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.map.test; import com.liferay.arquillian.deploymentscenario.annotations.BndFile; import com.liferay.osgi.service.tracker.collections.internal.map.BundleContextWrapper; import com.liferay.osgi.service.tracker.collections.internal.map.TrackedOne; import com.liferay.osgi.service.tracker.collections.internal.map.TrackedTwo; import com.liferay.osgi.service.tracker.collections.map.PropertyServiceReferenceMapper; import com.liferay.osgi.service.tracker.collections.map.ServiceReferenceMapper; import com.liferay.osgi.service.tracker.collections.map.ServiceTrackerCustomizerFactory; import com.liferay.osgi.service.tracker.collections.map.ServiceTrackerCustomizerFactory.ServiceWrapper; import com.liferay.osgi.service.tracker.collections.map.ServiceTrackerMap; import com.liferay.osgi.service.tracker.collections.map.ServiceTrackerMapFactory; import java.util.Collection; import java.util.Comparator; import java.util.Dictionary; import java.util.Hashtable; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.util.tracker.ServiceTrackerCustomizer; /** * @author Carlos Sierra Andrés */ @BndFile("src/testIntegration/resources/bnd.bnd") @RunWith(Arquillian.class) public class ObjectServiceTrackerMapTest { @Before public void setUp() throws BundleException { bundle.start(); _bundleContext = bundle.getBundleContext(); } @After public void tearDown() throws BundleException { bundle.stop(); if (_serviceTrackerMap != null) { _serviceTrackerMap.close(); _serviceTrackerMap = null; } } @Test public void testGetServiceAfterRemoval() { ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = createServiceTrackerMap(_bundleContext); ServiceRegistration<TrackedOne> serviceRegistration = registerService( new TrackedOne()); Assert.assertNotNull(serviceTrackerMap.getService("aTarget")); serviceRegistration.unregister(); Assert.assertNull(serviceTrackerMap.getService("aTarget")); } @Test public void testGetServiceGetsReplacedAfterRemoval() { ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = createServiceTrackerMap(_bundleContext); TrackedOne trackedOne1 = new TrackedOne(); ServiceRegistration<TrackedOne> serviceRegistration1 = registerService( trackedOne1, 2); TrackedOne trackedOne2 = new TrackedOne(); ServiceRegistration<TrackedOne> serviceRegistration2 = registerService( trackedOne2, 1); Assert.assertEquals( trackedOne1, serviceTrackerMap.getService("aTarget")); serviceRegistration1.unregister(); Assert.assertEquals( trackedOne2, serviceTrackerMap.getService("aTarget")); serviceRegistration2.unregister(); } @Test public void testGetServiceGetsReplacedAfterRemovalInverseOrder() { ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = createServiceTrackerMap(_bundleContext); TrackedOne trackedOne2 = new TrackedOne(); registerService(trackedOne2, 1); TrackedOne trackedOne1 = new TrackedOne(); ServiceRegistration<TrackedOne> serviceRegistration1 = registerService( trackedOne1, 2); Assert.assertEquals( trackedOne1, serviceTrackerMap.getService("aTarget")); serviceRegistration1.unregister(); Assert.assertEquals( trackedOne2, serviceTrackerMap.getService("aTarget")); } @Test public void testGetServiceInvokesCustomizerOnlyOnce() { final AtomicInteger atomicInteger = new AtomicInteger(0); ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = ServiceTrackerMapFactory.openSingleValueMap( _bundleContext, TrackedOne.class, "(target=*)", new ServiceReferenceMapper<String, TrackedOne>() { @Override public void map( ServiceReference<TrackedOne> serviceReference, Emitter<String> emitter) { emitter.emit("one"); emitter.emit("two"); } }, new ServiceTrackerCustomizer<TrackedOne, TrackedOne>() { @Override public TrackedOne addingService( ServiceReference<TrackedOne> serviceReference) { atomicInteger.incrementAndGet(); return _bundleContext.getService(serviceReference); } @Override public void modifiedService( ServiceReference<TrackedOne> serviceReference, TrackedOne trackedTwo) { } @Override public void removedService( ServiceReference<TrackedOne> serviceReference, TrackedOne trackedTwo) { _bundleContext.ungetService(serviceReference); } }); TrackedOne trackedOne = new TrackedOne("1"); ServiceRegistration<TrackedOne> serviceRegistration = registerService( trackedOne, "one"); Assert.assertEquals(serviceTrackerMap.getService("one"), trackedOne); Assert.assertEquals(serviceTrackerMap.getService("two"), trackedOne); Assert.assertEquals(1, atomicInteger.get()); serviceRegistration.unregister(); serviceTrackerMap.close(); } @Test public void testGetServiceIsNullAfterDeregistration() { ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = createServiceTrackerMap(_bundleContext); ServiceRegistration<TrackedOne> serviceRegistration1 = registerService( new TrackedOne()); ServiceRegistration<TrackedOne> serviceRegistration2 = registerService( new TrackedOne()); ServiceRegistration<TrackedOne> serviceRegistration3 = registerService( new TrackedOne()); Assert.assertNotNull(serviceTrackerMap.getService("aTarget")); serviceRegistration1.unregister(); serviceRegistration2.unregister(); serviceRegistration3.unregister(); Assert.assertNull(serviceTrackerMap.getService("aTarget")); } @Test public void testGetServiceWithCustomComparator() { ServiceReferenceMapper<String, TrackedOne> propertyServiceReferenceMapper = new PropertyServiceReferenceMapper<>("target"); ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = ServiceTrackerMapFactory.openSingleValueMap( _bundleContext, TrackedOne.class, "(target=*)", propertyServiceReferenceMapper, new Comparator<ServiceReference<TrackedOne>>() { @Override public int compare( ServiceReference<TrackedOne> serviceReference1, ServiceReference<TrackedOne> serviceReference2) { return -1; } }); TrackedOne trackedOne1 = new TrackedOne(); ServiceRegistration<TrackedOne> serviceRegistration1 = registerService( trackedOne1); TrackedOne trackedOne2 = new TrackedOne(); ServiceRegistration<TrackedOne> serviceRegistration2 = registerService( trackedOne2); Assert.assertEquals( trackedOne2, serviceTrackerMap.getService("aTarget")); serviceRegistration1.unregister(); serviceRegistration2.unregister(); registerService(trackedOne2); registerService(trackedOne1); Assert.assertEquals( trackedOne1, serviceTrackerMap.getService("aTarget")); serviceTrackerMap.close(); } @Test public void testGetServiceWithCustomServiceReferenceMapper() { ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = ServiceTrackerMapFactory.openSingleValueMap( _bundleContext, TrackedOne.class, "(&(other=*)(target=*))", new ServiceReferenceMapper<String, TrackedOne>() { @Override public void map( ServiceReference<TrackedOne> serviceReference, Emitter<String> keys) { keys.emit( serviceReference.getProperty("other") + " - " + serviceReference.getProperty("target")); } }); Dictionary<String, String> properties = new Hashtable<>(); properties.put("other", "aProperty"); properties.put("target", "aTarget"); _bundleContext.registerService( TrackedOne.class, new TrackedOne(), properties); Assert.assertNotNull( serviceTrackerMap.getService("aProperty - aTarget")); } @Test public void testGetServiceWithIncorrectKey() { ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = createServiceTrackerMap(_bundleContext); registerService(new TrackedOne(), "anotherTarget"); Assert.assertNull(serviceTrackerMap.getService("aTarget")); } @Test public void testGetServiceWithModifiedService() { ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = createServiceTrackerMap(_bundleContext); Hashtable<String, Object> properties = new Hashtable<>(); properties.put("target", new String[] {"one", "two"}); ServiceRegistration<TrackedOne> serviceRegistration = _bundleContext.registerService( TrackedOne.class, new TrackedOne(), properties); Assert.assertTrue(serviceTrackerMap.containsKey("one")); Assert.assertTrue(serviceTrackerMap.containsKey("two")); properties.put("target", new String[] {"two", "three"}); serviceRegistration.setProperties(properties); Assert.assertTrue(serviceTrackerMap.containsKey("two")); Assert.assertTrue(serviceTrackerMap.containsKey("three")); Assert.assertFalse(serviceTrackerMap.containsKey("one")); serviceRegistration.unregister(); serviceTrackerMap.close(); } @Test public void testGetServiceWithMultiPropertyRegistration() { try (ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = createServiceTrackerMap(_bundleContext)) { Dictionary<String, Object> properties = new Hashtable<>(); properties.put("service.ranking", 1); properties.put("target", new String[] {"aTarget1", "aTarget2"}); ServiceRegistration<TrackedOne> serviceRegistration = _bundleContext.registerService( TrackedOne.class, new TrackedOne(), properties); Assert.assertNotNull(serviceTrackerMap.getService("aTarget1")); Assert.assertNotNull(serviceTrackerMap.getService("aTarget2")); serviceRegistration.unregister(); } } @Test public void testGetServiceWithServiceTrackerCustomizer() { ServiceTrackerMap<String, TrackedTwo> serviceTrackerMap = ServiceTrackerMapFactory.openSingleValueMap( _bundleContext, TrackedOne.class, "target", new ServiceTrackerCustomizer<TrackedOne, TrackedTwo>() { @Override public TrackedTwo addingService( ServiceReference<TrackedOne> serviceReference) { return new TrackedTwo( _bundleContext.getService(serviceReference)); } @Override public void modifiedService( ServiceReference<TrackedOne> serviceReference, TrackedTwo service) { removedService(serviceReference, service); } @Override public void removedService( ServiceReference<TrackedOne> serviceReference, TrackedTwo service) { _bundleContext.ungetService(serviceReference); } }); TrackedOne trackedOne1 = new TrackedOne(); registerService(trackedOne1, "one"); TrackedOne trackedOne2 = new TrackedOne(); registerService(trackedOne2, "two"); TrackedTwo trackedTwo1 = serviceTrackerMap.getService("one"); Assert.assertEquals(trackedOne1, trackedTwo1.getTrackedOne()); TrackedTwo trackedTwo2 = serviceTrackerMap.getService("two"); Assert.assertEquals(trackedOne2, trackedTwo2.getTrackedOne()); serviceTrackerMap.close(); } @Test public void testGetServiceWithServiceTrackerCustomizerAndServiceReferenceMapper() { ServiceTrackerMap<String, TrackedTwo> serviceTrackerMap = ServiceTrackerMapFactory.openSingleValueMap( _bundleContext, TrackedOne.class, "(target=*)", new ServiceReferenceMapper<String, TrackedOne>() { @Override public void map( ServiceReference<TrackedOne> serviceReference, Emitter<String> emitter) { TrackedOne trackedOne = _bundleContext.getService( serviceReference); emitter.emit( serviceReference.getProperty("target") + "-" + trackedOne.getKey()); _bundleContext.ungetService(serviceReference); } }, new ServiceTrackerCustomizer<TrackedOne, TrackedTwo>() { @Override public TrackedTwo addingService( ServiceReference<TrackedOne> serviceReference) { return new TrackedTwo( _bundleContext.getService(serviceReference)); } @Override public void modifiedService( ServiceReference<TrackedOne> serviceReference, TrackedTwo trackedTwo) { removedService(serviceReference, trackedTwo); } @Override public void removedService( ServiceReference<TrackedOne> serviceReference, TrackedTwo trackedTwo) { _bundleContext.ungetService(serviceReference); } }); TrackedOne trackedOne1 = new TrackedOne("1"); registerService(trackedOne1, "one"); TrackedOne trackedOne2 = new TrackedOne("2"); registerService(trackedOne2, "two"); TrackedTwo trackedTwo1 = serviceTrackerMap.getService("one-1"); Assert.assertEquals(trackedOne1, trackedTwo1.getTrackedOne()); TrackedTwo trackedTwo2 = serviceTrackerMap.getService("two-2"); Assert.assertEquals(trackedOne2, trackedTwo2.getTrackedOne()); serviceTrackerMap.close(); } @Test public void testGetServiceWithServiceTrackerCustomizerReturningNull() { ServiceTrackerMap<String, TrackedTwo> serviceTrackerMap = ServiceTrackerMapFactory.openSingleValueMap( _bundleContext, TrackedOne.class, "(target=*)", new ServiceReferenceMapper<String, TrackedOne>() { @Override public void map( ServiceReference<TrackedOne> serviceReference, Emitter<String> emitter) { emitter.emit( (String)serviceReference.getProperty("target")); emitter.emit( (String)serviceReference.getProperty("target")); } }, new ServiceTrackerCustomizer<TrackedOne, TrackedTwo>() { @Override public TrackedTwo addingService( ServiceReference<TrackedOne> serviceReference) { return null; } @Override public void modifiedService( ServiceReference<TrackedOne> serviceReference, TrackedTwo trackedTwo) { } @Override public void removedService( ServiceReference<TrackedOne> serviceReference, TrackedTwo trackedTwo) { } }); TrackedOne trackedOne = new TrackedOne("1"); ServiceRegistration<TrackedOne> serviceRegistration = registerService( trackedOne, "one"); Assert.assertFalse(serviceTrackerMap.containsKey("one")); serviceRegistration.unregister(); serviceTrackerMap.close(); } @Test public void testGetServiceWithSimpleRegistration() { ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = createServiceTrackerMap(_bundleContext); registerService(new TrackedOne()); Assert.assertNotNull(serviceTrackerMap.getService("aTarget")); } @Test public void testOperationBalancesOutGetServiceAndUngetService() { BundleContextWrapper bundleContextWrapper = wrapContext(); ServiceTrackerMap<String, TrackedOne> serviceTrackerMap = createServiceTrackerMap(bundleContextWrapper); ServiceRegistration<TrackedOne> serviceRegistration1 = registerService( new TrackedOne()); ServiceRegistration<TrackedOne> serviceRegistration2 = registerService( new TrackedOne()); serviceRegistration2.unregister(); serviceRegistration2 = registerService(new TrackedOne()); serviceRegistration2.unregister(); serviceRegistration1.unregister(); Map<ServiceReference<?>, AtomicInteger> serviceReferenceCountsMap = bundleContextWrapper.getServiceReferenceCountsMap(); Collection<AtomicInteger> serviceReferenceCounts = serviceReferenceCountsMap.values(); Assert.assertEquals( serviceReferenceCounts.toString(), 3, serviceReferenceCounts.size()); for (AtomicInteger serviceReferenceCount : serviceReferenceCounts) { Assert.assertEquals(0, serviceReferenceCount.get()); } serviceTrackerMap.close(); } @Test public void testServiceWrapperServiceTrackerCustomizer() { ServiceTrackerMap<String, ServiceWrapper<TrackedOne>> serviceTrackerMap = ServiceTrackerMapFactory.openSingleValueMap( _bundleContext, TrackedOne.class, "target", ServiceTrackerCustomizerFactory.<TrackedOne>serviceWrapper( _bundleContext)); try { Dictionary<String, Object> properties = new Hashtable<>(); properties.put("property", "aProperty"); properties.put("target", "aTarget"); TrackedOne trackedOne = new TrackedOne(); ServiceRegistration<TrackedOne> serviceRegistration = _bundleContext.registerService( TrackedOne.class, trackedOne, properties); ServiceWrapper<TrackedOne> serviceWrapper = serviceTrackerMap.getService("aTarget"); Assert.assertEquals(trackedOne, serviceWrapper.getService()); Map<String, Object> serviceWrapperProperties = serviceWrapper.getProperties(); Assert.assertTrue(serviceWrapperProperties.containsKey("property")); Assert.assertTrue(serviceWrapperProperties.containsKey("target")); Assert.assertEquals( "aProperty", serviceWrapperProperties.get("property")); Assert.assertEquals( "aTarget", serviceWrapperProperties.get("target")); serviceRegistration.unregister(); } finally { serviceTrackerMap.close(); } } @Test public void testUnkeyedServiceReferencesBalanceReferenceCount() { BundleContextWrapper wrappedBundleContext = wrapContext(); ServiceTrackerMap<TrackedOne, TrackedOne> serviceTrackerMap = ServiceTrackerMapFactory.openSingleValueMap( wrappedBundleContext, TrackedOne.class, null, new ServiceReferenceMapper<TrackedOne, TrackedOne>() { @Override public void map( ServiceReference<TrackedOne> serviceReference, Emitter<TrackedOne> emitter) { } }); ServiceRegistration<TrackedOne> serviceRegistration1 = registerService( new TrackedOne()); ServiceRegistration<TrackedOne> serviceRegistration2 = registerService( new TrackedOne()); Map<ServiceReference<?>, AtomicInteger> serviceReferenceCountsMap = wrappedBundleContext.getServiceReferenceCountsMap(); Collection<AtomicInteger> serviceReferenceCounts = serviceReferenceCountsMap.values(); Assert.assertEquals( serviceReferenceCounts.toString(), 0, serviceReferenceCounts.size()); serviceRegistration1.unregister(); serviceRegistration2.unregister(); Assert.assertEquals( serviceReferenceCounts.toString(), 0, serviceReferenceCounts.size()); serviceTrackerMap.close(); } @ArquillianResource public Bundle bundle; protected ServiceTrackerMap<String, TrackedOne> createServiceTrackerMap( BundleContext bundleContext) { return ServiceTrackerMapFactory.openSingleValueMap( bundleContext, TrackedOne.class, "target"); } protected ServiceRegistration<TrackedOne> registerService( TrackedOne trackedOne) { return registerService(trackedOne, "aTarget"); } protected ServiceRegistration<TrackedOne> registerService( TrackedOne trackedOne, int ranking) { return registerService(trackedOne, ranking, "aTarget"); } protected ServiceRegistration<TrackedOne> registerService( TrackedOne trackedOne, int ranking, String target) { Dictionary<String, Object> properties = new Hashtable<>(); properties.put("service.ranking", ranking); properties.put("target", target); return _bundleContext.registerService( TrackedOne.class, trackedOne, properties); } protected ServiceRegistration<TrackedOne> registerService( TrackedOne trackedOne, String target) { Dictionary<String, Object> properties = new Hashtable<>(); properties.put("target", target); return _bundleContext.registerService( TrackedOne.class, trackedOne, properties); } protected BundleContextWrapper wrapContext() { return new BundleContextWrapper(_bundleContext); } private BundleContext _bundleContext; private ServiceTrackerMap<String, TrackedOne> _serviceTrackerMap; }