AnswersFeedGenerator.java
/*
* Copyright (C) 2003-2009 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.forum.rss;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Session;
import org.exoplatform.forum.common.jcr.JCRTask;
import org.exoplatform.forum.common.jcr.KSDataLocation;
import org.exoplatform.forum.common.jcr.PropertyReader;
import org.exoplatform.forum.common.jcr.VoidReturn;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
/**
* @author <a href="mailto:patrice.lamarque@exoplatform.com">Patrice Lamarque</a>
* @version $Revision$
*/
public final class AnswersFeedGenerator extends RSSProcess implements FeedContentProvider, FeedListener {
private static final Log LOG = ExoLogger.getLogger(AnswersFeedGenerator.class);
public static final String FAQ_RSS_TYPE = "exo:faqRSS".intern();
public static final String KS_FAQ = "faq".intern();
public static final String FAQ_APP = "faqApp".intern();
public AnswersFeedGenerator() {
super();
}
public AnswersFeedGenerator(KSDataLocation dataLocator) {
super(dataLocator);
}
public void itemAdded(String path) {
try {
ItemSavedTask task = new ItemSavedTask(path,false);
dataLocator.getSessionManager().executeAndSave(task);
} catch (Exception e) {
LOG.error("itemAdded failed for" + path, e);
}
}
public void itemUpdated(String path) {
try {
ItemSavedTask task = new ItemSavedTask(path,true);
dataLocator.getSessionManager().executeAndSave(task);
} catch (Exception e) {
LOG.error("itemUpdated failed for" + path, e);
}
}
class ItemSavedTask implements JCRTask<VoidReturn> {
private String path;
private boolean updated;
public ItemSavedTask(String path, boolean updated) {
this.path = path;
this.updated = updated;
}
public VoidReturn execute(Session session) throws Exception {
itemSaved(path,updated);
return VoidReturn.VALUE;
}
}
protected void itemSaved(String path, boolean updated) throws Exception {
// find the node corresponding to this event
Node questionNode = findQuestionNode(path);
if (questionNode == null) {
LOG.debug("generate Feed event was ignored on " + path);
return;
}
final String questionNodeName = questionNode.getName();
PropertyReader question = new PropertyReader(questionNode);
Node categoryNode = questionNode.getParent().getParent();
PropertyReader category = new PropertyReader(categoryNode);
String categoryDescription = category.string("exo:description", "eXo link:" + RSS.DEFAULT_FEED_LINK);
String categoryTitle = category.string("exo:name", "Home");
// only approved or activated questions
if ((!question.bool("exo:isActivated") || !question.bool("exo:isApproved"))) {
RSS rss = new RSS(categoryNode);
SyndFeed feed = rss.removeEntry(questionNodeName);
feed.setTitle(categoryTitle);
feed.setDescription(categoryDescription);
rss.saveFeed(feed, FAQ_RSS_TYPE);
return;
}
SyndEntry entry = createQuestionEntry(questionNode);
RSS data = new RSS(categoryNode);
if (data.feedExists()) {
SyndFeed feed = null;
if (updated) {
feed = data.removeEntry(questionNodeName);
}
feed = data.addEntry(entry);
feed.setDescription(categoryDescription);
feed.setTitle(categoryTitle);
data.saveFeed(feed, FAQ_RSS_TYPE);
} else {
SyndFeed feed = RSS.createNewFeed(categoryTitle, category.date("exo:createdDate", new Date()));
feed.setDescription(categoryDescription);
String categoryLink = entry.getLink()
+ "?portal:componentId=faq&portal:type=action&portal:isSecure=false&uicomponent=UICategories&op=OpenCategory&"
+ "objectId=" + question.string("exo:categoryId");
feed.setLink(categoryLink);
feed.setEntries(Arrays.asList(new SyndEntry[] { entry }));
data.saveFeed(feed, FAQ_RSS_TYPE);
}
}
private SyndEntry createQuestionEntry(Node questionNode) throws Exception {
String linkItem = getPageLink();
linkItem += "?portal:componentId=faq&portal:type=action&portal:isSecure=false&uicomponent=UIQuestions&op=ViewQuestion&objectId=";
linkItem += questionNode.getPath().substring(questionNode.getPath().indexOf("/categories/") + 1);
// Create new entry
List<String> listContent = new ArrayList<String>();
StringBuffer content = new StringBuffer();
if (questionNode.hasNode("faqAnswerHome") && questionNode.getNode("faqAnswerHome").hasNodes()) {
for (String answer : getAnswers(questionNode))
content.append(" <b><u>Answer:</u></b> ").append(answer).append(". ");
}
if (questionNode.hasNode("faqCommentHome") && questionNode.getNode("faqCommentHome").hasNodes()) {
for (String comment : getComments(questionNode))
content.append(" <b><u>Comment:</u></b> ").append(comment).append(". ");
}
listContent.add(content.toString());
SyndContent description = new SyndContentImpl();
description.setType(RSS.PLAIN_TEXT);
final String questionNodeName = questionNode.getName();
PropertyReader question = new PropertyReader(questionNode);
description.setValue(question.string("exo:name") + ". " + content);
final String title = question.string("exo:title");
final Date created = question.date("exo:createdDate");
final String owner = question.string("exo:author");
SyndEntry entry = RSS.createNewEntry(questionNodeName, title, linkItem, listContent, description, created, owner);
entry.setLink(linkItem);
return entry;
}
private Node findQuestionNode(String nodePath) {
try {
Node questionNode = (Node) getCurrentSession().getItem(nodePath);
if (!questionNode.isNodeType("exo:faqQuestion") && !questionNode.isNodeType("exo:answer")
&& !questionNode.isNodeType("exo:answerHome") && !questionNode.isNodeType("exo:comment")
&& !questionNode.isNodeType("exo:commentHome"))
return null;
else if (questionNode.isNodeType("exo:answer") || questionNode.isNodeType("exo:comment")) {
questionNode = questionNode.getParent().getParent();
if (!questionNode.isNodeType("exo:faqQuestion"))
return null; // Worked on other languages
} else if (questionNode.isNodeType("exo:answerHome")
|| questionNode.isNodeType("exo:commentHome")) {
questionNode = questionNode.getParent();
if (!questionNode.isNodeType("exo:faqQuestion"))
return null; // Worked on other languages
}
if (!questionNode.isNodeType("exo:faqQuestion")) {
return null;
}
return questionNode;
} catch(Exception e) {
LOG.error("Failed to identify question Node for path" + nodePath, e);
return null;
}
}
List<String> getAnswers(Node questionNode) throws Exception{
List<String> listAnswers = new ArrayList<String>();
try{
if(questionNode.hasNode("faqAnswerHome")){
NodeIterator nodeIterator = questionNode.getNode("faqAnswerHome").getNodes();
Node answerNode = null;
int i = 0;
while(nodeIterator.hasNext()){
answerNode = nodeIterator.nextNode();
if(answerNode.hasProperty("exo:responses") && answerNode.getProperty("exo:approveResponses").getBoolean() &&
answerNode.getProperty("exo:activateResponses").getBoolean())
listAnswers.add((answerNode.getProperty("exo:responses").getValue().getString())) ;
i ++;
}
}
} catch (Exception e){
LOG.error("Failed to get answers for " + questionNode.getName(), e);
}
return listAnswers;
}
List<String> getComments(Node questionNode) throws Exception{
List<String> listComment = new ArrayList<String>();
try{
if(questionNode.hasNode("faqCommentHome")){
NodeIterator nodeIterator = questionNode.getNode("faqCommentHome").getNodes();
Node commentNode = null;
while(nodeIterator.hasNext()){
commentNode = nodeIterator.nextNode();
if(commentNode.hasProperty("exo:comments"))
listComment.add((commentNode.getProperty("exo:comments").getValue().getString())) ;
}
}
} catch (Exception e){
LOG.error("Failed to get comments for " + questionNode.getName(), e);
}
return listComment;
}
public InputStream getFeedContent(String targetId) {
return dataLocator.getSessionManager().executeAndSave(new GetFeedStreamTask(targetId));
}
class GetFeedStreamTask implements JCRTask<InputStream> {
private String targetId;
public GetFeedStreamTask(String targetId) {
this.targetId = targetId;
}
public InputStream execute(Session session) throws Exception {
Node parentNode = getAnswersServiceHome().getNode(targetId) ;
return getFeedStream(parentNode, FAQ_RSS_TYPE, "ANSWERS RSS FEED");
}
}
private Node getAnswersServiceHome() throws Exception {
String path = dataLocator.getFaqHomeLocation();
return dataLocator.getSessionManager().getCurrentSession().getRootNode().getNode(path);
}
public void itemRemoved(String path) {
dataLocator.getSessionManager().executeAndSave(new ItemRemovedTask(path));
}
class ItemRemovedTask implements JCRTask<VoidReturn> {
private String path;
public ItemRemovedTask(String path) {
this.path = path;
}
public VoidReturn execute(Session session) throws Exception {
try {
String categoryPath = path.substring(0, path.indexOf("/questions/"));
Node categoryNode = (Node) session.getItem(categoryPath);
if(categoryNode == null ) categoryNode = (Node) getCurrentSession().getItem(categoryPath);
while (!categoryNode.isNodeType("exo:faqCategory")) {
categoryNode = categoryNode.getParent();
}
String itemId = path.substring(path.lastIndexOf("/") + 1);
RSS rss = new RSS(categoryNode);
SyndFeed feed = rss.removeEntry(itemId);
String title = new PropertyReader(categoryNode).string("exo:name", "Root");
feed.setTitle(title);
rss.saveFeed(feed, FAQ_RSS_TYPE);
} catch (Exception e) {
LOG.debug("Failed to get RSS.", e);
}
return VoidReturn.VALUE;
}
}
}