de.hybris.platform.category.impl.DefaultCategoryService.java Source code

Java tutorial

Introduction

Here is the source code for de.hybris.platform.category.impl.DefaultCategoryService.java

Source

/*
 * [y] hybris Platform
 *
 * Copyright (c) 2000-2013 hybris AG
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of hybris
 * ("Confidential Information"). You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the
 * license agreement you entered into with hybris.
 * 
 *  
 */
package de.hybris.platform.category.impl;

import static de.hybris.platform.servicelayer.util.ServicesUtil.validateParameterNotNull;

import de.hybris.platform.catalog.CatalogVersionService;
import de.hybris.platform.catalog.impl.CatalogUtils;
import de.hybris.platform.catalog.model.CatalogVersionModel;
import de.hybris.platform.category.CategoryService;
import de.hybris.platform.category.constants.CategoryConstants;
import de.hybris.platform.category.daos.CategoryDao;
import de.hybris.platform.category.model.CategoryModel;
import de.hybris.platform.category.strategies.CategoryPrincipalStrategy;
import de.hybris.platform.core.model.product.ProductModel;
import de.hybris.platform.core.model.security.PrincipalModel;
import de.hybris.platform.servicelayer.exceptions.AmbiguousIdentifierException;
import de.hybris.platform.servicelayer.exceptions.UnknownIdentifierException;
import de.hybris.platform.servicelayer.internal.service.AbstractBusinessService;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Required;

import com.google.common.base.Preconditions;

/**
 * Default implementation for {@link CategoryService}.
 */
public class DefaultCategoryService extends AbstractBusinessService implements CategoryService {

    private static final Logger LOG = Logger.getLogger(DefaultCategoryService.class);

    private CategoryDao categoryDao;
    private CatalogVersionService catalogVersionService;
    private volatile CategoryPrincipalStrategy categoryPrincipalStrategy;

    @Override
    public void disableSubcategoryRemovalCheck() {
        getSessionService().setAttribute(CategoryConstants.DISABLE_SUBCATEGORY_REMOVALCHECK, Boolean.TRUE);
    }

    @Override
    public void enableSubcategoryRemovalCheck() {
        getSessionService().removeAttribute(CategoryConstants.DISABLE_SUBCATEGORY_REMOVALCHECK);
    }

    @Override
    public boolean isSubcategoryRemovalCheckDisabled() {
        return Boolean.TRUE
                .equals(getSessionService().getAttribute(CategoryConstants.DISABLE_SUBCATEGORY_REMOVALCHECK));
    }

    @Override
    public Collection<CategoryModel> getCategoriesForCode(final String code) {
        validateParameterNotNull(code, "Parameter 'code' was null.");
        return categoryDao.findCategoriesByCode(code);
    }

    @Override
    public List<CategoryModel> getCategoryPathForProduct(final ProductModel product,
            final Class... includeOnlyCategories) {
        final List<CategoryModel> result = new ArrayList<CategoryModel>();
        final Collection<CategoryModel> currentLevel = new ArrayList<CategoryModel>();
        currentLevel.addAll(product.getSupercategories());

        while (!CollectionUtils.isEmpty(currentLevel)) {
            CategoryModel categoryModel = null;
            for (final CategoryModel category : currentLevel) {
                if (categoryModel == null && shouldAddPathElement(category.getClass(), includeOnlyCategories)) {
                    categoryModel = category;
                }
            }
            currentLevel.clear();
            if (categoryModel != null) {
                currentLevel.addAll(categoryModel.getSupercategories());
                result.add(categoryModel);
            }
        }

        Collections.reverse(result);
        return result;
    }

    private boolean shouldAddPathElement(final Class element, final Class... includeOnlyCategories) {
        boolean result = false;
        if (ArrayUtils.isEmpty(includeOnlyCategories)) {
            result = true;
        } else {
            if (ArrayUtils.contains(includeOnlyCategories, element)) {
                result = true;
            }
        }
        return result;
    }

    @SuppressWarnings("deprecation")
    @Deprecated
    @Override
    public CategoryModel getCategory(final CatalogVersionModel catalogVersion, final String code) {
        return getCategoryForCode(catalogVersion, code);
    }

    @SuppressWarnings("deprecation")
    @Deprecated
    @Override
    public CategoryModel getCategory(final String code) {
        validateParameterNotNull(code, "Parameter 'code' was null.");
        final Collection<CategoryModel> categories = getCategoriesForCode(code);
        return categories.isEmpty() ? null : categories.iterator().next();
    }

    @Override
    public CategoryModel getCategoryForCode(final CatalogVersionModel catalogVersion, final String code) {
        validateParameterNotNull(catalogVersion, "Parameter 'catalogVersion' was null.");
        validateParameterNotNull(code, "Parameter 'code' was null.");
        final Collection<CategoryModel> categories = this.categoryDao.findCategoriesByCode(catalogVersion, code);

        if (categories.isEmpty()) {
            throw new UnknownIdentifierException("Category with code '" + code + "' in CatalogVersion '"
                    + CatalogUtils.getFullCatalogVersionName(catalogVersion)
                    + "' not found! (Active session catalogversions: " + getCatalogVersionsString() + ")");
        } else if (categories.size() > 1) {
            throw new AmbiguousIdentifierException("Category with code '" + code + "' in CatalogVersion '"
                    + CatalogUtils.getFullCatalogVersionName(catalogVersion) + "' is not unique. "
                    + categories.size() + " categories found! (Active session catalogversions: "
                    + getCatalogVersionsString() + ")");
        }
        return categories.iterator().next();
    }

    @Override
    public CategoryModel getCategoryForCode(final String code) {
        validateParameterNotNull(code, "Parameter 'code' was null.");
        final Collection<CategoryModel> categories = getCategoriesForCode(code);
        if (categories.isEmpty()) {
            throw new UnknownIdentifierException("Category with code '" + code
                    + "' not found! (Active session catalogversions: " + getCatalogVersionsString() + ")");
        } else if (categories.size() > 1) {
            throw new AmbiguousIdentifierException("Category with code '" + code + "' is not unique. "
                    + categories.size() + " categories found! (Active session catalogversions: "
                    + getCatalogVersionsString() + ")");
        }
        return categories.iterator().next();
    }

    @SuppressWarnings("deprecation")
    @Deprecated
    @Override
    public List<CategoryModel> getPath(final CategoryModel category) {
        validateParameterNotNull(category, "Parameter 'category' was null.");
        final List<CategoryModel> ret = new LinkedList<CategoryModel>();
        CategoryModel cat = category;
        final Set<CategoryModel> controlSet = new HashSet<CategoryModel>();
        do {
            if (controlSet.add(cat)) {
                ret.add(cat);
                final List<CategoryModel> superCategories = cat.getSupercategories();
                if (superCategories.isEmpty()) {
                    cat = null;
                } else {
                    cat = superCategories.iterator().next();
                }
            } else {
                LOG.warn("path cycle found for category: [" + category.getCode() + "]");
            }
        } while (cat != null);
        return ret;
    }

    @Override
    public List<CategoryModel> getPathForCategory(final CategoryModel category) {
        final Collection<List<CategoryModel>> pathsForCategory = getPathsForCategory(category);
        if (pathsForCategory.size() == 1) {
            return pathsForCategory.iterator().next();
        } else {
            throw new AmbiguousIdentifierException("Found more than one path for category " + category + " (found "
                    + pathsForCategory.size() + ")");
        }
    }

    @Override
    public Collection<List<CategoryModel>> getPathsForCategory(final CategoryModel category) {
        validateParameterNotNull(category, "Parameter 'category' was null.");
        return getPathsInternal(category, new HashSet<CategoryModel>(Collections.singleton(category)));
    }

    @SuppressWarnings("deprecation")
    @Deprecated
    @Override
    public Collection<CategoryModel> getRootCategories(final CatalogVersionModel catalogVersion) {
        return getRootCategoriesForCatalogVersion(catalogVersion);
    }

    @Override
    public Collection<CategoryModel> getRootCategoriesForCatalogVersion(final CatalogVersionModel catalogVersion) {
        validateParameterNotNull(catalogVersion, "Parameter 'catalogVersion' was null.");
        return this.categoryDao.findRootCategoriesByCatalogVersion(catalogVersion);
    }

    @Override
    public boolean isEmpty(final CategoryModel category) {
        validateParameterNotNull(category, "Parameter 'category' was null.");
        return category.getCategories().isEmpty() && category.getProducts().isEmpty();
    }

    @Override
    public boolean isRoot(final CategoryModel category) {
        validateParameterNotNull(category, "Parameter 'category' was null.");
        return category.getSupercategories().isEmpty();
    }

    @Override
    public void setAllowedPrincipalsForCategory(final CategoryModel category,
            final List<PrincipalModel> newPrincipals) {
        Preconditions.checkArgument(category != null, "Parameter 'category' was null.");
        Preconditions.checkArgument(newPrincipals != null, "Parameter 'newPrincipals' was null.");
        categoryPrincipalStrategy.replacePrincipalsForCategory(category, newPrincipals);
    }

    @Override
    public void setAllowedPrincipalsForAllRelatedCategories(final CategoryModel category,
            final List<PrincipalModel> newPrincipals) {
        Preconditions.checkArgument(category != null, "Parameter 'category' was null.");
        Preconditions.checkArgument(newPrincipals != null, "Parameter 'newPrincipals' was null.");
        categoryPrincipalStrategy.replacePrincipalsForAllRelatedCategories(category, newPrincipals);
    }

    @Override
    public Collection<CategoryModel> getAllSubcategoriesForCategory(final CategoryModel category) {
        Preconditions.checkArgument(category != null, "Category is required to perform this operation, null given");
        return getAllSubcategories(Collections.singletonList(category));
    }

    private Collection<CategoryModel> getAllSubcategories(final Collection<CategoryModel> categories) {
        Collection<CategoryModel> result = null;
        Collection<CategoryModel> currentLevel = new ArrayList<CategoryModel>();
        for (final CategoryModel categoryModel : categories) {
            final List<CategoryModel> subCategories = categoryModel.getCategories();
            if (subCategories != null) {
                currentLevel.addAll(subCategories);
            }
        }

        while (!CollectionUtils.isEmpty(currentLevel)) {
            for (final Iterator iterator = currentLevel.iterator(); iterator.hasNext();) {
                final CategoryModel categoryModel = (CategoryModel) iterator.next();
                if (result == null) {
                    result = new HashSet<CategoryModel>();
                }
                if (!result.add(categoryModel)) {
                    // avoid cycles by removing all which are already found
                    iterator.remove();
                }
            }

            if (currentLevel.isEmpty()) {
                break;
            }
            final Collection<CategoryModel> nextLevel = getAllSubcategories(currentLevel);
            currentLevel = nextLevel;
        }

        return result == null ? Collections.EMPTY_LIST : result;
    }

    @Override
    public Collection<CategoryModel> getAllSupercategoriesForCategory(final CategoryModel category) {
        Preconditions.checkArgument(category != null, "Category is required to perform this operation, null given");
        return getAllSupercategories(Collections.singletonList(category));
    }

    private Collection<CategoryModel> getAllSupercategories(final Collection<CategoryModel> categories) {
        Collection<CategoryModel> result = null;
        Collection<CategoryModel> currentLevel = new ArrayList<CategoryModel>();
        for (final CategoryModel categoryModel : categories) {
            final List<CategoryModel> superCategories = categoryModel.getSupercategories();
            if (superCategories != null) {
                currentLevel.addAll(superCategories);
            }
        }

        while (!CollectionUtils.isEmpty(currentLevel)) {
            for (final Iterator iterator = currentLevel.iterator(); iterator.hasNext();) {
                final CategoryModel categoryModel = (CategoryModel) iterator.next();
                if (result == null) {
                    result = new HashSet<CategoryModel>();
                }
                if (!result.add(categoryModel)) {
                    // avoid cycles by removing all which are already found
                    iterator.remove();
                }
            }

            if (currentLevel.isEmpty()) {
                break;
            }
            final Collection<CategoryModel> nextLevel = getAllSupercategories(currentLevel);
            currentLevel = nextLevel;
        }

        return result == null ? Collections.EMPTY_LIST : result;
    }

    @Required
    public void setCatalogVersionService(final CatalogVersionService catalogVersionService) {
        this.catalogVersionService = catalogVersionService;
    }

    @Required
    public void setCategoryDao(final CategoryDao categoryDao) {
        this.categoryDao = categoryDao;
    }

    @Required
    public void setCategoryPrincipalStrategy(final CategoryPrincipalStrategy categoryPrincipalStrategy) {
        this.categoryPrincipalStrategy = categoryPrincipalStrategy;
    }

    private String getCatalogVersionsString() {
        return CatalogUtils.getCatalogVersionsString(catalogVersionService.getSessionCatalogVersions());
    }

    private Collection<List<CategoryModel>> getPathsInternal(final CategoryModel category,
            final Set<CategoryModel> controlSet) {
        Collection<List<CategoryModel>> result = null;

        final Collection<CategoryModel> superCategories = category.getSupercategories();
        if (CollectionUtils.isNotEmpty(superCategories)) {
            for (final CategoryModel parent : superCategories) {
                if (notVisited(parent, controlSet)) {
                    if (result == null) {
                        result = new LinkedList<List<CategoryModel>>();
                    }
                    visitSuperCategory(category, parent, controlSet, result);
                    markNotVisited(parent, controlSet);
                } else {
                    LOG.warn("path cycle found for category: [" + category.getCode() + "]");
                }
            }
        }

        return result == null ? Collections.singletonList(Collections.singletonList(category)) : result;
    }

    /**
     * @see #notVisited(CategoryModel, Set)
     */
    private void markNotVisited(final CategoryModel cat, final Set<CategoryModel> visitedCategories) {
        visitedCategories.remove(cat);
    }

    /**
     * @see #markNotVisited(CategoryModel, Set)
     */
    private boolean notVisited(final CategoryModel cat, final Set<CategoryModel> visitedCategories) {
        return visitedCategories.add(cat);
    }

    private void visitSuperCategory(final CategoryModel category, final CategoryModel parent,
            final Set<CategoryModel> controlSet, final Collection<List<CategoryModel>> result) {
        for (List<CategoryModel> parentPath : getPathsInternal(parent, controlSet)) {
            if (!(parentPath instanceof LinkedList)) {
                parentPath = new LinkedList<CategoryModel>(parentPath);
            }
            parentPath.add(category);
            result.add(parentPath);
        }
    }

}