com.opengamma.web.analytics.blotter.BeanBuildingVisitor.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.web.analytics.blotter.BeanBuildingVisitor.java

Source

/**
 * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.web.analytics.blotter;

import java.util.List;
import java.util.Map;

import org.joda.beans.Bean;
import org.joda.beans.BeanBuilder;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaBean;
import org.joda.beans.MetaProperty;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.opengamma.core.id.ExternalSchemes;
import com.opengamma.id.ExternalId;
import com.opengamma.util.ArgumentChecker;

/**
 * Builds a bean instance by traversing the {@link MetaBean} and populating the {@link MetaBean#builder() builder}
 * with data from a {@link BeanDataSource}. The {@link BeanBuilder builder} is returned so calling code can update
 * it before building the instance, e.g. to set invariant values that aren't in the data source but are necessary
 * to build a valid object.
 * @param <T> The type of bean to build
 */
/* package */ class BeanBuildingVisitor<T extends Bean> implements BeanVisitor<BeanBuilder<T>> {

    /** The source of data for building the bean */
    private final BeanDataSource _data;
    /** For looking up {@link MetaBean}s for building the bean and any sub-beans */
    private final MetaBeanFactory _metaBeanFactory;
    /** For converting the data to property values */
    private final Converters _converters;

    /** The builder for the instance being built */
    private BeanBuilder<T> _builder;

    /* package */ BeanBuildingVisitor(BeanDataSource data, MetaBeanFactory metaBeanFactory, Converters converters) {
        ArgumentChecker.notNull(data, "data");
        ArgumentChecker.notNull(metaBeanFactory, "metaBeanFactory");
        ArgumentChecker.notNull(converters, "converters");
        _converters = converters;
        _metaBeanFactory = metaBeanFactory;
        _data = data;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void visitMetaBean(MetaBean metaBean) {
        _builder = (BeanBuilder<T>) metaBean.builder();
    }

    @Override
    public void visitBeanProperty(MetaProperty<?> property, BeanTraverser traverser) {
        visitProperty(property, traverser);
    }

    @Override
    public void visitSetProperty(MetaProperty<?> property, BeanTraverser traverser) {
        // TODO implement visitSetProperty()
        throw new UnsupportedOperationException("visitSetProperty not implemented");
    }

    @Override
    public void visitListProperty(MetaProperty<?> property, BeanTraverser traverser) {
        List<?> dataValues = _data.getCollectionValues(property.name());
        List<Object> values = Lists.newArrayList();
        Class<?> collectionType = JodaBeanUtils.collectionType(property, property.declaringType());
        for (Object dataValue : dataValues) {
            values.add(convert(dataValue, property, collectionType, traverser));
        }
        _builder.set(property, values);
    }

    @Override
    public void visitCollectionProperty(MetaProperty<?> property, BeanTraverser traverser) {
        visitListProperty(property, traverser);
    }

    @Override
    public void visitMapProperty(MetaProperty<?> property, BeanTraverser traverser) {
        _builder.set(property, buildMap(property, traverser));
    }

    @Override
    public void visitProperty(MetaProperty<?> property, BeanTraverser traverser) {
        _builder.set(property,
                convert(_data.getValue(property.name()), property, property.propertyType(), traverser));
    }

    @Override
    public BeanBuilder<T> finish() {
        return _builder;
    }

    private Object convert(Object value, MetaProperty<?> property, Class<?> expectedType, BeanTraverser traverser) {
        Object convertedValue = _converters.convert(value, property, expectedType);
        if (convertedValue != Converters.CONVERSION_FAILED) {
            return convertedValue;
        }
        if (value instanceof BeanDataSource) {
            BeanDataSource beanData = (BeanDataSource) value;
            BeanBuildingVisitor<?> visitor = new BeanBuildingVisitor<>(beanData, _metaBeanFactory, _converters);
            MetaBean metaBean = _metaBeanFactory.beanFor(beanData);
            return ((BeanBuilder<?>) traverser.traverse(metaBean, visitor)).build();
        }
        throw new IllegalArgumentException("Unable to convert " + value + " to " + expectedType.getName());
    }

    private Map<?, ?> buildMap(MetaProperty<?> property, BeanTraverser traverser) {
        Map<?, ?> sourceData = _data.getMapValues(property.name());
        Class<? extends Bean> beanType = property.metaBean().beanType();
        Class<?> keyType = JodaBeanUtils.mapKeyType(property, beanType);
        Class<?> valueType = JodaBeanUtils.mapValueType(property, beanType);
        Map<Object, Object> map = Maps.newHashMapWithExpectedSize(sourceData.size());
        for (Map.Entry<?, ?> entry : sourceData.entrySet()) {
            Object key = convert(entry.getKey(), property, keyType, traverser);
            Object value = convert(entry.getValue(), property, valueType, traverser);
            map.put(key, value);
        }
        return map;
    }
}

/**
 * Converter that ignores its input and always returns {@code FINANCIAL_REGION~GB}. This is for building FX securities
 * which always have the same region.
 */
/* package */ class FXRegionConverter implements Converter<Object, ExternalId> {

    /** Great Britain region */
    private static final ExternalId GB_REGION = ExternalId.of(ExternalSchemes.FINANCIAL, "GB");

    /**
     * Ignores its input, always returns {@code FINANCIAL_REGION~GB}.
     * @param notUsed Not used
     * @return {@code FINANCIAL_REGION~GB}
     */
    @Override
    public ExternalId convert(Object notUsed) {
        return GB_REGION;
    }
}