blob: f05b61d980d6f02b8ed7075a9f9772a9b1aa20eb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.felix.cm.impl.helper;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Dictionary;
import java.util.Hashtable;
import org.apache.felix.cm.impl.ConfigurationManager;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
public class ManagedServiceTracker extends BaseTracker<ManagedService>
{
private static final Dictionary<String, ?> INITIAL_MARKER = new Hashtable<String, Object>( 0 );
public ManagedServiceTracker( ConfigurationManager cm )
{
super( cm, false );
}
@Override
protected ConfigurationMap<?> createConfigurationMap( String[] pids )
{
return new ManagedServiceConfigurationMap( pids );
}
@Override
public String getServicePid( ServiceReference<ManagedService> service, TargetedPID pid )
{
final ConfigurationMap configs = this.getService( service );
if ( configs != null )
{
return configs.getKeyPid( pid );
}
// this service is not handled...
return null;
}
/**
* Provides the given configuration to the managed service.
* <p>
* Depending on targeted PIDs this configuration may not actually be
* provided if the service already has more strictly binding
* configuration from a targeted configuration bound.
* <p>
* If the revision is a negative value, the provided configuration
* is assigned to the ManagedService in any case without further
* checks. This allows a replacement configuration for a deleted
* or invisible configuration to be assigned without first removing
* the deleted or invisible configuration.
*/
@Override
public void provideConfiguration( ServiceReference<ManagedService> service, TargetedPID configPid,
TargetedPID factoryPid, Dictionary<String, ?> properties, long revision, ConfigurationMap<?> configs )
{
Dictionary<String, ?> supplied = ( properties == null ) ? INITIAL_MARKER : properties;
updateService( service, configPid, supplied, revision, configs );
}
@Override
public void removeConfiguration( ServiceReference<ManagedService> service, TargetedPID configPid,
TargetedPID factoryPid )
{
updateService( service, configPid, null, -1, null );
}
private void updateService( ServiceReference<ManagedService> service, final TargetedPID configPid,
Dictionary<String, ?> properties, long revision, ConfigurationMap<?> configs)
{
// Get the ManagedService and terminate here if already
// unregistered from the framework concurrently
final ManagedService srv = this.getRealService( service );
if (srv == null) {
return;
}
// Get the Configuration-to-PID map from the parameter or from
// the service tracker. If not available, the service tracker
// already unregistered this service concurrently
if ( configs == null )
{
configs = this.getService( service );
if ( configs == null )
{
return;
}
}
// Both the ManagedService to update and the Configuration-to-PID
// are available, so the service can be updated with the
// configuration (which may be null)
boolean doUpdate = false;
if ( properties == null )
{
doUpdate = configs.removeConfiguration( configPid, null );
}
else if ( properties == INITIAL_MARKER )
{
// initial call to ManagedService may supply null properties
properties = null;
revision = -1;
doUpdate = true;
}
else if ( revision < 0 || configs.shallTake( configPid, null, revision ) )
{
// run the plugins and cause the update
properties = getProperties( properties, service, configPid.toString(), null );
doUpdate = true;
revision = Math.abs( revision );
}
else
{
// new configuration is not a better match, don't update
doUpdate = false;
}
if ( doUpdate )
{
try
{
updated( service, srv, properties );
configs.record( configPid, null, revision );
}
catch ( Throwable t )
{
this.handleCallBackError( t, service, configPid );
}
finally
{
this.ungetRealService( service );
}
}
}
private void updated( final ServiceReference<ManagedService> reference, final ManagedService service, final Dictionary properties) throws ConfigurationException
{
if ( System.getSecurityManager() != null )
{
try
{
AccessController.doPrivileged( new PrivilegedExceptionAction()
{
public Object run() throws ConfigurationException
{
service.updated( properties );
return null;
}
}, getAccessControlContext( reference.getBundle() ) );
}
catch ( PrivilegedActionException e )
{
throw ( ConfigurationException ) e.getException();
}
}
else
{
service.updated( properties );
}
}
}