org.eclipse.sisu.osgi.BindingTracker Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2010-present Sonatype, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Stuart McCulloch (Sonatype, Inc.) - initial API and implementation
*******************************************************************************/
package org.eclipse.sisu.osgi;
import java.util.Collection;
import org.eclipse.sisu.inject.BindingSubscriber;
import org.eclipse.sisu.inject.Logs;
import org.eclipse.sisu.inject.Weak;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
/**
* Tracker of {@link ServiceBinding}s from the OSGi service registry.
*/
final class BindingTracker
extends ServiceTracker>
{
// ----------------------------------------------------------------------
// Implementation fields
// ----------------------------------------------------------------------
private final Collection> subscribers = Weak.elements();
private final String clazzName;
private final int maxRank;
private boolean isOpen;
// ----------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------
BindingTracker( final BundleContext context, final int maxRank, final String clazzName )
{
super( context, clazzName, null );
this.clazzName = clazzName;
this.maxRank = maxRank;
}
// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------
public void subscribe( final BindingSubscriber subscriber )
{
synchronized ( subscribers )
{
openIfNecessary();
for ( final ServiceBinding binding : getTracked().values() )
{
if ( binding.isCompatibleWith( subscriber ) )
{
subscriber.add( binding, binding.rank() );
}
}
subscribers.add( subscriber );
}
}
public void unsubscribe( final BindingSubscriber subscriber )
{
synchronized ( subscribers )
{
if ( subscribers.remove( subscriber ) )
{
for ( final ServiceBinding binding : getTracked().values() )
{
subscriber.remove( binding );
}
}
closeIfNecessary();
}
}
@Override
public ServiceBinding addingService( final ServiceReference reference )
{
final ServiceBinding binding;
try
{
binding = new ServiceBinding( context, clazzName, maxRank, reference );
}
catch ( final Exception e )
{
Logs.warn( "Problem subscribing to service: {}", reference, e );
return null;
}
synchronized ( subscribers )
{
for ( final BindingSubscriber subscriber : subscribers )
{
if ( binding.isCompatibleWith( subscriber ) )
{
subscriber.add( binding, binding.rank() );
}
}
closeIfNecessary();
}
return binding;
}
@Override
public void removedService( final ServiceReference reference, final ServiceBinding binding )
{
synchronized ( subscribers )
{
for ( final BindingSubscriber subscriber : subscribers )
{
subscriber.remove( binding );
}
closeIfNecessary();
}
super.removedService( reference, binding );
}
// ----------------------------------------------------------------------
// Implementation methods
// ----------------------------------------------------------------------
private void openIfNecessary()
{
if ( !isOpen )
{
open( true ); // calls addingService to pre-fill the tracker
Logs.trace( "Started tracking services: {}", filter, null );
isOpen = true; // set last to avoid premature close
}
}
private void closeIfNecessary()
{
if ( isOpen && subscribers.isEmpty() )
{
isOpen = false; // set first to avoid repeated close
Logs.trace( "Stopped tracking services: {}", filter, null );
close(); // calls removedService to clear out the tracker
}
}
}