001/*
002 *  Copyright 2013 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.ArrayList;
019import java.util.HashMap;
020import java.util.HashSet;
021import java.util.LinkedHashMap;
022import java.util.List;
023import java.util.Map;
024
025import org.apache.avalon.framework.parameters.Parameters;
026import org.apache.cocoon.ProcessingException;
027import org.apache.cocoon.environment.ObjectModelHelper;
028import org.apache.cocoon.environment.Redirector;
029import org.apache.cocoon.environment.Request;
030import org.apache.cocoon.environment.SourceResolver;
031
032import org.ametys.cms.content.GetMetadataSetDefAction;
033import org.ametys.core.cocoon.JSonReader;
034
035/**
036 * Get metadata set definition as JSON object from a given content type.
037 * Be careful, this action is only based on a single content type and a metadata set.
038 * All metadata of the asked metadata set are returned regardless of the current content and user's rights
039 */
040public class GetMetadataSetDefByContentTypeAction extends GetMetadataSetDefAction
041{
042    @Override
043    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
044    {
045        Request request = ObjectModelHelper.getRequest(objectModel);
046
047        boolean isEditionMetadataSet = parameters.getParameterAsBoolean("isEditionMetadataSet", false);
048        String metadataSetName = parameters.getParameter("metadataSetName", "main");
049        String contentTypeId = parameters.getParameter("contentTypeId");
050        
051        Map<String, Object> jsonObject = new HashMap<>();
052        
053        List<String> languages = getLanguages(request);
054        
055        ContentType contentType = _contentTypeExtensionPoint.getExtension(contentTypeId);
056        jsonObject.put("contentType", contentType2Json(contentType, metadataSetName, isEditionMetadataSet, languages));
057        
058        request.setAttribute(JSonReader.OBJECT_TO_READ, jsonObject);
059        return EMPTY_MAP;
060    }
061
062    /**
063     * Convert content to JSON object
064     * @param contentType The content type
065     * @param metadataSetName The metadata set name
066     * @param isEditionMetadataSet true if it is metadataset for edition
067     * @param languages the current languages requested by the client (an ordonned list)
068     * @return The JSON object representing the content
069     * @throws ProcessingException if an error occurred
070     */
071    protected Map<String, Object> contentType2Json (ContentType contentType, String metadataSetName, boolean isEditionMetadataSet, List<String> languages) throws ProcessingException
072    {
073        Map<String, Object> jsonObject = new LinkedHashMap<>();
074        
075        jsonObject.put("id", contentType.getId());
076        jsonObject.put("title", contentType.getLabel());
077        jsonObject.put("defaultTitle", contentType.getDefaultTitle());
078        
079        MetadataSet metadataSet = null;
080        
081        if (isEditionMetadataSet)
082        {
083            metadataSet = contentType.getMetadataSetForEdition(metadataSetName);
084        }
085        else
086        {
087            metadataSet = contentType.getMetadataSetForView(metadataSetName);
088        }
089        
090        jsonObject.put("metadataSetName", metadataSetName); 
091        jsonObject.put("isEditionMetadataSet", isEditionMetadataSet); 
092        
093        if (metadataSet == null)
094        {
095            _logger.warn("Unknown metadata set '{}' of type '{}' for content type(s) '{}'",
096                                          metadataSetName, isEditionMetadataSet ? "edition" : "view", contentType.getId());
097        }
098        else
099        {
100            jsonObject.put("metadataSet", metadataSetElement2JsonObject(contentType, null, metadataSet, languages));
101        }
102        
103        
104        return jsonObject;
105    }
106    
107    /**
108     * Convert {@link AbstractMetadataSetElement} to JSON object
109     * @param contentType The content type
110     * @param metadataDefinition The metadata definition
111     * @param metadataSetElement The metadataset element
112     * @param languages the current languages requested by the client (an ordonned list)
113     * @return The JSON object representing the metadataset element
114     * @throws ProcessingException If an error occured
115     */
116    protected Map<String, Object> metadataSetElement2JsonObject(ContentType contentType, MetadataDefinition metadataDefinition, AbstractMetadataSetElement metadataSetElement, List<String> languages) throws ProcessingException
117    {
118        Map<String, Object> jsonObject = new LinkedHashMap<>();
119        
120        for (AbstractMetadataSetElement subMetadataSetElement : metadataSetElement.getElements())
121        {
122            if (subMetadataSetElement instanceof MetadataDefinitionReference)
123            {
124                MetadataDefinitionReference metadataDefRef = (MetadataDefinitionReference) subMetadataSetElement;
125                String metadataName = metadataDefRef.getMetadataName();
126                MetadataDefinition metaDef = _getMetadataDefinition(contentType, metadataDefinition, metadataName);
127                
128                if (metaDef == null)
129                {
130                    throw new IllegalArgumentException("Unable to get the metadata definition of metadata \"" + metadataName + "\"");
131                }
132                
133                String metadataPath = metaDef.getId();
134                jsonObject.put(metaDef.getName(), metadataDefinition2JsonObject(null, metadataDefRef, metaDef, metadataPath, new HashSet<>(), languages));
135            }
136            else
137            {
138                if (!jsonObject.containsKey("fieldsets"))
139                {
140                    jsonObject.put("fieldsets", new ArrayList<Map<String, Object>>());
141                }
142                
143                @SuppressWarnings("unchecked")
144                List<Map<String, Object>> fieldsets = (List<Map<String, Object>>) jsonObject.get("fieldsets");
145                
146                Fieldset fieldset = (Fieldset) subMetadataSetElement;
147                
148                Map<String, Object> fieldSetObject = new LinkedHashMap<>();
149                fieldSetObject.put("role", fieldset.getRole());
150                fieldSetObject.put("label", fieldset.getLabel());
151                fieldSetObject.put("elements", metadataSetElement2JsonObject(contentType, metadataDefinition, fieldset, languages));
152                
153                fieldsets.add(fieldSetObject);
154            }
155        }
156        
157        return jsonObject;
158    }
159    
160    /**
161     * Retrieves a sub metadata definition from a content type or a parent metadata definition. 
162     * @param contentType the content type.
163     * @param parentMetadataDefinition the parent metadata definition.
164     * @param metadataName the metadata name.
165     * @return the metadata definition found or <code>null</code> otherwise.
166     */
167    protected MetadataDefinition _getMetadataDefinition(ContentType contentType, MetadataDefinition parentMetadataDefinition, String metadataName)
168    {
169        MetadataDefinition metadataDefinition = null;
170        
171        if (parentMetadataDefinition == null)
172        {
173            metadataDefinition =  contentType.getMetadataDefinition(metadataName);
174        }
175        else
176        {
177            metadataDefinition = parentMetadataDefinition.getMetadataDefinition(metadataName);
178        }
179        
180        return metadataDefinition;
181    }
182}