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