001/*
002 *  Copyright 2010 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.plugins.calendar.enumerators;
017
018import java.util.Collection;
019import java.util.HashMap;
020import java.util.HashSet;
021import java.util.Map;
022import java.util.Set;
023
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.commons.collections.CollectionUtils;
027import org.apache.commons.collections.Predicate;
028import org.apache.commons.lang.StringUtils;
029
030import org.ametys.cms.contenttype.ContentType;
031import org.ametys.cms.contenttype.ContentTypeEnumerator;
032import org.ametys.runtime.i18n.I18nizableText;
033import org.ametys.runtime.model.ElementDefinition;
034import org.ametys.runtime.model.ModelItem;
035
036/**
037 * Enumerator on {@link ContentType} for the Agenda service.
038 * Restrict content types to those which have all the attributes referenced by the <code>_metadataNames</code> list.
039 */
040public class CalendarContentTypesEnumerator extends ContentTypeEnumerator
041{
042    /** Map of mandatory attributes names and their type id. */
043    protected Map<String, Set<String>> _mandatoryAttributes;
044    
045    @Override
046    public void configure(Configuration configuration) throws ConfigurationException
047    {
048        super.configure(configuration);
049        
050        Configuration mandatoryAttributesConf = configuration.getChild("enumeration").getChild("custom-enumerator").getChild("mandatory-metadata", false);
051        if (mandatoryAttributesConf == null)
052        {
053            _mandatoryAttributes = null;
054        }
055        else
056        {
057            _mandatoryAttributes = new HashMap<>();
058            
059            Configuration[] metadataRefConfs = mandatoryAttributesConf.getChildren("metadata-ref");
060            for (Configuration metadataRefConf : metadataRefConfs)
061            {
062                String name = metadataRefConf.getValue(null);
063                
064                String[] types = StringUtils.split(metadataRefConf.getAttribute("type", "string"), ',');
065                
066                Set<String> attributeTypes = new HashSet<>(types.length);
067                for (String type : types)
068                {
069                    attributeTypes.add(type.trim().toUpperCase());
070                }
071                
072                _mandatoryAttributes.put(name, attributeTypes);
073            }
074            _mandatoryAttributes.remove(null);
075        }
076    }
077    
078    @Override
079    public Map<String, I18nizableText> getTypedEntries() throws Exception
080    {
081        Map<String, I18nizableText> entries = new HashMap<>();
082        Set<ContentType> contentTypes = getMatchingContentTypes();
083        
084        for (ContentType contentType : contentTypes)
085        {
086            // Build a Set containing the rejected mandatory attributes.
087            // This means either the attribute does not exist for this content type, or the attribute type is not matching the expectations.
088            Collection<String> rejectedAttributes = CollectionUtils.selectRejected(_mandatoryAttributes.keySet(), new MandatoryAttributePredicate(contentType));
089
090            if (rejectedAttributes.isEmpty())
091            {
092                entries.put(contentType.getId(), contentType.getLabel());
093            }
094        }
095
096        // All contents
097        _handleAllOptionEntry(entries);
098        
099        return entries;
100    }
101    
102    /**
103     * Predicate that test if the requested attribute is in the content type and if its type is correct.
104     */
105    public class MandatoryAttributePredicate implements Predicate
106    {
107        private ContentType _contentType;
108        
109        /**
110         * Build a {@code MandatoryAttributePredicate}
111         * @param contentType The ContentType to check against.
112         */
113        protected MandatoryAttributePredicate(ContentType contentType)
114        {
115            _contentType = contentType;
116        }
117        
118        @Override
119        public boolean evaluate(Object object)
120        {
121            String attributeName = (String) object;
122            return _isDefined(attributeName) && _isTypeCorrect(attributeName); 
123        }
124        
125        private boolean _isDefined(String attributeName)
126        {
127            return _contentType.hasModelItem(attributeName);
128        }
129        
130        private boolean _isTypeCorrect(String attributeName)
131        {
132            ModelItem modelItem = _contentType.getModelItem(attributeName);
133            if (modelItem instanceof ElementDefinition)
134            {
135                String modelItemType = ((ElementDefinition) modelItem).getType().getId().toUpperCase();
136                return _mandatoryAttributes.get(attributeName).contains(modelItemType);
137            }
138            else
139            {
140                return false;
141            }
142        }
143    }
144}