001/*
002 *  Copyright 2015 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.contenttype;
017
018import java.util.Collection;
019import java.util.Collections;
020import java.util.HashMap;
021import java.util.HashSet;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import org.apache.avalon.framework.parameters.Parameters;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.acting.ServiceableAction;
030import org.apache.cocoon.environment.ObjectModelHelper;
031import org.apache.cocoon.environment.Redirector;
032import org.apache.cocoon.environment.Request;
033import org.apache.cocoon.environment.SourceResolver;
034import org.apache.commons.lang.BooleanUtils;
035import org.apache.commons.lang3.ArrayUtils;
036import org.apache.commons.lang3.StringUtils;
037
038import org.ametys.cms.repository.Content;
039import org.ametys.core.cocoon.JSonReader;
040import org.ametys.plugins.repository.AmetysObjectResolver;
041
042/**
043 * Get the common metadata set between given content types and/or among given contents
044 */
045public class GetCommonMetadataSetAction extends ServiceableAction
046{
047    /** The content type EP */
048    protected ContentTypeExtensionPoint _cTypeEP;
049    
050    /** The content types Helper */
051    protected ContentTypesHelper _contentTypesHelper;
052    
053    /** The ametys object resolver */
054    protected AmetysObjectResolver _resolver;
055    
056    @Override
057    public void service(ServiceManager smanager) throws ServiceException
058    {
059        super.service(smanager);
060        _cTypeEP = (ContentTypeExtensionPoint) smanager.lookup(ContentTypeExtensionPoint.ROLE);
061        _contentTypesHelper = (ContentTypesHelper) smanager.lookup(ContentTypesHelper.ROLE);
062        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
063    }
064    
065    @Override
066    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
067    {
068        Request request = ObjectModelHelper.getRequest(objectModel);
069        
070        boolean isEdition = BooleanUtils.toBoolean(request.getParameter("isEdition")); // false by default
071        boolean includeInternal = BooleanUtils.toBoolean(request.getParameter("includeInternal")); // false by default
072        
073        Set<String> cTypesId = getContentTypes(request);
074        cTypesId.addAll(getContentTypesFromContents(request));
075        if (cTypesId.isEmpty())
076        {
077            cTypesId.addAll(getAllAvailablesContentTypes(request, true));
078        }
079        
080        Map<String, Object> result = new HashMap<>();
081        
082        Collection<Map<String, Object>> commonMetadataSetsInfo = getCommonMetadataSetsInfo(cTypesId, isEdition, includeInternal);
083        result.put("metadataSets", commonMetadataSetsInfo);
084        
085        request.setAttribute(JSonReader.OBJECT_TO_READ, result);
086        return EMPTY_MAP;
087    }
088    
089    
090    /**
091     * Retrieves the common metadata labels by name
092     * @param cTypesId the content types ids
093     * @param isEdition Is the metadata set for edition ? 
094     * @param includeInternal include internal metadata sets ?
095     * @return The map of metadata set
096     */
097    protected Collection<Map<String, Object>> getCommonMetadataSetsInfo(Collection<String> cTypesId, boolean isEdition, boolean includeInternal)
098    {
099        // Map<Metadata set name, Map<key, value>>>
100        Map<String, Map<String, Object>> commonMetadataSetsInfo = null;
101        
102        for (String cTypeId : cTypesId)
103        {
104            List<Map<String, Object>> metadataSetsInfo = _contentTypesHelper.getMetadataSetsInfo(cTypeId, false, includeInternal);
105            
106            if (commonMetadataSetsInfo == null)
107            {
108                commonMetadataSetsInfo = new HashMap<>();
109                for (Map<String, Object> entry : metadataSetsInfo)
110                {
111                    String metadataSetName = (String) entry.get("name");
112                    commonMetadataSetsInfo.put(metadataSetName, entry);
113                }
114            }
115            else
116            {
117                Set<String> metadataSetNames = new HashSet<>();
118                for (Map<String, Object> entry : metadataSetsInfo)
119                {
120                    String metadataSetName = (String) entry.get("name");
121                    metadataSetNames.add(metadataSetName);
122                }
123                
124                // only retains common metadata (performs a set intersection)
125                commonMetadataSetsInfo.keySet().retainAll(metadataSetNames);
126            }
127        }
128        
129        return commonMetadataSetsInfo != null ? commonMetadataSetsInfo.values() : Collections.EMPTY_LIST;
130    }
131    
132    /**
133     * Get the content types id to search for
134     * @param request the request
135     * @return the content types
136     */
137    protected Set<String> getContentTypes(Request request)
138    {
139        Set<String> cTypeIds = new HashSet<>();
140        String[] ids = request.getParameterValues("ids");
141        
142        if (ids != null)
143        {
144            for (String id : ids)
145            {
146                if (StringUtils.isNotEmpty(id))
147                {
148                    // id can contains comma (when allOption is selected for example).
149                    for (String idPart : StringUtils.split(id, ','))
150                    {
151                        cTypeIds.add(idPart);
152                    }
153                }
154            }
155        }
156        
157        return cTypeIds;
158    }
159    
160    /**
161     * Get the content types id to search for
162     * @param request the request
163     * @return the content types
164     */
165    protected Set<String> getContentTypesFromContents(Request request)
166    {
167        Set<String> cTypeIds = new HashSet<>();
168        String[] contentIds = request.getParameterValues("contentIds");
169        
170        if (contentIds != null)
171        {
172            for (String contentId : contentIds)
173            {
174                if (StringUtils.isNotEmpty(contentId))
175                {
176                    Content content = _resolver.resolveById(contentId);
177                    
178                    String[] allContentTypes = ArrayUtils.addAll(content.getTypes(), content.getMixinTypes());
179                    for (String id : allContentTypes)
180                    {
181                        cTypeIds.add(id);
182                    }
183                }
184            }
185        }
186        
187        return cTypeIds;
188    }
189    
190    /**
191     * Get all the available content types 
192     * @param request the request
193     * @param publicOnly Only the non private content types will be returned
194     * @return all the available content types 
195     */
196    protected Set<String> getAllAvailablesContentTypes (Request request, boolean publicOnly)
197    {
198        Set<String> types = new HashSet<>();
199        
200        for (String id : _cTypeEP.getExtensionsIds())
201        {
202            if (!publicOnly || !_cTypeEP.getExtension(id).isPrivate())
203            {
204                types.add(id);
205            }
206        }
207        
208        return types;
209    }
210}