/** * 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.lang.reflect.Modifier; import java.util.Collections; import java.util.Map; import java.util.Set; import org.joda.beans.Bean; import org.joda.beans.MetaBean; import com.google.common.collect.Maps; import com.google.common.collect.Sets; /** * */ // TODO do I need to worry about properties whose type is an interface with implementations that are beans? /* package */ class BeanHierarchy { private final Map<Class<?>, Node> _nodes = Maps.newHashMap(); private final Set<Class<?>> _classesWithMetaBean = Sets.newHashSet(); /* package */ BeanHierarchy(Set<MetaBean> metaBeans) { for (MetaBean metaBean : metaBeans) { _classesWithMetaBean.add(metaBean.beanType()); } for (MetaBean metaBean : metaBeans) { getOrAddNode(metaBean.beanType()); } } private Node getOrAddNode(Class<?> type) { Node node = _nodes.get(type); if (node != null) { return node; } Node newNode = new Node(type); _nodes.put(type, newNode); Class<?> superclass = type.getSuperclass(); if (superclass != null) { getOrAddNode(superclass).addSubclass(newNode); } return newNode; } /* package */ Set<Class<? extends Bean>> subtypes(Class<?> type) { Node node = _nodes.get(type); if (node == null) { return Collections.emptySet(); } Set<Class<? extends Bean>> types = Sets.newHashSet(); addSubtypes(node, types); return types; } @SuppressWarnings("unchecked") private void addSubtypes(Node node, Set<Class<? extends Bean>> types) { Class<?> type = node.getType(); if (isConcreteBeanWithMetaBean(type)) { types.add((Class<? extends Bean>) type); } for (Node subclassNode : node.getSubclasses()) { addSubtypes(subclassNode, types); } } /** * @param type A type * @return true if type is a concrete subclass of {@link Bean} whose {@link MetaBean} was in the set passed to * the constructor. */ private boolean isConcreteBeanWithMetaBean(Class<?> type) { return Bean.class.isAssignableFrom(type) && (type.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT && _classesWithMetaBean.contains(type); } private static final class Node { private final Class<?> _type; private final Set<Node> _subclasses = Sets.newHashSet(); private Node(Class<?> type) { _type = type; } private void addSubclass(Node subclassNode) { _subclasses.add(subclassNode); } private Class<?> getType() { return _type; } private Set<Node> getSubclasses() { return _subclasses; } } }