Index: src/main/java/info/magnolia/module/rssaggregator/servlet/FeedSyndicationServlet.java
===================================================================
--- src/main/java/info/magnolia/module/rssaggregator/servlet/FeedSyndicationServlet.java Sun Feb 22 21:11:08 CET 2009
+++ src/main/java/info/magnolia/module/rssaggregator/servlet/FeedSyndicationServlet.java Sun Feb 22 21:11:08 CET 2009
@@ -0,0 +1,163 @@
+/**
+ * This file Copyright (c) 2008-2009 Magnolia International
+ * Ltd. (http://www.magnolia-cms.com). All rights reserved.
+ *
+ *
+ * This file is dual-licensed under both the Magnolia
+ * Network Agreement and the GNU General Public License.
+ * You may elect to use one or the other of these licenses.
+ *
+ * This file is distributed in the hope that it will be
+ * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
+ * Redistribution, except as permitted by whichever of the GPL
+ * or MNA you select, is prohibited.
+ *
+ * 1. For the GPL license (GPL), you can redistribute and/or
+ * modify this file under the terms of the GNU General
+ * Public License, Version 3, as published by the Free Software
+ * Foundation. You should have received a copy of the GNU
+ * General Public License, Version 3 along with this program;
+ * if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 2. For the Magnolia Network Agreement (MNA), this file
+ * and the accompanying materials are made available under the
+ * terms of the MNA which accompanies this distribution, and
+ * is available at http://www.magnolia-cms.com/mna.html
+ *
+ * Any modifications to this file must keep this entire header
+ * intact.
+ *
+ */
+package info.magnolia.module.rssaggregator.servlet;
+
+import info.magnolia.cms.core.Content;
+import info.magnolia.cms.core.ItemType;
+import info.magnolia.content2bean.Content2BeanException;
+import info.magnolia.content2bean.Content2BeanUtil;
+import info.magnolia.module.rssaggregator.generator.Feed;
+import info.magnolia.module.rssaggregator.generator.FeedGenerator;
+import info.magnolia.module.rssaggregator.generator.FeedGeneratorFactory;
+import info.magnolia.module.rssaggregator.generator.FeedGeneratorResolver;
+import info.magnolia.module.rssaggregator.util.Assert;
+import info.magnolia.module.rssaggregator.util.MagnoliaQueryOperations;
+import info.magnolia.module.rssaggregator.util.MagnoliaTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import static java.lang.String.*;
+import java.util.Map;
+
+/**
+ * Writes an XML feed to the response. Based on the given request parameters, a FeedGenerator will be resolved and is
+ * used for generating an XML feed. The content of the feed will be written to the response with the appropriate
+ * character encoding.
+ *
+ * @author Rob van der Linden Vooren
+ * @see FeedGeneratorResolver
+ * @see FeedGenerator
+ */
+public class FeedSyndicationServlet extends AbstractServlet {
+
+ protected Logger logger = LoggerFactory.getLogger(getClass());
+
+ private FeedGeneratorResolver feedGeneratorResolver;
+ private MagnoliaQueryOperations magnoliaTemplate;
+
+ /** Construct a new AggregateFeedSyndicationController initialized with a {@link FeedGeneratorResolver}. */
+ public FeedSyndicationServlet() {
+ feedGeneratorResolver = new FeedGeneratorResolver();
+ magnoliaTemplate = new MagnoliaTemplate();
+ }
+
+ @Override
+ public void init() throws ServletException {
+ try {
+ registerConfiguredFeedGeneratorFactories();
+ } catch (Exception e) {
+ throw new ServletException("Failed to register feed generator factories", e);
+ }
+ }
+
+ /**
+ * Retrieve and register {@link FeedGeneratorFactory}s that have been configured through the Magnolia Admin
+ * Interface under a generators node. Each content node under the "generators" node, represents a
+ * FeedGeneratorFactory to register. The name of such a node is its "generatorName". Each FeedGeneratorFactory has a
+ * "class" property as well, which holds the fully qualified name of the class of the FeedGeneratorFactory. A
+ * configured node should like this:
+ *
+ * /modules/rssaggregator/config/generators <- generators
+ * /rss < FeedGeneratoryFactory named "rss"
+ * /class < FeedGeneratoryFactory FQN class
+ * /news < FeedGeneratoryFactory named "news"
+ * /class < FeedGeneratoryFactory FQN class
+ * /...etc
+ *
+ * Note that you can have an any numbers of FeedGeneratorFactories configured you want.
+ */
+ protected void registerConfiguredFeedGeneratorFactories() {
+ Map feedGeneratorFactories = loadFeedGeneratorFactories();
+ for (Map.Entry entry : feedGeneratorFactories.entrySet()) {
+ String name = entry.getKey();
+ FeedGeneratorFactory factory = entry.getValue();
+ feedGeneratorResolver.registerFeedGeneratorFactory(name, factory);
+ if (logger.isInfoEnabled()) {
+ logger.info(format("Registered FeedGeneratorFactory '%s' for name '%s'",
+ factory.getClass().getName(), name));
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Map loadFeedGeneratorFactories() {
+ String query = "/jcr:root/modules/rssaggregator/config/generators";
+ Content generatorsNode = magnoliaTemplate.xpathQueryForContent("config", query, ItemType.CONTENTNODE);
+ try {
+ return Content2BeanUtil.toMap(generatorsNode, true, Map.class);
+ } catch (Content2BeanException c2be) {
+ throw new RuntimeException(format("Failed to convert generators node '%s'", query), c2be);
+ }
+ }
+
+ public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
+ @SuppressWarnings("unchecked")
+ FeedGenerator generator = feedGeneratorResolver.resolve(request.getParameterMap());
+ Feed feed = generator.generate();
+ writeToResponse(feed.getXml(), feed.getCharacterEncoding(), response);
+ }
+
+ /**
+ * Write the given content to the response.
+ *
+ * @param content the content to write
+ * @param characterEncoding the character encoding to use
+ * @param response the response to write to
+ * @throws IOException if an IOException occurs
+ */
+ protected void writeToResponse(String content, String characterEncoding, HttpServletResponse response) throws IOException {
+ response.setCharacterEncoding(characterEncoding);
+ response.setContentType("text/xml");
+ PrintWriter writer = response.getWriter();
+ writer.write((content == null) ? "" : content);
+ writer.flush();
+ writer.close();
+ }
+
+ /**
+ * Set the {@link FeedGeneratorResolver} used for resolving the FeedGenerators.
+ *
+ * @param feedGeneratorResolver the generator resolver to be used (must not be null)
+ * @throws IllegalArgumentException if the given {@code generatorResolver} is null
+ */
+ public void setFeedGeneratorResolver(FeedGeneratorResolver feedGeneratorResolver) {
+ Assert.notNull(feedGeneratorResolver, "'feedGeneratorResolver' must not be null");
+ this.feedGeneratorResolver = feedGeneratorResolver;
+ }
+}
Index: src/main/java/info/magnolia/module/rssaggregator/importhandler/AggregateFilter.java
===================================================================
--- src/main/java/info/magnolia/module/rssaggregator/importhandler/AggregateFilter.java (revision 22801)
+++ src/main/java/info/magnolia/module/rssaggregator/importhandler/AggregateFilter.java Sun Feb 22 19:43:18 CET 2009
@@ -53,7 +53,7 @@
*/
public class AggregateFilter {
- private Logger log = LoggerFactory.getLogger(AggregateFilter.class);
+ private Logger logger = LoggerFactory.getLogger(getClass());
private final Set filters;
@@ -71,8 +71,8 @@
try {
propertyValue = MethodUtils.invokeExactMethod(entry, getterName, null);
} catch (Exception e) {
- if (log.isWarnEnabled()) {
- log.warn("Property {} can't be retrieved from the feed and will be treated as if it was empty during filtering", property);
+ if (logger.isWarnEnabled()) {
+ logger.warn("Property {} can't be retrieved from the feed and will be treated as if it was empty during filtering", property);
}
}
String regularExpression = filter.getRegularExpression();
Index: src/main/java/info/magnolia/module/rssaggregator/importhandler/FilterPredicateContentMapper.java
===================================================================
--- src/main/java/info/magnolia/module/rssaggregator/importhandler/FilterPredicateContentMapper.java (revision 22801)
+++ src/main/java/info/magnolia/module/rssaggregator/importhandler/FilterPredicateContentMapper.java Sat Feb 21 20:58:09 CET 2009
@@ -34,10 +34,11 @@
package info.magnolia.module.rssaggregator.importhandler;
import info.magnolia.cms.core.Content;
-import static info.magnolia.module.rssaggregator.importhandler.FilterPredicate.*;
+import static info.magnolia.module.rssaggregator.importhandler.FilterPredicate.Condition;
+import info.magnolia.module.rssaggregator.util.ContentMapper;
import org.apache.commons.lang.StringUtils;
-import static java.util.Arrays.*;
+import static java.util.Arrays.asList;
/**
* Maps a content node representing a {@link FilterPredicate} to a FilterPredicate.
Index: src/main/resources/mgnl-bootstrap/rssaggregator/config.modules.data.config.importers.rssaggregator.xml
===================================================================
--- src/main/resources/mgnl-bootstrap/rssaggregator/config.modules.data.config.importers.rssaggregator.xml (revision 22801)
+++ src/main/resources/mgnl-bootstrap/rssaggregator/config.modules.data.config.importers.rssaggregator.xml Sat Feb 21 21:08:53 CET 2009
@@ -2,8 +2,8 @@
+ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn_old="http://www.w3.org/2004/10/xpath-functions"
+ xmlns:sv="http://www.jcp.org/jcr/sv/1.0" xmlns:jcrfn="http://www.jcp.org/jcr/xpath-functions/1.0">
mgnl:contentNode
@@ -19,9 +19,6 @@
false
-
- info.magnolia.module.rssaggregator.importhandler.SimpleRSSFeedFetcher
- data
@@ -45,7 +42,7 @@
2008-07-03T07:03:50.946+02:00
- 2009-02-02T22:21:41.334+01:00
+ 2009-02-21T21:06:53.484+01:00
@@ -149,8 +146,39 @@
2008-07-03T07:03:50.962+02:00
- 2009-02-02T22:21:35.576+01:00
+ 2009-02-21T21:07:30.375+01:00
+
+
+ mgnl:contentNode
+
+
+ mix:lockable
+
+
+ a30106a2-2000-485d-b03b-66faebf8b85e
+
+
+ info.magnolia.module.rssaggregator.importhandler.FastRSSFeedFetcher
+
+
+
+ mgnl:metaData
+
+
+ superuser
+
+
+ 2009-02-15T13:44:19.375+01:00
+
+
+ 2009-02-21T21:08:07.328+01:00
+
+
+
+
-
+
+
+
Index: src/main/java/info/magnolia/module/rssaggregator/generator/AbstractSyndFeedGenerator.java
===================================================================
--- src/main/java/info/magnolia/module/rssaggregator/generator/AbstractSyndFeedGenerator.java Sun Feb 22 21:16:11 CET 2009
+++ src/main/java/info/magnolia/module/rssaggregator/generator/AbstractSyndFeedGenerator.java Sun Feb 22 21:16:11 CET 2009
@@ -0,0 +1,125 @@
+/**
+ * This file Copyright (c) 2008-2009 Magnolia International
+ * Ltd. (http://www.magnolia-cms.com). All rights reserved.
+ *
+ *
+ * This file is dual-licensed under both the Magnolia
+ * Network Agreement and the GNU General Public License.
+ * You may elect to use one or the other of these licenses.
+ *
+ * This file is distributed in the hope that it will be
+ * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
+ * Redistribution, except as permitted by whichever of the GPL
+ * or MNA you select, is prohibited.
+ *
+ * 1. For the GPL license (GPL), you can redistribute and/or
+ * modify this file under the terms of the GNU General
+ * Public License, Version 3, as published by the Free Software
+ * Foundation. You should have received a copy of the GNU
+ * General Public License, Version 3 along with this program;
+ * if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 2. For the Magnolia Network Agreement (MNA), this file
+ * and the accompanying materials are made available under the
+ * terms of the MNA which accompanies this distribution, and
+ * is available at http://www.magnolia-cms.com/mna.html
+ *
+ * Any modifications to this file must keep this entire header
+ * intact.
+ *
+ */
+package info.magnolia.module.rssaggregator.generator;
+
+import com.sun.syndication.feed.synd.SyndEntry;
+import com.sun.syndication.feed.synd.SyndFeed;
+import com.sun.syndication.feed.synd.SyndFeedImpl;
+import com.sun.syndication.io.FeedException;
+import com.sun.syndication.io.SyndFeedOutput;
+import info.magnolia.module.rssaggregator.util.Assert;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static java.lang.String.*;
+import java.util.List;
+
+/**
+ * Convenience base class providing plumbing required for generating a Feed from a {@link SyndFeed}. The generated feed
+ * will by default be of type "{@value #DEFAULT_FEEDTYPE}". Subclasses need implement the template methods {@link
+ * #loadFeedEntries()} and {@link #setFeedInfo(SyndFeed)} to have a Feed generated.
+ *
+ * @author Rob van der Linden Vooren
+ * @see FeedGenerator
+ * @see SyndFeed
+ * @see Feed
+ */
+public abstract class AbstractSyndFeedGenerator implements FeedGenerator {
+
+ protected static final String DEFAULT_FEEDTYPE = "rss_2.0";
+ protected static final String DEFAULT_ENCODING = "UTF-8";
+
+ protected Logger logger = LoggerFactory.getLogger(getClass());
+
+ /**
+ * Generate a SyndFeed.
+ *
+ * @return the generated SyndFeed
+ * @throws FeedGenerationException when an exception occurs while generating the aggregate feed
+ */
+ public Feed generate() throws FeedGenerationException {
+ try {
+ SyndFeed syndFeed = newSyndFeed();
+ syndFeed.setFeedType(DEFAULT_FEEDTYPE);
+ syndFeed.setEntries(loadFeedEntries());
+ setFeedInfo(syndFeed);
+
+ String xml = syndFeedToXml(syndFeed);
+ return new Feed(xml, DEFAULT_ENCODING);
+ } catch (Exception e) {
+ String message = format("Failed to generate Feed using generator '%s'", getClass().getName());
+ logger.error(message, e);
+ throw new FeedGenerationException(message, e);
+ }
+ }
+
+ protected String syndFeedToXml(SyndFeed feed) throws FeedException {
+ SyndFeedOutput feedOutput = new SyndFeedOutput();
+ return feedOutput.outputString(feed);
+ }
+
+ /**
+ * Construct a new SyndFeed instance.
+ *
+ * @return the new SyndFeed instance
+ */
+ protected SyndFeedImpl newSyndFeed() {
+ return new SyndFeedImpl();
+ }
+
+ /**
+ * Template method for subclasses to implement in order to provide the feed entries to include in the Feed to
+ * generate.
+ *
+ * @return the feed entries to include in the Feed to generate
+ */
+ public abstract List loadFeedEntries();
+
+ /**
+ * Template method for subclasses are to override in order to set appropriate Feed meta data. Typical use cases
+ * would be to set the {@link SyndFeed#setTitle(String) title} , {@link SyndFeed#setLink(String) link} and {@link
+ * SyndFeed#setDescription(String) description}. The given {@code feed} will never be null.
+ *
+ * @param feed the syndication feed that is generated to set the feed meta data for
+ */
+ public abstract void setFeedInfo(SyndFeed feed);
+
+ // Getters & setters
+
+ /** for testing */
+ protected void setLogger(Logger logger) {
+ Assert.notNull(logger, "'logger' must not be null");
+ this.logger = logger;
+ }
+}
Index: src/main/java/info/magnolia/module/rssaggregator/servlet/AbstractServlet.java
===================================================================
--- src/main/java/info/magnolia/module/rssaggregator/servlet/AbstractServlet.java Sun Feb 22 11:29:41 CET 2009
+++ src/main/java/info/magnolia/module/rssaggregator/servlet/AbstractServlet.java Sun Feb 22 11:29:41 CET 2009
@@ -0,0 +1,101 @@
+/**
+ * This file Copyright (c) 2008-2009 Magnolia International
+ * Ltd. (http://www.magnolia-cms.com). All rights reserved.
+ *
+ *
+ * This file is dual-licensed under both the Magnolia
+ * Network Agreement and the GNU General Public License.
+ * You may elect to use one or the other of these licenses.
+ *
+ * This file is distributed in the hope that it will be
+ * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
+ * Redistribution, except as permitted by whichever of the GPL
+ * or MNA you select, is prohibited.
+ *
+ * 1. For the GPL license (GPL), you can redistribute and/or
+ * modify this file under the terms of the GNU General
+ * Public License, Version 3, as published by the Free Software
+ * Foundation. You should have received a copy of the GNU
+ * General Public License, Version 3 along with this program;
+ * if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 2. For the Magnolia Network Agreement (MNA), this file
+ * and the accompanying materials are made available under the
+ * terms of the MNA which accompanies this distribution, and
+ * is available at http://www.magnolia-cms.com/mna.html
+ *
+ * Any modifications to this file must keep this entire header
+ * intact.
+ *
+ */
+package info.magnolia.module.rssaggregator.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Convenience base servlet for simple request handling. As such provides a {@link #handleRequest(HttpServletRequest,
+ * HttpServletResponse) main entry point} for handling POST and GET requests.
+ *
+ * @author Rob van der Linden Vooren
+ */
+public abstract class AbstractServlet extends HttpServlet {
+
+ /**
+ * Delegate POST requests to {@link #processRequest}.
+ *
+ * @see #handleRequest
+ */
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ processRequest(request, response);
+ }
+
+ /**
+ * Delegate GET requests to {@link #processRequest}.
+ *
+ * @see #handleRequest
+ */
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ processRequest(request, response);
+ }
+
+ /**
+ * Delegates to template method {@link #handleRequest(HttpServletRequest, HttpServletResponse) handleRequest} which
+ * handles actual handling of the request. Additionaly wraps exceptions other than IOException and ServletException
+ * in a ServletException.
+ *
+ * @param request the request to handle
+ * @param response the associated response
+ * @throws IOException if an input or output error is detected when the servlet handles the request
+ * @throws ServletException if the request could not be handled
+ */
+ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ try {
+ handleRequest(request, response);
+ } catch (ServletException se) {
+ throw se;
+ } catch (IOException ioe) {
+ throw ioe;
+ } catch (Throwable t) {
+ throw new ServletException("Failed to process request", t);
+ }
+ }
+
+ /**
+ * Subclass need implement this method in order to handle the request.
+ *
+ * @param request the request to handle
+ * @param response the associated response
+ * @throws Exception if an exception occurs during request handling
+ */
+ public abstract void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
+
+}
Index: src/main/java/info/magnolia/module/rssaggregator/generator/FeedGenerationException.java
===================================================================
--- src/main/java/info/magnolia/module/rssaggregator/generator/FeedGenerationException.java Sun Feb 22 21:14:53 CET 2009
+++ src/main/java/info/magnolia/module/rssaggregator/generator/FeedGenerationException.java Sun Feb 22 21:14:53 CET 2009
@@ -0,0 +1,46 @@
+/**
+ * This file Copyright (c) 2008-2009 Magnolia International
+ * Ltd. (http://www.magnolia-cms.com). All rights reserved.
+ *
+ *
+ * This file is dual-licensed under both the Magnolia
+ * Network Agreement and the GNU General Public License.
+ * You may elect to use one or the other of these licenses.
+ *
+ * This file is distributed in the hope that it will be
+ * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
+ * Redistribution, except as permitted by whichever of the GPL
+ * or MNA you select, is prohibited.
+ *
+ * 1. For the GPL license (GPL), you can redistribute and/or
+ * modify this file under the terms of the GNU General
+ * Public License, Version 3, as published by the Free Software
+ * Foundation. You should have received a copy of the GNU
+ * General Public License, Version 3 along with this program;
+ * if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 2. For the Magnolia Network Agreement (MNA), this file
+ * and the accompanying materials are made available under the
+ * terms of the MNA which accompanies this distribution, and
+ * is available at http://www.magnolia-cms.com/mna.html
+ *
+ * Any modifications to this file must keep this entire header
+ * intact.
+ *
+ */
+package info.magnolia.module.rssaggregator.generator;
+
+/**
+ * Thrown when an exception occurs while generating a feed.
+ *
+ * @author Rob van der Linden Vooren
+ */
+public class FeedGenerationException extends RuntimeException {
+
+ public FeedGenerationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: src/test/java/info/magnolia/module/rssaggregator/importhandler/SimpleRSSFeedFetcherTest.java
===================================================================
--- src/test/java/info/magnolia/module/rssaggregator/importhandler/SimpleRSSFeedFetcherTest.java (revision 22801)
+++ src/test/java/info/magnolia/module/rssaggregator/importhandler/SimpleRSSFeedFetcherTest.java Sun Feb 22 19:21:11 CET 2009
@@ -45,7 +45,6 @@
import java.util.Set;
-
/**
* Tests {@link SimpleRSSFeedFetcher}.
*
@@ -54,7 +53,7 @@
public class SimpleRSSFeedFetcherTest {
private SimpleRSSFeedFetcher feedFetcher;
- private Logger logger = LoggerFactory.getLogger(SimpleRSSFeedFetcherTest.class);
+ private Logger logger = LoggerFactory.getLogger(getClass());
@Before
public void before() {
@@ -77,7 +76,7 @@
expect(feedFetcher.fetchFeedChannel(channel)).andReturn(expectedFetchResult);
replay(feedFetcher);
- Set fetchedAggregates = feedFetcher.fetchAggregate(aggregates);
+ Set fetchedAggregates = feedFetcher.fetchAggregateFeeds(aggregates);
verify(feedFetcher);
AggregateFeed fetchedAggregateFeed = fetchedAggregates.iterator().next();
Index: src/test/java/info/magnolia/module/rssaggregator/servlet/FeedSyndicationServletTest.java
===================================================================
--- src/test/java/info/magnolia/module/rssaggregator/servlet/FeedSyndicationServletTest.java Sun Feb 22 18:51:26 CET 2009
+++ src/test/java/info/magnolia/module/rssaggregator/servlet/FeedSyndicationServletTest.java Sun Feb 22 18:51:26 CET 2009
@@ -0,0 +1,94 @@
+/**
+ * This file Copyright (c) 2008-2009 Magnolia International
+ * Ltd. (http://www.magnolia-cms.com). All rights reserved.
+ *
+ *
+ * This file is dual-licensed under both the Magnolia
+ * Network Agreement and the GNU General Public License.
+ * You may elect to use one or the other of these licenses.
+ *
+ * This file is distributed in the hope that it will be
+ * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
+ * Redistribution, except as permitted by whichever of the GPL
+ * or MNA you select, is prohibited.
+ *
+ * 1. For the GPL license (GPL), you can redistribute and/or
+ * modify this file under the terms of the GNU General
+ * Public License, Version 3, as published by the Free Software
+ * Foundation. You should have received a copy of the GNU
+ * General Public License, Version 3 along with this program;
+ * if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 2. For the Magnolia Network Agreement (MNA), this file
+ * and the accompanying materials are made available under the
+ * terms of the MNA which accompanies this distribution, and
+ * is available at http://www.magnolia-cms.com/mna.html
+ *
+ * Any modifications to this file must keep this entire header
+ * intact.
+ *
+ */
+package info.magnolia.module.rssaggregator.servlet;
+
+import info.magnolia.module.rssaggregator.generator.Feed;
+import info.magnolia.module.rssaggregator.generator.FeedGenerator;
+import info.magnolia.module.rssaggregator.generator.FeedGeneratorResolver;
+import static org.easymock.classextension.EasyMock.*;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import static java.util.Collections.*;
+import java.util.Map;
+
+/**
+ * Tests {@link FeedSyndicationServlet}.
+ *
+ * @author Rob van der Linden Vooren
+ */
+public class FeedSyndicationServletTest {
+
+ private FeedSyndicationServlet servlet;
+ private HttpServletRequest mockRequest;
+ private HttpServletResponse mockResponse;
+ private FeedGeneratorResolver mockFeedGeneratorResolver;
+ private FeedGenerator mockFeedGenerator;
+
+ @Before
+ public void before() {
+ servlet = new FeedSyndicationServlet();
+ mockRequest = createMock("mockHttpServletRequest", HttpServletRequest.class);
+ mockResponse = createMock("mockHttpServletResponse", HttpServletResponse.class);
+ mockFeedGeneratorResolver = createMock("mockFeedGeneratorResolver", FeedGeneratorResolver.class);
+ mockFeedGenerator = createMock("mockFeedGenerator", FeedGenerator.class);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testHandleRequest() throws Exception {
+ servlet = createMock("partialMockFeedSyndicationServlet", FeedSyndicationServlet.class,
+ FeedSyndicationServlet.class.getDeclaredMethod("writeToResponse", String.class, String.class,
+ HttpServletResponse.class)
+ );
+ servlet.setFeedGeneratorResolver(mockFeedGeneratorResolver);
+
+ final String content = "";
+ final String encoding = "UTF-8";
+ final Feed expectedFeed = new Feed(content, encoding);
+ final Map expectedParameters = emptyMap();
+
+ expect(mockRequest.getParameterMap()).andReturn(expectedParameters);
+ expect(mockFeedGeneratorResolver.resolve(expectedParameters)).andReturn(mockFeedGenerator);
+ expect(mockFeedGenerator.generate()).andReturn(expectedFeed);
+ servlet.writeToResponse(content, encoding, mockResponse);
+ replay(mockRequest, mockFeedGeneratorResolver, mockFeedGenerator, servlet);
+
+ servlet.handleRequest(mockRequest, mockResponse);
+
+ verify(mockRequest, mockFeedGeneratorResolver, mockFeedGenerator, servlet);
+ }
+}
Index: src/main/resources/META-INF/magnolia/rssaggregator.xml
===================================================================
--- src/main/resources/META-INF/magnolia/rssaggregator.xml (revision 22801)
+++ src/main/resources/META-INF/magnolia/rssaggregator.xml Sun Feb 22 19:52:12 CET 2009
@@ -1,31 +1,44 @@
- rssaggregator
- RSS Aggregator
- info.magnolia.module.rssaggregator.RSSAggregator
- info.magnolia.module.rssaggregator.RSSAggregatorVersionHandler
- ${project.version}
+ rssaggregator
+ RSS Aggregator
+ info.magnolia.module.rssaggregator.RSSAggregator
+ info.magnolia.module.rssaggregator.RSSAggregatorVersionHandler
+ ${project.version}
-
-
- info.magnolia.module.rssaggregator.importhandler.RSSFeedFetcher
- info.magnolia.module.rssaggregator.importhandler.SimpleRSSFeedFetcher
-
-
+
+
+ info.magnolia.module.rssaggregator.importhandler.RSSFeedFetcher
+ info.magnolia.module.rssaggregator.importhandler.SimpleRSSFeedFetcher
+
+
+
-
-
- core
- 4.0/*
-
-
- observation
- 1.1/*
- true
-
-
- data
- 1.3/*
-
-
+
+
+ core
+ 4.0/*
+
+
+ observation
+ 1.1/*
+ true
+
+
+ data
+ 1.3/*
+
+
+
+
+
+ FeedSyndicationServlet
+ info.magnolia.module.rssaggregator.servlet.FeedSyndicationServlet
+ Responsible for RSS Feed syndication
+
+ /rss
+
+
+
+
Index: src/main/java/info/magnolia/module/rssaggregator/generator/FeedGeneratorConstructionException.java
===================================================================
--- src/main/java/info/magnolia/module/rssaggregator/generator/FeedGeneratorConstructionException.java Sun Feb 22 19:49:06 CET 2009
+++ src/main/java/info/magnolia/module/rssaggregator/generator/FeedGeneratorConstructionException.java Sun Feb 22 19:49:06 CET 2009
@@ -0,0 +1,47 @@
+/**
+ * This file Copyright (c) 2008-2009 Magnolia International
+ * Ltd. (http://www.magnolia-cms.com). All rights reserved.
+ *
+ *
+ * This file is dual-licensed under both the Magnolia
+ * Network Agreement and the GNU General Public License.
+ * You may elect to use one or the other of these licenses.
+ *
+ * This file is distributed in the hope that it will be
+ * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
+ * Redistribution, except as permitted by whichever of the GPL
+ * or MNA you select, is prohibited.
+ *
+ * 1. For the GPL license (GPL), you can redistribute and/or
+ * modify this file under the terms of the GNU General
+ * Public License, Version 3, as published by the Free Software
+ * Foundation. You should have received a copy of the GNU
+ * General Public License, Version 3 along with this program;
+ * if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 2. For the Magnolia Network Agreement (MNA), this file
+ * and the accompanying materials are made available under the
+ * terms of the MNA which accompanies this distribution, and
+ * is available at http://www.magnolia-cms.com/mna.html
+ *
+ * Any modifications to this file must keep this entire header
+ * intact.
+ *
+ */
+package info.magnolia.module.rssaggregator.generator;
+
+/**
+ * Thrown when a FeedGenerator cannot be constructed.
+ *
+ * @author Rob van der Linden Vooren
+ */
+public class FeedGeneratorConstructionException extends RuntimeException {
+
+ /** {@inheritDoc} */
+ public FeedGeneratorConstructionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: src/test/java/info/magnolia/module/rssaggregator/util/MagnoliaTemplateTest.java
===================================================================
--- src/test/java/info/magnolia/module/rssaggregator/util/MagnoliaTemplateTest.java Sun Feb 22 19:02:34 CET 2009
+++ src/test/java/info/magnolia/module/rssaggregator/util/MagnoliaTemplateTest.java Sun Feb 22 19:02:34 CET 2009
@@ -0,0 +1,215 @@
+/**
+ * This file Copyright (c) 2008-2009 Magnolia International
+ * Ltd. (http://www.magnolia-cms.com). All rights reserved.
+ *
+ *
+ * This file is dual-licensed under both the Magnolia
+ * Network Agreement and the GNU General Public License.
+ * You may elect to use one or the other of these licenses.
+ *
+ * This file is distributed in the hope that it will be
+ * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
+ * Redistribution, except as permitted by whichever of the GPL
+ * or MNA you select, is prohibited.
+ *
+ * 1. For the GPL license (GPL), you can redistribute and/or
+ * modify this file under the terms of the GNU General
+ * Public License, Version 3, as published by the Free Software
+ * Foundation. You should have received a copy of the GNU
+ * General Public License, Version 3 along with this program;
+ * if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 2. For the Magnolia Network Agreement (MNA), this file
+ * and the accompanying materials are made available under the
+ * terms of the MNA which accompanies this distribution, and
+ * is available at http://www.magnolia-cms.com/mna.html
+ *
+ * Any modifications to this file must keep this entire header
+ * intact.
+ *
+ */
+package info.magnolia.module.rssaggregator.util;
+
+import info.magnolia.cms.core.Content;
+import info.magnolia.cms.core.ItemType;
+import static info.magnolia.cms.core.ItemType.*;
+import info.magnolia.cms.core.search.Query;
+import static org.easymock.classextension.EasyMock.*;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.jcr.RepositoryException;
+import static java.util.Arrays.*;
+import java.util.Collection;
+import static java.util.Collections.*;
+import java.util.List;
+
+/**
+ * Tests {@link MagnoliaTemplate}.
+ *
+ * @author Rob van der Linden Vooren
+ */
+public class MagnoliaTemplateTest {
+
+ private MagnoliaTemplate template;
+
+ @Before
+ public void before() {
+ template = new MagnoliaTemplate();
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testQueryForList() throws Exception {
+ template = createMock(MagnoliaTemplate.class,
+ MagnoliaTemplate.class.getDeclaredMethod("queryInternal", String.class, String.class, String.class, ItemType.class)
+ );
+
+ Content dummyContent = createMock(Content.class);
+ ContentMapper mockMapper = createMock(ContentMapper.class);
+ Collection contents = asList(dummyContent);
+
+ expect(template.queryInternal("repo", "query", "xpath", CONTENTNODE)).andReturn(contents);
+ expect(mockMapper.map(dummyContent)).andReturn("mapping result #1");
+ replay(template, mockMapper);
+
+ List results = template.queryForList("repo", "query", "xpath", CONTENTNODE, mockMapper);
+ assertEquals("mapping result #1", results.get(0));
+ verify(template, mockMapper);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testQueryForObject() throws Exception {
+ template = createMock(MagnoliaTemplate.class,
+ MagnoliaTemplate.class.getDeclaredMethod("queryInternal", String.class, String.class, String.class, ItemType.class)
+ );
+
+ Content dummyContent = createMock(Content.class);
+ ContentMapper mockMapper = createMock(ContentMapper.class);
+ Collection contents = asList(dummyContent);
+
+ expect(template.queryInternal("repo", "query", "xpath", CONTENTNODE)).andReturn(contents);
+ expect(mockMapper.map(dummyContent)).andReturn("mapping result #1");
+ replay(template, mockMapper);
+
+ String result = (String) template.queryForObject("repo", "query", "xpath", CONTENTNODE, mockMapper);
+ assertEquals("mapping result #1", result);
+ verify(template, mockMapper);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testQueryForObject_returnsNullOnZeroResults() throws Exception {
+ template = createMock(MagnoliaTemplate.class,
+ MagnoliaTemplate.class.getDeclaredMethod("queryInternal", String.class, String.class, String.class, ItemType.class)
+ );
+
+ ContentMapper mockMapper = createMock(ContentMapper.class);
+ Collection contents = emptyList();
+
+ expect(template.queryInternal("repo", "query", "xpath", CONTENTNODE)).andReturn(contents);
+ replay(template, mockMapper);
+
+ assertNull(template.queryForObject("repo", "query", "xpath", CONTENTNODE, mockMapper));
+ verify(template, mockMapper);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testQueryForObject_throwsIncorrectResultSizeDataAccessExceptionOnMultipleResults() throws Exception {
+ template = createMock(MagnoliaTemplate.class,
+ MagnoliaTemplate.class.getDeclaredMethod("queryInternal", String.class, String.class, String.class, ItemType.class)
+ );
+
+ Content dummyContent = createMock(Content.class);
+ ContentMapper mockMapper = createMock(ContentMapper.class);
+ Collection contents = asList(dummyContent, dummyContent);
+
+ expect(template.queryInternal("repo", "query", "xpath", CONTENTNODE)).andReturn(contents);
+ expect(mockMapper.map(dummyContent)).andReturn("mapping result #1");
+ expect(mockMapper.map(dummyContent)).andReturn("mapping result #2");
+ replay(template, mockMapper);
+
+ try {
+ template.queryForObject("repo", "query", "xpath", CONTENTNODE, mockMapper);
+ fail("IncorrectResultSizeDataAccessException expected");
+ } catch (IncorrectResultSizeDataAccessException exception) {
+ assertEquals(1, exception.getExpectedSize());
+ assertEquals(2, exception.getActualSize());
+ verify(template, mockMapper);
+ }
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testXpathQueryForList() throws Exception {
+ template = createMock(MagnoliaTemplate.class,
+ MagnoliaTemplate.class.getDeclaredMethod("queryForList", String.class, String.class, String.class, ItemType.class, ContentMapper.class)
+ );
+
+ List expectedResults = emptyList();
+ ContentMapper dummyMapper = createMock(ContentMapper.class);
+
+ expect(template.queryForList("repository", "query", Query.XPATH, ItemType.CONTENT, dummyMapper)).andReturn(expectedResults);
+ replay(template);
+
+ assertSame(expectedResults, template.xpathQueryForList("repository", "query", ItemType.CONTENT, dummyMapper));
+ verify(template);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testXpathQueryForObject() throws Exception {
+ template = createMock(MagnoliaTemplate.class,
+ MagnoliaTemplate.class.getDeclaredMethod("queryForObject", String.class, String.class, String.class, ItemType.class, ContentMapper.class)
+ );
+
+ ContentMapper dummyMapper = createMock(ContentMapper.class);
+ String expectedResult = "result";
+
+ expect(template.queryForObject("repository", "query", Query.XPATH, ItemType.CONTENT, dummyMapper)).andReturn(expectedResult);
+ replay(template);
+
+ assertSame(expectedResult, template.xpathQueryForObject("repository", "query", ItemType.CONTENT, dummyMapper));
+ verify(template);
+ }
+
+ @Test
+ public void testQueryInternal() throws Exception {
+ template = createMock(MagnoliaTemplate.class,
+ MagnoliaTemplate.class.getDeclaredMethod("doExceptionThrowingQuery", String.class, String.class, String.class, ItemType.class)
+ );
+
+ Collection