/* * Copyright 2015 JAXIO http://www.jaxio.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jaxio.celerio.util.support; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.jaxio.celerio.util.Hierarchical; import com.jaxio.celerio.util.ListHolder; import com.jaxio.celerio.util.Named; import java.util.List; import java.util.Set; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; import static com.jaxio.celerio.util.support.Flatten.*; import static org.springframework.util.Assert.notNull; /** * Mix {@link ListHolder} and {@link Hierarchical}. * <p> * When a node is part of a hierarchy exposing a list of elements (example: an entity exposing a list of attributes), * this class enable you to retrieve in one single {@link ListHolder} the elements that are scattered in the node's family tree. * * @param <T> - An element that is part of a List. * @param <H> - In our case, an Entity */ public class CurrentAndFlatListHolder<T extends Named, H extends Hierarchical<H>> extends AbstractListHolder<T> { private H node; private ListGetter<T, H> listGetter; private Predicate<T> predicate; private SimpleListHolder<T> flatDown = null; private SimpleListHolder<T> flatAbove = null; private SimpleListHolder<T> flatUp = null; private SimpleListHolder<T> flatFull = null; private SimpleListHolder<T> uniqueUp = null; private SimpleListHolder<T> uniqueDown = null; private SimpleListHolder<T> uniqueFull = null; // DO NOT FETCH the list from the constructor. It must be fetched lazily as we construct // it before the list are available... // Important Note: we do not extends SimpleListHolder because we want the list to be fetched Lazily. public CurrentAndFlatListHolder(H node, ListGetter<T, H> listGetter) { notNull(node, "the node must not be null"); notNull(listGetter, "the listGetter must not be null"); this.node = node; this.listGetter = listGetter; this.predicate = Predicates.<T>alwaysTrue(); } public CurrentAndFlatListHolder(H node, ListGetter<T, H> listGetter, Predicate<T> predicate) { notNull(node, "the node must not be null"); this.node = node; this.listGetter = listGetter; this.predicate = predicate; } @Override protected Iterable<T> getIterable() { return filter(listGetter.getList(node), predicate); } /** * Returns in a {@link ListHolder} all the T elements that are present in the * current node and its ancestors, up to the root node. */ public SimpleListHolder<T> getFlatUp() { if (flatUp == null) { flatUp = newSimpleListHolder(up_to_root, getSortProperty()); } return flatUp; } /** * Returns in a {@link ListHolder} all the T elements that are present in the * current node's ancestors, up to the root node. */ public SimpleListHolder<T> getFlatAbove() { if (flatAbove == null) { flatAbove = newSimpleListHolder(above, getSortProperty()); } return flatAbove; } /** * Returns in a {@link ListHolder} all the T elements that are present in the * current node and all its descendants. */ public SimpleListHolder<T> getFlatDown() { if (flatDown == null) { flatDown = newSimpleListHolder(down_to_leave, getSortProperty()); } return flatDown; } /** * Returns in a {@link ListHolder} all the T elements that are present in the * current node's root and all its descendants. */ public SimpleListHolder<T> getFlatFull() { if (flatFull == null) { flatFull = newSimpleListHolder(all, getSortProperty()); } return flatFull; } /** * Returns in a {@link ListHolder} all the T elements (without duplicate) that are present in the * current node and its ancestors, up to the root node. */ public SimpleListHolder<T> getUniqueFlatUp() { if (uniqueUp == null) { uniqueUp = newUniqueSimpleListHolder(up_to_root, getSortProperty()); } return uniqueUp; } /** * Returns in a {@link ListHolder} all the T elements (without duplicates) that are present in the * current node and all its descendants. */ public SimpleListHolder<T> getUniqueFlatDown() { if (uniqueDown == null) { uniqueDown = newUniqueSimpleListHolder(down_to_leave, getSortProperty()); } return uniqueDown; } /** * Returns in a {@link ListHolder} all the T elements (without duplicate) that are present in the * current node's root and all its descendants. */ public SimpleListHolder<T> getUniqueFlatFull() { if (uniqueFull == null) { uniqueFull = newUniqueSimpleListHolder(all, getSortProperty()); } return uniqueFull; } // // Impl details // private SimpleListHolder<T> newSimpleListHolder(Flatten flatten, String sortProperty) { return new SimpleListHolder<T>(getIterable(flatten), predicate, sortProperty); } private SimpleListHolder<T> newUniqueSimpleListHolder(Flatten flatten, String sortProperty) { return new SimpleListHolder<T>(getIterableNoDuplicate(flatten), predicate, sortProperty); } private Iterable<T> getIterableNoDuplicate(Flatten flatten) { List<T> result = newArrayList(); Set<String> tracker = newHashSet(); for (T value : getIterable(flatten)) { if (!tracker.contains(value.getName())) { result.add(value); tracker.add(value.getName()); } } return result; } private Iterable<T> getIterable(Flatten flatten) { if (flatten == up_to_root) { return HierarchyUtil.flattenUpToRoot(node, listGetter); } if (flatten == above) { return HierarchyUtil.flattenAbove(node, listGetter); } if (flatten == down_to_leave) { return HierarchyUtil.flattenDownToLeaves(node, listGetter); } if (flatten == all) { return HierarchyUtil.flattenDownToLeaves(node.getRoot(), listGetter); } throw new RuntimeException("Flatten " + flatten + " is not handled"); } }