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.cms.contenttype.MetadataType;
033import org.ametys.runtime.i18n.I18nizableText;
034
035/**
036 * Enumerator on {@link ContentType} for the Agenda service.
037 * Restrict content types to thoses who have all the metadatas referenced by the <code>_metadataNames</code> list.
038 */
039public class CalendarContentTypesEnumerator extends ContentTypeEnumerator
040{
041    /** Map of mandatory metadata names and their type. */
042    protected Map<String, Set<MetadataType>> _mandatoryMetadata;
043    
044    @Override
045    public void configure(Configuration configuration) throws ConfigurationException
046    {
047        super.configure(configuration);
048        
049        Configuration mandatoryMetadataConf = configuration.getChild("enumeration").getChild("custom-enumerator").getChild("mandatory-metadata", false);
050        if (mandatoryMetadataConf == null)
051        {
052            _mandatoryMetadata = null;
053        }
054        else
055        {
056            _mandatoryMetadata = new HashMap<>();
057            
058            Configuration[] metadataRefConfs = mandatoryMetadataConf.getChildren("metadata-ref");
059            for (Configuration metadataRefConf : metadataRefConfs)
060            {
061                String name = metadataRefConf.getValue(null);
062                
063                String[] types = StringUtils.split(metadataRefConf.getAttribute("type", "string"), ',');
064                
065                Set<MetadataType> metaTypes = new HashSet<>(types.length);
066                for (String type : types)
067                {
068                    metaTypes.add(MetadataType.valueOf(type.trim().toUpperCase()));
069                }
070                
071                _mandatoryMetadata.put(name, metaTypes);
072            }
073            _mandatoryMetadata.remove(null);
074        }
075    }
076    
077    @Override
078    public Map<Object, I18nizableText> getEntries() throws Exception
079    {
080        Map<Object, I18nizableText> entries = new HashMap<>();
081        Set<String> cTypeIds = getCTypeIds();
082        
083        for (String cTypeId : cTypeIds)
084        {
085            ContentType cType = _cTypeExtPt.getExtension(cTypeId);
086            
087            // Build a Set containing the rejected mandatory metadata.
088            // This means either the metadata does not exists for this content type, or the metadata type is not matching the expectations.
089            Collection<String> rejectedMetadata = CollectionUtils.selectRejected(_mandatoryMetadata.keySet(), new MandatoryMetadataPredicate(cType));
090
091            if (rejectedMetadata.isEmpty())
092            {
093                entries.put(cTypeId, cType.getLabel());
094            }
095        }
096
097        // All contents
098        _handleAllOptionEntry(entries);
099        
100        return entries;
101    }
102    
103    /**
104     * Predicate that test if the requested metadata is in the content type and if its type is correct.
105     */
106    public class MandatoryMetadataPredicate implements Predicate
107    {
108        private ContentType _cType;
109        
110        /**
111         * Build a {@code MandatoryMetadataPredicate}
112         * @param cType The ContentType to check against.
113         */
114        protected MandatoryMetadataPredicate(ContentType cType)
115        {
116            _cType = cType;
117        }
118        
119        @Override
120        public boolean evaluate(Object object)
121        {
122            String metadataName = (String) object;
123            return _isDefined(metadataName) && _isTypeCorrect(metadataName); 
124        }
125        
126        private boolean _isDefined(String metadataName)
127        {
128            return _cType.getMetadataNames().contains(metadataName);
129        }
130        
131        private boolean _isTypeCorrect(String metadataName)
132        {
133            return _mandatoryMetadata.get(metadataName).contains(_cType.getMetadataDefinition(metadataName).getType());
134        }
135    }
136}