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        for (String reference : getReferences())
070        {
071            Model model = getModel();
072            if (!model.hasModelItem(reference) || !(model.getModelItem(reference) instanceof ElementDefinition))
073            {
074                throw new ConfigurationException("'" + reference + "' is invalid for property '" + getName() + "' in model '" + model.getId() + "'. The referenced item has not been found or is a group.");
075            }
076        }
077
078        super.init(availableTypesRole);
079    }
080    
081    /**
082     * Retrieves the definition of the given referenced element
083     * @param reference the reference
084     * @return the referenced element's definition
085     */
086    @SuppressWarnings("unchecked")
087    protected ElementDefinition<T> _getReferenceDefinition(String reference)
088    {
089        return (ElementDefinition<T>) getModel().getModelItem(reference);
090    } 
091    
092    @Override
093    public String getName()
094    {
095        return Optional.ofNullable(super.getName())
096                       // If no name has been configured, use the first referenced element's one
097                       .orElseGet(() -> this._getFirstReferenceDefinition().getName());
098    }
099    
100    @Override
101    public I18nizableText getLabel()
102    {
103        return Optional.ofNullable(super.getLabel())
104                       // If no label has been configured, use the first referenced element's one
105                       .orElseGet(() -> this._getFirstReferenceDefinition().getLabel());
106    }
107    
108    @Override
109    public I18nizableText getDescription()
110    {
111        return Optional.ofNullable(super.getDescription())
112                       // If no description has been configured, use the first referenced element's one
113                       .orElseGet(() -> this._getFirstReferenceDefinition().getDescription());
114    }
115    
116    private String _getFirstReference()
117    {
118        return getReferences().get(0);
119    }
120    
121    private ElementDefinition<T> _getFirstReferenceDefinition()
122    {
123        return _getReferenceDefinition(_getFirstReference());
124    }
125}