/*******************************************************************************
* Copyright (c) 2008 Cambridge Semantics Incorporated.
* 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:
* Cambridge Semantics Incorporated - initial API and implementation
*******************************************************************************/
package org.openanzo.osgi.bootstrap;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Map.Entry;
import org.openanzo.exceptions.LogUtils;
import org.openanzo.osgi.ServiceActivator;
import org.openanzo.services.ServicesDictionary;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.packageadmin.PackageAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com</a>)
*
*/
public class BootstrapActivator extends ServiceActivator {
private static final Logger log = LoggerFactory.getLogger(BootstrapActivator.class);
private ManifestConfigurationListener listener = null;
private static final String SERVICE_PID = "org.openanzo.osgi.Bootstrap";
enum Mode {
//If configuration already exists, do nothing with the new properties
IGNORE,
//If configuration already exists, add any new properties contained within file, without overwriting existing properties
AUGMENT,
//If configuration already exists, add any new properties contained within file, and update existing properties with new value
UPDATE,
//Remove old configuration and replace with new properties
REPLACE
}
private Mode mode = Mode.IGNORE;
@Override
public String getServicePid() {
return SERVICE_PID;
}
@Override
public boolean registerService() {
return false;
}
@Override
public String[] getDependencies() {
return new String[] { ConfigurationAdmin.class.getName(), PackageAdmin.class.getName(), org.osgi.service.startlevel.StartLevel.class.getName() };
}
@Override
public boolean startThreaded() {
return false;
}
@Override
public void start(BundleContext bundleContext) throws Exception {
super.start(bundleContext);
String modeString = context.getProperty("org.openanzo.osgi.bootstrap.mode");
if (modeString != null) {
mode = Mode.valueOf(modeString);
}
}
@Override
public void serviceAvailable(String type, ServiceReference ref, Object service) {
if (type.equals(ConfigurationAdmin.class.getName())) {
String bootStrap = context.getProperty("org.openanzo.osgi.bootstrap.path");
if (bootStrap != null) {
StringTokenizer st = new StringTokenizer(bootStrap, ":");
while (st.hasMoreElements()) {
String path = st.nextToken().trim();
File pathFile = new File(path);
if (pathFile.exists()) {
if (pathFile.isDirectory()) {
loadDirectory(pathFile);
} else {
try {
loadBootStrapFile(null, new FileInputStream(pathFile));
} catch (FileNotFoundException fnfe) {
log.error(LogUtils.LIFECYCLE_MARKER, "Error loading bootstrap properties file:" + pathFile, fnfe);
}
}
}
}
}
listener = new ManifestConfigurationListener(context, this);
listener.open();
}
}
static final String FILE_EXTENSION = ".properties";
private void loadDirectory(File dir) {
File files[] = dir.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.isDirectory() || pathname.getName().endsWith(FILE_EXTENSION);
}
});
Arrays.sort(files, new Comparator<File>() {
public int compare(File o1, File o2) { //NO_UCD
return o1.getName().compareTo(o2.getName());
}
});
for (File file : files) {
if (file.exists()) {
if (file.isDirectory()) {
loadDirectory(file);
} else {
try {
loadBootStrapFile(null, new FileInputStream(file));
} catch (FileNotFoundException fnfe) {
log.error(LogUtils.LIFECYCLE_MARKER, "Error loading bootstrap properties file:" + file, fnfe);
}
}
}
}
}
@SuppressWarnings( { "unchecked", "null" })
// marshal between Configuration type
void loadBootStrapFile(Bundle bundle, InputStream file) {
ConfigurationAdmin configurationAdmin = getDependency(ConfigurationAdmin.class);
try {
Properties properties = new Properties();
properties.load(file);
if (bundle != null) {
properties.put("bundleId", Long.toString(bundle.getBundleId()));
}
String factoryPid = (String) properties.get("service.factoryPid");
if (factoryPid != null) {
String instanceUri = ServicesDictionary.getInstanceURI(properties);
Configuration[] cfgs = null;
if (instanceUri != null) {
cfgs = configurationAdmin.listConfigurations("(&(" + ServicesDictionary.KEY_INSTANCE_URI + "=" + instanceUri + ")(service.factoryPid=" + factoryPid + "))");
}
boolean newConfig = false;
if (cfgs == null || cfgs.length == 0) {
newConfig = true;
} else if (mode == Mode.REPLACE) {
for (Configuration cfg : cfgs) {
cfg.delete();
}
newConfig = true;
}
if (newConfig) {
Configuration config = configurationAdmin.createFactoryConfiguration(factoryPid, null);
config.update(properties);
} else if (mode != Mode.IGNORE) {
for (Configuration cfg : cfgs) {
boolean changed = false;
for (Entry<Object, Object> entry : properties.entrySet()) {
Object oldValue = cfg.getProperties().get(entry.getKey());
if (mode == Mode.UPDATE || (mode == Mode.AUGMENT && oldValue == null)) {
cfg.getProperties().put(entry.getKey(), entry.getValue());
changed = true;
}
}
if (changed) {
cfg.update(cfg.getProperties());
}
}
}
} else {
String pid = (String) properties.get(Constants.SERVICE_PID);
if (pid != null) {
Configuration[] cfgs = configurationAdmin.listConfigurations("(" + org.osgi.framework.Constants.SERVICE_PID + "=" + pid + ")");
boolean newConfig = false;
if (cfgs == null || cfgs.length == 0) {
newConfig = true;
} else if (mode == Mode.REPLACE) {
for (Configuration cfg : cfgs) {
cfg.delete();
}
newConfig = true;
}
if (newConfig) {
Configuration config = configurationAdmin.getConfiguration(pid, null);
config.update(properties);
} else if (mode != Mode.IGNORE) {
for (Configuration cfg : cfgs) {
boolean changed = false;
for (Entry<Object, Object> entry : properties.entrySet()) {
Object oldValue = cfg.getProperties().get(entry.getKey());
if (mode == Mode.UPDATE || (mode == Mode.AUGMENT && oldValue == null)) {
cfg.getProperties().put(entry.getKey(), entry.getValue());
changed = true;
}
}
if (changed) {
cfg.update(cfg.getProperties());
}
}
}
}
}
} catch (Exception e) {
log.error(LogUtils.LIFECYCLE_MARKER, "Error loading bootstrap file", e);
throw new RuntimeException(e);
}
}
@Override
public void start() {
}
@Override
public void stop(boolean bundleStopping) {
if (bundleStopping) {
listener.close();
}
}
}