org.jamwiki.servlets.RecentChangesFeedServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.jamwiki.servlets.RecentChangesFeedServlet.java

Source

/**
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, version 2.1, dated February 1999.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the latest version of the GNU Lesser General
 * Public License as published by the Free Software Foundation;
 *
 * 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program (LICENSE.txt); if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.jamwiki.servlets;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.SyndFeedOutput;
import org.apache.commons.lang.StringUtils;
import org.jamwiki.Environment;
import org.jamwiki.WikiBase;
import org.jamwiki.model.RecentChange;
import org.jamwiki.utils.Pagination;
import org.jamwiki.utils.Utilities;
import org.jamwiki.utils.WikiLogger;
import org.jamwiki.utils.WikiUtil;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

/**
 * Provides an RSS or Atom feed for recent changes.
 *
 * Feed generation can be influenced through following request parameters:
 * <ul>
 * <li><code>feedType</code>: RSS or Atom (see
 * {@link #setDefaultFeedType(String)}) </li>
 * <li><code>minorEdits</code>: set to 'true' to include minor edits </li>
 * <li><code>num</code>: number of entries to return (see
 * {@link WikiUtil#buildPagination(HttpServletRequest)})</li>
 * </ul>
 *
 * @author Rainer Schmitz
 * @since 22.12.2006
 */
public class RecentChangesFeedServlet extends AbstractController {

    private static final WikiLogger logger = WikiLogger.getLogger(RecentChangesFeedServlet.class.getName());
    private static final String MIME_TYPE = "application/xml";
    private static final String FEED_ENCODING = "UTF-8";
    private static final String DEFAULT_FEED_TYPE = "rss_2.0";
    private static final String FEED_TYPE = "feedType";
    private static final String MINOR_EDITS = "minorEdits";
    private static final String LINK_TO_VERSION = "linkToVersion";
    private String defaultFeedType = DEFAULT_FEED_TYPE;
    private boolean defaultIncludeMinorEdits = false;
    private boolean defaultLinkToVersion = false;
    private String feedUrlPrefix = "";

    /**
     * Sets the default feed type.
     *
     * Valid values are rss_0.92, rss_0.93, rss_0.94, rss_1.0, rss_2.0,
     * atom_0.3, and atom_1.0.
     *
     * This value is used if no feed type is given in the request (parameter
     * 'feedType'). Default is rss_2.0.
     *
     * @param defaultFeedType
     *            The defaultFeedType to set.
     */
    public void setDefaultFeedType(String defaultFeedType) {
        this.defaultFeedType = defaultFeedType;
    }

    /**
     * Sets whether minor edits are included in generated feed.
     *
     * This value can be overriden by the request parameter 'minorEdits'.
     * Default is false.
     *
     * @param includeMinorEdits
     *            <code>true</code> if minor edits shall be included in feed.
     */
    public void setDefaultIncludeMinorEdits(boolean includeMinorEdits) {
        this.defaultIncludeMinorEdits = includeMinorEdits;
    }

    /**
     * Sets whether feed entry link should link to the changed or to the current
     * version of the changed entry.
     *
     * This value can be overriden by the request parameter 'linkToVersion'.
     * Default is false.
     *
     * @param feedUrlPrefix feed URL prefix to set; may not be null.
     */
    public void setFeedUrlPrefix(String feedUrlPrefix) {
        if (feedUrlPrefix == null) {
            throw new IllegalArgumentException("Feed URL prefix may not be null");
        }
        this.feedUrlPrefix = feedUrlPrefix;
    }

    /**
     * Prefix to use in feed and feed entry links.
     *
     * This is useful in portal environments to prefix the feed URL with the portal URL.
     *
     * @param linkToVersion
     *            <code>true</code> if link should point to edited version.
     */
    public void setDefaultLinkToVersion(boolean linkToVersion) {
        this.defaultLinkToVersion = linkToVersion;
    }

    /**
     * Handle the servlet request, generating appropriate output.
     *
     * @see org.springframework.web.servlet.mvc.AbstractController#handleRequestInternal(javax.servlet.http.HttpServletRequest,
     *      javax.servlet.http.HttpServletResponse)
     */
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        try {
            String feedType = ServletRequestUtils.getStringParameter(request, FEED_TYPE, defaultFeedType);
            logger.finer("Serving xml feed of type " + feedType);
            SyndFeed feed = getFeed(request);
            feed.setFeedType(feedType);
            response.setContentType(MIME_TYPE);
            response.setCharacterEncoding(FEED_ENCODING);
            SyndFeedOutput output = new SyndFeedOutput();
            output.output(feed, response.getWriter());
        } catch (Exception e) {
            logger.severe("Could not generate feed: " + e.getMessage(), e);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                    "Could not generate feed: " + e.getMessage());
        }
        return null;
    }

    /**
     * TODO cache feed to avoid high load caused by RSS aggregators
     *
     * @throws Exception
     */
    private SyndFeed getFeed(HttpServletRequest request) throws Exception {
        List<RecentChange> changes = getChanges(request);
        SyndFeed feed = new SyndFeedImpl();
        feed.setEncoding(FEED_ENCODING);
        feed.setTitle(Environment.getValue(Environment.PROP_RSS_TITLE));
        StringBuffer requestURL = request.getRequestURL();
        String feedURL = feedUrlPrefix
                + requestURL.substring(0, requestURL.length() - WikiUtil.getTopicFromURI(request).length());
        feed.setLink(feedURL);
        feed.setDescription("List of the last " + changes.size() + " changed wiki pages.");
        boolean includeMinorEdits = ServletRequestUtils.getBooleanParameter(request, MINOR_EDITS,
                defaultIncludeMinorEdits);
        boolean linkToVersion = ServletRequestUtils.getBooleanParameter(request, LINK_TO_VERSION,
                defaultLinkToVersion);
        feed.setEntries(getFeedEntries(changes, includeMinorEdits, linkToVersion, feedURL));
        return feed;
    }

    /**
     *
     */
    private List<SyndEntry> getFeedEntries(List<RecentChange> changes, boolean includeMinorEdits,
            boolean linkToVersion, String feedURL) {
        List<SyndEntry> entries = new ArrayList<SyndEntry>();
        for (RecentChange change : changes) {
            // FIXME - add support for log item changes
            if (!StringUtils.isBlank(change.getTopicName()) && (includeMinorEdits || !change.getMinor())) {
                entries.add(getFeedEntry(change, linkToVersion, feedURL));
            }
        }
        return entries;
    }

    /**
     *
     */
    private SyndEntry getFeedEntry(RecentChange change, boolean linkToVersion, String feedURL) {
        SyndContent description;
        SyndEntry entry = new SyndEntryImpl();
        entry.setTitle(change.getTopicName());
        entry.setAuthor(change.getAuthorName());
        entry.setPublishedDate(change.getChangeDate());
        description = new SyndContentImpl();
        description.setType("text/plain");
        StringBuffer descr = new StringBuffer();
        if (!StringUtils.isBlank(change.getChangeComment())) {
            descr.append(change.getChangeComment());
        }
        if (change.isDelete()) {
            descr.append(" (deleted)");
        } else {
            if (linkToVersion) {
                try {
                    String url = feedURL + URLEncoder
                            .encode("Special:History?topicVersionId=" + change.getTopicVersionId() + "&topic="
                                    + Utilities.encodeAndEscapeTopicName(change.getTopicName()), "UTF-8");
                    entry.setLink(url);
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } else {
                entry.setLink(feedURL + Utilities.encodeAndEscapeTopicName(change.getTopicName()));
            }
        }
        if (change.isUndelete()) {
            descr.append(" (undeleted)");
        }
        if (change.getMinor()) {
            descr.append(" (minor)");
        }
        description.setValue(descr.toString());
        entry.setDescription(description);
        // URI is used as GUID in RSS 2.0 and should therefore contain the
        // version id
        entry.setUri(feedURL + Utilities.encodeAndEscapeTopicName(change.getTopicName()) + "#"
                + change.getTopicVersionId());
        return entry;
    }

    /**
     *
     */
    private List<RecentChange> getChanges(HttpServletRequest request) throws Exception {
        String virtualWiki = WikiUtil.getVirtualWikiFromURI(request);
        Pagination pagination = WikiUtil.buildPagination(request);
        return WikiBase.getDataHandler().getRecentChanges(virtualWiki, pagination, true);
    }
}