001/*
002 *  Copyright 2011 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.blog.posts;
017
018import java.io.IOException;
019import java.time.ZoneId;
020import java.time.ZonedDateTime;
021import java.util.HashMap;
022import java.util.Map;
023
024import javax.jcr.Node;
025import javax.jcr.NodeIterator;
026import javax.jcr.Repository;
027import javax.jcr.RepositoryException;
028import javax.jcr.Session;
029import javax.jcr.query.Query;
030
031import org.apache.avalon.framework.service.ServiceException;
032import org.apache.avalon.framework.service.ServiceManager;
033import org.apache.cocoon.ProcessingException;
034import org.apache.cocoon.environment.ObjectModelHelper;
035import org.apache.cocoon.environment.Request;
036import org.apache.cocoon.generation.ServiceableGenerator;
037import org.apache.cocoon.xml.AttributesImpl;
038import org.apache.cocoon.xml.XMLUtils;
039import org.xml.sax.SAXException;
040
041import org.ametys.cms.repository.Content;
042import org.ametys.cms.repository.comment.Comment;
043import org.ametys.core.util.DateUtils;
044import org.ametys.plugins.repository.AmetysObjectResolver;
045import org.ametys.plugins.repository.AmetysRepositoryException;
046import org.ametys.plugins.repository.RepositoryConstants;
047import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder;
048import org.ametys.plugins.repository.data.holder.impl.DefaultModifiableModelLessDataHolder;
049import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData;
050import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData;
051import org.ametys.plugins.repository.provider.AbstractRepository;
052import org.ametys.plugins.repository.version.UnversionedDataTypeExtensionPoint;
053import org.ametys.web.repository.content.jcr.DefaultWebContent;
054
055/**
056 * Generate the latest comments.
057 */
058public class CommentsGenerator extends ServiceableGenerator
059{
060    
061    /** RSS max number of comments. */
062    public static final int RSS_MAX_COMMENTS = 20;
063    
064    /** The ametys object resolver. */
065    protected AmetysObjectResolver _resolver;
066    
067    /** The repository. */
068    protected Repository _repository;
069    
070    /** the the extension point with available data types for unversioned data */
071    protected UnversionedDataTypeExtensionPoint _unversionedDataTypeExtensionPoint;
072    
073    @Override
074    public void service(ServiceManager serviceManager) throws ServiceException
075    {
076        super.service(serviceManager);
077        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
078        _repository = (Repository) serviceManager.lookup(AbstractRepository.ROLE);
079        _unversionedDataTypeExtensionPoint = (UnversionedDataTypeExtensionPoint) serviceManager.lookup(UnversionedDataTypeExtensionPoint.ROLE);
080    }
081    
082    @Override
083    public void generate() throws IOException, SAXException, ProcessingException
084    {
085        Request request = ObjectModelHelper.getRequest(objectModel);
086        
087        String siteName = parameters.getParameter("siteName", (String) request.getAttribute("site"));
088        
089        Map<Comment, Content> comments = getComments(siteName, RSS_MAX_COMMENTS);
090        
091        AttributesImpl attrs = new AttributesImpl();
092        attrs.addCDATAAttribute("site", siteName);
093        attrs.addCDATAAttribute("now", DateUtils.getISODateTimeFormatter().format(ZonedDateTime.now()));
094        
095        contentHandler.startDocument();
096        XMLUtils.startElement(contentHandler, "comments", attrs);
097        
098        for (Comment comment : comments.keySet())
099        {
100            Content content = comments.get(comment);
101            
102            AttributesImpl cmtAttrs = new AttributesImpl();
103            
104            cmtAttrs.addCDATAAttribute("id", comment.getId());
105            cmtAttrs.addCDATAAttribute("date", DateUtils.getISODateTimeFormatter().format(comment.getCreationDate().toInstant().atZone(ZoneId.systemDefault())));
106            cmtAttrs.addCDATAAttribute("sortDate", Long.toString(comment.getCreationDate().toInstant().toEpochMilli()));
107            cmtAttrs.addCDATAAttribute("authorName", comment.getAuthorName());
108            cmtAttrs.addCDATAAttribute("contentId", content.getId());
109            cmtAttrs.addCDATAAttribute("contentName", content.getName());
110            cmtAttrs.addCDATAAttribute("contentTitle", content.getTitle());
111            
112            XMLUtils.startElement(contentHandler, "comment", cmtAttrs);
113            XMLUtils.valueOf(contentHandler, comment.getContent());
114            XMLUtils.endElement(contentHandler, "comment");
115        }
116        
117        XMLUtils.endElement(contentHandler, "comments");
118        contentHandler.endDocument();
119    }
120    
121    /**
122     * Get a site's latest comments.
123     * @param siteName the site name.
124     * @param max the maximum number of comments.
125     * @return the comments.
126     */
127    protected Map<Comment, Content> getComments(String siteName, int max)
128    {
129        Map<Comment, Content> comments = new HashMap<>();
130        
131        // element(*, ametys:content)[(@ametys:site = 'siteName')]/ametys-internal:unversioned/@ametys:comments/element(*, ametys:compositeMetadata)
132        String jcrQuery = "//element(*, ametys:content)[@" + RepositoryConstants.NAMESPACE_PREFIX + ":" + DefaultWebContent.METADATA_SITE + " = '" + siteName + "']/"
133            + RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":unversioned/"
134            + RepositoryConstants.NAMESPACE_PREFIX + ":" + Comment.METADATA_COMMENTS
135            + "/element(*, ametys:compositeMetadata)[@ametys:validated = true()]"
136            + " order by @ametys:creation descending";
137        
138        Session session = null;
139        try
140        {
141            session = _repository.login();
142            
143            @SuppressWarnings("deprecation")
144            Query query = session.getWorkspace().getQueryManager().createQuery(jcrQuery, Query.XPATH);
145            
146            NodeIterator nodes = query.execute().getNodes();
147            int processed = 0;
148            while (nodes.hasNext() && processed < max)
149            {
150                Node commentNode = nodes.nextNode();
151                
152                Node unversionedNode = commentNode.getParent().getParent();
153                Node contentNode = unversionedNode.getParent();
154                
155                String nodeName = commentNode.getName();
156                String commentId = nodeName.substring(RepositoryConstants.NAMESPACE_PREFIX.length() + 1);
157                ModifiableRepositoryData repositoryData = new JCRRepositoryData(unversionedNode);
158                ModifiableModelLessDataHolder unversionedDataHolder = new DefaultModifiableModelLessDataHolder(_unversionedDataTypeExtensionPoint, repositoryData);
159                
160                Comment comment = new Comment(unversionedDataHolder, commentId);
161                
162                Content content = _resolver.resolve(contentNode, false);
163                
164                comments.put(comment, content);
165                
166                processed++;
167            }
168        }
169        catch (RepositoryException ex)
170        {
171            if (session != null)
172            {
173                session.logout();
174            }
175
176            throw new AmetysRepositoryException("An error occurred executing the JCR query : " + jcrQuery, ex);
177        }
178        
179        return comments;
180//        return commentedContents;
181    }
182
183}