Optimizations for the models processing content items.

pull/20/head
Jens Pelzetter 2022-01-29 13:16:39 +01:00
parent 65d53e9992
commit 661c70073f
8 changed files with 497 additions and 225 deletions

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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() {

View File

@ -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;
}
}

View File

@ -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);
}