/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.component.factory.engine;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.fudgemsg.FudgeContext;
import org.joda.beans.Bean;
import org.joda.beans.BeanBuilder;
import org.joda.beans.BeanDefinition;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaProperty;
import org.joda.beans.Property;
import org.joda.beans.PropertyDefinition;
import org.joda.beans.impl.direct.DirectBeanBuilder;
import org.joda.beans.impl.direct.DirectMetaProperty;
import org.joda.beans.impl.direct.DirectMetaPropertyMap;
import com.google.common.base.Supplier;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.component.ComponentInfo;
import com.opengamma.component.ComponentRepository;
import com.opengamma.component.factory.AbstractComponentFactory;
import com.opengamma.engine.calcnode.CalcNodeSocketConfiguration;
import com.opengamma.transport.jaxrs.UriEndPointDescriptionProvider;
import com.opengamma.util.GUIDGenerator;
import com.opengamma.util.fudgemsg.OpenGammaFudgeContext;
import com.opengamma.util.rest.DataConfigurationResource;
/**
* Component factory providing a managed sub set of the server capabilities.
*/
@BeanDefinition
public class EngineConfigurationComponentFactory extends AbstractComponentFactory {
/**
* The name of the configuration document published.
* <p>
* This is used to support servers which publish multiple configurations, for example
* if they host multiple view processors, or that act as aggregators for a number of
* other servers at the installation site.
* <p>
* This default name may be hard-coded in native code and installation scripts.
* Changes may cause client tools such as Excel to stop working correctly.
*/
private static final String DEFAULT_CONFIGURATION_DOCUMENT_ID = "0";
/**
* The field name under which the logical server unique identifier is published.
* <p>
* This property may be set explicitly by calling {@link #setLogicalServerId},
* or if omitted will be generated randomly.
* <p>
* This default name is hard-coded in native code. Changes may cause client tools
* such as Excel to stop working correctly.
*/
private static final String LOGICAL_SERVER_UNIQUE_IDENTIFIER = "lsid";
/**
* The classifier that the factory should publish under.
*/
@PropertyDefinition(validate = "notNull")
private String _classifier;
/**
* The Fudge context.
*/
@PropertyDefinition(validate = "notNull")
private FudgeContext _fudgeContext = OpenGammaFudgeContext.getInstance();
/**
* The logical server unique identifier. This is defined by the data environment.
* Clustered servers (that is, they appear suitably identical to any connecting clients)
* should have the same logical identifier to reflect this. Any server backed by a
* unique data environment must have a correspondingly unique identifier.
* If a server has a transient or temporary data environment it must
* generate a new logical identifier whenever that environment is flushed.
* <p>
* The default behavior, if this is not specified in the configuration file,
* is to generate a unique identifier at start up. This is suitable for most
* standard installations which include temporary
* (for example, in-memory) masters or other data stores.
*/
@PropertyDefinition
private String _logicalServerId;
/**
* Creates a random logical server unique identifier.
* This is used if an explicit identifier is not set in the configuration file.
* <p>
* This is a 24 character string using base-64 characters, created using
* the algorithm from {@link GUIDGenerator} for uniqueness.
*
* @return the logical server unique identifier, not null
*/
protected String createLogicalServerId() {
final UUID uuid = GUIDGenerator.generate();
final byte[] bytes = new byte[16];
long x = uuid.getMostSignificantBits();
bytes[0] = (byte) x;
bytes[1] = (byte) (x >> 8);
bytes[2] = (byte) (x >> 16);
bytes[3] = (byte) (x >> 24);
bytes[4] = (byte) (x >> 32);
bytes[5] = (byte) (x >> 40);
bytes[6] = (byte) (x >> 48);
bytes[7] = (byte) (x >> 56);
x = uuid.getLeastSignificantBits();
bytes[8] = (byte) x;
bytes[9] = (byte) (x >> 8);
bytes[10] = (byte) (x >> 16);
bytes[11] = (byte) (x >> 24);
bytes[12] = (byte) (x >> 32);
bytes[13] = (byte) (x >> 40);
bytes[14] = (byte) (x >> 48);
bytes[15] = (byte) (x >> 56);
return Base64.encodeBase64String(bytes);
}
protected void afterPropertiesSet() {
if (getLogicalServerId() == null) {
setLogicalServerId(createLogicalServerId());
}
}
protected void buildConfiguration(ComponentRepository repo, Map<String, String> configuration, Map<String, Object> map) {
map.put(LOGICAL_SERVER_UNIQUE_IDENTIFIER, getLogicalServerId());
for (String key : configuration.keySet()) {
String valueStr = configuration.get(key);
Object targetValue = valueStr;
if (valueStr.contains("::")) {
ComponentInfo info = repo.findInfo(valueStr);
if (info == null) {
throw new IllegalArgumentException("Component not found: " + valueStr);
}
Object instance = repo.getInstance(info);
if ((instance instanceof CalcNodeSocketConfiguration) || (instance instanceof Supplier)) {
targetValue = instance;
} else {
if (info.getUri() == null) {
throw new OpenGammaRuntimeException("Unable to add component to configuration as it has not been published by REST: " + valueStr);
}
targetValue = new UriEndPointDescriptionProvider(info.getUri().toString());
}
}
buildMap(map, key, targetValue);
}
}
@Override
public void init(ComponentRepository repo, LinkedHashMap<String, String> configuration) {
afterPropertiesSet();
Map<String, Object> map = new LinkedHashMap<String, Object>();
buildConfiguration(repo, configuration, map);
Map<String, Object> outer = new LinkedHashMap<String, Object>();
outer.put(DEFAULT_CONFIGURATION_DOCUMENT_ID, map);
DataConfigurationResource resource = new DataConfigurationResource(getFudgeContext(), outer);
repo.getRestComponents().publishResource(resource);
// indicate that all component configuration was used
configuration.clear();
}
/**
* Builds the map, handling dot separate keys.
*
* @param map the map, not null
* @param key the key, not null
* @param targetValue the target value,not null
*/
protected void buildMap(Map<String, Object> map, String key, Object targetValue) {
if (key.contains(".")) {
String key1 = StringUtils.substringBefore(key, ".");
String key2 = StringUtils.substringAfter(key, ".");
@SuppressWarnings("unchecked")
Map<String, Object> subMap = (Map<String, Object>) map.get(key1);
if (subMap == null) {
subMap = new LinkedHashMap<String, Object>();
map.put(key1, subMap);
}
buildMap(subMap, key2, targetValue);
} else {
map.put(key, targetValue);
}
}
//------------------------- AUTOGENERATED START -------------------------
///CLOVER:OFF
/**
* The meta-bean for {@code EngineConfigurationComponentFactory}.
* @return the meta-bean, not null
*/
public static EngineConfigurationComponentFactory.Meta meta() {
return EngineConfigurationComponentFactory.Meta.INSTANCE;
}
static {
JodaBeanUtils.registerMetaBean(EngineConfigurationComponentFactory.Meta.INSTANCE);
}
@Override
public EngineConfigurationComponentFactory.Meta metaBean() {
return EngineConfigurationComponentFactory.Meta.INSTANCE;
}
//-----------------------------------------------------------------------
/**
* Gets the classifier that the factory should publish under.
* @return the value of the property, not null
*/
public String getClassifier() {
return _classifier;
}
/**
* Sets the classifier that the factory should publish under.
* @param classifier the new value of the property, not null
*/
public void setClassifier(String classifier) {
JodaBeanUtils.notNull(classifier, "classifier");
this._classifier = classifier;
}
/**
* Gets the the {@code classifier} property.
* @return the property, not null
*/
public final Property<String> classifier() {
return metaBean().classifier().createProperty(this);
}
//-----------------------------------------------------------------------
/**
* Gets the Fudge context.
* @return the value of the property, not null
*/
public FudgeContext getFudgeContext() {
return _fudgeContext;
}
/**
* Sets the Fudge context.
* @param fudgeContext the new value of the property, not null
*/
public void setFudgeContext(FudgeContext fudgeContext) {
JodaBeanUtils.notNull(fudgeContext, "fudgeContext");
this._fudgeContext = fudgeContext;
}
/**
* Gets the the {@code fudgeContext} property.
* @return the property, not null
*/
public final Property<FudgeContext> fudgeContext() {
return metaBean().fudgeContext().createProperty(this);
}
//-----------------------------------------------------------------------
/**
* Gets the logical server unique identifier. This is defined by the data environment.
* Clustered servers (that is, they appear suitably identical to any connecting clients)
* should have the same logical identifier to reflect this. Any server backed by a
* unique data environment must have a correspondingly unique identifier.
* If a server has a transient or temporary data environment it must
* generate a new logical identifier whenever that environment is flushed.
* <p>
* The default behavior, if this is not specified in the configuration file,
* is to generate a unique identifier at start up. This is suitable for most
* standard installations which include temporary
* (for example, in-memory) masters or other data stores.
* @return the value of the property
*/
public String getLogicalServerId() {
return _logicalServerId;
}
/**
* Sets the logical server unique identifier. This is defined by the data environment.
* Clustered servers (that is, they appear suitably identical to any connecting clients)
* should have the same logical identifier to reflect this. Any server backed by a
* unique data environment must have a correspondingly unique identifier.
* If a server has a transient or temporary data environment it must
* generate a new logical identifier whenever that environment is flushed.
* <p>
* The default behavior, if this is not specified in the configuration file,
* is to generate a unique identifier at start up. This is suitable for most
* standard installations which include temporary
* (for example, in-memory) masters or other data stores.
* @param logicalServerId the new value of the property
*/
public void setLogicalServerId(String logicalServerId) {
this._logicalServerId = logicalServerId;
}
/**
* Gets the the {@code logicalServerId} property.
* Clustered servers (that is, they appear suitably identical to any connecting clients)
* should have the same logical identifier to reflect this. Any server backed by a
* unique data environment must have a correspondingly unique identifier.
* If a server has a transient or temporary data environment it must
* generate a new logical identifier whenever that environment is flushed.
* <p>
* The default behavior, if this is not specified in the configuration file,
* is to generate a unique identifier at start up. This is suitable for most
* standard installations which include temporary
* (for example, in-memory) masters or other data stores.
* @return the property, not null
*/
public final Property<String> logicalServerId() {
return metaBean().logicalServerId().createProperty(this);
}
//-----------------------------------------------------------------------
@Override
public EngineConfigurationComponentFactory clone() {
return JodaBeanUtils.cloneAlways(this);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj != null && obj.getClass() == this.getClass()) {
EngineConfigurationComponentFactory other = (EngineConfigurationComponentFactory) obj;
return JodaBeanUtils.equal(getClassifier(), other.getClassifier()) &&
JodaBeanUtils.equal(getFudgeContext(), other.getFudgeContext()) &&
JodaBeanUtils.equal(getLogicalServerId(), other.getLogicalServerId()) &&
super.equals(obj);
}
return false;
}
@Override
public int hashCode() {
int hash = 7;
hash = hash * 31 + JodaBeanUtils.hashCode(getClassifier());
hash = hash * 31 + JodaBeanUtils.hashCode(getFudgeContext());
hash = hash * 31 + JodaBeanUtils.hashCode(getLogicalServerId());
return hash ^ super.hashCode();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(128);
buf.append("EngineConfigurationComponentFactory{");
int len = buf.length();
toString(buf);
if (buf.length() > len) {
buf.setLength(buf.length() - 2);
}
buf.append('}');
return buf.toString();
}
@Override
protected void toString(StringBuilder buf) {
super.toString(buf);
buf.append("classifier").append('=').append(JodaBeanUtils.toString(getClassifier())).append(',').append(' ');
buf.append("fudgeContext").append('=').append(JodaBeanUtils.toString(getFudgeContext())).append(',').append(' ');
buf.append("logicalServerId").append('=').append(JodaBeanUtils.toString(getLogicalServerId())).append(',').append(' ');
}
//-----------------------------------------------------------------------
/**
* The meta-bean for {@code EngineConfigurationComponentFactory}.
*/
public static class Meta extends AbstractComponentFactory.Meta {
/**
* The singleton instance of the meta-bean.
*/
static final Meta INSTANCE = new Meta();
/**
* The meta-property for the {@code classifier} property.
*/
private final MetaProperty<String> _classifier = DirectMetaProperty.ofReadWrite(
this, "classifier", EngineConfigurationComponentFactory.class, String.class);
/**
* The meta-property for the {@code fudgeContext} property.
*/
private final MetaProperty<FudgeContext> _fudgeContext = DirectMetaProperty.ofReadWrite(
this, "fudgeContext", EngineConfigurationComponentFactory.class, FudgeContext.class);
/**
* The meta-property for the {@code logicalServerId} property.
*/
private final MetaProperty<String> _logicalServerId = DirectMetaProperty.ofReadWrite(
this, "logicalServerId", EngineConfigurationComponentFactory.class, String.class);
/**
* The meta-properties.
*/
private final Map<String, MetaProperty<?>> _metaPropertyMap$ = new DirectMetaPropertyMap(
this, (DirectMetaPropertyMap) super.metaPropertyMap(),
"classifier",
"fudgeContext",
"logicalServerId");
/**
* Restricted constructor.
*/
protected Meta() {
}
@Override
protected MetaProperty<?> metaPropertyGet(String propertyName) {
switch (propertyName.hashCode()) {
case -281470431: // classifier
return _classifier;
case -917704420: // fudgeContext
return _fudgeContext;
case -41854233: // logicalServerId
return _logicalServerId;
}
return super.metaPropertyGet(propertyName);
}
@Override
public BeanBuilder<? extends EngineConfigurationComponentFactory> builder() {
return new DirectBeanBuilder<EngineConfigurationComponentFactory>(new EngineConfigurationComponentFactory());
}
@Override
public Class<? extends EngineConfigurationComponentFactory> beanType() {
return EngineConfigurationComponentFactory.class;
}
@Override
public Map<String, MetaProperty<?>> metaPropertyMap() {
return _metaPropertyMap$;
}
//-----------------------------------------------------------------------
/**
* The meta-property for the {@code classifier} property.
* @return the meta-property, not null
*/
public final MetaProperty<String> classifier() {
return _classifier;
}
/**
* The meta-property for the {@code fudgeContext} property.
* @return the meta-property, not null
*/
public final MetaProperty<FudgeContext> fudgeContext() {
return _fudgeContext;
}
/**
* The meta-property for the {@code logicalServerId} property.
* @return the meta-property, not null
*/
public final MetaProperty<String> logicalServerId() {
return _logicalServerId;
}
//-----------------------------------------------------------------------
@Override
protected Object propertyGet(Bean bean, String propertyName, boolean quiet) {
switch (propertyName.hashCode()) {
case -281470431: // classifier
return ((EngineConfigurationComponentFactory) bean).getClassifier();
case -917704420: // fudgeContext
return ((EngineConfigurationComponentFactory) bean).getFudgeContext();
case -41854233: // logicalServerId
return ((EngineConfigurationComponentFactory) bean).getLogicalServerId();
}
return super.propertyGet(bean, propertyName, quiet);
}
@Override
protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) {
switch (propertyName.hashCode()) {
case -281470431: // classifier
((EngineConfigurationComponentFactory) bean).setClassifier((String) newValue);
return;
case -917704420: // fudgeContext
((EngineConfigurationComponentFactory) bean).setFudgeContext((FudgeContext) newValue);
return;
case -41854233: // logicalServerId
((EngineConfigurationComponentFactory) bean).setLogicalServerId((String) newValue);
return;
}
super.propertySet(bean, propertyName, newValue, quiet);
}
@Override
protected void validate(Bean bean) {
JodaBeanUtils.notNull(((EngineConfigurationComponentFactory) bean)._classifier, "classifier");
JodaBeanUtils.notNull(((EngineConfigurationComponentFactory) bean)._fudgeContext, "fudgeContext");
super.validate(bean);
}
}
///CLOVER:ON
//-------------------------- AUTOGENERATED END --------------------------
}