001/*
002 *  Copyright 2019 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.web.content;
017
018import java.util.HashMap;
019import java.util.Locale;
020import java.util.Map;
021import java.util.Set;
022
023import javax.xml.transform.TransformerException;
024
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.cocoon.xml.AttributesImpl;
028import org.apache.cocoon.xml.XMLUtils;
029import org.apache.xpath.XPathAPI;
030import org.w3c.dom.Node;
031import org.w3c.dom.NodeList;
032import org.xml.sax.ContentHandler;
033import org.xml.sax.SAXException;
034
035import org.ametys.cms.repository.Content;
036import org.ametys.cms.repository.ModifiableContent;
037import org.ametys.cms.repository.TagAwareAmetysObject;
038import org.ametys.cms.repository.TaggableAmetysObject;
039import org.ametys.cms.tag.Tag;
040import org.ametys.cms.tag.TagProviderExtensionPoint;
041import org.ametys.plugins.repository.data.extractor.xml.XMLValuesExtractorAdditionalDataGetter;
042import org.ametys.runtime.model.View;
043import org.ametys.web.repository.content.ModifiableWebContent;
044import org.ametys.web.repository.content.WebContent;
045
046/**
047 * Generates SAX events for Content, including tags for {@link WebContent}.
048 */
049public class ContentSaxer extends org.ametys.cms.content.ContentSaxer
050{
051    private TagProviderExtensionPoint _tagProviderEP;
052
053    @Override
054    public void service(ServiceManager manager) throws ServiceException
055    {
056        super.service(manager);
057        _tagProviderEP = (TagProviderExtensionPoint) manager.lookup(TagProviderExtensionPoint.ROLE);
058    }
059    
060    @Override
061    protected void saxBody(Content content, ContentHandler contentHandler, Locale locale, View view, String tagName, boolean saxWorkflowStep, boolean saxWorkflowInfo, boolean saxLanguageInfo, String attributesTagName) throws SAXException
062    {
063        super.saxBody(content, contentHandler, locale, view, tagName, saxWorkflowStep, saxWorkflowInfo, saxLanguageInfo, attributesTagName);
064        
065        if (content instanceof WebContent)
066        {
067            saxSiteName((WebContent) content, contentHandler);
068            saxTags((WebContent) content, contentHandler);
069        }
070    }
071    
072    /**
073     * Generates SAX events for the site name.
074     * @param content the {@link WebContent}.
075     * @param contentHandler the ContentHandler receving SAX events.
076     * @throws SAXException if an error occurs during the SAX events generation.
077     */
078    protected void saxSiteName(WebContent content, ContentHandler contentHandler) throws SAXException
079    {
080        AttributesImpl attrs = new AttributesImpl();
081        attrs.addCDATAAttribute("name", content.getSiteName());
082        XMLUtils.createElement(contentHandler, "site", attrs);
083    }
084    
085    /**
086     * Generates SAX events for tags.
087     * @param content the {@link WebContent}.
088     * @param contentHandler the ContentHandler receving SAX events.
089     * @throws SAXException if an error occurs during the SAX events generation.
090     */
091    protected void saxTags(WebContent content, ContentHandler contentHandler) throws SAXException
092    {
093        XMLUtils.startElement(contentHandler, "tags");
094
095        String siteName = content.getSiteName();
096
097        Set<String> tags = ((TagAwareAmetysObject) content).getTags();
098        for (String tagName : tags)
099        {
100            Map<String, Object> contextParameters = new HashMap<>();
101            contextParameters.put("siteName", siteName);
102            Tag tag = _tagProviderEP.getTag(tagName, contextParameters);
103
104            if (tag != null)
105            {
106                AttributesImpl attrs = new AttributesImpl();
107                if (tag.getParentName() != null)
108                {
109                    attrs.addCDATAAttribute("parent", tag.getParentName());
110                }
111
112                XMLUtils.startElement(contentHandler, tagName, attrs);
113                tag.getTitle().toSAX(contentHandler);
114                XMLUtils.endElement(contentHandler, tagName);
115            }
116        }
117
118        XMLUtils.endElement(contentHandler, "tags");
119    }
120    
121    @Override
122    public void fillContent(ModifiableContent content, Node contentNode, XMLValuesExtractorAdditionalDataGetter additionalDataGetter) throws Exception
123    {
124        super.fillContent(content, contentNode, additionalDataGetter);
125        
126        if (content instanceof ModifiableWebContent)
127        {
128            fillSiteName((ModifiableWebContent) content, contentNode);
129        }
130        
131        fillTags(content, contentNode);
132    }
133    
134    /**
135     * Fills the given content with the site name from the provided {@link org.w3c.dom.Node}
136     * @param content The content to fill
137     * @param contentNode the node to read to get the site name
138     * @throws TransformerException if an error occurs
139     */
140    protected void fillSiteName(ModifiableWebContent content, Node contentNode) throws TransformerException
141    {
142        String siteName = XPathAPI.eval(contentNode, "site/@name").str();
143        content.setSiteName(siteName);
144    }
145    
146    /**
147     * Fills the given {@link TaggableAmetysObject} with the tags from the provided {@link org.w3c.dom.Node}
148     * @param taggable The {@link TaggableAmetysObject} to fill
149     * @param contentNode the node to read to get the tags
150     * @throws TransformerException if an error occurs
151     */
152    protected void fillTags(TaggableAmetysObject taggable, Node contentNode) throws TransformerException
153    {
154        NodeList tagsNode = XPathAPI.selectNodeList(contentNode, "content/tags/*");
155        for (int i = 0; i < tagsNode.getLength(); i++)
156        {
157            Node tagNode = tagsNode.item(i);
158            String tagName = tagNode.getNodeName();
159            taggable.tag(tagName);
160        }
161    }
162}