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.odf.program.properties;
017
018import java.lang.reflect.Array;
019import java.util.Arrays;
020import java.util.List;
021
022import org.apache.avalon.framework.configuration.Configuration;
023import org.apache.avalon.framework.configuration.ConfigurationException;
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.commons.lang3.StringUtils;
027
028import org.ametys.cms.contenttype.ContentType;
029import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
030import org.ametys.cms.data.type.ModelItemTypeExtensionPoint;
031import org.ametys.cms.data.type.indexing.IndexableElementType;
032import org.ametys.cms.model.CMSDataContext;
033import org.ametys.cms.model.properties.AbstractProperty;
034import org.ametys.cms.model.properties.Property;
035import org.ametys.cms.repository.Content;
036import org.ametys.cms.search.model.CriterionDefinitionAwareElementDefinition;
037import org.ametys.cms.search.model.CriterionDefinitionHelper;
038import org.ametys.cms.search.model.IndexationAwareElementDefinition;
039import org.ametys.cms.search.model.IndexationAwareElementDefinitionHelper;
040import org.ametys.odf.ODFHelper;
041import org.ametys.odf.program.Program;
042import org.ametys.odf.program.ProgramFactory;
043import org.ametys.odf.program.SubProgram;
044import org.ametys.runtime.model.ModelItem;
045import org.ametys.runtime.model.type.ElementType;
046
047/**
048 * {@link Property} for attribute name of the parent {@link Program} of a {@link SubProgram}
049 */
050public class SubProgramParentProgramProperty extends AbstractProperty<Object, Content> implements CriterionDefinitionAwareElementDefinition<Object>, IndexationAwareElementDefinition<Object, Content>
051{
052    /** The ODF Helper */
053    protected ODFHelper _odfHelper;
054    
055    /** The Content Type Extension Point */
056    protected ContentTypeExtensionPoint _ctypeEP;
057    
058    /** The Content Attribute Type Extension Point */
059    protected ModelItemTypeExtensionPoint _contentAttributeTypeEP;
060    
061    /** The criterion definition helper */
062    protected CriterionDefinitionHelper _criterionDefinitionHelper;
063    
064    /** The indexation aware element definition helper */
065    protected IndexationAwareElementDefinitionHelper _indexationAwareElementDefinitionHelper;
066    
067    /** The program attribute name to index for subProgram */
068    protected String _programAttributeName;
069    
070    /** The program attribute type to index for subProgram */
071    protected String _programAttributeType;
072    
073    @Override
074    public void service(ServiceManager manager) throws ServiceException
075    {
076        super.service(manager);
077        _contentAttributeTypeEP = (ModelItemTypeExtensionPoint) manager.lookup(ModelItemTypeExtensionPoint.ROLE_CONTENT_ATTRIBUTE);
078        _ctypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE);
079        _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE);
080        _criterionDefinitionHelper = (CriterionDefinitionHelper) manager.lookup(CriterionDefinitionHelper.ROLE);
081        _indexationAwareElementDefinitionHelper = (IndexationAwareElementDefinitionHelper) manager.lookup(IndexationAwareElementDefinitionHelper.ROLE);
082    }
083    
084    @Override
085    public void configure(Configuration configuration) throws ConfigurationException
086    {
087        super.configure(configuration);
088        
089        _programAttributeType = configuration.getAttribute("type");
090        if (StringUtils.isBlank(_programAttributeType))
091        {
092            throw new ConfigurationException("Attribute 'type' is mandatory for " + SubProgramParentProgramProperty.class.getName());
093        }
094        
095        _programAttributeName = configuration.getChild("program-attribute-name").getValue();
096        if (StringUtils.isBlank(_programAttributeName))
097        {
098            throw new ConfigurationException("Child 'program-attribute-name' is mandatory for " + SubProgramParentProgramProperty.class.getName());
099        }
100    }
101    
102    @Override
103    public Object getValue(Content content)
104    {
105        if (content instanceof SubProgram subProgram)
106        {
107            List<Object> values = _odfHelper.getParentPrograms(subProgram)
108                .stream()
109                .map(this::_getValues)
110                .flatMap(List::stream)
111                .toList();
112            
113            ContentType programCType = _ctypeEP.getExtension(ProgramFactory.PROGRAM_CONTENT_TYPE);
114            ModelItem modelItem = programCType.getModelItem(_programAttributeName);
115            ElementType attributeType = (ElementType) _contentAttributeTypeEP.getExtension(modelItem.getType().getId());
116            
117            return !values.isEmpty() ? values.toArray((Object[]) Array.newInstance(attributeType.getManagedClass(), values.size())) : null;
118        }
119        
120        return null;
121    }
122    
123    private List<Object> _getValues(Program program)
124    {
125        if (program.isMultiple(_programAttributeName))
126        {
127            Object[] values = program.getValue(_programAttributeName);
128            
129            return values != null ? Arrays.asList(values) : List.of();
130        }
131        else
132        {
133            Object value = program.getValue(_programAttributeName);
134            return value != null ? List.of(value) : List.of();
135        }
136    }
137    
138    @Override
139    public boolean isMultiple()
140    {
141        return true;
142    }
143    
144    @Override
145    protected String getTypeId()
146    {
147        return _programAttributeType;
148    }
149    
150    public IndexableElementType getDefaultCriterionType()
151    {
152        CMSDataContext context = CMSDataContext.newInstance()
153                                               .withModelItem(this);
154        
155        String typeId = getType().getDefaultCriterionTypeId(context);
156        return _criterionDefinitionHelper.getCriterionDefinitionType(typeId);
157    }
158    
159    public String getSolrSortFieldName()
160    {
161        return _indexationAwareElementDefinitionHelper.getDefaultSolrSortFieldName(this);
162    }
163}