diff --git a/ccm-cms-default-theme/src/main/resources/themes/librecms/templates/index-page.html.ftl b/ccm-cms-default-theme/src/main/resources/themes/librecms/templates/index-page.html.ftl
index 1a68ad991..17edb4f29 100644
--- a/ccm-cms-default-theme/src/main/resources/themes/librecms/templates/index-page.html.ftl
+++ b/ccm-cms-default-theme/src/main/resources/themes/librecms/templates/index-page.html.ftl
@@ -4,21 +4,33 @@
-
- LibreCMS
-
-
- No index item has been defined.
-
-
- Find out more
-
+ <#if CmsPagesCategorizedItemModel.itemAvailable>
+
+ ${CmsPagesCategorizedItemModel.title}
+
+
+ ${CmsPagesCategorizedItemModel.description}
+
+
+ Find out more
+
+ <#else>
+
+ LibreCMS
+
+
+ No index item has been defined.
+
+
+ Find out more
+
+ #if>
- <#if CmsPagesCategorizedItemModel.contentItem??>
+ <#if CmsPagesCategorizedItemModel.itemAvailable>
Category has an index item
<#else>
Category has no index item
@@ -34,6 +46,39 @@
view
${view!""}
+
+
From ArticleModel
+
+ - Title
+ - ${CmsPagesArticleModel.title}
+ - Description
+ - ${CmsPagesArticleModel.description}
+ - Text
+ - ${CmsPagesArticleModel.text}
+
+
+
Item List
+
Item List size: ${CmsPagesItemListModel.listSize}
+
+ <#list CmsPagesItemListModel.items as item>
+ -
+
+ - UUID
+ - ${item.uuid}
+ - displayName
+ - ${item.displayName}
+ - Name
+ - ${item.name}
+ - Title
+ - ${item.title}
+ - description
+ - ${item.description}
+ - Type
+ - ${item.type}
+
+
+ #list>
+
@main.librecms>
\ No newline at end of file
diff --git a/ccm-cms/src/main/java/org/librecms/pages/models/ArticleModel.java b/ccm-cms/src/main/java/org/librecms/pages/models/ArticleModel.java
index 1c784db9e..a11d3a214 100644
--- a/ccm-cms/src/main/java/org/librecms/pages/models/ArticleModel.java
+++ b/ccm-cms/src/main/java/org/librecms/pages/models/ArticleModel.java
@@ -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;
}
-
+
}
diff --git a/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemModel.java b/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemModel.java
index a6a8d8ff4..09037d248 100644
--- a/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemModel.java
+++ b/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemModel.java
@@ -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 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;
+ /**
+ * 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 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 getAttachments() {
-// throw new UnsupportedOperationException("Not implemented yet.");
-// }
-// private Optional 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 getOrRetrieveContentItem() {
- if (contentItem == null) {
- contentItem = retrieveContentItem().map(this::buildModelData);
+ public void init() {
+ if (contentItem != null) {
+ return;
+ }
+
+ final Optional item = retrieveContentItem();
+ contentItem = item.map(this::buildModelData);
+
+ final Iterator 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 not {@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 retrieveContentItem() {
+ private Optional retrieveContentItem() {
final Optional 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;
diff --git a/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemTypeModel.java b/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemTypeModel.java
index 81b4d10b9..e17c42f2e 100644
--- a/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemTypeModel.java
+++ b/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemTypeModel.java
@@ -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 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 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)
diff --git a/ccm-cms/src/main/java/org/librecms/pages/models/EventModel.java b/ccm-cms/src/main/java/org/librecms/pages/models/EventModel.java
index 3c34c6b03..3e9562130 100644
--- a/ccm-cms/src/main/java/org/librecms/pages/models/EventModel.java
+++ b/ccm-cms/src/main/java/org/librecms/pages/models/EventModel.java
@@ -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;
}
}
diff --git a/ccm-cms/src/main/java/org/librecms/pages/models/MultiPartArticleModel.java b/ccm-cms/src/main/java/org/librecms/pages/models/MultiPartArticleModel.java
index 2ca5e77ec..34d426507 100644
--- a/ccm-cms/src/main/java/org/librecms/pages/models/MultiPartArticleModel.java
+++ b/ccm-cms/src/main/java/org/librecms/pages/models/MultiPartArticleModel.java
@@ -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 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 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 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() {
diff --git a/ccm-cms/src/main/java/org/librecms/pages/models/NewsModel.java b/ccm-cms/src/main/java/org/librecms/pages/models/NewsModel.java
index f88c421bd..426a9aef7 100644
--- a/ccm-cms/src/main/java/org/librecms/pages/models/NewsModel.java
+++ b/ccm-cms/src/main/java/org/librecms/pages/models/NewsModel.java
@@ -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;
}
}
diff --git a/ccm-cms/src/main/java/org/librecms/pages/models/ProcessesContentItem.java b/ccm-cms/src/main/java/org/librecms/pages/models/ProcessesContentItem.java
new file mode 100644
index 000000000..9d3714e29
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/pages/models/ProcessesContentItem.java
@@ -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 Jens Pelzetter
+ */
+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);
+
+}