001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.servicemix.components.rss;
018:
019: import com.sun.syndication.feed.synd.SyndContent;
020: import com.sun.syndication.feed.synd.SyndContentImpl;
021: import com.sun.syndication.feed.synd.SyndEntry;
022: import com.sun.syndication.feed.synd.SyndEntryImpl;
023: import com.sun.syndication.feed.synd.SyndFeed;
024: import com.sun.syndication.feed.synd.SyndFeedImpl;
025: import com.sun.syndication.io.FeedException;
026: import com.sun.syndication.io.SyndFeedInput;
027: import com.sun.syndication.io.SyndFeedOutput;
028: import com.sun.syndication.io.XmlReader;
029:
030: import org.apache.servicemix.components.util.OutBinding;
031: import org.apache.servicemix.expression.Expression;
032: import org.apache.servicemix.expression.ExpressionHelper;
033: import org.apache.servicemix.jbi.jaxp.SourceTransformer;
034:
035: import javax.jbi.JBIException;
036: import javax.jbi.messaging.MessageExchange;
037: import javax.jbi.messaging.MessagingException;
038: import javax.jbi.messaging.NormalizedMessage;
039: import javax.xml.transform.Source;
040: import javax.xml.transform.TransformerException;
041:
042: import java.io.File;
043: import java.io.FileWriter;
044: import java.io.IOException;
045: import java.io.Writer;
046: import java.util.ArrayList;
047: import java.util.Date;
048: import java.util.List;
049:
050: /**
051: * This component generates an RSS/Atom Feed from the JBI messages it receives.
052: *
053: * @version $Revision: 579627 $
054: */
055: public class FeedWriter extends OutBinding {
056:
057: private String feedType = "atom_0.3";
058: private SyndFeed cachedFeed;
059: private String title;
060: private String link = "http://servicemix.org/RSS";
061: private Expression entryTitle;
062: private Expression entryValue;
063: private String feedDescription = "This feed is auto-generated by ServiceMix";
064: private int maximumEntryCount = 200;
065: private File feedFile;
066: private String contentType = "text/plain";
067: private SourceTransformer sourceTransformer = new SourceTransformer();
068: private boolean loadOnStartup = true;
069:
070: public synchronized SyndFeed getCachedFeed()
071: throws IllegalArgumentException, FeedException, IOException {
072: if (cachedFeed == null) {
073: cachedFeed = loadOrCreateFeed();
074: }
075: return cachedFeed;
076: }
077:
078: public void setCachedFeed(SyndFeed feed) {
079: this .cachedFeed = feed;
080: }
081:
082: public String getFeedType() {
083: return feedType;
084: }
085:
086: public void setFeedType(String feedType) {
087: this .feedType = feedType;
088: }
089:
090: public String getFeedDescription() {
091: return feedDescription;
092: }
093:
094: public void setFeedDescription(String feedDescription) {
095: this .feedDescription = feedDescription;
096: }
097:
098: public String getTitle() {
099: if (title == null) {
100: title = "ServiceMix feed for service: " + getService();
101: }
102: return title;
103: }
104:
105: public void setTitle(String title) {
106: this .title = title;
107: }
108:
109: public String getLink() {
110: return link;
111: }
112:
113: public void setLink(String link) {
114: this .link = link;
115: }
116:
117: public Expression getEntryTitle() {
118: return entryTitle;
119: }
120:
121: public void setEntryTitle(Expression title) {
122: this .entryTitle = title;
123: }
124:
125: public Expression getEntryValue() {
126: return entryValue;
127: }
128:
129: public void setEntryValue(Expression entryValue) {
130: this .entryValue = entryValue;
131: }
132:
133: public int getMaximumEntryCount() {
134: return maximumEntryCount;
135: }
136:
137: public void setMaximumEntryCount(int maximumEntryCount) {
138: this .maximumEntryCount = maximumEntryCount;
139: }
140:
141: public File getFeedFile() {
142: if (feedFile == null) {
143: throw new IllegalArgumentException(
144: "You must set the 'feedFile' property");
145: }
146: return feedFile;
147: }
148:
149: public void setFeedFile(File feedFile) {
150: this .feedFile = feedFile;
151: }
152:
153: public String getContentType() {
154: return contentType;
155: }
156:
157: public void setContentType(String contentType) {
158: this .contentType = contentType;
159: }
160:
161: public SourceTransformer getSourceTransformer() {
162: return sourceTransformer;
163: }
164:
165: public void setSourceTransformer(SourceTransformer sourceTransformer) {
166: this .sourceTransformer = sourceTransformer;
167: }
168:
169: public boolean isLoadOnStartup() {
170: return loadOnStartup;
171: }
172:
173: public void setLoadOnStartup(boolean loadOnStartup) {
174: this .loadOnStartup = loadOnStartup;
175: }
176:
177: // Implementation methods
178: // -------------------------------------------------------------------------
179:
180: protected void init() throws JBIException {
181: super .init();
182:
183: // enforce validation
184: File file = getFeedFile();
185: if (file.exists() && file.isDirectory()) {
186: throw new IllegalArgumentException(
187: "Cannot generate the cachedFeed as the cachedFeed file is a directory: "
188: + file);
189: }
190: }
191:
192: protected void process(MessageExchange exchange,
193: NormalizedMessage message) throws Exception {
194: SyndFeed feed = getCachedFeed();
195: synchronized (feed) {
196: addMessageToFeed(feed, exchange, message);
197: removeExpiredEntries(feed);
198: writeFeed(feed, exchange, message);
199: }
200: done(exchange);
201: }
202:
203: protected void addMessageToFeed(SyndFeed feed,
204: MessageExchange exchange, NormalizedMessage message)
205: throws TransformerException, MessagingException {
206: List entries = feed.getEntries();
207: SyndEntry entry = createEntry(exchange, message);
208: SyndContent description = createEntryContent(exchange, message);
209: entry.setDescription(description);
210:
211: // TODO this line really should work but for some reason it doesn't
212: // entries.add(0, entry);
213:
214: List temp = new ArrayList();
215: temp.add(entry);
216: temp.addAll(entries);
217: feed.setEntries(temp);
218: }
219:
220: protected SyndEntry createEntry(MessageExchange exchange,
221: NormalizedMessage message) throws MessagingException {
222: SyndEntry entry = new SyndEntryImpl();
223:
224: entry.setTitle(ExpressionHelper.asString(getEntryTitle(),
225: exchange, message, "ServiceMix Feed"));
226: entry.setLink(getLink());
227: entry.setPublishedDate(new Date());
228: return entry;
229: }
230:
231: protected SyndContent createEntryContent(MessageExchange exchange,
232: NormalizedMessage message) throws TransformerException,
233: MessagingException {
234: SyndContent description = new SyndContentImpl();
235: description.setType(contentType);
236: Source content = message.getContent();
237:
238: String value = ExpressionHelper.asString(getEntryValue(),
239: exchange, message, null);
240: if (value == null && content != null) {
241: value = getSourceTransformer().toString(content);
242: value = encodeContent(value);
243: }
244: if (value != null) {
245: description.setValue(value);
246: }
247: return description;
248: }
249:
250: /**
251: * Encodes the content so its valid XML when used inside an entry
252: */
253: protected String encodeContent(String value) {
254: return "<![CDATA[" + value + "]]>";
255: }
256:
257: protected void writeFeed(SyndFeed feed,
258: MessageExchange messageExchange, NormalizedMessage message)
259: throws IOException, FeedException {
260: Writer writer = new FileWriter(feedFile);
261: SyndFeedOutput output = new SyndFeedOutput();
262: output.output(feed, writer);
263: writer.close();
264: }
265:
266: /**
267: * Removes any old entires no longer required in the cachedFeed
268: *
269: * @param feed
270: */
271: protected void removeExpiredEntries(SyndFeed feed) {
272: // lets limit the count
273: if (maximumEntryCount > 0) {
274: List entries = feed.getEntries();
275: int size = entries.size();
276: if (size > maximumEntryCount) {
277: entries.subList(maximumEntryCount, size).clear();
278: }
279: }
280: }
281:
282: protected SyndFeed loadOrCreateFeed()
283: throws IllegalArgumentException, FeedException, IOException {
284: if (isLoadOnStartup()) {
285: File file = getFeedFile();
286: if (file.exists() && file.isFile()) {
287: SyndFeedInput input = new SyndFeedInput();
288: XmlReader xmlReader = new XmlReader(file);
289: return input.build(xmlReader);
290: }
291: }
292: return createFeed();
293: }
294:
295: protected SyndFeed createFeed() {
296: SyndFeed feed = new SyndFeedImpl();
297: feed.setFeedType(feedType);
298:
299: feed.setTitle(getTitle());
300: feed.setLink(getLink());
301: feed.setDescription(getFeedDescription());
302: return feed;
303: }
304:
305: }
|