001/*
002 *  Copyright 2018 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.services;
017
018import java.io.IOException;
019import java.io.UnsupportedEncodingException;
020import java.util.HashSet;
021
022import org.apache.avalon.framework.service.ServiceException;
023import org.apache.avalon.framework.service.ServiceManager;
024import org.apache.cocoon.ProcessingException;
025import org.apache.cocoon.environment.ObjectModelHelper;
026import org.apache.cocoon.environment.Request;
027import org.apache.cocoon.generation.ServiceableGenerator;
028import org.apache.cocoon.xml.XMLUtils;
029import org.apache.commons.lang.ArrayUtils;
030import org.apache.commons.lang3.StringUtils;
031import org.xml.sax.SAXException;
032
033import org.ametys.cms.contenttype.ContentTypesHelper;
034import org.ametys.cms.contenttype.MetadataDefinition;
035import org.ametys.cms.contenttype.MetadataDefinitionReference;
036import org.ametys.cms.contenttype.MetadataManager;
037import org.ametys.cms.contenttype.MetadataSet;
038import org.ametys.cms.repository.DefaultContent;
039import org.ametys.odf.workflow.ValidateODFContentFunction;
040import org.ametys.plugins.repository.AmetysObjectResolver;
041import org.ametys.plugins.repository.AmetysRepositoryException;
042import org.ametys.plugins.repository.metadata.CompositeMetadata;
043import org.ametys.runtime.i18n.I18nizableText;
044
045/**
046 * Class to parse a metadata from an ODF content in Live version.
047 */
048public class ODFContentFieldGenerator extends ServiceableGenerator
049{
050    /** The source resolver */
051    protected AmetysObjectResolver _resolver;
052    
053    /** Metadata manager */
054    protected MetadataManager _metadataManager;
055
056    /** Content type helper */
057    protected ContentTypesHelper _contentTypesHelper;
058    
059    @Override
060    public void service(ServiceManager serviceManager) throws ServiceException
061    {
062        super.service(serviceManager);
063        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
064        _metadataManager = (MetadataManager) serviceManager.lookup(MetadataManager.ROLE);
065        _contentTypesHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE);
066    }
067
068    @Override
069    public void generate() throws ProcessingException
070    {
071        Request request = ObjectModelHelper.getRequest(objectModel);
072        String contentId = request.getParameter("contentId");
073        if (StringUtils.isEmpty(contentId))
074        {
075            throw new ProcessingException("The content ID is empty.");
076        }
077
078        try
079        {
080            DefaultContent content = _resolver.resolveById(contentId);
081
082            // Is this an ODF content ?
083            if (!_contentTypesHelper.isInstanceOf(content, "org.ametys.plugins.odf.Content.odfContent"))
084            {
085                throw new ProcessingException(String.format("The content with the ID '%s' is not an ODF content.", contentId));
086            }
087
088            // The content Have a Live version ?
089            String[] labels = content.getAllLabels();
090            if (!ArrayUtils.contains(labels, ValidateODFContentFunction.VALID_LABEL))
091            {
092                throw new ProcessingException(String.format("The content with the ID '%s' hasn't a Live version.", contentId));
093            }
094            
095            // Get the Live version to the content
096            content.switchToLabel(ValidateODFContentFunction.VALID_LABEL);
097            
098            // Do we have a metadata name ?
099            String metadataName = request.getParameter("metadata");
100            if (StringUtils.isEmpty(metadataName))
101            {
102                throw new ProcessingException(String.format("No metadata has been transmitted for the content '%s'.", contentId));
103            }
104            
105            // The metadata exists ?
106            MetadataDefinition definition = _contentTypesHelper.getMetadataDefinitionByMetadataValuePath(metadataName, content);
107            if (definition == null)
108            {
109                throw new ProcessingException(String.format("There is no metadata named '%s' for the content '%s'.", metadataName, contentId));
110            }
111            
112            
113            // Sax the metadata
114            contentHandler.startDocument();
115            XMLUtils.startElement(contentHandler, "metadata");
116            if (metadataName.contains("/"))
117            {
118                MetadataDefinition cmDefinition = _contentTypesHelper.getMetadataDefinitionByMetadataValuePath(StringUtils.substringBeforeLast(metadataName, "/"), content);
119                
120                CompositeMetadata holder = content.getMetadataHolder();
121                while (holder != null && metadataName.contains("/"))
122                {
123                    String currentMetadataName =  StringUtils.substringBefore(metadataName, "/");
124                    String entryName = _getEntryName(currentMetadataName);
125                    currentMetadataName = StringUtils.substringBefore(currentMetadataName, "[");
126                    holder = _getHolder(holder, currentMetadataName, entryName);
127                    metadataName = StringUtils.substringAfter(metadataName, "/");
128                }
129                
130                MetadataSet metadataSet = new MetadataSet();
131                metadataSet.setName("__generated__");
132                metadataSet.setLabel(new I18nizableText("Metadataset for export"));
133                metadataSet.setDescription(new I18nizableText("Metadataset for export"));
134                metadataSet.setEdition(false);
135                metadataSet.setInternal(true);
136                metadataSet.addElement(new MetadataDefinitionReference(metadataName, "main"));
137                _metadataManager.saxMetadata(contentHandler, content, holder, metadataSet, cmDefinition, null, new HashSet<>());
138            }
139            else
140            {
141                _metadataManager.saxMetadata(contentHandler, content, metadataName, null);
142            }
143
144            XMLUtils.endElement(contentHandler, "metadata");
145            contentHandler.endDocument();
146        }
147        catch (UnsupportedEncodingException e)
148        {
149            // Shouldn't happen
150            throw new ProcessingException("Impossible to decode the parameter.", e);
151        }
152        catch (AmetysRepositoryException e)
153        {
154            throw new ProcessingException(String.format("Unable to get the content with the ID '%s'.", contentId), e);
155        }
156        catch (SAXException e)
157        {
158            throw new ProcessingException("Error while saxing the document.", e);
159        }
160        catch (IOException e)
161        {
162            throw new ProcessingException(String.format("Error while saxing the content '%s' on the 'export' metadata set.", contentId), e);
163        }
164    }
165    
166    private CompositeMetadata _getHolder(CompositeMetadata holder, String metadataName, String entryName)
167    {
168        if (!holder.hasMetadata(metadataName))
169        {
170            return null;
171        }
172        
173        CompositeMetadata cm = holder.getCompositeMetadata(metadataName);
174        
175        if (StringUtils.isNotEmpty(entryName))
176        {
177            if (!cm.hasMetadata(entryName))
178            {
179                return null;
180            }
181            
182            cm = cm.getCompositeMetadata(entryName);
183        }
184        
185        return cm;
186    }
187    
188    private String _getEntryName(String metadataName)
189    {
190        return StringUtils.substringBefore(StringUtils.substringAfter(metadataName, "["), "]");
191    }
192}