diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ContainerUUIDChanged.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ContainerUUIDChanged.java
index 3c7756d3d4a5..8c1dc84e2a07 100644
--- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ContainerUUIDChanged.java
+++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ContainerUUIDChanged.java
@@ -3,9 +3,22 @@
import com.dotmarketing.portlets.templates.design.bean.ContainerUUID;
/**
- * It is a change do by the end point into a {@link ContainerUUID}
+ * Represents a Container layout change in a dotCMS Template.
+ *
+ *
An instance of a Container in a Template is defined by its ID -- or file path for File
+ * Containers -- and its current instance ID. Such an instance ID allows content authors to add the
+ * same Container more than once in a Template. If one or more Containers of the same type are moved
+ * or deleted from the Template, the instance IDs of the remaining Containers may need to be updated
+ * so that such IDs are sorted sequentially. This class helps keep track of such changes.
+ *
+ * Instance IDs are simple numeric values that are sorted in ascendant order, from top to bottom,
+ * from left to right, and their value starts with 1.
+ *
+ * @author Freddy Rodriguez
+ * @since Apr 23rd, 2018
*/
public class ContainerUUIDChanged {
+
private final ContainerUUID oldContainer;
private final ContainerUUID newContainer;
@@ -14,11 +27,23 @@ public ContainerUUIDChanged(final ContainerUUID oldContainer, final ContainerUUI
this.newContainer = newContainer;
}
- public ContainerUUID getOld() {
+ /**
+ * Returns the Container instance ID information before the Template's layout was changed.
+ *
+ * @return The {@link ContainerUUID} instance before the Template's layout was changed.
+ */
+ public ContainerUUID getPreviousInfo() {
return oldContainer;
}
- public ContainerUUID getNew() {
+ /**
+ * Returns the Container instance ID information after the Template's layout was changed. This
+ * can translate into the instance ID being updated.
+ *
+ * @return The {@link ContainerUUID} instance after the Template's layout was changed.
+ */
+ public ContainerUUID getNewInfo() {
return newContainer;
}
+
}
diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageForm.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageForm.java
index 90236de1017c..17b14dae0577 100644
--- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageForm.java
+++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageForm.java
@@ -1,47 +1,49 @@
package com.dotcms.rest.api.v1.page;
-import java.io.IOException;
-import java.util.*;
-import java.util.stream.Stream;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.dotcms.repackage.javax.validation.constraints.NotNull;
-import com.dotcms.rest.api.Validated;
+import com.dotcms.exception.ExceptionUtil;
import com.dotcms.rest.exception.BadRequestException;
import com.dotmarketing.portlets.templates.design.bean.ContainerUUID;
import com.dotmarketing.portlets.templates.design.bean.TemplateLayout;
import com.dotmarketing.portlets.templates.model.Template;
import com.dotmarketing.util.Logger;
import com.dotmarketing.util.UtilMethods;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.ImmutableList;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.common.collect.ImmutableMap;
-import javax.annotation.Nullable;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
/**
- * {@link PageResource}'s form
+ * Represents the layout of a Template in dotCMS.
+ *
+ * All Containers that make up the structure of a Template -- along with its rows and columns --
+ * are organized and transformed into an instance of this class.
+ *
+ * @author Freddy Rodriguez
+ * @since Nov 22nd, 2017
*/
@JsonDeserialize(builder = PageForm.Builder.class)
class PageForm {
private final String themeId;
private final String title;
- private final String hostId;
+ private final String siteId;
private final TemplateLayout layout;
private final Map changes;
private final Map newlyContainersUUID;
- public PageForm(final String themeId, final String title, final String hostId, final TemplateLayout layout,
- final Map changes, Map newlyContainersUUID) {
+ public PageForm(final String themeId, final String title, final String siteId, final TemplateLayout layout,
+ final Map changes, final Map newlyContainersUUID) {
this.themeId = themeId;
this.title = title;
- this.hostId = hostId;
+ this.siteId = siteId;
this.layout = layout;
this.changes = ImmutableMap. builder().putAll(changes).build();
this.newlyContainersUUID = ImmutableMap.copyOf(newlyContainersUUID);
@@ -66,10 +68,10 @@ public String getTitle() {
/**
*
- * @return Layout's host
+ * @return Layout's site
*/
- public String getHostId() {
- return hostId;
+ public String getSiteId() {
+ return siteId;
}
public boolean isAnonymousLayout() {
@@ -84,7 +86,28 @@ public TemplateLayout getLayout() {
return layout;
}
- public ContainerUUIDChanged getChange (String identifier, String uuid) {
+ /**
+ * Allows you to determine whether the instance ID of a given Container has changed or not based
+ * on the modifications that are being persisted. This makes it easier for the API to be able to
+ * update the necessary instance IDs across the page's Template so that contents are displayed
+ * in the appropriate order.
+ *
+ * For instance, if a Template has three instances of the Default Container -- "1", "2", and
+ * "3" -- and instance "2" is deleted, the change list will be:
+ *
+ * - Old Instance ID = "1" / New Instance ID = "1" -- The value remains.
+ * - Instance ID "2" is NOT present as it is the one that was removed from the Template
+ * .
+ * - Old Instance ID = "3" / New Instance ID = "2" -- Because the second instance was
+ * removed, the third Container now takes the second instance's ID.
+ *
+ *
+ * @param identifier The ID of the Container, or its path in case it's a Container as File.
+ * @param uuid The current instance ID of the Container.
+ *
+ * @return The {@link ContainerUUIDChanged} instance that contains the old and new instance IDs.
+ */
+ public ContainerUUIDChanged getChangeInContainerInstanceIDs(final String identifier, final String uuid) {
ContainerUUIDChanged containerUUIDChanged = this.changes.get(getChangeKey(identifier, uuid));
if (containerUUIDChanged == null) {
@@ -96,14 +119,37 @@ public ContainerUUIDChanged getChange (String identifier, String uuid) {
return containerUUIDChanged;
}
+ /**
+ * Returns the instance ID of a Container that has just been added to the Template. That is, a
+ * Container that didn't exist and was added by this change in particular.
+ *
+ * @param identifier The ID or file path of the recently-added Container
+ *
+ * @return The instance ID of the recently-added Container.
+ */
public String getNewlyContainerUUID (String identifier) {
return this.newlyContainersUUID.get(identifier);
}
+ /**
+ * Generates the key that identifies the potential change in a Container instance ID.
+ *
+ * @param containerUUID The {@link ContainerUUID} object whose information may have changed..
+ *
+ * @return The key that identifies the potential change in a Container instance ID.
+ */
private static String getChangeKey(ContainerUUID containerUUID) {
return getChangeKey(containerUUID.getIdentifier(), containerUUID.getUUID());
}
+ /**
+ * Generates the key that identifies a potential change in a Container's instance ID.
+ *
+ * @param identifier The ID or file path to a given Container.
+ * @param uuid The current instance ID of the Container.
+ *
+ * @return The key that identifies the potential change in a Container instance ID.
+ */
private static String getChangeKey(String identifier, String uuid) {
return String.format("%s - %s", identifier, uuid);
}
@@ -154,6 +200,14 @@ public Builder layout(Map layout) {
return this;
}
+ /**
+ * Transforms the Template's layout as a data Map into an instance of
+ * {@link TemplateLayout}.
+ *
+ * @return An instance of {@link TemplateLayout} that represents the Template's layout.
+ *
+ * @throws BadRequestException If the Template's layout is invalid or missing.
+ */
private TemplateLayout getTemplateLayout() throws BadRequestException {
if (layout == null) {
@@ -164,8 +218,10 @@ private TemplateLayout getTemplateLayout() throws BadRequestException {
this.setContainersUUID();
final String layoutString = MAPPER.writeValueAsString(layout);
return MAPPER.readValue(layoutString, TemplateLayout.class);
- } catch (IOException e) {
- throw new BadRequestException(e, "An error occurred when proccessing the JSON request");
+ } catch (final IOException e) {
+ throw new BadRequestException(e, String.format("An error occurred when processing" +
+ " the layout for Template '%s'", UtilMethods.isSet(title) ? title : "- " +
+ "Anonymous Template -"));
}
}
@@ -190,35 +246,43 @@ private void setContainersUUID() {
getAllContainers().forEach(container -> setChange(maxUUIDByContainer, container));
}
- private void setChange(Map maxUUIDByContainer, Map container) {
+ /**
+ * Loads the data Maps of every Container in the Template's layout, with its previous and
+ * updated instance ID.
+ *
+ * @param maxInstanceIDByContainer Keeps track of the maximum instance ID that has been
+ * assigned to a previously added Container of the same
+ * type. It helps increase the instance ID one by one in
+ * order.
+ * @param container The current Container instance inside the Template.
+ */
+ private void setChange(final Map maxInstanceIDByContainer, final Map container) {
try {
final String containerId = container.get("identifier");
- final long currentUUID = maxUUIDByContainer.get(containerId) != null ?
- maxUUIDByContainer.get(containerId) : 0;
- final long nextUUID = currentUUID + 1;
+ final long currentInstanceID = maxInstanceIDByContainer.get(containerId) != null ?
+ maxInstanceIDByContainer.get(containerId) : 0;
+ final long nextInstanceID = currentInstanceID + 1;
if (container.get("uuid") != null) {
- final ContainerUUID oldContainerUUID = MAPPER.readValue(MAPPER.writeValueAsString(container),
+ final ContainerUUID oldContainerInstanceID = MAPPER.readValue(MAPPER.writeValueAsString(container),
ContainerUUID.class);
- container.put("uuid", String.valueOf(nextUUID));
- final ContainerUUID newContainerUUID = MAPPER.readValue(MAPPER.writeValueAsString(container),
+ container.put("uuid", String.valueOf(nextInstanceID));
+ final ContainerUUID newContainerInstanceID = MAPPER.readValue(MAPPER.writeValueAsString(container),
ContainerUUID.class);
-
- String changeKey = getChangeKey(oldContainerUUID);
- changes.put(changeKey, new ContainerUUIDChanged(oldContainerUUID, newContainerUUID));
+ changes.put(getChangeKey(oldContainerInstanceID), new ContainerUUIDChanged(oldContainerInstanceID, newContainerInstanceID));
} else {
- container.put("uuid", String.valueOf(nextUUID));
- newlyContainersUUID.put(containerId, String.valueOf(nextUUID));
+ container.put("uuid", String.valueOf(nextInstanceID));
+ newlyContainersUUID.put(containerId, String.valueOf(nextInstanceID));
}
- maxUUIDByContainer.put(containerId, nextUUID);
-
- } catch (IOException e) {
- Logger.error(this.getClass(),"Exception on setContainersUUID exception message: " + e.getMessage(), e);
+ maxInstanceIDByContainer.put(containerId, nextInstanceID);
+ } catch (final IOException e) {
+ Logger.error(this.getClass(),String.format("Failed to map changed Container instance IDs in Template " +
+ "'%s': %s", UtilMethods.isSet(title) ? title : "- Anonymous Template -",
+ ExceptionUtil.getErrorMessage(e)), e);
}
}
-
private Stream