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.avalon.framework.service.ServiceException; 023import org.apache.avalon.framework.service.ServiceManager; 024import org.apache.avalon.framework.service.Serviceable; 025import org.apache.commons.lang3.StringUtils; 026 027import org.ametys.cms.contenttype.ContentAttributeDefinition; 028import org.ametys.cms.data.ContentValue; 029import org.ametys.plugins.repository.AmetysObjectResolver; 030import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 031import org.ametys.plugins.repository.data.holder.group.impl.ModifiableModelAwareComposite; 032import org.ametys.plugins.repository.data.holder.group.impl.ModifiableModelAwareRepeater; 033import org.ametys.plugins.repository.data.holder.group.impl.ModifiableModelAwareRepeaterEntry; 034import org.ametys.plugins.repository.model.CompositeDefinition; 035import org.ametys.plugins.repository.model.RepeaterDefinition; 036import org.ametys.runtime.model.ModelItem; 037import org.ametys.runtime.plugin.component.AbstractLogEnabled; 038 039/** 040 * The abstract class to copy content attribute of program item type. 041 */ 042public abstract class AbstractProgramItemAttributeCopyUpdater extends AbstractLogEnabled implements CopyCatalogUpdater, Serviceable 043{ 044 /** The Ametys object resolver */ 045 protected AmetysObjectResolver _ametysResolver; 046 047 @Override 048 public void service(ServiceManager manager) throws ServiceException 049 { 050 _ametysResolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 051 } 052 053 /** 054 * Update the program item attribute with the value of the new catalog. 055 * @param dataHolder The data holder 056 * @param definitionPath The definition path 057 * @param copiedContents The copied contents for the referenced attribute 058 */ 059 protected void _updateContentAttribute(ModifiableModelAwareDataHolder dataHolder, String definitionPath, Map<String, String> copiedContents) 060 { 061 String[] pathSegments = StringUtils.split(definitionPath, ModelItem.ITEM_PATH_SEPARATOR); 062 String attributeName = pathSegments[0]; 063 ModelItem definition = dataHolder.getDefinition(attributeName); 064 if (pathSegments.length == 1 && definition instanceof ContentAttributeDefinition) 065 { 066 if (((ContentAttributeDefinition) definition).isMultiple()) 067 { 068 _updateMultipleContentAttribute(dataHolder, attributeName, copiedContents); 069 } 070 else 071 { 072 _updateSingleContentAttribute(dataHolder, attributeName, copiedContents); 073 } 074 } 075 else if (definition instanceof RepeaterDefinition) 076 { 077 ModifiableModelAwareRepeater repeater = dataHolder.getRepeater(attributeName); 078 if (repeater != null) 079 { 080 String childDefinitionPath = StringUtils.join(pathSegments, ModelItem.ITEM_PATH_SEPARATOR, 1, pathSegments.length); 081 for (ModifiableModelAwareRepeaterEntry entry : repeater.getEntries()) 082 { 083 _updateContentAttribute(entry, childDefinitionPath, copiedContents); 084 } 085 } 086 } 087 else if (definition instanceof CompositeDefinition) 088 { 089 ModifiableModelAwareComposite composite = dataHolder.getComposite(attributeName); 090 if (composite != null) 091 { 092 String childDefinitionPath = StringUtils.join(pathSegments, ModelItem.ITEM_PATH_SEPARATOR, 1, pathSegments.length); 093 _updateContentAttribute(composite, childDefinitionPath, copiedContents); 094 } 095 } 096 else 097 { 098 // This method shouldn't be called with anything else than a final content attribute 099 throw new IllegalArgumentException("The path '" + definitionPath + "' on data holder '" + definition.getPath() + "' is not a content attribute on content type '" + definition.getModel().getId() + "'."); 100 } 101 } 102 103 /** 104 * Update the single attribute with the content value. 105 * @param dataHolder The data holder 106 * @param attributeName The attribute name 107 * @param copiedContents The copied contents for the referenced attribute 108 */ 109 protected void _updateSingleContentAttribute(ModifiableModelAwareDataHolder dataHolder, String attributeName, Map<String, String> copiedContents) 110 { 111 String contentId = Optional.of(dataHolder) 112 // Get the attribute value 113 .map(dh -> dh.<ContentValue>getValue(attributeName)) 114 // Get the content id 115 .map(ContentValue::getContentId) 116 // Keep himself if not found in the copied contents map 117 .map(id -> copiedContents.getOrDefault(id, id)) 118 // Get the retrieved value or null 119 .orElse(null); 120 121 // Set the attribute with the new content id 122 // If null, the attribute value will be empty 123 dataHolder.setValue(attributeName, contentId); 124 } 125 126 /** 127 * Update the multiple attribute with the program item value. 128 * @param dataHolder The data holder 129 * @param attributeName The attribute name 130 * @param copiedContents The copied contents for the referenced attribute 131 */ 132 protected void _updateMultipleContentAttribute(ModifiableModelAwareDataHolder dataHolder, String attributeName, Map<String, String> copiedContents) 133 { 134 String[] contentIds = Optional.of(dataHolder) 135 // Get the attribute values 136 .map(dh -> dh.<ContentValue[]>getValue(attributeName)) 137 // Build a stream from the ContentValue array 138 .map(Stream::of) 139 // Or build an empty stream if there is no values 140 .orElseGet(Stream::empty) 141 // For each element, get the content id 142 .map(ContentValue::getContentId) 143 // Keep himself if not found in the copied contents map 144 .map(id -> copiedContents.getOrDefault(id, id)) 145 // Collect into an array 146 .toArray(String[]::new); 147 148 // Set the attribute with the new content ids list 149 dataHolder.setValue(attributeName, contentIds); 150 } 151}