blob: 16a4f2074ab08c5373553a770094b9c3c8fd0511 [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.scr.impl.config;
import java.util.Dictionary;
import java.util.Hashtable;
import org.apache.felix.scr.impl.Activator;
import org.apache.felix.scr.impl.ComponentCommands;
import org.apache.felix.scr.impl.manager.ScrConfiguration;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.log.LogService;
import org.osgi.service.metatype.MetaTypeProvider;
/**
* The <code>ScrConfiguration</code> class conveys configuration for the
* Felix DS implementation bundle.
* <p>
* <b>Configuration Source</b>
* <p>
* <ol>
* <li>Framework properties: These are read when the Declarative Services
* implementation is first started.</li>
* <li>Configuration Admin Service: Properties are provided by means of a
* <code>ManagedService</code> with Service PID
* <code>org.apache.felix.scr.ScrService</code>. This class uses an OSGi
* Service Factory ({@link ScrManagedServiceServiceFactory}) to register the
* managed service without requiring the Configuration Admin Service API to be
* required upfront.
* </li>
* </ol>
* <p>
* See the <i>Configuration</i> section of the
* <a href="http://felix.apache.org/site/apache-felix-service-component-runtime.html">Apache Felix Service Component Runtime</a>
* documentation page for detailed information.
*/
public class ScrConfigurationImpl implements ScrConfiguration
{
private static final String VALUE_TRUE = Boolean.TRUE.toString();
private static final String LOG_LEVEL_DEBUG = "debug";
private static final String LOG_LEVEL_INFO = "info";
private static final String LOG_LEVEL_WARN = "warn";
private static final String LOG_LEVEL_ERROR = "error";
private static final String PROP_SHOWTRACE = "ds.showtrace";
private static final String PROP_SHOWERRORS = "ds.showerrors";
private final Activator activator;
private int logLevel;
private boolean factoryEnabled;
private boolean keepInstances;
private boolean infoAsService;
private boolean cacheMetadata;
private long lockTimeout = DEFAULT_LOCK_TIMEOUT_MILLISECONDS;
private long stopTimeout = DEFAULT_STOP_TIMEOUT_MILLISECONDS;
private long serviceChangecountTimeout = DEFAULT_SERVICE_CHANGECOUNT_TIMEOUT_MILLISECONDS;
private Boolean globalExtender;
private volatile BundleContext bundleContext;
private volatile ServiceRegistration<?> managedServiceRef;
private volatile ServiceRegistration<?> metatypeProviderRef;
private ComponentCommands scrCommand;
public ScrConfigurationImpl(Activator activator )
{
this.activator = activator;
}
public void start(final BundleContext bundleContext)
{
this.bundleContext = bundleContext;
// listen for Configuration Admin configuration
final Dictionary<String, Object> msProps = new Hashtable<>();
msProps.put(Constants.SERVICE_PID, PID);
msProps.put(Constants.SERVICE_DESCRIPTION, "SCR Configurator");
msProps.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
// Process configure from bundle context properties so they can be predictably
// overriden by configuration admin later.
// Note that if the managed service is registered first then it is random which will win since
// configuration may be delivered asynchronously
configure( null, false );
managedServiceRef = bundleContext.registerService("org.osgi.service.cm.ManagedService", new ScrManagedServiceServiceFactory(this),
msProps);
final Dictionary<String, Object> mtProps = new Hashtable<>();
mtProps.put(MetaTypeProvider.METATYPE_PID, PID);
mtProps.put(Constants.SERVICE_DESCRIPTION, "SCR Configurator MetaTypeProvider");
mtProps.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
metatypeProviderRef = bundleContext.registerService("org.osgi.service.metatype.MetaTypeProvider", new ScrMetaTypeProviderServiceFactory(this),
mtProps);
}
public void stop()
{
if (this.managedServiceRef != null)
{
this.managedServiceRef.unregister();
this.managedServiceRef = null;
}
if (this.metatypeProviderRef != null)
{
this.metatypeProviderRef.unregister();
this.metatypeProviderRef = null;
}
this.bundleContext = null;
}
public void setScrCommand(ComponentCommands scrCommand)
{
this.scrCommand = scrCommand;
scrCommand.updateProvideScrInfoService(infoAsService());
}
// Called from the ScrManagedService.updated method to reconfigure
void configure( Dictionary<String, ?> config, boolean fromConfig )
{
Boolean newGlobalExtender;
Boolean oldGlobalExtender;
synchronized (this)
{
if ( config == null )
{
if (!fromConfig)
{
if (this.bundleContext == null)
{
logLevel = LogService.LOG_ERROR;
factoryEnabled = false;
keepInstances = false;
infoAsService = false;
lockTimeout = DEFAULT_LOCK_TIMEOUT_MILLISECONDS;
stopTimeout = DEFAULT_STOP_TIMEOUT_MILLISECONDS;
serviceChangecountTimeout = DEFAULT_SERVICE_CHANGECOUNT_TIMEOUT_MILLISECONDS;
newGlobalExtender = false;
cacheMetadata = false;
}
else
{
logLevel = getDefaultLogLevel();
factoryEnabled = getDefaultFactoryEnabled();
keepInstances = getDefaultKeepInstances();
infoAsService = getDefaultInfoAsService();
lockTimeout = getDefaultLockTimeout();
stopTimeout = getDefaultStopTimeout();
serviceChangecountTimeout = getServiceChangecountTimeout();
newGlobalExtender = getDefaultGlobalExtender();
cacheMetadata = getDefaultCacheMetadata();
}
}
else
{
newGlobalExtender = this.globalExtender;
}
}
else
{
logLevel = getLogLevel( config.get( PROP_LOGLEVEL ) );
factoryEnabled = VALUE_TRUE.equalsIgnoreCase( String.valueOf( config.get( PROP_FACTORY_ENABLED ) ) );
keepInstances = VALUE_TRUE.equalsIgnoreCase( String.valueOf( config.get( PROP_DELAYED_KEEP_INSTANCES ) ) );
infoAsService = VALUE_TRUE.equalsIgnoreCase( String.valueOf( config.get( PROP_INFO_SERVICE) ) );
Long timeout = ( Long ) config.get( PROP_LOCK_TIMEOUT );
lockTimeout = timeout == null? DEFAULT_LOCK_TIMEOUT_MILLISECONDS: timeout;
timeout = ( Long ) config.get( PROP_STOP_TIMEOUT );
stopTimeout = timeout == null? DEFAULT_STOP_TIMEOUT_MILLISECONDS: timeout;
newGlobalExtender = VALUE_TRUE.equalsIgnoreCase( String.valueOf( config.get( PROP_GLOBAL_EXTENDER) ) );
cacheMetadata = VALUE_TRUE.equalsIgnoreCase(
String.valueOf(config.get(PROP_CACHE_METADATA)));
}
if ( scrCommand != null )
{
scrCommand.updateProvideScrInfoService( infoAsService() );
}
oldGlobalExtender = this.globalExtender;
this.globalExtender = newGlobalExtender;
}
if ( newGlobalExtender != oldGlobalExtender )
{
activator.restart( newGlobalExtender );
}
}
/**
* Returns the current log level.
* Note that this log level is not used with an R7 LogService implementation.
* @return
*/
@Override
public int getLogLevel()
{
return logLevel;
}
@Override
public boolean isFactoryEnabled()
{
return factoryEnabled;
}
@Override
public boolean keepInstances()
{
return keepInstances;
}
@Override
public boolean infoAsService()
{
return infoAsService;
}
@Override
public long lockTimeout()
{
return lockTimeout;
}
@Override
public long stopTimeout()
{
return stopTimeout;
}
@Override
public boolean globalExtender()
{
return globalExtender;
}
@Override
public boolean cacheMetadata()
{
return cacheMetadata;
}
@Override
public long serviceChangecountTimeout()
{
return serviceChangecountTimeout;
}
private boolean getDefaultFactoryEnabled()
{
return VALUE_TRUE.equals( bundleContext.getProperty( PROP_FACTORY_ENABLED ) );
}
private boolean getDefaultKeepInstances()
{
return VALUE_TRUE.equals( bundleContext.getProperty( PROP_DELAYED_KEEP_INSTANCES ) );
}
private int getDefaultLogLevel()
{
return getLogLevel( bundleContext.getProperty( PROP_LOGLEVEL ) );
}
private boolean getDefaultInfoAsService()
{
return VALUE_TRUE.equalsIgnoreCase( bundleContext.getProperty( PROP_INFO_SERVICE) );
}
private long getDefaultLockTimeout()
{
String val = bundleContext.getProperty( PROP_LOCK_TIMEOUT);
if ( val == null)
{
return DEFAULT_LOCK_TIMEOUT_MILLISECONDS;
}
return Long.parseLong( val );
}
private long getDefaultStopTimeout()
{
String val = bundleContext.getProperty( PROP_STOP_TIMEOUT);
if ( val == null)
{
return DEFAULT_STOP_TIMEOUT_MILLISECONDS;
}
return Long.parseLong( val );
}
private long getServiceChangecountTimeout()
{
String val = bundleContext.getProperty( PROP_SERVICE_CHANGECOUNT_TIMEOUT );
if ( val == null)
{
return DEFAULT_SERVICE_CHANGECOUNT_TIMEOUT_MILLISECONDS;
}
return Long.parseLong( val );
}
private boolean getDefaultGlobalExtender()
{
return VALUE_TRUE.equalsIgnoreCase( bundleContext.getProperty( PROP_GLOBAL_EXTENDER) );
}
private boolean getDefaultCacheMetadata()
{
return VALUE_TRUE.equalsIgnoreCase(
bundleContext.getProperty(PROP_CACHE_METADATA));
}
private int getLogLevel( final Object levelObject )
{
if ( levelObject != null )
{
if ( levelObject instanceof Number )
{
return ( ( Number ) levelObject ).intValue();
}
String levelString = levelObject.toString();
try
{
return Integer.parseInt( levelString );
}
catch ( NumberFormatException nfe )
{
// might be a descriptive name
}
if ( LOG_LEVEL_DEBUG.equalsIgnoreCase( levelString ) )
{
return LogService.LOG_DEBUG;
}
else if ( LOG_LEVEL_INFO.equalsIgnoreCase( levelString ) )
{
return LogService.LOG_INFO;
}
else if ( LOG_LEVEL_WARN.equalsIgnoreCase( levelString ) )
{
return LogService.LOG_WARNING;
}
else if ( LOG_LEVEL_ERROR.equalsIgnoreCase( levelString ) )
{
return LogService.LOG_ERROR;
}
}
// check ds.showtrace property
if ( VALUE_TRUE.equalsIgnoreCase( bundleContext.getProperty( PROP_SHOWTRACE ) ) )
{
return LogService.LOG_DEBUG;
}
// next check ds.showerrors property
if ( "false".equalsIgnoreCase( bundleContext.getProperty( PROP_SHOWERRORS ) ) )
{
return -1; // no logging at all !!
}
// default log level (errors only)
return LogService.LOG_ERROR;
}
}