com.opengamma.component.factory.engine.EngineConfigurationComponentFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.component.factory.engine.EngineConfigurationComponentFactory.java

Source

/**
 * 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.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(final ComponentRepository repo, final Map<String, String> configuration,
            final Map<String, Object> map) {
        map.put(LOGICAL_SERVER_UNIQUE_IDENTIFIER, getLogicalServerId());
        for (final String key : configuration.keySet()) {
            final String valueStr = configuration.get(key);
            Object targetValue = valueStr;
            if (valueStr.contains("::")) {
                final String type = StringUtils.substringBefore(valueStr, "::");
                final String classifier = StringUtils.substringAfter(valueStr, "::");
                final ComponentInfo info = repo.findInfo(type, classifier);
                if (info == null) {
                    throw new IllegalArgumentException("Component not found: " + valueStr);
                }
                final 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(final ComponentRepository repo, final LinkedHashMap<String, String> configuration) {
        afterPropertiesSet();
        final Map<String, Object> map = new LinkedHashMap<String, Object>();
        buildConfiguration(repo, configuration, map);
        final Map<String, Object> outer = new LinkedHashMap<String, Object>();
        outer.put(DEFAULT_CONFIGURATION_DOCUMENT_ID, map);
        final 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(final Map<String, Object> map, final String key, final Object targetValue) {
        if (key.contains(".")) {
            final String key1 = StringUtils.substringBefore(key, ".");
            final 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;
    }

    @Override
    protected Object propertyGet(String propertyName, boolean quiet) {
        switch (propertyName.hashCode()) {
        case -281470431: // classifier
            return getClassifier();
        case -917704420: // fudgeContext
            return getFudgeContext();
        case -41854233: // logicalServerId
            return getLogicalServerId();
        }
        return super.propertyGet(propertyName, quiet);
    }

    @Override
    protected void propertySet(String propertyName, Object newValue, boolean quiet) {
        switch (propertyName.hashCode()) {
        case -281470431: // classifier
            setClassifier((String) newValue);
            return;
        case -917704420: // fudgeContext
            setFudgeContext((FudgeContext) newValue);
            return;
        case -41854233: // logicalServerId
            setLogicalServerId((String) newValue);
            return;
        }
        super.propertySet(propertyName, newValue, quiet);
    }

    @Override
    protected void validate() {
        JodaBeanUtils.notNull(_classifier, "classifier");
        JodaBeanUtils.notNull(_fudgeContext, "fudgeContext");
        super.validate();
    }

    @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();
    }

    //-----------------------------------------------------------------------
    /**
     * 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.
     * 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);
    }

    //-----------------------------------------------------------------------
    /**
     * 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;
        }

    }

    ///CLOVER:ON
    //-------------------------- AUTOGENERATED END --------------------------
}