Manage RSS feeds with the Rome API
RSS (Really Simple Syndication) is an established way of publishing short snippets of information, such as news headlines, project releases, or blog entries. Modern browsers such as Firefox, and more recently Internet Explorer 7, and mail clients such as Thunderbird recognize and support RSS feeds; not to mention the a large number of dedicated RSS readers (also known as aggregators) out there.
RSS feeds aren't just for end-users, though. A variety of application scenarios could require you to read, publish, or process RSS feeds from within your code. Your application could need to publish information through a set of RSS feeds, or need to read, and possibly manipulate, RSS data from another source. For example, some applications use RSS feeds to inform users of changes to the application database that could affect them.
RSS feeds also can be useful inside of a development project. Tools like Trac let you use RSS feeds to monitor changes made to a Subversion repository or to a project Web site, which can be a good way to easily keep tabs on the status of many projects simultaneously. Some development projects, for instance, use RSS feeds to monitor continuous integration build results. End users simply subscribe to the CI server's feed in their RSS reader or RSS-enabled Web browser. The server publishes real-time build results in RSS format, which the client can then consult at any time without having to go to the server's Web site.
In this article, I'll show you how to manipulate RSS feeds in Java using the Rome (RSS and Atom utilities) API. I'll also walk you through a concrete application of these techniques, where you'll write a simple class that publishes build results from a Continuum build server in RSS format.
Introducing the Rome API
You could define RSS very simply by saying that it is an XML format that allows you to share information in a condensed manner; for example by publishing only a title, a description, and a link to a more detailed article.
Now, strictly speaking RSS is not a single format, but a family of formats. Among the many flavors of RSS are RSS 0.91 (in Netscape and Userland "sub-flavors"), RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, and RSS 2.0. More recently Atom 1.0 has also entered the mix, introducing many subtle and non-so-subtle compatibility issues.
Although you can very well write your own RSS script directly (after all, it's just XML!), doing so forces you to choose, and stick to, one particular format. The issue is even trickier if you have to read and process external RSS feeds, which can come in a variety of formats. This is where an API like Rome comes in handy. In addition to being fluent in the many flavors of RSS, as you will see, the Rome API is easy to use and intuitive to understand, which helps to make coding more productive and code more maintainable.
Rome is an open source Java API for reading and publishing RSS feeds in a relatively format-neutral way. Originally developed by Sun and now a Java.net project, Rome is designed to provide a level of abstraction to mask the subtle differences between the various formats. This lets you concentrate on publishing and/or processing content, rather than wrestling with the particularities of each format. Rome was designed from the onset to be easy to use, flexible, and to support all existing RSS flavors.
Get started with Rome
In this article you'll try your hand at two exercises using the Rome API. First, you'll create a simple feed, populate it, and publish it, with a few small steps in between. Once you have the basics down you can tackle the more advanced exercise of setting up syndicated build reports from a continuous integration server like Continuum.
You'll need to download Rome 0.9, which you can get from the Rome homepage. Rome needs Java 1.4 or higher, and requires JDOM 1.0 for XML processing, which you will also need to download if you don't have it already. If you're using Maven, all you need to do is to add the following dependency to your pom.xml
:
rome
rome
0.9
Publishing an RSS feed with Rome
Let's start off by creating a new RSS feed and publishing some content. You manipulate an RSS feed by using the SyndFeed
interface. True to Rome's charter, SyndFeed
provides a common interface for handling all RSS feed types in a uniform manner. It is designed for simplicity rather than universality, and lets you handle any RSS format without having to worry about which RSS flavor you are using. The flip-side of this is that the SyndFeed
interface does not support the more exotic fields found in some newer formats. Nevertheless, in practice, SyndFeed
is sufficient for the vast majority of RSS programming requirements. Here's how it's done:
Listing 1. A really simple RSS feed
SyndFeed feed = new SyndFeedImpl();
feed.setFeedType("rss_1.0");
feed.setTitle("MyProject Build Results");
feed.setLink(");
feed.setDescription("Continuous build results for the MyProject project");
feed.setCategory("MyProject");
Did you notice the setFeedType()
method? It lets you choose your preferred RSS format with a minimum of fuss. Then, you can just get on with coding the usual RSS fields such as title, link, description, and category. These fields are common to all RSS formats, so the SyndFeed
class handles them all just fine.
Fields versus formats
As I mentioned, although this interface handles all RSS feed types, it does not support all the fields in those formats. So, when it fetches data from a feed, it may lose some of the specific data from certain RSS formats. There is no way to access these format-specific fields using SyndFeed
. For example, the "info" and "language" fields in the Atom formats have no equivalent in other RSS feeds, and are not supported by SyndFeed
.
If you do need to exploit the extra features or fields available in a particular format, you can use one of the WireFeed
classes. The com.sun.syndication.feed.atom.Feed
class, for instance, works for Atom 0.3 and Atom 1.0 feeds. The com.sun.syndication.feed.rss.Channel
class handles all RSS versions without loss of data.
Adding an entry
The RSS feed created in Listing 1 does not actually contain any entries yet. You manage entries with the SyndEntry
interface. Again, creating a new entry is an intuitive affair, as shown in Listing 2.
Listing 2. Creating a new entry using Rome
SyndEntry entry = new SyndEntryImpl();
entry.setTitle("BUILD SUCCESSFUL");
entry.setLink(");
entry.setPublishedDate(new Date());
The SyndEntry
interface has a number of attributes, many of which map to different fields in the actual RSS feed, depending on the format used. Like the SyndFeed
interface, SyndEntry
is a general interface, compatible with all RSS formats. It does not support all the format-specific features available for each format, however. If you are using one of the format-specific WireFeed
classes described above, you will need to use a more specific entry object, such as com.sun.syndication.feed.atom.Feed
for Atom entries or com.sun.syndication.feed.rss.Item
for the RSS versions.
Descriptions
Next, you need to add the actual entry description, using the SyndContent
interface. The setType()
method is used to specify the type of content you are going to place in the description: plain text ("text/plain"
), HTML ("text/html"
), or XML ("text/xml"
):
Listing 3. Adding a description
SyndContent description = new SyndContentImpl();
description.setType("text/html");
description.setValue("The build was successful!");
entry.setDescription(description);
Categories
You can also define categories for your entry. Categories are widely used in RSS feeds to class entries into what the RSS people call a "categorization taxonomy." In order to be meaningful, categories generally come from a pre-defined list of possible values for a given RSS feed. An entry can have any number of categories, which allows you to cross-reference an entry in several different categories. Rome represents categories with the SyndCategory
interface, as shown here:
Listing 4. Categorizing the entry
List categories = new ArrayList();
SyndCategory category = new SyndCategoryImpl();
category.setName("MyProject");
categories.add(category);
entry.setCategories(categories);
Set and publish
Once you have obtained some entries, you can add them to your SyndFeed
object, using the setEntries()
method, like so:
feed.setEntries(entries);
And now you have an RSS feed ready to go! To write your RSS feed to an output stream, just use the SyndFeedOutput
class, as shown in Listing 5.
Listing 5. Publishing the feed
Writer writer = new FileWriter("stream.xml");
SyndFeedOutput output = new SyndFeedOutput();
output.output(feed,writer);
writer.close();
Reading and updating an external RSS feed
Rome is not only good at writing RSS feeds: in fact, it also excels at reading and manipulating them. This is one of the things that makes Rome a good choice if you need to provide any aggregation features in your applications.
You can read an RSS feed from any source (URL, file, and so on) using the SyndFeedInput
and XmlReader
classes, as shown in Listing 6.
Listing 6. Loading a feed with SyndFeedInput
URL feedSource = new URL(");
SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build(new XmlReader(feedSource));
Once you have loaded the SyndFeed
object, you can modify the RSS entries or add new ones, as shown above. Note that you are modifying your local copy of the feed, not the original feed. When you're done, you will probably need to write the new feed to disk using the SyndFeedOutput
class.
The eternal city: Integrating Rome and Continuum
You've seen how to use Rome to easily publish an RSS feed. Now let's apply it in the context of a realistic development project, such as generating an RSS feed from a continuous integration server. Some CI servers, such as Hudson, come with RSS feeds built in, but not Continuum -- at least not just yet. Continuum does come with a convenient API that allows you to access the server from an external Java application, however. You can put this API to good use to provide an RSS feed that details build results.
It is fairly easy to write a class that monitors build results and creates a new RSS entry whenever a new build is executed. In the next sections you'll go through the steps involved in creating such a class. I've simplified some of the code shown here to make reading easier, and also removed comments and error-handling code. See the source code download for full-fledged samples.
The RssPublisher class
The monitor class, called RssPublisher
, is a simple POJO-style Java bean. Its only dependencies are to the Rome jars, the Continuum XML-RPC client classes, and the Jakarta Commons CLI libraries (to handle command-line options). The class uses some JavaBeans-style attributes (the getters and setters are not shown) to provide configuration details and to customize its behavior. RssPublisher
is shown in Listing 7.
Listing 7. RssPublisher
public class RssPublisher implements Serializable { private String rssFeedFilename = "rss/builds.xml"; private int updateFrequency = 30; private String continuumXMLRPCUrl = " private String rssFormat = "rss_1.0"; private String rssFeedTitle = "Company Build Results"; ... }
Read and update the RSS feed
The next step is to read and update the RSS feed whenever a project's build status changes. You do this in the updateLatestBuildResults()
method, which uses a Map
object to store the state of each managed project, like so:
Listing 8. updateLatestBuildResults()
private Map previousState = new HashMap();
public void updateLatestBuildResults() throws IOException, FeedException, XmlRpcException {
...
This method begins by preparing the RSS feed, creating it if necessary.
Listing 9. Preparing the RSS feed
SyndFeed feed = null;
File feedSource = new File(getRssFeedFilename());
if (feedSource.exists()) {
SyndFeedInput input = new SyndFeedInput();
feed = input.build(new XmlReader(feedSource));
} else {
feed = new SyndFeedImpl();
feed.setFeedType(getRssFormat());
feed.setTitle(getRssFeedTitle());
feed.setLink(getContinuumServerUrl());
feed.setDescription("Continuum build results");
}
Once you've obtained the RSS feed, you need to fetch, or create, the list of RSS entries for it.
Listing 10. Fetching or creating entries
List entries = feed.getEntries();
if (entries == null) {
entries = new ArrayList();
}
Ready, set, connect
Your next step is to obtain the list of projects being built on the Continuum server. To do this, you use the Continuum RPC library. Including this library in a Maven project is easy to do with the following dependency declaration:
Listing 11. Adding the Continuum RPC library to your dependencies
org.apache.maven.continuum
continuum-xmlrpc-client
1.1-beta-1
Next, you connect to the Continuum server, using the ContinuumXmlRpcClient
class and the special "xmlrpc
" URL.
Listing 12. ContinuumXmlRpcClient
ContinuumXmlRpcClient client
= new ContinuumXmlRpcClient(
new URL("),
getUsername(),getPassword());
You will need to provide an administrator-level username and password here. You then fetch the list of project groups and projects for each group.
Listing 13. Fetching project groups and projects
List
groups = client.getAllProjectGroups(); for (ProjectGroup group : groups) { List projects = client.getProjects(group.getId()); for (Project project : projects) { The build report
With Rome and Continuum talking, you can get to the heart of the matter, which is comparing the current state of each project to the previous project state. If the project state has changed, you may need to report it, as shown in Listing 14.
Listing 14. Reporting state change
int state = project.getState(); int prevState = -1; if (previousState.containsKey(project.getName())) { prevState = previousState.get(project.getName()); } if (prevState != state) { previousState.put(project.getName(), state); String buildStateMessage = null; if ((state == 1) || (state == 10)) { buildStateMessage = "New build"; } else if (state == 2) { buildStateMessage = "Successful build"; } else if (state == 3) { buildStateMessage = "Failed build"; } else if (state == 4) { buildStateMessage = "Build error"; }
If a significant state change has occurred, you create a new RSS entry with a link to the build results and add it to your RSS feed. Finally, you write the new RSS feed to the disk.
Listing 15. Writing to disk
if (buildStateMessage != null) { SyndEntry entry = new SyndEntryImpl(); entry.setTitle(project.getName() + " : " + buildStateMessage); entry .setLink(getContinuumServerUrl() + "/servlet/continuum/target/ProjectBuild.vm?view=ProjectBuild&buildId=" + project.getLatestBuildId() + "&id=" + project.getId()); entry.setPublishedDate(new Date()); entries.add(entry); } } } } feed.setEntries(entries); Writer writer = new FileWriter(getRssFeedFilename()); SyndFeedOutput output = new SyndFeedOutput(); output.output(feed,writer); writer.close(); }
Now you need to call this method at regular intervals, to keep tabs on the build results. The
startScheduler()
method starts aTimer
instance that does just that, based on theupdateFrequency
property.Listing 16. Scheduler goes to work
public void startScheduler() { if (timer != null) { timer.cancel(); } timer = new Timer(); timer.schedule(new TimerTask() { public void run() { try { updateLatestBuildResults(); } catch (Exception e) { e.printStackTrace(); } } }, 0, updateFrequency * 1000); }
All you have to do now is create an instance of the bean and call this method to start the monitoring process. The sample source code also allows you to run the class from the command line, and to specify properties as command-line options.
The
RssPublisher
class will now produce an RSS feed and send it, by default, to a file calledrss/builds.xml
. Publishing the feed to a Web server is straightforward -- any old Web server, such as Tomcat, Jetty, or Apache, will do the job. The simplest approach is to run your feed class on the home (or some other) directory of your Web server. It will monitor the Continuum server and update therss/builds.xml
file whenever necessary. Users can subscribe to the feed just as they would any other RSS feed.In conclusion
Rome's charter is to end syndication feed confusion by supporting all formats, meaning the many variants of RSS as well as Atom. In this article I've introduced you to the Rome API and shown you how to use it to create and manage RSS feeds. I've also walked you through the practical and useful example of setting up syndicated feeds for a continuous integration server. While some CI servers (such as Hudson) come with RSS built in, others like Continuum still require some hand tooling. After reading this article you should be feeling pretty comfortable with the Rome API. See the source code download if you want to play around with the CI server class some more.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/71047/viewspace-996760/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Rss-Rome 閱讀器讀取XML檔案XML
- 使用YQL(Google Feed API替代方案)顯示RSS源(2)GoAPI
- 前端工具Rome將用Rust改寫前端Rust
- [ACTF新生賽2020]rome
- su -s /bin/sh -c “nova-manage api_db sync“ nova報錯API
- 使用 PubSubHubbub 製作 RSS 定時器 —— Laravel RSS (三)定時器Laravel
- manage-docs-versions
- RSS 語法概述
- 瞭解下RSS 元素
- RSS概念和使用
- AFX_MANAGE_STATE(AfxGetStaticModuleState())
- manage logical standby databaseDatabase
- RSS-proxy可建立任何網站的RSS或ATOM提要網站
- php生成rss訂閱PHP
- RSS Reader in PC & iPhoneiPhone
- C#解讀RSSC#
- Leaf for Mac RSS閱讀器Mac
- C# 生成RSS通用類C#
- RSS Fever API 服務搭建避坑指南(FreshRSS + Fluent Reader, 2024年最新可用教程)API
- RSS Menu for Mac(選單欄rss閱讀管理器) v3.1啟用版Mac
- 測試rss與navicat連線
- RSS生成工具/服務推薦
- 如何使用Java訂閱RSS Feed?Java
- GraphQL 配合 JWT 使用 —— Laravel RSS (二)JWTLaravel
- 用newsbeauter收the old reader RSS
- 給你的部落格新增RSS
- SAP Fiori 應用 Manage Workflows for Purchase RequisitionsUI
- Newsflow for mac RSS新聞閱讀器Mac
- Reeder for Mac(rss新聞閱讀器)Mac
- CSS3 實現RSS圖示CSSS3
- C#讀取Rss功能函式C#函式
- Node.js NPM Tutorial: Create, Publish, Extend & ManageNode.jsNPM
- 基於業務沉澱元件 manage-table元件
- 基於業務沉澱元件 => manage-table元件
- Using Supplied Packages to Manage Stored OutlinesPackage
- ReadKit for Mac(全功能RSS閱讀器)Mac
- Feeder for Mac rss文件編輯和釋出Mac
- QuiteRSS: Linux桌面的RSS閱讀器UILinux