package org.springmodules.feedxt.web.ajax.handler;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springmodules.feedxt.domain.Feed;
import org.springmodules.feedxt.domain.FeedSubscription;
import org.springmodules.feedxt.domain.User;
import org.springmodules.feedxt.domain.support.CannotAccessFeedException;
import org.springmodules.feedxt.domain.support.UserNotExistentException;
import org.springmodules.feedxt.web.controller.support.UserHolder;
import org.springmodules.feedxt.domain.Entry;
import org.springmodules.feedxt.service.UserService;
import org.springmodules.xt.ajax.AbstractAjaxHandler;
import org.springmodules.xt.ajax.AjaxActionEvent;
import org.springmodules.xt.ajax.AjaxResponse;
import org.springmodules.xt.ajax.AjaxResponseImpl;
import org.springmodules.xt.ajax.ElementMatcher;
import org.springmodules.xt.ajax.action.ExecuteJavascriptFunctionAction;
import org.springmodules.xt.ajax.action.ReplaceContentAction;
import org.springmodules.xt.ajax.action.SetAttributeAction;
import org.springmodules.xt.ajax.action.behaviour.ApplyBehaviour;
import org.springmodules.xt.ajax.action.matcher.SelectorMatcher;
import org.springmodules.xt.ajax.action.prototype.scriptaculous.Effect;
import org.springmodules.xt.ajax.component.Image;
import org.springmodules.xt.ajax.component.TaggedText;
import org.springmodules.xt.ajax.component.dynamic.JspComponent;
/**
* Ajax Handler for viewing feeds.
*
* @author Sergio Bossa
*/
public class FeedViewerHandler extends AbstractAjaxHandler implements MessageSourceAware {
private static final Logger logger = Logger.getLogger(FeedViewerHandler.class);
private UserHolder userHolder;
private UserService userService;
private MessageSource messageSource;
public void setUserHolder(UserHolder userHolder) {
this.userHolder = userHolder;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
public AjaxResponse viewFeed(AjaxActionEvent event) {
AjaxResponse response = new AjaxResponseImpl("UTF-8");
String subscriptionName = event.getParameters().get("subscription");
if (subscriptionName != null) {
try {
// Get the feed from user's subscriptions:
Feed feed = this.getFeedFromSubscriptionName(subscriptionName);
if (feed != null) {
// Render the feed via external JSP content:
event.getHttpRequest().setAttribute("feed", feed);
event.getHttpRequest().setAttribute("subscription", subscriptionName);
JspComponent jsp = new JspComponent(event.getHttpRequest(), "/personal/includes/feedPanel.page");
// Replace the content of the "viewer" page part:
ReplaceContentAction action1 = new ReplaceContentAction("viewer", jsp);
// Re-apply javascript Behaviour rules:
ApplyBehaviour action2 = new ApplyBehaviour();
// Add actions to response:
response.addAction(action1);
response.addAction(action2);
} else {
this.renderErrorMessage(event, response, "message.error.feed.not.found", "No feed found.");
}
} catch (UserNotExistentException ex) {
logger.warn(ex.getMessage(), ex.getCause());
this.renderErrorMessage(event, response, "message.error.reading.feed", "Error while reading the feed.");
} catch (CannotAccessFeedException ex) {
logger.warn(ex.getMessage(), ex.getCause());
this.renderErrorMessage(event, response, "message.error.reading.feed", "Error while reading the feed.");
}
}
return response;
}
public AjaxResponse toggleEntry(AjaxActionEvent event) {
AjaxResponse response = new AjaxResponseImpl("UTF-8");
String currentStatus = event.getParameters().get("status");
if (currentStatus != null && currentStatus.equals("closed")) {
response = this.showEntry(event);
} else if (currentStatus != null && currentStatus.equals("expanded")) {
response = this.hideEntry(event);
}
return response;
}
/**
* Show a feed entry.
*/
private AjaxResponse showEntry(AjaxActionEvent event) {
AjaxResponse response = new AjaxResponseImpl("UTF-8");
String subscriptionName = event.getParameters().get("subscription");
if (subscriptionName != null) {
try {
// Get the feed from user's subscriptions:
Feed feed = this.getFeedFromSubscriptionName(subscriptionName);
if (feed != null) {
// Get the feed entry at the corresponding index:
int entryIndex = Integer.parseInt(event.getParameters().get("entryIndex"));
Entry entry = (Entry) feed.getEntries().get(entryIndex);
// Set the entry object in the request:
event.getHttpRequest().setAttribute("entry", entry);
// Render the entry via external JSP content:
JspComponent jsp = new JspComponent(event.getHttpRequest(), "/personal/includes/entryPanel.page");
// Change the class of the web element that fired the event:
SetAttributeAction action1 = new SetAttributeAction(event.getElementId(), "class", "expanded");
// Construct the CSS selector identifying the web page part that will be updated with the JSP content:
String selector = new StringBuilder("#").append(event.getElementId()).append("~").append("div.entryBody").toString();
ElementMatcher matcher = new SelectorMatcher(Arrays.asList(selector));
// Replace the content of the web page part identified by the selector:
ReplaceContentAction action2 = new ReplaceContentAction(matcher, jsp);
// Call a client-side javascript function:
Map<String, Object> params = new HashMap<String, Object>();
params.put("selector", selector);
ExecuteJavascriptFunctionAction action3 = new ExecuteJavascriptFunctionAction("showEntryEffect", params);
// Add actions to response:
response.addAction(action1);
response.addAction(action2);
response.addAction(action3);
} else {
this.renderErrorMessage(event, response, "message.error.feed.not.found", "No feed found.");
}
} catch (UserNotExistentException ex) {
logger.warn(ex.getMessage(), ex.getCause());
this.renderErrorMessage(event, response, "message.error.reading.feed", "Error while reading the feed.");
} catch (CannotAccessFeedException ex) {
logger.warn(ex.getMessage(), ex.getCause());
this.renderErrorMessage(event, response, "message.error.reading.feed", "Error while reading the feed.");
}
}
return response;
}
/**
* Hide the feed entry: this could be completely done via pure client side javascript, but
* this is a sample application, so let us play a bit ;)
*/
private AjaxResponse hideEntry(AjaxActionEvent event) {
AjaxResponse response = new AjaxResponseImpl("UTF-8");
// Change the class of the web element that fired the event:
SetAttributeAction action1 = new SetAttributeAction(event.getElementId(), "class", "closed");
// Construct the CSS selector identifying the web page part that will be updated :
String selector = new StringBuilder("#").append(event.getElementId()).append("~").append("div.entryBody").toString();
ElementMatcher matcher = new SelectorMatcher(Arrays.asList(selector));
// Call a client-side javascript function for hiding the entry:
Map<String, Object> params = new HashMap<String, Object>();
params.put("selector", selector);
ExecuteJavascriptFunctionAction action2 = new ExecuteJavascriptFunctionAction("hideEntryEffect", params);
// Add actions to response:
response.addAction(action1);
response.addAction(action2);
return response;
}
private void renderErrorMessage(AjaxActionEvent event, AjaxResponse response, String messageCode, String defaultMessage) {
// If errors occur, render an error message with a proper icon:
String message = this.messageSource.getMessage(messageCode, null, defaultMessage, LocaleContextHolder.getLocale());
Image img = new Image(event.getHttpRequest().getContextPath() + "/images/error.gif", "error");
TaggedText txt = new TaggedText(message, TaggedText.Tag.SPAN);
// Put the message in its proper web page space:
ReplaceContentAction action1 = new ReplaceContentAction("message", img, txt);
// Shake the message:
Effect action2 = new Effect("Shake", "message");
// Add actions to response:
response.addAction(action1);
response.addAction(action2);
}
private Feed getFeedFromSubscriptionName(String name) throws UserNotExistentException, CannotAccessFeedException {
User user = this.userHolder.getUser();
FeedSubscription subscription = this.userService.getUserSubscriptionByName(user, name);
if (subscription != null) {
return subscription.getFeed();
} else {
return null;
}
}
}