001/* 002 * Copyright 2022 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.cms.content.properties; 017 018import java.util.Collection; 019import java.util.Collections; 020import java.util.List; 021 022import org.apache.avalon.framework.configuration.ConfigurationException; 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025 026import org.ametys.cms.contenttype.ContentType; 027import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 028import org.ametys.cms.contenttype.ContentTypesHelper; 029import org.ametys.cms.data.ContentValue; 030import org.ametys.cms.data.type.ModelItemTypeConstants; 031import org.ametys.cms.model.ContentElementDefinition; 032import org.ametys.cms.model.properties.Property; 033import org.ametys.runtime.model.ModelItem; 034 035/** 036 * {@link Property} referencing multiple content values in one property. 037 */ 038public class MultiContentValuesProperty extends AbstractMultiTypedValuesProperty<ContentValue, ContentValue> implements ContentElementDefinition 039{ 040 private ContentTypeExtensionPoint _contentTypeExtensionPoint; 041 private ContentTypesHelper _contentTypesHelper; 042 private String _contentTypeId; 043 044 @Override 045 protected String getTypeId() 046 { 047 return ModelItemTypeConstants.CONTENT_ELEMENT_TYPE_ID; 048 } 049 050 @Override 051 public void service(ServiceManager manager) throws ServiceException 052 { 053 super.service(manager); 054 _contentTypeExtensionPoint = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 055 _contentTypesHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 056 } 057 058 @Override 059 public void init(String availableTypesRole) throws Exception 060 { 061 super.init(availableTypesRole); 062 063 // Get the common ancestors content types 064 List<String> contentTypes = _references.stream() 065 .map(this::_getReferenceDefinition) 066 .map(ContentElementDefinition.class::cast) 067 .map(ContentElementDefinition::getContentTypeId) 068 .distinct() 069 .toList(); 070 071 // Set the content type id to this common content type (containing a title) 072 _contentTypeId = _contentTypesHelper.getCommonAncestors(contentTypes) 073 .stream() 074 .map(_contentTypeExtensionPoint::getExtension) 075 .filter(ct -> ct.hasModelItem("title")) 076 .map(ContentType::getId) 077 .findFirst() 078 // There is no common ancestor with title, throw an exception 079 .orElseThrow(() -> new ConfigurationException("The references of property '" + getName() + "' in model '" + getModel().getId() + "' do not have a common ancestor content type.")); 080 } 081 082 public void setContentTypeId(String contentTypeId) 083 { 084 throw new UnsupportedOperationException("Setting the content type is not supported on " + getClass() + ", it is defined by the property itself."); 085 } 086 087 public String getContentTypeId() 088 { 089 return _contentTypeId; 090 } 091 092 public Collection<? extends ModelItem> getModelItems() 093 { 094 if (_contentTypeExtensionPoint.hasExtension(getContentTypeId())) 095 { 096 ContentType contentType = _contentTypeExtensionPoint.getExtension(getContentTypeId()); 097 return contentType.getModelItems(); 098 } 099 100 return Collections.singleton(_contentTypesHelper.getTitleAttributeDefinition()); 101 } 102}