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}