/*
* 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 java.util.Hashtable;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.felix.cm.PersistenceManager;
import org.apache.felix.cm.file.FilePersistenceManager;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* Activator for the configuration admin implementation.
* When the bundle is started this activator:
* <ul>
* <li>Sets up the logger {@link Log}.
* <li>A {@link FilePersistenceManager} instance is registered as a default
* {@link PersistenceManager}.
* <li>Creates and sets up the {@link ConfigurationManager}.
* </ul>
* <p>
* The default {@link FilePersistenceManager} is configured with a configuration
* location taken from the <code>felix.cm.dir</code> framework property. If
* this property is not set the <code>config</code> directory in the current
* working directory as specified in the <code>user.dir</code> system property
* is used.
*/
public class Activator implements BundleActivator
{
/**
* The name of the bundle context property defining the location for the
* configuration files (value is "felix.cm.dir").
*
* @see #start(BundleContext)
*/
private static final String CM_CONFIG_DIR = "felix.cm.dir";
private volatile ConfigurationManager manager;
// the service registration of the default file persistence manager
private volatile ServiceRegistration<PersistenceManager> filepmRegistration;
// service tracker for optional coordinator
@SuppressWarnings("rawtypes")
private volatile ServiceTracker coordinatorTracker;
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void start( final BundleContext bundleContext )
{
// setup log
Log.logger.start(bundleContext);
// register default file persistence manager
// set up the location (might throw IllegalArgumentException)
DynamicBindings dynamicBindings = null;
try
{
final FilePersistenceManager fpm = new FilePersistenceManager( bundleContext,
bundleContext.getProperty( CM_CONFIG_DIR ) );
final Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
props.put( Constants.SERVICE_VENDOR, "The Apache Software Foundation" );
props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
filepmRegistration = bundleContext.registerService( PersistenceManager.class, fpm, props );
// setup dynamic configuration bindings
dynamicBindings = new DynamicBindings( bundleContext, fpm );
}
catch ( IOException ioe )
{
Log.logger.log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
}
catch ( IllegalArgumentException iae )
{
Log.logger.log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
}
this.manager = new ConfigurationManager();
// start coordinator tracker
coordinatorTracker = new ServiceTracker(bundleContext, "org.osgi.service.coordinator.Coordinator",
new ServiceTrackerCustomizer()
{
private final SortedMap<ServiceReference, Object> sortedServices = new TreeMap<ServiceReference, Object>();
@Override
public Object addingService(final ServiceReference reference)
{
final Object srv = bundleContext.getService(reference);
if ( srv != null )
{
synchronized ( this.sortedServices )
{
sortedServices.put(reference, srv);
manager.setCoordinator(sortedServices.get(sortedServices.lastKey()));
}
}
return srv;
}
@Override
public void modifiedService(final ServiceReference reference, final Object srv) {
synchronized ( this.sortedServices )
{
// update the map, service ranking might have changed
sortedServices.remove(reference);
sortedServices.put(reference, srv);
manager.setCoordinator(sortedServices.get(sortedServices.lastKey()));
}
}
@Override
public void removedService(final ServiceReference reference, final Object service) {
synchronized ( this.sortedServices )
{
sortedServices.remove(reference);
if ( sortedServices.isEmpty() )
{
manager.setCoordinator(null);
}
else
{
manager.setCoordinator(sortedServices.get(sortedServices.lastKey()));
}
}
bundleContext.ungetService(reference);
}
});
coordinatorTracker.open();
// start configuration manager implementation
final ServiceReference<ConfigurationAdmin> ref = this.manager.start(dynamicBindings, bundleContext);
// update log
Log.logger.set(ref);
}
@Override
public void stop( final BundleContext bundleContext )
{
// stop logger
Log.logger.stop();
// stop configuration manager implementation
if ( this.manager != null )
{
this.manager.stop(bundleContext);
this.manager = null;
}
// stop coordinator tracker
if ( this.coordinatorTracker != null )
{
this.coordinatorTracker.close();
this.coordinatorTracker = null;
}
// shutdown the file persistence manager
if ( filepmRegistration != null )
{
filepmRegistration.unregister();
filepmRegistration = null;
}
}
}