/*******************************************************************************
* Copyright (c) 2009 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;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import org.openanzo.exceptions.LogUtils;
import org.openanzo.services.ServicesDictionary;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.metatype.MetaTypeProvider;
import org.slf4j.LoggerFactory;
/**
* Abstract activator that is managed via OSGI configuration admin
*
* @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com</a>)
*
*/
public abstract class ConfiguredServiceActivator extends ServiceActivator implements ManagedService, MetaTypeProvider {
private static final org.slf4j.Logger log = LoggerFactory.getLogger(ConfiguredServiceActivator.class);
protected Dictionary<? extends Object, ? extends Object> configProperties;
/**
* @return the configProperties
*/
public final Dictionary<? extends Object, ? extends Object> getConfigProperties() {
return configProperties;
}
@Override
protected Collection<String> getServiceClassNames() {
HashSet<String> scn = new HashSet<String>(super.getServiceClassNames());
scn.add(ConfiguredServiceActivator.class.getName());
scn.add(ManagedService.class.getName());
scn.add(MetaTypeProvider.class.getName());
return scn;
}
@Override
public String getExtraStatus(boolean html) {
if (html) {
if (getConfigProperties() != null) {
StringBuilder sb = new StringBuilder("<br/>Configuration Properties: ");
sb.append("<table border='1'>");
for (Enumeration<? extends Object> keys = getConfigProperties().keys(); keys.hasMoreElements();) {
Object key = keys.nextElement();
Object value = getConfigProperties().get(key);
if (key.toString().toLowerCase().contains("password") && value.toString().startsWith("encrypted:")) {
value = "********";
}
sb.append("<tr><td>" + key.toString() + "</td><td>" + value.toString() + "</td></tr>");
}
sb.append("</table>");
return sb.toString();
} else {
return ("<br/>Configuration Properties: <font color='#cc0000'>NOT Set</font> ");
}
} else {
return ("Are Configuration properties set? " + (getConfigProperties() != null));
}
}
@Override
public boolean isInitialized() {
lock.lock();
try {
return super.isInitialized() && configProperties != null;
} finally {
lock.unlock();
}
}
@SuppressWarnings("unchecked")
public void updated(Dictionary properties) throws ConfigurationException {
lock.lock();
try {
log.info(LogUtils.LIFECYCLE_MARKER, "Configuration Updated: " + this.getClass().getName());
if (properties != null) {
OsgiConfigurationUtils.validateConfiguration(getObjectClassDefinition(getServicePid(), null), properties);
OsgiConfigurationUtils.updateConfigProperties(properties, context);
boolean restartSystemRequired = false;
Set<String> changedProps = null;
if (this.configProperties != null && state == ServiceLifecycleState.STARTED) {
changedProps = OsgiConfigurationUtils.isRestartRequired(getObjectClassDefinition(getServicePid(), null), configProperties, properties);
restartSystemRequired = (changedProps == null);
}
this.configProperties = properties;
if (!restartSystemRequired) {
configurationPropertiesSet(changedProps);
if (isInitialized()) {
if (changedProps == null) {
startLocked();
} else {
restartLocked(changedProps);
}
}
}
} else if (this.configProperties != null) {
stopLocked(false);
}
} finally {
lock.unlock();
}
}
/**
* Config properties have been set
*
* @param changedProps
* set of properties that changed
* @throws ConfigurationException
*/
public void configurationPropertiesSet(Set<String> changedProps) throws ConfigurationException {
}
/**
* Start was called after the service was already started, which usually means the configuration changed
*
* @param changedProps
* set of properties that changed
*/
public void restartLocked(Set<String> changedProps) {
lock.lock();
ServiceLifecycleState prevState = state;
try {
if (state == ServiceLifecycleState.STARTED) {
restarted(changedProps);
} else if (state != ServiceLifecycleState.STARTED && state != ServiceLifecycleState.STARTING) {
state = ServiceLifecycleState.STARTING;
start();
state = ServiceLifecycleState.STARTED;
}
fireEvent();
} catch (Throwable t) {
log.error(LogUtils.LIFECYCLE_MARKER, "Error restarting due to modified configuration:" + this.getClass().getName(), t);
state = prevState;
} finally {
startThread = null;
lock.unlock();
}
}
/**
* Start was called after the service was already started, which usually means the configuration changed
*
* @param changedProps
* set of properties that changed
*/
public void restarted(Set<String> changedProps) {
Boolean enabled = ServicesDictionary.getEnabled(configProperties);
if (enabled != null && !enabled) {
ServiceLifecycleState prevState = state;
try {
state = ServiceLifecycleState.STOPPING;
stop(false);
} catch (Throwable t) {
log.error(LogUtils.LIFECYCLE_MARKER, "Error restarting due to modified configuration:" + this.getClass().getName(), t);
state = prevState;
} finally {
state = ServiceLifecycleState.NOT_ENABLED;
}
} else {
state = ServiceLifecycleState.NOT_ENABLED;
}
}
public String[] getLocales() {
return null;
}
}