[seam-commits] Seam SVN: r7186 - in trunk/examples/wiki: src/etc/META-INF and 12 other directories.
seam-commits at lists.jboss.org
seam-commits at lists.jboss.org
Tue Jan 22 10:17:34 EST 2008
Author: christian.bauer at jboss.com
Date: 2008-01-22 10:17:34 -0500 (Tue, 22 Jan 2008)
New Revision: 7186
Added:
trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/FeedAggregateCache.java
Modified:
trunk/examples/wiki/src/etc/META-INF/wiki.taglib.xml
trunk/examples/wiki/src/etc/WEB-INF/urlrewrite.xml
trunk/examples/wiki/src/etc/messages_en.properties
trunk/examples/wiki/src/etc/messages_feedAggregator_en.properties
trunk/examples/wiki/src/etc/messages_lastModifiedDocuments_en.properties
trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/cache/ConnectorCache.java
trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/FeedAggregatorDAO.java
trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/RomeFeedConnector.java
trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/FeedEntry.java
trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiFeed.java
trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FeedServlet.java
trunk/examples/wiki/src/main/org/jboss/seam/wiki/plugin/feedAggregator/FeedAggregator.java
trunk/examples/wiki/src/main/org/jboss/seam/wiki/plugin/feedAggregator/FeedAggregatorPreferences.java
trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiUtil.java
trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/WikiBaseData.dbunit.xml
trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/connector/FeedConnectorTest.java
trunk/examples/wiki/view/plugins/feedAggregator/plugin.xhtml
trunk/examples/wiki/view/themes/default/css/feedAggregator.css
trunk/examples/wiki/view/themes/sfwkorg/css/feedAggregator.css
trunk/examples/wiki/view/themes/sfwkorg/css/sfwk.css
Log:
Implemented subscription for aggregated feeds
Modified: trunk/examples/wiki/src/etc/META-INF/wiki.taglib.xml
===================================================================
--- trunk/examples/wiki/src/etc/META-INF/wiki.taglib.xml 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/etc/META-INF/wiki.taglib.xml 2008-01-22 15:17:34 UTC (rev 7186)
@@ -13,6 +13,12 @@
</function>
<function>
+ <function-name>renderAggregateFeedURL</function-name>
+ <function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
+ <function-signature>java.lang.String renderAggregateFeedURL(java.lang.String)</function-signature>
+ </function>
+
+ <function>
<function-name>renderFeedURL</function-name>
<function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
<function-signature>java.lang.String renderFeedURL(org.jboss.seam.wiki.core.model.Feed,java.lang.String,java.lang.String)</function-signature>
Modified: trunk/examples/wiki/src/etc/WEB-INF/urlrewrite.xml
===================================================================
--- trunk/examples/wiki/src/etc/WEB-INF/urlrewrite.xml 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/etc/WEB-INF/urlrewrite.xml 2008-01-22 15:17:34 UTC (rev 7186)
@@ -32,10 +32,10 @@
<to last="true">/wiki.seam?nodeId=$1</to>
</rule>
- <!-- /service/Feed/atom (/Foo) (/Bar) /Feed/atom (/Comments/exclude/) (Tag/foobar) -->
+ <!-- /service/Feed/atom (/Area/Foo) (/Node/Bar) (/Comments/exclude/) (/Tag/foobar) (/Aggregate/My Aggregate) -->
<rule>
- <from casesensitive="true">^/service/Feed/atom(?:/([A-Z0-9]+[A-Za-z0-9]*))?(?:/([A-Z0-9]+[A-Za-z0-9]*))?(?:/Comments/([a-z]+))?(?:/Tag/(.+))?$</from>
- <to last="true">/servlets/feeds/atom.seam?areaName=$1&nodeName=$2&comments=$3&tag=$4</to>
+ <from casesensitive="true">^/service/Feed/atom(?:/Area/([A-Z0-9]+[A-Za-z0-9]*))?(?:/Node/([A-Z0-9]+[A-Za-z0-9]*))?(?:/Comments/([a-z]+))?(?:/Tag/(.+))?(?:/Aggregate/(.+))?$</from>
+ <to last="true">/servlets/feeds/atom.seam?areaName=$1&nodeName=$2&comments=$3&tag=$4&aggregate=$5</to>
</rule>
<!-- /service/File/123 -->
Modified: trunk/examples/wiki/src/etc/messages_en.properties
===================================================================
--- trunk/examples/wiki/src/etc/messages_en.properties 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/etc/messages_en.properties 2008-01-22 15:17:34 UTC (rev 7186)
@@ -640,6 +640,7 @@
lacewiki.msg.AccessDenied=Access Denied
lacewiki.msg.FatalError=An unrecoverable error occured!
lacewiki.msg.Trash.Emptied=All items in the trash have been permanently deleted.
+lacewiki.msg.AutomaticallyGeneratedFeed=Aggregated Feed
# Preferences Editors
lacewiki.preferences.editor.SelectNone=(None)
Modified: trunk/examples/wiki/src/etc/messages_feedAggregator_en.properties
===================================================================
--- trunk/examples/wiki/src/etc/messages_feedAggregator_en.properties 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/etc/messages_feedAggregator_en.properties 2008-01-22 15:17:34 UTC (rev 7186)
@@ -8,7 +8,9 @@
feedAggregator.preferences.HideFeedInfo=Hide link to feed
feedAggregator.preferences.HideDescription=Hide feed entry text
feedAggregator.preferences.HideTitle=Hide feed entry title
+feedAggregator.preferences.AggregateId=Identifier for aggregate (enables subscription)
feedAggregator.label.More=more...
feedAggregator.label.By=by
+feedAggregator.label.Subscribe=Subscribe
feedAggregator.label.NoEntriesFound=No feed entries found.
\ No newline at end of file
Modified: trunk/examples/wiki/src/etc/messages_lastModifiedDocuments_en.properties
===================================================================
--- trunk/examples/wiki/src/etc/messages_lastModifiedDocuments_en.properties 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/etc/messages_lastModifiedDocuments_en.properties 2008-01-22 15:17:34 UTC (rev 7186)
@@ -4,4 +4,4 @@
lastModifiedDocuments.preferences.DocumentTitleLength=Truncate document titles after characters
lastModifiedDocuments.label.Last=Last
-lastModifiedDocuments.label.ModifiedDocuments=Updates
+lastModifiedDocuments.label.ModifiedDocuments=Site Updates
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/cache/ConnectorCache.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/cache/ConnectorCache.java 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/cache/ConnectorCache.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -38,12 +38,12 @@
List<T> result = Collections.EMPTY_LIST;
if (cacheKey == null) {
- log.debug("cache miss, retrieving it from connector, asynchronously: " + isCacheMissResolvedAsynchronously());
+ log.debug("cache miss, retrieving it from connector, asynchronously: " + isFirstCacheMissResolvedAsynchronously());
// The following operations modify the structure of the cache map, which is ok because this
// method is synchronized by Seam. The write triggered (later) by the AysncUpdater is not
// synchronized, but we never modify the structure of the cache map then, only now.
- if (isCacheMissResolvedAsynchronously()) {
+ if (getAsyncUpdater() != null && isFirstCacheMissResolvedAsynchronously()) {
// Write an empty list into the cache
write(key, Collections.EMPTY_LIST, currentTime);
@@ -59,22 +59,26 @@
}
} else {
- log.debug("cache hit, checking age of cached entry");
+ log.debug("cache hit");
- // Check updateTimestamp of cached entry
- if (currentTime - cacheKey.getUpdateTimestamp() > (getUpdateTimeoutSeconds()*1000) ) {
- log.debug("cached entry is older than maximum cache time, refreshing...");
+ if (getUpdateTimeoutSeconds() != 0) {
- // Start asynchronous updating, might take a while - but should never take longer than cache timeout!
- getAsyncUpdater().updateCacheAsynchronously(this, cacheKey);
+ log.debug("checking age of cached entry against update timeout");
+ // Check updateTimestamp of cached entry
+ if (currentTime - cacheKey.getUpdateTimestamp() > (getUpdateTimeoutSeconds()*1000) ) {
+ log.debug("cached entry is older than maximum cache time, refreshing...");
- // Meanwhile, update the timestamp so that the next caller doesn't also start asynchronous updating
- // .. we expect to be finished with that before the next caller runs into a cache timeout again!
- cacheKey.setAccessTimestamp(currentTime);
- cacheKey.setUpdateTimestamp(currentTime);
+ // Start asynchronous updating, might take a while - but should never take longer than cache timeout!
+ getAsyncUpdater().updateCacheAsynchronously(this, cacheKey);
- } else {
- log.debug("cached entry is still inside maximum cache time");
+ // Meanwhile, update the timestamp so that the next caller doesn't also start asynchronous updating
+ // .. we expect to be finished with that before the next caller runs into a cache timeout again!
+ cacheKey.setAccessTimestamp(currentTime);
+ cacheKey.setUpdateTimestamp(currentTime);
+
+ } else {
+ log.debug("cached entry is still inside maximum cache time");
+ }
}
// Read the value from the cache
@@ -116,17 +120,17 @@
return (ConnectorCacheAsyncUpdater<T, K>) Component.getInstance(getAsyncUpdaterClass());
};
- private ConnectorCacheKey<K> findKey(ConnectorCacheKey<K> key) {
+ protected ConnectorCacheKey<K> findKey(ConnectorCacheKey<K> key) {
for (ConnectorCacheKey keyOfMap : cache.keySet()) {
if (keyOfMap.equals(key)) return keyOfMap;
}
return null;
}
- protected abstract long getUpdateTimeoutSeconds();
+ protected long getUpdateTimeoutSeconds() { return 0; }
protected abstract long getIdleTimeoutSeconds();
- protected abstract Class<? extends ConnectorCacheAsyncUpdater<T, K>> getAsyncUpdaterClass();
- protected boolean isCacheMissResolvedAsynchronously() { return true; }
+ protected Class<? extends ConnectorCacheAsyncUpdater<T, K>> getAsyncUpdaterClass() { return null; };
+ protected boolean isFirstCacheMissResolvedAsynchronously() { return true; }
protected List<T> udpateCacheSynchronously(ConnectorCache<T, K> cache, ConnectorCacheKey<K> key) {
return Collections.EMPTY_LIST;
};
Added: trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/FeedAggregateCache.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/FeedAggregateCache.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/FeedAggregateCache.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -0,0 +1,88 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.connectors.feed;
+
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Synchronized;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.wiki.connectors.cache.ConnectorCache;
+import org.jboss.seam.wiki.connectors.cache.ConnectorCacheKey;
+import org.jboss.seam.wiki.core.model.Feed;
+import org.jboss.seam.wiki.core.model.FeedEntry;
+
+import java.net.URL;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Collections;
+import java.io.Serializable;
+
+/**
+ * Caches transient feeds.
+ *
+ * TODO: Maybe we should use a simple synchronized collection instead, but Seam does the job.
+ *
+ * @author Christian Bauer
+ */
+ at Name("feedAggregateCache")
+ at Scope(ScopeType.APPLICATION)
+ at Synchronized
+ at AutoCreate
+public class FeedAggregateCache extends ConnectorCache<FeedEntryDTO, FeedAggregateCache.FeedAggregateCacheKey> {
+
+ public void put(String aggregateId, List<FeedEntryDTO> feedEntries) {
+ long currentTime = System.currentTimeMillis();
+ FeedAggregateCacheKey newKey = new FeedAggregateCacheKey(aggregateId);
+
+ write(new ConnectorCacheKey<FeedAggregateCacheKey>(newKey), feedEntries, currentTime);
+ purge(currentTime);
+ }
+
+ public List<FeedEntryDTO> get(String aggregateId) {
+ long currentTime = System.currentTimeMillis();
+ FeedAggregateCacheKey newKey = new FeedAggregateCacheKey(aggregateId);
+
+ List<FeedEntryDTO> result = read(new ConnectorCacheKey<FeedAggregateCacheKey>(newKey), currentTime);
+ purge(currentTime);
+ return result;
+ }
+
+ protected long getIdleTimeoutSeconds() {
+ return 36000;
+ }
+
+ public static class FeedAggregateCacheKey implements Serializable {
+ private String aggregateId;
+
+ public FeedAggregateCacheKey(String aggregateId) {
+ this.aggregateId = aggregateId;
+ }
+
+ public String getAggregateId() {
+ return aggregateId;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ FeedAggregateCacheKey that = (FeedAggregateCacheKey) o;
+
+ if (!aggregateId.equals(that.aggregateId)) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return aggregateId.hashCode();
+ }
+ }
+
+
+}
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/FeedAggregatorDAO.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/FeedAggregatorDAO.java 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/FeedAggregatorDAO.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -7,11 +7,13 @@
package org.jboss.seam.wiki.connectors.feed;
import org.jboss.seam.ScopeType;
+import org.jboss.seam.wiki.core.model.Feed;
import org.jboss.seam.annotations.*;
import org.jboss.seam.log.Log;
import java.util.*;
import java.io.Serializable;
+import java.net.URL;
/**
* @author Christian Bauer
@@ -27,16 +29,23 @@
@In("feedConnectorCache")
FeedConnector feedConnector;
- public List<FeedEntryDTO> getLatestFeedEntries(int numberOfFeedEntries, String[] feedURLs) {
+ @In
+ FeedAggregateCache feedAggregateCache;
+
+ public List<FeedEntryDTO> getLatestFeedEntries(int numberOfFeedEntries, URL[] feedURLs) {
+ return getLatestFeedEntries(numberOfFeedEntries, feedURLs, null);
+ }
+
+ public List<FeedEntryDTO> getLatestFeedEntries(int numberOfFeedEntries, URL[] feedURLs, String aggregateId) {
if (feedURLs == null) return Collections.EMPTY_LIST;
List<FeedEntryDTO> feedEntries = new ArrayList<FeedEntryDTO>();
- for (String feedURL : feedURLs) {
+ for (URL feedURL : feedURLs) {
// For each feed, get the feed entries and put them in a sorted collection,
// so we get overall sorting
log.debug("retrieving feed entries from connector for feed URL: " + feedURL);
- List<FeedEntryDTO> result = feedConnector.getFeedEntries(feedURL);
+ List<FeedEntryDTO> result = feedConnector.getFeedEntries(feedURL.toString());
log.debug("retrieved feed entries: " + result.size());
feedEntries.addAll(result);
log.debug("number of aggregated feed entries so far: " + feedEntries.size());
@@ -56,6 +65,12 @@
}
);
+ if (aggregateId != null) {
+ log.debug("caching aggregated feed entries under id: " + aggregateId);
+ // Cache the result for later requests through FeedServlet (by aggregateId)
+ feedAggregateCache.put(aggregateId, feedEntries);
+ }
+
return feedEntries.size() > numberOfFeedEntries
? new ArrayList<FeedEntryDTO>(feedEntries).subList(0, numberOfFeedEntries)
: new ArrayList<FeedEntryDTO>(feedEntries);
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/RomeFeedConnector.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/RomeFeedConnector.java 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/connectors/feed/RomeFeedConnector.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -73,7 +73,11 @@
SyndEntry syndEntry = (SyndEntry)o;
FeedEntry fe = convertSyndEntry(syndEntry);
- // Linking it in our model makes it persistable
+ // Append some information on the title
+ fe.setTitlePrefix("(" + feed.getTitle() + ") ");
+ //fe.setTitleSuffix(" (" + fe.getAuthor() + ")");
+
+ // Linking it in our model makes it persistable/cachable
feed.getFeedEntries().add(fe);
// Now project them so the client has a unified view without iterating collections of Feeds
@@ -121,7 +125,8 @@
if (syndEntry.getDescription() != null) {
SyndContent description = syndEntry.getDescription();
- feedEntry.setDescriptionType(description.getType());
+ // TODO: Hardcode 'html', otherwise the ROME stuff craps out and kills Firefox feed renderer...
+ feedEntry.setDescriptionType("html");
feedEntry.setDescriptionValue(description.getValue());
}
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/FeedEntry.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/FeedEntry.java 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/FeedEntry.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -42,6 +42,12 @@
@Length(min = 3, max = 1024)
private String title;
+ @Transient
+ private String titlePrefix = "";
+
+ @Transient
+ private String titleSuffix = "";
+
@Column(name = "AUTHOR", nullable = false)
@Length(min = 3, max = 255)
private String author;
@@ -81,6 +87,22 @@
return title;
}
+ public String getTitlePrefix() {
+ return titlePrefix;
+ }
+
+ public void setTitlePrefix(String titlePrefix) {
+ this.titlePrefix = titlePrefix;
+ }
+
+ public String getTitleSuffix() {
+ return titleSuffix;
+ }
+
+ public void setTitleSuffix(String titleSuffix) {
+ this.titleSuffix = titleSuffix;
+ }
+
public String getTitleStripped() {
return stripHTMLTags(title);
}
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiFeed.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiFeed.java 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiFeed.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -39,6 +39,13 @@
}
public String getURL() {
- return directory.getWikiURL().length() > 0 ? "/"+directory.getWikiURL() : "";
+ if (directory.getWikiURL().length() >0) {
+ if (directory.getArea().getWikiname().equals(directory.getWikiname())) {
+ return "/Area/"+directory.getArea().getWikiname();
+ } else {
+ return "/Area/"+directory.getArea().getWikiname() + "/Node/" + directory.getWikiname();
+ }
+ }
+ return ""; // Root, no area or node
}
}
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FeedServlet.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FeedServlet.java 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FeedServlet.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -18,6 +18,8 @@
import org.jboss.seam.wiki.core.dao.WikiNodeFactory;
import org.jboss.seam.wiki.util.WikiUtil;
import org.jboss.seam.wiki.preferences.Preferences;
+import org.jboss.seam.wiki.connectors.feed.FeedAggregateCache;
+import org.jboss.seam.wiki.connectors.feed.FeedEntryDTO;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
@@ -79,17 +81,8 @@
String feedIdParam = request.getParameter("feedId");
String areaNameParam = request.getParameter("areaName");
String nodeNameParam = request.getParameter("nodeName");
+ String aggregateParam = request.getParameter("aggregate");
log.debug(">>> feed request id: '" + feedIdParam + "' area name: '" + areaNameParam + "' node name: '" + nodeNameParam + "'");
- log.debug("full request URL: " + request.getRequestURL().toString());
- if (log.isDebugEnabled()) {
- Map<String,String[]> params = (Map<String,String[]>)request.getParameterMap();
- for (Map.Entry<String, String[]> entry : params.entrySet()) {
- log.debug("request param: " + entry.getKey());
- for (String s : entry.getValue()) {
- log.debug("value: '" +s + "'");
- }
- }
- }
// Feed type
String pathInfo = request.getPathInfo();
@@ -120,6 +113,7 @@
}
// TODO: Seam should use its transaction interceptor for java beans: http://jira.jboss.com/jira/browse/JBSEAM-957
+ // and that would allow us to break up this gigantic if/then/else clause easily...
UserTransaction userTx = null;
boolean startedTx = false;
try {
@@ -132,8 +126,26 @@
Feed feed = null;
// Find the feed, depending on variations of request parameters
- if (feedIdParam != null && feedIdParam.length() >0) {
+ if (aggregateParam != null && aggregateParam.length() > 0) {
+
+ log.debug("trying to retrieve aggregated feed from cache: " + aggregateParam);
+
+ FeedAggregateCache aggregateCache = (FeedAggregateCache)Component.getInstance(FeedAggregateCache.class);
+ List<FeedEntryDTO> result = aggregateCache.get(aggregateParam);
+ if (result != null) {
+ feed = new Feed();
+ feed.setAuthor(Messages.instance().get("lacewiki.msg.AutomaticallyGeneratedFeed"));
+ feed.setTitle(Messages.instance().get("lacewiki.msg.AutomaticallyGeneratedFeed") + ": " + aggregateParam);
+ feed.setPublishedDate(new Date());
+ feed.setLink( ((WikiPreferences) Preferences.getInstance("Wiki")).getBaseUrl() );
+ for (FeedEntryDTO feedEntryDTO : result) {
+ feed.getFeedEntries().add(feedEntryDTO.getFeedEntry());
+ }
+ }
+
+ } else if (feedIdParam != null && feedIdParam.length() >0) {
try {
+
log.debug("trying to retrieve feed for id: " + feedIdParam);
Long feedId = Long.valueOf(feedIdParam);
FeedDAO feedDAO = (FeedDAO)Component.getInstance(FeedDAO.class);
@@ -142,6 +154,8 @@
log.debug("feed identifier couldn't be converted to java.lang.Long");
response.sendError(HttpServletResponse.SC_NOT_FOUND, "Feed " + feedIdParam);
}
+
+
} else if (areaNameParam != null && areaNameParam.matches("^[A-Z0-9]+.*")) {
log.debug("trying to retrieve area: " + areaNameParam);
WikiNodeDAO nodeDAO = (WikiNodeDAO)Component.getInstance(WikiNodeDAO.class);
@@ -189,8 +203,18 @@
}
}
+ // TODO: Refactor this mess a little
log.debug("finally rendering feed");
- SyndFeed syndFeed = createSyndFeed(request.getRequestURL().toString(), syndFeedType, feed, currentAccessLevel, tag, comments);
+ SyndFeed syndFeed =
+ createSyndFeed(
+ request.getRequestURL().toString(),
+ syndFeedType,
+ feed,
+ currentAccessLevel,
+ tag,
+ comments,
+ aggregateParam
+ );
// Write feed to output
response.setContentType(syndFeedType.contentType);
@@ -214,16 +238,26 @@
}
public SyndFeed createSyndFeed(String baseURI, SyndFeedType syndFeedType, Feed feed, Integer currentAccessLevel) {
- return createSyndFeed(baseURI, syndFeedType, feed, currentAccessLevel, null, Comments.include);
+ return createSyndFeed(baseURI, syndFeedType, feed, currentAccessLevel, null, Comments.include, null);
}
- public SyndFeed createSyndFeed(String baseURI, SyndFeedType syndFeedType, Feed feed, Integer currentAccessLevel, String tag, Comments comments) {
+ public SyndFeed createSyndFeed(String baseURI,
+ SyndFeedType syndFeedType,
+ Feed feed,
+ Integer currentAccessLevel,
+ String tag,
+ Comments comments,
+ String aggregateParam) {
WikiPreferences prefs = (WikiPreferences) Preferences.getInstance("Wiki");
// Create feed
SyndFeed syndFeed = new SyndFeedImpl();
- syndFeed.setUri(baseURI + "?feedId=" + feed.getId());
+ String feedUri =
+ feed.getId() != null
+ ? "?feedId="+feed.getId()
+ : "?aggregate="+WikiUtil.encodeURL(aggregateParam);
+ syndFeed.setUri(baseURI + feedUri);
syndFeed.setFeedType(syndFeedType.feedType);
syndFeed.setTitle(prefs.getFeedTitlePrefix() + feed.getTitle());
if (tag != null) {
@@ -251,7 +285,7 @@
SyndEntry syndEntry;
syndEntry = new SyndEntryImpl();
- syndEntry.setTitle(entry.getTitle());
+ syndEntry.setTitle(entry.getTitlePrefix() + entry.getTitle() + entry.getTitleSuffix());
syndEntry.setLink(entry.getLink());
syndEntry.setUri(entry.getLink());
syndEntry.setAuthor(entry.getAuthor());
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/plugin/feedAggregator/FeedAggregator.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/plugin/feedAggregator/FeedAggregator.java 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/plugin/feedAggregator/FeedAggregator.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -6,17 +6,17 @@
*/
package org.jboss.seam.wiki.plugin.feedAggregator;
+import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.*;
-import org.jboss.seam.ScopeType;
import org.jboss.seam.log.Log;
import org.jboss.seam.wiki.connectors.feed.FeedAggregatorDAO;
import org.jboss.seam.wiki.connectors.feed.FeedEntryDTO;
+import java.io.Serializable;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
import java.util.List;
-import java.util.ArrayList;
-import java.net.URL;
-import java.net.MalformedURLException;
-import java.io.Serializable;
/**
* @author Christian Bauer
@@ -46,31 +46,47 @@
if (prefs.getUrls() == null || prefs.getUrls().length() < 8) return;
+ List<URL> validURLs = getValidURLs(prefs.getUrls());
+ log.debug("aggregating feeds: " + validURLs.size());
+
+ String aggregateId =
+ prefs.getAggregateId() != null && prefs.getAggregateId().length() > 0
+ ? prefs.getAggregateId()
+ : null;
+
+ if (aggregateId != null) {
+ log.debug("aggregating under subscribable identifier: "+ aggregateId);
+ }
+
+ feedEntries =
+ feedAggregatorDAO.getLatestFeedEntries(
+ prefs.getNumberOfFeedEntries().intValue(),
+ validURLs.toArray(new URL[validURLs.size()]),
+ aggregateId
+ );
+ }
+
+ private List<URL> getValidURLs(String spaceSeparatedURLs) {
+
// Split the URLs by space
- String[] urls = prefs.getUrls().split(" ");
+ String[] urls = spaceSeparatedURLs.split(" ");
// First check if the URLs are valid, if not we might as well just skip it...
- List<String> validUrls = new ArrayList<String>();
+ List<URL> validUrls = new ArrayList<URL>();
for (String url : urls) {
try {
- URL testUrl = new URL(url);
- if (!testUrl.getProtocol().equals("http")) {
+ URL u = new URL(url);
+ if (!u.getProtocol().equals("http")) {
log.debug("skipping URL with unsupported protocol: " + url);
continue;
}
+ validUrls.add(u);
} catch (MalformedURLException e) {
log.debug("skipping invalid URL: " + url);
continue;
}
- validUrls.add(url);
}
-
- log.debug("aggregating feeds: " + validUrls.size());
- feedEntries =
- feedAggregatorDAO.getLatestFeedEntries(
- prefs.getNumberOfFeedEntries().intValue(),
- validUrls.toArray(new String[validUrls.size()])
- );
+ return validUrls;
}
}
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/plugin/feedAggregator/FeedAggregatorPreferences.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/plugin/feedAggregator/FeedAggregatorPreferences.java 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/plugin/feedAggregator/FeedAggregatorPreferences.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -55,6 +55,14 @@
private Long truncateDescription;
@PreferenceProperty(
+ description = "#{messages['feedAggregator.preferences.AggregateId']}",
+ visibility = {PreferenceVisibility.INSTANCE},
+ editorIncludeName = "NumberRange"
+ )
+ @Length(min = 0, max = 255)
+ private String aggregateId;
+
+ @PreferenceProperty(
description = "#{messages['feedAggregator.preferences.HideDate']}",
visibility = {PreferenceVisibility.INSTANCE}
)
@@ -100,6 +108,10 @@
return truncateDescription;
}
+ public String getAggregateId() {
+ return aggregateId;
+ }
+
public Boolean getHideDate() {
return hideDate;
}
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiUtil.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiUtil.java 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiUtil.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -23,6 +23,7 @@
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
+import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
@@ -96,6 +97,15 @@
accessLevels.indexOf(new Role.AccessLevel(accessLevel, null))
);
}
+
+ public static String renderAggregateFeedURL(String aggregateId) {
+ if (aggregateId == null) return "";
+ StringBuilder url = new StringBuilder();
+ url.append(Component.getInstance("basePath"))
+ .append("/service/Feed/atom/Aggregate/")
+ .append(aggregateId);
+ return url.toString();
+ }
public static String renderFeedURL(Feed feed, String tag, String comments) {
if (feed == null || feed.getId() == null) return "";
@@ -158,6 +168,14 @@
}
}
+ public static String decodeURL(String string) {
+ try {
+ return URLDecoder.decode(string, "UTF-8");
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
public static String escapeEmailURL(String string) {
WikiPreferences wikiPrefs = (WikiPreferences) Preferences.getInstance("Wiki");
return string.length() >= 7 && string.substring(0, 7).equals("mailto:")
Modified: trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/WikiBaseData.dbunit.xml
===================================================================
--- trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/WikiBaseData.dbunit.xml 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/WikiBaseData.dbunit.xml 2008-01-22 15:17:34 UTC (rev 7186)
@@ -262,7 +262,7 @@
<WIKI_FILE
NODE_ID="8" FILE_REVISION="0"/>
<WIKI_DOCUMENT
- NODE_ID="8" CONTENT="Testdocument Three

<div class="homepageNews">
[<=feedAggregator[truncateDescription=250][numberOfFeedEntries=10][urls=http://rss.slashdot.org/Slashdot/slashdot http://feeds.engadget.com/weblogsinc/engadget]]
</div>
"
+ NODE_ID="8" CONTENT="Testdocument Three

<div class="homepageNews">
[<=feedAggregator[truncateDescription=250][numberOfFeedEntries=10][aggregateId=My Aggregated Feed][urls=http://rss.slashdot.org/Slashdot/slashdot http://feeds.engadget.com/weblogsinc/engadget]]
</div>
"
HEADER="[NULL]" FOOTER="[NULL]"
HEADER_MACROS="[NULL]" CONTENT_MACROS="feedAggregator" FOOTER_MACROS="[NULL]"
NAME_AS_TITLE="true" ENABLE_COMMENTS="true" ENABLE_COMMENT_FORM="true" ENABLE_COMMENTS_ON_FEEDS="true"/>
Modified: trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/connector/FeedConnectorTest.java
===================================================================
--- trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/connector/FeedConnectorTest.java 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/connector/FeedConnectorTest.java 2008-01-22 15:17:34 UTC (rev 7186)
@@ -23,6 +23,7 @@
import java.util.List;
import java.util.ArrayList;
import java.util.Date;
+import java.net.URL;
/**
* @author Christian Bauer
@@ -42,8 +43,8 @@
protected void renderResponse() throws Exception {
FeedAggregatorDAO dao = (FeedAggregatorDAO)getInstance(FeedAggregatorDAO.class);
- String[] feedURLs = {
- "http://foo", "http://bar", "http:WrongURL"
+ URL[] feedURLs = {
+ new URL("http://foo"), new URL("http://bar")
};
List<FeedEntryDTO> dtos = dao.getLatestFeedEntries(30, feedURLs);
Modified: trunk/examples/wiki/view/plugins/feedAggregator/plugin.xhtml
===================================================================
--- trunk/examples/wiki/view/plugins/feedAggregator/plugin.xhtml 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/view/plugins/feedAggregator/plugin.xhtml 2008-01-22 15:17:34 UTC (rev 7186)
@@ -9,10 +9,29 @@
<s:div styleClass="feedAggregator box">
- <s:div styleClass="boxHeader">
+
+ <s:div styleClass="boxHeader" rendered="#{empty preferences.get('FeedAggregator', currentMacro).aggregateId}">
<h:outputText value="#{preferences.get('FeedAggregator', currentMacro).title}"/>
</s:div>
+
+ <h:panelGrid rendered="#{not empty preferences.get('FeedAggregator', currentMacro).aggregateId}"
+ columns="2" cellpadding="0" cellspacing="0" border="0"
+ columnClasses="feedAggregatorSubscribe, feedAggregatorTitle"
+ styleClass="boxHeader fullWidth">
+ <h:panelGrid columns="2" cellpadding="0" cellspacing="0" border="0">
+ <h:outputLink value="#{wiki:renderAggregateFeedURL(preferences.get('FeedAggregator', currentMacro).aggregateId)}">
+ <h:graphicImage value="/themes/#{preferences.get('Wiki').themeName}/img/icon.atom.ongrey.gif" width="18" height="18" alt="Atom"/>
+ </h:outputLink>
+ <h:outputLink value="#{wiki:renderAggregateFeedURL(preferences.get('FeedAggregator', currentMacro).aggregateId)}">
+ <h:outputText value="#{messages['feedAggregator.label.Subscribe']}"/>
+ </h:outputLink>
+ </h:panelGrid>
+
+ <h:outputText value="#{preferences.get('FeedAggregator', currentMacro).title}"/>
+
+ </h:panelGrid>
+
<div class="boxContent">
<h:dataTable value="#{feedAggregator.feedEntries}" var="feDTO"
rendered="#{not empty feedAggregator.feedEntries and feedAggregator.feedEntries.size() > 0}"
Modified: trunk/examples/wiki/view/themes/default/css/feedAggregator.css
===================================================================
--- trunk/examples/wiki/view/themes/default/css/feedAggregator.css 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/view/themes/default/css/feedAggregator.css 2008-01-22 15:17:34 UTC (rev 7186)
@@ -1,3 +1,11 @@
+.feedAggregatorTitle {
+ text-align: right;
+}
+
+.feedAggregatorSubscribe {
+ text-align: left;
+}
+
.feedEntryColumn {
padding: 10px;
}
Modified: trunk/examples/wiki/view/themes/sfwkorg/css/feedAggregator.css
===================================================================
--- trunk/examples/wiki/view/themes/sfwkorg/css/feedAggregator.css 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/view/themes/sfwkorg/css/feedAggregator.css 2008-01-22 15:17:34 UTC (rev 7186)
@@ -1,3 +1,11 @@
+.feedAggregatorTitle {
+ text-align: right;
+}
+
+.feedAggregatorSubscribe {
+ text-align: left;
+}
+
.feedEntryColumn {
padding: 10px;
}
@@ -13,4 +21,4 @@
.feedEntryBody {
line-height: 130%;
-}
\ No newline at end of file
+}
Modified: trunk/examples/wiki/view/themes/sfwkorg/css/sfwk.css
===================================================================
--- trunk/examples/wiki/view/themes/sfwkorg/css/sfwk.css 2008-01-22 15:16:57 UTC (rev 7185)
+++ trunk/examples/wiki/view/themes/sfwkorg/css/sfwk.css 2008-01-22 15:17:34 UTC (rev 7186)
@@ -280,6 +280,7 @@
border-bottom: 1px solid #b6b6b6;
padding-left: 0;
padding-bottom: 5px;
+ text-align: right;
}
.homepageNews .boxContent {
@@ -294,6 +295,10 @@
padding-left: 0;
}
+.homepageNews .feedAggregatorSubscribe {
+ font-size: 110%;
+}
+
.homepageNews .feedEntryColumn {
padding: 0;
}
More information about the seam-commits
mailing list