CCM NG: ItemListComponent for the PageModel
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5072 8810af33-2d31-482b-a856-94f89814c4dfpull/2/head
parent
37a8756ad0
commit
b66024e8b3
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue