001/*
002 *  Copyright 2024 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.Optional;
019
020import org.apache.avalon.framework.configuration.Configuration;
021import org.apache.avalon.framework.configuration.ConfigurationException;
022
023import org.ametys.cms.data.ametysobject.ModelAwareDataAwareAmetysObject;
024import org.ametys.runtime.i18n.I18nizableText;
025import org.ametys.runtime.model.ElementDefinition;
026import org.ametys.runtime.model.ItemParserHelper;
027import org.ametys.runtime.model.ItemParserHelper.ConfigurationAndPluginName;
028import org.ametys.runtime.model.Model;
029
030/**
031 * Abstract implementation for a property referencing {@link ElementDefinition}s
032 * @param <T> Type of the property values
033 * @param <C> Type of criterion
034 * @param <X> Type of ametys object supported by this property
035 */
036public abstract class AbstractElementsReferencingProperty<T, C, X extends ModelAwareDataAwareAmetysObject> extends AbstractIndexableStaticProperty<T, C, X> implements ReferencingProperty<T, X>
037{
038    @Override
039    public void configure(Configuration configuration) throws ConfigurationException
040    {
041        super.configure(configuration);
042        configureReferences(configuration);
043    }
044    
045    @Override
046    protected I18nizableText _parseLabel(Configuration configuration) throws ConfigurationException
047    {
048        // Do not use name as default value, to use the referenced element's one if the the concerned text is not filled
049        return ItemParserHelper.parseI18nizableText(new ConfigurationAndPluginName(configuration, getPluginName()), "label", (I18nizableText) null);
050    }
051    
052    @Override
053    protected I18nizableText _parseDescription(Configuration configuration) throws ConfigurationException
054    {
055        // Do not use empty string as default value, to use the referenced element's one if the the concerned text is not filled
056        return ItemParserHelper.parseI18nizableText(new ConfigurationAndPluginName(configuration, getPluginName()), "description", (I18nizableText) null);
057    }
058    
059    /**
060     * Configures the references
061     * @param configuration the property configuration
062     * @throws ConfigurationException if an error occurred
063     */
064    protected abstract void configureReferences(Configuration configuration) throws ConfigurationException;
065    
066    @Override
067    public void init(String availableTypesRole) throws Exception
068    {
069        Model model = getModel();
070        
071        for (String reference : getReferences())
072        {
073            if (!model.hasModelItem(reference) || !(model.getModelItem(reference) instanceof ElementDefinition))
074            {
075                throw new ConfigurationException("'" + reference + "' is invalid for property '" + getName() + "' in model '" + model.getId() + "'. The referenced item has not been found or is a group.");
076            }
077        }
078
079        super.init(availableTypesRole);
080    }
081    
082    /**
083     * Retrieves the definition of the given referenced element
084     * @param reference the reference
085     * @return the referenced element's definition
086     */
087    @SuppressWarnings("unchecked")
088    protected ElementDefinition<T> _getReferenceDefinition(String reference)
089    {
090        return (ElementDefinition<T>) getModel().getModelItem(reference);
091    }
092    
093    @Override
094    public String getName()
095    {
096        return Optional.ofNullable(super.getName())
097                       // If no name has been configured, use the first referenced element's one
098                       .orElseGet(() -> this._getFirstReferenceDefinition().getName());
099    }
100    
101    @Override
102    public I18nizableText getLabel()
103    {
104        return Optional.ofNullable(super.getLabel())
105                       // If no label has been configured, use the first referenced element's one
106                       .orElseGet(() -> this._getFirstReferenceDefinition().getLabel());
107    }
108    
109    @Override
110    public I18nizableText getDescription()
111    {
112        return Optional.ofNullable(super.getDescription())
113                       // If no description has been configured, use the first referenced element's one
114                       .orElseGet(() -> this._getFirstReferenceDefinition().getDescription());
115    }
116    
117    private String _getFirstReference()
118    {
119        return getReferences().get(0);
120    }
121    
122    private ElementDefinition<T> _getFirstReferenceDefinition()
123    {
124        return _getReferenceDefinition(_getFirstReference());
125    }
126}