com.isotrol.impe3.palette.menu.category.CategoryComponent.java Source code

Java tutorial

Introduction

Here is the source code for com.isotrol.impe3.palette.menu.category.CategoryComponent.java

Source

/**
 * This file is part of Port@l
 * Port@l 3.0 - Portal Engine and Management System
 * Copyright (C) 2010  Isotrol, SA.  http://www.isotrol.com
 *
 * Port@l is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Port@l is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Port@l.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.isotrol.impe3.palette.menu.category;

import static com.google.common.base.Predicates.and;
import static com.google.common.collect.Iterables.filter;

import java.net.URI;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.isotrol.impe3.api.Categories;
import com.isotrol.impe3.api.Category;
import com.isotrol.impe3.api.Name;
import com.isotrol.impe3.api.NavigationKey;
import com.isotrol.impe3.api.PageKey;
import com.isotrol.impe3.api.PageKey.WithNavigation;
import com.isotrol.impe3.api.Route;
import com.isotrol.impe3.api.URIGenerator;
import com.isotrol.impe3.api.component.Inject;
import com.isotrol.impe3.api.component.RenderContext;
import com.isotrol.impe3.api.component.Renderer;
import com.isotrol.impe3.api.component.html.HTMLFragment;
import com.isotrol.impe3.api.component.html.HTMLFragments;
import com.isotrol.impe3.api.component.html.HTMLRenderer;
import com.isotrol.impe3.api.component.html.SkeletalHTMLRenderer;
import com.isotrol.impe3.api.content.ContentLoader;
import com.isotrol.impe3.api.content.OneLevelGroupResult;
import com.isotrol.impe3.freemarker.FreeMarkerService;
import com.isotrol.impe3.freemarker.Model;
import com.isotrol.impe3.palette.AbstractFreeMarkerComponent;
import com.isotrol.impe3.palette.menu.MenuItem;

/**
 * Abstract class for components in this module.
 * @author Andres Rodriguez
 */
public abstract class CategoryComponent extends AbstractFreeMarkerComponent {

    /** Module Configuration. */
    private CategoryMenuModuleConfig config;

    /** Component configuration. */
    private CategoryMenuConfig componentConfig;

    /** Categories. */
    private Categories categories;

    /** URI Generator. */
    private URIGenerator uriGenerator;

    /** Route. */
    private Route route = null;

    /** Current navigation key. */
    private NavigationKey navigationKey;

    /** Locale. */
    private Locale locale = null;

    /** Menu items. */
    private final List<MenuItem> items = Lists.newArrayList();

    /** Content loader. */
    private ContentLoader contentLoader;

    /** Category predicate. */
    private Predicate<Category> filter = null;

    /** External predicate provider. */
    private CategoryPredicateProvider filterProvider = null;

    /** Filter by content predicate. */
    private Predicate<? super Category> filterByContent = null;

    /** Whether to include not visible categories. */
    private Predicate<? super Category> includeNotVisible = null;

    /** Whether to include not routable categories. */
    private Predicate<? super Category> includeNotRoutable = null;

    /** Predicate for selected category. */
    private Predicate<Category> selected = null;

    /**
     * Public constructor.
     */
    public CategoryComponent() {
    }

    public void setConfig(CategoryMenuModuleConfig config) {
        this.config = config;
    }

    public void setFilterProvider(CategoryPredicateProvider filterProvider) {
        this.filterProvider = filterProvider;
    }

    @Inject
    public void setComponentConfig(CategoryMenuConfig componentConfig) {
        this.componentConfig = componentConfig;
    }

    @Inject
    public void setContentLoader(ContentLoader contentLoader) {
        this.contentLoader = contentLoader;
    }

    public void setCategories(Categories categories) {
        this.categories = categories;
    }

    public void setUriGenerator(URIGenerator uriGenerator) {
        this.uriGenerator = uriGenerator;
    }

    @Inject
    public void setRoute(Route route) {
        this.route = route;
        this.locale = (route != null) ? route.getLocale() : null;
    }

    @Inject
    public void setNavigationKey(NavigationKey navigationKey) {
        this.navigationKey = navigationKey;
    }

    protected Categories getCategories() {
        return categories;
    }

    protected List<MenuItem> getItems() {
        return items;
    }

    protected MenuItem createItem(Category category, Predicate<Category> selected) {
        URI uri = null;
        if (category.isRoutable()) {
            final NavigationKey nk = NavigationKey.category(category);
            final PageKey pk = PageKey.navigation(nk);
            final Route r = (route != null) ? route.toPage(pk) : Route.of(false, pk, null, null);
            uri = uriGenerator.getURI(r);
        }
        final Name name = (locale != null) ? category.getName().get(locale) : category.getDefaultName();
        final MenuItem item = new MenuItem(name.getDisplayName(), uri, selected.apply(category));
        return item;
    }

    protected MenuItem createParentItem(Category category, Predicate<Category> selected) {
        if (categories == null || category == null) {
            return null;
        }
        final UUID id = category.getId();
        if (!categories.containsKey(id)) {
            return null;
        }
        final Category parent = categories.getParent(id);
        if (parent == null || !include().apply(parent)) {
            return null;
        }
        final MenuItem item = createItem(parent, selected);
        item.setParent(createParentItem(parent, selected));
        return item;
    }

    /**
     * Returns the category included in the navigation key, if any.
     * @return The category or {@code null}.
     */
    final Category getCurrent() {
        if (componentConfig != null && componentConfig.current() != null) {
            return componentConfig.current();
        } else if (config != null && config.current() != null) {
            return config.current();
        }

        if (navigationKey != null && navigationKey.isCategory()) {
            Category c = navigationKey.getCategory();
            if (categories.containsValue(c)) {
                return c;
            }
        }

        return null;
    }

    protected void add(Iterable<Category> categories, Predicate<Category> selected, MenuItem parent) {
        add(items, 0, depth(), categories, selected, parent);
    }

    protected void add(List<MenuItem> list, int depth, int maxDepth, Iterable<Category> level,
            Predicate<Category> selected, MenuItem parent) {
        if (depth > maxDepth) {
            return;
        }
        for (Category c : filter(level, include())) {
            MenuItem mi = createItem(c, selected);
            mi.setParent(parent);
            list.add(mi);
            add(mi.getChildren(), depth + 1, maxDepth, categories.getChildren(c.getId()), selected, mi);
        }
    }

    @SuppressWarnings("unchecked")
    final Predicate<? super Category> include() {
        if (filter == null) {
            filter = and(includeNotVisible(), includeNotRoutable(), filterByContent());
            if (filterProvider != null) {
                Predicate<Category> f = filterProvider.getCategoryPredicate(filter);
                if (f != null) {
                    filter = f;
                }
            }
        }
        return filter;
    }

    // Configuration items resolution

    final Predicate<? super Category> filterByContent() {
        if (filterByContent == null) {
            filterByContent = calculateFilterByContent();
        }
        return filterByContent;
    }

    private Predicate<? super Category> calculateFilterByContent() {
        if (config != null && config.filterByContentAvailability() && contentLoader != null) {
            final OneLevelGroupResult<Category> g = contentLoader.newCriteria().groupByCategory();
            final Predicate<Category> p = new Predicate<Category>() {
                public boolean apply(Category input) {
                    return g.apply(input) > 0;
                }
            };
            return p;
        }
        return Predicates.alwaysTrue();
    }

    final Predicate<? super Category> includeNotVisible() {
        if (includeNotVisible == null) {
            includeNotVisible = calculateIncludeNotVisible();
        }
        return includeNotVisible;
    }

    private Predicate<? super Category> calculateIncludeNotVisible() {
        boolean include = false;
        if (componentConfig != null && componentConfig.includeNotVisible() != null) {
            include = componentConfig.includeNotVisible().booleanValue();
        } else if (config != null && config.includeNotVisible() != null) {
            include = config.includeNotVisible().booleanValue();
        }
        if (include) {
            return Predicates.alwaysTrue();
        }
        return Category.VISIBLE;
    }

    final Predicate<? super Category> includeNotRoutable() {
        if (includeNotRoutable == null) {
            includeNotRoutable = calculateIncludeNotRoutable();
        }
        return includeNotRoutable;
    }

    private Predicate<? super Category> calculateIncludeNotRoutable() {
        boolean include = false;
        if (componentConfig != null && componentConfig.includeNotRoutable() != null) {
            include = componentConfig.includeNotRoutable().booleanValue();
        } else if (config != null && config.includeNotRoutable() != null) {
            include = config.includeNotRoutable().booleanValue();
        }
        if (include) {
            return Predicates.alwaysTrue();
        }
        return Category.IS_ROUTABLE;
    }

    private int parseDepth(int depth) {
        return depth < 0 ? Integer.MAX_VALUE : depth;

    }

    final int depth() {
        if (componentConfig != null && componentConfig.depth() != null) {
            return parseDepth(componentConfig.depth());
        } else if (config != null && config.includeNotVisible() != null) {
            return parseDepth(config.depth());
        }
        return 0;
    }

    final Predicate<Category> selected() {
        if (selected == null) {
            selected = calculateSelected();
        }
        return selected;
    }

    private Predicate<Category> calculateSelected() {
        Category c = getSelected();
        if (c == null || !categories.containsValue(c)) {
            return Predicates.alwaysFalse();
        }
        if (config != null && config.selectParents()) {
            Set<Category> selected = Sets.newHashSet();
            do {
                selected.add(c);
                c = categories.getParent(c.getId());
            } while (c != null);
            return Predicates.in(selected);
        }
        return Predicates.equalTo(c);
    }

    private Category getSelected() {
        if (componentConfig != null && componentConfig.selected() != null) {
            return componentConfig.selected();
        } else if (config != null && config.selected() != null) {
            return config.selected();
        }
        if (config != null && config.decoupledSelection()) {
            final PageKey p = route.getPage();
            if (p instanceof WithNavigation) {
                final NavigationKey navigationKey = ((WithNavigation) p).getNavigationKey();
                if (navigationKey != null && navigationKey.isCategory()) {
                    Category c = navigationKey.getCategory();
                    if (categories.containsValue(c)) {
                        return c;
                    }
                }
            }
        }
        return getCurrent();
    }

    @Renderer
    public HTMLRenderer html(final RenderContext context) {
        return new SkeletalHTMLRenderer() {
            @Override
            public HTMLFragment getBody() {
                final String template;
                if (componentConfig != null && componentConfig.templateFile() != null) {
                    template = componentConfig.templateFile();
                } else if (config != null && config.templateFile() != null) {
                    template = config.templateFile();
                } else {
                    return HTMLFragments.empty();
                }
                final FreeMarkerService fms = getFreeMarkerService();
                final Model model = fms.createModel(context);
                model.put("items", items);
                return fms.getFragment(template, context, model);
            }
        };
    }

}