Initial refactoring.

This commit is contained in:
kebernet 2011-03-14 23:44:51 +00:00
parent 3a338d4343
commit 1e1207404b
22 changed files with 2971 additions and 1 deletions

View file

@ -5,9 +5,13 @@
<groupId>org.rometools</groupId>
<artifactId>rome-opml</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<version>1.5-SNAPSHOT</version>
<name>rome-opml</name>
<url>http://rometools.jira.com</url>
<description>Support for OPML 1 and OPML 2 in ROME</description>
<issueManagement>
<url>https://rometools.jira.com/secure/IssueNavigator.jspa</url>
</issueManagement>
<developers>
<developer>
<id>kebernet</id>

View file

@ -0,0 +1,107 @@
/*
* Attribute.java
*
* Created on April 24, 2006, 11:11 PM
*
* 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.rometools.feed.opml;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import java.io.Serializable;
/**
* This is a simple name-value pair attribute for outlines.
*
* @author <a href="mailto:cooper@screaming-penguin.com">Robert "kebernet" Cooper</a>
*/
public class Attribute implements Cloneable, Serializable {
private String _name;
private String _value;
/** Creates a new instance of Attribute */
public Attribute() {
super();
}
/**
* Creates a new instance of Attribute.
* @param name name of the attribute.
* @param value value of the attribute.
*/
public Attribute(String name, String value) {
if ((name == null) || (value == null)) {
throw new NullPointerException("Name and value are required.");
}
this.setName(name);
this.setValue(value);
}
/**
* name of the attribute.
* @param name name of the attribute.
*/
public void setName(String name) {
this._name = name;
}
/**
* name of the attribute.
* @return name of the attribute.
*/
public String getName() {
return _name;
}
/**
* value of the attribute.
* @param value value of the attribute.
*/
public void setValue(String value) {
this._value = value;
}
/**
* value of the attribute.
* @return value of the attribute.
*/
public String getValue() {
return _value;
}
public Object clone() {
return new Attribute(this._name, this._value);
}
public boolean equals(Object obj) {
EqualsBean eBean = new EqualsBean(Attribute.class, this);
return eBean.beanEquals(obj);
}
public int hashCode() {
EqualsBean equals = new EqualsBean(Attribute.class, this);
return equals.beanHashCode();
}
public String toString() {
ToStringBean tsBean = new ToStringBean(Attribute.class, this);
return tsBean.toString();
}
}

View file

@ -0,0 +1,280 @@
/*
* Opml.java
*
* Created on April 24, 2006, 11:00 PM
*
* 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.rometools.feed.opml;
import com.sun.syndication.feed.WireFeed;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* This class represents the root of an OPML 1/2 feed and contains the elements that
* may appear in the &lt;head&gt; tag of the feed.
* @author <a href="mailto:cooper@screaming-penguin.com"> Robert "kebernet" Cooper</a>
*/
public class Opml extends WireFeed {
private Date _created;
private Date _modified;
private Integer _verticalScrollState;
private Integer _windowBottom;
private Integer _windowLeft;
private Integer _windowRight;
private Integer _windowTop;
private List _outlines;
private String _docs;
private String _ownerEmail;
private String _ownerId;
private String _ownerName;
private String _title;
private int[] _expansionState;
/** Creates a new instance of Opml */
public Opml() {
super();
}
/**
* <dateCreated> is a date-time, indicating when the document was created.
* @param created date-time, indicating when the document was created.
*/
public void setCreated(Date created) {
this._created = created;
}
/**
* &lt;dateCreated&gt; is a date-time, indicating when the document was created.
* @return date-time, indicating when the document was created.
*/
public Date getCreated() {
return _created;
}
/**
* (OPML 2) &lt;docs&gt; is the http address of documentation for the format used in the OPML file. It's probably a pointer to <a href="http://www.opml.org/spec2">this page</a> for people who might stumble across the file on a web server 25 years from now and wonder what it is.
* @param docs http address of documentation for the format used
*/
public void setDocs(String docs) {
this._docs = docs;
}
/**
* (OPML 2) &lt;docs&gt; is the http address of documentation for the format used in the OPML file. It's probably a pointer to <a href="http://www.opml.org/spec2">this page</a> for people who might stumble across the file on a web server 25 years from now and wonder what it is.
* @return http address of documentation for the format used
*/
public String getDocs() {
return _docs;
}
/**
* &lt;expansionState&gt;is a comma-separated list of line numbers that are expanded. The line numbers in the list tell you which headlines to expand. The order is important. For each element in the list, X, starting at the first summit, navigate flatdown X times and expand. Repeat for each element in the list.
* @param expansionState int array containing expanded elements.
*/
public void setExpansionState(int[] expansionState) {
this._expansionState = expansionState;
}
/**
* &lt;expansionState&gt; is a comma-separated list of line numbers that are expanded. The line numbers in the list tell you which headlines to expand. The order is important. For each element in the list, X, starting at the first summit, navigate flatdown X times and expand. Repeat for each element in the list.
* @return int array containing expanded elements.
*/
public int[] getExpansionState() {
return _expansionState;
}
/**
* &lt;dateModified&gt; is a date-time, indicating when the document was last modified.
* @param modified date-time, indicating when the document was last modified.
*/
public void setModified(Date modified) {
this._modified = modified;
}
/**
* &lt;dateModified&gt; is a date-time, indicating when the document was last modified.
* @return date-time, indicating when the document was last modified.
*/
public Date getModified() {
return _modified;
}
/**
* Root level Outline object that should appear in the &lt;body&gt;
* @param outlines Root level Outline object that should appear in the &lt;body&gt;
*/
public void setOutlines(List outlines) {
this._outlines = outlines;
}
/**
* Root level Outline object that should appear in the &lt;body&gt;
* @return Root level Outline object that should appear in the &lt;body&gt;
*/
public List getOutlines() {
if (_outlines == null) {
_outlines = new ArrayList();
}
return _outlines;
}
/**
* &lt;ownerEmail&gt; is a string, the email address of the owner of the document.
* @param ownerEmail the email address of the owner of the document.
*/
public void setOwnerEmail(String ownerEmail) {
this._ownerEmail = ownerEmail;
}
/**
* &lt;ownerEmail&gt; is a string, the email address of the owner of the document.
* @return the email address of the owner of the document.
*/
public String getOwnerEmail() {
return _ownerEmail;
}
/**
* (OPML 2) &lt;ownerId&gt; is the http address of a web page that contains <strike>an HTML</strike> a form that allows a human reader to communicate with the author of the document via email or other means.
* @param ownerId http address of a web page that contains <strike>an HTML</strike> a form that allows a human reader to communicate with the author of the document via email or other means.
*/
public void setOwnerId(String ownerId) {
this._ownerId = ownerId;
}
/**
* (OPML 2) &lt;ownerId&gt; is the http address of a web page that contains <strike>an HTML</strike> a form that allows a human reader to communicate with the author of the document via email or other means.
* @return http address of a web page that contains <strike>an HTML</strike> a form that allows a human reader to communicate with the author of the document via email or other means.
*/
public String getOwnerId() {
return _ownerId;
}
/**
* &lt;ownerName&gt; is a string, the owner of the document.
* @param ownerName the owner of the document.
*/
public void setOwnerName(String ownerName) {
this._ownerName = ownerName;
}
/**
* &lt;ownerName&gt; is a string, the owner of the document.
* @return the owner of the document.
*/
public String getOwnerName() {
return _ownerName;
}
/**
* &lt;title&gt; is the title of the document.
* @param title title of the document.
*/
public void setTitle(String title) {
this._title = title;
}
/**
* &lt;title&gt; is the title of the document.
* @return title of the document.
*/
public String getTitle() {
return _title;
}
/**
* &lt;vertScrollState&gt; is a number, saying which line of the outline is displayed on the top line of the window. This number is calculated with the expansion state already applied.
* @param verticalScrollState which line of the outline is displayed on the top line of the window.
*/
public void setVerticalScrollState(Integer verticalScrollState) {
this._verticalScrollState = verticalScrollState;
}
/**
* &lt;vertScrollState&gt; is a number, saying which line of the outline is displayed on the top line of the window. This number is calculated with the expansion state already applied.
* @return which line of the outline is displayed on the top line of the window. This number is calculated with the expansion state already applied.
*/
public Integer getVerticalScrollState() {
return _verticalScrollState;
}
/**
* &lt;windowBottom&gt; is a number, the pixel location of the bottom edge of the window.
* @param windowBottom the pixel location of the bottom edge of the window.
*/
public void setWindowBottom(Integer windowBottom) {
this._windowBottom = windowBottom;
}
/**
* &lt;windowBottom&gt; is a number, the pixel location of the bottom edge of the window.
* @return the pixel location of the bottom edge of the window.
*/
public Integer getWindowBottom() {
return _windowBottom;
}
/**
* &lt;windowLeft&gt; is a number, the pixel location of the left edge of the window.
* @param windowLeft the pixel location of the left edge of the window.
*/
public void setWindowLeft(Integer windowLeft) {
this._windowLeft = windowLeft;
}
/**
* &lt;windowLeft&gt; is a number, the pixel location of the left edge of the window.
* @return the pixel location of the left edge of the window.
*/
public Integer getWindowLeft() {
return _windowLeft;
}
/**
* &lt;windowRight&gt; is a number, the pixel location of the right edge of the window.
* @param windowRight the pixel location of the right edge of the window.
*/
public void setWindowRight(Integer windowRight) {
this._windowRight = windowRight;
}
/**
* &lt;windowRight&gt; is a number, the pixel location of the right edge of the window.
* @return the pixel location of the right edge of the window.
*/
public Integer getWindowRight() {
return _windowRight;
}
/**
* &lt;windowTop&gt; is a number, the pixel location of the top edge of the window.
* @param windowTop the pixel location of the top edge of the window.
*/
public void setWindowTop(Integer windowTop) {
this._windowTop = windowTop;
}
/**
* &lt;windowTop&gt; is a number, the pixel location of the top edge of the window.
* @return the pixel location of the top edge of the window.
*/
public Integer getWindowTop() {
return _windowTop;
}
}

View file

@ -0,0 +1,343 @@
/*
* Outline.java
*
* Created on April 24, 2006, 11:04 PM
*
* 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.rometools.feed.opml;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
/**
* This class represents an OPML outline element.
* @author <a href="mailto:cooper@screaming-penguin.com">Robert "kebernet" Cooper</a>
*/
public class Outline implements Cloneable, Serializable {
private Date _created;
private List _attributes;
private List _categories;
private List _children;
private List _modules;
private String _text;
private String _title;
private String _type;
private boolean _breakpoint;
private boolean _comment;
/** Creates a new instance of Outline */
public Outline() {
super();
}
/**
* Creates a new outline with the specified type and text values.
* @param type type attribute value/
* @param text text attribute value
*/
public Outline(String type, String text) {
super();
this.setType(type);
this.setText(text);
}
/**
* Creates an outline with the given title, xmlUrl and htmlUrl. This is traditionally
* used for aggregator feed lists and will get a type of "rss".
* @param title Title of the entry.
* @param xmlUrl link to XML file.
* @param htmlUrl link to html page.
*/
public Outline(String title, URL xmlUrl, URL htmlUrl) {
super();
this.setType("rss");
this.setTitle(title);
this.setAttributes(new ArrayList());
if (xmlUrl != null) {
getAttributes().add(new Attribute("xmlUrl", xmlUrl.toString()));
}
if (htmlUrl != null) {
getAttributes().add(new Attribute("htmlUrl", htmlUrl.toString()));
}
}
/**
* List of attributes on this outline excluding the "common types" for the specification.
* @param attributes List of attributes on this outline.
*/
public void setAttributes(List attributes) {
this._attributes = attributes;
}
/**
* List of attributes on this outline excluding the "common types" for the specification.
* @return List of attributes on this outline.
*/
public List getAttributes() {
if (this._attributes == null) {
this._attributes = new ArrayList();
}
return _attributes;
}
/**
* isBreakpoint is a string, either "true" or "false", indicating whether a breakpoint is set on this outline. This attribute is mainly necessary for outlines used to edit scripts. If it's not present, the value is false.
* @param breakpoint whether a breakpoint is set on this outline.
*/
public void setBreakpoint(boolean breakpoint) {
this._breakpoint = breakpoint;
}
/**
* isBreakpoint is a string, either "true" or "false", indicating whether a breakpoint is set on this outline. This attribute is mainly necessary for outlines used to edit scripts. If it's not present, the value is false.
* @return whether a breakpoint is set on this outline
*/
public boolean isBreakpoint() {
return _breakpoint;
}
/**
* (OPML 2) A List of Strings indicating values in the category attribute.
* @param categories (OPML 2) A List of Strings indicating values in the category attribute.
*/
public void setCategories(List categories) {
this._categories = categories;
}
/**
* (OPML 2) A List of Strings indicating values in the category attribute.
* @return (OPML 2) A List of Strings indicating values in the category attribute.
*/
public List getCategories() {
if (_categories == null) {
_categories = new ArrayList();
}
return _categories;
}
/**
* A list of sub-outlines for this entry.
* @param children A list of sub-outlines for this entry.
*/
public void setChildren(List children) {
this._children = children;
}
/**
* A list of sub-outlines for this entry.
* @return A list of sub-outlines for this entry.
*/
public List getChildren() {
if (_children == null) {
_children = new ArrayList();
}
return _children;
}
/**
* isComment is a string, either "true" or "false", indicating whether the outline is commented or not. By convention if an outline is commented, all subordinate outlines are considered to also be commented. If it's not present, the value is false.
* @param comment whether the outline is commented
*/
public void setComment(boolean comment) {
this._comment = comment;
}
/**
* isComment is a string, either "true" or "false", indicating whether the outline is commented or not. By convention if an outline is commented, all subordinate outlines are considered to also be commented. If it's not present, the value is false.
* @return whether the outline is commented
*/
public boolean isComment() {
return _comment;
}
/**
* (OPML 2) created is the date-time that the outline node was created.
* @param created date-time that the outline node was created.
*/
public void setCreated(Date created) {
this._created = created;
}
/**
* (OPML 2) created is the date-time that the outline node was created.
* @return date-time that the outline node was created.
*/
public Date getCreated() {
return _created;
}
/**
* A convenience method to return the value of the url attribute.
* @return value of the htmlUrl attribute.
*/
public String getUrl() {
return getAttributeValue("url");
}
/**
* A convenience method to return the value of the htmlUrl attribute.
* @return value of the htmlUrl attribute.
*/
public String getHtmlUrl() {
return getAttributeValue("htmlUrl");
}
public void setModules(List modules) {
this._modules = modules;
}
public List getModules() {
if (this._modules == null) {
this._modules = new ArrayList();
}
return _modules;
}
/**
* The "text" attribute of the outline.
* @param text The "text" attribute of the outline.
*/
public void setText(String text) {
this._text = text;
}
/**
* The "text" attribute of the outline.
* @return The "text" attribute of the outline.
*/
public String getText() {
return _text;
}
/**
* The "title" attribute of the outline.
* @param title The "title" attribute of the outline.
*/
public void setTitle(String title) {
this._title = title;
}
/**
* The "title" attribute of the outline.
* @return The "title" attribute of the outline.
*/
public String getTitle() {
return _title;
}
/**
* The "type" attribute of the outline.
* @param type The "type" attribute of the outline.
*/
public void setType(String type) {
this._type = type;
}
/**
* The "type" attribute of the outline.
* @return The "type" attribute of the outline.
*/
public String getType() {
return _type;
}
/**
* A convenience method to return the value of the xmlUrl attribute.
* @return value of the xmlUrl attribute.
*/
public String getXmlUrl() {
return getAttributeValue("xmlUrl");
}
/** Returns the value of an attribute on the outline or null.
* @param name name of the attribute.
*/
public String getAttributeValue(String name ){
List attributes = Collections.synchronizedList(this.getAttributes());
for (int i = 0; i < attributes.size(); i++) {
Attribute a = (Attribute) attributes.get(i);
if ((a.getName() != null) && a.getName().equals(name)) {
return a.getValue();
}
}
return null;
}
public Object clone() {
Outline o = new Outline();
o.setBreakpoint(this.isBreakpoint());
o.setCategories(new ArrayList(this.getCategories()));
o.setComment(this.isComment());
o.setCreated((this._created != null) ? (Date) this._created.clone() : null);
o.setModules(new ArrayList(this.getModules()));
o.setText(this.getText());
o.setTitle(this.getTitle());
o.setType(this.getType());
ArrayList children = new ArrayList();
for (int i = 0; i < this.getChildren().size(); i++) {
children.add(((Outline) this._children.get(i)).clone());
}
o.setChildren(children);
ArrayList attributes = new ArrayList();
for (int i = 0; i < this.getAttributes().size(); i++) {
attributes.add(((Attribute) this._attributes.get(i)).clone());
}
o.setAttributes(attributes);
return o;
}
public boolean equals(Object obj) {
EqualsBean eBean = new EqualsBean(Outline.class, this);
return eBean.beanEquals(obj);
}
public int hashCode() {
EqualsBean equals = new EqualsBean(Outline.class, this);
return equals.beanHashCode();
}
public String toString() {
ToStringBean tsBean = new ToStringBean(Outline.class, this);
return tsBean.toString();
}
}

View file

@ -0,0 +1,47 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title></title>
</head>
<body>
This package represents the base objects for OPML support for ROME.
<p>
There are three classes here that are relevant. <code>Opml</code>,
which represents the root document and <code>head</code> information,
<code>Outline</code> which represents a single node on an Opml
outline tree, and provides convenience methods for commonly used
attributes such as <code>xmlUrl</code>. Finally, the
<code>Attribute</code> class, which represents a specific attribute
on an Outline object. Since OPML supports free-form attribute
assignments, this is a very multi-purpose class.
</p>
<p>Sample Usage:
To use this parser, simply include the jar file in your classpath
as you are using ROME. Be sure it exists at the same level as ROME,
such that, if ROME is in the common classpath of an application server,
don't include this jar in your webapps WEB-INF/lib.
<code><pre>
WireFeedInput input = new WireFeedInput();
Opml feed = (Opml) input.build( new File("myOpml.xml") );
List&lt;Outline&gt; outlines = (List&lt;Outline&gt;) feed.getOutlines();
</pre></code>
</p>
<pre>
*
* 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.
</pre>
</body>
</html>

View file

@ -0,0 +1,374 @@
/*
* ConverterForOPML10.java
*
* Created on April 25, 2006, 1:26 AM
*
* 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.rometools.feed.synd.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import java.util.logging.Logger;
import com.sun.syndication.feed.WireFeed;
import org.rometools.feed.opml.Attribute;
import org.rometools.feed.opml.Opml;
import org.rometools.feed.opml.Outline;
import com.sun.syndication.feed.synd.Converter;
import com.sun.syndication.feed.synd.SyndCategory;
import com.sun.syndication.feed.synd.SyndCategoryImpl;
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.SyndLink;
import com.sun.syndication.feed.synd.SyndLinkImpl;
import com.sun.syndication.feed.synd.SyndPerson;
import com.sun.syndication.feed.synd.SyndPersonImpl;
/**
*
* @author cooper
*/
public class ConverterForOPML10 implements Converter {
private static final Logger LOG = Logger.getLogger(ConverterForOPML10.class.getName()
.toString());
public static final String URI_TREE = "urn:rome.tree";
public static final String URI_ATTRIBUTE = "urn:rome.attribute#";
/** Creates a new instance of ConverterForOPML10 */
public ConverterForOPML10() {
super();
}
protected void addOwner(Opml opml, SyndFeed syndFeed) {
if((opml.getOwnerEmail() != null) || (opml.getOwnerName() != null)) {
List authors = new ArrayList();
SyndPerson person = new SyndPersonImpl();
person.setEmail(opml.getOwnerEmail());
person.setName(opml.getOwnerName());
authors.add(person);
syndFeed.setAuthors(authors);
}
}
/**
* Makes a deep copy/conversion of the values of a real feed into a SyndFeedImpl.
* <p>
* It assumes the given SyndFeedImpl has no properties set.
* <p>
*
* @param feed real feed to copy/convert.
* @param syndFeed the SyndFeedImpl that will contain the copied/converted values of the real feed.
*/
public void copyInto(WireFeed feed, SyndFeed syndFeed) {
Opml opml = (Opml) feed;
syndFeed.setTitle(opml.getTitle());
addOwner(opml, syndFeed);
syndFeed.setPublishedDate((opml.getModified() != null)
? opml.getModified() : opml.getCreated());
syndFeed.setFeedType(opml.getFeedType());
syndFeed.setModules(opml.getModules());
syndFeed.setFeedType(this.getType());
ArrayList entries = new ArrayList();
createEntries(new TreeContext(), syndFeed.getEntries(),
opml.getOutlines());
}
protected void createEntries(TreeContext context, List allEntries,
List outlines) {
List so = Collections.synchronizedList(outlines);
for(int i = 0; i < so.size(); i++) {
createEntry(context, allEntries, (Outline) so.get(i));
}
}
protected SyndEntry createEntry(TreeContext context, List allEntries,
Outline outline) {
SyndEntry entry = new SyndEntryImpl();
if((outline.getType() != null) && outline.getType().equals("rss")) {
entry.setLink((outline.getHtmlUrl() != null) ? outline.getHtmlUrl()
: outline.getXmlUrl());
} else if((outline.getType() != null) &&
outline.getType().equals("link")) {
entry.setLink(outline.getUrl());
}
if(outline.getHtmlUrl() != null) {
SyndLink link = new SyndLinkImpl();
link.setRel("alternate");
link.setType("text/html");
link.setHref(outline.getHtmlUrl());
entry.getLinks().add(link);
entry.setLink(outline.getHtmlUrl());
}
if((outline.getXmlUrl() != null) && (outline.getType() != null) &&
outline.getType().equalsIgnoreCase("rss")) {
SyndLink link = new SyndLinkImpl();
link.setRel("alternate");
link.setType("application/rss+xml");
link.setHref(outline.getXmlUrl());
entry.getLinks().add(link);
if(entry.getLink() == null) {
entry.setLink(outline.getXmlUrl());
}
}
if((outline.getXmlUrl() != null) && (outline.getType() != null) &&
outline.getType().equalsIgnoreCase("atom")) {
SyndLink link = new SyndLinkImpl();
link.setRel("alternate");
link.setType("application/atom+xml");
link.setHref(outline.getXmlUrl());
entry.getLinks().add(link);
if(entry.getLink() == null) {
entry.setLink(outline.getXmlUrl());
}
}
if((outline.getType() != null) && outline.getType().equals("rss")) {
entry.setTitle(outline.getTitle());
} else {
entry.setTitle(outline.getText());
}
if((outline.getText() == null) && (entry.getTitle() != null)) {
SyndContent c = new SyndContentImpl();
c.setValue(outline.getText());
entry.setDescription(c);
}
entry.setPublishedDate(outline.getCreated());
String nodeName = "node." + outline.hashCode();
SyndCategory cat = new TreeCategoryImpl();
cat.setTaxonomyUri(URI_TREE);
cat.setName(nodeName);
entry.getCategories().add(cat);
if(context.size() > 0) {
Integer parent = (Integer) context.peek();
SyndCategory pcat = new TreeCategoryImpl();
pcat.setTaxonomyUri(URI_TREE);
pcat.setName("parent." + parent);
entry.getCategories().add(pcat);
}
List attributes = Collections.synchronizedList(outline.getAttributes());
for(int i = 0; i < attributes.size(); i++) {
Attribute a = (Attribute) attributes.get(i);
SyndCategory acat = new SyndCategoryImpl();
acat.setName(a.getValue());
acat.setTaxonomyUri(URI_ATTRIBUTE + a.getName());
entry.getCategories().add(acat);
}
entry.setModules(outline.getModules());
allEntries.add(entry);
context.push(new Integer(outline.hashCode()));
createEntries(context, allEntries, outline.getChildren());
context.pop();
return entry;
}
/**
* Creates real feed with a deep copy/conversion of the values of a SyndFeedImpl.
* <p>
*
* @param syndFeed SyndFeedImpl to copy/convert value from.
* @return a real feed with copied/converted values of the SyndFeedImpl.
*
*/
public WireFeed createRealFeed(SyndFeed syndFeed) {
List entries = Collections.synchronizedList(syndFeed.getEntries());
HashMap entriesByNode = new HashMap();
ArrayList doAfterPass = new ArrayList(); // this will hold entries that we can't parent the first time.
ArrayList root = new ArrayList(); // this holds root level outlines;
for(int i = 0; i < entries.size(); i++) {
SyndEntry entry = (SyndEntry) entries.get(i);
Outline o = new Outline();
List cats = Collections.synchronizedList(entry.getCategories());
boolean parentFound = false;
StringBuffer category = new StringBuffer();
for(int j = 0; j < cats.size(); j++) {
SyndCategory cat = (SyndCategory) cats.get(j);
if((cat.getTaxonomyUri() != null) &&
cat.getTaxonomyUri().equals(URI_TREE)) {
String nodeVal = cat.getName()
.substring(cat.getName().lastIndexOf("."),
cat.getName().length());
if(cat.getName().startsWith("node.")) {
entriesByNode.put(nodeVal, o);
} else if(cat.getName().startsWith("parent.")) {
parentFound = true;
Outline parent = (Outline) entriesByNode.get(nodeVal);
if(parent != null) {
parent.getChildren().add(o);
} else {
doAfterPass.add(new OutlineHolder(o, nodeVal));
}
}
} else if((cat.getTaxonomyUri() != null) &&
cat.getTaxonomyUri().startsWith(URI_ATTRIBUTE)) {
String name = cat.getTaxonomyUri()
.substring(cat.getTaxonomyUri().indexOf("#") +
1, cat.getTaxonomyUri().length());
o.getAttributes().add(new Attribute(name, cat.getName()));
} else {
if(category.length() > 0) {
category.append(", ");
}
category.append(cat.getName());
}
}
if(!parentFound) {
root.add(o);
}
if(category.length() > 0) {
o.getAttributes()
.add(new Attribute("category", category.toString()));
}
List links = Collections.synchronizedList(entry.getLinks());
String entryLink = entry.getLink();
for(int j = 0; j < links.size(); j++) {
SyndLink link = (SyndLink) links.get(j);
//if(link.getHref().equals(entryLink)) {
if(((link.getType() != null) && (link.getRel() != null) &&
link.getRel().equals("alternate")) &&
(link.getType().equals("application/rss+xml") ||
link.getType().equals("application/atom+xml"))) {
o.setType("rss");
if(o.getXmlUrl() == null) {
o.getAttributes()
.add(new Attribute("xmlUrl", link.getHref()));
}
} else if((link.getType() != null) &&
(link.getType().equals("text/html"))) {
if(o.getHtmlUrl() == null) {
o.getAttributes()
.add(new Attribute("htmlUrl", link.getHref()));
}
} else {
o.setType(link.getType());
}
//}
}
if((o.getType() == null) || o.getType().equals("link")) {
o.setText(entry.getTitle());
} else {
o.setTitle(entry.getTitle());
}
if((o.getText() == null) && (entry.getDescription() != null)) {
o.setText(entry.getDescription().getValue());
}
}
// Do back and parenting for things we missed.
for(int i = 0; i < doAfterPass.size(); i++) {
OutlineHolder o = (OutlineHolder) doAfterPass.get(i);
Outline parent = (Outline) entriesByNode.get(o.parent);
if(parent == null) {
root.add(o.outline);
LOG.warning("Unable to find parent node :" + o.parent);
} else {
parent.getChildren().add(o.outline);
}
}
Opml opml = new Opml();
opml.setFeedType(this.getType());
opml.setCreated(syndFeed.getPublishedDate());
opml.setTitle(syndFeed.getTitle());
List authors = Collections.synchronizedList(syndFeed.getAuthors());
for(int i = 0; i < authors.size(); i++) {
SyndPerson p = (SyndPerson) authors.get(i);
if((syndFeed.getAuthor() == null) ||
syndFeed.getAuthor().equals(p.getName())) {
opml.setOwnerName(p.getName());
opml.setOwnerEmail(p.getEmail());
opml.setOwnerId(p.getUri());
}
}
opml.setOutlines(root);
return opml;
}
/**
* Returns the type (version) of the real feed this converter handles.
* <p>
*
* @return the real feed type.
* @see WireFeed for details on the format of this string.
* <p>
*/
public String getType() {
return "opml_1.0";
}
private static class OutlineHolder {
Outline outline;
String parent;
public OutlineHolder(Outline outline, String parent) {
this.outline = outline;
this.parent = parent;
}
}
private static class TreeContext extends Stack {
TreeContext() {
super();
}
}
}

View file

@ -0,0 +1,64 @@
/*
* ConverterForOPML20.java
*
* Created on April 25, 2006, 5:29 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.rometools.feed.synd.impl;
import com.sun.syndication.feed.WireFeed;
import com.sun.syndication.feed.synd.SyndFeed;
/**
*
* @author cooper
*/
public class ConverterForOPML20 extends ConverterForOPML10 {
/** Creates a new instance of ConverterForOPML20 */
public ConverterForOPML20() {
super();
}
/**
* Returns the type (version) of the real feed this converter handles.
* <p>
*
* @return the real feed type.
* @see WireFeed for details on the format of this string.
* <p>
*/
public String getType() {
return "opml_2.0";
}
/**
* Makes a deep copy/conversion of the values of a real feed into a SyndFeedImpl.
* <p>
* It assumes the given SyndFeedImpl has no properties set.
* <p>
*
* @param feed real feed to copy/convert.
* @param syndFeed the SyndFeedImpl that will contain the copied/converted values of the real feed.
*/
public void copyInto(WireFeed feed, SyndFeed syndFeed) {
super.copyInto(feed, syndFeed);
}
/**
* Creates real feed with a deep copy/conversion of the values of a SyndFeedImpl.
* <p>
*
* @param syndFeed SyndFeedImpl to copy/convert value from.
* @return a real feed with copied/converted values of the SyndFeedImpl.
*/
public WireFeed createRealFeed(SyndFeed syndFeed) {
WireFeed retValue;
retValue = super.createRealFeed(syndFeed);
return retValue;
}
}

View file

@ -0,0 +1,34 @@
/*
* TreeCategoryImpl.java
*
* Created on April 27, 2006, 3:44 AM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.rometools.feed.synd.impl;
import com.sun.syndication.feed.synd.SyndCategory;
import com.sun.syndication.feed.synd.SyndCategoryImpl;
/**
*
* @author cooper
*/
public class TreeCategoryImpl extends SyndCategoryImpl {
/** Creates a new instance of TreeCategoryImpl */
public TreeCategoryImpl() {
super();
}
public boolean equals(Object o) {
SyndCategory c = (SyndCategory) o;
if( c.getTaxonomyUri() != null && c.getTaxonomyUri().equals( this.getTaxonomyUri() ) )
return true;
else
return false;
}
}

View file

@ -0,0 +1,30 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title></title>
</head>
<body>
This packages contains the SyndFeed converters for the
OPML module. For information on how Opml gets turned into
other feed types through the Synd structures, see the OPML
Subproject page on the ROME wiki.
<pre>
*
* 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.
</pre>
</body>
</html>

View file

@ -0,0 +1,189 @@
/*
* Opml10Generator.java
*
* Created on April 24, 2006, 11:35 PM
*
* 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.rometools.io.impl;
import com.sun.syndication.feed.WireFeed;
import org.rometools.feed.opml.Attribute;
import org.rometools.feed.opml.Opml;
import org.rometools.feed.opml.Outline;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.WireFeedGenerator;
import com.sun.syndication.io.impl.BaseWireFeedGenerator;
import com.sun.syndication.io.impl.DateParser;
import org.jdom.Document;
import org.jdom.Element;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
*
* @author <a href="mailto:cooper@screaming-penguin.com">Robert "kebernet" Cooper</a>
*/
public class OPML10Generator extends BaseWireFeedGenerator implements WireFeedGenerator {
/** Creates a new instance of Opml10Generator */
public OPML10Generator() {
super("opml_1.0");
}
public OPML10Generator(String type) {
super(type);
}
/**
* Creates an XML document (JDOM) for the given feed bean.
* <p>
*
* @param feed the feed bean to generate the XML document from.
* @return the generated XML document (JDOM).
* @throws IllegalArgumentException thrown if the type of the given feed bean does not
* match with the type of the WireFeedGenerator.
* @throws FeedException thrown if the XML Document could not be created.
*/
public Document generate(WireFeed feed) throws IllegalArgumentException, FeedException {
if (!(feed instanceof Opml)) {
throw new IllegalArgumentException("Not an OPML file");
}
Opml opml = (Opml) feed;
Document doc = new Document();
Element root = new Element("opml");
doc.addContent(root);
Element head = generateHead(opml);
if (head != null) {
root.addContent(head);
}
Element body = new Element("body");
root.addContent(body);
super.generateFeedModules(opml.getModules(), root);
body.addContent(generateOutlines(opml.getOutlines()));
return doc;
}
protected boolean addNotNullAttribute(Element target, String name, Object value) {
if ((target == null) || (name == null) || (value == null)) {
return false;
}
target.setAttribute(name, value.toString());
return true;
}
protected boolean addNotNullSimpleElement(Element target, String name, Object value) {
if ((target == null) || (name == null) || (value == null)) {
return false;
}
Element e = new Element(name);
e.addContent(value.toString());
target.addContent(e);
return true;
}
protected Element generateHead(Opml opml) {
Element head = new Element("head");
boolean hasHead = false;
if (opml.getCreated() != null) {
hasHead = addNotNullSimpleElement(head, "dateCreated", DateParser.formatRFC822(opml.getCreated()));
}
hasHead = addNotNullSimpleElement(head, "expansionState", intArrayToCsvString(opml.getExpansionState()));
if (opml.getModified() != null) {
hasHead = addNotNullSimpleElement(head, "dateModified", DateParser.formatRFC822(opml.getModified()));
}
hasHead = addNotNullSimpleElement(head, "ownerEmail", opml.getOwnerEmail());
hasHead = addNotNullSimpleElement(head, "ownerName", opml.getOwnerName());
hasHead = addNotNullSimpleElement(head, "title", opml.getTitle());
hasHead = addNotNullSimpleElement(head, "vertScrollState", opml.getVerticalScrollState());
hasHead = addNotNullSimpleElement(head, "windowBottom", opml.getWindowBottom());
hasHead = addNotNullSimpleElement(head, "windowLeft", opml.getWindowLeft());
hasHead = addNotNullSimpleElement(head, "windowRight", opml.getWindowRight());
hasHead = addNotNullSimpleElement(head, "windowTop", opml.getWindowTop());
if (hasHead) {
return head;
} else {
return null;
}
}
protected Element generateOutline(Outline outline) {
Element e = new Element("outline");
addNotNullAttribute(e, "text", outline.getText());
addNotNullAttribute(e, "type", outline.getType());
addNotNullAttribute(e, "title", outline.getTitle());
if (outline.isBreakpoint()) {
addNotNullAttribute(e, "isBreakpoint", "true");
}
if (outline.isComment()) {
addNotNullAttribute(e, "isComment", "true");
}
List atts = Collections.synchronizedList(outline.getAttributes());
for (int i = 0; i < atts.size(); i++) {
Attribute att = (Attribute) atts.get(i);
addNotNullAttribute(e, att.getName(), att.getValue());
}
super.generateItemModules(outline.getModules(), e);
e.addContent(generateOutlines(outline.getChildren()));
return e;
}
protected List generateOutlines(List outlines) {
ArrayList elements = new ArrayList();
for (int i = 0; (outlines != null) && (i < outlines.size()); i++) {
elements.add(generateOutline((Outline) outlines.get(i)));
}
return elements;
}
protected String intArrayToCsvString(int[] value) {
if ((value == null) || (value.length == 0)) {
return null;
}
StringBuffer sb = new StringBuffer();
sb.append(value[0]);
for (int i = 1; i < value.length; i++) {
sb.append(",");
sb.append(value[i]);
}
return sb.toString();
}
}

View file

@ -0,0 +1,263 @@
/*
* Opml10Parser.java
*
* Created on April 24, 2006, 11:34 PM
*
* 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.rometools.io.impl;
import com.sun.syndication.feed.WireFeed;
import org.rometools.feed.opml.Attribute;
import org.rometools.feed.opml.Opml;
import org.rometools.feed.opml.Outline;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.WireFeedParser;
import com.sun.syndication.io.impl.BaseWireFeedParser;
import com.sun.syndication.io.impl.DateParser;
import org.jdom.Document;
import org.jdom.Element;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author <a href="mailto:cooper@screaming-penguin.com">Robert "kebernet" Cooper</a>
*/
public class OPML10Parser extends BaseWireFeedParser implements WireFeedParser {
private static Logger LOG = Logger.getLogger(OPML10Parser.class.getName());
/** Creates a new instance of Opml10Parser */
public OPML10Parser() {
super("opml_1.0", null);
}
public OPML10Parser(String type) {
super(type, null);
}
/**
* Inspects an XML Document (JDOM) to check if it can parse it.
* <p>
* It checks if the given document if the type of feeds the parser understands.
* <p>
*
* @param document XML Document (JDOM) to check if it can be parsed by this parser.
* @return <b>true</b> if the parser know how to parser this feed, <b>false</b> otherwise.
*/
public boolean isMyType(Document document) {
Element e = document.getRootElement();
if (e.getName().equals("opml")
&& ( e.getChild("head") == null || e.getChild("head").getChild("docs") == null)
&& (e.getAttributeValue("version") == null || e.getAttributeValue("version").equals("1.0"))) {
return true;
}
return false;
}
/**
* Parses an XML document (JDOM Document) into a feed bean.
* <p>
*
* @param document XML document (JDOM) to parse.
* @param validate indicates if the feed should be strictly validated (NOT YET IMPLEMENTED).
* @return the resulting feed bean.
* @throws IllegalArgumentException thrown if the parser cannot handle the given feed type.
* @throws FeedException thrown if a feed bean cannot be created out of the XML document (JDOM).
*/
public WireFeed parse(Document document, boolean validate) throws IllegalArgumentException, FeedException {
Opml opml = new Opml();
opml.setFeedType("opml_1.0");
Element root = document.getRootElement();
Element head = root.getChild("head");
if (head != null) {
opml.setTitle(head.getChildText("title"));
if (head.getChildText("dateCreated") != null) {
opml.setCreated(DateParser.parseRFC822(head.getChildText("dateCreated")));
}
if (head.getChildText("dateModified") != null) {
opml.setModified(DateParser.parseRFC822(head.getChildText("dateModified")));
}
opml.setOwnerName(head.getChildTextTrim("ownerName"));
opml.setOwnerEmail(head.getChildTextTrim("ownerEmail"));
opml.setVerticalScrollState(readInteger(head.getChildText("vertScrollState")));
}
try {
opml.setWindowBottom(readInteger(head.getChildText("windowBottom")));
} catch (NumberFormatException nfe) {
LOG.log(Level.WARNING, "Unable to parse windowBottom", nfe);
if (validate) {
throw new FeedException("Unable to parse windowBottom", nfe);
}
}
try {
opml.setWindowLeft(readInteger(head.getChildText("windowLeft")));
} catch (NumberFormatException nfe) {
LOG.log(Level.WARNING, "Unable to parse windowLeft", nfe);
}
try {
opml.setWindowRight(readInteger(head.getChildText("windowRight")));
} catch (NumberFormatException nfe) {
LOG.log(Level.WARNING, "Unable to parse windowRight", nfe);
if (validate) {
throw new FeedException("Unable to parse windowRight", nfe);
}
}
try {
opml.setWindowLeft(readInteger(head.getChildText("windowLeft")));
} catch (NumberFormatException nfe) {
LOG.log(Level.WARNING, "Unable to parse windowLeft", nfe);
if (validate) {
throw new FeedException("Unable to parse windowLeft", nfe);
}
}
try {
opml.setWindowTop(readInteger(head.getChildText("windowTop")));
} catch (NumberFormatException nfe) {
LOG.log(Level.WARNING, "Unable to parse windowTop", nfe);
if (validate) {
throw new FeedException("Unable to parse windowTop", nfe);
}
}
try {
opml.setExpansionState(readIntArray(head.getChildText("expansionState")));
} catch (NumberFormatException nfe) {
LOG.log(Level.WARNING, "Unable to parse expansionState", nfe);
if (validate) {
throw new FeedException("Unable to parse expansionState", nfe);
}
}
opml.setOutlines(parseOutlines(root.getChild("body").getChildren("outline"), validate));
opml.setModules(this.parseFeedModules(root));
return opml;
}
protected Outline parseOutline(Element e, boolean validate) throws FeedException {
if (!e.getName().equals("outline")) {
throw new RuntimeException("Not an outline element.");
}
Outline outline = new Outline();
outline.setText(e.getAttributeValue("text"));
outline.setType(e.getAttributeValue("type"));
outline.setTitle(e.getAttributeValue("title"));
List jAttributes = e.getAttributes();
ArrayList attributes = new ArrayList();
for (int i = 0; i < jAttributes.size(); i++) {
org.jdom.Attribute a = (org.jdom.Attribute) jAttributes.get(i);
if (!a.getName().equals("isBreakpoint") && !a.getName().equals("isComment") && !a.getName().equals("title") && !a.getName().equals("text") && !a.getName().equals("type")) {
attributes.add(new Attribute(a.getName(), a.getValue()));
}
}
outline.setAttributes(attributes);
try {
outline.setBreakpoint(readBoolean(e.getAttributeValue("isBreakpoint")));
} catch (Exception ex) {
LOG.log(Level.WARNING, "Unable to parse isBreakpoint value", ex);
if (validate) {
throw new FeedException("Unable to parse isBreakpoint value", ex);
}
}
try {
outline.setComment(readBoolean(e.getAttributeValue("isComment")));
} catch (Exception ex) {
LOG.log(Level.WARNING, "Unable to parse isComment value", ex);
if (validate) {
throw new FeedException("Unable to parse isComment value", ex);
}
}
List children = e.getChildren("outline");
outline.setModules(this.parseItemModules(e));
outline.setChildren(parseOutlines(children, validate));
return outline;
}
protected List parseOutlines(List elements, boolean validate) throws FeedException {
ArrayList results = new ArrayList();
for (int i = 0; i < elements.size(); i++) {
results.add(parseOutline((Element) elements.get(i), validate));
}
return results;
}
protected boolean readBoolean(String value) {
if (value == null) {
return false;
} else {
return Boolean.getBoolean(value.trim());
}
}
protected int[] readIntArray(String value) {
if (value == null) {
return null;
} else {
StringTokenizer tok = new StringTokenizer(value, ",");
int[] result = new int[tok.countTokens()];
int count = 0;
while (tok.hasMoreElements()) {
result[count] = Integer.parseInt(tok.nextToken().trim());
count++;
}
return result;
}
}
protected Integer readInteger(String value) {
if (value != null) {
return new Integer(value);
} else {
return null;
}
}
}

View file

@ -0,0 +1,83 @@
/*
* OPML20Generator.java
*
* Created on April 25, 2006, 5:31 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.rometools.io.impl;
import com.sun.syndication.feed.WireFeed;
import org.rometools.feed.opml.Opml;
import org.rometools.feed.opml.Outline;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.impl.DateParser;
import org.jdom.Document;
import org.jdom.Element;
/**
*
* @author cooper
*/
public class OPML20Generator extends OPML10Generator {
/** Creates a new instance of OPML20Generator */
public OPML20Generator() {
}
/**
* Returns the type of feed the generator creates.
* <p>
*
* @return the type of feed the generator creates.
* @see WireFeed for details on the format of this string.
* <p>
*/
public String getType() {
return "opml_2.0";
}
/**
* Creates an XML document (JDOM) for the given feed bean.
* <p>
*
* @param feed the feed bean to generate the XML document from.
* @return the generated XML document (JDOM).
* @throws IllegalArgumentException thrown if the type of the given feed bean does not
* match with the type of the WireFeedGenerator.
* @throws FeedException thrown if the XML Document could not be created.
*/
public Document generate(WireFeed feed) throws IllegalArgumentException, FeedException {
Document retValue;
retValue = super.generate(feed);
retValue.getRootElement().setAttribute("version", "2.0");
return retValue;
}
protected Element generateHead(Opml opml) {
Element retValue;
retValue = super.generateHead(opml);
Element docs = new Element("docs", opml.getDocs());
retValue.addContent(docs);
return retValue;
}
protected Element generateOutline(Outline outline) {
Element retValue;
retValue = super.generateOutline(outline);
if (outline.getCreated() != null) {
retValue.setAttribute("created", DateParser.formatRFC822(outline.getCreated()));
}
return retValue;
}
}

View file

@ -0,0 +1,117 @@
/*
* Opml20Parser.java
*
* Created on April 25, 2006, 1:04 AM
*
* 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.rometools.io.impl;
import com.sun.syndication.feed.WireFeed;
import org.rometools.feed.opml.Attribute;
import org.rometools.feed.opml.Opml;
import org.rometools.feed.opml.Outline;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.impl.DateParser;
import org.jdom.Document;
import org.jdom.Element;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
*
* @author cooper
*/
public class OPML20Parser extends OPML10Parser {
/** Creates a new instance of Opml20Parser */
public OPML20Parser() {
super("opml_2.0");
}
/**
* Inspects an XML Document (JDOM) to check if it can parse it.
* <p>
* It checks if the given document if the type of feeds the parser understands.
* <p>
*
* @param document XML Document (JDOM) to check if it can be parsed by this parser.
* @return <b>true</b> if the parser know how to parser this feed, <b>false</b> otherwise.
*/
public boolean isMyType(Document document) {
Element e = document.getRootElement();
if (e.getName().equals("opml") && (((e.getChild("head") != null) && (e.getChild("head").getChild("docs") != null)) || ((e.getAttributeValue("version") != null) && e.getAttributeValue("version").equals("2.0")) || ((e.getChild("head") != null) && (e.getChild("head").getChild("ownerId") != null)))) {
return true;
}
return false;
}
/**
* Parses an XML document (JDOM Document) into a feed bean.
* <p>
*
* @param document XML document (JDOM) to parse.
* @param validate indicates if the feed should be strictly validated (NOT YET IMPLEMENTED).
* @return the resulting feed bean.
* @throws IllegalArgumentException thrown if the parser cannot handle the given feed type.
* @throws FeedException thrown if a feed bean cannot be created out of the XML document (JDOM).
*/
public WireFeed parse(Document document, boolean validate) throws IllegalArgumentException, FeedException {
Opml opml;
opml = (Opml) super.parse(document, validate);
Element head = document.getRootElement().getChild("head");
if (head != null) {
opml.setOwnerId(head.getChildTextTrim("ownerId"));
opml.setDocs(head.getChildTextTrim("docs"));
if (opml.getDocs() == null) {
opml.setDocs("http://www.opml.org/spec2");
}
}
opml.setFeedType("opml_2.0");
return opml;
}
protected Outline parseOutline(Element e, boolean validate) throws FeedException {
Outline retValue;
retValue = super.parseOutline(e, validate);
if (e.getAttributeValue("created") != null) {
retValue.setCreated(DateParser.parseRFC822(e.getAttributeValue("created")));
}
List atts = retValue.getAttributes();
for (int i = 0; i < atts.size(); i++) {
Attribute a = (Attribute) atts.get(i);
if (a.getName().equals("created")) {
retValue.getAttributes().remove(a);
break;
}
}
return retValue;
}
}

View file

@ -0,0 +1,28 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title></title>
</head>
<body>
This package contains the feed parsers for OPML1 and OPML2.
<pre>
*
* 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.
</pre>
</body>
</html>

View file

@ -0,0 +1,114 @@
package org.rometools.unittest;
import com.sun.syndication.feed.WireFeed;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.ObjectInputStream;
/**
*
* <p>
* @author Alejandro Abdelnur
*
*/
public abstract class FeedOpsTest extends FeedTest {
protected FeedOpsTest(String feedType) {
super(feedType+".xml");
System.out.println("Testing "+feedType+".xml");
new File("target/test-reports").mkdirs();
}
//1.2a
public void testWireFeedEquals() throws Exception {
WireFeed feed1 = getCachedWireFeed();
WireFeed feed2 = getWireFeed();
assertTrue(feed1.equals(feed2));
}
//1.2b
public void testWireFeedNotEqual() throws Exception {
WireFeed feed1 = getCachedWireFeed();
WireFeed feed2 = getWireFeed();
feed2.setFeedType("dummy");
assertFalse(feed1.equals(feed2));
}
//1.3
public void testWireFeedCloning() throws Exception {
WireFeed feed1 = getCachedWireFeed();
WireFeed feed2 = (WireFeed) feed1.clone();;
assertTrue(feed1.equals(feed2));
}
// 1.4
public void testWireFeedSerialization() throws Exception {
WireFeed feed1 = getCachedWireFeed();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(feed1);
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
WireFeed feed2 = (WireFeed) ois.readObject();
ois.close();
assertTrue(feed1.equals(feed2));
}
// 1.6
public void testWireFeedSyndFeedConversion() throws Exception {
SyndFeed sFeed1 = getCachedSyndFeed();
WireFeed wFeed1 = sFeed1.createWireFeed();
SyndFeed sFeed2 = new SyndFeedImpl(wFeed1);
assertEquals(sFeed1, sFeed2 );
}
//1.7a
public void testSyndFeedEquals() throws Exception {
SyndFeed feed1 = getCachedSyndFeed();
SyndFeed feed2 = getSyndFeed();
assertTrue(feed1.equals(feed2));
}
//1.7b
public void testSyndFeedNotEqual() throws Exception {
SyndFeed feed1 = getCachedSyndFeed();
SyndFeed feed2 = getSyndFeed();
feed2.setFeedType("dummy");
assertFalse(feed1.equals(feed2));
}
//1.8
public void testSyndFeedCloning() throws Exception {
SyndFeed feed1 = getCachedSyndFeed();
SyndFeed feed2 = (SyndFeed) feed1.clone();;
assertTrue(feed1.equals(feed2));
}
//1.9
public void testSyndFeedSerialization() throws Exception {
SyndFeed feed1 = getCachedSyndFeed();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(feed1);
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
SyndFeed feed2 = (SyndFeed) ois.readObject();
ois.close();
assertTrue(feed1.equals(feed2));
}
}

View file

@ -0,0 +1,78 @@
package org.rometools.unittest;
import junit.framework.TestCase;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.WireFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.WireFeedInput;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.InputStream;
import org.jdom.Document;
import org.jdom.input.SAXBuilder;
/**
* @author pat, tucu
*
*/
public abstract class FeedTest extends TestCase {
private String _feedFileName;
private Document _jDomDoc = null;
private WireFeed _wireFeed = null;
private SyndFeed _syndFeed = null;
protected FeedTest(String feedFileName) {
_feedFileName = feedFileName;
}
protected String getFeedFileName() {
return _feedFileName;
}
protected Reader getFeedReader() throws Exception {
InputStream resource = Thread.currentThread().
getContextClassLoader().getResourceAsStream(getFeedFileName());
assertNotNull("Could not find resource " + getFeedFileName(), resource);
return new InputStreamReader(resource);
}
protected Document getJDomDoc() throws Exception {
SAXBuilder saxBuilder = new SAXBuilder(false);
return saxBuilder.build(getFeedReader());
}
protected WireFeed getWireFeed() throws Exception {
WireFeedInput in = new WireFeedInput();
return in.build(getFeedReader());
}
protected SyndFeed getSyndFeed() throws Exception {
SyndFeedInput in = new SyndFeedInput();
return in.build(getFeedReader());
}
protected Document getCachedJDomDoc() throws Exception {
if (_jDomDoc==null) {
_jDomDoc = getJDomDoc();
}
return _jDomDoc;
}
protected WireFeed getCachedWireFeed() throws Exception {
if (_wireFeed==null) {
_wireFeed = getWireFeed();
}
return _wireFeed;
}
protected SyndFeed getCachedSyndFeed() throws Exception {
if (_syndFeed==null) {
_syndFeed = getSyndFeed();
}
return _syndFeed;
}
}

View file

@ -0,0 +1,267 @@
/*
* Created on Jun 22, 2004
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
package org.rometools.unittest;
/**
* @author pat
*
*/
public abstract class SyndFeedTest extends FeedTest {
private String _prefix = null;
protected SyndFeedTest(String feedType) {
this(feedType,feedType+".xml");
}
protected SyndFeedTest(String feedType,String feedFileName) {
super(feedFileName);
_prefix = feedType;
}
protected String getPrefix() {
return _prefix;
}
protected void assertProperty(String property, String value) {
assertEquals(property,getPrefix() + "." + value);
}
public void testType() throws Exception {
assertEquals(getCachedSyndFeed().getFeedType(),getPrefix());
}
/*
public void testType() throws Exception {
assertEquals(getPrefix(), getCachedSyndFeed().getFeedType());
}
public void testTitle() throws Exception {
assertEqualsStr("channel.title", getCachedSyndFeed().getTitle());
}
public void testLink() throws Exception {
assertEqualsStr("channel.link", getCachedSyndFeed().getLink());
}
public void testDescription() throws Exception {
assertEqualsStr("channel.description", getCachedSyndFeed().getDescription());
}
public void testLanguage() throws Exception {
assertEqualsStr("channel.language", getCachedSyndFeed().getLanguage());
}
public void testCategories() throws Exception {
List catlist = getCachedSyndFeed().getCategories();
//don't understand why this one fails
assertEquals(2, catlist.size());
SyndCategory cat = (SyndCategory)catlist.get(0);
assertEqualsStr("channel.category[0]", cat.getName());
assertEqualsStr("channel.category[0]^domain", cat.getTaxonomyUri());
cat = (SyndCategory)catlist.get(1);
assertEqualsStr("channel.category[1]", cat.getName());
assertEqualsStr("channel.category[1]^domain", cat.getTaxonomyUri());
}
public void testPublishedDate() throws Exception {
assertEquals(DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"), getCachedSyndFeed().getPublishedDate());
}
//how do i get height and width?
public void testImage() throws Exception {
SyndImage img = getCachedSyndFeed().getImage();
assertEqualsStr("channel.image.description", img.getDescription());
assertEqualsStr("channel.image.link", img.getLink());
assertEqualsStr("channel.image.title", img.getTitle());
assertEqualsStr("channel.image.url", img.getUrl());
}
public void testEntries() throws Exception {
List entrylist = getCachedSyndFeed().getEntries();
assertEquals(2, entrylist.size());
}
public void testEntryTitle() throws Exception {
assertEqualsStr("channel.item[0].title", getEntryTitle(getCachedSyndFeed().getEntries().get(0)));
assertEqualsStr("channel.item[1].title", getEntryTitle(getCachedSyndFeed().getEntries().get(1)));
}
public String getEntryTitle(Object o) throws Exception {
SyndEntry e = (SyndEntry) o;
return e.getTitle();
}
public void testEntryDescription() throws Exception {
assertEqualsStr("channel.item[0].description", getEntryDescription(getCachedSyndFeed().getEntries().get(0)));
assertEqualsStr("channel.item[1].description", getEntryDescription(getCachedSyndFeed().getEntries().get(1)));
}
public String getEntryDescription(Object o) throws Exception {
SyndEntry e = (SyndEntry) o;
return e.getDescription().getValue();
}
public void testEntryLink() throws Exception {
assertEqualsStr("channel.item[0].link", getEntryLink(getCachedSyndFeed().getEntries().get(0)));
assertEqualsStr("channel.item[1].link", getEntryLink(getCachedSyndFeed().getEntries().get(1)));
}
public String getEntryLink(Object o) {
SyndEntry e = (SyndEntry) o;
return e.getLink();
}
public void testEntryPublishedDate() throws Exception {
assertEquals(DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"), getEntryPublishedDate(getCachedSyndFeed().getEntries().get(0)));
assertEquals(DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"), getEntryPublishedDate(getCachedSyndFeed().getEntries().get(1)));
}
public Date getEntryPublishedDate(Object o) {
SyndEntry e = (SyndEntry) o;
return e.getPublishedDate();
}
public void testEntryCategories() throws Exception {
SyndEntry e = (SyndEntry)getCachedSyndFeed().getEntries().get(0);
List catlist = e.getCategories();
//don't understand why this one fails
assertEquals(2, catlist.size());
SyndCategory cat = (SyndCategory)catlist.get(0);
assertEqualsStr("channel.item[0].category[0]", cat.getName());
assertEqualsStr("channel.item[0].category[0]^domain", cat.getTaxonomyUri());
cat = (SyndCategory)catlist.get(1);
assertEqualsStr("channel.item[0].category[1]", cat.getName());
assertEqualsStr("channel.item[0].category[1]^domain", cat.getTaxonomyUri());
//DO 2nd set of items
}
public void testEntryAuthor() throws Exception {
assertEqualsStr("channel.item[0].author", getEntryAuthor(getCachedSyndFeed().getEntries().get(0)));
assertEqualsStr("channel.item[1].author", getEntryAuthor(getCachedSyndFeed().getEntries().get(1)));
}
public String getEntryAuthor(Object o) {
SyndEntry e = (SyndEntry) o;
return e.getAuthor();
}
*/
/*
//things you cannot get from SyndEntryImpl
// <source url="http://localhost:8080/item0/source.url">item[0].source</source>
// <enclosure url="http://localhost:8080/item0/enclosure0.url" length="100" type="audio/mpeg"/>
// <enclosure url="http://localhost:8080/item0/enclosure1.url" length="1000" type="audio/mpeg"/>
<category domain="item0.domain0">item0.category0</category>
<category domain="item0.domain1">item0.category1</category>
<pubDate>Thu, 08 Jul 1999 08:00:00 GMT</pubDate>
<expirationDate>Thu, 08 Jul 1999 09:00:00 GMT</.expirationDate>
<author>item0.author</author>
<comments>http://localhost:8080/item0/comments</comments>
<guid isPermaLink="true">http://localhost:8080/item0/guid</guid>
//TODO: I still have the elements to test
*/
/*
public void test() {
assertEqualsStr(feed, "");
}
public void test() {
assertEqualsStr(feed, "");
}
*/
//Things that you cannot get form a SyndFeedImpl today
//these need to be put in a RSS 2.0 module
//or is a roundtrip to wirefeed the right way to do this?
/*
* <textInput>
<title>Search</title>
<description>Search this site:</description>
<name>q</name>
<link>http://example.org/mt/mt-search.cgi</link>
</textInput>
image height and width
*
//<copyright>Copyright 2004, Mark Pilgrim</copyright>
public void test() {
assertEqualsStr(getCachedSyndFeed()., "");
}
//<generator>Sample Toolkit</generator>
public void test() {
assertEqualsStr(feed, "");
}
// <managingEditor>editor@example.org</managingEditor>
public void test() {
assertEqualsStr(feed, "");
}
// <webMaster>webmaster@example.org</webMaster>
public void test() {
assertEqualsStr(feed, "");
}
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<cloud domain="rpc.sys.com" port="80" path="/RPC2" registerProcedure="pingMe" protocol="soap"/>
<ttl>60</ttl>
<rating></rating>
<skiphours>
<hour>0</hour>
<hour>1</hour>
<hour>2</hour>
<hour>3</hour>
<hour>4</hour>
<hour>5</hour>
<hour>6</hour>
<hour>7</hour>
<hour>8</hour>
<hour>9.5</hour>
<hour>10</hour>
<hour>11</hour>
<hour>12</hour>
<hour>13</hour>
<hour>14</hour>
<hour>15</hour>
<hour>16</hour>
<hour>17</hour>
<hour>18</hour>
<hour>19</hour>
<hour>20</hour>
<hour>21</hour>
<hour>22</hour>
<hour>23</hour>
</skiphours>
<skipdays>
<day>Monday</day>
<day>Tuesday</day>
<day>Wednesday</day>
<day>Thursday</day>
<day>Friday</day>
<day>Saturday</day>
<day>Sunday</day>
</skipdays>
**/
/*
* @see TestCase#tearDown()
*/
protected void tearDown() throws Exception {
super.tearDown();
}
}

View file

@ -0,0 +1,47 @@
/*
* TestOpsOPML10.java
*
* Created on April 25, 2006, 4:26 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.rometools.unittest;
import com.sun.syndication.feed.WireFeed;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import java.io.FileOutputStream;
import java.io.PrintWriter;
/**
*
* @author cooper
*/
public class TestOpsOPML10 extends FeedOpsTest{
/** Creates a new instance of TestOpsOPML10 */
public TestOpsOPML10() {
super("opml_1.0");
}
// 1.6
public void testWireFeedSyndFeedConversion() throws Exception {
SyndFeed sFeed1 = getCachedSyndFeed();
WireFeed wFeed1 = sFeed1.createWireFeed();
SyndFeed sFeed2 = new SyndFeedImpl(wFeed1);
PrintWriter w = new PrintWriter( new FileOutputStream( "target/test-reports/1") );
w.println( sFeed1.toString() );
w.close();
w = new PrintWriter( new FileOutputStream( "target/test-reports/2") );
w.println( sFeed2.toString() );
w.close();
assertEquals(sFeed1, sFeed2);
}
}

View file

@ -0,0 +1,67 @@
/*
* TestOpsOPML10.java
*
* Created on April 25, 2006, 4:26 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.rometools.unittest;
import com.sun.syndication.feed.WireFeed;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.WireFeedInput;
import com.sun.syndication.io.WireFeedOutput;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
/**
*
* @author cooper
*/
public class TestOpsOPML10links extends FeedOpsTest{
/** Creates a new instance of TestOpsOPML10 */
public TestOpsOPML10links() {
super("opml_1.0_links");
}
// 1.6
public void testWireFeedSyndFeedConversion() throws Exception {
SyndFeed sFeed1 = getCachedSyndFeed();
WireFeed wFeed1 = sFeed1.createWireFeed();
//System.out.println( wFeed1 );
SyndFeed sFeed2 = new SyndFeedImpl(wFeed1);
PrintWriter w = new PrintWriter( new FileOutputStream( "target/test-reports/1") );
w.println( sFeed1.toString() );
w.close();
w = new PrintWriter( new FileOutputStream( "target/test-reports/2") );
w.println( sFeed2.toString() );
w.close();
assertEquals(sFeed2.createWireFeed(), sFeed1.createWireFeed());
}
public void testTemp() throws Exception {
WireFeedInput input = new WireFeedInput();
WireFeed wf = input.build( new File( System.getProperty("basedir")+ "/src/test/resources/opml_1.0_links.xml"));
WireFeedOutput output = new WireFeedOutput();
//System.out.println( wf );
//System.out.println( "=================================");
//System.out.println( new SyndFeedImpl( wf) );
SyndFeedImpl sf = new SyndFeedImpl( wf);
sf.setFeedType("rss_2.0");
sf.setDescription("");
sf.setLink("http://foo.com");
//output.output( sf.createWireFeed() , new PrintWriter( System.out ) );
sf.setFeedType("opml_1.0");
output.output( sf.createWireFeed() , new File( System.getProperty("basedir")+ "/target/test-reports/1.xml") );
}
}

View file

@ -0,0 +1,43 @@
/*
* TestOpsOPML20.java
*
* Created on April 25, 2006, 5:38 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.rometools.unittest;
import com.sun.syndication.feed.WireFeed;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import java.io.FileOutputStream;
import java.io.PrintWriter;
/**
*
* @author cooper
*/
public class TestOpsOPML20 extends FeedOpsTest {
/** Creates a new instance of TestOpsOPML20 */
public TestOpsOPML20() {
super("opml_2.0");
}
public void testWireFeedSyndFeedConversion() throws Exception {
SyndFeed sFeed1 = getCachedSyndFeed();
WireFeed wFeed1 = sFeed1.createWireFeed();
SyndFeed sFeed2 = new SyndFeedImpl(wFeed1);
PrintWriter w = new PrintWriter( new FileOutputStream( "target/test-reports/3") );
w.println( sFeed1.toString() );
w.close();
w = new PrintWriter( new FileOutputStream( "target/test-reports/4") );
w.println( sFeed2.toString() );
w.close();
assertEquals(sFeed1, sFeed2 );
}
}

View file

@ -0,0 +1,134 @@
/*
* Copyright 2004 Sun Microsystems, Inc.
*
* 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.rometools.unittest;
import com.sun.syndication.io.XmlReader;
import com.sun.syndication.io.impl.XmlFixerReader;
import junit.framework.TestCase;
import org.jdom.input.SAXBuilder;
import java.io.*;
/**
* @author pat, tucu
*
*/
public class TestXmlFixerReader extends TestCase {
private static final String XML_PROLOG = "<?xml version=\"1.0\" ?>";
public void testTrim() throws Exception {
_testValidTrim("","<hello></hello>");
_testValidTrim("",XML_PROLOG+"<hello></hello>");
_testValidTrim(" ","<hello></hello>");
_testValidTrim(" ",XML_PROLOG+"<hello></hello>");
_testValidTrim(" \n","<hello></hello>");
_testValidTrim(" \n",XML_PROLOG+"<hello></hello>");
_testValidTrim("<!-- - -- -->","<hello></hello>");
_testValidTrim("<!-- - -- -->",XML_PROLOG+"<hello></hello>");
_testValidTrim(" <!-- - -- -->","<hello></hello>");
_testValidTrim(" <!-- - -- -->",XML_PROLOG+"<hello></hello>");
_testValidTrim(" <!-- - -- --> ","<hello></hello>");
_testValidTrim(" <!-- - -- --> ",XML_PROLOG+"<hello></hello>");
_testValidTrim(" <!-- - -- --> <!-- - -- --> ","<hello></hello>");
_testValidTrim(" <!-- - -- --> <!-- - -- --> ",XML_PROLOG+"<hello></hello>");
_testValidTrim(" <!-- - -- --> \n <!-- - -- --> ","<hello></hello>");
_testValidTrim(" <!-- - -- --> \n <!-- - -- --> ",XML_PROLOG+"<hello></hello>");
_testInvalidTrim("x","<hello></hello>");
_testInvalidTrim("x",XML_PROLOG+"<hello></hello>");
_testInvalidTrim(" x","<hello></hello>");
_testInvalidTrim(" x",XML_PROLOG+"<hello></hello>");
_testInvalidTrim(" x\n","<hello></hello>");
_testInvalidTrim(" x\n",XML_PROLOG+"<hello></hello>");
_testInvalidTrim("<!-- - -- - ->","<hello></hello>");
_testInvalidTrim("<!-- - -- - ->",XML_PROLOG+"<hello></hello>");
_testInvalidTrim(" <!-- - -- -- >","<hello></hello>");
_testInvalidTrim(" <!-- - -- -- >",XML_PROLOG+"<hello></hello>");
_testInvalidTrim(" <!-- - -- -->x ","<hello></hello>");
_testInvalidTrim(" <!-- - -- -->x ",XML_PROLOG+"<hello></hello>");
_testInvalidTrim(" <!-- - -- --> x <!-- - -- --> ","<hello></hello>");
_testInvalidTrim(" <!-- - -- --> x <!-- - -- --> ",XML_PROLOG+"<hello></hello>");
_testInvalidTrim(" <!-- - -- --> x\n <!-- - -- --> ","<hello></hello>");
_testInvalidTrim(" <!-- - -- --> x\n <!-- - -- --> ",XML_PROLOG+"<hello></hello>");
}
public void testHtmlEntities() throws Exception {
_testValidEntities("<hello></hello>");
_testValidEntities(XML_PROLOG+"<hello></hello>");
_testValidEntities(" <!-- just in case -->\n"+XML_PROLOG+"<hello></hello>");
_testValidEntities("<hello>&apos;&yen;&#250;&yen;</hello>");
_testValidEntities(XML_PROLOG+"<hello>&apos;&yen;&#250;&yen;</hello>");
_testValidEntities(" <!-- just in case -->\n"+XML_PROLOG+"<hello>&apos;&yen;&#250;&yen;</hello>");
_testInvalidEntities("<hello>&apos;&yexn;&#250;&yen;</hello>");
_testInvalidEntities(XML_PROLOG+"<hello>&apos;&yexn;&#250;&yen;</hello>");
_testInvalidEntities(" <!-- just in case -->\n"+XML_PROLOG+"<hello>&apos;&yexn;&#250;&yen;</hello>");
_testInvalidEntities("<hello>&apos;&yen;&#2x50;&yen;</hello>");
_testInvalidEntities(XML_PROLOG+"<hello>&apos;&yen;&#2x50;&yen;</hello>");
_testInvalidEntities(" <!-- just in case -->\n"+XML_PROLOG+"<hello>&apos;&yen;&#2x50;&yen;</hello>");
}
protected void _testXmlParse(String garbish,String xmlDoc) throws Exception {
InputStream is = getStream(garbish,xmlDoc);
Reader reader = new XmlReader(is);
reader = new XmlFixerReader(reader);
SAXBuilder saxBuilder = new SAXBuilder();
saxBuilder.build(reader);
}
protected void _testValidTrim(String garbish,String xmlDoc) throws Exception {
_testXmlParse(garbish,xmlDoc);
}
protected void _testInvalidTrim(String garbish,String xmlDoc) throws Exception {
try {
_testXmlParse(garbish,xmlDoc);
assertTrue(false);
}
catch (Exception ex) {
}
}
protected void _testValidEntities(String xmlDoc) throws Exception {
_testXmlParse("",xmlDoc);
}
protected void _testInvalidEntities(String xmlDoc) throws Exception {
try {
_testXmlParse("",xmlDoc);
assertTrue(false);
}
catch (Exception ex) {
}
}
// XML Stream generator
protected InputStream getStream(String garbish,String xmlDoc) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
Writer writer = new OutputStreamWriter(baos);
writer.write(garbish);
writer.write(xmlDoc);
writer.close();
return new ByteArrayInputStream(baos.toByteArray());
}
}

View file

@ -0,0 +1,257 @@
/*
* Copyright 2004 Sun Microsystems, Inc.
*
* 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.rometools.unittest;
import com.sun.syndication.io.XmlReader;
import junit.framework.TestCase;
import java.io.*;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
/**
* @author pat, tucu
*
*/
public class TestXmlReader extends TestCase {
public static void main(String[] args) throws Exception {
TestXmlReader test = new TestXmlReader();
test.testRawBom();
test.testRawNoBom();
test.testHttp();
}
protected void _testRawNoBomValid(String encoding) throws Exception {
InputStream is = getXmlStream("no-bom","xml",encoding,encoding);
XmlReader xmlReader = new XmlReader(is,false);
assertEquals(xmlReader.getEncoding(),"UTF-8");
is = getXmlStream("no-bom","xml-prolog",encoding,encoding);
xmlReader = new XmlReader(is);
assertEquals(xmlReader.getEncoding(),"UTF-8");
is = getXmlStream("no-bom","xml-prolog-encoding",encoding,encoding);
xmlReader = new XmlReader(is);
assertEquals(xmlReader.getEncoding(),encoding);
}
protected void _testRawNoBomInvalid(String encoding) throws Exception {
InputStream is = getXmlStream("no-bom","xml-prolog-encoding",encoding,encoding);
try {
XmlReader xmlReader = new XmlReader(is,false);
fail("It should have failed");
}
catch (IOException ex) {
assertTrue(ex.getMessage().indexOf("Invalid encoding,")>-1);
}
}
public void testRawNoBom() throws Exception {
_testRawNoBomValid("US-ASCII");
_testRawNoBomValid("UTF-8");
_testRawNoBomValid("ISO-8859-1");
}
protected void _testRawBomValid(String encoding) throws Exception {
InputStream is = getXmlStream(encoding+"-bom","xml-prolog-encoding",encoding,encoding);
XmlReader xmlReader = new XmlReader(is,false);
if (!encoding.equals("UTF-16")) {
assertEquals(xmlReader.getEncoding(),encoding);
}
else {
assertEquals(xmlReader.getEncoding().substring(0,encoding.length()),encoding);
}
}
protected void _testRawBomInvalid(String bomEnc,String streamEnc,String prologEnc) throws Exception {
InputStream is = getXmlStream(bomEnc,"xml-prolog-encoding",streamEnc,prologEnc);
try {
XmlReader xmlReader = new XmlReader(is,false);
fail("It should have failed for BOM "+bomEnc+", streamEnc "+streamEnc+" and prologEnc "+prologEnc);
}
catch (IOException ex) {
assertTrue(ex.getMessage().indexOf("Invalid encoding,")>-1);
}
}
public void testRawBom() throws Exception {
_testRawBomValid("UTF-8");
_testRawBomValid("UTF-16BE");
_testRawBomValid("UTF-16LE");
_testRawBomValid("UTF-16");
_testRawBomInvalid("UTF-8-bom","US-ASCII","US-ASCII");
_testRawBomInvalid("UTF-8-bom","ISO-8859-1","ISO-8859-1");
_testRawBomInvalid("UTF-8-bom","UTF-8","UTF-16");
_testRawBomInvalid("UTF-8-bom","UTF-8","UTF-16BE");
_testRawBomInvalid("UTF-8-bom","UTF-8","UTF-16LE");
_testRawBomInvalid("UTF-16BE-bom","UTF-16BE","UTF-16LE");
_testRawBomInvalid("UTF-16LE-bom","UTF-16LE","UTF-16BE");
_testRawBomInvalid("UTF-16LE-bom","UTF-16LE","UTF-8");
}
public void testHttp() throws Exception {
_testHttpValid("application/xml","no-bom","US-ASCII",null);
_testHttpValid("application/xml","UTF-8-bom","US-ASCII",null);
_testHttpValid("application/xml","UTF-8-bom","UTF-8",null);
_testHttpValid("application/xml","UTF-8-bom","UTF-8","UTF-8");
_testHttpValid("application/xml;charset=UTF-8","UTF-8-bom","UTF-8",null);
_testHttpValid("application/xml;charset=UTF-8","UTF-8-bom","UTF-8","UTF-8");
_testHttpValid("application/xml;charset=UTF-16","UTF-16BE-bom","UTF-16BE",null);
_testHttpValid("application/xml;charset=UTF-16","UTF-16BE-bom","UTF-16BE","UTF-16");
_testHttpValid("application/xml;charset=UTF-16","UTF-16BE-bom","UTF-16BE","UTF-16BE");
_testHttpInvalid("application/xml;charset=UTF-16BE","UTF-16BE-bom","UTF-16BE",null);
_testHttpInvalid("application/xml;charset=UTF-16BE","UTF-16BE-bom","UTF-16BE","UTF-16");
_testHttpInvalid("application/xml;charset=UTF-16BE","UTF-16BE-bom","UTF-16BE","UTF-16BE");
_testHttpInvalid("application/xml","UTF-8-bom","US-ASCII","US-ASCII");
_testHttpInvalid("application/xml;charset=UTF-16","UTF-16LE","UTF-8","UTF-8");
_testHttpInvalid("application/xml;charset=UTF-16","no-bom","UTF-16BE","UTF-16BE");
_testHttpValid("text/xml","no-bom","US-ASCII",null);
_testHttpValid("text/xml;charset=UTF-8","UTF-8-bom","UTF-8","UTF-8");
_testHttpValid("text/xml;charset=UTF-8","UTF-8-bom","UTF-8",null);
_testHttpValid("text/xml;charset=UTF-16","UTF-16BE-bom","UTF-16BE",null);
_testHttpValid("text/xml;charset=UTF-16","UTF-16BE-bom","UTF-16BE","UTF-16");
_testHttpValid("text/xml;charset=UTF-16","UTF-16BE-bom","UTF-16BE","UTF-16BE");
_testHttpValid("text/xml","UTF-8-bom","US-ASCII",null);
_testHttpInvalid("text/xml;charset=UTF-16BE","UTF-16BE-bom","UTF-16BE",null);
_testHttpInvalid("text/xml;charset=UTF-16BE","UTF-16BE-bom","UTF-16BE","UTF-16");
_testHttpInvalid("text/xml;charset=UTF-16BE","UTF-16BE-bom","UTF-16BE","UTF-16BE");
_testHttpInvalid("text/xml;charset=UTF-16","no-bom","UTF-16BE","UTF-16BE");
_testHttpInvalid("text/xml;charset=UTF-16","no-bom","UTF-16BE",null);
_testHttpLenient("text/xml","no-bom","US-ASCII",null, "US-ASCII");
_testHttpLenient("text/xml;charset=UTF-8","UTF-8-bom","UTF-8","UTF-8", "UTF-8");
_testHttpLenient("text/xml;charset=UTF-8","UTF-8-bom","UTF-8",null, "UTF-8");
_testHttpLenient("text/xml;charset=UTF-16","UTF-16BE-bom","UTF-16BE",null, "UTF-16BE");
_testHttpLenient("text/xml;charset=UTF-16","UTF-16BE-bom","UTF-16BE","UTF-16", "UTF-16");
_testHttpLenient("text/xml;charset=UTF-16","UTF-16BE-bom","UTF-16BE","UTF-16BE", "UTF-16BE");
_testHttpLenient("text/xml","UTF-8-bom","US-ASCII",null, "US-ASCII");
_testHttpLenient("text/xml;charset=UTF-16BE","UTF-16BE-bom","UTF-16BE",null, "UTF-16BE");
_testHttpLenient("text/xml;charset=UTF-16BE","UTF-16BE-bom","UTF-16BE","UTF-16", "UTF-16");
_testHttpLenient("text/xml;charset=UTF-16BE","UTF-16BE-bom","UTF-16BE","UTF-16BE", "UTF-16BE");
_testHttpLenient("text/xml;charset=UTF-16","no-bom","UTF-16BE","UTF-16BE", "UTF-16BE");
_testHttpLenient("text/xml;charset=UTF-16","no-bom","UTF-16BE",null, "UTF-16");
_testHttpLenient("text/html","no-bom","US-ASCII","US-ASCII", "US-ASCII");
_testHttpLenient("text/html","no-bom","US-ASCII",null, "US-ASCII");
_testHttpLenient("text/html;charset=UTF-8","no-bom","US-ASCII","UTF-8", "UTF-8");
_testHttpLenient("text/html;charset=UTF-16BE","no-bom","US-ASCII","UTF-8", "UTF-8");
}
public void _testHttpValid(String cT,String bomEnc,String streamEnc,String prologEnc) throws Exception {
InputStream is = getXmlStream(bomEnc,(prologEnc==null)?"xml":"xml-prolog-encoding",streamEnc,prologEnc);
XmlReader xmlReader = new XmlReader(is,cT,false);
if (!streamEnc.equals("UTF-16")) {
// we can not assert things here becuase UTF-8, US-ASCII and ISO-8859-1 look alike for the chars used for detection
}
else {
assertEquals(xmlReader.getEncoding().substring(0,streamEnc.length()),streamEnc);
}
}
protected void _testHttpInvalid(String cT,String bomEnc,String streamEnc,String prologEnc) throws Exception {
InputStream is = getXmlStream(bomEnc,(prologEnc==null)?"xml-prolog":"xml-prolog-encoding",streamEnc,prologEnc);
try {
XmlReader xmlReader = new XmlReader(is,cT,false);
fail("It should have failed for HTTP Content-type "+cT+", BOM "+bomEnc+", streamEnc "+streamEnc+" and prologEnc "+prologEnc);
}
catch (IOException ex) {
assertTrue(ex.getMessage().indexOf("Invalid encoding,")>-1);
}
}
protected void _testHttpLenient(String cT, String bomEnc, String streamEnc, String prologEnc, String shouldbe) throws Exception {
InputStream is = getXmlStream(bomEnc,(prologEnc==null)?"xml-prolog":"xml-prolog-encoding",streamEnc,prologEnc);
XmlReader xmlReader = new XmlReader(is,cT,true);
assertEquals(xmlReader.getEncoding(),shouldbe);
}
// XML Stream generator
private static final int[] NO_BOM_BYTES = {};
private static final int[] UTF_16BE_BOM_BYTES = {0xFE,0xFF};
private static final int[] UTF_16LE_BOM_BYTES = {0xFF,0XFE};
private static final int[] UTF_8_BOM_BYTES = {0xEF,0xBB,0xBF};
private static final Map BOMs = new HashMap();
static {
BOMs.put("no-bom",NO_BOM_BYTES);
BOMs.put("UTF-16BE-bom",UTF_16BE_BOM_BYTES);
BOMs.put("UTF-16LE-bom",UTF_16LE_BOM_BYTES);
BOMs.put("UTF-16-bom",NO_BOM_BYTES); // it's added by the writer
BOMs.put("UTF-8-bom",UTF_8_BOM_BYTES);
}
private static final MessageFormat XML = new MessageFormat(
"<root>{2}</root>");
private static final MessageFormat XML_WITH_PROLOG = new MessageFormat(
"<?xml version=\"1.0\"?>\n<root>{2}</root>");
private static final MessageFormat XML_WITH_PROLOG_AND_ENCODING = new MessageFormat(
"<?xml version=\"1.0\" encoding=\"{1}\"?>\n<root>{2}</root>");
private static final MessageFormat INFO = new MessageFormat(
"\nBOM : {0}\nDoc : {1}\nStream Enc : {2}\nProlog Enc : {3}\n");
private static final Map XMLs = new HashMap();
static {
XMLs.put("xml",XML);
XMLs.put("xml-prolog",XML_WITH_PROLOG);
XMLs.put("xml-prolog-encoding",XML_WITH_PROLOG_AND_ENCODING);
}
/**
*
* @param bomType no-bom, UTF-16BE-bom, UTF-16LE-bom, UTF-8-bom
* @param xmlType xml, xml-prolog, xml-prolog-charset
* @return XML stream
*/
protected InputStream getXmlStream(String bomType,String xmlType,String streamEnc,String prologEnc) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
int[] bom = (int[]) BOMs.get(bomType);
if (bom==null) {
bom = new int[0];
}
MessageFormat xml = (MessageFormat) XMLs.get(xmlType);
for (int i=0;i<bom.length;i++) {
baos.write(bom[i]);
}
Writer writer = new OutputStreamWriter(baos,streamEnc);
String info = INFO.format(new Object[]{bomType,xmlType,prologEnc});
String xmlDoc = xml.format(new Object[]{streamEnc,prologEnc,info});
writer.write(xmlDoc);
// PADDDING TO TEST THINGS WORK BEYOND PUSHBACK_SIZE
writer.write("<da>\n");
for (int i=0;i<10000;i++) {
writer.write("<do/>\n");
}
writer.write("</da>\n");
writer.close();
return new ByteArrayInputStream(baos.toByteArray());
}
}