CCM NG: ItemListComponent for the PageModel

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5072 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2017-10-23 07:18:38 +00:00
parent 37a8756ad0
commit b66024e8b3
2 changed files with 280 additions and 21 deletions

View File

@ -56,15 +56,17 @@ public class ItemListComponent extends ComponentModel {
private boolean descending; private boolean descending;
/** /**
* Include only the types listed here into the list * Include only items of the specified type into the list. This must be a
* subtype of {@link ContentItem}.
*/ */
@ElementCollection @Column(name = "LIMIT_TO_TYPE")
@CollectionTable(name = "ITEM_LIST_LIMIT_TO_TYPES", private String limitToType;
schema = DB_SCHEMA,
joinColumns = { /**
@JoinColumn(name = "ITEM_LIST_ID") * Maximum number of items shown on one page.
}) */
private Set<String> limitToTypes; @Column(name = "PAGE_SIZE")
private int pageSize;
/** /**
* Order the list by this properties. Warning: All items must have the * Order the list by this properties. Warning: All items must have the
@ -87,22 +89,22 @@ public class ItemListComponent extends ComponentModel {
this.descending = descending; this.descending = descending;
} }
public Set<String> getLimitToTypes() { public String getLimitToType() {
return Collections.unmodifiableSet(limitToTypes); return limitToType;
} }
public void addLimitToTypes(final String type) { public void setLimitToTypes(final String limitToType) {
limitToTypes.add(type); this.limitToType = limitToType;
} }
public void removeLimitToType(final String type) { public int getPageSize() {
limitToTypes.remove(type); return pageSize;
} }
public void setLimitToTypes(final Set<String> limitToTypes) { public void setPageSize(final int pageSize) {
this.limitToTypes = new HashSet<>(limitToTypes); this.pageSize = pageSize;
} }
public List<String> getListOrder() { public List<String> getListOrder() {
return Collections.unmodifiableList(listOrder); return Collections.unmodifiableList(listOrder);
} }
@ -123,7 +125,7 @@ public class ItemListComponent extends ComponentModel {
public int hashCode() { public int hashCode() {
int hash = super.hashCode(); int hash = super.hashCode();
hash = 41 * hash + (descending ? 1 : 0); hash = 41 * hash + (descending ? 1 : 0);
hash = 41 * hash + Objects.hashCode(limitToTypes); hash = 41 * hash + Objects.hashCode(limitToType);
hash = 41 * hash + Objects.hashCode(listOrder); hash = 41 * hash + Objects.hashCode(listOrder);
return hash; return hash;
} }
@ -152,7 +154,7 @@ public class ItemListComponent extends ComponentModel {
if (descending != other.isDescending()) { if (descending != other.isDescending()) {
return false; return false;
} }
if (!Objects.equals(limitToTypes, other.getLimitToTypes())) { if (!Objects.equals(limitToType, other.getLimitToType())) {
return false; return false;
} }
return Objects.equals(listOrder, other.getListOrder()); return Objects.equals(listOrder, other.getListOrder());
@ -169,7 +171,7 @@ public class ItemListComponent extends ComponentModel {
+ "limitToTypes = %s, " + "limitToTypes = %s, "
+ "listOrder = %s%s", + "listOrder = %s%s",
descending, descending,
Objects.toString(limitToTypes), limitToType,
Objects.toString(listOrder), Objects.toString(listOrder),
data)); data));
} }

View File

@ -0,0 +1,257 @@
/*
* Copyright (C) 2017 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.pagemodel;
import com.arsdigita.kernel.KernelConfig;
import org.libreccm.categorization.Categorization;
import org.libreccm.categorization.Category;
import org.libreccm.categorization.CategoryManager;
import org.libreccm.categorization.CategoryRepository;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.core.UnexpectedErrorException;
import org.libreccm.pagemodel.ComponentModelType;
import java.util.Map;
import javax.enterprise.context.RequestScoped;
import org.libreccm.pagemodel.ComponentRenderer;
import org.librecms.contentsection.ContentItem;
import org.librecms.pagemodel.contentitems.AbstractContentItemRenderer;
import org.librecms.pagemodel.contentitems.ContentItemRenderers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import static org.librecms.pages.PagesConstants.*;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@ComponentModelType(componentModel = ItemListComponent.class)
public class ItemListComponentRenderer
implements ComponentRenderer<ItemListComponent> {
@Inject
private ConfigurationManager confManager;
@Inject
private ContentItemRenderers itemRenderers;
@Inject
private EntityManager entityManager;
@Inject
private HttpServletRequest request;
@Override
public Map<String, Object> renderComponent(
final ItemListComponent componentModel,
final Map<String, Object> parameters) {
Objects.requireNonNull(componentModel);
Objects.requireNonNull(parameters);
if (!parameters.containsKey(PARAMETER_CATEGORY)) {
throw new IllegalArgumentException(
"The parameters map passed to this GreetingItem component does "
+ "not include the parameter \"category\"");
}
if (!(parameters.get(PARAMETER_CATEGORY) instanceof Category)) {
throw new IllegalArgumentException(String
.format("The parameters map passed to this GreetingItem "
+ "component contains the parameter \"category\", but the "
+ "parameter is not of type \"%s\" but of type \"%s\".",
Category.class.getName(),
parameters.get(PARAMETER_CATEGORY).getClass().getName()));
}
final Category category = (Category) parameters.get(PARAMETER_CATEGORY);
final Locale language;
if (parameters.containsKey(PARAMETER_LANGUAGE)) {
language = new Locale((String) parameters.get(PARAMETER_LANGUAGE));
} else {
final KernelConfig kernelConfig = confManager
.findConfiguration(KernelConfig.class);
language = kernelConfig.getDefaultLocale();
}
final List<Category> categories;
if (componentModel.isDescending()) {
categories = collectCategories(category);
} else {
categories = new ArrayList<>();
}
categories.add(category);
final Class<? extends ContentItem> limitToType = getLimitToType(
componentModel);
final List<? extends ContentItem> items = findItems(
limitToType,
categories,
componentModel.getListOrder(),
componentModel.getPageSize());
final Map<String, Object> result = new HashMap<>();
result.put("items",
items
.stream()
.map(item -> renderItem(item, language))
.collect(Collectors.toList()));
return result;
}
private List<Category> collectCategories(final Category category) {
if (category.getSubCategories().isEmpty()) {
return Collections.emptyList();
} else {
final List<Category> categories = new ArrayList<>();
for (final Category subCategory : category.getSubCategories()) {
categories.add(subCategory);
categories.addAll(collectCategories(subCategory));
}
return categories;
}
}
private List<? extends ContentItem> findItems(
final Class<? extends ContentItem> limitToType,
final List<Category> categories,
final List<String> listOrder,
final int pageSize) {
final CriteriaBuilder criteriaBuilder = entityManager
.getCriteriaBuilder();
final CriteriaQuery<? extends ContentItem> criteriaQuery
= criteriaBuilder
.createQuery(limitToType);
final Root<? extends ContentItem> from = criteriaQuery
.from(limitToType);
final Join<? extends ContentItem, Categorization> catJoin = from
.join("categories");
criteriaQuery.where(catJoin.get("category").in(categories));
criteriaQuery
.orderBy(listOrder
.stream()
.map(order -> createOrder(order, from, criteriaBuilder))
.collect(Collectors.toList()));
return entityManager
.createQuery(criteriaQuery)
.setFirstResult(getOffset(pageSize))
.setMaxResults(pageSize)
.getResultList();
}
private Class<? extends ContentItem> getLimitToType(
final ItemListComponent componentModel) {
final String className = componentModel.getLimitToType();
if (className == null
|| className.matches("\\s*")) {
return ContentItem.class;
} else {
final Class<?> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException ex) {
throw new UnexpectedErrorException(ex);
}
if (ContentItem.class.isAssignableFrom(clazz)) {
@SuppressWarnings("unchecked")
final Class<? extends ContentItem> type
= (Class<? extends ContentItem>) clazz;
return type;
} else {
throw new UnexpectedErrorException(String
.format(
"The type \"%s\" set in ItemList is not a subtype of "
+ "\"%s\".",
clazz.getName(),
ContentItem.class.getName()));
}
}
}
private Order createOrder(final String order,
final Root<? extends ContentItem> from,
final CriteriaBuilder criteriaBuilder) {
if (order.endsWith(" ASC")) {
final String colName = order
.substring(0, order.length() - " ASC".length());
return (criteriaBuilder.asc(from.get(colName)));
} else if (order.endsWith(" DESC")) {
final String colName = order
.substring(0, order.length() - " DESC".length());
return criteriaBuilder.desc(from.get(colName));
} else {
return criteriaBuilder.asc(from.get(order));
}
}
private int getOffset(final int pageSize) {
if (request.getParameterMap().containsKey("page")) {
final String value = request.getParameter("page");
if (value.matches("\\d*")) {
final int page = Integer.valueOf(value);
return page * pageSize;
} else {
return 0;
}
} else {
return 0;
}
}
private Map<String, Object> renderItem(final ContentItem item,
final Locale language) {
final AbstractContentItemRenderer renderer = itemRenderers
.findRenderer(item.getClass());
return renderer.render(item, language);
}
}