Optimizations for the models processing content items.
parent
65d53e9992
commit
661c70073f
|
|
@ -4,21 +4,33 @@
|
|||
<div class="container">
|
||||
<div class="bg-light mb-4 rounded-3">
|
||||
<div class="container-fluid py-5">
|
||||
<h1 class="display-5 fw-bold">
|
||||
LibreCMS
|
||||
</h1>
|
||||
<p>
|
||||
No index item has been defined.
|
||||
</p>
|
||||
<a class="btn btn-primary btn-lg"
|
||||
href="https://www.libreccm.org"
|
||||
type="button">
|
||||
Find out more
|
||||
</a>
|
||||
<#if CmsPagesCategorizedItemModel.itemAvailable>
|
||||
<h1 class="display-5 fw-bold">
|
||||
${CmsPagesCategorizedItemModel.title}
|
||||
</h1>
|
||||
<p>
|
||||
${CmsPagesCategorizedItemModel.description}
|
||||
</p>
|
||||
<a class="btn btn-primary btn-lg"
|
||||
href="#">
|
||||
Find out more
|
||||
</a>
|
||||
<#else>
|
||||
<h1 class="display-5 fw-bold">
|
||||
LibreCMS
|
||||
</h1>
|
||||
<p>
|
||||
No index item has been defined.
|
||||
</p>
|
||||
<a class="btn btn-primary btn-lg"
|
||||
href="https://www.libreccm.org">
|
||||
Find out more
|
||||
</a>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<#if CmsPagesCategorizedItemModel.contentItem??>
|
||||
<#if CmsPagesCategorizedItemModel.itemAvailable>
|
||||
Category has an index item
|
||||
<#else>
|
||||
Category has no index item
|
||||
|
|
@ -34,6 +46,39 @@
|
|||
<dt>view</dt>
|
||||
<dd>${view!""}</dd>
|
||||
</dl>
|
||||
|
||||
<h2>From <code>ArticleModel</code></h2>
|
||||
<dl>
|
||||
<dt>Title</dt>
|
||||
<dd>${CmsPagesArticleModel.title}</dd>
|
||||
<dt>Description</dt>
|
||||
<dd>${CmsPagesArticleModel.description}</dd>
|
||||
<dt>Text</dt>
|
||||
<dd>${CmsPagesArticleModel.text}</dd>
|
||||
</dl>
|
||||
|
||||
<h2>Item List</h2>
|
||||
<p>Item List size: ${CmsPagesItemListModel.listSize}</p>
|
||||
<ul>
|
||||
<#list CmsPagesItemListModel.items as item>
|
||||
<li>
|
||||
<dl>
|
||||
<dt>UUID</dt>
|
||||
<dd>${item.uuid}</dd>
|
||||
<dt>displayName</dt>
|
||||
<dd>${item.displayName}</dd>
|
||||
<dt>Name</dt>
|
||||
<dd>${item.name}</dd>
|
||||
<dt>Title</dt>
|
||||
<dd>${item.title}</dd>
|
||||
<dt>description</dt>
|
||||
<dd>${item.description}</dd>
|
||||
<dt>Type</dt>
|
||||
<dd>${item.type}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
</#list>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</@main.librecms>
|
||||
|
|
@ -28,8 +28,6 @@ import javax.enterprise.context.RequestScoped;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.transaction.Transactional;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
* Model for getting the special properties of an {@link Article}. For general
|
||||
|
|
@ -39,7 +37,7 @@ import javax.ws.rs.core.Response;
|
|||
*/
|
||||
@RequestScoped
|
||||
@Named("CmsPagesArticleModel")
|
||||
public class ArticleModel {
|
||||
public class ArticleModel implements ProcessesContentItem {
|
||||
|
||||
@Inject
|
||||
private ContentItemModel contentItemModel;
|
||||
|
|
@ -47,41 +45,46 @@ public class ArticleModel {
|
|||
@Inject
|
||||
private GlobalizationHelper globalizationHelper;
|
||||
|
||||
private boolean initialized;
|
||||
|
||||
private String title;
|
||||
|
||||
private String description;
|
||||
|
||||
private String text;
|
||||
|
||||
public ArticleModel() {
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getTitle() {
|
||||
if (title == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getDescription() {
|
||||
if (description == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getText() {
|
||||
if (text == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected void init() {
|
||||
final ContentItem contentItem = contentItemModel
|
||||
.retrieveContentItem()
|
||||
.orElse(null);
|
||||
@Override
|
||||
public void init(final ContentItem contentItem) {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (contentItem instanceof Article) {
|
||||
final Article article = (Article) contentItem;
|
||||
|
||||
|
|
@ -97,15 +100,8 @@ public class ArticleModel {
|
|||
.ofNullable(article.getText())
|
||||
.map(globalizationHelper::getValueFromLocalizedString)
|
||||
.orElse("");
|
||||
} 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()
|
||||
);
|
||||
}
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,24 +18,24 @@
|
|||
*/
|
||||
package org.librecms.pages.models;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.libreccm.categorization.CategoryManager;
|
||||
import org.libreccm.categorization.CategoryRepository;
|
||||
import org.libreccm.core.CcmObject;
|
||||
import org.libreccm.l10n.GlobalizationHelper;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemVersion;
|
||||
import org.librecms.pages.PagesController;
|
||||
import org.librecms.pages.PagesRouter;
|
||||
import org.librecms.pages.PagesService;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.enterprise.inject.Instance;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
|
|
@ -50,162 +50,348 @@ import javax.transaction.Transactional;
|
|||
@Named("CmsPagesCategorizedItemModel")
|
||||
public class ContentItemModel {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
ContentItemModel.class
|
||||
);
|
||||
|
||||
@Inject
|
||||
private CategoryManager categoryManager;
|
||||
|
||||
/**
|
||||
* Category repository used to retrieve the current category.
|
||||
*/
|
||||
@Inject
|
||||
private CategoryRepository categoryRepository;
|
||||
|
||||
/**
|
||||
* Category model used to get the curretn category.
|
||||
*/
|
||||
@Inject
|
||||
private CategoryModel categoryModel;
|
||||
|
||||
@Inject
|
||||
private EntityManager entityManager;
|
||||
|
||||
/**
|
||||
* Utility for globalization stuff.
|
||||
*/
|
||||
@Inject
|
||||
private GlobalizationHelper globalizationHelper;
|
||||
|
||||
/**
|
||||
* Provides some utility methods.
|
||||
*/
|
||||
@Inject
|
||||
private PagesService pagesService;
|
||||
|
||||
/**
|
||||
* All instances of implementations of the {@link ProcessesContentItem}
|
||||
* interface.
|
||||
*/
|
||||
@Inject
|
||||
private Instance<ProcessesContentItem> contentItemProcessingModels;
|
||||
|
||||
/**
|
||||
* A {@link DateTimeFormatter} instance for converting dates and times to an
|
||||
* ISO 8601 date/time string.
|
||||
*/
|
||||
private final DateTimeFormatter dateTimeFormatter
|
||||
= DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.systemDefault());
|
||||
|
||||
/**
|
||||
* The name of the item to be shown.
|
||||
*/
|
||||
private String itemName;
|
||||
|
||||
/**
|
||||
* The version of the item to be shown.
|
||||
*/
|
||||
private ContentItemVersion itemVersion;
|
||||
|
||||
// private Optional<ContentItem> contentItem;
|
||||
/**
|
||||
* Data of the current content item, already prepared for retrieving the
|
||||
* data from a MVC template. If no item with the {@link #itemName} provided
|
||||
* by the {@link PagesController} is present in the category, the
|
||||
* {@link Optional} will be empty.
|
||||
*/
|
||||
private Optional<ContentItemModelData> contentItem;
|
||||
|
||||
/**
|
||||
* Gets the item name provided by the {@link PagesController}.
|
||||
*
|
||||
* @return The item name provided by the {@link PagesController}.
|
||||
*/
|
||||
public String getItemName() {
|
||||
return itemName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the {@link PagesController} to set the name of the requested
|
||||
* content item. May be used by other controllers.
|
||||
*
|
||||
* @param itemName The name of the requested content item.
|
||||
*/
|
||||
public void setItemName(final String itemName) {
|
||||
this.itemName = itemName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The requested version of the content item.
|
||||
*
|
||||
* @return The requested version of the content item.
|
||||
*/
|
||||
public ContentItemVersion getItemVersion() {
|
||||
return itemVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by controllers, for example the {@link PagesController} to set the
|
||||
* requested version of the content item.
|
||||
*
|
||||
* @param itemVersion The requested version of the content item.
|
||||
*/
|
||||
public void setItemVersion(final ContentItemVersion itemVersion) {
|
||||
this.itemVersion = itemVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convient getter for checking if a content item is available from a
|
||||
* template.
|
||||
*
|
||||
* @return {@code true} if an item is available, {@code false} if not.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public boolean isItemAvailable() {
|
||||
return getOrRetrieveContentItem().isPresent();
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public long getObjectId() {
|
||||
return getOrRetrieveContentItem()
|
||||
.map(ContentItemModelData::getObjectId)
|
||||
.orElse(0L);
|
||||
init();
|
||||
return contentItem.isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@code objectId)} (see {@link CcmObject#objectId} of the current
|
||||
* item.
|
||||
*
|
||||
* @return The {@code objectId} of the current item if there is an item or
|
||||
* {@code -1L} if there is no item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public long getObjectId() {
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getObjectId)
|
||||
.orElse(-1L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the UUID of the current item (see {@link CcmObject#uuid}.
|
||||
*
|
||||
* @return The UUID of the current item if there is an item, an empty string
|
||||
* if there is not item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getUuid() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getUuid)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display name of the current item (see
|
||||
* {@link CcmObject#displayName}.
|
||||
*
|
||||
* @return The display name of the current item, or an empty string if there
|
||||
* is not current item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getDisplayName() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getDisplayName)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item UUID of the current item (see {@link ContentItem#itemUuid}.
|
||||
*
|
||||
* @return The item UUID of the current item, or an empty string if the is
|
||||
* no current item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getItemUuid() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getItemUuid)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the current item {@link ContentItem#name}) for the
|
||||
* current language (see {@link GlobalizationHelper#getNegotiatedLocale()}).
|
||||
*
|
||||
* @return The name of the the current item for the current language, or an
|
||||
* empty string if there is no item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getName() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getName)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the title of the current item (see {@link ContentItem#title} for the
|
||||
* current language (see {@link GlobalizationHelper#getNegotiatedLocale()}).
|
||||
*
|
||||
* @return The title of the current item for the current language, or an
|
||||
* empty string if there is no item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getTitle() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getTitle)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the description of the current item (see
|
||||
* {@link ContentItem#description} for the current language (see
|
||||
* {@link GlobalizationHelper#getNegotiatedLocale()}).
|
||||
*
|
||||
* @return The description of the current item for the current language, or
|
||||
* an empty string if there is no item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getDescription() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getDescription)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version of the current item (see {@link ContentItem#version}.
|
||||
*
|
||||
* @return The version of the current version as a string, or an empty
|
||||
* string if there is not current item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getVersion() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getVersion)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the creation date/time of the current item (see
|
||||
* {@link ContentItem#creationDate}.
|
||||
*
|
||||
* @return The creation date/time of the current item as ISO 8601 date/time
|
||||
* string, or an empty string if there is no item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getCreationDate() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getCreationDate)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date/time of the last modification of the current item (see
|
||||
* {@link ContentItem#lastModified}.
|
||||
*
|
||||
* @return The date/time of the modification of the current item as ISO 8601
|
||||
* date/time string, or an empty string of there is not current
|
||||
* item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getLastModified() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getLastModified)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user name of the user that created the item.
|
||||
*
|
||||
* @return The user name of the user that created the item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getCreationUser() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getCreationUser)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user name of the user that did the last modifications on the
|
||||
* item.
|
||||
*
|
||||
* @return The user name of the user that did the last modifications on the
|
||||
* item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getLastModifyingUserName() {
|
||||
return getOrRetrieveContentItem()
|
||||
init();
|
||||
return contentItem
|
||||
.map(ContentItemModelData::getLastModifyingUserName)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
// public List<AttachmentList> getAttachments() {
|
||||
// throw new UnsupportedOperationException("Not implemented yet.");
|
||||
// }
|
||||
// private Optional<ContentItem> getOrRetrieveContentItem() {
|
||||
// if (contentItem == null) {
|
||||
// retrieveContentItem();
|
||||
// }
|
||||
// return contentItem;
|
||||
// }
|
||||
/**
|
||||
* Initialize the this model and all models implementing
|
||||
* {@link ProcessesContentItem#}.
|
||||
*
|
||||
* If this model has not been initalizied already this method retrieves the
|
||||
* current content item using {@link #retrieveContentItem()}, and
|
||||
* initializes {@link #contentItem} with an instance of
|
||||
* {@link ContentItemModelData} build from the item using
|
||||
* {@link #buildModelData(org.librecms.contentsection.ContentItem)}.
|
||||
*
|
||||
* After that, the method will invoke the implementation of
|
||||
* {@link ProcessesContentItem#init(org.librecms.contentsection.ContentItem)}
|
||||
* for all available implemetentations of {@link ProcessesContentItem} (see
|
||||
* {@link #contentItemProcessingModels}).
|
||||
*
|
||||
* Models implementing SHOULD call this method in their getters before
|
||||
* returning a value. There is not need to wrap the invocation of this
|
||||
* method in an {@code if} statement, the method will only run its logic if
|
||||
* the item has not been initialized.
|
||||
*
|
||||
* If there is no current item, the method will do nothing.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
private Optional<ContentItemModelData> getOrRetrieveContentItem() {
|
||||
if (contentItem == null) {
|
||||
contentItem = retrieveContentItem().map(this::buildModelData);
|
||||
public void init() {
|
||||
if (contentItem != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Optional<ContentItem> item = retrieveContentItem();
|
||||
contentItem = item.map(this::buildModelData);
|
||||
|
||||
final Iterator<ProcessesContentItem> iterator
|
||||
= contentItemProcessingModels.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final ProcessesContentItem model = iterator.next();
|
||||
model.init(item.orElse(null));
|
||||
}
|
||||
return contentItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for retrieving the current content item. If
|
||||
* {@link #itemName} is {@code null} or {@code index} the method will return
|
||||
* if the index item of the current category. If the category has not index
|
||||
* item, an empty {@link Optional} is returned.
|
||||
*
|
||||
* If {@link #itemName} is <b>not</b> {@code null} or {@code index}, the
|
||||
* method will try to find a content item associated to the category where
|
||||
* {@link ContentItem#name} matches {@link #itemName}.
|
||||
*
|
||||
* @return The current content item if any, or an empyty {@link Optional}.
|
||||
*
|
||||
* @see PagesService#findIndexItem(org.libreccm.categorization.Category,
|
||||
* org.librecms.contentsection.ContentItemVersion)
|
||||
* @see
|
||||
* PagesService#findCategorizedItem(org.libreccm.categorization.Category,
|
||||
* java.lang.String, org.librecms.contentsection.ContentItemVersion)
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected Optional<ContentItem> retrieveContentItem() {
|
||||
private Optional<ContentItem> retrieveContentItem() {
|
||||
final Optional<ContentItem> item;
|
||||
if (itemName == null || "index".equals(itemName)) {
|
||||
item = pagesService.findIndexItem(
|
||||
|
|
@ -245,6 +431,15 @@ public class ContentItemModel {
|
|||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for building an instance {@link ContentItemModelData} for a
|
||||
* {@link ContentItem}.
|
||||
*
|
||||
* @param item The source content item.
|
||||
*
|
||||
* @return An instance of {@link ContentItemModelData} for the provided
|
||||
* content item.
|
||||
*/
|
||||
private ContentItemModelData buildModelData(final ContentItem item) {
|
||||
final ContentItemModelData data = new ContentItemModelData();
|
||||
data.setObjectId(item.getObjectId());
|
||||
|
|
@ -292,6 +487,12 @@ public class ContentItemModel {
|
|||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates the data of content item provided by this model. To avoid to
|
||||
* have to many fields in this model class we use an internal class to
|
||||
* encapsulate the data. The getters of the model class return the values
|
||||
* from an instance of this class.
|
||||
*/
|
||||
private class ContentItemModelData {
|
||||
|
||||
private long objectId;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ import javax.transaction.Transactional;
|
|||
*/
|
||||
@RequestScoped
|
||||
@Named("CmsPagesContentItemTypeModel")
|
||||
public class ContentItemTypeModel {
|
||||
public class ContentItemTypeModel implements ProcessesContentItem {
|
||||
|
||||
@Inject
|
||||
private ContentItemModel contentItemModel;
|
||||
|
|
@ -54,48 +54,55 @@ public class ContentItemTypeModel {
|
|||
private Optional<ContentItemTypeModelData> contentType;
|
||||
|
||||
public long getContentTypeId() {
|
||||
return getOrRetrieveContentType()
|
||||
contentItemModel.init();
|
||||
|
||||
return contentType
|
||||
.map(ContentItemTypeModelData::getTypeId)
|
||||
.orElse(0L);
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return getOrRetrieveContentType()
|
||||
contentItemModel.init();
|
||||
|
||||
return contentType
|
||||
.map(ContentItemTypeModelData::getUuid)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return getOrRetrieveContentType()
|
||||
contentItemModel.init();
|
||||
|
||||
return contentType
|
||||
.map(ContentItemTypeModelData::getDisplayName)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return getOrRetrieveContentType()
|
||||
contentItemModel.init();
|
||||
|
||||
return contentType
|
||||
.map(ContentItemTypeModelData::getLabel)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return getOrRetrieveContentType()
|
||||
contentItemModel.init();
|
||||
|
||||
return contentType
|
||||
.map(ContentItemTypeModelData::getDescription)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
private Optional<ContentItemTypeModelData> getOrRetrieveContentType() {
|
||||
if (contentType == null) {
|
||||
retrieveContentType();
|
||||
}
|
||||
return contentType;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
private void retrieveContentType() {
|
||||
contentType = contentItemModel.retrieveContentItem()
|
||||
public void init(final ContentItem contentItem) {
|
||||
if (contentType != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
contentType = Optional
|
||||
.ofNullable(contentItem)
|
||||
.map(ContentItem::getContentType)
|
||||
.map(this::buildModelData);
|
||||
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ import javax.enterprise.context.RequestScoped;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.transaction.Transactional;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -40,7 +38,7 @@ import javax.ws.rs.core.Response;
|
|||
*/
|
||||
@RequestScoped
|
||||
@Named("CmsPagesEventModel")
|
||||
public class EventModel {
|
||||
public class EventModel implements ProcessesContentItem {
|
||||
|
||||
@Inject
|
||||
private ContentItemModel contentItemModel;
|
||||
|
|
@ -48,6 +46,8 @@ public class EventModel {
|
|||
@Inject
|
||||
private GlobalizationHelper globalizationHelper;
|
||||
|
||||
private boolean initialized;
|
||||
|
||||
private final DateTimeFormatter isoDateTimeFormatter;
|
||||
|
||||
private String title;
|
||||
|
|
@ -65,77 +65,67 @@ public class EventModel {
|
|||
private String eventType;
|
||||
|
||||
public EventModel() {
|
||||
initialized = false;
|
||||
isoDateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME
|
||||
.withZone(ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getTitle() {
|
||||
if (title == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getText() {
|
||||
if (text == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getStartDateTime() {
|
||||
if (startDateTime == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return startDateTime;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getEndDateTime() {
|
||||
if (endDateTime == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return endDateTime;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getEventDate() {
|
||||
if (eventDate == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return eventDate;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getLocation() {
|
||||
if (location == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getEventType() {
|
||||
if (eventType == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return eventDate;
|
||||
return eventType;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected void init() {
|
||||
final ContentItem contentItem = contentItemModel
|
||||
.retrieveContentItem()
|
||||
.orElse(null);
|
||||
public void init(final ContentItem contentItem) {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (contentItem instanceof Event) {
|
||||
final Event event = (Event) contentItem;
|
||||
|
||||
|
|
@ -169,15 +159,9 @@ public class EventModel {
|
|||
.ofNullable(event.getEventType())
|
||||
.map(globalizationHelper::getValueFromLocalizedString)
|
||||
.orElse("");
|
||||
} else {
|
||||
throw new WebApplicationException(
|
||||
"Current content item is not an event",
|
||||
Response
|
||||
.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Current content item is not an event.")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import javax.ws.rs.core.Response;
|
|||
*/
|
||||
@RequestScoped
|
||||
@Named("CmsPagesMultiPartArticleModel")
|
||||
public class MultiPartArticleModel {
|
||||
public class MultiPartArticleModel implements ProcessesContentItem {
|
||||
|
||||
@Inject
|
||||
private ContentItemModel contentItemModel;
|
||||
|
|
@ -49,6 +49,8 @@ public class MultiPartArticleModel {
|
|||
@Inject
|
||||
private GlobalizationHelper globalizationHelper;
|
||||
|
||||
private boolean initialized;
|
||||
|
||||
@Inject
|
||||
private PageUrlModel pageUrlModel;
|
||||
|
||||
|
|
@ -61,69 +63,62 @@ public class MultiPartArticleModel {
|
|||
private String currentSectionTitle;
|
||||
|
||||
private String currentSectionText;
|
||||
|
||||
|
||||
private List<MultiPartArticleSectionModel> sections;
|
||||
|
||||
public MultiPartArticleModel() {
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getTitle() {
|
||||
if (title == null) {
|
||||
init();
|
||||
}
|
||||
|
||||
contentItemModel.init();
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getSummary() {
|
||||
if (summary == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
contentItemModel.init();
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public List<String> getSectionTitles() {
|
||||
if (sectionTitles == null) {
|
||||
init();
|
||||
}
|
||||
|
||||
contentItemModel.init();
|
||||
|
||||
return Collections.unmodifiableList(sectionTitles);
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getCurrentSectionTitle() {
|
||||
if (currentSectionTitle == null) {
|
||||
init();
|
||||
}
|
||||
|
||||
contentItemModel.init();
|
||||
|
||||
return currentSectionTitle;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getCurrentSectionText() {
|
||||
if (currentSectionText == null) {
|
||||
init();
|
||||
}
|
||||
|
||||
contentItemModel.init();
|
||||
|
||||
return currentSectionText;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public List<MultiPartArticleSectionModel> getSections() {
|
||||
if (sections == null) {
|
||||
init();
|
||||
}
|
||||
|
||||
contentItemModel.init();
|
||||
|
||||
return Collections.unmodifiableList(sections);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected void init() {
|
||||
final ContentItem contentItem = contentItemModel
|
||||
.retrieveContentItem()
|
||||
.orElse(null);
|
||||
public void init(final ContentItem contentItem) {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (contentItem instanceof MultiPartArticle) {
|
||||
final MultiPartArticle mpa = (MultiPartArticle) contentItem;
|
||||
|
||||
|
|
@ -165,26 +160,20 @@ public class MultiPartArticleModel {
|
|||
.ofNullable(mpa.getSections().get(currentSection).getTitle())
|
||||
.map(globalizationHelper::getValueFromLocalizedString)
|
||||
.orElse("");
|
||||
|
||||
|
||||
currentSectionText = Optional
|
||||
.ofNullable(mpa.getSections().get(currentSection).getText())
|
||||
.map(globalizationHelper::getValueFromLocalizedString)
|
||||
.orElse("");
|
||||
|
||||
|
||||
sections = mpa
|
||||
.getSections()
|
||||
.stream()
|
||||
.map(this::buildSectionModel)
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
throw new WebApplicationException(
|
||||
"Current content item is not an MultiPartArticle",
|
||||
Response
|
||||
.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Current content item is not an MultiPartArticle.")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private int readCurrentSection() {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import org.libreccm.l10n.GlobalizationHelper;
|
|||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contenttypes.News;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
|
|
@ -32,8 +31,6 @@ import javax.enterprise.context.RequestScoped;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.transaction.Transactional;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -41,79 +38,79 @@ import javax.ws.rs.core.Response;
|
|||
*/
|
||||
@RequestScoped
|
||||
@Named("CmsPagesNewsModel")
|
||||
public class NewsModel {
|
||||
public class NewsModel implements ProcessesContentItem {
|
||||
|
||||
@Inject
|
||||
private ContentItemModel contentItemModel;
|
||||
|
||||
@Inject
|
||||
private GlobalizationHelper globalizationHelper;
|
||||
|
||||
|
||||
private boolean initialized;
|
||||
|
||||
private final DateTimeFormatter isoDateTimeFormatter;
|
||||
|
||||
|
||||
private String title;
|
||||
|
||||
|
||||
private String description;
|
||||
|
||||
|
||||
private String text;
|
||||
|
||||
|
||||
private String releaseDateTime;
|
||||
|
||||
|
||||
private boolean homepage;
|
||||
|
||||
|
||||
public NewsModel() {
|
||||
initialized = false;
|
||||
isoDateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME
|
||||
.withZone(ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getTitle() {
|
||||
if (title == null) {
|
||||
init();
|
||||
}
|
||||
|
||||
contentItemModel.init();
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getDescription() {
|
||||
if (description == null) {
|
||||
init();
|
||||
}
|
||||
|
||||
contentItemModel.init();
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getText() {
|
||||
if (text == null) {
|
||||
init();
|
||||
}
|
||||
contentItemModel.init();
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getReleaseDateTime() {
|
||||
if (releaseDateTime == null) {
|
||||
init();
|
||||
}
|
||||
|
||||
contentItemModel.init();
|
||||
|
||||
return releaseDateTime;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public boolean getHomepage() {
|
||||
return homepage;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected void init() {
|
||||
final ContentItem contentItem = contentItemModel
|
||||
.retrieveContentItem()
|
||||
.orElse(null);
|
||||
public boolean getHomepage() {
|
||||
contentItemModel.init();
|
||||
|
||||
return homepage;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public void init(final ContentItem contentItem) {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (contentItem instanceof News) {
|
||||
final News news = (News) contentItem;
|
||||
|
||||
final News news = (News) contentItem;
|
||||
|
||||
title = Optional
|
||||
.ofNullable(news.getTitle())
|
||||
.map(globalizationHelper::getValueFromLocalizedString)
|
||||
|
|
@ -132,15 +129,9 @@ public class NewsModel {
|
|||
.map(isoDateTimeFormatter::format)
|
||||
.orElse("");
|
||||
homepage = news.isHomepage();
|
||||
} else {
|
||||
throw new WebApplicationException(
|
||||
"Current content item is not a news item.",
|
||||
Response
|
||||
.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Current content item is not a new item.")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.hibernate.LazyInitializationException;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
* Models that provide data for the current content item (either the index item
|
||||
* of a category or a selected content item) SHOULD implement this interface.
|
||||
*
|
||||
* This {@link ContentItemModel} collects all instances of classes implementing
|
||||
* this interface and calls their implemententation of the
|
||||
* {@link #init(org.librecms.contentsection.ContentItem)} method.
|
||||
*
|
||||
* For an example of an implementation please look at
|
||||
* {@link ContentItemTypeModel}, {@link ArticleModel} or
|
||||
* at {@link MultiPartArticleModel} for a more complex model.
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public interface ProcessesContentItem {
|
||||
|
||||
/**
|
||||
* Initalizes a model providing the data of a content item for MVC
|
||||
* templates.
|
||||
*
|
||||
* If the implementing model only provides data for specific sub classes of
|
||||
* {@link ContentItem} the implementation MUST check the correct type using
|
||||
* the {@code instanceof} operator. If the item is not a the correct type a
|
||||
* implementation MUST gracefully ignore the item.
|
||||
*
|
||||
* To avoid a {@link LazyInitializationException} implementations SHOULD be
|
||||
* annotated with {@link Transactional} and the
|
||||
* {@link Transactional.TxType#REQUIRED}.
|
||||
*
|
||||
* @param item The item.
|
||||
*/
|
||||
void init(ContentItem item);
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue