/********************************************************************************
* CruiseControl, a Continuous Integration Toolkit
* Copyright (c) 2005, ThoughtWorks, Inc.
* 200 E. Randolph, 25th Floor
* Chicago, IL 60601 USA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* + Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************************/
package net.sourceforge.cruisecontrol.publishers.rss;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.apache.log4j.Logger;
/**
* The feed class acts as a generic RSS Feed (there's no CruiseControl-specific
* functionality in this class).
*
* Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
* Licensed under the CruiseControl BSD license
* @author Patrick Conant
*/
public class Feed {
private static final Logger LOG = Logger.getLogger(Feed.class);
private String channelTitle;
private String channelLink;
private String channelDescription;
private String channelLanguage = "en-US";
private int maxLength = 20;
private final List<Item> items = new ArrayList<Item>();
/**
* Constructor
*
* @param publishToFile the file to which the feed should be published.
*/
public Feed(final File publishToFile) {
// If we can read the file then load the RSSFeed settings from the existing file...
if (publishToFile.exists() && publishToFile.canRead()) {
try {
final SAXBuilder builder = new SAXBuilder();
final Document doc = builder.build(publishToFile);
if (doc.getRootElement() != null
&& doc.getRootElement().getChild(RSS.NODE_CHANNEL) != null) {
final Element channelElement = doc.getRootElement().getChild(RSS.NODE_CHANNEL);
if (channelElement.getChild(RSS.NODE_CHANNEL_TITLE) != null) {
this.channelTitle =
channelElement.getChild(RSS.NODE_CHANNEL_TITLE).getText().trim();
}
if (channelElement.getChild(RSS.NODE_CHANNEL_LINK) != null) {
this.channelLink =
channelElement.getChild(RSS.NODE_CHANNEL_LINK).getText().trim();
}
if (channelElement.getChild(RSS.NODE_CHANNEL_DESCRIPTION) != null) {
this.channelDescription =
channelElement.getChild(RSS.NODE_CHANNEL_DESCRIPTION).getText().trim();
}
if (channelElement.getChildren(RSS.NODE_ITEM) != null) {
final List itemNodes = channelElement.getChildren(RSS.NODE_ITEM);
for (final Object itemNode : itemNodes) {
this.items.add(new Item((Element) itemNode));
}
}
} else {
LOG.info("existing RSS file doesn't appear to be valid. Missnig root element or channel node.");
}
// Now sort the items from the old XML and remove enough to get to maxSize.
Collections.sort(this.items);
while (this.items.size() > this.maxLength) {
this.items.remove(this.items.size() - 1);
}
} catch (JDOMException jex) {
LOG.error("jdom exception while parsing existing RSS file " + publishToFile.getPath()
+ "; deleting file and starting over...", jex);
publishToFile.delete();
} catch (IOException ioe) {
LOG.error("IOException while reading existing RSS file " + publishToFile.getPath()
+ "; deleting file and starting over...", ioe);
publishToFile.delete();
}
} else {
LOG.info("Unable to locate or read the existing RSS feed file.");
}
}
/**
* Set the title of the RSS feed. The title will go into the /rss/title
* element in the RSS XML.
*
* @param title the title of the RSS feed.
*/
public void setTitle(final String title) {
this.channelTitle = title;
}
/**
* Returns the title of the RSS feed. The title goes into the /rss/title
* element in the RSS XML.
*
* @return title the title of the RSS feed.
*/
public String getTitle() {
return this.channelTitle;
}
public void setLink(final String link) {
this.channelLink = link;
}
public String getLink() {
return this.channelLink;
}
public void setDescription(final String description) {
this.channelDescription = description;
}
public String getDescription() {
return this.channelDescription;
}
public void setMaxLength(final int max) {
this.maxLength = max;
}
public int getMaxLength() {
return this.maxLength;
}
public void addItem(final Item item) {
synchronized (this.items) {
if (this.items.size() == this.maxLength) {
this.items.remove(this.items.size() - 1);
}
this.items.add(0, item);
}
}
public List getItems() {
return this.items;
}
public void write(final Writer wr) throws IOException {
final BufferedWriter br = new BufferedWriter(wr);
br.write("<?xml version=\"1.0\" ?>\n");
br.write("<rss version=\"2.0\">\n");
br.write(" <channel>\n");
br.write(" <title>");
if (this.getTitle() != null) {
br.write(this.getTitle());
}
br.write("</title>\n");
br.write(" <link>");
if (this.getLink() != null) {
br.write(this.getLink());
}
br.write("</link>\n");
br.write(" <description>");
if (this.getDescription() != null) {
br.write(this.getDescription());
}
br.write("</description>\n");
br.write(" <language>");
br.write(this.channelLanguage);
br.write("</language>\n");
for (final Item item : this.items) {
//write each item...
if (item != null) {
br.write(item.toXml());
}
}
br.write(" </channel>\n");
br.write("</rss>\n");
br.flush();
}
}