org.jasig.portlet.notice.service.rome.RomeNotificationService.java Source code

Java tutorial

Introduction

Here is the source code for org.jasig.portlet.notice.service.rome.RomeNotificationService.java

Source

/**
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License.  You may obtain a
 * copy of the License at the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.jasig.portlet.notice.service.rome;

import java.io.IOException;
import java.net.URL;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.portlet.notice.NotificationAttribute;
import org.jasig.portlet.notice.NotificationCategory;
import org.jasig.portlet.notice.NotificationEntry;
import org.jasig.portlet.notice.NotificationError;
import org.jasig.portlet.notice.NotificationResponse;
import org.jasig.portlet.notice.service.AbstractNotificationService;
import org.jasig.portlet.notice.util.UsernameFinder;
import org.springframework.beans.factory.annotation.Autowired;

import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;

public final class RomeNotificationService extends AbstractNotificationService {

    public static final String URLS_PREFERENCE = "RomeNotificationService.urls";

    private static final Object NO_FURTHER_INFORMATION = "No further information is available.";
    private static final DateFormat DATE_FORMAT = DateFormat.getDateInstance(DateFormat.SHORT);

    private Cache cache;

    @Autowired
    private UsernameFinder usernameFinder;

    @Resource(name = "RomeNotificationService.feedCache")
    public void setCache(Cache cache) {
        this.cache = cache;
    }

    private final Log log = LogFactory.getLog(getClass());

    @Override
    public void invoke(final ActionRequest req, final ActionResponse res, final boolean refresh) {

        if (log.isDebugEnabled()) {
            log.debug("Performing RomeNotificationService.invoke() for user='" + usernameFinder.findUsername(req)
                    + "' refresh=" + refresh);
        }

        if (refresh) {
            final PortletPreferences prefs = req.getPreferences();
            final String[] urls = prefs.getValues(URLS_PREFERENCE, new String[0]);
            for (String item : urls) {
                cache.remove(item);
            }
        }

    }

    @Override
    public NotificationResponse fetch(final PortletRequest req) {

        final List<NotificationCategory> categories = new ArrayList<NotificationCategory>();
        final List<NotificationError> errors = new ArrayList<NotificationError>();

        final PortletPreferences prefs = req.getPreferences();
        final String[] urls = prefs.getValues(URLS_PREFERENCE, new String[0]);
        for (String item : urls) {

            // It's okay to pull a response from cache, if we have one, since refresh happens in invoke()
            final Element m = cache.get(item);
            if (m != null) {
                // ## CACHE HIT ##
                if (log.isDebugEnabled()) {
                    log.debug("Feed cache HIT for url:  " + item);
                }
                final NotificationCategory category = (NotificationCategory) m.getObjectValue();
                categories.add(category);
            } else {
                // ## CACHE MISS ##
                if (log.isDebugEnabled()) {
                    log.debug("Feed cache MISS for url:  " + item);
                    log.debug("Checking the following feed URL for notifications for user '"
                            + usernameFinder.findUsername(req) + "' -- " + item);
                }
                final NotificationCategory category = fetchFromSource(item);
                if (category != null) {
                    cache.put(new Element(item, category));
                    categories.add(category);
                } else {
                    final NotificationError error = new NotificationError();
                    error.setError("Service Unavailable");
                    error.setSource(getName());
                    errors.add(error);
                }
            }

        }

        final NotificationResponse rslt = new NotificationResponse();
        rslt.setCategories(categories);
        rslt.setErrors(errors);
        return rslt;

    }

    /*
     * Implementation
     */

    private NotificationCategory fetchFromSource(final String url) {

        NotificationCategory rslt = null; // default

        XmlReader reader = null;
        try {

            final URL u = new URL(url);

            reader = new XmlReader(u);
            final SyndFeedInput input = new SyndFeedInput();
            final SyndFeed feed = input.build(reader);

            rslt = new NotificationCategory();
            rslt.setTitle(feed.getTitle());

            final List<TimestampNotificationEntry> entries = new ArrayList<TimestampNotificationEntry>();

            @SuppressWarnings("unchecked")
            final List<SyndEntry> list = feed.getEntries();
            for (SyndEntry y : list) {

                if (log.isTraceEnabled()) {
                    log.trace("Processing SyndEntry:  \n" + y.toString());
                }

                final long timestamp = y.getPublishedDate().getTime();
                final TimestampNotificationEntry entry = new TimestampNotificationEntry(timestamp);

                // Strongly-typed members
                entry.setSource(feed.getAuthor());
                entry.setTitle(y.getTitle());
                entry.setUrl(y.getLink());
                // No priority
                // No due date
                // No image

                // Body
                final StringBuilder body = new StringBuilder();
                final SyndContent desc = y.getDescription();
                if (desc != null) {
                    // Prefer description
                    body.append(desc.getValue());
                }
                if (body.length() == 0) {
                    // Fall back to contents
                    @SuppressWarnings("unchecked")
                    final List<SyndContent> contents = y.getContents();
                    for (SyndContent c : contents) {
                        body.append(c.getValue());
                    }
                }
                if (body.length() == 0) {
                    // Last resort... 
                    body.append(NO_FURTHER_INFORMATION);
                }
                entry.setBody(body.toString());

                // Attributes -- TODO:  These labels should be internationalized in messages.properties
                final List<NotificationAttribute> attributes = new ArrayList<NotificationAttribute>();
                final String author = y.getAuthor();
                if (StringUtils.isNotBlank(author)) {
                    attributes.add(new NotificationAttribute("Author", author));
                }
                final Date publishedDate = y.getPublishedDate();
                if (publishedDate != null) {
                    attributes.add(new NotificationAttribute("Published date", DATE_FORMAT.format(publishedDate)));
                }
                final Date updatededDate = y.getUpdatedDate();
                if (updatededDate != null) {
                    attributes.add(new NotificationAttribute("Updated date", DATE_FORMAT.format(updatededDate)));
                }
                entry.setAttributes(attributes);

                entries.add(entry);

            }

            // Items should be in reverse chronological order
            Collections.sort(entries);
            Collections.reverse(entries);

            rslt.setEntries(new ArrayList<NotificationEntry>(entries));

        } catch (Exception e) {
            final String msg = "Unable to read the specified feed:  " + url;
            log.error(msg, e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException ioe) {
                    final String msg = "Unable to close the XmlReader";
                    log.error(msg, ioe);
                }
            }
        }

        return rslt;

    }

}