package com.ibm.sbt.opensocial.domino.config;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.shindig.auth.BlobCrypterSecurityTokenCodec;
import org.apache.shindig.common.Nullable;
import org.apache.shindig.common.crypto.Crypto;
import org.apache.shindig.common.util.CharsetUtil;
import org.apache.shindig.config.ContainerConfig;
import org.apache.shindig.config.ContainerConfigException;
import org.apache.shindig.config.JsonContainerConfig;
import org.apache.shindig.expressions.Expressions;
import com.google.caja.util.Maps;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.ibm.sbt.opensocial.domino.container.ContainerExtPoint;
import com.ibm.sbt.opensocial.domino.container.ContainerExtPointManager;
import com.ibm.sbt.opensocial.domino.container.ContainerExtPointManager.ContainerExtPointListener;
/**
* Contributes containers from extension points.
*/
@Singleton
public class ExtensionPointContainerConfig extends JsonContainerConfig {
private static final String CLASS = ExtensionPointContainerConfig.class.getName();
private static final String DOMINO_CONTAINER = "domino";
private Logger log;
private ContainerExtPointListener listener = new ContainerExtPointListener() {
@Override
public void added(Collection<ContainerExtPoint> extPoints) {
modifyContainerConfigs(extPoints, true);
}
@Override
public void removed(Collection<ContainerExtPoint> extPoints) {
modifyContainerConfigs(extPoints, false);
}
};
/**
* Creates a new extension point container config.
* @param containers The default set of containers.
* @param host The host.
* @param port The port.
* @param contextRoot The context root of the web app.
* @param expressions Expressions to be evaluated.
* @param extPointManager The container extension point manager.
* @param log The logger.
* @throws ContainerConfigException Thrown if a configuration is invalid.
*/
@Inject
public ExtensionPointContainerConfig(@Named("shindig.containers.default") String containers,
@Nullable @Named("shindig.host") String host,
@Nullable @Named("shindig.port") String port,
@Nullable @Named("shindig.contextroot") String contextRoot,
Expressions expressions, ContainerExtPointManager extPointManager,
Logger log)
throws ContainerConfigException {
super(containers, host, port, contextRoot, expressions);
this.log = log;
addSecurityTokenKeyToDominoContainer();
modifyContainerConfigs(extPointManager.getExtPoints().values(), true);
extPointManager.addExtensionPointListener(listener);
}
/**
* Adds a security token key to the domino container. Since the domino container
* is defined in a static file (domino-container.js) we cannot specify a key there
* so when this class is started we get the config for the domino container and add
* the key.
*/
private void addSecurityTokenKeyToDominoContainer() {
final String method = "addSecurityTokenToDominoContainer";
Map<String, Object> domino = this.getProperties(DOMINO_CONTAINER);
if(domino != null) {
//We need to create a new map because getProperties returns an unmodifiable map
Map<String, Object> config = Maps.newHashMap(domino);
config.put(BlobCrypterSecurityTokenCodec.SECURITY_TOKEN_KEY,
CharsetUtil.newUtf8String(Crypto.getRandomBytes(20)));
try {
newTransaction().addContainer(config).commit();
} catch (ContainerConfigException e) {
log.logp(Level.WARNING, CLASS, method,
"Error commiting new container config for domino container after adding security token key.",
e);
}
} else {
log.logp(Level.WARNING, CLASS, method, "There was not container with the ID domino, could not add token key.");
}
}
/**
* Modifies the containers.
* @param containers The collections of containers to either add or remove.
* @param add True to add the collection of containers, false to remove them.
*/
private void modifyContainerConfigs(Collection<ContainerExtPoint> containers, boolean add) {
final String method = "modifyContainerConfigs";
try {
if(!containers.isEmpty()) {
Transaction transaction = newTransaction();
for(ContainerExtPoint extPoint : containers) {
if(add) {
Map<String, Object> containerProps = extPoint.getContainerConfig().getProperties();
if(!containerProps.containsKey(ContainerConfig.CONTAINER_KEY)) {
containerProps.put(ContainerConfig.CONTAINER_KEY,
new ImmutableList.Builder<String>().add(extPoint.getId()).build());
}
transaction.addContainer(containerProps);
} else {
transaction.removeContainer(extPoint.getId());
}
}
transaction.commit();
}
} catch (Exception e) {
log.logp(Level.WARNING, CLASS, method, "Error while committing container modifications.", e);
}
}
}