View Javadoc

1   /*
2    * Copyright 2004 Sun Microsystems, Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   */
17  package com.sun.syndication.io.impl;
18  
19  import java.io.StringReader;
20  import java.util.Iterator;
21  import java.util.List;
22  
23  import org.jdom.Attribute;
24  import org.jdom.Document;
25  import org.jdom.Element;
26  import org.jdom.Namespace;
27  import org.jdom.input.SAXBuilder;
28  
29  import com.sun.syndication.feed.WireFeed;
30  import com.sun.syndication.feed.atom.Category;
31  import com.sun.syndication.feed.atom.Content;
32  import com.sun.syndication.feed.atom.Entry;
33  import com.sun.syndication.feed.atom.Feed;
34  import com.sun.syndication.feed.atom.Generator;
35  import com.sun.syndication.feed.atom.Link;
36  import com.sun.syndication.feed.atom.Person;
37  import com.sun.syndication.io.FeedException;
38  import com.sun.syndication.io.WireFeedOutput;
39  import java.io.IOException;
40  import java.io.Writer;
41  import java.util.ArrayList;
42  import org.jdom.output.XMLOutputter;
43  
44  /***
45   * Feed Generator for Atom
46   * <p/>
47   *
48   * @author Elaine Chien
49   * @author Dave Johnson (updated for Atom 1.0)
50   *
51   */
52  
53  public class Atom10Generator extends BaseWireFeedGenerator {
54      private static final String ATOM_10_URI = "http://www.w3.org/2005/Atom";
55      private static final Namespace ATOM_NS = Namespace.getNamespace(ATOM_10_URI);
56  
57      private String _version;
58  
59      public Atom10Generator() {
60          this("atom_1.0","1.0");
61      }
62  
63      protected Atom10Generator(String type,String version) {
64          super(type);
65          _version = version;
66      }
67  
68      protected String getVersion() {
69          return _version;
70      }
71  
72      protected Namespace getFeedNamespace() {
73          return ATOM_NS;
74      }
75  
76      public Document generate(WireFeed wFeed) throws FeedException {
77          Feed feed = (Feed) wFeed;
78          Element root = createRootElement(feed);
79          populateFeed(feed,root);
80          purgeUnusedNamespaceDeclarations(root);
81          return createDocument(root);
82      }
83  
84      protected Document createDocument(Element root) {
85          return new Document(root);
86      }
87  
88      protected Element createRootElement(Feed feed) {
89          Element root = new Element("feed",getFeedNamespace());
90          root.addNamespaceDeclaration(getFeedNamespace());
91          //Attribute version = new Attribute("version", getVersion());
92          //root.setAttribute(version);
93          if (feed.getXmlBase() != null) {
94              root.setAttribute("base", feed.getXmlBase(), Namespace.XML_NAMESPACE);
95          }
96          generateModuleNamespaceDefs(root);
97          return root;
98      }
99  
100     protected void populateFeed(Feed feed,Element parent) throws FeedException  {
101         addFeed(feed,parent);
102         addEntries(feed,parent);
103     }
104 
105     protected void addFeed(Feed feed,Element parent) throws FeedException {
106         Element eFeed = parent;
107         populateFeedHeader(feed,eFeed);
108         generateForeignMarkup(eFeed, (List)feed.getForeignMarkup());
109         checkFeedHeaderConstraints(eFeed);
110         generateFeedModules(feed.getModules(),eFeed);
111     }
112 
113     protected void addEntries(Feed feed,Element parent) throws FeedException {
114         List items = feed.getEntries();
115         for (int i=0;i<items.size();i++) {
116             addEntry((Entry)items.get(i),parent);
117         }
118         checkEntriesConstraints(parent);
119     }
120 
121     protected void addEntry(Entry entry,Element parent) throws FeedException {
122         Element eEntry = new Element("entry", getFeedNamespace());
123         if (entry.getXmlBase() != null) {
124             eEntry.setAttribute("base", entry.getXmlBase(), Namespace.XML_NAMESPACE);
125         }
126         populateEntry(entry,eEntry);
127         generateForeignMarkup(eEntry, (List)entry.getForeignMarkup());
128         checkEntryConstraints(eEntry);
129         generateItemModules(entry.getModules(),eEntry);
130         parent.addContent(eEntry);
131     }
132 
133     protected void populateFeedHeader(Feed feed,Element eFeed) throws FeedException {
134         if (feed.getTitleEx() != null) {
135             Element titleElement = new Element("title", getFeedNamespace());
136             fillContentElement(titleElement, feed.getTitleEx());
137             eFeed.addContent(titleElement);
138         }
139 
140         List links = feed.getAlternateLinks();
141         if (links != null) for (int i = 0; i < links.size(); i++) {
142             eFeed.addContent(generateLinkElement((Link)links.get(i)));
143         }
144         links = feed.getOtherLinks();
145         if (links != null) for (int j = 0; j < links.size(); j++) {
146             eFeed.addContent(generateLinkElement((Link)links.get(j)));
147         }
148 
149         List cats = feed.getCategories();
150         if (cats != null) for (Iterator iter=cats.iterator(); iter.hasNext();) {
151             eFeed.addContent(generateCategoryElement((Category)iter.next()));
152         }
153             
154         List authors = feed.getAuthors();
155         if (authors != null && authors.size() > 0) {
156             for (int i = 0; i < authors.size(); i++) {
157                 Element authorElement = new Element("author", getFeedNamespace());
158                 fillPersonElement(authorElement, (Person)feed.getAuthors().get(i));
159                 eFeed.addContent(authorElement);
160             }
161         }
162 
163         List contributors = feed.getContributors();
164         if (contributors != null && contributors.size() > 0) {
165             for (int i = 0; i < contributors.size(); i++) {
166                 Element contributorElement = new Element("contributor", getFeedNamespace());
167                 fillPersonElement(contributorElement, (Person)contributors.get(i));
168                 eFeed.addContent(contributorElement);
169             }
170         }
171 
172         if (feed.getSubtitle() != null) {
173           Element subtitleElement = new Element("subtitle", getFeedNamespace());
174           fillContentElement(subtitleElement, feed.getSubtitle());
175                 eFeed.addContent(subtitleElement);
176         }
177 
178         if (feed.getId() != null) {
179             eFeed.addContent(generateSimpleElement("id", feed.getId()));
180         }
181 
182         if (feed.getGenerator() != null) {
183             eFeed.addContent(generateGeneratorElement(feed.getGenerator()));
184         }
185 
186         if (feed.getRights() != null) {
187             eFeed.addContent(generateSimpleElement("rights", feed.getRights()));
188         }
189 
190         if (feed.getIcon() != null) {
191           eFeed.addContent(generateSimpleElement("icon", feed.getIcon()));
192         }
193 
194         if (feed.getLogo() != null) {
195           eFeed.addContent(generateSimpleElement("logo", feed.getLogo()));
196         }
197 
198         if (feed.getUpdated() != null) {
199             Element updatedElement = new Element("updated", getFeedNamespace());
200             updatedElement.addContent(DateParser.formatW3CDateTime(feed.getUpdated()));
201             eFeed.addContent(updatedElement);
202         }
203     }
204 
205     protected void populateEntry(Entry entry, Element eEntry) throws FeedException {
206         if (entry.getTitleEx() != null) {
207             Element titleElement = new Element("title", getFeedNamespace());
208             fillContentElement(titleElement, entry.getTitleEx());
209             eEntry.addContent(titleElement);
210         }
211         List links = entry.getAlternateLinks();
212         if (links != null) {
213             for (int i = 0; i < links.size(); i++) {
214                 eEntry.addContent(generateLinkElement((Link)links.get(i)));
215             }
216         }
217         links = entry.getOtherLinks();
218         if (links != null) {
219             for (int i = 0; i < links.size(); i++) {
220                 eEntry.addContent(generateLinkElement((Link)links.get(i)));
221             }
222         }
223 
224         List cats = entry.getCategories();
225         if (cats != null) {
226             for (int i = 0; i < cats.size(); i++) {
227                 eEntry.addContent(generateCategoryElement((Category)cats.get(i)));
228             }
229         }
230         
231         List authors = entry.getAuthors();
232         if (authors != null && authors.size() > 0) {
233             for (int i = 0; i < authors.size(); i++)  {
234                 Element authorElement = new Element("author", getFeedNamespace());
235                 fillPersonElement(authorElement, (Person)entry.getAuthors().get(i));
236                 eEntry.addContent(authorElement);            
237             }
238         }
239 
240         List contributors = entry.getContributors();
241         if (contributors != null && contributors.size() > 0) {
242             for (int i = 0; i < contributors.size(); i++) {
243                 Element contributorElement = new Element("contributor", getFeedNamespace());
244                 fillPersonElement(contributorElement, (Person)contributors.get(i));
245                 eEntry.addContent(contributorElement);
246             }
247         }
248         if (entry.getId() != null) {
249             eEntry.addContent(generateSimpleElement("id", entry.getId()));
250         }
251 
252         if (entry.getUpdated() != null) {
253             Element updatedElement = new Element("updated", getFeedNamespace());
254             updatedElement.addContent(DateParser.formatW3CDateTime(entry.getUpdated()));
255             eEntry.addContent(updatedElement);
256         }
257 
258         if (entry.getPublished() != null) {
259             Element publishedElement = new Element("published", getFeedNamespace());
260             publishedElement.addContent(DateParser.formatW3CDateTime(entry.getPublished()));
261             eEntry.addContent(publishedElement);
262         }
263 
264         if (entry.getContents() != null && entry.getContents().size() > 0) {
265             Element contentElement = new Element("content", getFeedNamespace());
266             Content content = (Content)entry.getContents().get(0);
267             fillContentElement(contentElement, content);
268             eEntry.addContent(contentElement);
269         }
270 
271         if (entry.getSummary() != null) {
272             Element summaryElement = new Element("summary", getFeedNamespace());
273             fillContentElement(summaryElement, entry.getSummary());
274             eEntry.addContent(summaryElement);
275         }
276 
277         if (entry.getSource() != null) {
278         	Element sourceElement = new Element("source", getFeedNamespace());
279             populateFeedHeader(entry.getSource(), sourceElement);
280             eEntry.addContent(sourceElement);
281         }
282     }
283 
284     protected void checkFeedHeaderConstraints(Element eFeed) throws FeedException {
285     }
286 
287     protected void checkEntriesConstraints(Element parent) throws FeedException {
288     }
289 
290     protected void checkEntryConstraints(Element eEntry) throws FeedException {
291     }
292 
293 
294     protected Element generateCategoryElement(Category cat) {
295         Element catElement = new Element("category", getFeedNamespace());
296 
297         if (cat.getTerm() != null) {
298             Attribute termAttribute = new Attribute("term", cat.getTerm());
299             catElement.setAttribute(termAttribute);
300         }
301 
302         if (cat.getLabel() != null) {
303             Attribute labelAttribute = new Attribute("label", cat.getLabel());
304             catElement.setAttribute(labelAttribute);
305         }
306 
307         if (cat.getScheme() != null) {
308             Attribute schemeAttribute = new Attribute("scheme", cat.getScheme());
309             catElement.setAttribute(schemeAttribute);
310         }
311         return catElement;
312     }
313 
314     protected Element generateLinkElement(Link link) {
315         Element linkElement = new Element("link", getFeedNamespace());
316 
317         if (link.getRel() != null) {
318             Attribute relAttribute = new Attribute("rel", link.getRel());
319             linkElement.setAttribute(relAttribute);
320         }
321 
322         if (link.getType() != null) {
323             Attribute typeAttribute = new Attribute("type", link.getType());
324             linkElement.setAttribute(typeAttribute);
325         }
326 
327         if (link.getHref() != null) {
328             Attribute hrefAttribute = new Attribute("href", link.getHref());
329             linkElement.setAttribute(hrefAttribute);
330         }
331         
332         if (link.getHreflang() != null) {
333             Attribute hreflangAttribute = new Attribute("hreflang", link.getHreflang());
334             linkElement.setAttribute(hreflangAttribute);
335         }
336         if (link.getTitle() != null) {
337             Attribute title = new Attribute("title", link.getTitle());
338             linkElement.setAttribute(title);
339         }
340         if (link.getLength() != 0) {
341             Attribute lenght = new Attribute("length", Long.toString(link.getLength()));
342             linkElement.setAttribute(lenght);
343         }
344         return linkElement;
345     }
346 
347 
348     protected void fillPersonElement(Element element, Person person) {
349         if (person.getName() != null) {
350             element.addContent(generateSimpleElement("name", person.getName()));
351         }
352         if (person.getUri() != null) {
353             element.addContent(generateSimpleElement("uri", person.getUri()));
354         }
355 
356         if (person.getEmail() != null) {
357             element.addContent(generateSimpleElement("email", person.getEmail()));
358         }
359     }
360 
361     protected Element generateTagLineElement(Content tagline) {
362         Element taglineElement = new Element("subtitle", getFeedNamespace());
363 
364         if (tagline.getType() != null) {
365             Attribute typeAttribute = new Attribute("type", tagline.getType());
366             taglineElement.setAttribute(typeAttribute);
367         }
368 
369         if (tagline.getValue() != null) {
370             taglineElement.addContent(tagline.getValue());
371         }
372         return taglineElement;
373     }
374 
375     protected void fillContentElement(Element contentElement, Content content)
376         throws FeedException {
377 
378         String type = content.getType();
379             String atomType = type;
380         if (type != null) {
381             // Fix for issue #39 "Atom 1.0 Text Types Not Set Correctly"
382             // we're not sure who set this value, so ensure Atom types are used
383             if ("text/plain".equals(type)) atomType = Content.TEXT;
384             else if ("text/html".equals(type)) atomType = Content.HTML;
385             else if ("application/xhtml+xml".equals(type)) atomType = Content.XHTML;
386             
387             Attribute typeAttribute = new Attribute("type", atomType);
388             contentElement.setAttribute(typeAttribute);
389         }
390         String href = content.getSrc();
391         if (href != null) {
392             Attribute srcAttribute = new Attribute("src", href);
393             contentElement.setAttribute(srcAttribute);
394         }
395         if (content.getValue() != null) {
396             if (atomType != null && (atomType.equals(Content.XHTML) || (atomType.indexOf("/xml")) != -1 ||
397                 (atomType.indexOf("+xml")) != -1)) {
398 
399                 StringBuffer tmpDocString = new StringBuffer("<tmpdoc>");
400                 tmpDocString.append(content.getValue());
401                 tmpDocString.append("</tmpdoc>");
402                 StringReader tmpDocReader = new StringReader(tmpDocString.toString());
403                 Document tmpDoc;
404                 try {
405                     SAXBuilder saxBuilder = new SAXBuilder();
406                     tmpDoc = saxBuilder.build(tmpDocReader);
407                 }
408                 catch (Exception ex) {
409                     throw new FeedException("Invalid XML",ex);
410                 }
411                 List children = tmpDoc.getRootElement().removeContent();
412                 contentElement.addContent(children);
413             } else { 
414                 // must be type html, text or some other non-XML format
415                 // JDOM will escape property for XML
416                 contentElement.addContent(content.getValue());
417             }
418         }
419     }
420 
421     protected Element generateGeneratorElement(Generator generator) {
422         Element generatorElement = new Element("generator", getFeedNamespace());
423 
424         if (generator.getUrl() != null) {
425             Attribute urlAttribute = new Attribute("uri", generator.getUrl());
426             generatorElement.setAttribute(urlAttribute);
427         }
428 
429         if (generator.getVersion() != null) {
430             Attribute versionAttribute = new Attribute("version", generator.getVersion());
431             generatorElement.setAttribute(versionAttribute);
432         }
433 
434         if (generator.getValue() != null) {
435             generatorElement.addContent(generator.getValue());
436         }
437 
438         return generatorElement;
439 
440     }
441 
442     protected Element generateSimpleElement(String name, String value) {
443         Element element = new Element(name, getFeedNamespace());
444         element.addContent(value);
445         return element;
446     }
447     
448     /***
449      * Utility method to serialize an entry to writer.
450      */
451     public static void serializeEntry(Entry entry, Writer writer)
452         throws IllegalArgumentException, FeedException, IOException {
453         
454         // Build a feed containing only the entry
455         List entries = new ArrayList();
456         entries.add(entry);
457         Feed feed1 = new Feed();
458         feed1.setFeedType("atom_1.0");
459         feed1.setEntries(entries);
460 
461         // Get Rome to output feed as a JDOM document
462         WireFeedOutput wireFeedOutput = new WireFeedOutput();
463         Document feedDoc = wireFeedOutput.outputJDom(feed1);
464 
465         // Grab entry element from feed and get JDOM to serialize it
466         Element entryElement= (Element)feedDoc.getRootElement().getChildren().get(0);
467 
468         XMLOutputter outputter = new XMLOutputter();
469         outputter.output(entryElement, writer);
470     }
471 
472 }