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

Java tutorial

Introduction

Here is the source code for com.opengamma.web.analytics.blotter.BeanTraverser.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.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.joda.beans.Bean;
import org.joda.beans.MetaBean;
import org.joda.beans.MetaProperty;

import com.google.common.collect.Lists;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.util.ArgumentChecker;

/**
 * TODO is there a generally useful way to have pluggable handlers to override default behaviour for specific properties?
 * or would that have to be done in the visitors?
 * could also handle it by property name instead of using the metaproperty
 */
/* package */ class BeanTraverser {

    /** Decorators that are applied to the visitor in the {@link #traverse} method. */
    private final List<BeanVisitorDecorator> _decorators;

    /* package */ BeanTraverser() {
        _decorators = Collections.emptyList();
    }

    /* package */ BeanTraverser(BeanVisitorDecorator... decorators) {
        _decorators = Arrays.asList(decorators);
        // first decorator in the list should be on the outside, need to reverse before wrapping
        Collections.reverse(_decorators);
    }

    /* package */ Object traverse(MetaBean metaBean, BeanVisitor<?> visitor) {
        BeanVisitor<?> decoratedVisitor = decorate(visitor);
        decoratedVisitor.visitMetaBean(metaBean);
        List<BeanTraversalFailure> failures = Lists.newArrayList();
        for (MetaProperty<?> property : metaBean.metaPropertyIterable()) {
            Class<?> propertyType = property.propertyType();
            try {
                if (Bean.class.isAssignableFrom(propertyType)) {
                    decoratedVisitor.visitBeanProperty(property, this);
                } else if (Set.class.isAssignableFrom(propertyType)) {
                    decoratedVisitor.visitSetProperty(property, this);
                } else if (List.class.isAssignableFrom(propertyType)) {
                    decoratedVisitor.visitListProperty(property, this);
                } else if (Collection.class.isAssignableFrom(propertyType)) {
                    decoratedVisitor.visitCollectionProperty(property, this);
                } else if (Map.class.isAssignableFrom(propertyType)) {
                    decoratedVisitor.visitMapProperty(property, this);
                } else {
                    decoratedVisitor.visitProperty(property, this);
                }
            } catch (Exception e) {
                failures.add(new BeanTraversalFailure(e, property));
            }
        }
        if (failures.isEmpty()) {
            return decoratedVisitor.finish();
        } else {
            throw new BeanTraversalException(metaBean, visitor, failures);
        }
    }

    private BeanVisitor<?> decorate(BeanVisitor<?> visitor) {
        BeanVisitor<?> decoratedVisitor = visitor;
        for (BeanVisitorDecorator decorator : _decorators) {
            decoratedVisitor = decorator.decorate(decoratedVisitor);
        }
        return decoratedVisitor;
    }
}

/**
 * Wraps a property and the exception that occurred when the traverser tried to visit the property.
 */
/* package */ class BeanTraversalFailure {

    /** The exception triggered by the attempted visit. */
    private final Exception _exception;
    /** The visited property. */
    private final MetaProperty<?> _property;

    /* package */ BeanTraversalFailure(Exception exception, MetaProperty<?> property) {
        ArgumentChecker.notNull(exception, "exception");
        ArgumentChecker.notNull(property, "property");
        _exception = exception;
        _property = property;
    }

    /* package */ Exception getException() {
        return _exception;
    }

    @Override
    public String toString() {
        String message = _exception.getMessage() == null ? null : "'" + _exception.getMessage() + "'";
        return "[" + _property.toString() + ", " + message + "]";
    }
}

/**
 * Exception thrown after a bean traversal that threw exceptions. All exceptions thrown during traversal are added
 * to this exception as {@link #addSuppressed suppressed} exceptions.
 */
/* package */ class BeanTraversalException extends OpenGammaRuntimeException {

    /** Serialization version. */
    private static final long serialVersionUID = -3048022694152981946L;

    /* package */ BeanTraversalException(MetaBean metaBean, BeanVisitor<?> visitor,
            List<BeanTraversalFailure> failures) {
        super(buildMessage(metaBean, visitor, failures));
        for (BeanTraversalFailure failure : failures) {
            addSuppressed(failure.getException());
        }
    }

    private static String buildMessage(MetaBean metaBean, BeanVisitor<?> visitor,
            List<BeanTraversalFailure> failures) {
        ArgumentChecker.notNull(metaBean, "metaBean");
        ArgumentChecker.notEmpty(failures, "failures");
        ArgumentChecker.notNull(visitor, "visitor");
        return "Bean traversal failed. " + "bean: " + metaBean + ", " + "visitor: " + visitor + ", " + "failures: ["
                + StringUtils.join(failures, ", ") + "]";
    }

}