001/* 002 * Copyright 2019 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.odf.catalog; 017 018import java.util.Map; 019import java.util.Optional; 020import java.util.stream.Stream; 021 022import org.apache.commons.lang3.StringUtils; 023 024import org.ametys.cms.contenttype.ContentAttributeDefinition; 025import org.ametys.cms.data.ContentValue; 026import org.ametys.cms.repository.Content; 027import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 028import org.ametys.plugins.repository.data.holder.group.ModifiableModelAwareComposite; 029import org.ametys.plugins.repository.data.holder.group.ModifiableModelAwareRepeater; 030import org.ametys.plugins.repository.data.holder.group.ModifiableModelAwareRepeaterEntry; 031import org.ametys.plugins.repository.model.CompositeDefinition; 032import org.ametys.plugins.repository.model.RepeaterDefinition; 033import org.ametys.runtime.model.ModelItem; 034import org.ametys.runtime.plugin.component.AbstractLogEnabled; 035 036/** 037 * The abstract class to copy content attribute of program item type. 038 */ 039public abstract class AbstractProgramItemAttributeCopyUpdater extends AbstractLogEnabled implements CopyCatalogUpdater 040{ 041 /** 042 * Update the program item attribute with the value of the new catalog. 043 * @param dataHolder The data holder 044 * @param definitionPath The definition path 045 * @param copiedContents The copied contents for the referenced attribute 046 */ 047 protected void _updateContentAttribute(ModifiableModelAwareDataHolder dataHolder, String definitionPath, Map<Content, Content> copiedContents) 048 { 049 String[] pathSegments = StringUtils.split(definitionPath, ModelItem.ITEM_PATH_SEPARATOR); 050 String attributeName = pathSegments[0]; 051 ModelItem definition = dataHolder.getDefinition(attributeName); 052 if (pathSegments.length == 1 && definition instanceof ContentAttributeDefinition) 053 { 054 if (((ContentAttributeDefinition) definition).isMultiple()) 055 { 056 _updateMultipleContentAttribute(dataHolder, attributeName, copiedContents); 057 } 058 else 059 { 060 _updateSingleContentAttribute(dataHolder, attributeName, copiedContents); 061 } 062 } 063 else if (definition instanceof RepeaterDefinition) 064 { 065 ModifiableModelAwareRepeater repeater = dataHolder.getRepeater(attributeName); 066 if (repeater != null) 067 { 068 String childDefinitionPath = StringUtils.join(pathSegments, ModelItem.ITEM_PATH_SEPARATOR, 1, pathSegments.length); 069 for (ModifiableModelAwareRepeaterEntry entry : repeater.getEntries()) 070 { 071 _updateContentAttribute(entry, childDefinitionPath, copiedContents); 072 } 073 } 074 } 075 else if (definition instanceof CompositeDefinition) 076 { 077 ModifiableModelAwareComposite composite = dataHolder.getComposite(attributeName); 078 if (composite != null) 079 { 080 String childDefinitionPath = StringUtils.join(pathSegments, ModelItem.ITEM_PATH_SEPARATOR, 1, pathSegments.length); 081 _updateContentAttribute(composite, childDefinitionPath, copiedContents); 082 } 083 } 084 else 085 { 086 // This method shouldn't be called with anything else than a final content attribute 087 throw new IllegalArgumentException("The path '" + definitionPath + "' on data holder '" + definition.getPath() + "' is not a content attribute on content type '" + definition.getModel().getId() + "'."); 088 } 089 } 090 091 /** 092 * Update the single attribute with the content value. 093 * @param dataHolder The data holder 094 * @param attributeName The attribute name 095 * @param copiedContents The copied contents for the referenced attribute 096 */ 097 protected void _updateSingleContentAttribute(ModifiableModelAwareDataHolder dataHolder, String attributeName, Map<Content, Content> copiedContents) 098 { 099 Content newContent = Optional.of(dataHolder) 100 // Get the attribute value 101 .map(dh -> dh.<ContentValue>getValue(attributeName)) 102 // Get the content 103 .flatMap(ContentValue::getContentIfExists) 104 // Keep himself if not found in the copied contents map 105 .map(content -> copiedContents.getOrDefault(content, content)) 106 // Get the retrieved value or null 107 .orElse(null); 108 109 // Set the attribute with the new content 110 // If null, the attribute value will be empty 111 dataHolder.setValue(attributeName, newContent); 112 } 113 114 /** 115 * Update the multiple attribute with the program item value. 116 * @param dataHolder The data holder 117 * @param attributeName The attribute name 118 * @param copiedContents The copied contents for the referenced attribute 119 */ 120 protected void _updateMultipleContentAttribute(ModifiableModelAwareDataHolder dataHolder, String attributeName, Map<Content, Content> copiedContents) 121 { 122 Content[] newContents = Optional.of(dataHolder) 123 // Get the attribute values 124 .map(dh -> dh.<ContentValue[]>getValue(attributeName)) 125 // Build a stream from the ContentValue array 126 .map(Stream::of) 127 // Or build an empty stream if there is no values 128 .orElseGet(Stream::empty) 129 // For each element, get the content 130 .map(ContentValue::getContentIfExists) 131 .flatMap(Optional::stream) 132 // Keep himself if not found in the copied contents map 133 .map(content -> copiedContents.getOrDefault(content, content)) 134 // Collect into an array 135 .toArray(Content[]::new); 136 137 // Set the attribute with the new contents list 138 dataHolder.setValue(attributeName, newContents); 139 } 140}