001/*
002 *  Copyright 2023 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.model.properties;
017
018import java.util.Collection;
019import java.util.Collections;
020import java.util.Map;
021import java.util.Optional;
022import java.util.Set;
023import java.util.stream.Stream;
024
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.avalon.framework.service.Serviceable;
028import org.apache.cocoon.ProcessingException;
029import org.xml.sax.ContentHandler;
030import org.xml.sax.SAXException;
031
032import org.ametys.cms.contenttype.ContentType;
033import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
034import org.ametys.cms.contenttype.ContentTypesHelper;
035import org.ametys.cms.data.ContentValue;
036import org.ametys.cms.data.ametysobject.ModelAwareDataAwareAmetysObject;
037import org.ametys.cms.data.type.ModelItemTypeConstants;
038import org.ametys.cms.model.ContentElementDefinition;
039import org.ametys.cms.repository.ModifiableContent;
040import org.ametys.core.util.XMLUtils;
041import org.ametys.runtime.model.DefinitionContext;
042import org.ametys.runtime.model.ModelItem;
043
044/**
045 * Abstract class for content property
046 * @param <X> type of ametys object supported by this property
047 */
048public abstract class AbstractContentProperty<X extends ModelAwareDataAwareAmetysObject> extends AbstractProperty<ContentValue, X> implements ContentElementDefinition, Serviceable
049{
050    private ContentTypeExtensionPoint _contentTypeExtensionPoint;
051    private ContentTypesHelper _contentTypesHelper;
052    
053    public void service(ServiceManager manager) throws ServiceException
054    {
055        _contentTypesHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE);
056        _contentTypeExtensionPoint = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE);
057    }
058    
059    @Override
060    protected String _getTypeId()
061    {
062        return ModelItemTypeConstants.CONTENT_ELEMENT_TYPE_ID;
063    }
064    
065    public String getCriterionWidget()
066    {
067        return "edition.select-content";
068    }
069    
070    public void setContentTypeId(String contentTypeId)
071    {
072        throw new UnsupportedOperationException("Setting the content type is not supported on " + getClass() + ", it is defined by the property itself.");
073    }
074    
075    public Collection< ? extends ModelItem> getModelItems()
076    {
077        if (_contentTypeExtensionPoint.hasExtension(getContentTypeId()))
078        {
079            ContentType contentType = _contentTypeExtensionPoint.getExtension(getContentTypeId());
080            return contentType.getModelItems();
081        }
082        else
083        {
084            return Collections.singleton(_contentTypesHelper.getTitleAttributeDefinition());
085        }
086    }
087    
088    @Override
089    protected Map<String, Object> _toJSON(DefinitionContext context) throws ProcessingException
090    {
091        Map<String, Object> result = super._toJSON(context);
092        result.put("contentType", getContentTypeId());
093        return result;
094    }
095    
096    @Override
097    public void toSAX(ContentHandler contentHandler, DefinitionContext context) throws SAXException
098    {
099        super.toSAX(contentHandler, context);
100        XMLUtils.createElementIfNotNull(contentHandler, "contentType", getContentTypeId());
101    }
102    
103    @Override
104    public Object getValue(X dataHolder)
105    {
106        Set<? extends ModifiableContent> contents = _getLinkedContents(dataHolder);
107        
108        return isMultiple()
109                ? _transformToContentValueArray(contents)
110                : Optional.ofNullable(contents)
111                    .map(Set::stream)
112                    .orElseGet(Stream::empty)
113                    .findFirst()
114                    .orElse(null);
115    }
116    
117    /**
118     * Get the linked contents to index.
119     * @param dataHolder The data holder
120     * @return The linked contents
121     */
122    protected abstract Set<? extends ModifiableContent> _getLinkedContents(X dataHolder);
123    
124    private ContentValue[] _transformToContentValueArray(Set<? extends ModifiableContent> contents)
125    {
126        if (contents == null)
127        {
128            return null;
129        }
130        
131        return contents.stream()
132            .map(ContentValue::new)
133            .toArray(ContentValue[]::new);
134    }
135}