Complex Node Hierarchies

Complex Node Hierarchies

When you're using the Nodes API, things can become a bit tricky, especially when you want to visualize different Node types on the same level within a hierarchy.

As an example, let's imagine our domain model represents music bands, e.g., 'Oasis', etc. Here's a very simple node hierarchy that simply lists the names of the bands, i.e., each Node below visualizes an underlying Band object that is defined by a name:

After you've done the above, you want to show the members of the band. So, now the Band object is defined by a name and a list of Members:

However, let's say each Band has a list of Members, as well as one Manager. Here things start getting a bit tricky. The ChildFactory class has a 'createNodesForKey' method that returns multiple Nodes, so your inclination would be to use that, something like this:

@Override
protected Node[] createNodesForKey(Band key) {
    int size = key.getMembers().size() + 1;
    Node[] nodes = new Node[size];
    for (int i = 0; i < key.getMembers().size(); i++) {
        try {
            nodes[i] = new MemberNode(key.getMembers().get(i));
        } catch (IntrospectionException ex) {
            Exceptions.printStackTrace(ex);
        }
    }
    try {
        nodes[size-1] = new ManagerNode(key.getManager());
    } catch (IntrospectionException ex) {
        Exceptions.printStackTrace(ex);
    }
    return nodes;
}

What the above gets you is a structure like this:

However, you're more likely to want the structure below instead, i.e., a container Node for all the Members, together with a leaf Node for the Manager, of which there will always be one:

To achieve the above, I learned this approach from Sven Reimers during JCrete:

public class MusicBandContainerChildFactory extends 
    ChildFactory<MusicBandContainerChildFactory.Container> {
    
    private final Band band;

    public enum Container {
        MEMBERS, MANAGER
    }
    
    public MusicBandContainerChildFactory(Band band) {
        this.band = band;
    }

    @Override
    protected boolean createKeys(List<Container> list) {
        list.add(Container.MEMBERS);
        list.add(Container.MANAGER);
        return true;
    }
    
    @Override
    protected Node createNodeForKey(Container key) {
        switch (key) {
            case MEMBERS: {
                try {
                    return new MemberContainerNode(key);
                } catch (IntrospectionException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
            case MANAGER: {
                try {
                    return new ManagerNode(key);
                } catch (IntrospectionException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        }
        return null;
    }
    
    private class ManagerNode extends BeanNode {
        public ManagerNode(Container key) throws IntrospectionException {
            super(key);
            setDisplayName("Manager: "+band.getManager().getName());
        }
    }
    
    private class MemberContainerNode extends BeanNode {
        public MemberContainerNode(Container key) throws IntrospectionException {
            super(key, Children.create(new BandMemberChildFactory(band), true));
            setDisplayName("Members");
        }
    }
    
    private class BandMemberChildFactory extends ChildFactory<Member> {
        private final Band bean;
        public BandMemberChildFactory(Band bean) {
            this.bean = bean;
        }
        @Override
        protected boolean createKeys(List<Member> list) {
            list.addAll(bean.getMembers());
            return true;
        }
        @Override
        protected Node createNodeForKey(Member key) {
            BandMemberNode node = null;
            try {
                node = new BandMemberNode(key);
            } catch (IntrospectionException ex) {
                Exceptions.printStackTrace(ex);
            }
            return node;
        }
    }

    private class BandMemberNode extends BeanNode<Member> {
        public BandMemberNode(Member bean) throws IntrospectionException {
            super(bean, Children.LEAF);
            setDisplayName(bean.getName());
        }
    }
    
}

Thanks, Sven!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值