/**
*
* Copyright 2005 LogicBlaze, Inc. http://www.logicblaze.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**/
package org.servicemix.components.rss;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndEntryImpl;
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.SyndFeedInput;
import com.sun.syndication.io.SyndFeedOutput;
import com.sun.syndication.io.XmlReader;
import org.servicemix.components.util.OutBinding;
import org.servicemix.expression.ConstantExpression;
import org.servicemix.expression.Expression;
import org.servicemix.expression.ExpressionHelper;
import org.servicemix.jbi.jaxp.SourceTransformer;
import javax.jbi.JBIException;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.messaging.MessagingException;
import javax.jbi.messaging.NormalizedMessage;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* This component generates an RSS/Atom Feed from the JBI messages it receives.
*
* @version $Revision$
*/
public class FeedWriter extends OutBinding {
private String feedType = "atom_0.3";
private SyndFeed cachedFeed;
private String title;
private String link = "http://servicemix.org/RSS";
private Expression entryTitle;
private Expression entryValue;
private String feedDescription = "This feed is auto-generated by ServiceMix";
private int maximumEntryCount = 200;
private File feedFile;
private String contentType = "text/plain";
private SourceTransformer sourceTransformer = new SourceTransformer();
private boolean loadOnStartup = true;
public SyndFeed getCachedFeed() throws IllegalArgumentException, FeedException, IOException {
if (cachedFeed == null) {
cachedFeed = loadOrCreateFeed();
}
return cachedFeed;
}
public void setCachedFeed(SyndFeed feed) {
this.cachedFeed = feed;
}
public String getFeedType() {
return feedType;
}
public void setFeedType(String feedType) {
this.feedType = feedType;
}
public String getFeedDescription() {
return feedDescription;
}
public void setFeedDescription(String feedDescription) {
this.feedDescription = feedDescription;
}
public String getTitle() {
if (title == null) {
title = "ServiceMix feed for service: " + getService();
}
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public Expression getEntryTitle() {
return entryTitle;
}
public void setEntryTitle(Expression title) {
this.entryTitle = title;
}
public Expression getEntryValue() {
return entryValue;
}
public void setEntryValue(Expression entryValue) {
this.entryValue = entryValue;
}
public int getMaximumEntryCount() {
return maximumEntryCount;
}
public void setMaximumEntryCount(int maximumEntryCount) {
this.maximumEntryCount = maximumEntryCount;
}
public File getFeedFile() {
if (feedFile == null) {
throw new IllegalArgumentException("You must set the 'feedFile' property");
}
return feedFile;
}
public void setFeedFile(File feedFile) {
this.feedFile = feedFile;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public SourceTransformer getSourceTransformer() {
return sourceTransformer;
}
public void setSourceTransformer(SourceTransformer sourceTransformer) {
this.sourceTransformer = sourceTransformer;
}
public boolean isLoadOnStartup() {
return loadOnStartup;
}
public void setLoadOnStartup(boolean loadOnStartup) {
this.loadOnStartup = loadOnStartup;
}
// Implementation methods
// -------------------------------------------------------------------------
protected void init() throws JBIException {
super.init();
// enforce validation
File file = getFeedFile();
if (file.exists() && file.isDirectory()) {
throw new IllegalArgumentException("Cannot generate the cachedFeed as the cachedFeed file is a directory: " + file);
}
}
protected void process(MessageExchange exchange, NormalizedMessage message) throws MessagingException {
try {
SyndFeed feed = getCachedFeed();
addMessageToFeed(feed, exchange, message);
removeExpiredEntries(feed);
writeFeed(feed, exchange, message);
done(exchange);
}
catch (IOException e) {
throw new MessagingException(e);
}
catch (FeedException e) {
throw new MessagingException(e);
}
catch (TransformerException e) {
throw new MessagingException(e);
}
}
protected void addMessageToFeed(SyndFeed feed, MessageExchange exchange, NormalizedMessage message) throws TransformerException, MessagingException {
List entries = feed.getEntries();
SyndEntry entry = createEntry(exchange, message);
SyndContent description = createEntryContent(exchange, message);
entry.setDescription(description);
// TODO this line really should work but for some reason it doesn't
// entries.add(0, entry);
List temp = new ArrayList();
temp.add(entry);
temp.addAll(entries);
feed.setEntries(temp);
}
protected SyndEntry createEntry(MessageExchange exchange, NormalizedMessage message) throws MessagingException {
SyndEntry entry = new SyndEntryImpl();
entry.setTitle(ExpressionHelper.asString(getEntryTitle(), exchange, message, "ServiceMix Feed"));
entry.setLink(getLink());
entry.setPublishedDate(new Date());
return entry;
}
protected SyndContent createEntryContent(MessageExchange exchange, NormalizedMessage message) throws TransformerException, MessagingException {
SyndContent description = new SyndContentImpl();
description.setType(contentType);
Source content = message.getContent();
String value = ExpressionHelper.asString(getEntryValue(), exchange, message, null);
if (value == null && content != null) {
value = getSourceTransformer().toString(content);
value = encodeContent(value);
}
if (value != null) {
description.setValue(value);
}
return description;
}
/**
* Encodes the content so its valid XML when used inside an entry
*/
protected String encodeContent(String value) {
return "<![CDATA[" + value + "]]>";
}
protected void writeFeed(SyndFeed feed, MessageExchange messageExchange, NormalizedMessage message) throws IOException, FeedException {
Writer writer = new FileWriter(feedFile);
SyndFeedOutput output = new SyndFeedOutput();
output.output(feed, writer);
writer.close();
}
/**
* Removes any old entires no longer required in the cachedFeed
*
* @param feed
*/
protected void removeExpiredEntries(SyndFeed feed) {
// lets limit the count
if (maximumEntryCount > 0) {
List entries = feed.getEntries();
int size = entries.size();
if (size > maximumEntryCount) {
entries.subList(maximumEntryCount, size).clear();
}
}
}
protected SyndFeed loadOrCreateFeed() throws IllegalArgumentException, FeedException, IOException {
if (isLoadOnStartup()) {
File file = getFeedFile();
if (file.exists() && file.isFile()) {
SyndFeedInput input = new SyndFeedInput();
XmlReader xmlReader = new XmlReader(file);
return input.build(xmlReader);
}
}
return createFeed();
}
protected SyndFeed createFeed() {
SyndFeed feed = new SyndFeedImpl();
feed.setFeedType(feedType);
feed.setTitle(getTitle());
feed.setLink(getLink());
feed.setDescription(getFeedDescription());
return feed;
}
}