blob: b5192cf49d9b5dabd28ee0b64e76e2409243a16d [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;
import java.io.IOException;
import java.util.Dictionary;
import org.apache.felix.cm.PersistenceManager;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
abstract class ConfigurationBase
{
/**
* The {@link ConfigurationManager configuration manager} instance which
* caused this configuration object to be created.
*/
private final ConfigurationManager configurationManager;
// the persistence manager storing this factory mapping
private final PersistenceManager persistenceManager;
// the basic ID of this instance
private final String baseId;
/**
* The statically bound bundle location, which is set explicitly by calling
* the Configuration.setBundleLocation(String) method.
*/
private volatile String staticBundleLocation;
/**
* The bundle location from dynamic binding. This value is set as the
* configuration or factory is assigned to a ManagedService[Factory].
*/
private volatile String dynamicBundleLocation;
/**
* The <code>ServiceReference</code> of the serviceReference which first
* asked for this instance. This field is <code>null</code> if the instance
* has not been handed to a serviceReference by way of the
* <code>ManagedService.update(Dictionary)</code> or
* <code>ManagedServiceFactory.updated(String, Dictionary)</code> method.
*/
private volatile ServiceReference serviceReference;
protected ConfigurationBase( final ConfigurationManager configurationManager,
final PersistenceManager persistenceManager, final String baseId, final String bundleLocation )
{
if ( configurationManager == null )
{
throw new IllegalArgumentException( "ConfigurationManager must not be null" );
}
if ( persistenceManager == null )
{
throw new IllegalArgumentException( "PersistenceManager must not be null" );
}
this.configurationManager = configurationManager;
this.persistenceManager = persistenceManager;
this.baseId = baseId;
// set bundle location from persistence and/or check for dynamic binding
this.staticBundleLocation = bundleLocation;
this.dynamicBundleLocation = configurationManager.getDynamicBundleLocation( baseId );
}
ConfigurationManager getConfigurationManager()
{
return configurationManager;
}
PersistenceManager getPersistenceManager()
{
return persistenceManager;
}
String getBaseId()
{
return baseId;
}
String getBundleLocation()
{
if ( dynamicBundleLocation != null )
{
return dynamicBundleLocation;
}
return staticBundleLocation;
}
String getDynamicBundleLocation()
{
return dynamicBundleLocation;
}
String getStaticBundleLocation()
{
return staticBundleLocation;
}
boolean isStaticallyBound()
{
// TODO: consider static location too ? to indicate whether we are
// actually bound ?
return dynamicBundleLocation == null;
}
void setServiceReference( ServiceReference serviceReference )
{
this.serviceReference = serviceReference;
}
ServiceReference getServiceReference()
{
return serviceReference;
}
void setStaticBundleLocation( final String bundleLocation )
{
// 104.15.2.8 The bundle location will be set persistently
this.staticBundleLocation = bundleLocation;
storeSilently();
// FELIX-1488: If a configuration is bound to a location and a new
// location is statically set, the old binding must be removed
// by removing the configuration from the targets and the new binding
// must be setup by updating the configuration for new targets
if ( ( this instanceof ConfigurationImpl ) && ( bundleLocation != null ) )
{
// remove configuration from current managed service [factory]
if ( getDynamicBundleLocation() != null && !bundleLocation.equals( getDynamicBundleLocation() ) )
{
getConfigurationManager().revokeConfiguration( ( ConfigurationImpl ) this );
}
// check whether we have to assign the configuration to new targets
getConfigurationManager().reassignConfiguration( ( ConfigurationImpl ) this );
}
}
void setDynamicBundleLocation( final String bundleLocation )
{
this.dynamicBundleLocation = bundleLocation;
this.configurationManager.setDynamicBundleLocation( this.getBaseId(), bundleLocation );
// FELIX-1488: If a dynamically bound configuration is unbound and not
// statically bound, it may be rebound to another bundle asking for it
// (unless the dynamic unbind happens due to configuration deletion)
if ( bundleLocation == null && getStaticBundleLocation() == null && ( this instanceof ConfigurationImpl ) )
{
getConfigurationManager().reassignConfiguration( ( ConfigurationImpl ) this );
}
}
/**
* Tries to bind this configuration or factory to the given bundle location:
* <ul>
* <li>If already dynamically bound, <code>true</code> is returned if the
* dynamic binding equals the desired binding. Otherwise <code>false</code>
* is returned.</li>
* <li>If not dynamically bound but statically bound and the static binding
* is not equal to the desired binding, <code>false</code> is returned.</li>
* <li>Otherwise this configuration or factory is dynamically bound to the
* desired location and <code>true</code> is returned.</li>
* </ul>
*
* @param bundleLocation
* The desired bundle location to which this configuration or
* factory should be dynamically bound.
* @return <code>true</code> if this configuration or factory is dynamically
* bound to the desired location.
*/
boolean tryBindLocation( final String bundleLocation )
{
if ( this.dynamicBundleLocation != null )
{
return this.dynamicBundleLocation.equals( bundleLocation );
}
else if ( this.staticBundleLocation != null && !this.staticBundleLocation.equals( bundleLocation ) )
{
return false;
}
setDynamicBundleLocation( bundleLocation );
return true;
}
abstract void store() throws IOException;
void storeSilently()
{
try
{
this.store();
}
catch ( IOException ioe )
{
configurationManager.log( LogService.LOG_ERROR, "Persisting new bundle location failed", ioe );
}
}
static protected void replaceProperty( Dictionary properties, String key, String value )
{
if ( value == null )
{
properties.remove( key );
}
else
{
properties.put( key, value );
}
}
}