MVC models/named beans for the pages application.

pull/10/head
Jens Pelzetter 2021-10-23 17:40:46 +02:00
parent 4d069eb109
commit d5cc0370bc
5 changed files with 619 additions and 0 deletions

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2021 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.pages.models;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.contentsection.ContentItem;
import org.librecms.contenttypes.Article;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
/**
* Model for getting the special properties of an {@link Article}. For general
* properties of an content item use {@link ContentItemModel}.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsPagesArticleModel")
public class ArticleModel {
@Inject
private ContentItemModel contentItemModel;
@Inject
private GlobalizationHelper globalizationHelper;
public String getTitle() {
return getArticle()
.getTitle()
.getValue(globalizationHelper.getNegotiatedLocale());
}
public String getDescription() {
return getArticle()
.getDescription()
.getValue(globalizationHelper.getNegotiatedLocale());
}
public String getText() {
return getArticle()
.getText()
.getValue(globalizationHelper.getNegotiatedLocale());
}
protected Article getArticle() {
final ContentItem contentItem = contentItemModel.getContentItem();
if (contentItem instanceof Article) {
return (Article) contentItem;
} else {
throw new WebApplicationException(
"Current content item is not an article.",
Response
.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Current content item is not an article.")
.build()
);
}
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2021 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.pages.models;
import org.libreccm.categorization.Category;
import org.librecms.pages.PagesRouter;
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
/**
* Model for MVC applications providing access to the current category. This
* model MUST be initalized by the calling application (for example
* {@link PagesRouter} with the current category.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsPagesCategoryModel")
public class CategoryModel implements Serializable {
private static final long serialVersionUID = 1L;
private Category category;
private String categoryPath;
public Category getCategory() {
return category;
}
public void setCategory(final Category category) {
this.category = category;
}
public String getCategoryPath() {
return categoryPath;
}
public void setCategoryPath(final String categoryPath) {
this.categoryPath = categoryPath;
}
}

View File

@ -0,0 +1,282 @@
/*
* Copyright (C) 2021 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.pages.models;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.categorization.Categorization;
import org.libreccm.categorization.Category;
import org.libreccm.categorization.CategoryManager;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemVersion;
import org.librecms.pages.PagesRouter;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Root;
import javax.ws.rs.NotFoundException;
/**
* Retrieves a categorized content item for the current category. To work, the
* {@link #itemName} property MUST be initalized by the using application (for
* example {@link PagesRouter}. The value for {@link #itemName} is usually
* determined from the requested URL.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsPagesCategorizedItemModel")
public class ContentItemModel {
private static final Logger LOGGER = LogManager.getLogger(ContentItemModel.class
);
@Inject
private CategoryManager categoryManager;
@Inject
private CategoryModel categoryModel;
@Inject
private EntityManager entityManager;
@Inject
private GlobalizationHelper globalizationHelper;
private DateTimeFormatter dateTimeFormatter
= DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.systemDefault());
private String itemName;
private ContentItemVersion itemVersion;
private Optional<ContentItem> contentItem;
public String getItemName() {
return itemName;
}
public void setItemName(final String itemName) {
this.itemName = itemName;
}
/**
* Retrieves the current content item. Depending if {@link #itemName} has
* been initalized with a value either the index item of the current
* category or the item in the category identified by {@link #itemName} will
* be retrieved. The item is only received once per request. The method will
* retrieve the item on the first call and store the result in
* {@link #contentItem}. Subsequent calls will return the value of
* {@link #contentItem}. If {@link #itemName} is not {@code null} and there
* is no content item with the requested name in the category this method
* throws a {@link NotFoundException}.
*
* @return The requested categorized item. If {@link #itemName} is
* {@code null}, and the current category has not index item, the
* method will return {@code null}.
*
* @throws NotFoundException If there is no item identified by the name in
* {@link #itemName}.
*/
public ContentItem getContentItem() {
return getOrRetrieveContentItem().orElse(null);
}
public long getObjectId() {
return getOrRetrieveContentItem()
.map(ContentItem::getObjectId)
.orElse(0L);
}
public String getUuid() {
return getOrRetrieveContentItem()
.map(ContentItem::getUuid)
.orElse("");
}
public String getDisplayName() {
return getOrRetrieveContentItem()
.map(ContentItem::getDisplayName)
.orElse("");
}
public String getItemUuid() {
return getOrRetrieveContentItem()
.map(ContentItem::getItemUuid)
.orElse("");
}
public String getName() {
return getOrRetrieveContentItem()
.map(ContentItem::getName)
.map(
localized -> localized.getValue(
globalizationHelper.getNegotiatedLocale()
)
)
.orElse("");
}
public String getTitle() {
return getOrRetrieveContentItem()
.map(ContentItem::getTitle)
.map(
localized -> localized.getValue(
globalizationHelper.getNegotiatedLocale()
)
).orElse("");
}
public String getDescription() {
return getOrRetrieveContentItem()
.map(ContentItem::getDescription)
.map(
localized -> localized.getValue(
globalizationHelper.getNegotiatedLocale()
)
)
.orElse("");
}
public String getVersion() {
return getOrRetrieveContentItem()
.map(ContentItem::getVersion)
.map(ContentItemVersion::toString)
.orElse("");
}
public String getCreationDate() {
return getOrRetrieveContentItem()
.map(ContentItem::getCreationDate)
.map(Date::toInstant)
.map(instant -> instant.atZone(ZoneId.systemDefault()))
.map(ZonedDateTime::toLocalDateTime)
.map(dateTimeFormatter::format)
.orElse("");
}
public String getLastModified() {
return getOrRetrieveContentItem()
.map(ContentItem::getLastModified)
.map(Date::toInstant)
.map(instant -> instant.atZone(ZoneId.systemDefault()))
.map(ZonedDateTime::toLocalDateTime)
.map(dateTimeFormatter::format)
.orElse("");
}
public String getCreationUser() {
return getOrRetrieveContentItem()
.map(ContentItem::getCreationUserName)
.orElse("");
}
public String getLastModifyingUserName() {
return getOrRetrieveContentItem()
.map(ContentItem::getLastModifyingUserName)
.orElse("");
}
private Optional<ContentItem> getOrRetrieveContentItem() {
if (contentItem == null) {
retrieveContentItem();
}
return contentItem;
}
private void retrieveContentItem() {
if (itemName == null) {
retrieveIndexItem();
} else {
retrieveCategorizedItem();
}
}
private void retrieveIndexItem() {
final Category category = categoryModel.getCategory();
contentItem = categoryManager
.getIndexObject(category)
.stream()
.filter(object -> object instanceof ContentItem)
.map(object -> (ContentItem) object)
.filter(item -> item.getVersion() == itemVersion)
.findFirst();
}
private void retrieveCategorizedItem() {
final Category category = categoryModel.getCategory();
final CriteriaBuilder builder = entityManager
.getCriteriaBuilder();
final CriteriaQuery<ContentItem> criteriaQuery = builder
.createQuery(ContentItem.class);
final Root<ContentItem> from = criteriaQuery.from(
ContentItem.class
);
final Join<ContentItem, Categorization> join = from.join(
"categories"
);
final TypedQuery<ContentItem> query = entityManager
.createQuery(criteriaQuery
.select(from)
.where(builder.and(
builder.equal(from.get("displayName"), itemName),
builder.equal(
from.get("version"),
ContentItemVersion.DRAFT
),
builder.equal(join.get("category"), category)
)));
try {
contentItem = Optional.of(query.getSingleResult());
} catch (NoResultException ex) {
LOGGER.warn(
"No ContentItem with name \"{}\" in Category \"{}\".",
itemName,
Objects.toString(category)
);
throw new NotFoundException(
String.format(
"No ContentItem with name \"%s\" in Category \"%s\".",
itemName,
Objects.toString(category)
)
);
}
}
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2021 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.pages.models;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentType;
import java.util.Optional;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.swing.text.AbstractDocument.Content;
/**
* MVC model for retrieving information about the content type of the current
* content item. If there is no current content item, the methods of this model
* will return an empty string.
*
* The content type is retrieved once per request cycle on the first call
*
* @see ContentItemModel
* @see ContentItemModel#getContentItem()
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsPagesContentItemTypeModel")
public class ContentItemTypeModel {
@Inject
private ContentItemModel contentItemModel;
@Inject
private GlobalizationHelper globalizationHelper;
private Optional<ContentType> contentType;
public ContentType getContentType() {
return getOrRetrieveContentType().orElse(null);
}
public long getContentTypeId() {
return getOrRetrieveContentType()
.map(ContentType::getObjectId)
.orElse(0L);
}
public String getUuid() {
return getOrRetrieveContentType()
.map(ContentType::getUuid)
.orElse("");
}
public String getDisplayName() {
return getOrRetrieveContentType()
.map(ContentType::getDisplayName)
.orElse("");
}
public String getLabel() {
return getOrRetrieveContentType()
.map(ContentType::getLabel)
.map(
label -> label.getValue(
globalizationHelper.getNegotiatedLocale())
)
.orElse("");
}
public String getDescription() {
return getOrRetrieveContentType()
.map(ContentType::getDescription)
.map(
description -> description.getValue(
globalizationHelper.getNegotiatedLocale()
)
)
.orElse("");
}
private Optional<ContentType> getOrRetrieveContentType() {
if (contentType == null) {
retrieveContentType();
}
return contentType;
}
private void retrieveContentType() {
contentType = Optional
.ofNullable(contentItemModel.getContentItem())
.map(ContentItem::getContentType);
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2021 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.pages.models;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
/**
* Model providing information about the current site. Must be initalized by the
* calling application.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsPagesSiteInfoModel")
public class SiteInfoModel implements Serializable {
private static final long serialVersionUID = 1L;
private String host;
private String domain;
private String name;
private List<String> availableLanguages;
public String getHost() {
return host;
}
public void setHost(final String host) {
this.host = host;
}
public String getDomain() {
return domain;
}
public void setDomain(final String domain) {
this.domain = domain;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public List<String> getAvailableLanguages() {
return Collections.unmodifiableList(availableLanguages);
}
public void setAvailableLanguages(final List<String> availableLanguages) {
this.availableLanguages = new ArrayList<>(availableLanguages);
}
}