diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f43cdb1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +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. + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e9198a5 --- /dev/null +++ b/pom.xml @@ -0,0 +1,191 @@ + + + 4.0.0 + + org.rometools + rome + ROME, RSS and atOM utilitiEs for Java + 1.5-SNAPSHOT + jar + All Roads Lead to ROME. ROME is a set of Atom/RSS Java utilities that make it + easy to work in Java with most syndication formats. Today it accepts all flavors of RSS + (0.90, 0.91, 0.92, 0.93, 0.94, 1.0 and 2.0), Atom 0.3 and Atom 1.0 feeds. Rome includes + a set of parsers and generators for the various flavors of feeds, as well as converters + to convert from one format to another. The parsers can give you back Java objects that + are either specific for the format you want to work with, or a generic normalized + SyndFeed object that lets you work on with the data without bothering about the + underlying format. + https://rome.dev.java.net/ + + https://rometools.jira.com/browse/ROME#selectedTab=com.atlassian.jira.plugin.system.project%3Aissues-panel + + + + + +
dev@rome.dev.java.net
+
+
+
+
+ 2004 + + + dev@rome.dev.java.net + + https://rome.dev.java.net/servlets/ProjectMailingListList + + https://rome.dev.java.net/servlets/ProjectMailingListList + + https://rome.dev.java.net/servlets/SummarizeList?listName=dev + + + + + Robert Cooper + http://www.screaming-penguin.com + -4 + kebernet@gmail.com + + + Alejandro Abdelnur + http://blog.sun.com/roller/page/tucu/ + 0 + + + Elaine Chien + 0 + + + Patrick Chanezon + http://www.chanezon.com/pat/weblog/ + -9 + + + + scm:svn:https://rometools.jira.com/svn/ROME/trunk + scm:svn:https://rometools.jira.com/svn/ROME/trunk + https://rometools.jira.com/source/browse/ROME + + + + Apache 2 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + ROME Project + http://www.rometools.org + + + + org.jdom + jdom + 1.1 + + + junit + junit + 3.8.1 + test + + + + + + org.apache.maven.plugins + maven-scm-plugin + 1.0 + + install + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.0.2 + + 1.4 + 1.4 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.2 + + ${project.build.sourceEncoding} + + + + + + + release + + + performRelease + true + + + + + central.staging + Nexus Release Repository + http://oss.sonatype.org/service/local/staging/deploy/maven2 + + + sonatype.snapshots + My Nexus Snapshots Repository + https://oss.sonatype.org/content/repositories/snapshots/ + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + + + UTF-8 + + +
diff --git a/src/main/java/com/sun/syndication/feed/CopyFrom.java b/src/main/java/com/sun/syndication/feed/CopyFrom.java new file mode 100644 index 0000000..c40f761 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/CopyFrom.java @@ -0,0 +1,47 @@ +/* + * 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 com.sun.syndication.feed; + +/** + * @author Alejandro Abdelnur + */ +public interface CopyFrom { + + /** + * Returns the interface the copyFrom works on. + *

+ * This is useful when dealing with properties that may have multiple implementations. + * For example, Module. + *

+ * @return the interface the copyFrom works on. + */ + public Class getInterface(); + + /** + * Copies all the properties of the given bean into this one. + *

+ * Any existing properties in this bean are lost. + *

+ * This method is useful for moving from one implementation of a bean interface to another. + * For example from the default SyndFeed bean implementation to a Hibernate ready implementation. + *

+ * @param obj the instance to copy properties from. + * + */ + public void copyFrom(Object obj); + +} diff --git a/src/main/java/com/sun/syndication/feed/WireFeed.java b/src/main/java/com/sun/syndication/feed/WireFeed.java new file mode 100644 index 0000000..16a34ec --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/WireFeed.java @@ -0,0 +1,222 @@ +/* + * 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 com.sun.syndication.feed; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.impl.ModuleUtils; +import com.sun.syndication.feed.module.Extendable; + +import java.util.List; +import java.util.ArrayList; +import java.io.Serializable; + +/** + * Parent class of the RSS (Channel) and Atom (Feed) feed beans. + *

+ * NOTE: We don't like this class at this package level but the alternative would have + * been a proliferation of packages (one more level to hold atom and rss package with + * this class just in that package). + *

+ * The format of the 'type' property must be [FEEDNAME]_[FEEDVERSION] with the FEEDNAME in lower case, + * for example: rss_0.9, rss_0.93, atom_0.3 + *

+ * @author Alejandro Abdelnur + * + */ +public abstract class WireFeed implements Cloneable, Serializable, Extendable { + private ObjectBean _objBean; + private String _feedType; + private String _encoding; + private List _modules; + private List _foreignMarkup; + + /** + * Default constructor, for bean cloning purposes only. + *

+ * + */ + protected WireFeed() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a feed for a given type. + *

+ * @param type of the feed to create. + * + */ + protected WireFeed(String type) { + this(); + _feedType = type; + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + if (other == null) { + return false; + } + // can't use foreign markup in equals, due to JDOM equals impl + Object fm = getForeignMarkup(); + setForeignMarkup(((WireFeed)other).getForeignMarkup()); + boolean ret = _objBean.equals(other); + // restore foreign markup + setForeignMarkup(fm); + return ret; + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + + + + + /** + * Sets the feedType of a the feed. Do not use, for bean cloning purposes only. + *

+ * @param feedType the feedType of the feed. + * + */ + public void setFeedType(String feedType) { + _feedType = feedType; + } + + /** + * Returns the type of the feed. + * + * @return the type of the feed. + */ + public String getFeedType() { + return _feedType; + } + + /** + * Returns the charset encoding of a the feed. + *

+ * This property is not set by feed parsers. But it is used by feed generators + * to set the encoding in the XML prolog. + *

+ * @return the charset encoding of the feed. + * + */ + public String getEncoding() { + return _encoding; + } + + /** + * Sets the charset encoding of a the feed. + *

+ * This property is not set by feed parsers. But it is used by feed generators + * to set the encoding in the XML prolog. + *

+ * @param encoding the charset encoding of the feed. + * + */ + public void setEncoding(String encoding) { + _encoding = encoding; + } + + + /** + * Returns the channel modules. + *

+ * @return a list of ModuleImpl elements with the channel modules, + * an empty list if none. + * + */ + public List getModules() { + return (_modules==null) ? (_modules=new ArrayList()) : _modules; + } + + /** + * Sets the channel modules. + *

+ * @param modules the list of ModuleImpl elements with the channel modules to set, + * an empty list or null if none. + * + */ + public void setModules(List modules) { + _modules = modules; + } + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri) { + return ModuleUtils.getModule(_modules,uri); + } + + /** + * Returns foreign markup found at channel level. + *

+ * @return Opaque object to discourage use + * + */ + public Object getForeignMarkup() { + return (_foreignMarkup==null) ? (_foreignMarkup=new ArrayList()) : _foreignMarkup; + } + + /** + * Sets foreign markup found at channel level. + *

+ * @param foreignMarkup Opaque object to discourage use + * + */ + public void setForeignMarkup(Object foreignMarkup) { + _foreignMarkup = (List)foreignMarkup; + } +} diff --git a/src/main/java/com/sun/syndication/feed/atom/Category.java b/src/main/java/com/sun/syndication/feed/atom/Category.java new file mode 100644 index 0000000..eac01ec --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/atom/Category.java @@ -0,0 +1,151 @@ +/* + * 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 com.sun.syndication.feed.atom; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for category elements of Atom feeds. + *

+ * @author Dave Johnson (added for Atom 1.0) + */ +public class Category implements Cloneable, Serializable { + + private ObjectBean _objBean; + + private String _term; + private String _scheme; + private String _schemeResolved; + private String _label; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Category() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Get label for category. + *

+ * @return Label for category. + */ + public String getLabel() { + return _label; + } + + /** + * Set label for category. + *

+ * @param label Label for category. + */ + public void setLabel(String label) { + this._label = label; + } + + /** + * Get Scheme URI for category. + *

+ * @return Scheme URI for category. + */ + public String getScheme() { + return _scheme; + } + + /** + * Set scheme URI for category. + *

+ * @param scheme Scheme URI for category. + */ + public void setScheme(String scheme) { + this._scheme = scheme; + } + + public void setSchemeResolved(String schemeResolved) { + _schemeResolved = schemeResolved; + } + + public String getSchemeResolved() { + return _schemeResolved != null ? _schemeResolved : _scheme; + } + + /** + * Return term for category. + *

+ * @return Term for category. + */ + public String getTerm() { + return _term; + } + + /** + * Set term for category. + *

+ * @param term Term for category. + */ + public void setTerm(String term) { + this._term = term; + } +} diff --git a/src/main/java/com/sun/syndication/feed/atom/Content.java b/src/main/java/com/sun/syndication/feed/atom/Content.java new file mode 100644 index 0000000..1f8dda4 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/atom/Content.java @@ -0,0 +1,212 @@ +/* + * 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 com.sun.syndication.feed.atom; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +/** + * Bean for content elements of Atom feeds. + *

+ * @author Alejandro Abdelnur + * @author Dave Johnson (updated for Atom 1.0) + */ +public class Content implements Cloneable,Serializable { + + private ObjectBean _objBean; + + private String _type; + private String _value; + private String _src; + + /** @since Atom 1.0 */ + public static final String TEXT = "text"; + + /** @since Atom 1.0 */ + public static final String HTML = "html"; + + /** @since Atom 1.0 */ + public static final String XHTML = "xhtml"; + + /** Atom 0.3 only */ + public static final String XML = "xml"; + + /** Atom 0.3 only */ + public static final String BASE64 = "base64"; + + /** Atom 0.3 only */ + public static final String ESCAPED = "escaped"; + + private String _mode; + private static final Set MODES = new HashSet(); + static { + MODES.add(XML); + MODES.add(BASE64); + MODES.add(ESCAPED); + } + + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Content() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the content type. + *

+ * The type indicates how the value was/will-be encoded in the XML feed. + *

+ * @since Atom 1.0 + */ + public String getType() { + return _type; + } + + /** + * Sets the content type. + *

+ * The type indicates how the value was/will-be encoded in the XML feed. + *

+ * @since Atom 1.0 + */ + public void setType(String type) { + _type = type; + } + + /** + * Returns the content mode (Atom 0.3 only). + *

+ * The mode indicates how the value was/will-be encoded in the XML feed. + *

+ * @return the content mode, null if none. + */ + public String getMode() { + return _mode; + } + + /** + * Sets the content mode (Atom 0.3 only). + *

+ * The mode indicates how the value was/will-be encoded in the XML feed. + *

+ * @param mode the content mode, null if none. + */ + public void setMode(String mode) { + mode = (mode!=null) ? mode.toLowerCase() : null; + if (mode==null || !MODES.contains(mode)) { + throw new IllegalArgumentException("Invalid mode ["+mode+"]"); + } + _mode = mode; + } + + /** + * Returns the content value. + *

+ * The return value should be decoded. + *

+ * @return the content value, null if none. + * + */ + public String getValue() { + return _value; + } + + /** + * Sets the content value. + *

+ * The value being set should be decoded. + *

+ * @param value the content value, null if none. + * + */ + public void setValue(String value) { + _value = value; + } + + /** + * Returns the src + *

+ * @return Returns the src. + * @since Atom 1.0 + */ + public String getSrc() { + return _src; + } + + /** + * Set the src + *

+ * @param src The src to set. + * @since Atom 1.0 + */ + public void setSrc(String src) { + _src = src; + } +} + + diff --git a/src/main/java/com/sun/syndication/feed/atom/Entry.java b/src/main/java/com/sun/syndication/feed/atom/Entry.java new file mode 100644 index 0000000..fdd7896 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/atom/Entry.java @@ -0,0 +1,550 @@ +/* + * 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 com.sun.syndication.feed.atom; + +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.impl.ModuleUtils; +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.module.Extendable; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.io.Serializable; +import java.util.Iterator; + +/** + * Bean for entry elements of Atom feeds. + *

+ * @author Alejandro Abdelnur + * @author Dave Johnson (updated for Atom 1.0) + */ +public class Entry implements Cloneable, Serializable, Extendable { + + private ObjectBean _objBean; + + private String _xmlBase; + private List _authors; + private List _contributors; + private List _categories; + private List _contents; + private String _id; + private Date _published; // AKA issued + private String _rights; + private Feed _source; + private Content _summary; + private Content _title; + private Date _updated; // AKA modified + private List _alternateLinks; + private List _otherLinks; + private List _foreignMarkup; + + private List _modules; + + private Date _created; // Atom 0.3 only + + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Entry() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + if (other == null) { + return false; + } + // can't use foreign markup in equals, due to JDOM equals impl + Object fm = getForeignMarkup(); + setForeignMarkup(((Entry)other).getForeignMarkup()); + boolean ret = _objBean.equals(other); + // restore foreign markup + setForeignMarkup(fm); + return ret; + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the entry title. + *

+ * @return the entry title, null if none. + * + */ + public String getTitle() { + if (_title != null) return _title.getValue(); + return null; + } + + /** + * Sets the entry title. + *

+ * @param title the entry title, null if none. + * + */ + public void setTitle(String title) { + if (_title == null) _title = new Content(); + _title.setValue(title); + } + + /** + * Returns the entry title as a text construct. + *

+ * @return the entry title, null if none. + * + */ + public Content getTitleEx() { + return _title; + } + + /** + * Sets the entry title as a text construct. + *

+ * @param title the entry title, null if none. + * + */ + public void setTitleEx(Content title) { + _title = title; + } + + /** + * Returns the entry alternate links. + *

+ * @return a list of Link elements with the entry alternate links, an empty list if none. + */ + public List getAlternateLinks() { + return (_alternateLinks==null) ? (_alternateLinks=new ArrayList()) : _alternateLinks; + } + + /** + * Sets the entry alternate links. + *

+ * @param alternateLinks the list of Link elements with the entry alternate links to set, + * an empty list or null if none. + */ + public void setAlternateLinks(List alternateLinks) { + _alternateLinks = alternateLinks; + } + + /** + * Returns the entry non-alternate links. + *

+ * @return the list of Link elements with the entry non-alternate links to set, + * an empty list if none. + */ + public List getOtherLinks() { + return (_otherLinks==null) ? (_otherLinks=new ArrayList()) : _otherLinks; + } + + /** + * Sets the entry non-alternate links. + *

+ * @param otherLinks the list Link elements with the entry non-alternate links to set, + * an empty list or null if none. + */ + public void setOtherLinks(List otherLinks) { + _otherLinks = otherLinks; + } + + /** + * Returns the entry author. + *

+ * @return the entry author, null if none. + * + */ + public List getAuthors() { + return (_authors==null) ? (_authors=new ArrayList()) : _authors; + } + + /** + * Sets the author of the entry. + *

+ * @param authors the author of the entry, null if none. + * + */ + public void setAuthors(List authors) { + _authors = authors; + } + + /** + * Returns the entry contributors. + *

+ * @return a list of Person elements with the entry contributors, + * an empty list if none. + * + */ + public List getContributors() { + return (_contributors==null) ? (_contributors=new ArrayList()) : _contributors; + } + + /** + * Sets the entry contributors. + *

+ * @param contributors the list of Person elements with the entry contributors to set, + * an empty list or null if none. + * + */ + public void setContributors(List contributors) { + _contributors = contributors; + } + + /** + * Returns the entry ID. + *

+ * @return the entry ID, null if none. + * + */ + public String getId() { + return _id; + } + + /** + * Sets the entry ID. + *

+ * @param id the entry ID, null if none. + * + */ + public void setId(String id) { + _id = id; + } + + /** + * Returns the entry modified date (Atom 0.3, maps to {@link #getUpdated()}). + *

+ * @return the entry modified date, null if none. + */ + public Date getModified() { + return _updated; + } + + /** + * Sets the entry modified date (Atom 0.3, maps to {@link #setUpdated(java.util.Date)}). + *

+ * @param modified the entry modified date, null if none. + */ + public void setModified(Date modified) { + _updated = modified; + } + + /** + * Returns the entry issued date (Atom 0.3, maps to {@link #getPublished()}). + *

+ * @return the entry issued date, null if none. + */ + public Date getIssued() { + return _published; + } + + /** + * Sets the entry issued date (Atom 0.3, maps to {@link #setPublished(java.util.Date)}). + *

+ * @param issued the entry issued date, null if none. + */ + public void setIssued(Date issued) { + _published = issued; + } + + /** + * Returns the entry created date (Atom 0.3 only) + *

+ * @return the entry created date, null if none. + */ + public Date getCreated() { + return _created; + } + + /** + * Sets the entry created date (Atom 0.3 only) + *

+ * @param created the entry created date, null if none. + */ + public void setCreated(Date created) { + _created = created; + } + + /** + * Returns the entry summary. + *

+ * @return the entry summary, null if none. + * + */ + public Content getSummary() { + return _summary; + } + + /** + * Sets the entry summary. + *

+ * @param summary the entry summary, null if none. + * + */ + public void setSummary(Content summary) { + _summary = summary; + } + + /** + * Returns the entry contents. + *

+ * @return a list of Content elements with the entry contents, + * an empty list if none. + */ + public List getContents() { + return (_contents==null) ? (_contents=new ArrayList()) : _contents; + } + + /** + * Sets the entry contents. + *

+ * @param contents the list of Content elements with the entry contents to set, + * an empty list or null if none. + */ + public void setContents(List contents) { + _contents = contents; + } + + /** + * Returns the entry modules. + *

+ * @return a list of ModuleImpl elements with the entry modules, + * an emtpy list if none. + * + */ + public List getModules() { + return (_modules==null) ? (_modules=new ArrayList()) : _modules; + } + + /** + * Sets the entry modules. + *

+ * @param modules the list of ModuleImpl elements with the entry modules to set, + * an empty list or null if none. + * + */ + public void setModules(List modules) { + _modules = modules; + } + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri) { + return ModuleUtils.getModule(_modules,uri); + } + + /** + * Returns the published + *

+ * @return Returns the published. + * @since Atom 1.0 + */ + public Date getPublished() { + return _published; + } + + /** + * Set the published + *

+ * @param published The published to set. + * @since Atom 1.0 + */ + public void setPublished(Date published) { + _published = published; + } + + /** + * Returns the rights + *

+ * @return Returns the rights. + * @since Atom 1.0 + */ + public String getRights() { + return _rights; + } + + /** + * Set the rights + *

+ * @param rights The rights to set. + * @since Atom 1.0 + */ + public void setRights(String rights) { + _rights = rights; + } + + /** + * Returns the source + *

+ * @return Returns the source. + */ + public Feed getSource() { + return _source; + } + + /** + * Set the source + *

+ * @param source The source to set. + */ + public void setSource(Feed source) { + _source = source; + } + + /** + * Returns the updated + *

+ * @return Returns the updated. + * @since Atom 1.0 + */ + public Date getUpdated() { + return _updated; + } + + /** + * Set the updated + *

+ * @param updated The updated to set. + * @since Atom 1.0 + */ + public void setUpdated(Date updated) { + _updated = updated; + } + + /** + * Returns the categories + *

+ * @return Returns the categories. + * @since Atom 1.0 + */ + public List getCategories() { + return (_categories==null) ? (_categories=new ArrayList()) : _categories; + + } + + /** + * Set the categories + *

+ * @param categories The categories to set. + * @since Atom 1.0 + */ + public void setCategories(List categories) { + _categories = categories; + } + + /** + * Returns the xmlBase + *

+ * @return Returns the xmlBase. + * @since Atom 1.0 + */ + public String getXmlBase() { + return _xmlBase; + } + + /** + * Set the xmlBase + *

+ * @param xmlBase The xmlBase to set. + * @since Atom 1.0 + */ + public void setXmlBase(String xmlBase) { + _xmlBase = xmlBase; + } + + + /** + * Returns foreign markup found at entry level. + *

+ * @return list of Opaque object to discourage use + * + */ + public Object getForeignMarkup() { + return (_foreignMarkup==null) ? (_foreignMarkup=new ArrayList()) : _foreignMarkup; + } + + /** + * Sets foreign markup found at entry level. + *

+ * @param foreignMarkup Opaque object to discourage use + * + */ + public void setForeignMarkup(Object foreignMarkup) { + _foreignMarkup = (List)foreignMarkup; + } + + /** + * Returns true if entry is a media entry, i.e. has rel="edit-media". + * + * @return true if entry is a media entry + */ + public boolean isMediaEntry() { + boolean mediaEntry = false; + List links = getOtherLinks(); + for (Iterator it = links.iterator(); it.hasNext();) { + Link link = (Link) it.next(); + if ("edit-media".equals(link.getRel())) { + mediaEntry = true; + break; + } + } + return mediaEntry; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/atom/Feed.java b/src/main/java/com/sun/syndication/feed/atom/Feed.java new file mode 100644 index 0000000..ce8bb46 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/atom/Feed.java @@ -0,0 +1,525 @@ +/* + * 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 com.sun.syndication.feed.atom; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.impl.ModuleUtils; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Bean for Atom feeds. + *

+ * It handles Atom feeds version 0.3 without loosing any feed information. + *

+ * @author Alejandro Abdelnur + * @author Dave Johnson (updated for Atom 1.0) + */ +public class Feed extends WireFeed { + + private String _xmlBase; + private List _categories; + private List _authors; + private List _contributors; + private Generator _generator; + private String _icon; + private String _id; + private String _logo; + private String _rights; // AKA copyright + private Content _subtitle; // AKA tagline + private Content _title; + private Date _updated; // AKA modified + private List _alternateLinks; + private List _otherLinks; + private List _entries; + + private List _modules; + + private Content _info; // Atom 0.3 only + private String _language; // Atom 0.3 only + + /** + * Default constructor, for bean cloning purposes only. + * + */ + public Feed() { + } + + /** + * Feed Constructor. All properties, except the type, are set to null. + *

+ * @param type the type of the Atom feed. + * + */ + public Feed(String type) { + super(type); + } + + /** + * Returns the feed language (Atom 0.3 only) + *

+ * @return the feed language, null if none. + * + */ + public String getLanguage() { + return _language; + } + + /** + * Sets the feed language (Atom 0.3 only) + *

+ * @param language the feed language to set, null if none. + * + */ + public void setLanguage(String language) { + _language = language; + } + + /** + * Returns the feed title. + *

+ * @return the feed title, null if none. + * + */ + public String getTitle() { + if (_title != null) return _title.getValue(); + return null; + } + + /** + * Sets the feed title. + *

+ * @param title the feed title to set, null if none. + * + */ + public void setTitle(String title) { + if (_title == null) _title = new Content(); + _title.setValue(title); + } + + /** + * Returns the feed title. + *

+ * @return the feed title, null if none. + * + */ + public Content getTitleEx() { + return _title; + } + + /** + * Sets the feed title. + *

+ * @param title the feed title to set, null if none. + * + */ + public void setTitleEx(Content title) { + _title = title; + } + + /** + * Returns the feed alternate links. + *

+ * @return a list of Link elements with the feed alternate links, + * an empty list if none. + */ + public List getAlternateLinks() { + return (_alternateLinks==null) ? (_alternateLinks=new ArrayList()) : _alternateLinks; + } + + /** + * Sets the feed alternate links. + *

+ * @param alternateLinks the list of Link elements with the feed alternate links to set, + * an empty list or null if none. + */ + public void setAlternateLinks(List alternateLinks) { + _alternateLinks = alternateLinks; + } + + /** + * Returns the feed other links (non-alternate ones). + *

+ * @return a list of Link elements with the feed other links (non-alternate ones), + * an empty list if none. + */ + public List getOtherLinks() { + return (_otherLinks==null) ? (_otherLinks=new ArrayList()) : _otherLinks; + } + + /** + * Sets the feed other links (non-alternate ones). + *

+ * @param otherLinks the list of Link elements with the feed other links (non-alternate ones) to set, + * an empty list or null if none. + */ + public void setOtherLinks(List otherLinks) { + _otherLinks = otherLinks; + } + + /** + * Returns the feed author. + *

+ * @return the feed author, null if none. + * + */ + public List getAuthors() { + return (_authors==null) ? (_authors=new ArrayList()) : _authors; + } + + /** + * Sets the feed author. + *

+ * @param authors the feed author to set, null if none. + * + */ + public void setAuthors(List authors) { + _authors = authors; + } + + /** + * Returns the feed contributors. + *

+ * @return a list of Person elements with the feed contributors, + * an empty list if none. + * + */ + public List getContributors() { + return (_contributors==null) ? (_contributors=new ArrayList()) : _contributors; + } + + /** + * Sets the feed contributors. + *

+ * @param contributors the list of Person elements with the feed contributors to set, + * an empty list or null if none. + * + */ + public void setContributors(List contributors) { + _contributors = contributors; + } + + /** + * Returns the feed tag line (Atom 0.3, maps to {@link #getSubtitle()}). + *

+ * @return the feed tag line, null if none. + */ + public Content getTagline() { + return _subtitle; + } + + /** + * Sets the feed tagline (Atom 0.3, maps to {@link #setSubtitle(com.sun.syndication.feed.atom.Content)}). + *

+ * @param tagline the feed tagline to set, null if none. + */ + public void setTagline(Content tagline) { + _subtitle = tagline; + } + + /** + * Returns the feed ID. + *

+ * @return the feed ID, null if none. + * + */ + public String getId() { + return _id; + } + + /** + * Sets the feed ID. + *

+ * @param id the feed ID to set, null if none. + * + */ + public void setId(String id) { + _id = id; + } + + /** + * Returns the feed generator. + *

+ * @return the feed generator, null if none. + * + */ + public Generator getGenerator() { + return _generator; + } + + /** + * Sets the feed generator. + *

+ * @param generator the feed generator to set, null if none. + * + */ + public void setGenerator(Generator generator) { + _generator = generator; + } + + /** + * Returns the feed copyright (Atom 0.3, maps to {@link #getRights()}). + *

+ * @return the feed copyright, null if none. + */ + public String getCopyright() { + return _rights; + } + + /** + * Sets the feed copyright (Atom 0.3, maps to {@link #setRights(java.lang.String)}). + *

+ * @param copyright the feed copyright to set, null if none. + */ + public void setCopyright(String copyright) { + _rights = copyright; + } + + /** + * Returns the feed info (Atom 0.3 only) + *

+ * @return the feed info, null if none. + */ + public Content getInfo() { + return _info; + } + + /** + * Sets the feed info (Atom 0.3 only) + *

+ * @param info the feed info to set, null if none. + */ + public void setInfo(Content info) { + _info = info; + } + + /** + * Returns the feed modified date (Atom 0.3, maps to {@link #getUpdated()}). + *

+ * @return the feed modified date, null if none. + */ + public Date getModified() { + return _updated; + } + + /** + * Sets the feed modified date (Atom 0.3, maps to {@link #setUpdated(java.util.Date)}). + *

+ * @param modified the feed modified date to set, null if none. + */ + public void setModified(Date modified) { + _updated = modified; + } + + /** + * Returns the feed entries. + *

+ * @return a list of Entry elements with the feed entries, + * an empty list if none. + * + */ + public List getEntries() { + return (_entries==null) ? (_entries=new ArrayList()) : _entries; + } + + /** + * Sets the feed entries. + *

+ * @param entries the list of Entry elements with the feed entries to set, + * an empty list or null if none. + * + */ + public void setEntries(List entries) { + _entries = entries; + } + + /** + * Returns the feed modules. + *

+ * @return a list of ModuleImpl elements with the feed modules, + * an empty list if none. + * + */ + public List getModules() { + return (_modules==null) ? (_modules=new ArrayList()) : _modules; + } + + /** + * Sets the feed moduless. + *

+ * @param modules the list of ModuleImpl elements with the feed moduless to set, + * an empty list or null if none. + * + */ + public void setModules(List modules) { + _modules = modules; + } + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri) { + return ModuleUtils.getModule(_modules,uri); + } + + /** + * Returns the categories + *

+ * @return Returns the categories. + * @since Atom 1.0 + */ + public List getCategories() { + return (_categories==null) ? (_categories=new ArrayList()) : _categories; + } + + /** + * Set the categories + *

+ * @param categories The categories to set. + * @since Atom 1.0 + */ + public void setCategories(List categories) { + _categories = categories; + } + + /** + * Returns the icon + *

+ * @return Returns the icon. + * @since Atom 1.0 + */ + public String getIcon() { + return _icon; + } + + /** + * Set the icon + *

+ * @param icon The icon to set. + * @since Atom 1.0 + */ + public void setIcon(String icon) { + _icon = icon; + } + + /** + * Returns the logo + *

+ * @return Returns the logo. + * @since Atom 1.0 + */ + public String getLogo() { + return _logo; + } + + /** + * Set the logo + *

+ * @param logo The logo to set. + * @since Atom 1.0 + */ + public void setLogo(String logo) { + _logo = logo; + } + + /** + * Returns the rights + *

+ * @return Returns the rights. + * @since Atom 1.0 + */ + public String getRights() { + return _rights; + } + + /** + * Set the rights + *

+ * @param rights The rights to set. + * @since Atom 1.0 + */ + public void setRights(String rights) { + _rights = rights; + } + + /** + * Returns the subtitle + *

+ * @return Returns the subtitle. + * @since Atom 1.0 + */ + public Content getSubtitle() { + return _subtitle; + } + + /** + * Set the subtitle + *

+ * @param subtitle The subtitle to set. + * @since Atom 1.0 + */ + public void setSubtitle(Content subtitle) { + _subtitle = subtitle; + } + + /** + * Returns the updated + *

+ * @return Returns the updated. + * @since Atom 1.0 + */ + public Date getUpdated() { + return _updated; + } + + /** + * Set the updated + *

+ * @param updated The updated to set. + * @since Atom 1.0 + */ + public void setUpdated(Date updated) { + _updated = updated; + } + + /** + * Returns the xmlBase + *

+ * @return Returns the xmlBase. + * @since Atom 1.0 + */ + public String getXmlBase() { + return _xmlBase; + } + + /** + * Set the xmlBase + *

+ * @param xmlBase The xmlBase to set. + * @since Atom 1.0 + */ + public void setXmlBase(String xmlBase) { + _xmlBase = xmlBase; + } +} + diff --git a/src/main/java/com/sun/syndication/feed/atom/Generator.java b/src/main/java/com/sun/syndication/feed/atom/Generator.java new file mode 100644 index 0000000..4e9e307 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/atom/Generator.java @@ -0,0 +1,149 @@ +/* + * 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 com.sun.syndication.feed.atom; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for the generator element of Atom feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class Generator implements Cloneable,Serializable { + private ObjectBean _objBean; + private String _url; + private String _version; + private String _value; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Generator() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the generator URL. + *

+ * @return the generator URL, null if none. + * + */ + public String getUrl() { + return _url; + } + + /** + * Sets the generator URL. + *

+ * @param url the generator URL, null if none. + * + */ + public void setUrl(String url) { + _url = url; + } + + /** + * Returns the generator version. + *

+ * @return the generator version, null if none. + * + */ + public String getVersion() { + return _version; + } + + /** + * Sets the generator version. + *

+ * @param version the generator version, null if none. + * + */ + public void setVersion(String version) { + _version = version; + } + + /** + * Returns the generator value. + *

+ * @return the generator value, null if none. + * + */ + public String getValue() { + return _value; + } + + /** + * Sets the generator value. + *

+ * @param value the generator value, null if none. + * + */ + public void setValue(String value) { + _value = value; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/atom/Link.java b/src/main/java/com/sun/syndication/feed/atom/Link.java new file mode 100644 index 0000000..d18c4cd --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/atom/Link.java @@ -0,0 +1,220 @@ +/* + * 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 com.sun.syndication.feed.atom; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for link elements of Atom feeds. + *

+ * @author Alejandro Abdelnur + * @author Dave Johnson (updated for Atom 1.0) + */ +public class Link implements Cloneable,Serializable { + + private ObjectBean _objBean; + + private String _href; + private String _hrefResolved; + private String _rel = "alternate"; + private String _type; + private String _hreflang; + private String _title; + private long _length; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Link() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the link rel. + *

+ * @return the link rel, null if none. + * + */ + public String getRel() { + return _rel; + } + + /** + * Sets the link rel. + *

+ * @param rel the link rel,, null if none. + * + */ + public void setRel(String rel) { + //TODO add check, ask P@ about the check + _rel = rel; + } + + /** + * Returns the link type. + *

+ * @return the link type, null if none. + * + */ + public String getType() { + return _type; + } + + /** + * Sets the link type. + *

+ * @param type the link type, null if none. + * + */ + public void setType(String type) { + _type = type; + } + + /** + * Returns the link href. + *

+ * @return the link href, null if none. + * + */ + public String getHref() { + return _href; + } + + /** + * Sets the link href. + *

+ * @param href the link href, null if none. + * + */ + public void setHref(String href) { + _href = href; + } + + public void setHrefResolved(String hrefResolved) { + _hrefResolved = hrefResolved; + } + + public String getHrefResolved() { + return _hrefResolved != null ? _hrefResolved : _href; + } + + /** + * Returns the link title. + *

+ * @return the link title, null if none. + * + */ + public String getTitle() { + return _title; + } + + /** + * Sets the link title. + *

+ * @param title the link title, null if none. + * + */ + public void setTitle(String title) { + _title = title; + } + + /** + * Returns the hreflang + *

+ * @return Returns the hreflang. + * @since Atom 1.0 + */ + public String getHreflang() { + return _hreflang; + } + + /** + * Set the hreflang + *

+ * @param hreflang The hreflang to set. + * @since Atom 1.0 + */ + public void setHreflang(String hreflang) { + _hreflang = hreflang; + } + + /** + * Returns the length + *

+ * @return Returns the length. + */ + public long getLength() { + return _length; + } + + /** + * Set the length + *

+ * @param length The length to set. + */ + public void setLength(long length) { + _length = length; + } +} diff --git a/src/main/java/com/sun/syndication/feed/atom/Person.java b/src/main/java/com/sun/syndication/feed/atom/Person.java new file mode 100644 index 0000000..73b0d12 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/atom/Person.java @@ -0,0 +1,216 @@ +/* + * 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 com.sun.syndication.feed.atom; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.module.Extendable; +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.impl.ModuleUtils; + +import java.io.Serializable; +import java.util.List; +import java.util.ArrayList; + +/** + * Bean for person elements of Atom feeds. + *

+ * @author Alejandro Abdelnur + * @author Dave Johnson (updated for Atom 1.0) + */ +public class Person implements Cloneable,Serializable, Extendable +{ + + private ObjectBean _objBean; + + private String _name; + private String _uri; // since Atom 1.0 (was called url) + private String _uriResolved; + private String _email; + private List _modules; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Person() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the person name. + *

+ * @return the person name, null if none. + * + */ + public String getName() { + return _name; + } + + /** + * Sets the personname. + *

+ * @param name the person name, null if none. + * + */ + public void setName(String name) { + _name = name; + } + + /** + * Returns the person URL (same as {@link #getUri()}) + *

+ * @return the person URL, null if none. + */ + public String getUrl() { + return _uri; + } + + /** + * Sets the person URL (same as {@link #setUri(java.lang.String)}) + *

+ * @param url the person URL, null if none. + */ + public void setUrl(String url) { + _uri = url; + } + + public void setUriResolved(String uriResolved) { + _uriResolved = uriResolved; + } + + public String getUriResolved(String resolveURI) { + return _uriResolved != null ? _uriResolved : _uri; + } + + /** + * Returns the person email. + *

+ * @return the person email, null if none. + * + */ + public String getEmail() { + return _email; + } + + /** + * Sets the person email. + *

+ * @param email the person email, null if none. + * + */ + public void setEmail(String email) { + _email = email; + } + + /** + * Returns the uri + *

+ * @return Returns the uri. + * @since Atom 1.0 + */ + public String getUri() { + return _uri; + } + + /** + * Set the uri + *

+ * @param uri The uri to set. + * @since Atom 1.0 + */ + public void setUri(String uri) { + _uri = uri; + } + + /** + * Returns the entry modules. + *

+ * @return a list of ModuleImpl elements with the entry modules, + * an emtpy list if none. + * + */ + public List getModules() { + return (_modules==null) ? (_modules=new ArrayList()) : _modules; + } + + /** + * Sets the entry modules. + *

+ * @param modules the list of ModuleImpl elements with the entry modules to set, + * an empty list or null if none. + * + */ + public void setModules(List modules) { + _modules = modules; + } + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri) { + return ModuleUtils.getModule(_modules,uri); + } + +} diff --git a/src/main/java/com/sun/syndication/feed/impl/BeanIntrospector.java b/src/main/java/com/sun/syndication/feed/impl/BeanIntrospector.java new file mode 100644 index 0000000..dded484 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/impl/BeanIntrospector.java @@ -0,0 +1,123 @@ +/* + * 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 com.sun.syndication.feed.impl; + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; + +/** + * Obtains all property descriptors from a bean (interface or implementation). + *

+ * The java.beans.Introspector does not process the interfaces hierarchy chain, this one does. + *

+ * @author Alejandro Abdelnur + * + */ +public class BeanIntrospector { + + private static final Map _introspected = new HashMap(); + + public static synchronized PropertyDescriptor[] getPropertyDescriptors(Class klass) throws IntrospectionException { + PropertyDescriptor[] descriptors = (PropertyDescriptor[]) _introspected.get(klass); + if (descriptors==null) { + descriptors = getPDs(klass); + _introspected.put(klass,descriptors); + } + return descriptors; + } + + private static PropertyDescriptor[] getPDs(Class klass) throws IntrospectionException { + Method[] methods = klass.getMethods(); + Map getters = getPDs(methods,false); + Map setters = getPDs(methods,true); + List pds = merge(getters,setters); + PropertyDescriptor[] array = new PropertyDescriptor[pds.size()]; + pds.toArray(array); + return array; + } + + private static final String SETTER = "set"; + private static final String GETTER = "get"; + private static final String BOOLEAN_GETTER = "is"; + + private static Map getPDs(Method[] methods,boolean setters) throws IntrospectionException { + Map pds = new HashMap(); + for (int i=0;iBean clonning support. + *

+ * It works on all read/write properties, recursively. It support all primitive types, Strings, Collections, + * Cloneable objects and multi-dimensional arrays of any of them. + *

+ * @author Alejandro Abdelnur + * + */ +public class CloneableBean implements Serializable, Cloneable { + + private static final Class[] NO_PARAMS_DEF = new Class[0]; + private static final Object[] NO_PARAMS = new Object[0]; + + private Object _obj; + private Set _ignoreProperties; + + /** + * Default constructor. + *

+ * To be used by classes extending CloneableBean only. + *

+ * + */ + protected CloneableBean() { + _obj = this; + } + + /** + * Creates a CloneableBean to be used in a delegation pattern. + *

+ * For example: + *

+ * + * public class Foo implements Cloneable { + * private CloneableBean _cloneableBean; + * + * public Foo() { + * _cloneableBean = new CloneableBean(this); + * } + * + * public Object clone() throws CloneNotSupportedException { + * return _cloneableBean.beanClone(); + * } + * + * } + * + *

+ * @param obj object bean to clone. + * + */ + public CloneableBean(Object obj) { + this(obj,null); + } + + /** + * Creates a CloneableBean to be used in a delegation pattern. + *

+ * The property names in the ignoreProperties Set will not be copied into + * the cloned instance. This is useful for cases where the Bean has convenience + * properties (properties that are actually references to other properties or + * properties of properties). For example SyndFeed and SyndEntry beans have + * convenience properties, publishedDate, author, copyright and categories all + * of them mapped to properties in the DC Module. + *

+ * @param obj object bean to clone. + * @param ignoreProperties properties to ignore when cloning. + * + */ + public CloneableBean(Object obj,Set ignoreProperties) { + _obj = obj; + _ignoreProperties = (ignoreProperties!=null) ? ignoreProperties : Collections.EMPTY_SET; + } + + /** + * Makes a deep bean clone of the object. + *

+ * To be used by classes extending CloneableBean. Although it works also for classes using + * CloneableBean in a delegation pattern, for correctness those classes should use the + * @see #beanClone() beanClone method. + *

+ * @return a clone of the object bean. + * @throws CloneNotSupportedException thrown if the object bean could not be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return beanClone(); + } + + /** + * Makes a deep bean clone of the object passed in the constructor. + *

+ * To be used by classes using CloneableBean in a delegation pattern, + * @see #CloneableBean(Object) constructor. + * + * @return a clone of the object bean. + * @throws CloneNotSupportedException thrown if the object bean could not be cloned. + * + */ + public Object beanClone() throws CloneNotSupportedException { + Object clonedBean; + try { + clonedBean = _obj.getClass().newInstance(); + PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(_obj.getClass()); + if (pds!=null) { + for (int i=0;iBean equals() and hashCode() functionality for Java Beans. + *

+ * It works on all read/write properties, recursively. It support all primitive types, Strings, Collections, + * bean-like objects and multi-dimensional arrays of any of them. + *

+ * The hashcode is calculated by getting the hashcode of the Bean String representation. + *

+ * @author Alejandro Abdelnur + * + */ +public class EqualsBean implements Serializable { + + private static final Object[] NO_PARAMS = new Object[0]; + + private Class _beanClass; + private Object _obj; + + /** + * Default constructor. + *

+ * To be used by classes extending EqualsBean only. + *

+ * @param beanClass the class/interface to be used for property scanning. + * + */ + protected EqualsBean(Class beanClass) { + _beanClass = beanClass; + _obj = this; + } + + /** + * Creates a EqualsBean to be used in a delegation pattern. + *

+ * For example: + *

+ * + * public class Foo implements FooI { + * private EqualsBean _equalsBean; + * + * public Foo() { + * _equalsBean = new EqualsBean(FooI.class); + * } + * + * public boolean equals(Object obj) { + * return _equalsBean.beanEquals(obj); + * } + * + * public int hashCode() { + * return _equalsBean.beanHashCode(); + * } + * + * } + * + *

+ * @param beanClass the class/interface to be used for property scanning. + * @param obj object bean to test equality. + * + */ + public EqualsBean(Class beanClass,Object obj) { + if (!beanClass.isInstance(obj)) { + throw new IllegalArgumentException(obj.getClass()+" is not instance of "+beanClass); + } + _beanClass = beanClass; + _obj = obj; + } + + /** + * Indicates whether some other object is "equal to" this object as defined by the Object equals() method. + *

+ * To be used by classes extending EqualsBean. Although it works also for classes using + * EqualsBean in a delegation pattern, for correctness those classes should use the + * @see #beanEquals(Object) beanEquals method. + *

+ * @param obj he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object obj) { + return beanEquals(obj); + } + + /** + * Indicates whether some other object is "equal to" the object passed in the constructor, + * as defined by the Object equals() method. + *

+ * To be used by classes using EqualsBean in a delegation pattern, + * @see #EqualsBean(Class,Object) constructor. + *

+ * @param obj he reference object with which to compare. + * @return true if the object passed in the constructor is equal to the 'obj' object. + * + */ + public boolean beanEquals(Object obj) { + Object bean1 = _obj; + Object bean2 = obj; + boolean eq; + if (bean2==null) { + eq = false; + } + else + if (bean1==null && bean2==null) { + eq = true; + } + else + if (bean1==null || bean2==null) { + eq = false; + } + else { + if (!_beanClass.isInstance(bean2)) { + eq = false; + } + else { + eq = true; + try { + PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(_beanClass); + if (pds!=null) { + for (int i = 0; eq && i + * It follows the contract defined by the Object hashCode() method. + *

+ * The hashcode is calculated by getting the hashcode of the Bean String representation. + *

+ * To be used by classes extending EqualsBean. Although it works also for classes using + * EqualsBean in a delegation pattern, for correctness those classes should use the + * @see #beanHashCode() beanHashCode method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return beanHashCode(); + } + + /** + * Returns the hashcode for the object passed in the constructor. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * The hashcode is calculated by getting the hashcode of the Bean String representation. + *

+ * To be used by classes using EqualsBean in a delegation pattern, + * @see #EqualsBean(Class,Object) constructor. + *

+ * @return the hashcode of the bean object. + * + */ + public int beanHashCode() { + return _obj.toString().hashCode(); + } + + + private boolean doEquals(Object obj1, Object obj2) { + boolean eq = obj1==obj2; + if (!eq && obj1!=null && obj2!=null) { + Class classObj1 = obj1.getClass(); + Class classObj2 = obj2.getClass(); + if (classObj1.isArray() && classObj2.isArray()) { + eq = equalsArray(obj1, obj2); + } + else { + eq = obj1.equals(obj2); + } + } + return eq; + } + + private boolean equalsArray(Object array1, Object array2) { + boolean eq; + int length1 = Array.getLength(array1); + int length2 = Array.getLength(array2); + if (length1==length2) { + eq = true; + for (int i = 0; eq && i + * It works on all read/write properties, recursively. + *

+ * It uses the CloneableBean, EqualsBean and ToStringBean classes in a delegation pattern. + *

+ *

ObjectBean programming conventions

+ *

+ * All ObjectBean subclasses having properties that return collections they should never + * return null if the property has been set to null or if a collection has not been set. + * They should create and return an empty collection, this empty collection instance should + * also be set to the corresponding property. + *

+ * All ObjectBean subclasses properties should be live references. + *

+ * @author Alejandro Abdelnur + * + */ +public class ObjectBean implements Serializable, Cloneable { + private EqualsBean _equalsBean; + private ToStringBean _toStringBean; + private CloneableBean _cloneableBean; + + /** + * Constructor. + *

+ * @param beanClass the class/interface to be used for property scanning. + * + */ + public ObjectBean(Class beanClass,Object obj) { + this(beanClass,obj,null); + } + + /** + * Constructor. + *

+ * The property names in the ignoreProperties Set will not be copied into + * the cloned instance. This is useful for cases where the Bean has convenience + * properties (properties that are actually references to other properties or + * properties of properties). For example SyndFeed and SyndEntry beans have + * convenience properties, publishedDate, author, copyright and categories all + * of them mapped to properties in the DC Module. + *

+ * @param beanClass the class/interface to be used for property scanning. + * @param ignoreProperties properties to ignore when cloning. + * + */ + public ObjectBean(Class beanClass,Object obj,Set ignoreProperties) { + _equalsBean = new EqualsBean(beanClass,obj); + _toStringBean = new ToStringBean(beanClass,obj); + _cloneableBean = new CloneableBean(obj,ignoreProperties); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _cloneableBean.beanClone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _equalsBean.beanEquals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _equalsBean.beanHashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _toStringBean.toString(); + } + +} + diff --git a/src/main/java/com/sun/syndication/feed/impl/ToStringBean.java b/src/main/java/com/sun/syndication/feed/impl/ToStringBean.java new file mode 100644 index 0000000..50fdc6d --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/impl/ToStringBean.java @@ -0,0 +1,240 @@ +/* + * 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 com.sun.syndication.feed.impl; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Stack; +import java.io.Serializable; + +/** + * Provides deep Bean toString support. + *

+ * It works on all read/write properties, recursively. It support all primitive types, Strings, Collections, + * ToString objects and multi-dimensional arrays of any of them. + *

+ * @author Alejandro Abdelnur + * + */ +public class ToStringBean implements Serializable { + private static final ThreadLocal PREFIX_TL = new ThreadLocal() { + public Object get() { + Object o = super.get(); + if (o==null) { + o = new Stack(); + set(o); + } + return o; + } + }; + + private static final Object[] NO_PARAMS = new Object[0]; + + private Class _beanClass; + private Object _obj; + + /** + * Default constructor. + *

+ * To be used by classes extending ToStringBean only. + *

+ * @param beanClass indicates the class to scan for properties, normally an interface class. + * + */ + protected ToStringBean(Class beanClass) { + _beanClass = beanClass; + _obj = this; + } + + /** + * Creates a ToStringBean to be used in a delegation pattern. + *

+ * For example: + *

+ * + * public class Foo implements ToString { + * + * public String toString(String prefix) { + * ToStringBean tsb = new ToStringBean(this); + * return tsb.toString(prefix); + * } + * + * public String toString() { + * return toString("Foo"); + * } + * + * } + * + *

+ * @param beanClass indicates the class to scan for properties, normally an interface class. + * @param obj object bean to create String representation. + * + */ + public ToStringBean(Class beanClass,Object obj) { + _beanClass = beanClass; + _obj = obj; + } + + /** + * Returns the String representation of the bean given in the constructor. + *

+ * It uses the Class name as the prefix. + *

+ * @return bean object String representation. + * + */ + public String toString() { + Stack stack = (Stack) PREFIX_TL.get(); + String[] tsInfo = (String[]) ((stack.isEmpty()) ? null : stack.peek()); + String prefix; + if (tsInfo==null) { + String className = _obj.getClass().getName(); + prefix = className.substring(className.lastIndexOf(".")+1); + } + else { + prefix = tsInfo[0]; + tsInfo[1] = prefix; + } + return toString(prefix); + } + + /** + * Returns the String representation of the bean given in the constructor. + *

+ * @param prefix to use for bean properties. + * @return bean object String representation. + * + */ + private String toString(String prefix) { + StringBuffer sb = new StringBuffer(128); + try { + PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(_beanClass); + if (pds!=null) { + for (int i=0;i + * @see Dublin Core module. + * @author Alejandro Abdelnur + * + */ +public interface DCModule extends Module,CopyFrom { + + /** + * URI of the Dublin Core Module (http://purl.org/dc/elements/1.1/). + * + */ + String URI = "http://purl.org/dc/elements/1.1/"; + + /** + * Returns the DublinCore module titles. + *

+ * @return a list of Strings representing the DublinCore module title, + * an empty list if none. + * + */ + List getTitles(); + + /** + * Sets the DublinCore module titles. + *

+ * @param titles the list of String representing the DublinCore module titles + * to set, an empty list or null if none. + * + */ + void setTitles(List titles); + + /** + * Gets the DublinCore module title. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module title, null if none. + */ + String getTitle(); + + /** + * Sets the DublinCore module title. Convenience method that can be used + * when there is only one title to set. + *

+ * @param title the DublinCore module title to set, null if none. + * + */ + void setTitle(String title); + + /** + * Returns the DublinCore module creator. + *

+ * @return a list of Strings representing the DublinCore module creator, + * an empty list if none. + * + */ + List getCreators(); + + /** + * Sets the DublinCore module creators. + *

+ * @param creators the list of String representing the DublinCore module + * creators to set, an empty list or null if none. + * + */ + void setCreators(List creators); + + /** + * Gets the DublinCore module creator. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module creator, null if none. + */ + String getCreator(); + + /** + * Sets the DublinCore module creator. Convenience method that can be used + * when there is only one creator to set. + *

+ * @param creator the DublinCore module creator to set, null if none. + * + */ + void setCreator(String creator); + + /** + * Returns the DublinCore module subjects. + *

+ * @return a list of DCSubject elements with the DublinCore module subjects, + * an empty list if none. + * + */ + List getSubjects(); + + /** + * Sets the DublinCore module subjects. + *

+ * @param subjects the list of DCSubject elements with the DublinCore + * module subjects to set, an empty list or null if none. + * + */ + void setSubjects(List subjects); + + /** + * Gets the DublinCore module subject. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module subject, null if none. + */ + DCSubject getSubject(); + + /** + * Sets the DCSubject element. Convenience method that can be used when + * there is only one subject to set. + *

+ * @param subject the DublinCore module subject to set, null if none. + * + */ + void setSubject(DCSubject subject); + + /** + * Returns the DublinCore module description. + *

+ * @return a list of Strings representing the DublinCore module description, + * an empty list if none. + * + */ + List getDescriptions(); + + /** + * Sets the DublinCore module descriptions. + *

+ * @param descriptions the list of String representing the DublinCore + * module descriptions to set, an empty list or null if none. + * + */ + void setDescriptions(List descriptions); + + /** + * Gets the DublinCore module description. Convenience method that can be + * used to obtain the first item, null if none. + *

+ * @return the first DublinCore module description, null if none. + */ + String getDescription(); + + /** + * Sets the DublinCore module description. Convenience method that can be + * used when there is only one description to set. + *

+ * @param description the DublinCore module description to set, null if none. + * + */ + void setDescription(String description); + + /** + * Returns the DublinCore module publisher. + *

+ * @return a list of Strings representing the DublinCore module publisher, + * an empty list if none. + * + */ + List getPublishers(); + + /** + * Sets the DublinCore module publishers. + *

+ * @param publishers the list of String representing the DublinCore module + * publishers to set, an empty list or null if none. + * + */ + void setPublishers(List publishers); + + /** + * Gets the DublinCore module publisher. Convenience method that can be + * used to obtain the first item, null if none. + *

+ * @return the first DublinCore module publisher, null if none. + */ + String getPublisher(); + + /** + * Sets the DublinCore module publisher. Convenience method that can be used when + * there is only one publisher to set. + *

+ * @param publisher the DublinCore module publisher to set, null if none. + * + */ + void setPublisher(String publisher); + + /** + * Returns the DublinCore module contributor. + *

+ * @return a list of Strings representing the DublinCore module contributor, + * an empty list if none. + * + */ + List getContributors(); + + /** + * Sets the DublinCore module contributors. + *

+ * @param contributors the list of String representing the DublinCore module + * contributors to set, an empty list or null if none. + * + */ + void setContributors(List contributors); + + /** + * Gets the DublinCore module contributor. Convenience method that can be + * used to obtain the first item, null if none. + *

+ * @return the first DublinCore module contributor, null if none. + */ + String getContributor(); + + /** + * Sets the DublinCore module contributor. Convenience method that can be + * used when there is only one contributor to set. + *

+ * @param contributor the DublinCore module contributor to set, null if none. + * + */ + void setContributor(String contributor); + + /** + * Returns the DublinCore module date. + *

+ * @return a list of Strings representing the DublinCore module date, + * an empty list if none. + * + */ + List getDates(); + + /** + * Sets the DublinCore module dates. + *

+ * @param dates the list of Date representing the DublinCore module dates to set, + * an empty list or null if none. + * + */ + void setDates(List dates); + + /** + * Gets the DublinCore module date. Convenience method that can be used to + * obtain the first item, null if none. + *

+ * @return the first DublinCore module date, null if none. + */ + Date getDate(); + + /** + * Sets the DublinCore module date. Convenience method that can be used + * when there is only one date to set. + *

+ * @param date the DublinCore module date to set, null if none. + * + */ + void setDate(Date date); + + /** + * Returns the DublinCore module type. + *

+ * @return a list of Strings representing the DublinCore module type, + * an empty list if none. + * + */ + List getTypes(); + + /** + * Sets the DublinCore module types. + *

+ * @param types the list of String representing the DublinCore module types to set, + * an empty list or null if none. + * + */ + void setTypes(List types); + + /** + * Gets the DublinCore module type. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module type, null if none. + */ + String getType(); + + /** + * Sets the DublinCore module type. Convenience method that can be used + * when there is only one type to set. + *

+ * @param type the DublinCore module type to set, null if none. + * + */ + void setType(String type); + + /** + * Returns the DublinCore module format. + *

+ * @return a list of Strings representing the DublinCore module format, + * an empty list if none. + * + */ + List getFormats(); + + /** + * Sets the DublinCore module formats. + *

+ * @param formats the list of String representing the DublinCore module + * formats to set, an empty list or null if none. + * + */ + void setFormats(List formats); + + /** + * Gets the DublinCore module format. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module format, null if none. + */ + String getFormat(); + + /** + * Sets the DublinCore module format. Convenience method that can be used + * when there is only one format to set. + *

+ * @param format the DublinCore module format to set, null if none. + * + */ + void setFormat(String format); + + /** + * Returns the DublinCore module identifier. + *

+ * @return a list of Strings representing the DublinCore module identifier, + * an empty list if none. + * + */ + List getIdentifiers(); + + /** + * Sets the DublinCore module identifiers. + *

+ * @param identifiers the list of String representing the DublinCore module + * identifiers to set, an empty list or null if none. + * + */ + void setIdentifiers(List identifiers); + + /** + * Gets the DublinCore module identifier. Convenience method that can be + * used to obtain the first item, null if none. + *

+ * @return the first DublinCore module identifier, null if none. + */ + String getIdentifier(); + + /** + * Sets the DublinCore module identifier. Convenience method that can be + * used when there is only one identifier to set. + *

+ * @param identifier the DublinCore module identifier to set, null if none. + * + */ + void setIdentifier(String identifier); + + /** + * Returns the DublinCore module source. + *

+ * @return a list of Strings representing the DublinCore module source, + * an empty list if none. + * + */ + List getSources(); + + /** + * Sets the DublinCore module sources. + *

+ * @param sources the list of String representing the DublinCore module + * sources to set, an empty list or null if none. + * + */ + void setSources(List sources); + + /** + * Gets the DublinCore module subject. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module creator, null if none. + */ + String getSource(); + + /** + * Sets the DublinCore module source. Convenience method that can be used + * when there is only one source to set. + *

+ * @param source the DublinCore module source to set, null if none. + * + */ + void setSource(String source); + + /** + * Returns the DublinCore module language. + *

+ * @return a list of Strings representing the DublinCore module language, + * an empty list if none. + * + */ + List getLanguages(); + + /** + * Sets the DublinCore module languages. + *

+ * @param languages the list of String representing the DublinCore module + * languages to set, an empty list or null if none. + * + */ + void setLanguages(List languages); + + /** + * Gets the DublinCore module language. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module language, null if none. + */ + String getLanguage(); + + /** + * Sets the DublinCore module language. Convenience method that can be used + * when there is only one language to set. + *

+ * @param language the DublinCore module language to set, null if none. + * + */ + void setLanguage(String language); + + /** + * Returns the DublinCore module relation. + *

+ * @return a list of Strings representing the DublinCore module relation, + * an empty list if none. + * + */ + List getRelations(); + + /** + * Sets the DublinCore module relations. + *

+ * @param relations the list of String representing the DublinCore module + * relations to set, an empty list or null if none. + * + */ + void setRelations(List relations); + + /** + * Gets the DublinCore module relation. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module relation, null if none. + */ + String getRelation(); + + /** + * Sets the DublinCore module relation. Convenience method that can be used + * when there is only one relation to set. + *

+ * @param relation the DublinCore module relation to set, null if none. + * + */ + void setRelation(String relation); + + /** + * Returns the DublinCore module coverage. + *

+ * @return a list of Strings representing the DublinCore module coverage, + * an empty list if none. + * + */ + List getCoverages(); + + /** + * Sets the DublinCore module coverages. + *

+ * @param coverages the list of String representing the DublinCore module + * coverages to set, an empty list or null if none. + * + */ + void setCoverages(List coverages); + + /** + * Gets the DublinCore module coverage. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module coverage, null if none. + */ + String getCoverage(); + + /** + * Sets the DublinCore module coverage. Convenience method that can be used + * when there is only one coverage to set. + *

+ * @param coverage the DublinCore module coverage to set, null if none. + * + */ + void setCoverage(String coverage); + + /** + * Returns the DublinCore module rights. + *

+ * @return a list of Strings representing the DublinCore module rights, + * an empty list if none. + * + */ + List getRightsList(); + + /** + * Sets the DublinCore module rightss. + *

+ * @param rights the list of String representing the DublinCore module + * rights to set, an empty list or null if none. + * + */ + void setRightsList(List rights); + + /** + * Gets the DublinCore module right. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module right, null if none. + */ + String getRights(); + + /** + * Sets the DublinCore module rights. Convenience method that can be used + * when there is only one rights to set. + *

+ * @param rights the DublinCore module rights to set, null if none. + * + */ + void setRights(String rights); +} diff --git a/src/main/java/com/sun/syndication/feed/module/DCModuleImpl.java b/src/main/java/com/sun/syndication/feed/module/DCModuleImpl.java new file mode 100644 index 0000000..c3ac5b9 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/module/DCModuleImpl.java @@ -0,0 +1,840 @@ +/* + * 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 com.sun.syndication.feed.module; + +import com.sun.syndication.feed.impl.CopyFromHelper; +import com.sun.syndication.feed.impl.ObjectBean; + +import java.util.*; + + +/** + * Dublin Core ModuleImpl, default implementation. + *

+ * @see Dublin Core module. + * @author Alejandro Abdelnur + * + */ +public class DCModuleImpl extends ModuleImpl implements DCModule { + private ObjectBean _objBean; + private List _title; + private List _creator; + private List _subject; + private List _description; + private List _publisher; + private List _contributors; + private List _date; + private List _type; + private List _format; + private List _identifier; + private List _source; + private List _language; + private List _relation; + private List _coverage; + private List _rights; + + /** + * Properties to be ignored when cloning. + */ + private static final Set IGNORE_PROPERTIES = new HashSet(); + + /** + * Unmodifiable Set containing the convenience properties of this class. + *

+ * Convenience properties are mapped to Modules, for cloning the convenience + * properties can be ignored as the will be copied as part of the module + * cloning. + */ + public static final Set CONVENIENCE_PROPERTIES = Collections.unmodifiableSet(IGNORE_PROPERTIES); + + static { + IGNORE_PROPERTIES.add("title"); + IGNORE_PROPERTIES.add("creator"); + IGNORE_PROPERTIES.add("subject"); + IGNORE_PROPERTIES.add("description"); + IGNORE_PROPERTIES.add("publisher"); + IGNORE_PROPERTIES.add("contributor"); + IGNORE_PROPERTIES.add("date"); + IGNORE_PROPERTIES.add("type"); + IGNORE_PROPERTIES.add("format"); + IGNORE_PROPERTIES.add("identifier"); + IGNORE_PROPERTIES.add("source"); + IGNORE_PROPERTIES.add("language"); + IGNORE_PROPERTIES.add("relation"); + IGNORE_PROPERTIES.add("coverage"); + IGNORE_PROPERTIES.add("rights"); + } + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public DCModuleImpl() { + super(DCModule.class, URI); + _objBean = new ObjectBean(DCModule.class, this, CONVENIENCE_PROPERTIES); + } + + /** + * Returns the DublinCore module titles. + *

+ * @return a list of Strings representing the DublinCore module title, + * an empty list if none. + * + */ + public List getTitles() { + return (_title == null) ? (_title = new ArrayList()) : _title; + } + + /** + * Sets the DublinCore module titles. + *

+ * @param titles the list of String representing the DublinCore module + * titles to set, an empty list or null if none. + * + */ + public void setTitles(List titles) { + _title = titles; + } + + /** + * Gets the DublinCore module title. Convenience method that can be used to + * obtain the first item, null if none. + *

+ * @return the first DublinCore module title, null if none. + */ + public String getTitle() { + return ((_title != null) && (_title.size() > 0)) ? (String) _title.get(0) : null; + } + + /** + * Sets the DublinCore module title. Convenience method that can be used + * when there is only one title to set. + *

+ * @param title the DublinCore module title to set, null if none. + * + */ + public void setTitle(String title) { + _title = new ArrayList(); + _title.add(title); + } + + /** + * Returns the DublinCore module creator. + *

+ * @return a list of Strings representing the DublinCore module creator, + * an empty list if none. + * + */ + public List getCreators() { + return (_creator == null) ? (_creator = new ArrayList()) : _creator; + } + + /** + * Sets the DublinCore module creators. + *

+ * @param creators the list of String representing the DublinCore module + * creators to set, an empty list or null if none. + * + */ + public void setCreators(List creators) { + _creator = creators; + } + + /** + * Gets the DublinCore module title. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module title, null if none. + */ + public String getCreator() { + return ((_creator != null) && (_creator.size() > 0)) ? (String) _creator.get(0) : null; + } + + /** + * Sets the DublinCore module creator. Convenience method that can be used + * when there is only one creator to set. + *

+ * @param creator the DublinCore module creator to set, null if none. + * + */ + public void setCreator(String creator) { + _creator = new ArrayList(); + _creator.add(creator); + } + + /** + * Returns the DublinCore module subjects. + *

+ * @return a list of DCSubject elements with the DublinCore module subjects, + * an empty list if none. + * + */ + public List getSubjects() { + return (_subject == null) ? (_subject = new ArrayList()) : _subject; + } + + /** + * Sets the DublinCore module subjects. + *

+ * @param subjects the list of DCSubject elements with the DublinCore + * module subjects to set, an empty list or null if none. + * + */ + public void setSubjects(List subjects) { + _subject = subjects; + } + + /** + * Gets the DublinCore module subject. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module subject, null if none. + */ + public DCSubject getSubject() { + return ((_subject != null) && (_subject.size() > 0)) ? + (DCSubject) _subject.get(0) : null; + } + + /** + * Sets the DCSubject element. Convenience method that can be used when + * there is only one subject to set. + *

+ * @param subject the DublinCore module subject to set, null if none. + * + */ + public void setSubject(DCSubject subject) { + _subject = new ArrayList(); + _subject.add(subject); + } + + /** + * Returns the DublinCore module description. + *

+ * @return a list of Strings representing the DublinCore module + * description, an empty list if none. + * + */ + public List getDescriptions() { + return (_description == null) ? (_description = new ArrayList()) : _description; + } + + /** + * Sets the DublinCore module descriptions. + *

+ * @param descriptions the list of String representing the DublinCore + * module descriptions to set, an empty list or null if none. + * + */ + public void setDescriptions(List descriptions) { + _description = descriptions; + } + + /** + * Gets the DublinCore module description. Convenience method that can be + * used to obtain the first item, null if none. + *

+ * @return the first DublinCore module description, null if none. + */ + public String getDescription() { + return ((_description != null) && (_description.size() > 0)) ? + (String) _description.get(0) : null; + } + + /** + * Sets the DublinCore module description. Convenience method that can be + * used when there is only one description to set. + *

+ * @param description the DublinCore module description to set, null if none. + * + */ + public void setDescription(String description) { + _description = new ArrayList(); + _description.add(description); + } + + /** + * Returns the DublinCore module publisher. + *

+ * @return a list of Strings representing the DublinCore module publisher, + * an empty list if none. + * + */ + public List getPublishers() { + return (_publisher == null) ? (_publisher = new ArrayList()) : _publisher; + } + + /** + * Sets the DublinCore module publishers. + *

+ * @param publishers the list of String representing the DublinCore module + * publishers to set, an empty list or null if none. + * + */ + public void setPublishers(List publishers) { + _publisher = publishers; + } + + /** + * Gets the DublinCore module title. Convenience method that can be used to + * obtain the first item, null if none. + *

+ * @return the first DublinCore module title, null if none. + */ + public String getPublisher() { + return ((_publisher != null) && (_publisher.size() > 0)) ? + (String) _publisher.get(0) : null; + } + + /** + * Sets the DublinCore module publisher. Convenience method that can be + * used when there is only one publisher to set. + *

+ * @param publisher the DublinCore module publisher to set, null if none. + * + */ + public void setPublisher(String publisher) { + _publisher = new ArrayList(); + _publisher.add(publisher); + } + + /** + * Returns the DublinCore module contributor. + *

+ * @return a list of Strings representing the DublinCore module contributor, + * an empty list if none. + * + */ + public List getContributors() { + return (_contributors == null) ? (_contributors = new ArrayList()) : _contributors; + } + + /** + * Sets the DublinCore module contributors. + *

+ * @param contributors the list of String representing the DublinCore + * module contributors to set, an empty list or null if none. + * + */ + public void setContributors(List contributors) { + _contributors = contributors; + } + + /** + * Gets the DublinCore module contributor. Convenience method that can be + * used to obtain the first item, null if none. + *

+ * @return the first DublinCore module contributor, null if none. + */ + public String getContributor() { + return ((_contributors != null) && (_contributors.size() > 0)) ? + (String) _contributors.get(0) : null; + } + + /** + * Sets the DublinCore module contributor. Convenience method that can be + * used when there is only one contributor to set. + *

+ * @param contributor the DublinCore module contributor to set, null if none. + * + */ + public void setContributor(String contributor) { + _contributors = new ArrayList(); + _contributors.add(contributor); + } + + /** + * Returns the DublinCore module date. + *

+ * @return a list of Strings representing the DublinCore module date, + * an empty list if none. + * + */ + public List getDates() { + return (_date == null) ? (_date = new ArrayList()) : _date; + } + + /** + * Sets the DublinCore module dates. + *

+ * @param dates the list of Date representing the DublinCore module dates + * to set, an empty list or null if none. + * + */ + public void setDates(List dates) { + _date = dates; + } + + /** + * Gets the DublinCore module date. Convenience method that can be used to + * obtain the first item, null if none. + *

+ * @return the first DublinCore module date, null if none. + */ + public Date getDate() { + return ((_date != null) && (_date.size() > 0)) ? + (Date) _date.get(0) : null; + } + /** + * Sets the DublinCore module date. Convenience method that can be used + * when there is only one date to set. + *

+ * @param date the DublinCore module date to set, null if none. + * + */ + public void setDate(Date date) { + _date = new ArrayList(); + _date.add(date); + } + + /** + * Returns the DublinCore module type. + *

+ * @return a list of Strings representing the DublinCore module type, + * an empty list if none. + * + */ + public List getTypes() { + return (_type == null) ? (_type = new ArrayList()) : _type; + } + + /** + * Sets the DublinCore module types. + *

+ * @param types the list of String representing the DublinCore module types + * to set, an empty list or null if none. + * + */ + public void setTypes(List types) { + _type = types; + } + + /** + * Gets the DublinCore module type. Convenience method that can be used to + * obtain the first item, null if none. + *

+ * @return the first DublinCore module type, null if none. + */ + public String getType() { + return ((_type != null) && (_type.size() > 0)) ? + (String) _type.get(0) : null; + } + + /** + * Sets the DublinCore module type. Convenience method that can be used + * when there is only one type to set. + *

+ * @param type the DublinCore module type to set, null if none. + * + */ + public void setType(String type) { + _type = new ArrayList(); + _type.add(type); + } + + /** + * Returns the DublinCore module format. + *

+ * @return a list of Strings representing the DublinCore module format, + * an empty list if none. + * + */ + public List getFormats() { + return (_format == null) ? (_format = new ArrayList()) : _format; + } + + /** + * Sets the DublinCore module formats. + *

+ * @param formats the list of String representing the DublinCore module + * formats to set, an empty list or null if none. + * + */ + public void setFormats(List formats) { + _format = formats; + } + + /** + * Gets the DublinCore module format. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module format, null if none. + */ + public String getFormat() { + return ((_format != null) && (_format.size() > 0)) ? + (String) _format.get(0) : null; + } + + /** + * Sets the DublinCore module format. Convenience method that can be used + * when there is only one format to set. + *

+ * @param format the DublinCore module format to set, null if none. + * + */ + public void setFormat(String format) { + _format = new ArrayList(); + _format.add(format); + } + + /** + * Returns the DublinCore module identifier. + *

+ * @return a list of Strings representing the DublinCore module identifier, + * an empty list if none. + * + */ + public List getIdentifiers() { + return (_identifier == null) ? (_identifier = new ArrayList()) : _identifier; + } + + /** + * Sets the DublinCore module identifiers. + *

+ * @param identifiers the list of String representing the DublinCore module + * identifiers to set, an empty list or null if none. + * + */ + public void setIdentifiers(List identifiers) { + _identifier = identifiers; + } + + /** + * Gets the DublinCore module identifier. Convenience method that can be + * used to obtain the first item, null if none. + *

+ * @return the first DublinCore module identifier, null if none. + */ + public String getIdentifier() { + return ((_identifier != null) && (_identifier.size() > 0)) ? + (String) _identifier.get(0) : null; + } + + /** + * Sets the DublinCore module identifier. Convenience method that can be + * used when there is only one identifier to set. + *

+ * @param identifier the DublinCore module identifier to set, null if none. + * + */ + public void setIdentifier(String identifier) { + _identifier = new ArrayList(); + _identifier.add(identifier); + } + + /** + * Returns the DublinCore module source. + *

+ * @return a list of Strings representing the DublinCore module source, + * an empty list if none. + * + */ + public List getSources() { + return (_source == null) ? (_source = new ArrayList()) : _source; + } + + /** + * Sets the DublinCore module sources. + *

+ * @param sources the list of String representing the DublinCore module + * sources to set, an empty list or null if none. + * + */ + public void setSources(List sources) { + _source = sources; + } + + /** + * Gets the DublinCore module source. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module source, null if none. + */ + public String getSource() { + return ((_source != null) && (_source.size() > 0)) ? + (String) _source.get(0) : null; + } + + /** + * Sets the DublinCore module source. Convenience method that can be used + * when there is only one source to set. + *

+ * @param source the DublinCore module source to set, null if none. + * + */ + public void setSource(String source) { + _source = new ArrayList(); + _source.add(source); + } + + /** + * Returns the DublinCore module language. + *

+ * @return a list of Strings representing the DublinCore module language, + * an empty list if none. + * + */ + public List getLanguages() { + return (_language == null) ? (_language = new ArrayList()) : _language; + } + + /** + * Sets the DublinCore module languages. + *

+ * @param languages the list of String representing the DublinCore module + * languages to set, an empty list or null if none. + * + */ + public void setLanguages(List languages) { + _language = languages; + } + + /** + * Gets the DublinCore module language. Convenience method that can be + * used to obtain the first item, null if none. + *

+ * @return the first DublinCore module langauge, null if none. + */ + public String getLanguage() { + return ((_language != null) && (_language.size() > 0)) ? + (String) _language.get(0) : null; + } + /** + * Sets the DublinCore module language. Convenience method that can be used + * when there is only one language to set. + *

+ * @param language the DublinCore module language to set, null if none. + * + */ + public void setLanguage(String language) { + _language = new ArrayList(); + _language.add(language); + } + + /** + * Returns the DublinCore module relation. + *

+ * @return a list of Strings representing the DublinCore module relation, + * an empty list if none. + * + */ + public List getRelations() { + return (_relation == null) ? (_relation = new ArrayList()) : _relation; + } + + /** + * Sets the DublinCore module relations. + *

+ * @param relations the list of String representing the DublinCore module + * relations to set, an empty list or null if none. + * + */ + public void setRelations(List relations) { + _relation = relations; + } + + /** + * Gets the DublinCore module relation. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module relation, null if none. + */ + public String getRelation() { + return ((_relation != null) && (_relation.size() > 0)) ? + (String) _relation.get(0) : null; + } + + /** + * Sets the DublinCore module relation. Convenience method that can be used + * when there is only one relation to set. + *

+ * @param relation the DublinCore module relation to set, null if none. + * + */ + public void setRelation(String relation) { + _relation = new ArrayList(); + _relation.add(relation); + } + + /** + * Returns the DublinCore module coverage. + *

+ * @return a list of Strings representing the DublinCore module coverage, + * an empty list if none. + * + */ + public List getCoverages() { + return (_coverage == null) ? (_coverage = new ArrayList()) : _coverage; + } + + /** + * Sets the DublinCore module coverages. + *

+ * @param coverages the list of String representing the DublinCore module + * coverages to set, an empty list or null if none. + * + */ + public void setCoverages(List coverages) { + _coverage = coverages; + } + + /** + * Gets the DublinCore module coverage. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module coverage, null if none. + */ + public String getCoverage() { + return ((_coverage != null) && (_coverage.size() > 0)) ? + (String) _coverage.get(0) : null; + } + + /** + * Sets the DublinCore module coverage. Convenience method that can be used + * when there is only one coverage to set. + *

+ * @param coverage the DublinCore module coverage to set, null if none. + * + */ + public void setCoverage(String coverage) { + _coverage = new ArrayList(); + _coverage.add(coverage); + } + + /** + * Returns the DublinCore module rights. + *

+ * @return a list of Strings representing the DublinCore module rights, + * an empty list if none. + * + */ + public List getRightsList() { + return (_rights == null) ? (_rights = new ArrayList()) : _rights; + } + + /** + * Sets the DublinCore module rights. + *

+ * @param rights the list of String representing the DublinCore module + * rights to set, an empty list or null if none. + * + */ + public void setRightsList(List rights) { + _rights = rights; + } + + /** + * Gets the DublinCore module rights. Convenience method that can be used + * to obtain the first item, null if none. + *

+ * @return the first DublinCore module rights, null if none. + */ + public String getRights() { + return ((_rights != null) && (_rights.size() > 0)) ? + (String) _rights.get(0) : null; + } + + /** + * Sets the DublinCore module rights. Convenience method that can be used + * when there is only one rights to set. + *

+ * @param rights the DublinCore module rights to set, null if none. + * + */ + public void setRights(String rights) { + _rights = new ArrayList(); + _rights.add(rights); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public final Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public final boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public final int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public final String toString() { + return _objBean.toString(); + } + + public final Class getInterface() { + return DCModule.class; + } + + public final void copyFrom(Object obj) { + COPY_FROM_HELPER.copy(this,obj); + } + + private static final CopyFromHelper COPY_FROM_HELPER; + + static { + Map basePropInterfaceMap = new HashMap(); + basePropInterfaceMap.put("titles", String.class); + basePropInterfaceMap.put("creators", String.class); + basePropInterfaceMap.put("subjects", DCSubject.class); + basePropInterfaceMap.put("descriptions", String.class); + basePropInterfaceMap.put("publishers", String.class); + basePropInterfaceMap.put("contributors", String.class); + basePropInterfaceMap.put("dates", Date.class); + basePropInterfaceMap.put("types", String.class); + basePropInterfaceMap.put("formats", String.class); + basePropInterfaceMap.put("identifiers", String.class); + basePropInterfaceMap.put("sources", String.class); + basePropInterfaceMap.put("languages", String.class); + basePropInterfaceMap.put("relations", String.class); + basePropInterfaceMap.put("coverages", String.class); + basePropInterfaceMap.put("rightsList", String.class); + + Map basePropClassImplMap = new HashMap(); + basePropClassImplMap.put(DCSubject.class,DCSubjectImpl.class); + + COPY_FROM_HELPER = new CopyFromHelper(DCModule.class,basePropInterfaceMap,basePropClassImplMap); + } +} diff --git a/src/main/java/com/sun/syndication/feed/module/DCSubject.java b/src/main/java/com/sun/syndication/feed/module/DCSubject.java new file mode 100644 index 0000000..d4fb96e --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/module/DCSubject.java @@ -0,0 +1,70 @@ +/* + * 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 com.sun.syndication.feed.module; + +import com.sun.syndication.feed.CopyFrom; + +/** + * Subject of the Dublin Core ModuleImpl. + *

+ * @see Dublin Core module. + * @author Alejandro Abdelnur + * + */ +public interface DCSubject extends Cloneable,CopyFrom { + /** + * Returns the DublinCore subject taxonomy URI. + *

+ * @return the DublinCore subject taxonomy URI, null if none. + * + */ + String getTaxonomyUri(); + + /** + * Sets the DublinCore subject taxonomy URI. + *

+ * @param taxonomyUri the DublinCore subject taxonomy URI to set, null if none. + * + */ + void setTaxonomyUri(String taxonomyUri); + + /** + * Returns the DublinCore subject value. + *

+ * @return the DublinCore subject value, null if none. + * + */ + String getValue(); + + /** + * Sets the DublinCore subject value. + *

+ * @param value the DublinCore subject value to set, null if none. + * + */ + void setValue(String value); + + /** + * Creates a deep clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException; + +} diff --git a/src/main/java/com/sun/syndication/feed/module/DCSubjectImpl.java b/src/main/java/com/sun/syndication/feed/module/DCSubjectImpl.java new file mode 100644 index 0000000..e585966 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/module/DCSubjectImpl.java @@ -0,0 +1,152 @@ +/* + * 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 com.sun.syndication.feed.module; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.impl.CopyFromHelper; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.io.Serializable; + +/** + * Subject of the Dublin Core ModuleImpl, default implementation. + *

+ * @see Dublin Core module. + * @author Alejandro Abdelnur + * + */ +public class DCSubjectImpl implements Cloneable,Serializable, DCSubject { + private ObjectBean _objBean; + private String _taxonomyUri; + private String _value; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public DCSubjectImpl() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the DublinCore subject taxonomy URI. + *

+ * @return the DublinCore subject taxonomy URI, null if none. + * + */ + public String getTaxonomyUri() { + return _taxonomyUri; + } + + /** + * Sets the DublinCore subject taxonomy URI. + *

+ * @param taxonomyUri the DublinCore subject taxonomy URI to set, null if none. + * + */ + public void setTaxonomyUri(String taxonomyUri) { + _taxonomyUri = taxonomyUri; + } + + /** + * Returns the DublinCore subject value. + *

+ * @return the DublinCore subject value, null if none. + * + */ + public String getValue() { + return _value; + } + + /** + * Sets the DublinCore subject value. + *

+ * @param value the DublinCore subject value to set, null if none. + * + */ + public void setValue(String value) { + _value = value; + } + + public Class getInterface() { + return DCSubject.class; + } + + public void copyFrom(Object obj) { + COPY_FROM_HELPER.copy(this,obj); + } + + private static final CopyFromHelper COPY_FROM_HELPER; + + static { + Map basePropInterfaceMap = new HashMap(); + basePropInterfaceMap.put("taxonomyUri",String.class); + basePropInterfaceMap.put("value",String.class); + + Map basePropClassImplMap = Collections.EMPTY_MAP; + + COPY_FROM_HELPER = new CopyFromHelper(DCSubject.class,basePropInterfaceMap,basePropClassImplMap); + } + +} diff --git a/src/main/java/com/sun/syndication/feed/module/Extendable.java b/src/main/java/com/sun/syndication/feed/module/Extendable.java new file mode 100644 index 0000000..ce4ad47 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/module/Extendable.java @@ -0,0 +1,53 @@ +/* + * 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 com.sun.syndication.feed.module; + +import java.util.List; + +/** + * Objects that can have modules are Extendable. + * @author Dave Johnson + */ +public interface Extendable { + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri); + + /** + * Returns the entry modules. + *

+ * @return a list of ModuleImpl elements with the entry modules, + * an empty list if none. + * + */ + List getModules(); + + /** + * Sets the entry modules. + *

+ * @param modules the list of ModuleImpl elements with the entry modules to set, + * an empty list or null if none. + * + */ + void setModules(List modules); +} diff --git a/src/main/java/com/sun/syndication/feed/module/Module.java b/src/main/java/com/sun/syndication/feed/module/Module.java new file mode 100644 index 0000000..8ba7f94 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/module/Module.java @@ -0,0 +1,48 @@ +/* + * 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 com.sun.syndication.feed.module; + +import com.sun.syndication.feed.CopyFrom; +import java.io.Serializable; + +/** + * Base class for modules describing Metadata of feeds. Examples of such modules are + * the Dublin Core and Syndication modules. + *

+ * @author Alejandro Abdelnur + * + */ +public interface Module extends Cloneable,CopyFrom,Serializable{ + + /** + * Returns the URI of the module. + *

+ * @return URI of the module. + * + */ + String getUri(); + + /** + * Creates a deep clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException; + +} diff --git a/src/main/java/com/sun/syndication/feed/module/ModuleImpl.java b/src/main/java/com/sun/syndication/feed/module/ModuleImpl.java new file mode 100644 index 0000000..b98764b --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/module/ModuleImpl.java @@ -0,0 +1,99 @@ +/* + * 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 com.sun.syndication.feed.module; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Base class for modules describing Metadata of feeds, default implementations. + * Examples of such modules are the Dublin Core and Syndication modules. + *

+ * @author Alejandro Abdelnur + * + */ +public abstract class ModuleImpl implements Cloneable,Serializable,Module { + private ObjectBean _objBean; + private String _uri; + + /** + * Constructor. + *

+ * @param uri URI of the module. + * + */ + protected ModuleImpl(Class beanClass,String uri) { + _objBean = new ObjectBean(beanClass,this); + _uri = uri; + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the URI of the module. + *

+ * @return URI of the module. + * + */ + public String getUri() { + return _uri; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/module/SyModule.java b/src/main/java/com/sun/syndication/feed/module/SyModule.java new file mode 100644 index 0000000..bfc4322 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/module/SyModule.java @@ -0,0 +1,90 @@ +/* + * 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 com.sun.syndication.feed.module; + +import java.util.Date; + +/** + * Syndication ModuleImpl. + *

+ * @see Syndication module. + * @author Alejandro Abdelnur + * + */ +public interface SyModule extends Module { + + /** + * URI of the Syndication ModuleImpl (http://purl.org/rss/1.0/modules/syndication/). + * + */ + String URI = "http://purl.org/rss/1.0/modules/syndication/"; + + String HOURLY = new String("hourly"); + String DAILY = new String("daily"); + String WEEKLY = new String("weekly"); + String MONTHLY = new String("monthly"); + String YEARLY = new String("yearly"); + + /** + * Returns the Syndication module update period. + *

+ * @return the Syndication module update period, null if none. + * + */ + String getUpdatePeriod(); + + /** + * Sets the Syndication module update period. + *

+ * @param updatePeriod the Syndication module update period to set, null if none. + * + */ + void setUpdatePeriod(String updatePeriod); + + /** + * Returns the Syndication module update frequency. + *

+ * @return the Syndication module update frequency, null if none. + * + */ + int getUpdateFrequency(); + + /** + * Sets the Syndication module update frequency. + *

+ * @param updateFrequency the Syndication module update frequency to set, null if none. + * + */ + void setUpdateFrequency(int updateFrequency); + + /** + * Returns the Syndication module update base date. + *

+ * @return the Syndication module update base date, null if none. + * + */ + Date getUpdateBase(); + + /** + * Sets the Syndication module update base date. + *

+ * @param updateBase the Syndication module update base date to set, null if none. + * + */ + void setUpdateBase(Date updateBase); + +} diff --git a/src/main/java/com/sun/syndication/feed/module/SyModuleImpl.java b/src/main/java/com/sun/syndication/feed/module/SyModuleImpl.java new file mode 100644 index 0000000..c89285a --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/module/SyModuleImpl.java @@ -0,0 +1,139 @@ +/* + * 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 com.sun.syndication.feed.module; + +import com.sun.syndication.feed.impl.CopyFromHelper; + +import java.util.*; + +/** + * Syndication ModuleImpl, default implementation. + *

+ * @see Syndication module. + * @author Alejandro Abdelnur + * + */ +public class SyModuleImpl extends ModuleImpl implements SyModule { + private static final Set PERIODS = new HashSet(); + + static { + PERIODS.add(HOURLY ); + PERIODS.add(DAILY ); + PERIODS.add(WEEKLY ); + PERIODS.add(MONTHLY); + PERIODS.add(YEARLY ); + } + + + private String _updatePeriod; + private int _updateFrequency; + private Date _updateBase; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public SyModuleImpl() { + super(SyModule.class,URI); + } + + /** + * Returns the Syndication module update period. + *

+ * @return the Syndication module update period, null if none. + * + */ + public String getUpdatePeriod() { + return _updatePeriod; + } + + /** + * Sets the Syndication module update period. + *

+ * @param updatePeriod the Syndication module update period to set, null if none. + * + */ + public void setUpdatePeriod(String updatePeriod) { + if (!PERIODS.contains(updatePeriod)) { + throw new IllegalArgumentException("Invalid period ["+updatePeriod+"]"); + } + _updatePeriod = updatePeriod; + } + + /** + * Returns the Syndication module update frequency. + *

+ * @return the Syndication module update frequency, null if none. + * + */ + public int getUpdateFrequency() { + return _updateFrequency; + } + + /** + * Sets the Syndication module update frequency. + *

+ * @param updateFrequency the Syndication module update frequency to set, null if none. + * + */ + public void setUpdateFrequency(int updateFrequency) { + _updateFrequency = updateFrequency; + } + + /** + * Returns the Syndication module update base date. + *

+ * @return the Syndication module update base date, null if none. + * + */ + public Date getUpdateBase() { + return _updateBase; + } + + /** + * Sets the Syndication module update base date. + *

+ * @param updateBase the Syndication module update base date to set, null if none. + * + */ + public void setUpdateBase(Date updateBase) { + _updateBase = updateBase; + } + + public Class getInterface() { + return SyModule.class; + } + + public void copyFrom(Object obj) { + COPY_FROM_HELPER.copy(this,obj); + } + + private static final CopyFromHelper COPY_FROM_HELPER; + + static { + Map basePropInterfaceMap = new HashMap(); + basePropInterfaceMap.put("updatePeriod",String.class); + basePropInterfaceMap.put("updateFrequency",Integer.TYPE); + basePropInterfaceMap.put("updateBase",Date.class); + + Map basePropClassImplMap = Collections.EMPTY_MAP; + + COPY_FROM_HELPER = new CopyFromHelper(SyModule.class,basePropInterfaceMap,basePropClassImplMap); + } + +} diff --git a/src/main/java/com/sun/syndication/feed/module/impl/ModuleUtils.java b/src/main/java/com/sun/syndication/feed/module/impl/ModuleUtils.java new file mode 100644 index 0000000..da59a12 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/module/impl/ModuleUtils.java @@ -0,0 +1,57 @@ +/* + * 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 com.sun.syndication.feed.module.impl; + +import com.sun.syndication.feed.module.Module; + +import java.util.ArrayList; +import java.util.List; + +/** + */ +public class ModuleUtils { + + public static List cloneModules(List modules) { + List cModules = null; + if (modules!=null) { + cModules = new ArrayList(); + for (int i=0;i + * @author Alejandro Abdelnur + * + */ +public class Category implements Cloneable,Serializable { + private ObjectBean _objBean; + private String _domain; + private String _value; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Category() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the category domain. + *

+ * @return the category domain, null if none. + * + */ + public String getDomain() { + return _domain; + } + + /** + * Sets the category domain. + *

+ * @param domain the category domain to set, null if none. + * + */ + public void setDomain(String domain) { + _domain = domain; + } + + /** + * Returns the category value. + *

+ * @return the category value, null if none. + * + */ + public String getValue() { + return _value; + } + + /** + * Sets the category value. + *

+ * @param value the category value to set, null if none. + * + */ + public void setValue(String value) { + _value = value; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/rss/Channel.java b/src/main/java/com/sun/syndication/feed/rss/Channel.java new file mode 100644 index 0000000..f27e32b --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/rss/Channel.java @@ -0,0 +1,583 @@ +/* + * 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 com.sun.syndication.feed.rss; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.impl.ModuleUtils; + +import java.util.*; + +/** + * Bean for RSS feeds. + *

+ * It handles all RSS versions (0.9, 0.91, 0.92, 0.93, 0.94, 1.0 and 2.0) + * without losing information. + *

+ * @author Alejandro Abdelnur + * + */ +public class Channel extends WireFeed { + public static final String SUNDAY = "sunday"; + public static final String MONDAY = "monday"; + public static final String TUESDAY = "tuesday"; + public static final String WEDNESDAY = "wednesday"; + public static final String THURSDAY = "thursday"; + public static final String FRIDAY = "friday"; + public static final String SATURDAY = "saturday"; + + private static final Set DAYS = new HashSet(); + + static { + DAYS.add(SUNDAY ); + DAYS.add(MONDAY ); + DAYS.add(TUESDAY ); + DAYS.add(WEDNESDAY); + DAYS.add(THURSDAY ); + DAYS.add(FRIDAY ); + DAYS.add(SATURDAY ); + } + + private String _title; + private String _description; + private String _link; + private String _uri; + private Image _image; + private List _items; + private TextInput _textInput; + private String _language; + private String _rating; + private String _copyright; + private Date _pubDate; + private Date _lastBuildDate; + private String _docs; + private String _managingEditor; + private String _webMaster; + private List _skipHours; + private List _skipDays; + private Cloud _cloud; + private List _categories; + private String _generator; + private int _ttl = -1; + private List _modules; + + /** + * Default constructor, for bean cloning purposes only. + * + */ + public Channel() { + } + + /** + * Channel Constructor. All properties, except the type, are set to null. + *

+ * @param type the type of the RSS feed. + * + */ + public Channel(String type) { + super(type); + } + + /** + * Returns the channel title. + *

+ * @return the channel title, null if none. + * + */ + public String getTitle() { + return _title; + } + + /** + * Sets the channel title. + *

+ * @param title the channel title to set, null if none. + * + */ + public void setTitle(String title) { + _title = title; + } + + /** + * Returns the channel description. + *

+ * @return the channel description, null if none. + * + */ + public String getDescription() { + return _description; + } + + /** + * Sets the channel description. + *

+ * @param description the channel description to set, null if none. + * + */ + public void setDescription(String description) { + _description = description; + } + + /** + * Returns the channel link. + *

+ * @return the channel link, null if none. + * + */ + public String getLink() { + return _link; + } + + /** + * Sets the channel link. + *

+ * @param link the channel link to set, null if none. + * + */ + public void setLink(String link) { + _link = link; + } + + /** + * Returns the channel uri. + *

+ * @return the channel uri, null if none. + */ + public String getUri() { + return _uri; + } + + /** + * Sets the channel uri. + *

+ * @param uri the channel uri, null if none. + */ + public void setUri(String uri) { + _uri = uri; + } + + /** + * Returns the channel image. + *

+ * @return the channel image, null if none. + * + */ + public Image getImage() { + return _image; + } + + /** + * Sets the channel image. + *

+ * @param image the channel image to set, null if none. + * + */ + public void setImage(Image image) { + _image = image; + } + + /** + * Returns the channel items. + *

+ * @return a list of Item elements with the channel items, + * an empty list if none. + * + */ + public List getItems() { + return (_items==null) ? (_items=new ArrayList()) : _items; + } + + /** + * Sets the channel items. + *

+ * @param items the list of Item elements with the channel items to set, + * an empty list or null if none. + * + */ + public void setItems(List items) { + _items = items; + } + + /** + * Returns the channel text input. + *

+ * @return the channel text input, null if none. + * + */ + public TextInput getTextInput() { + return _textInput; + } + + /** + * Sets the channel text input. + *

+ * @param textInput the channel text input to set, null if none. + * + */ + public void setTextInput(TextInput textInput) { + _textInput = textInput; + } + + /** + * Returns the channel language. + *

+ * @return the channel language, null if none. + * + */ + public String getLanguage() { + return _language; + } + + /** + * Sets the channel language. + *

+ * @param language the channel language to set, null if none. + * + */ + public void setLanguage(String language) { + _language = language; + } + + /** + * Returns the channel rating. + *

+ * @return the channel rating, null if none. + * + */ + public String getRating() { + return _rating; + } + + /** + * Sets the channel rating. + *

+ * @param rating the channel rating to set, null if none. + * + */ + public void setRating(String rating) { + _rating = rating; + } + + /** + * Returns the channel copyright. + *

+ * @return the channel copyright, null if none. + * + */ + public String getCopyright() { + return _copyright; + } + + /** + * Sets the channel copyright. + *

+ * @param copyright the channel copyright to set, null if none. + * + */ + public void setCopyright(String copyright) { + _copyright = copyright; + } + + /** + * Returns the channel publishing date. + *

+ * @return the channel publishing date, null if none. + * + */ + public Date getPubDate() { + return _pubDate; + } + + /** + * Sets the channel publishing date. + *

+ * @param pubDate the channel publishing date to set, null if none. + * + */ + public void setPubDate(Date pubDate) { + _pubDate = pubDate; + } + + /** + * Returns the channel last build date. + *

+ * @return the channel last build date, null if none. + * + */ + public Date getLastBuildDate() { + return _lastBuildDate; + } + + /** + * Sets the channel last build date. + *

+ * @param lastBuildDate the channel last build date to set, null if none. + * + */ + public void setLastBuildDate(Date lastBuildDate) { + _lastBuildDate = lastBuildDate; + } + + /** + * Returns the channel docs. + *

+ * @return the channel docs, null if none. + * + */ + public String getDocs() { + return _docs; + } + + /** + * Sets the channel docs. + *

+ * @param docs the channel docs to set, null if none. + * + */ + public void setDocs(String docs) { + _docs = docs; + } + + /** + * Returns the channel managing editor. + *

+ * @return the channel managing editor, null if none. + * + */ + public String getManagingEditor() { + return _managingEditor; + } + + /** + * Sets the channel managing editor. + *

+ * @param managingEditor the channel managing editor to set, null if none. + * + */ + public void setManagingEditor(String managingEditor) { + _managingEditor = managingEditor; + } + + /** + * Returns the channel web master. + *

+ * @return the channel web master, null if none. + * + */ + public String getWebMaster() { + return _webMaster; + } + + /** + * Sets the channel web master. + *

+ * @param webMaster the channel web master to set, null if none. + * + */ + public void setWebMaster(String webMaster) { + _webMaster = webMaster; + } + + /** + * Returns the channel skip hours. + *

+ * @return a list of Integer elements with the channel skip hours, + * an empty list if none. + * + */ + public List getSkipHours() { + return (_skipHours!=null) ? _skipHours : new ArrayList(); + } + + /** + * Sets the channel skip hours. + *

+ * @param skipHours the list of Integer elements with the channel skip hours to set, + * an empty list or null if none. + * + */ + public void setSkipHours(List skipHours) { + if (skipHours!=null) { + for (int i=0;i24) { + throw new IllegalArgumentException("Invalid hour ["+hour+"]"); + } + } + else { + throw new IllegalArgumentException("Invalid hour [null]"); + } + } + } + _skipHours = skipHours; + } + + /** + * Returns the channel skip days. + *

+ * @return a list of Day elements with the channel skip days, + * an empty list if none. + * + */ + public List getSkipDays() { + return (_skipDays!=null) ? _skipDays : new ArrayList(); + } + + /** + * Sets the channel skip days. + *

+ * @param skipDays the list of Day elements with the channel skip days to set, + * an empty list or null if none. + * + */ + public void setSkipDays(List skipDays) { + if (skipDays!=null) { + for (int i=0;i + * @return the channel cloud, null if none. + * + */ + public Cloud getCloud() { + return _cloud; + } + + /** + * Sets the channel cloud. + *

+ * @param cloud the channel cloud to set, null if none. + * + */ + public void setCloud(Cloud cloud) { + _cloud = cloud; + } + + /** + * Returns the channel categories. + *

+ * @return a list of Category elements with the channel categories, + * an empty list if none. + * + */ + public List getCategories() { + return (_categories==null) ? (_categories=new ArrayList()) : _categories; + } + + /** + * Sets the channel categories. + *

+ * @param categories the list of Category elements with the channel categories to set, + * an empty list or null if none. + * + */ + public void setCategories(List categories) { + _categories = categories; + } + + /** + * Returns the channel generator. + *

+ * @return the channel generator, null if none. + * + */ + public String getGenerator() { + return _generator; + } + + /** + * Sets the channel generator. + *

+ * @param generator the channel generator to set, null if none. + * + */ + public void setGenerator(String generator) { + _generator = generator; + } + + /** + * Returns the channel time to live. + *

+ * @return the channel time to live, null if none. + * + */ + public int getTtl() { + return _ttl; + } + + /** + * Sets the channel time to live. + *

+ * @param ttl the channel time to live to set, null if none. + * + */ + public void setTtl(int ttl) { + _ttl = ttl; + } + + /** + * Returns the channel modules. + *

+ * @return a list of ModuleImpl elements with the channel modules, + * an empty list if none. + * + */ + public List getModules() { + return (_modules==null) ? (_modules=new ArrayList()) : _modules; + } + + /** + * Sets the channel modules. + *

+ * @param modules the list of ModuleImpl elements with the channel modules to set, + * an empty list or null if none. + * + */ + public void setModules(List modules) { + _modules = modules; + } + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri) { + return ModuleUtils.getModule(_modules,uri); + } + + +} diff --git a/src/main/java/com/sun/syndication/feed/rss/Cloud.java b/src/main/java/com/sun/syndication/feed/rss/Cloud.java new file mode 100644 index 0000000..1f300ae --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/rss/Cloud.java @@ -0,0 +1,190 @@ +/* + * 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 com.sun.syndication.feed.rss; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for clouds of RSS feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class Cloud implements Cloneable,Serializable { + private ObjectBean _objBean; + private String _domain; + private int _port; + private String _path; + private String _registerProcedure; + private String _protocol; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Cloud() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the cloud domain. + *

+ * @return the cloud domain, null if none. + * + */ + public String getDomain() { + return _domain; + } + + /** + * Sets the cloud domain. + *

+ * @param domain the cloud domain to set, null if none. + * + */ + public void setDomain(String domain) { + _domain = domain; + } + + /** + * Returns the cloud port. + *

+ * @return the cloud port, null if none. + * + */ + public int getPort() { + return _port; + } + + /** + * Sets the cloud port. + *

+ * @param port the cloud port to set, null if none. + * + */ + public void setPort(int port) { + _port = port; + } + + /** + * Returns the cloud path. + *

+ * @return the cloud path, null if none. + * + */ + public String getPath() { + return _path; + } + + /** + * Sets the cloud path. + *

+ * @param path the cloud path to set, null if none. + * + */ + public void setPath(String path) { + _path = path; + } + + /** + * Returns the cloud register procedure. + *

+ * @return the cloud register procedure, null if none. + * + */ + public String getRegisterProcedure() { + return _registerProcedure; + } + + /** + * Sets the cloud register procedure. + *

+ * @param registerProcedure the cloud register procedure to set, null if none. + * + */ + public void setRegisterProcedure(String registerProcedure) { + _registerProcedure = registerProcedure; + } + + /** + * Returns the cloud protocol. + *

+ * @return the cloud protocol, null if none. + * + */ + public String getProtocol() { + return _protocol; + } + + /** + * Sets the cloud protocol. + *

+ * @param protocol the cloud protocol to set, null if none. + * + */ + public void setProtocol(String protocol) { + _protocol = protocol; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/rss/Content.java b/src/main/java/com/sun/syndication/feed/rss/Content.java new file mode 100644 index 0000000..3c1da6f --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/rss/Content.java @@ -0,0 +1,130 @@ +/* + * 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 com.sun.syndication.feed.rss; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for item descriptions of RSS feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class Content implements Cloneable,Serializable { + private ObjectBean _objBean; + private String _type; + private String _value; + + public static final String HTML = "html"; + public static final String TEXT = "text"; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Content() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the description type. + *

+ * @return the description type, null if none. + * + */ + public String getType() { + return _type; + } + + /** + * Sets the description type. + *

+ * @param type the description type to set, null if none. + * + */ + public void setType(String type) { + _type = type; + } + + /** + * Returns the description value. + *

+ * @return the description value, null if none. + * + */ + public String getValue() { + return _value; + } + + /** + * Sets the description value. + *

+ * @param value the description value to set, null if none. + * + */ + public void setValue(String value) { + _value = value; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/rss/Description.java b/src/main/java/com/sun/syndication/feed/rss/Description.java new file mode 100644 index 0000000..b624c3a --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/rss/Description.java @@ -0,0 +1,127 @@ +/* + * 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 com.sun.syndication.feed.rss; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for item descriptions of RSS feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class Description implements Cloneable,Serializable { + private ObjectBean _objBean; + private String _type; + private String _value; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Description() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the description type. + *

+ * @return the description type, null if none. + * + */ + public String getType() { + return _type; + } + + /** + * Sets the description type. + *

+ * @param type the description type to set, null if none. + * + */ + public void setType(String type) { + _type = type; + } + + /** + * Returns the description value. + *

+ * @return the description value, null if none. + * + */ + public String getValue() { + return _value; + } + + /** + * Sets the description value. + *

+ * @param value the description value to set, null if none. + * + */ + public void setValue(String value) { + _value = value; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/rss/Enclosure.java b/src/main/java/com/sun/syndication/feed/rss/Enclosure.java new file mode 100644 index 0000000..6ec1190 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/rss/Enclosure.java @@ -0,0 +1,148 @@ +/* + * 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 com.sun.syndication.feed.rss; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for item enclosures of RSS feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class Enclosure implements Cloneable,Serializable { + private ObjectBean _objBean; + private String _url; + private long _length; + private String _type; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Enclosure() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the enclosure URL. + *

+ * @return the enclosure URL, null if none. + * + */ + public String getUrl() { + return _url; + } + + /** + * Sets the enclosure URL. + *

+ * @param url the enclosure URL to set, null if none. + * + */ + public void setUrl(String url) { + _url = url; + } + + /** + * Returns the enclosure length. + *

+ * @return the enclosure length, 0 if none. + * + */ + public long getLength() { + return _length; + } + + /** + * Sets the enclosure length. + *

+ * @param length the enclosure length to set, 0 if none. + * + */ + public void setLength(long length) { + _length = length; + } + + /** + * Returns the enclosure type. + *

+ * @return the enclosure type, null if none. + * + */ + public String getType() { + return _type; + } + + /** + * Sets the enclosure type. + *

+ * @param type the enclosure type to set, null if none. + * + */ + public void setType(String type) { + _type = type; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/rss/Guid.java b/src/main/java/com/sun/syndication/feed/rss/Guid.java new file mode 100644 index 0000000..29986e0 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/rss/Guid.java @@ -0,0 +1,127 @@ +/* + * 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 com.sun.syndication.feed.rss; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for item GUIDs of RSS feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class Guid implements Cloneable,Serializable { + private ObjectBean _objBean; + private boolean _permaLink; + private String _value; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Guid() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the guid perma link. + *

+ * @return the guid perma link, null if none. + * + */ + public boolean isPermaLink() { + return _permaLink; + } + + /** + * Sets the guid perma link. + *

+ * @param permaLink the guid perma link to set, null if none. + * + */ + public void setPermaLink(boolean permaLink) { + _permaLink = permaLink; + } + + /** + * Returns the guid value. + *

+ * @return the guid value, null if none. + * + */ + public String getValue() { + return _value; + } + + /** + * Sets the guid value. + *

+ * @param value the guid value to set, null if none. + * + */ + public void setValue(String value) { + _value = value; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/rss/Image.java b/src/main/java/com/sun/syndication/feed/rss/Image.java new file mode 100644 index 0000000..208a2fd --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/rss/Image.java @@ -0,0 +1,211 @@ +/* + * 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 com.sun.syndication.feed.rss; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for images of RSS feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class Image implements Cloneable,Serializable { + private ObjectBean _objBean; + private String _title; + private String _url; + private String _link; + private int _width = -1; + private int _height = -1; + private String _description; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Image() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the image title. + *

+ * @return the image title, null if none. + * + */ + public String getTitle() { + return _title; + } + + /** + * Sets the image title. + *

+ * @param title the image title to set, null if none. + * + */ + public void setTitle(String title) { + _title = title; + } + + /** + * Returns the image URL. + *

+ * @return the image URL, null if none. + * + */ + public String getUrl() { + return _url; + } + + /** + * Sets the image URL. + *

+ * @param url the image URL to set, null if none. + * + */ + public void setUrl(String url) { + _url = url; + } + + /** + * Returns the image link. + *

+ * @return the image link, null if none. + * + */ + public String getLink() { + return _link; + } + + /** + * Sets the image link. + *

+ * @param link the image link to set, null if none. + * + */ + public void setLink(String link) { + _link = link; + } + + /** + * Returns the image width. + *

+ * @return the image width, null if none. + * + */ + public int getWidth() { + return _width; + } + + /** + * Sets the image width. + *

+ * @param width the image width to set, null if none. + * + */ + public void setWidth(int width) { + _width = width; + } + + /** + * Returns the image height. + *

+ * @return the image height, null if none. + * + */ + public int getHeight() { + return _height; + } + + /** + * Sets the image height. + *

+ * @param height the image height to set, null if none. + * + */ + public void setHeight(int height) { + _height = height; + } + + /** + * Returns the image description. + *

+ * @return the image description, null if none. + * + */ + public String getDescription() { + return _description; + } + + /** + * Sets the image description. + *

+ * @param description the image description to set, null if none. + * + */ + public void setDescription(String description) { + _description = description; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/rss/Item.java b/src/main/java/com/sun/syndication/feed/rss/Item.java new file mode 100644 index 0000000..cc6004e --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/rss/Item.java @@ -0,0 +1,435 @@ +/* + * 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 com.sun.syndication.feed.rss; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.impl.ModuleUtils; +import com.sun.syndication.feed.module.Extendable; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.io.Serializable; + +/** + * Bean for items of RSS feeds. + *

+ * It handles all RSS versions without loosing information. + *

+ * For RSS1.0 it supports Dublin Core and Syndication modules. Note that + * those modules currently support simple syntax format only. + *

+ * @author Alejandro Abdelnur + * + */ +public class Item implements Cloneable, Serializable, Extendable { + private ObjectBean _objBean; + private String _title; + private String _link; + private String _uri; + private Description _description; + private Content _content; + private Source _source; + private List _enclosures; + private List _categories; + private Guid _guid; + private String _comments; + private String _author; + private Date _pubDate; + private Date _expirationDate; + private List _modules; + private List _foreignMarkup; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Item() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + if (other == null) { + return false; + } + // can't use foreign markup in equals, due to JDOM equals impl + Object fm = getForeignMarkup(); + setForeignMarkup(((Item)other).getForeignMarkup()); + boolean ret = _objBean.equals(other); + // restore foreign markup + setForeignMarkup(fm); + return ret; + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the item title. + *

+ * @return the item title, null if none. + * + */ + public String getTitle() { + return _title; + } + + /** + * Sets the item title. + *

+ * @param title the item title to set, null if none. + * + */ + public void setTitle(String title) { + _title = title; + } + + /** + * Returns the item link. + *

+ * @return the item link, null if none. + * + */ + public String getLink() { + return _link; + } + + /** + * Sets the item link. + *

+ * @param link the item link to set, null if none. + * + */ + public void setLink(String link) { + _link = link; + } + + /** + * Returns the item uri. + *

+ * @return the item uri, null if none. + */ + public String getUri() { + return _uri; + } + + /** + * Sets the item uri. + *

+ * @param uri the item uri to set, null if none. + */ + public void setUri(String uri) { + _uri = uri; + } + + /** + * Returns the item description. + *

+ * @return the item description, null if none. + * + */ + public Description getDescription() { + return _description; + } + + /** + * Sets the item description. + *

+ * @param description the item description to set, null if none. + * + */ + public void setDescription(Description description) { + _description = description; + } + + /** + * Returns the item content. + *

+ * @return the item content, null if none. + * + */ + public Content getContent() { + return _content; + } + + /** + * Sets the item content. + *

+ * @param content the item content to set, null if none. + * + */ + public void setContent(Content content) { + _content = content; + } + + /** + * Returns the item source. + *

+ * @return the item source, null if none. + * + */ + public Source getSource() { + return _source; + } + + /** + * Sets the item source. + *

+ * @param source the item source to set, null if none. + * + */ + public void setSource(Source source) { + _source = source; + } + + /** + * Returns the item enclosures. + *

+ * @return a list of Enclosure elements with the item enclosures, + * an empty list if none. + * + */ + public List getEnclosures() { + return (_enclosures==null) ? (_enclosures=new ArrayList()) : _enclosures; + } + + /** + * Sets the item enclosures. + *

+ * @param enclosures the list of Enclosure elements with the item enclosures to set, + * an empty list or null if none. + * + */ + public void setEnclosures(List enclosures) { + _enclosures = enclosures; + } + + /** + * Returns the item categories. + *

+ * @return a list of Category elements with the item categories, + * an empty list if none. + * + */ + public List getCategories() { + return (_categories==null) ? (_categories=new ArrayList()) : _categories; + } + + /** + * Sets the item categories. + *

+ * @param categories the list of Categories elements with the item categories to set, + * an empty list or null if none. + * + */ + public void setCategories(List categories) { + _categories = categories; + } + + /** + * Returns the item GUID. + *

+ * @return the item GUID, null if none. + * + */ + public Guid getGuid() { + return _guid; + } + + /** + * Sets the item GUID. + *

+ * @param guid the item GUID to set, null if none. + * + */ + public void setGuid(Guid guid) { + _guid = guid; + } + + /** + * Returns the item comments. + *

+ * @return the item comments, null if none. + * + */ + public String getComments() { + return _comments; + } + + /** + * Sets the item comments. + *

+ * @param comments the item comments to set, null if none. + * + */ + public void setComments(String comments) { + _comments = comments; + } + + /** + * Returns the item author. + *

+ * @return the item author, null if none. + * + */ + public String getAuthor() { + return _author; + } + + /** + * Sets the item author. + *

+ * @param author the item author to set, null if none. + * + */ + public void setAuthor(String author) { + _author = author; + } + + /** + * Returns the item modules. + *

+ * @return a list of ModuleImpl elements with the item modules, + * an empty list if none. + * + */ + public List getModules() { + return (_modules==null) ? (_modules=new ArrayList()) : _modules; + } + + /** + * Sets the item modules. + *

+ * @param modules the list of ModuleImpl elements with the item modules to set, + * an empty list or null if none. + * + */ + public void setModules(List modules) { + _modules = modules; + } + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri) { + return ModuleUtils.getModule(_modules,uri); + } + + + /** + * Returns the item publishing date. + *

+ * @return the item publishing date, null if none. + * + */ + public Date getPubDate() { + return _pubDate; + } + + /** + * Sets the item publishing date. + *

+ * @param pubDate the item publishing date to set, null if none. + * + */ + public void setPubDate(Date pubDate) { + _pubDate = pubDate; + } + + /** + * Returns the item expiration date. + *

+ * @return the item expiration date, null if none. + * + */ + public Date getExpirationDate() { + return _expirationDate; + } + + /** + * Sets the item expiration date. + *

+ * @param expirationDate the item expiration date to set, null if none. + * + */ + public void setExpirationDate(Date expirationDate) { + _expirationDate = expirationDate; + } + + /** + * Returns foreign markup found at item level. + *

+ * @return Opaque object to discourage use + * + */ + public Object getForeignMarkup() { + return (_foreignMarkup==null) ? (_foreignMarkup=new ArrayList()) : _foreignMarkup; + } + + /** + * Sets foreign markup found at item level. + *

+ * @param foreignMarkup Opaque object to discourage use + * + */ + public void setForeignMarkup(Object foreignMarkup) { + _foreignMarkup = (List)foreignMarkup; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/rss/Source.java b/src/main/java/com/sun/syndication/feed/rss/Source.java new file mode 100644 index 0000000..d681b0c --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/rss/Source.java @@ -0,0 +1,126 @@ +/* + * 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 com.sun.syndication.feed.rss; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for item sources of RSS feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class Source implements Cloneable,Serializable { + private ObjectBean _objBean; + private String _url; + private String _value; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public Source() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the source URL. + *

+ * @return the source URL, null if none. + * + */ + public String getUrl() { + return _url; + } + + /** + * Sets the source URL. + *

+ * @param url the source URL to set, null if none. + * + */ + public void setUrl(String url) { + _url = url; + } + + /** + * Returns the source value. + *

+ * @return the source value, null if none. + * + */ + public String getValue() { + return _value; + } + + /** + * Sets the source value. + *

+ * @param value the source value to set, null if none. + * + */ + public void setValue(String value) { + _value = value; + } +} diff --git a/src/main/java/com/sun/syndication/feed/rss/TextInput.java b/src/main/java/com/sun/syndication/feed/rss/TextInput.java new file mode 100644 index 0000000..ea73a23 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/rss/TextInput.java @@ -0,0 +1,169 @@ +/* + * 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 com.sun.syndication.feed.rss; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Bean for text input of RSS feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class TextInput implements Cloneable,Serializable { + private ObjectBean _objBean; + private String _title; + private String _description; + private String _name; + private String _link; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public TextInput() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the text input title. + *

+ * @return the text input title, null if none. + * + */ + public String getTitle() { + return _title; + } + + /** + * Sets the text input title. + *

+ * @param title the text input title to set, null if none. + * + */ + public void setTitle(String title) { + _title = title; + } + + /** + * Returns the text input description. + *

+ * @return the text input description, null if none. + * + */ + public String getDescription() { + return _description; + } + + /** + * Sets the text input description. + *

+ * @param description the text input description to set, null if none. + * + */ + public void setDescription(String description) { + _description = description; + } + + /** + * Returns the text input name. + *

+ * @return the text input name, null if none. + * + */ + public String getName() { + return _name; + } + + /** + * Sets the text input name. + *

+ * @param name the text input name to set, null if none. + * + */ + public void setName(String name) { + _name = name; + } + + /** + * Returns the text input link. + *

+ * @return the text input link, null if none. + * + */ + public String getLink() { + return _link; + } + + /** + * Sets the text input link. + *

+ * @param link the text input link to set, null if none. + * + */ + public void setLink(String link) { + _link = link; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/Converter.java b/src/main/java/com/sun/syndication/feed/synd/Converter.java new file mode 100644 index 0000000..9f46b1d --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/Converter.java @@ -0,0 +1,68 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.synd.SyndFeed; + +/** + * Interface that defines the functionality to convert a SyndFeedImpl + * to a real feed (RSS or Atom) and vice versa. + *

+ * Each implementation knows how to deal with a specific type (version) + * of a real feed. + *

+ * Implementations must be thread safe. + *

+ * TODO: explain how developers can plugin their own implementations. + *

+ * @author Alejandro Abdelnur + * + */ +public interface Converter { + + /** + * Returns the type (version) of the real feed this converter handles. + *

+ * @see WireFeed for details on the format of this string. + *

+ * @return the real feed type. + * + */ + public String getType(); + + /** + * Makes a deep copy/conversion of the values of a real feed into a SyndFeedImpl. + *

+ * It assumes the given SyndFeedImpl has no properties set. + *

+ * @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); + + /** + * Creates real feed with a deep copy/conversion of the values of a SyndFeedImpl. + *

+ * @param syndFeed SyndFeedImpl to copy/convert value from. + * @return a real feed with copied/converted values of the SyndFeedImpl. + * + */ + public WireFeed createRealFeed(SyndFeed syndFeed); + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndCategory.java b/src/main/java/com/sun/syndication/feed/synd/SyndCategory.java new file mode 100644 index 0000000..450ab6a --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndCategory.java @@ -0,0 +1,70 @@ +/* + * 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 com.sun.syndication.feed.synd; + + + + +/** + * Bean interface for categories of SyndFeedImpl feeds and entries. + *

+ * @author Alejandro Abdelnur + * + */ +public interface SyndCategory extends Cloneable { + /** + * Returns the category name. + *

+ * @return the category name, null if none. + * + */ + String getName(); + + /** + * Sets the category name. + *

+ * @param name the category name to set, null if none. + * + */ + void setName(String name); + + /** + * Returns the category taxonomy URI. + *

+ * @return the category taxonomy URI, null if none. + * + */ + String getTaxonomyUri(); + + /** + * Sets the category taxonomy URI. + *

+ * @param taxonomyUri the category taxonomy URI to set, null if none. + * + */ + void setTaxonomyUri(String taxonomyUri); + + /** + * Creates a deep clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException; + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndCategoryImpl.java b/src/main/java/com/sun/syndication/feed/synd/SyndCategoryImpl.java new file mode 100644 index 0000000..9db36ba --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndCategoryImpl.java @@ -0,0 +1,276 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.module.DCSubjectImpl; +import com.sun.syndication.feed.module.DCSubject; + +import java.util.AbstractList; +import java.util.List; +import java.util.ArrayList; +import java.io.Serializable; + +/** + * Bean for categories of SyndFeedImpl feeds and entries. + *

+ * @author Alejandro Abdelnur + * + */ +public class SyndCategoryImpl implements Serializable,SyndCategory { + private ObjectBean _objBean; + private DCSubject _subject; + + /** + * For implementations extending SyndContentImpl to be able to use the ObjectBean functionality + * with extended interfaces. + *

+ * @param subject the DC subject to wrap. + */ + SyndCategoryImpl(DCSubject subject) { + _objBean = new ObjectBean(SyndCategory.class,this); + _subject = subject; + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Package private constructor, used by SyndCategoryListFacade. + *

+ * @return the DC subject being wrapped. + * + */ + DCSubject getSubject() { + return _subject; + } + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public SyndCategoryImpl() { + this(new DCSubjectImpl()); + } + + /** + * Returns the category name. + *

+ * @return the category name, null if none. + * + */ + public String getName() { + return _subject.getValue(); + } + + /** + * Sets the category name. + *

+ * @param name the category name to set, null if none. + * + */ + public void setName(String name) { + _subject.setValue(name); + } + + /** + * Returns the category taxonomy URI. + *

+ * @return the category taxonomy URI, null if none. + * + */ + public String getTaxonomyUri() { + return _subject.getTaxonomyUri(); + } + + /** + * Sets the category taxonomy URI. + *

+ * @param taxonomyUri the category taxonomy URI to set, null if none. + * + */ + public void setTaxonomyUri(String taxonomyUri) { + _subject.setTaxonomyUri(taxonomyUri); + } + +} + + +/** + * List implementation for SyndCategoryImpl elements. To be directly used by the SyndFeedImpl + * and SyndEntryImpl classes only. + *

+ * It acts as a facade on top of the DCSubjectImpl elements of the underlying list + * and remains in synch with it. It is possible to work on either list, the categories + * one or the subjects one and they remain in synch. + *

+ * This is necessary because the SyndFeedImpl categories are just a convenience to access + * the DublinCore subjects. + *

+ * All this mess to avoid making DCSubjectImpl implement SyndCategory (which it would be odd). + *

+ * @author Alejandro Abdelnur + * + */ +class SyndCategoryListFacade extends AbstractList { + private List _subjects; + + /** + * Default constructor. Creates and empty list. + */ + public SyndCategoryListFacade() { + this(new ArrayList()); + } + + /** + * Creates a facade list of categories on top the given subject list. + *

+ * @param subjects the list of subjects to create the facade. + * + */ + public SyndCategoryListFacade(List subjects) { + _subjects = subjects; + } + + /** + * Gets the category by index. + *

+ * @param index the index position to retrieve the category. + * @return the SyndCategoryImpl in position index, null if none. + * + */ + public Object get(int index) { + return new SyndCategoryImpl((DCSubject) _subjects.get(index)); + } + + /** + * Returns the size of the list. + *

+ * @return the size of the list. + * + */ + public int size() { + return _subjects.size(); + } + + /** + * Sets a category in an existing position in the list. + *

+ * @param index position to set the category. + * @param obj the SyndCategoryImpl object to set. + * @return the SyndCategoryImpl object that is being replaced, null if none. + * + */ + public Object set(int index,Object obj) { + SyndCategoryImpl sCat = (SyndCategoryImpl) obj; + DCSubject subject = (sCat!=null) ? sCat.getSubject() : null; + subject = (DCSubject) _subjects.set(index,subject); + return (subject!=null) ? new SyndCategoryImpl(subject) : null; + } + + /** + * Adds a category to the list. + *

+ * @param index position to add the category. + * @param obj the SyndCategoryImpl object to add. + * + */ + public void add(int index,Object obj) { + SyndCategoryImpl sCat = (SyndCategoryImpl) obj; + DCSubject subject = (sCat!=null) ? sCat.getSubject() : null; + _subjects.add(index,subject); + } + + /** + * Removes a category element from a specific position. + *

+ * @param index position to remove the category from. + * @return the SyndCategoryImpl being removed from position index, null if none. + * + */ + public Object remove(int index) { + DCSubject subject = (DCSubject) _subjects.remove(index); + return (subject!=null) ? new SyndCategoryImpl(subject) : null; + } + + /** + * Returns a list with the DCSubject elements of the SyndCategoryImpl list facade. + * To be used by the SyndFeedImpl class only. + *

+ * @param cList the list with SyndCategoryImpl elements to convert to subject list. + * @return a list with DCSubject elements corresponding to the categories in the given list. + * + */ + public static List convertElementsSyndCategoryToSubject(List cList) { + List sList = null; + if (cList!=null) { + sList = new ArrayList(); + for (int i=0;i + * @author Alejandro Abdelnur + * + */ +public interface SyndContent extends Cloneable,CopyFrom { + /** + * Returns the content type. + *

+ * When used for the description of an entry, if null 'text/plain' must be assumed. + *

+ * @return the content type, null if none. + * + */ + String getType(); + + /** + * Sets the content type. + *

+ * When used for the description of an entry, if null 'text/plain' must be assumed. + *

+ * @param type the content type to set, null if none. + * + */ + void setType(String type); + + /** + * Gets the content mode (needed for Atom 0.3 support). + * @return type the content, null if none. + * + */ + String getMode(); + + /** + * Sets the content mode (needed for Atom 0.3 support). + * @param mode the content mode to set, null if none. + * + */ + void setMode(String mode); + + /** + * Returns the content value. + *

+ * @return the content value, null if none. + * + */ + String getValue(); + + /** + * Sets the content value. + *

+ * @param value the content value to set, null if none. + * + */ + void setValue(String value); + + /** + * Creates a deep clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException; + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndContentImpl.java b/src/main/java/com/sun/syndication/feed/synd/SyndContentImpl.java new file mode 100644 index 0000000..251b1d5 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndContentImpl.java @@ -0,0 +1,176 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.impl.CopyFromHelper; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.io.Serializable; + +/** + * Bean for content of SyndFeedImpl entries. + *

+ * @author Alejandro Abdelnur + * + */ +public class SyndContentImpl implements Serializable,SyndContent { + private ObjectBean _objBean; + private String _type; + private String _value; + private String _mode; + + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public SyndContentImpl() { + _objBean = new ObjectBean(SyndContent.class,this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the content type. + *

+ * When used for the description of an entry, if null 'text/plain' must be assumed. + *

+ * @return the content type, null if none. + * + */ + public String getType() { + return _type; + } + + /** + * Sets the content type. + *

+ * When used for the description of an entry, if null 'text/plain' must be assumed. + *

+ * @param type the content type to set, null if none. + * + */ + public void setType(String type) { + _type = type; + } + + /** + * Returns the content mode. + * @return the content mode, null if none. + * + */ + public String getMode() { + return _mode; + } + + /** + * Sets the content mode. + * @param mode the content mode to set, null if none. + * + */ + public void setMode(String mode) { + _mode = mode; + } + + /** + * Returns the content value. + *

+ * @return the content value, null if none. + * + */ + public String getValue() { + return _value; + } + + /** + * Sets the content value. + *

+ * @param value the content value to set, null if none. + * + */ + public void setValue(String value) { + _value = value; + } + + + public Class getInterface() { + return SyndContent.class; + } + + public void copyFrom(Object obj) { + COPY_FROM_HELPER.copy(this,obj); + } + + private static final CopyFromHelper COPY_FROM_HELPER; + + static { + Map basePropInterfaceMap = new HashMap(); + basePropInterfaceMap.put("type",String.class); + basePropInterfaceMap.put("value",String.class); + + Map basePropClassImplMap = Collections.EMPTY_MAP; + + COPY_FROM_HELPER = new CopyFromHelper(SyndContent.class,basePropInterfaceMap,basePropClassImplMap); + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndEnclosure.java b/src/main/java/com/sun/syndication/feed/synd/SyndEnclosure.java new file mode 100644 index 0000000..344b0c8 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndEnclosure.java @@ -0,0 +1,57 @@ +package com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.CopyFrom; + +/** + * @author Alejandro Abdelnur + */ +public interface SyndEnclosure extends Cloneable, CopyFrom { + /** + * Returns the enclosure URL. + *

+ * @return the enclosure URL, null if none. + * + */ + public String getUrl(); + + /** + * Sets the enclosure URL. + *

+ * @param url the enclosure URL to set, null if none. + * + */ + public void setUrl(String url); + + /** + * Returns the enclosure length. + *

+ * @return the enclosure length, 0 if none. + * + */ + public long getLength(); + + /** + * Sets the enclosure length. + *

+ * @param length the enclosure length to set, 0 if none. + * + */ + public void setLength(long length); + + /** + * Returns the enclosure type. + *

+ * @return the enclosure type, null if none. + * + */ + public String getType(); + + /** + * Sets the enclosure type. + *

+ * @param type the enclosure type to set, null if none. + * + */ + public void setType(String type); + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndEnclosureImpl.java b/src/main/java/com/sun/syndication/feed/synd/SyndEnclosureImpl.java new file mode 100644 index 0000000..eeb2cbf --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndEnclosureImpl.java @@ -0,0 +1,154 @@ +package com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.impl.CopyFromHelper; + +import java.io.Serializable; +import java.util.Map; +import java.util.HashMap; +import java.util.Collections; + +/** + * @author Alejandro Abdelnur + */ +public class SyndEnclosureImpl implements Serializable,SyndEnclosure { + private ObjectBean _objBean; + private String _url; + private String _type; + private long _length; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public SyndEnclosureImpl() { + _objBean = new ObjectBean(SyndEnclosure.class,this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the enclosure URL. + *

+ * + * @return the enclosure URL, null if none. + */ + public String getUrl() { + return _url; + } + + /** + * Sets the enclosure URL. + *

+ * + * @param url the enclosure URL to set, null if none. + */ + public void setUrl(String url) { + _url = url; + } + + /** + * Returns the enclosure length. + *

+ * + * @return the enclosure length, null if none. + */ + public long getLength() { + return _length; + } + + /** + * Sets the enclosure length. + *

+ * + * @param length the enclosure length to set, null if none. + */ + public void setLength(long length) { + _length = length; + } + + /** + * Returns the enclosure type. + *

+ * + * @return the enclosure type, null if none. + */ + public String getType() { + return _type; + } + + /** + * Sets the enclosure type. + *

+ * + * @param type the enclosure type to set, null if none. + */ + public void setType(String type) { + _type = type; + } + + public Class getInterface() { + return SyndEnclosure.class; + } + + public void copyFrom(Object obj) { + COPY_FROM_HELPER.copy(this,obj); + } + + private static final CopyFromHelper COPY_FROM_HELPER; + + static { + Map basePropInterfaceMap = new HashMap(); + basePropInterfaceMap.put("url",String.class); + basePropInterfaceMap.put("type",String.class); + basePropInterfaceMap.put("length",Long.TYPE); + + Map basePropClassImplMap = Collections.EMPTY_MAP; + + COPY_FROM_HELPER = new CopyFromHelper(SyndEnclosure.class,basePropInterfaceMap,basePropClassImplMap); + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndEntry.java b/src/main/java/com/sun/syndication/feed/synd/SyndEntry.java new file mode 100644 index 0000000..2e3d6e6 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndEntry.java @@ -0,0 +1,385 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import java.util.Date; +import java.util.List; + +import com.sun.syndication.feed.CopyFrom; +import com.sun.syndication.feed.module.Extendable; +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.rss.Item; + +/** + * Bean interface for entries of SyndFeedImpl feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public interface SyndEntry extends Cloneable, CopyFrom, Extendable { + + /** + * Returns the entry URI. + *

+ * How the entry URI maps to a concrete feed type (RSS or Atom) depends on + * the concrete feed type. This is explained in detail in Rome documentation, + * Feed and entry URI mapping. + *

+ * The returned URI is a normalized URI as specified in RFC 2396bis. + *

+ * @return the entry URI, null if none. + * + */ + String getUri(); + + /** + * Sets the entry URI. + *

+ * How the entry URI maps to a concrete feed type (RSS or Atom) depends on + * the concrete feed type. This is explained in detail in Rome documentation, + * Feed and entry URI mapping. + *

+ * @param uri the entry URI to set, null if none. + * + */ + void setUri(String uri); + + /** + * Returns the entry title. + *

+ * @return the entry title, null if none. + * + */ + String getTitle(); + + /** + * Sets the entry title. + *

+ * @param title the entry title to set, null if none. + * + */ + void setTitle(String title); + + /** + * Returns the entry title as a text construct. + *

+ * @return the entry title, null if none. + * + */ + SyndContent getTitleEx(); + + /** + * Sets the entry title as a text construct. + *

+ * @param title the entry title to set, null if none. + * + */ + void setTitleEx(SyndContent title); + + /** + * Returns the entry link. + *

+ * @return the entry link, null if none. + * + */ + String getLink(); + + /** + * Sets the entry link. + *

+ * @param link the entry link to set, null if none. + * + */ + void setLink(String link); + + /** + * Returns the entry links + *

+ * @return the entry links, null if none. + * + */ + List getLinks(); + + /** + * Sets the entry links. + *

+ * @param links the entry links to set, null if none. + * + */ + void setLinks(List links); + + /** + * Returns the entry description. + *

+ * @return the entry description, null if none. + * + */ + SyndContent getDescription(); + + /** + * Sets the entry description. + *

+ * @param description the entry description to set, null if none. + * + */ + void setDescription(SyndContent description); + + /** + * Returns the entry contents. + *

+ * @return a list of SyndContentImpl elements with the entry contents, + * an empty list if none. + * + */ + List getContents(); + + /** + * Sets the entry contents. + *

+ * @param contents the list of SyndContentImpl elements with the entry contents to set, + * an empty list or null if none. + * + */ + void setContents(List contents); + + /** + * Returns the entry enclosures. + *

+ * @return a list of SyndEnclosure elements with the entry enclosures, + * an empty list if none. + * + */ + public List getEnclosures(); + + /** + * Sets the entry enclosures. + *

+ * @param enclosures the list of SyndEnclosure elements with the entry enclosures to set, + * an empty list or null if none. + * + */ + public void setEnclosures(List enclosures); + + /** + * Returns the entry published date. + *

+ * This method is a convenience method, it maps to the Dublin Core module date. + *

+ * @return the entry published date, null if none. + * + */ + Date getPublishedDate(); + + /** + * Sets the entry published date. + *

+ * This method is a convenience method, it maps to the Dublin Core module date. + *

+ * @param publishedDate the entry published date to set, null if none. + * + */ + void setPublishedDate(Date publishedDate); + + /** + * Returns the entry updated date. + *

+ * @return the entry updated date, null if none. + * + */ + Date getUpdatedDate(); + + /** + * Sets the entry updated date. + *

+ * @param updatedDate the entry updated date to set, null if none. + * + */ + void setUpdatedDate(Date updatedDate); + + /** + * Returns the entry authors. + *

+ * For Atom feeds, this returns the authors as a list of SyndPerson objects, + * for RSS feeds this method is a convenience method, it maps to the + * Dublin Core module creator. + *

+ * @return the feed author, null if none. + * + */ + List getAuthors(); + + /** + * Sets the entry author. + *

+ * For Atom feeds, this sets the authors as a list of SyndPerson + * objects, for RSS feeds this method is a convenience method, it maps + * to the Dublin Core module creator. + *

+ * @param authors the feed author to set, null if none. + * + */ + void setAuthors(List authors); + + /** + * Returns the name of the first entry author in the collection of authors. + *

+ * For Atom feeds, this returns the authors as a list of SyndPerson objects, + * for RSS feeds this method is a convenience method, it maps to the + * Dublin Core module creator. + *

+ * @return the feed author, null if none. + * + */ + String getAuthor(); + + /** + * Sets the entry author. + *

+ * For Atom feeds, this sets the feed author's name, for RSS feeds + * this method is a convenience method, it maps to the Dublin Core + * module creator. + *

+ * @param author the feed author to set, null if none. + */ + void setAuthor(String author); + + /** + * Returns the feed author. + *

+ * For Atom feeds, this returns the contributors as a list of + * SyndPerson objects + *

+ * @return the feed author, null if none. + * + */ + List getContributors(); + + /** + * Sets the feed contributors. + *

+ * Returns contributors as a list of SyndPerson objects. + *

+ * @param contributors the feed contributors to set, null if none. + * + */ + void setContributors(List contributors); + + /** + * Returns the entry categories. + *

+ * This method is a convenience method, it maps to the Dublin Core module subjects. + *

+ * @return a list of SyndCategoryImpl elements with the entry categories, + * an empty list if none. + * + */ + List getCategories(); + + /** + * Sets the entry categories. + *

+ * This method is a convenience method, it maps to the Dublin Core module subjects. + *

+ * @param categories the list of SyndCategoryImpl elements with the entry categories to set, + * an empty list or null if none. + * + */ + void setCategories(List categories); + + /** + * Returns the entry source. + *

+ * This returns the entry source as a SyndFeed + *

+ * @return the SyndFeed to which this entry is attributed + * + */ + SyndFeed getSource(); + + /** + * Sets the entry source feed (for use if different from containing feed) + *

+ * @param source the original SyndFeed that contained this article + * + */ + void setSource(SyndFeed source); + + /** + * Return the original item this SyndEntry is generated from. + * The type of the object returned depends on the original type of + * the feed. Atom 0.3/1.0 will return com.sun.syndication.feed.atom.Entry, + * while RSS will return com.sun.syndication.feed.rss.Item.java. + * If this entry was not generated from a WireFeed, or the SyndFeed + * was not set to preserve the WireFeed then it will return null + * + * @return the WireFeed Item or Entry this Entry is generated from, or null + */ + Object getWireEntry(); + + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri); + + /** + * Returns the entry modules. + *

+ * @return a list of ModuleImpl elements with the entry modules, + * an empty list if none. + * + */ + List getModules(); + + /** + * Sets the entry modules. + *

+ * @param modules the list of ModuleImpl elements with the entry modules to set, + * an empty list or null if none. + * + */ + void setModules(List modules); + + /** + * Returns foreign markup found at channel level. + *

+ * @return Opaque object to discourage use + * + */ + public Object getForeignMarkup(); + + /** + * Sets foreign markup found at channel level. + *

+ * @param foreignMarkup Opaque object to discourage use + * + */ + public void setForeignMarkup(Object foreignMarkup); + + /** + * Creates a deep clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException; + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndEntryImpl.java b/src/main/java/com/sun/syndication/feed/synd/SyndEntryImpl.java new file mode 100644 index 0000000..ccee36b --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndEntryImpl.java @@ -0,0 +1,571 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.module.*; +import com.sun.syndication.feed.module.impl.ModuleUtils; +import com.sun.syndication.feed.synd.impl.URINormalizer; +import com.sun.syndication.feed.impl.CopyFromHelper; + +import java.util.*; +import java.io.Serializable; + +/** + * Bean for entries of SyndFeedImpl feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class SyndEntryImpl implements Serializable,SyndEntry { + private ObjectBean _objBean; + private String _uri; + private String _link; + private Date _updatedDate; + private SyndContent _title; + private SyndContent _description; + private List _links; + private List _contents; // deprecated by Atom 1.0 + private List _modules; + private List _enclosures; + private List _authors; + private List _contributors; + private SyndFeed _source; + private List _foreignMarkup; + private Object wireEntry; // com.sun.syndication.feed.atom.Entry or com.sun.syndication.feed.rss.Item + + // ISSUE: some converters assume this is never null + private List _categories = new ArrayList(); + + private static final Set IGNORE_PROPERTIES = new HashSet(); + + /** + * Unmodifiable Set containing the convenience properties of this class. + *

+ * Convenience properties are mapped to Modules, for cloning the convenience properties + * can be ignored as the will be copied as part of the module cloning. + */ + public static final Set CONVENIENCE_PROPERTIES = Collections.unmodifiableSet(IGNORE_PROPERTIES); + + static { + IGNORE_PROPERTIES.add("publishedDate"); + IGNORE_PROPERTIES.add("author"); + } + + /** + * For implementations extending SyndEntryImpl to be able to use the ObjectBean functionality + * with extended interfaces. + *

+ * @param beanClass + * @param convenienceProperties set containing the convenience properties of the SyndEntryImpl + * (the are ignored during cloning, check CloneableBean for details). + * + */ + protected SyndEntryImpl(Class beanClass,Set convenienceProperties) { + _objBean = new ObjectBean(beanClass,this,convenienceProperties); + } + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public SyndEntryImpl() { + this(SyndEntry.class,IGNORE_PROPERTIES); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + if (other == null) { + return false; + } + // while ObjectBean does this check this method does a cast to obtain the foreign markup + // so we need to check before doing so. + if (!(other instanceof SyndEntryImpl)) { + return false; + } + // can't use foreign markup in equals, due to JDOM equals impl + Object fm = getForeignMarkup(); + setForeignMarkup(((SyndEntryImpl)other).getForeignMarkup()); + boolean ret = _objBean.equals(other); + // restore foreign markup + setForeignMarkup(fm); + return ret; + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + + /** + * Returns the entry URI. + *

+ * How the entry URI maps to a concrete feed type (RSS or Atom) depends on + * the concrete feed type. This is explained in detail in Rome documentation, + * Feed and entry URI mapping. + *

+ * The returned URI is a normalized URI as specified in RFC 2396bis. + *

+ * @return the entry URI, null if none. + * + */ + public String getUri() { + return _uri; + } + + /** + * Sets the entry URI. + *

+ * How the entry URI maps to a concrete feed type (RSS or Atom) depends on + * the concrete feed type. This is explained in detail in Rome documentation, + * Feed and entry URI mapping. + *

+ * @param uri the entry URI to set, null if none. + * + */ + public void setUri(String uri) { + _uri = URINormalizer.normalize(uri); + } + + /** + * Returns the entry title. + *

+ * @return the entry title, null if none. + * + */ + public String getTitle() { + if (_title != null) return _title.getValue(); + return null; + } + + /** + * Sets the entry title. + *

+ * @param title the entry title to set, null if none. + * + */ + public void setTitle(String title) { + if (_title == null) _title = new SyndContentImpl(); + _title.setValue(title); + } + + /** + * Returns the entry title as a text construct. + *

+ * @return the entry title, null if none. + * + */ + public SyndContent getTitleEx() { + return _title; + } + + /** + * Sets the entry title as a text construct. + *

+ * @param title the entry title to set, null if none. + * + */ + public void setTitleEx(SyndContent title) { + _title = title; + } + + /** + * Returns the entry link. + *

+ * @return the entry link, null if none. + * + */ + public String getLink() { + return _link; + } + + /** + * Sets the entry link. + *

+ * @param link the entry link to set, null if none. + * + */ + public void setLink(String link) { + _link = link; + } + + /** + * Returns the entry description. + *

+ * @return the entry description, null if none. + * + */ + public SyndContent getDescription() { + return _description; + } + + /** + * Sets the entry description. + *

+ * @param description the entry description to set, null if none. + * + */ + public void setDescription(SyndContent description) { + _description = description; + } + + /** + * Returns the entry contents. + *

+ * @return a list of SyndContentImpl elements with the entry contents, + * an empty list if none. + * + */ + public List getContents() { + return (_contents==null) ? (_contents=new ArrayList()) : _contents; + } + + /** + * Sets the entry contents. + *

+ * @param contents the list of SyndContentImpl elements with the entry contents to set, + * an empty list or null if none. + * + */ + public void setContents(List contents) { + _contents = contents; + } + + /** + * Returns the entry enclosures. + *

+ * @return a list of SyndEnclosure elements with the entry enclosures, + * an empty list if none. + * + */ + public List getEnclosures() { + return (_enclosures==null) ? (_enclosures=new ArrayList()) : _enclosures; + } + + /** + * Sets the entry enclosures. + *

+ * @param enclosures the list of SyndEnclosure elements with the entry enclosures to set, + * an empty list or null if none. + * + */ + public void setEnclosures(List enclosures) { + _enclosures = enclosures; + } + + + /** + * Returns the entry published date. + *

+ * This method is a convenience method, it maps to the Dublin Core module date. + *

+ * @return the entry published date, null if none. + * + */ + public Date getPublishedDate() { + return getDCModule().getDate(); + } + + /** + * Sets the entry published date. + *

+ * This method is a convenience method, it maps to the Dublin Core module date. + *

+ * @param publishedDate the entry published date to set, null if none. + * + */ + public void setPublishedDate(Date publishedDate) { + getDCModule().setDate(publishedDate); + } + + /** + * Returns the entry categories. + *

+ * @return a list of SyndCategoryImpl elements with the entry categories, + * an empty list if none. + * + */ + public List getCategories() { + return _categories; + } + + /** + * Sets the entry categories. + *

+ * This method is a convenience method, it maps to the Dublin Core module subjects. + *

+ * @param categories the list of SyndCategoryImpl elements with the entry categories to set, + * an empty list or null if none. + * + */ + public void setCategories(List categories) { + _categories = categories; + } + + /** + * Returns the entry modules. + *

+ * @return a list of ModuleImpl elements with the entry modules, + * an empty list if none. + * + */ + public List getModules() { + if (_modules==null) { + _modules=new ArrayList(); + } + if (ModuleUtils.getModule(_modules,DCModule.URI)==null) { + _modules.add(new DCModuleImpl()); + } + return _modules; + } + + /** + * Sets the entry modules. + *

+ * @param modules the list of ModuleImpl elements with the entry modules to set, + * an empty list or null if none. + * + */ + public void setModules(List modules) { + _modules = modules; + } + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri) { + return ModuleUtils.getModule(getModules(),uri); + } + + /** + * Returns the Dublin Core module of the feed. + * @return the DC module, it's never null + * + */ + private DCModule getDCModule() { + return (DCModule) getModule(DCModule.URI); + } + + public Class getInterface() { + return SyndEntry.class; + } + + public void copyFrom(Object obj) { + COPY_FROM_HELPER.copy(this,obj); + } + + private static final CopyFromHelper COPY_FROM_HELPER; + + static { + Map basePropInterfaceMap = new HashMap(); + basePropInterfaceMap.put("uri",String.class); + basePropInterfaceMap.put("title",String.class); + basePropInterfaceMap.put("link",String.class); + basePropInterfaceMap.put("uri",String.class); + basePropInterfaceMap.put("description",SyndContent.class); + basePropInterfaceMap.put("contents",SyndContent.class); + basePropInterfaceMap.put("enclosures",SyndEnclosure.class); + basePropInterfaceMap.put("modules",Module.class); + + Map basePropClassImplMap = new HashMap(); + basePropClassImplMap.put(SyndContent.class,SyndContentImpl.class); + basePropClassImplMap.put(SyndEnclosure.class,SyndEnclosureImpl.class); + basePropClassImplMap.put(DCModule.class,DCModuleImpl.class); + basePropClassImplMap.put(SyModule.class,SyModuleImpl.class); + + COPY_FROM_HELPER = new CopyFromHelper(SyndEntry.class,basePropInterfaceMap,basePropClassImplMap); + } + + /** + * Returns the links + *

+ * @return Returns the links. + */ + public List getLinks() { + return (_links==null) ? (_links=new ArrayList()) : _links; + } + + /** + * Set the links + *

+ * @param links The links to set. + */ + public void setLinks(List links) { + _links = links; + } + + /** + * Returns the updatedDate + *

+ * @return Returns the updatedDate. + */ + public Date getUpdatedDate() { + return _updatedDate; + } + + /** + * Set the updatedDate + *

+ * @param updatedDate The updatedDate to set. + */ + public void setUpdatedDate(Date updatedDate) { + _updatedDate = updatedDate; + } + + public List getAuthors() { + return (_authors==null) ? (_authors=new ArrayList()) : _authors; + } + + /* (non-Javadoc) + * @see com.sun.syndication.feed.synd.SyndEntry#setAuthors(java.util.List) + */ + public void setAuthors(List authors) { + _authors = authors; + } + + /** + * Returns the entry author. + *

+ * This method is a convenience method, it maps to the Dublin Core module creator. + *

+ * @return the entry author, null if none. + * + */ + public String getAuthor() { + String author; + + // Start out looking for one or more authors in _authors. For non-Atom + // feeds, _authors may actually be null. + if ((_authors != null) && (_authors.size() > 0)) { + author = ((SyndPerson)_authors.get(0)).getName(); + } else { + author = getDCModule().getCreator(); + } + if (author == null) { + author = ""; + } + + return author; + } + + /** + * Sets the entry author. + *

+ * This method is a convenience method, it maps to the Dublin Core module creator. + *

+ * @param author the entry author to set, null if none. + * + */ + public void setAuthor(String author) { + // Get the DCModule so that we can check to see if "creator" is already + // set. + DCModule dcModule = getDCModule(); + String currentValue = dcModule.getCreator(); + + if ((currentValue == null) || (currentValue.length() == 0)) { + getDCModule().setCreator(author); + } + } + + public List getContributors() { + return (_contributors==null) ? (_contributors=new ArrayList()) : _contributors; + } + + /* (non-Javadoc) + * @see com.sun.syndication.feed.synd.SyndEntry#setContributors(java.util.List) + */ + public void setContributors(List contributors) { + _contributors = contributors; + } + + public SyndFeed getSource() { + return _source; + } + + public void setSource(SyndFeed source) { + _source = source; + } + + /** + * Returns foreign markup found at channel level. + *

+ * @return list of JDOM nodes containing channel-level foreign markup, + * an empty list if none. + * + */ + public Object getForeignMarkup() { + return (_foreignMarkup==null) ? (_foreignMarkup=new ArrayList()) : _foreignMarkup; + } + + /** + * Sets foreign markup found at channel level. + *

+ * @param foreignMarkup list of JDOM nodes containing channel-level foreign markup, + * an empty list if none. + * + */ + public void setForeignMarkup(Object foreignMarkup) { + _foreignMarkup = (List)foreignMarkup; + } + + public Object getWireEntry() { + return wireEntry; + } + + public void setWireEntry(Object wireEntry) { + this.wireEntry = wireEntry; + } +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndFeed.java b/src/main/java/com/sun/syndication/feed/synd/SyndFeed.java new file mode 100644 index 0000000..090fb88 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndFeed.java @@ -0,0 +1,516 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.CopyFrom; +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.module.Extendable; +import com.sun.syndication.feed.module.Module; + +import java.util.Date; +import java.util.List; + +/** + * Bean interface for all types of feeds. + *

+ * It handles all RSS versions and Atom 0.3, it normalizes all info, it may lose information. + *

+ * @author Alejandro Abdelnur + * + */ +public interface SyndFeed extends Cloneable, CopyFrom, Extendable { + + /** + * Returns the real feed types the SyndFeedImpl supports when converting from and to. + *

+ * @return the real feed type supported. + */ + List getSupportedFeedTypes(); + + /** + * Creates a real feed containing the information of the SyndFeedImpl. + *

+ * The feed type of the created WireFeed is taken from the SyndFeedImpl feedType property. + *

+ * @return the real feed. + * + */ + WireFeed createWireFeed(); + + /** + * Creates a real feed containing the information of the SyndFeedImpl. + *

+ * @param feedType the feed type for the WireFeed to be created. + * @return the real feed. + * + */ + WireFeed createWireFeed(String feedType); + + /** + * Returns the WireFeed this SyndFeed was created from. + * Will return null if the original feed is not stored or if this SyndFeed was not created from a WireFeed + * + * @return The WireFeed this was created from, or null + * + */ + WireFeed originalWireFeed(); + + /** + * + * @return true if this SyndFeed preserves the WireFeed it was created from + */ + boolean isPreservingWireFeed(); + + /** + * Returns the wire feed type the feed had/will-have when converted from/to a WireFeed. + *

+ * @return the feed type, null if none. + * + */ + String getFeedType(); + + /** + * Sets the wire feed type the feed will-have when coverted to a WireFeed. + *

+ * @param feedType the feed type to set, null if none. + * + */ + void setFeedType(String feedType); + + /** + * Returns the charset encoding of a the feed. This is not set by Rome parsers. + *

+ * @return the charset encoding of the feed. + * + */ + public String getEncoding(); + + /** + * Sets the charset encoding of a the feed. This is not set by Rome parsers. + *

+ * @param encoding the charset encoding of the feed. + * + */ + public void setEncoding(String encoding); + + /** + * Returns the feed URI. + *

+ * How the feed URI maps to a concrete feed type (RSS or Atom) depends on + * the concrete feed type. This is explained in detail in Rome documentation, + * Feed and entry URI mapping. + *

+ * The returned URI is a normalized URI as specified in RFC 2396bis. + *

+ * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is + * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link + * is the URL that the item is accessible under, the URI is the + * permanent identifier which the aggregator should use to reference + * this item. Often the URI will use some standardized identifier scheme + * such as DOI's so that items can be identified even if they appear in + * multiple feeds with different "links" (they might be on different + * hosting platforms but be the same item). Also, though rare, there + * could be multiple items with the same link but a different URI and + * associated metadata which need to be treated as distinct entities. + * In the RSS 1.0 case the URI must be a valid RDF URI reference. + *

+ * @return the feed URI, null if none. + * + */ + String getUri(); + + /** + * Sets the feed URI. + *

+ * How the feed URI maps to a concrete feed type (RSS or Atom) depends on + * the concrete feed type. This is explained in detail in Rome documentation, + * Feed and entry URI mapping. + *

+ * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is + * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link + * is the URL that the item is accessible under, the URI is the + * permanent identifier which the aggregator should use to reference + * this item. Often the URI will use some standardized identifier scheme + * such as DOI's so that items can be identified even if they appear in + * multiple feeds with different "links" (they might be on different + * hosting platforms but be the same item). Also, though rare, there + * could be multiple items with the same link but a different URI and + * associated metadata which need to be treated as distinct entities. + * In the RSS 1.0 case the URI must be a valid RDF URI reference. + *

+ * @param uri the feed URI to set, null if none. + * + */ + void setUri(String uri); + + /** + * Returns the feed title. + *

+ * @return the feed title, null if none. + * + */ + String getTitle(); + + /** + * Sets the feed title. + *

+ * @param title the feed title to set, null if none. + * + */ + void setTitle(String title); + + /** + * Returns the feed title. + *

+ * @return the feed title, null if none. + * + */ + SyndContent getTitleEx(); + + /** + * Sets the feed title. + *

+ * @param title the feed title to set, null if none. + * + */ + void setTitleEx(SyndContent title); + + /** + * Returns the feed link. + *

+ * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is + * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link + * is the URL that the item is accessible under, the URI is the + * permanent identifier which the aggregator should use to reference + * this item. Often the URI will use some standardized identifier scheme + * such as DOI's so that items can be identified even if they appear in + * multiple feeds with different "links" (they might be on different + * hosting platforms but be the same item). Also, though rare, there + * could be multiple items with the same link but a different URI and + * associated metadata which need to be treated as distinct entities. + * In the RSS 1.0 case the URI must be a valid RDF URI reference. + *

+ * @return the feed link, null if none. + * + */ + String getLink(); + + /** + * Sets the feed link. + *

+ * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is + * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link + * is the URL that the item is accessible under, the URI is the + * permanent identifier which the aggregator should use to reference + * this item. Often the URI will use some standardized identifier scheme + * such as DOI's so that items can be identified even if they appear in + * multiple feeds with different "links" (they might be on different + * hosting platforms but be the same item). Also, though rare, there + * could be multiple items with the same link but a different URI and + * associated metadata which need to be treated as distinct entities. + * In the RSS 1.0 case the URI must be a valid RDF URI reference. + *

+ * @param link the feed link to set, null if none. + * + */ + void setLink(String link); + + /** + * Returns the entry links + *

+ * @return the entry links, null if none. + * + */ + List getLinks(); + + /** + * Sets the entry links. + *

+ * @param links the entry links to set, null if none. + * + */ + void setLinks(List links); + + /** + * Returns the feed description. + *

+ * @return the feed description, null if none. + * + */ + String getDescription(); + + /** + * Sets the feed description. + *

+ * @param description the feed description to set, null if none. + * + */ + void setDescription(String description); + + /** + * Returns the feed description as a text construct. + *

+ * @return the feed description, null if none. + * + */ + SyndContent getDescriptionEx(); + + /** + * Sets the feed description as a text construct. + *

+ * @param description the feed description to set, null if none. + * + */ + void setDescriptionEx(SyndContent description); + + /** + * Returns the feed published date. + *

+ * This method is a convenience method, it maps to the Dublin Core module date. + *

+ * @return the feed published date, null if none. + * + */ + Date getPublishedDate(); + + /** + * Sets the feed published date. + *

+ * This method is a convenience method, it maps to the Dublin Core module date. + *

+ * @param publishedDate the feed published date to set, null if none. + * + */ + void setPublishedDate(Date publishedDate); + + /** + * Returns the feed authors. + *

+ * For Atom feeds, this returns the authors as a list of SyndPerson objects, + * for RSS feeds this method is a convenience method, it maps to the + * Dublin Core module creator. + *

+ * @return the feed authors, null if none. + * + */ + List getAuthors(); + + /** + * Sets the feed authors. + *

+ * For Atom feeds, this sets the authors as a list of SyndPerson + * objects, for RSS feeds this method is a convenience method, it maps + * to the Dublin Core module creator. + *

+ * @param authors the feed authors to set, null if none. + * + */ + void setAuthors(List authors); + + /** + * Returns the name of the first feed author in the collection of authors. + *

+ * For Atom feeds, this returns the authors as a list of SyndPerson objects, + * for RSS feeds this method is a convenience method, it maps to the + * Dublin Core module creator. + *

+ * @return the feed author, null if none. + * + */ + String getAuthor(); + + /** + * Sets the feed author. + *

+ * For Atom feeds, this sets the feed author's name, for RSS feeds + * this method is a convenience method, it maps to the Dublin Core + * module creator. + *

+ * @param author the feed author to set, null if none. + * + */ + void setAuthor(String author); + + /** + * Returns the feed author. + *

+ * For Atom feeds, this returns the contributors as a list of + * SyndPerson objects + *

+ * @return the feed author, null if none. + * + */ + public List getContributors(); + + /** + * Sets the feed author. + *

+ * Returns contributors as a list of SyndPerson objects. + *

+ * @param contributors the feed contributors to set, null if none. + * + */ + void setContributors(List contributors); + + /** + * Returns the feed copyright. + *

+ * This method is a convenience method, it maps to the Dublin Core module rights. + *

+ * @return the feed copyright, null if none. + * + */ + String getCopyright(); + + /** + * Sets the feed copyright. + *

+ * This method is a convenience method, it maps to the Dublin Core module rights. + *

+ * @param copyright the feed copyright to set, null if none. + * + */ + void setCopyright(String copyright); + + /** + * Returns the feed image. + *

+ * @return the feed image, null if none. + * + */ + SyndImage getImage(); + + /** + * Sets the feed image. + *

+ * @param image the feed image to set, null if none. + * + */ + void setImage(SyndImage image); + + /** + * Returns the feed categories. + *

+ * This method is a convenience method, it maps to the Dublin Core module subjects. + *

+ * @return a list of SyndCategoryImpl elements with the feed categories, + * an empty list if none. + * + */ + List getCategories(); + + /** + * Sets the feed categories. + *

+ * This method is a convenience method, it maps to the Dublin Core module subjects. + *

+ * @param categories the list of SyndCategoryImpl elements with the feed categories to set, + * an empty list or null if none. + * + */ + void setCategories(List categories); + + /** + * Returns the feed entries. + *

+ * @return a list of SyndEntryImpl elements with the feed entries, + * an empty list if none. + * + */ + List getEntries(); + + /** + * Sets the feed entries. + *

+ * @param entries the list of SyndEntryImpl elements with the feed entries to set, + * an empty list or null if none. + * + */ + void setEntries(List entries); + + /** + * Returns the feed language. + *

+ * This method is a convenience method, it maps to the Dublin Core module language. + *

+ * @return the feed language, null if none. + * + */ + String getLanguage(); + + /** + * Sets the feed language. + *

+ * This method is a convenience method, it maps to the Dublin Core module language. + *

+ * @param language the feed language to set, null if none. + * + */ + void setLanguage(String language); + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri); + + /** + * Returns the feed modules. + *

+ * @return a list of ModuleImpl elements with the feed modules, + * an empty list if none. + * + */ + List getModules(); + + /** + * Sets the feed modules. + *

+ * @param modules the list of ModuleImpl elements with the feed modules to set, + * an empty list or null if none. + * + */ + void setModules(List modules); + + /** + * Returns foreign markup found at channel level. + *

+ * @return Opaque object to discourage use + * + */ + public Object getForeignMarkup(); + + /** + * Sets foreign markup found at channel level. + *

+ * @param foreignMarkup Opaque object to discourage use + * + */ + public void setForeignMarkup(Object foreignMarkup); + + /** + * Creates a deep clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException; + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndFeedImpl.java b/src/main/java/com/sun/syndication/feed/synd/SyndFeedImpl.java new file mode 100644 index 0000000..531d612 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndFeedImpl.java @@ -0,0 +1,771 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.impl.CopyFromHelper; +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.module.*; +import com.sun.syndication.feed.module.impl.ModuleUtils; +import com.sun.syndication.feed.synd.impl.Converters; +import com.sun.syndication.feed.synd.impl.URINormalizer; + +import java.util.*; +import java.io.Serializable; + +/** + * Bean for all types of feeds. + *

+ * It handles all RSS versions, Atom 0.3 and Atom 1.0, it normalizes all info, it may lose information. + *

+ * @author Alejandro Abdelnur + * + */ +public class SyndFeedImpl implements Serializable, SyndFeed { + + private ObjectBean _objBean; + + private String _encoding; + private String _uri; + private SyndContent _title; + private SyndContent _description; + private String _feedType; + private String _link; + private List _links; + private SyndImage _image; + private List _entries; + private List _modules; + private List _authors; + private List _contributors; + private List _foreignMarkup; + + private WireFeed wireFeed = null; + private boolean preserveWireFeed = false; + + private static final Converters CONVERTERS = new Converters(); + + private static final Set IGNORE_PROPERTIES = new HashSet(); + + /** + * Unmodifiable Set containing the convenience properties of this class. + *

+ * Convenience properties are mapped to Modules, for cloning the convenience properties + * can be ignored as the will be copied as part of the module cloning. + */ + + public static final Set CONVENIENCE_PROPERTIES = Collections.unmodifiableSet(IGNORE_PROPERTIES); + + static { + IGNORE_PROPERTIES.add("publishedDate"); + IGNORE_PROPERTIES.add("author"); + IGNORE_PROPERTIES.add("copyright"); + IGNORE_PROPERTIES.add("categories"); + IGNORE_PROPERTIES.add("language"); + } + + /** + * Returns the real feed types the SyndFeedImpl supports when converting from and to. + *

+ * @return the real feed type supported. + */ + public List getSupportedFeedTypes() { + return CONVERTERS.getSupportedFeedTypes(); + } + + /** + * For implementations extending SyndFeedImpl to be able to use the ObjectBean functionality + * with extended interfaces. + *

+ * @param beanClass + * @param convenienceProperties set containing the convenience properties of the SyndEntryImpl + * (the are ignored during cloning, check CloneableBean for details). + * + */ + protected SyndFeedImpl(Class beanClass,Set convenienceProperties) { + _objBean = new ObjectBean(beanClass,this,convenienceProperties); + } + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public SyndFeedImpl() { + this(null); + } + + /** + * Creates a SyndFeedImpl and populates all its properties out of the + * given RSS Channel or Atom Feed properties. + *

+ * @param feed the RSS Channel or the Atom Feed to populate the properties from. + * + */ + public SyndFeedImpl(WireFeed feed) { + this(feed, false); + } + + /** + * Creates a SyndFeedImpl and populates all its properties out of the + * given RSS Channel or Atom Feed properties, while optionally preserving + * the WireFeed for access via the orignalWireFeed() method. + * + * @param feed + * @param preserveWireFeed + */ + public SyndFeedImpl(WireFeed feed, boolean preserveWireFeed) { + this(SyndFeed.class,IGNORE_PROPERTIES); + + if (preserveWireFeed) { + this.wireFeed = feed; + this.preserveWireFeed = preserveWireFeed; + } + + if (feed!=null) { + _feedType = feed.getFeedType(); + Converter converter = CONVERTERS.getConverter(_feedType); + if (converter==null) { + throw new IllegalArgumentException("Invalid feed type ["+_feedType+"]"); + } + converter.copyInto(feed,this); + } + + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + if (other == null) { + return false; + } + // can't use foreign markup in equals, due to JDOM equals impl + Object fm = getForeignMarkup(); + setForeignMarkup(((SyndFeedImpl)other).getForeignMarkup()); + boolean ret = _objBean.equals(other); + // restore foreign markup + setForeignMarkup(fm); + return ret; + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Creates a real feed containing the information of the SyndFeedImpl. + *

+ * The feed type of the created WireFeed is taken from the SyndFeedImpl feedType property. + *

+ * @return the real feed. + * + */ + public WireFeed createWireFeed() { + return createWireFeed(_feedType); + } + + /** + * Creates a real feed containing the information of the SyndFeedImpl. + *

+ * @param feedType the feed type for the WireFeed to be created. + * @return the real feed. + * + */ + public WireFeed createWireFeed(String feedType) { + if (feedType==null) { + throw new IllegalArgumentException("Feed type cannot be null"); + } + Converter converter = CONVERTERS.getConverter(feedType); + if (converter==null) { + throw new IllegalArgumentException("Invalid feed type ["+feedType+"]"); + } + return converter.createRealFeed(this); + } + + /** + * Returns the WireFeed this SyndFeed was created from. + * Will return null if the original feed is not stored or if this SyndFeed was not created from a WireFeed. + *
+ * Note: The wire feed returned here will NOT contain any modifications done on this SyndFeed since it was created. + * That is in contrast to the createWireFeed method, which will reflect the current state of the SyndFeed + * + * @return The WireFeed this was created from, or null + * + */ + public WireFeed originalWireFeed() { + return wireFeed; + } + + /** + * Returns the wire feed type the feed had/will-have when coverted from/to a WireFeed. + *

+ * @return the feed type, null if none. + * + */ + public String getFeedType() { + return _feedType; + } + + /** + * Sets the wire feed type the feed will-have when coverted to a WireFeed. + *

+ * @param feedType the feed type to set, null if none. + * + */ + public void setFeedType(String feedType) { + _feedType = feedType; + } + + /** + * Returns the charset encoding of a the feed. This is not set by Rome parsers. + *

+ * @return the charset encoding of the feed. + * + */ + public String getEncoding() { + return _encoding; + } + + /** + * Sets the charset encoding of a the feed. This is not set by Rome parsers. + *

+ * @param encoding the charset encoding of the feed. + * + */ + public void setEncoding(String encoding) { + _encoding = encoding; + } + + /** + * Returns the feed URI. + *

+ * How the feed URI maps to a concrete feed type (RSS or Atom) depends on + * the concrete feed type. This is explained in detail in Rome documentation, + * Feed and entry URI mapping. + *

+ * The returned URI is a normalized URI as specified in RFC 2396bis. + *

+ * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is + * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link + * is the URL that the item is accessible under, the URI is the + * permanent identifier which the aggregator should use to reference + * this item. Often the URI will use some standardized identifier scheme + * such as DOI's so that items can be identified even if they appear in + * multiple feeds with different "links" (they might be on different + * hosting platforms but be the same item). Also, though rare, there + * could be multiple items with the same link but a different URI and + * associated metadata which need to be treated as distinct entities. + * In the RSS 1.0 case the URI must be a valid RDF URI reference. + *

+ * @return the feed URI, null if none. + * + */ + public String getUri() { + return _uri; + } + + /** + * Sets the feed URI. + *

+ * How the feed URI maps to a concrete feed type (RSS or Atom) depends on + * the concrete feed type. This is explained in detail in Rome documentation, + * Feed and entry URI mapping. + *

+ * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is + * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link + * is the URL that the item is accessible under, the URI is the + * permanent identifier which the aggregator should use to reference + * this item. Often the URI will use some standardized identifier scheme + * such as DOI's so that items can be identified even if they appear in + * multiple feeds with different "links" (they might be on different + * hosting platforms but be the same item). Also, though rare, there + * could be multiple items with the same link but a different URI and + * associated metadata which need to be treated as distinct entities. + * In the RSS 1.0 case the URI must be a valid RDF URI reference. + *

+ * @param uri the feed URI to set, null if none. + * + */ + public void setUri(String uri) { + _uri = URINormalizer.normalize(uri); + } + + /** + * Returns the feed title. + *

+ * @return the feed title, null if none. + * + */ + public String getTitle() { + if (_title != null) return _title.getValue(); + return null; + } + + /** + * Sets the feed title. + *

+ * @param title the feed title to set, null if none. + * + */ + public void setTitle(String title) { + if (_title == null) _title = new SyndContentImpl(); + _title.setValue(title); + } + + /** + * Returns the feed title as a text construct. + *

+ * @return the feed title, null if none. + * + */ + public SyndContent getTitleEx() { + return _title; + } + + /** + * Sets the feed title as a text construct. + *

+ * @param title the feed title to set, null if none. + * + */ + public void setTitleEx(SyndContent title) { + _title = title; + } + + /** + * Returns the feed link. + *

+ * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is + * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link + * is the URL that the item is accessible under, the URI is the + * permanent identifier which the aggregator should use to reference + * this item. Often the URI will use some standardized identifier scheme + * such as DOI's so that items can be identified even if they appear in + * multiple feeds with different "links" (they might be on different + * hosting platforms but be the same item). Also, though rare, there + * could be multiple items with the same link but a different URI and + * associated metadata which need to be treated as distinct entities. + * In the RSS 1.0 case the URI must be a valid RDF URI reference. + *

+ * @return the feed link, null if none. + * + */ + public String getLink() { + return _link; + } + + /** + * Sets the feed link. + *

+ * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is + * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link + * is the URL that the item is accessible under, the URI is the + * permanent identifier which the aggregator should use to reference + * this item. Often the URI will use some standardized identifier scheme + * such as DOI's so that items can be identified even if they appear in + * multiple feeds with different "links" (they might be on different + * hosting platforms but be the same item). Also, though rare, there + * could be multiple items with the same link but a different URI and + * associated metadata which need to be treated as distinct entities. + * In the RSS 1.0 case the URI must be a valid RDF URI reference. + *

+ * @param link the feed link to set, null if none. + * + */ + public void setLink(String link) { + _link = link; + } + + /** + * Returns the feed description. + *

+ * @return the feed description, null if none. + * + */ + public String getDescription() { + if (_description != null) return _description.getValue(); + return null; + } + + /** + * Sets the feed description. + *

+ * @param description the feed description to set, null if none. + * + */ + public void setDescription(String description) { + if (_description == null) _description = new SyndContentImpl(); + _description.setValue(description); + } + + /** + * Returns the feed description as a text construct. + *

+ * @return the feed description, null if none. + * + */ + public SyndContent getDescriptionEx() { + return _description; + } + + /** + * Sets the feed description as a text construct. + *

+ * @param description the feed description to set, null if none. + * + */ + public void setDescriptionEx(SyndContent description) { + _description = description; + } + + /** + * Returns the feed published date. + *

+ * This method is a convenience method, it maps to the Dublin Core module date. + *

+ * @return the feed published date, null if none. + * + */ + public Date getPublishedDate() { + return getDCModule().getDate(); + } + + /** + * Sets the feed published date. + *

+ * This method is a convenience method, it maps to the Dublin Core module date. + *

+ * @param publishedDate the feed published date to set, null if none. + * + */ + public void setPublishedDate(Date publishedDate) { + getDCModule().setDate(publishedDate); + } + + /** + * Returns the feed copyright. + *

+ * This method is a convenience method, it maps to the Dublin Core module rights. + *

+ * @return the feed copyright, null if none. + * + */ + public String getCopyright() { + return getDCModule().getRights(); + } + + /** + * Sets the feed copyright. + *

+ * This method is a convenience method, it maps to the Dublin Core module rights. + *

+ * @param copyright the feed copyright to set, null if none. + * + */ + public void setCopyright(String copyright) { + getDCModule().setRights(copyright); + } + + /** + * Returns the feed image. + *

+ * @return the feed image, null if none. + * + */ + public SyndImage getImage() { + return _image; + } + + /** + * Sets the feed image. + *

+ * @param image the feed image to set, null if none. + * + */ + public void setImage(SyndImage image) { + _image = image; + } + + /** + * Returns the feed categories. + *

+ * This method is a convenience method, it maps to the Dublin Core module subjects. + *

+ * @return a list of SyndCategoryImpl elements with the feed categories, + * an empty list if none. + * + */ + public List getCategories() { + return new SyndCategoryListFacade(getDCModule().getSubjects()); + } + + /** + * Sets the feed categories. + *

+ * This method is a convenience method, it maps to the Dublin Core module subjects. + *

+ * @param categories the list of SyndCategoryImpl elements with the feed categories to set, + * an empty list or null if none. + * + */ + public void setCategories(List categories) { + getDCModule().setSubjects(SyndCategoryListFacade.convertElementsSyndCategoryToSubject(categories)); + } + + /** + * Returns the feed entries. + *

+ * @return a list of SyndEntryImpl elements with the feed entries, + * an empty list if none. + * + */ + public List getEntries() { + return (_entries==null) ? (_entries=new ArrayList()) : _entries; + } + + /** + * Sets the feed entries. + *

+ * @param entries the list of SyndEntryImpl elements with the feed entries to set, + * an empty list or null if none. + * + */ + public void setEntries(List entries) { + _entries = entries; + } + + /** + * Returns the feed language. + *

+ * This method is a convenience method, it maps to the Dublin Core module language. + *

+ * @return the feed language, null if none. + * + */ + public String getLanguage() { + return getDCModule().getLanguage(); + } + + /** + * Sets the feed language. + *

+ * This method is a convenience method, it maps to the Dublin Core module language. + *

+ * @param language the feed language to set, null if none. + * + */ + public void setLanguage(String language) { + getDCModule().setLanguage(language); + } + + /** + * Returns the feed modules. + *

+ * @return a list of ModuleImpl elements with the feed modules, + * an empty list if none. + * + */ + public List getModules() { + if (_modules==null) { + _modules=new ArrayList(); + } + if (ModuleUtils.getModule(_modules,DCModule.URI)==null) { + _modules.add(new DCModuleImpl()); + } + return _modules; + } + + + /** + * Sets the feed modules. + *

+ * @param modules the list of ModuleImpl elements with the feed modules to set, + * an empty list or null if none. + * + */ + public void setModules(List modules) { + _modules = modules; + } + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri) { + return ModuleUtils.getModule(getModules(),uri); + } + + /** + * Returns the Dublin Core module of the feed. + * @return the DC module, it's never null + * + */ + private DCModule getDCModule() { + return (DCModule) getModule(DCModule.URI); + } + + public Class getInterface() { + return SyndFeed.class; + } + + public void copyFrom(Object obj) { + COPY_FROM_HELPER.copy(this,obj); + } + + + // TODO We need to find out how to refactor this one in a nice reusable way. + + private static final CopyFromHelper COPY_FROM_HELPER; + + static { + Map basePropInterfaceMap = new HashMap(); + basePropInterfaceMap.put("feedType",String.class); + basePropInterfaceMap.put("encoding",String.class); + basePropInterfaceMap.put("uri",String.class); + basePropInterfaceMap.put("title",String.class); + basePropInterfaceMap.put("link",String.class); + basePropInterfaceMap.put("description",String.class); + basePropInterfaceMap.put("image",SyndImage.class); + basePropInterfaceMap.put("entries",SyndEntry.class); + basePropInterfaceMap.put("modules",Module.class); + + Map basePropClassImplMap = new HashMap(); + basePropClassImplMap.put(SyndEntry.class,SyndEntryImpl.class); + basePropClassImplMap.put(SyndImage.class,SyndImageImpl.class); + basePropClassImplMap.put(DCModule.class,DCModuleImpl.class); + basePropClassImplMap.put(SyModule.class,SyModuleImpl.class); + + COPY_FROM_HELPER = new CopyFromHelper(SyndFeed.class,basePropInterfaceMap,basePropClassImplMap); + } + + /** + * Returns the links + *

+ * @return Returns the links. + */ + public List getLinks() { + return (_links==null) ? (_links=new ArrayList()) : _links; + } + + /** + * Set the links + *

+ * @param links The links to set. + */ + public void setLinks(List links) { + _links = links; + } + + public List getAuthors() { + return (_authors==null) ? (_authors=new ArrayList()) : _authors; + } + + public void setAuthors(List authors) { + this._authors = authors; + } + + /** + * Returns the feed author. + *

+ * This method is a convenience method, it maps to the Dublin Core module creator. + *

+ * @return the feed author, null if none. + * + */ + public String getAuthor() { + return getDCModule().getCreator(); + } + + /** + * Sets the feed author. + *

+ * This method is a convenience method, it maps to the Dublin Core module creator. + *

+ * @param author the feed author to set, null if none. + * + */ + public void setAuthor(String author) { + getDCModule().setCreator(author); + } + + public List getContributors() { + return (_contributors==null) ? (_contributors=new ArrayList()) : _contributors; + } + + public void setContributors(List contributors) { + this._contributors = contributors; + } + + /** + * Returns foreign markup found at channel level. + *

+ * @return Opaque object to discourage use + * + */ + public Object getForeignMarkup() { + return (_foreignMarkup==null) ? (_foreignMarkup=new ArrayList()) : _foreignMarkup; + } + + /** + * Sets foreign markup found at channel level. + *

+ * @param foreignMarkup Opaque object to discourage use + * + */ + public void setForeignMarkup(Object foreignMarkup) { + _foreignMarkup = (List)foreignMarkup; + } + + public boolean isPreservingWireFeed() { + return preserveWireFeed; + } +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndImage.java b/src/main/java/com/sun/syndication/feed/synd/SyndImage.java new file mode 100644 index 0000000..cfff70b --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndImage.java @@ -0,0 +1,101 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.CopyFrom; + +/** + * Bean interface for images of SyndFeedImpl feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public interface SyndImage extends Cloneable,CopyFrom { + /** + * Returns the image title. + *

+ * @return the image title, null if none. + * + */ + String getTitle(); + + /** + * Sets the image title. + *

+ * @param title the image title to set, null if none. + * + */ + void setTitle(String title); + + /** + * Returns the image URL. + *

+ * @return the image URL, null if none. + * + */ + String getUrl(); + + /** + * Sets the image URL. + *

+ * @param url the image URL to set, null if none. + * + */ + void setUrl(String url); + + /** + * Returns the image link. + *

+ * @return the image link, null if none. + * + */ + String getLink(); + + /** + * Sets the image link. + *

+ * @param link the image link to set, null if none. + * + */ + void setLink(String link); + + /** + * Returns the image description. + *

+ * @return the image description, null if none. + * + */ + String getDescription(); + + /** + * Sets the image description. + *

+ * @param description the image description to set, null if none. + * + */ + void setDescription(String description); + + /** + * Creates a deep clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException; + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndImageImpl.java b/src/main/java/com/sun/syndication/feed/synd/SyndImageImpl.java new file mode 100644 index 0000000..f9383f2 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndImageImpl.java @@ -0,0 +1,195 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.impl.CopyFromHelper; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.io.Serializable; + +/** + * Bean for images of SyndFeedImpl feeds. + *

+ * @author Alejandro Abdelnur + * + */ +public class SyndImageImpl implements Serializable,SyndImage { + private ObjectBean _objBean; + private String _title; + private String _url; + private String _link; + private String _description; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public SyndImageImpl() { + _objBean = new ObjectBean(SyndImage.class,this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the image title. + *

+ * @return the image title, null if none. + * + */ + public String getTitle() { + return _title; + } + + /** + * Sets the image title. + *

+ * @param title the image title to set, null if none. + * + */ + public void setTitle(String title) { + _title = title; + } + + /** + * Returns the image URL. + *

+ * @return the image URL, null if none. + * + */ + public String getUrl() { + return _url; + } + + /** + * Sets the image URL. + *

+ * @param url the image URL to set, null if none. + * + */ + public void setUrl(String url) { + _url = url; + } + + /** + * Returns the image link. + *

+ * @return the image link, null if none. + * + */ + public String getLink() { + return _link; + } + + /** + * Sets the image link. + *

+ * @param link the image link to set, null if none. + * + */ + public void setLink(String link) { + _link = link; + } + + /** + * Returns the image description. + *

+ * @return the image description, null if none. + * + */ + public String getDescription() { + return _description; + } + + /** + * Sets the image description. + *

+ * @param description the image description to set, null if none. + * + */ + public void setDescription(String description) { + _description = description; + } + + public Class getInterface() { + return SyndImage.class; + } + + public void copyFrom(Object syndImage) { + COPY_FROM_HELPER.copy(this,syndImage); + } + + private static final CopyFromHelper COPY_FROM_HELPER; + + static { + Map basePropInterfaceMap = new HashMap(); + basePropInterfaceMap.put("title",String.class); + basePropInterfaceMap.put("url",String.class); + basePropInterfaceMap.put("link",String.class); + basePropInterfaceMap.put("description",String.class); + + Map basePropClassImplMap = Collections.EMPTY_MAP; + + COPY_FROM_HELPER = new CopyFromHelper(SyndImage.class,basePropInterfaceMap,basePropClassImplMap); + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndLink.java b/src/main/java/com/sun/syndication/feed/synd/SyndLink.java new file mode 100644 index 0000000..f3da26a --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndLink.java @@ -0,0 +1,151 @@ +/* + * 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 com.sun.syndication.feed.synd; + +/** + * Represents a link or enclosure associated with entry. + * @author Dave Johnson + */ +public interface SyndLink { + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public abstract Object clone() throws CloneNotSupportedException; + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public abstract boolean equals(Object other); + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public abstract int hashCode(); + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public abstract String toString(); + + /** + * Returns the link rel. + *

+ * @return the link rel, null if none. + * + */ + public abstract String getRel(); + + /** + * Sets the link rel. + *

+ * @param rel the link rel,, null if none. + * + */ + public abstract void setRel(String rel); + + /** + * Returns the link type. + *

+ * @return the link type, null if none. + * + */ + public abstract String getType(); + + /** + * Sets the link type. + *

+ * @param type the link type, null if none. + * + */ + public abstract void setType(String type); + + /** + * Returns the link href. + *

+ * @return the link href, null if none. + * + */ + public abstract String getHref(); + + /** + * Sets the link href. + *

+ * @param href the link href, null if none. + * + */ + public abstract void setHref(String href); + + /** + * Returns the link title. + *

+ * @return the link title, null if none. + * + */ + public abstract String getTitle(); + + /** + * Sets the link title. + *

+ * @param title the link title, null if none. + * + */ + public abstract void setTitle(String title); + + /** + * Returns the hreflang + *

+ * @return Returns the hreflang. + */ + public abstract String getHreflang(); + + /** + * Set the hreflang + *

+ * @param hreflang The hreflang to set. + */ + public abstract void setHreflang(String hreflang); + + /** + * Returns the length + *

+ * @return Returns the length. + */ + public abstract long getLength(); + + /** + * Set the length + *

+ * @param length The length to set. + */ + public abstract void setLength(long length); +} \ No newline at end of file diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndLinkImpl.java b/src/main/java/com/sun/syndication/feed/synd/SyndLinkImpl.java new file mode 100644 index 0000000..a996488 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndLinkImpl.java @@ -0,0 +1,209 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.impl.ObjectBean; + +import java.io.Serializable; + +/** + * Represents a link or an enclosure. + *

+ * @author Alejandro Abdelnur + * @author Dave Johnson (updated for Atom 1.0) + */ +public class SyndLinkImpl implements Cloneable,Serializable, SyndLink { + + private ObjectBean _objBean; + + private String _href; + private String _rel; + private String _type; + private String _hreflang; + private String _title; + private long _length; + + /** + * Default constructor. All properties are set to null. + *

+ * + */ + public SyndLinkImpl() { + _objBean = new ObjectBean(this.getClass(),this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the link rel. + *

+ * @return the link rel, null if none. + * + */ + public String getRel() { + return _rel; + } + + /** + * Sets the link rel. + *

+ * @param rel the link rel,, null if none. + * + */ + public void setRel(String rel) { + //TODO add check, ask P@ about the check + _rel = rel; + } + + /** + * Returns the link type. + *

+ * @return the link type, null if none. + * + */ + public String getType() { + return _type; + } + + /** + * Sets the link type. + *

+ * @param type the link type, null if none. + * + */ + public void setType(String type) { + _type = type; + } + + /** + * Returns the link href. + *

+ * @return the link href, null if none. + * + */ + public String getHref() { + return _href; + } + + /** + * Sets the link href. + *

+ * @param href the link href, null if none. + * + */ + public void setHref(String href) { + _href = href; + } + + /** + * Returns the link title. + *

+ * @return the link title, null if none. + * + */ + public String getTitle() { + return _title; + } + + /** + * Sets the link title. + *

+ * @param title the link title, null if none. + * + */ + public void setTitle(String title) { + _title = title; + } + + /** + * Returns the hreflang + *

+ * @return Returns the hreflang. + */ + public String getHreflang() { + return _hreflang; + } + + /** + * Set the hreflang + *

+ * @param hreflang The hreflang to set. + */ + public void setHreflang(String hreflang) { + _hreflang = hreflang; + } + + /** + * Returns the length + *

+ * @return Returns the length. + */ + public long getLength() { + return _length; + } + + /** + * Set the length + *

+ * @param length The length to set. + */ + public void setLength(long length) { + _length = length; + } +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndPerson.java b/src/main/java/com/sun/syndication/feed/synd/SyndPerson.java new file mode 100644 index 0000000..869f479 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndPerson.java @@ -0,0 +1,70 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.module.Extendable; + +/** + * Bean interface for authors and contributors of SyndFeedImpl feeds and entries. + *

+ * @author Dave Johnson + * + */ +public interface SyndPerson extends Cloneable, Extendable +{ + + /** + * Returns name of person + */ + public String getName(); + + /** + * Sets name of person. + */ + public void setName(String name); + + /** + * Returns URI of person. + */ + public String getUri(); + + /** + * Sets URI of person. + */ + public void setUri(String uri); + + /** + * Returns email of person. + */ + public String getEmail(); + + /** + * Sets email of person. + */ + public void setEmail(String email); + + + /** + * Creates a deep clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException; + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/SyndPersonImpl.java b/src/main/java/com/sun/syndication/feed/synd/SyndPersonImpl.java new file mode 100644 index 0000000..c77ea23 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/SyndPersonImpl.java @@ -0,0 +1,189 @@ +/* + * 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 com.sun.syndication.feed.synd; + +import com.sun.syndication.feed.impl.ObjectBean; +import com.sun.syndication.feed.module.DCSubjectImpl; +import com.sun.syndication.feed.module.DCSubject; +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.impl.ModuleUtils; + +import java.util.AbstractList; +import java.util.List; +import java.util.ArrayList; +import java.io.Serializable; + +/** + * Bean for authors and contributors of SyndFeedImpl feeds and entries. + *

+ * @author Dave Johnson + * + */ +public class SyndPersonImpl implements Serializable, SyndPerson { + private ObjectBean _objBean; + private String _name; + private String _uri; + private String _email; + private List _modules; + + /** + * For implementations extending SyndContentImpl to be able to use the ObjectBean functionality + * with extended interfaces. + */ + public SyndPersonImpl() { + _objBean = new ObjectBean(SyndPerson.class,this); + } + + /** + * Creates a deep 'bean' clone of the object. + *

+ * @return a clone of the object. + * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. + * + */ + public Object clone() throws CloneNotSupportedException { + return _objBean.clone(); + } + + /** + * Indicates whether some other object is "equal to" this one as defined by the Object equals() method. + *

+ * @param other he reference object with which to compare. + * @return true if 'this' object is equal to the 'other' object. + * + */ + public boolean equals(Object other) { + return _objBean.equals(other); + } + + /** + * Returns a hashcode value for the object. + *

+ * It follows the contract defined by the Object hashCode() method. + *

+ * @return the hashcode of the bean object. + * + */ + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * @return String representation for the object. + * + */ + public String toString() { + return _objBean.toString(); + } + + /** + * Returns the person name. + *

+ * @return the person name, null if none. + * + */ + public String getName() { + return _name; + } + + /** + * Sets the category name. + *

+ * @param name the category name to set, null if none. + * + */ + public void setName(String name) { + _name = name; + } + + /** + * Returns the person's e-mail address. + *

+ * @return the person's e-mail address, null if none. + * + */ + public String getEmail() { + return _email; + } + + /** + * Sets the person's e-mail address. + *

+ * @param email The person's e-mail address to set, null if none. + * + */ + public void setEmail(String email) { + _email = email; + } + + /** + * Returns the person's URI. + *

+ * @return the person's URI, null if none. + * + */ + public String getUri() { + return _uri; + } + + /** + * Sets the person's URI. + *

+ * @param uri the peron's URI to set, null if none. + * + */ + public void setUri(String uri) { + _uri = uri; + } + + /** + * Returns the person modules. + *

+ * @return a list of ModuleImpl elements with the person modules, + * an empty list if none. + */ + public List getModules() + { + if (_modules==null) { + _modules=new ArrayList(); + } + return _modules; + } + + /** + * Sets the person modules. + *

+ * @param modules the list of ModuleImpl elements with the person modules to set, + * an empty list or null if none. + * + */ + public void setModules(List modules) { + _modules = modules; + } + + /** + * Returns the module identified by a given URI. + *

+ * @param uri the URI of the ModuleImpl. + * @return The module with the given URI, null if none. + */ + public Module getModule(String uri) { + return ModuleUtils.getModule(getModules(),uri); + } +} diff --git a/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForAtom03.java b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForAtom03.java new file mode 100644 index 0000000..81149ba --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForAtom03.java @@ -0,0 +1,501 @@ +/* + * 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 com.sun.syndication.feed.synd.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.atom.Content; +import com.sun.syndication.feed.atom.Entry; +import com.sun.syndication.feed.atom.Feed; +import com.sun.syndication.feed.atom.Link; +import com.sun.syndication.feed.atom.Person; +import com.sun.syndication.feed.module.impl.ModuleUtils; +import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.feed.synd.Converter; +import com.sun.syndication.feed.synd.SyndEnclosure; +import com.sun.syndication.feed.synd.SyndEnclosureImpl; +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndContentImpl; +import com.sun.syndication.feed.synd.SyndEntryImpl; +import com.sun.syndication.feed.synd.SyndContent; +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; + +import java.util.ArrayList; +import java.util.List; +import java.util.Date; +import java.util.Iterator; + +/** + */ +public class ConverterForAtom03 implements Converter { + private String _type; + + public ConverterForAtom03() { + this("atom_0.3"); + } + + protected ConverterForAtom03(String type) { + _type = type; + } + + public String getType() { + return _type; + } + + public void copyInto(WireFeed feed,SyndFeed syndFeed) { + Feed aFeed = (Feed) feed; + + syndFeed.setModules(ModuleUtils.cloneModules(aFeed.getModules())); + + if (((List)feed.getForeignMarkup()).size() > 0) { + syndFeed.setForeignMarkup(feed.getForeignMarkup()); + } + + syndFeed.setEncoding(aFeed.getEncoding()); + + syndFeed.setUri(aFeed.getId()); + + syndFeed.setTitle(aFeed.getTitle()); + + // use first alternate links as THE link + if (aFeed.getAlternateLinks() != null + && aFeed.getAlternateLinks().size() > 0) { + Link theLink = (Link)aFeed.getAlternateLinks().get(0); + syndFeed.setLink(theLink.getHrefResolved()); + } + // lump alternate and other links together + List syndLinks = new ArrayList(); + if (aFeed.getAlternateLinks() != null + && aFeed.getAlternateLinks().size() > 0) { + syndLinks.addAll(createSyndLinks(aFeed.getAlternateLinks())); + } + if (aFeed.getOtherLinks() != null + && aFeed.getOtherLinks().size() > 0) { + syndLinks.addAll(createSyndLinks(aFeed.getOtherLinks())); + } + syndFeed.setLinks(syndLinks); + + Content tagline = aFeed.getTagline(); + if (tagline!=null) { + syndFeed.setDescription(tagline.getValue()); + } + + + List aEntries = aFeed.getEntries(); + if (aEntries!=null) { + syndFeed.setEntries(createSyndEntries(aEntries, syndFeed.isPreservingWireFeed())); + } + + // Core Atom language/author/copyright/modified elements have precedence + // over DC equivalent info. + + String language = aFeed.getLanguage(); + if (language!=null) { + syndFeed.setLanguage(language); + } + + List authors = aFeed.getAuthors(); + if (authors!=null && authors.size() > 0) { + syndFeed.setAuthors(createSyndPersons(authors)); + } + + String copyright = aFeed.getCopyright(); + if (copyright!=null) { + syndFeed.setCopyright(copyright); + } + + Date date = aFeed.getModified(); + if (date!=null) { + syndFeed.setPublishedDate(date); + } + + } + + protected List createSyndLinks(List aLinks) { + ArrayList sLinks = new ArrayList(); + for (Iterator iter = aLinks.iterator(); iter.hasNext();) { + Link link = (Link)iter.next(); + if (!link.getRel().equals("enclosure")) { + SyndLink sLink = createSyndLink(link); + sLinks.add(sLink); + } + } + return sLinks; + } + + public SyndLink createSyndLink(Link link) { + SyndLink syndLink = new SyndLinkImpl(); + syndLink.setRel( link.getRel()); + syndLink.setType( link.getType()); + syndLink.setHref( link.getHrefResolved()); + syndLink.setTitle( link.getTitle()); + return syndLink; + } + + protected List createSyndEntries(List atomEntries, boolean preserveWireItems) { + List syndEntries = new ArrayList(); + for (int i=0;i 0) { + syndEntry.setForeignMarkup((List)entry.getForeignMarkup()); + } + + syndEntry.setTitle(entry.getTitle()); + + // if there is exactly one alternate link, use that as THE link + if (entry.getAlternateLinks() != null + && entry.getAlternateLinks().size() == 1) { + Link theLink = (Link)entry.getAlternateLinks().get(0); + syndEntry.setLink(theLink.getHrefResolved()); + } + + // Create synd enclosures from enclosure links + List syndEnclosures = new ArrayList(); + if (entry.getOtherLinks() != null && entry.getOtherLinks().size() > 0) { + List oLinks = entry.getOtherLinks(); + for (Iterator iter = oLinks.iterator(); iter.hasNext(); ) { + Link thisLink = (Link)iter.next(); + if ("enclosure".equals(thisLink.getRel())) + syndEnclosures.add(createSyndEnclosure(entry, thisLink)); + } + } + syndEntry.setEnclosures(syndEnclosures); + + // lump alternate and other links together + List syndLinks = new ArrayList(); + if (entry.getAlternateLinks() != null + && entry.getAlternateLinks().size() > 0) { + syndLinks.addAll(createSyndLinks(entry.getAlternateLinks())); + } + if (entry.getOtherLinks() != null + && entry.getOtherLinks().size() > 0) { + syndLinks.addAll(createSyndLinks(entry.getOtherLinks())); + } + syndEntry.setLinks(syndLinks); + + + String id = entry.getId(); + if (id!=null) { + syndEntry.setUri(entry.getId()); + } + else { + syndEntry.setUri(syndEntry.getLink()); + } + + Content content = entry.getSummary(); + if (content==null) { + List contents = entry.getContents(); + if (contents!=null && contents.size()>0) { + content = (Content) contents.get(0); + } + } + if (content!=null) { + SyndContent sContent = new SyndContentImpl(); + sContent.setType(content.getType()); + sContent.setValue(content.getValue()); + syndEntry.setDescription(sContent); + } + + List contents = entry.getContents(); + if (contents.size()>0) { + List sContents = new ArrayList(); + for (int i=0;i 0) { + syndEntry.setAuthors(createSyndPersons(authors)); + SyndPerson person0 = (SyndPerson)syndEntry.getAuthors().get(0); + syndEntry.setAuthor(person0.getName()); + } + + Date date = entry.getModified(); + if (date==null) { + date = entry.getIssued(); + if (date==null) { + date = entry.getCreated(); + } + } + if (date!=null) { + syndEntry.setPublishedDate(date); + } + + return syndEntry; + } + + public SyndEnclosure createSyndEnclosure(Entry entry, Link link) { + SyndEnclosure syndEncl = new SyndEnclosureImpl(); + syndEncl.setUrl(link.getHrefResolved()); + syndEncl.setType(link.getType()); + syndEncl.setLength(link.getLength()); + return syndEncl; + } + + public WireFeed createRealFeed(SyndFeed syndFeed) { + Feed aFeed = new Feed(getType()); + aFeed.setModules(ModuleUtils.cloneModules(syndFeed.getModules())); + + aFeed.setEncoding(syndFeed.getEncoding()); + + aFeed.setId(syndFeed.getUri()); + + SyndContent sTitle = syndFeed.getTitleEx(); + if (sTitle != null) { + Content title = new Content(); + if (sTitle.getType() != null) { + title.setType(sTitle.getType()); + } + + if (sTitle.getMode() != null) { + title.setMode(sTitle.getMode()); + } + + title.setValue(sTitle.getValue()); + aFeed.setTitleEx(title); + } + + // separate SyndEntry's links collection into alternate and other links + List alternateLinks = new ArrayList(); + List otherLinks = new ArrayList(); + List slinks = syndFeed.getLinks(); + if (slinks != null) { + for (Iterator iter=slinks.iterator(); iter.hasNext();) { + SyndLink syndLink = (SyndLink)iter.next(); + Link link = createAtomLink(syndLink); + if (link.getRel() == null || + "".equals(link.getRel().trim()) || + "alternate".equals(link.getRel())) { + alternateLinks.add(link); + } else { + otherLinks.add(link); + } + } + } + // no alternate link? then use THE link if there is one + if (alternateLinks.size() == 0 && syndFeed.getLink() != null) { + Link link = new Link(); + link.setRel("alternate"); + link.setHref(syndFeed.getLink()); + alternateLinks.add(link); + } + + if (alternateLinks.size() > 0) aFeed.setAlternateLinks(alternateLinks); + if (otherLinks.size() > 0) aFeed.setOtherLinks(otherLinks); + + String sDesc = syndFeed.getDescription(); + if (sDesc!=null) { + Content tagline = new Content(); + tagline.setValue(sDesc); + aFeed.setTagline(tagline); + } + + aFeed.setLanguage(syndFeed.getLanguage()); + + List authors = syndFeed.getAuthors(); + if (authors!=null && authors.size() > 0) { + aFeed.setAuthors(createAtomPersons(authors)); + } + + aFeed.setCopyright(syndFeed.getCopyright()); + + aFeed.setModified(syndFeed.getPublishedDate()); + + List sEntries = syndFeed.getEntries(); + if (sEntries!=null) { + aFeed.setEntries(createAtomEntries(sEntries)); + } + + return aFeed; + } + + protected static List createAtomPersons(List sPersons) { + List persons = new ArrayList(); + for (Iterator iter = sPersons.iterator(); iter.hasNext(); ) { + SyndPerson sPerson = (SyndPerson)iter.next(); + Person person = new Person(); + person.setName(sPerson.getName()); + person.setUri(sPerson.getUri()); + person.setEmail(sPerson.getEmail()); + person.setModules(sPerson.getModules()); + persons.add(person); + } + return persons; + } + + protected static List createSyndPersons(List aPersons) { + List persons = new ArrayList(); + for (Iterator iter = aPersons.iterator(); iter.hasNext(); ) { + Person aPerson = (Person)iter.next(); + SyndPerson person = new SyndPersonImpl(); + person.setName(aPerson.getName()); + person.setUri(aPerson.getUri()); + person.setEmail(aPerson.getEmail()); + person.setModules(aPerson.getModules()); + persons.add(person); + } + return persons; + } + + protected List createAtomEntries(List syndEntries) { + List atomEntries = new ArrayList(); + for (int i=0;i 0) aEntry.setAlternateLinks(alternateLinks); + if (otherLinks.size() > 0) aEntry.setOtherLinks(otherLinks); + + + SyndContent sContent = sEntry.getDescription(); + if (sContent!=null) { + Content content = new Content(); + content.setType(sContent.getType()); + content.setValue(sContent.getValue()); + content.setMode(Content.ESCAPED); + aEntry.setSummary(content); + } + + List contents = sEntry.getContents(); + if (contents.size()>0) { + List aContents = new ArrayList(); + for (int i=0;i 0) { + aEntry.setAuthors(createAtomPersons(sAuthors)); + } else if (sEntry.getAuthor() != null) { + Person person = new Person(); + person.setName(sEntry.getAuthor()); + List authors = new ArrayList(); + authors.add(person); + aEntry.setAuthors(authors); + } + + aEntry.setModified(sEntry.getPublishedDate()); + aEntry.setIssued(sEntry.getPublishedDate()); + + return aEntry; + } + + public Link createAtomLink(SyndLink syndLink) { + Link link = new Link(); + link.setRel( syndLink.getRel()); + link.setType( syndLink.getType()); + link.setHref( syndLink.getHref()); + link.setTitle( syndLink.getTitle()); + return link; + } + + public Link createAtomEnclosure(SyndEnclosure syndEnclosure) { + Link link = new Link(); + link.setRel( "enclosure"); + link.setType( syndEnclosure.getType()); + link.setHref( syndEnclosure.getUrl()); + link.setLength( syndEnclosure.getLength()); + return link; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForAtom10.java b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForAtom10.java new file mode 100644 index 0000000..49c1074 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForAtom10.java @@ -0,0 +1,562 @@ +/* + * 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 com.sun.syndication.feed.synd.impl; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.atom.Category; +import com.sun.syndication.feed.atom.Content; +import com.sun.syndication.feed.atom.Entry; +import com.sun.syndication.feed.atom.Feed; +import com.sun.syndication.feed.atom.Link; +import com.sun.syndication.feed.atom.Person; +import com.sun.syndication.feed.module.impl.ModuleUtils; +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.SyndFeedImpl; +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.SyndEnclosure; +import com.sun.syndication.feed.synd.SyndEnclosureImpl; + + +/** + */ +public class ConverterForAtom10 implements Converter { + private String _type; + + public ConverterForAtom10() { + this("atom_1.0"); + } + + protected ConverterForAtom10(String type) { + _type = type; + } + + public String getType() { + return _type; + } + + public void copyInto(WireFeed feed, SyndFeed syndFeed) { + Feed aFeed = (Feed) feed; + + syndFeed.setModules(ModuleUtils.cloneModules(aFeed.getModules())); + + if (((List)feed.getForeignMarkup()).size() > 0) { + syndFeed.setForeignMarkup((List)feed.getForeignMarkup()); + } + + syndFeed.setEncoding(aFeed.getEncoding()); + + syndFeed.setUri(aFeed.getId()); + + Content aTitle = aFeed.getTitleEx(); + if (aTitle != null) { + SyndContent c = new SyndContentImpl(); + c.setType(aTitle.getType()); + c.setValue(aTitle.getValue()); + syndFeed.setTitleEx(c); + } + + Content aSubtitle = aFeed.getSubtitle(); + if (aSubtitle!=null) { + SyndContent c = new SyndContentImpl(); + c.setType(aSubtitle.getType()); + c.setValue(aSubtitle.getValue()); + syndFeed.setDescriptionEx(c); + } + + // use first alternate links as THE link + if (aFeed.getAlternateLinks() != null + && aFeed.getAlternateLinks().size() > 0) { + Link theLink = (Link)aFeed.getAlternateLinks().get(0); + syndFeed.setLink(theLink.getHrefResolved()); + } + // lump alternate and other links together + List syndLinks = new ArrayList(); + if (aFeed.getAlternateLinks() != null + && aFeed.getAlternateLinks().size() > 0) { + syndLinks.addAll(createSyndLinks(aFeed.getAlternateLinks())); + } + if (aFeed.getOtherLinks() != null + && aFeed.getOtherLinks().size() > 0) { + syndLinks.addAll(createSyndLinks(aFeed.getOtherLinks())); + } + syndFeed.setLinks(syndLinks); + + List aEntries = aFeed.getEntries(); + if (aEntries!=null) { + syndFeed.setEntries(createSyndEntries(aFeed, aEntries, syndFeed.isPreservingWireFeed())); + } + + // Core Atom language/author/copyright/modified elements have precedence + // over DC equivalent info. + + List authors = aFeed.getAuthors(); + if (authors!=null && authors.size() > 0) { + syndFeed.setAuthors(ConverterForAtom03.createSyndPersons(authors)); + } + + List contributors = aFeed.getContributors(); + if (contributors!=null && contributors.size() > 0) { + syndFeed.setContributors(ConverterForAtom03.createSyndPersons(contributors)); + } + + String rights = aFeed.getRights(); + if (rights!=null) { + syndFeed.setCopyright(rights); + } + + Date date = aFeed.getUpdated(); + if (date!=null) { + syndFeed.setPublishedDate(date); + } + + } + + protected List createSyndLinks(List aLinks) { + ArrayList sLinks = new ArrayList(); + for (Iterator iter = aLinks.iterator(); iter.hasNext();) { + Link link = (Link)iter.next(); + SyndLink sLink = createSyndLink(link); + sLinks.add(sLink); + } + return sLinks; + } + + protected List createSyndEntries(Feed feed, List atomEntries, boolean preserveWireItems) { + List syndEntries = new ArrayList(); + for (int i=0;i 0) { + syndEntry.setForeignMarkup((List)entry.getForeignMarkup()); + } + + Content eTitle = entry.getTitleEx(); + if (eTitle != null) { + syndEntry.setTitleEx(createSyndContent(eTitle)); + } + + Content summary = entry.getSummary(); + if (summary!=null) { + syndEntry.setDescription(createSyndContent(summary)); + } + + List contents = entry.getContents(); + if (contents != null && contents.size() > 0) { + List sContents = new ArrayList(); + for (Iterator iter=contents.iterator(); iter.hasNext();) { + Content content = (Content)iter.next(); + sContents.add(createSyndContent(content)); + } + syndEntry.setContents(sContents); + } + + List authors = entry.getAuthors(); + if (authors!=null && authors.size() > 0) { + syndEntry.setAuthors(ConverterForAtom03.createSyndPersons(authors)); + SyndPerson person0 = (SyndPerson)syndEntry.getAuthors().get(0); + syndEntry.setAuthor(person0.getName()); + } + + List contributors = entry.getContributors(); + if (contributors!=null && contributors.size() > 0) { + syndEntry.setContributors(ConverterForAtom03.createSyndPersons(contributors)); + } + + Date date = entry.getPublished(); + if (date!=null) { + syndEntry.setPublishedDate(date); + } + + date = entry.getUpdated(); + if (date!=null) { + syndEntry.setUpdatedDate(date); + } + + List categories = entry.getCategories(); + if (categories!=null) { + List syndCategories = new ArrayList(); + for (Iterator iter=categories.iterator(); iter.hasNext();) { + Category c = (Category)iter.next(); + SyndCategory syndCategory = new SyndCategoryImpl(); + syndCategory.setName(c.getTerm()); + syndCategory.setTaxonomyUri(c.getSchemeResolved()); + // TODO: categories MAY have labels + // syndCategory.setLabel(c.getLabel()); + syndCategories.add(syndCategory); + } + syndEntry.setCategories(syndCategories); + } + + // use first alternate link as THE link + if (entry.getAlternateLinks() != null + && entry.getAlternateLinks().size() > 0) { + Link theLink = (Link)entry.getAlternateLinks().get(0); + syndEntry.setLink(theLink.getHrefResolved()); + } + + // Create synd enclosures from enclosure links + List syndEnclosures = new ArrayList(); + if (entry.getOtherLinks() != null && entry.getOtherLinks().size() > 0) { + List oLinks = entry.getOtherLinks(); + for (Iterator iter = oLinks.iterator(); iter.hasNext(); ) { + Link thisLink = (Link)iter.next(); + if ("enclosure".equals(thisLink.getRel())) + syndEnclosures.add( + createSyndEnclosure(feed, entry, thisLink)); + } + } + syndEntry.setEnclosures(syndEnclosures); + + // lump alternate and other links together + List syndLinks = new ArrayList(); + if (entry.getAlternateLinks() != null + && entry.getAlternateLinks().size() > 0) { + syndLinks.addAll(createSyndLinks(entry.getAlternateLinks())); + } + if (entry.getOtherLinks() != null + && entry.getOtherLinks().size() > 0) { + syndLinks.addAll(createSyndLinks(entry.getOtherLinks())); + } + syndEntry.setLinks(syndLinks); + + String id = entry.getId(); + if (id!=null) { + syndEntry.setUri(entry.getId()); + } + else { + syndEntry.setUri(syndEntry.getLink()); + } + + // Convert source element Feed into SyndFeed and assign as SyndEntry + // source + Feed source = entry.getSource(); + if (source != null) { + SyndFeed syndSource = new SyndFeedImpl(source); + syndEntry.setSource(syndSource); + } + + return syndEntry; + } + + public SyndEnclosure createSyndEnclosure(Feed feed, Entry entry, + Link link) { + SyndEnclosure syndEncl = new SyndEnclosureImpl(); + syndEncl.setUrl(link.getHrefResolved()); + syndEncl.setType(link.getType()); + syndEncl.setLength(link.getLength()); + return syndEncl; + } + + public Link createAtomEnclosure(SyndEnclosure syndEnclosure) { + Link link = new Link(); + link.setRel( "enclosure"); + link.setType( syndEnclosure.getType()); + link.setHref( syndEnclosure.getUrl()); + link.setLength( syndEnclosure.getLength()); + return link; + } + + public SyndLink createSyndLink(Link link) { + SyndLink syndLink = new SyndLinkImpl(); + syndLink.setRel( link.getRel()); + syndLink.setType( link.getType()); + syndLink.setHref( link.getHrefResolved()); + syndLink.setHreflang(link.getHreflang()); + syndLink.setLength( link.getLength()); + syndLink.setTitle( link.getTitle()); + return syndLink; + } + + public Link createAtomLink(SyndLink syndLink) { + Link link = new Link(); + link.setRel( syndLink.getRel()); + link.setType( syndLink.getType()); + link.setHref( syndLink.getHref()); + link.setHreflang(syndLink.getHreflang()); + link.setLength( syndLink.getLength()); + link.setTitle( syndLink.getTitle()); + return link; + } + + public WireFeed createRealFeed(SyndFeed syndFeed) { + Feed aFeed = new Feed(getType()); + aFeed.setModules(ModuleUtils.cloneModules(syndFeed.getModules())); + + aFeed.setEncoding(syndFeed.getEncoding()); + + aFeed.setId(syndFeed.getUri()); + + SyndContent sTitle = syndFeed.getTitleEx(); + if (sTitle != null) { + Content title = new Content(); + title.setType(sTitle.getType()); + title.setValue(sTitle.getValue()); + aFeed.setTitleEx(title); + } + + SyndContent sDesc = syndFeed.getDescriptionEx(); + if (sDesc != null) { + Content subtitle = new Content(); + subtitle.setType(sDesc.getType()); + subtitle.setValue(sDesc.getValue()); + aFeed.setSubtitle(subtitle); + } + + // separate SyndEntry's links collection into alternate and other links + List alternateLinks = new ArrayList(); + List otherLinks = new ArrayList(); + List slinks = syndFeed.getLinks(); + if (slinks != null) { + for (Iterator iter=slinks.iterator(); iter.hasNext();) { + SyndLink syndLink = (SyndLink)iter.next(); + Link link = createAtomLink(syndLink); + if (link.getRel() == null || + "".equals(link.getRel().trim()) || + "alternate".equals(link.getRel())) { + alternateLinks.add(link); + } else { + otherLinks.add(link); + } + } + } + // no alternate link? then use THE link if there is one + if (alternateLinks.size() == 0 && syndFeed.getLink() != null) { + Link link = new Link(); + link.setRel("alternate"); + link.setHref(syndFeed.getLink()); + alternateLinks.add(link); + } + if (alternateLinks.size() > 0) aFeed.setAlternateLinks(alternateLinks); + if (otherLinks.size() > 0) aFeed.setOtherLinks(otherLinks); + + List sCats = syndFeed.getCategories(); + List aCats = new ArrayList(); + if (sCats != null) { + for (Iterator iter=sCats.iterator(); iter.hasNext();) { + SyndCategory sCat = (SyndCategory)iter.next(); + Category aCat = new Category(); + aCat.setTerm(sCat.getName()); + // TODO: aCat.setLabel(sCat.getLabel()); + aCat.setScheme(sCat.getTaxonomyUri()); + aCats.add(aCat); + } + } + if (aCats.size() > 0) aFeed.setCategories(aCats); + + List authors = syndFeed.getAuthors(); + if (authors!=null && authors.size() > 0) { + aFeed.setAuthors(ConverterForAtom03.createAtomPersons(authors)); + } + + List contributors = syndFeed.getContributors(); + if (contributors!=null && contributors.size() > 0) { + aFeed.setContributors(ConverterForAtom03.createAtomPersons(contributors)); + } + + aFeed.setRights(syndFeed.getCopyright()); + + aFeed.setUpdated(syndFeed.getPublishedDate()); + + List sEntries = syndFeed.getEntries(); + if (sEntries!=null) { + aFeed.setEntries(createAtomEntries(sEntries)); + } + + if (((List)syndFeed.getForeignMarkup()).size() > 0) { + aFeed.setForeignMarkup(syndFeed.getForeignMarkup()); + } + return aFeed; + } + + protected SyndContent createSyndContent(Content content) { + SyndContent sContent = new SyndContentImpl(); + sContent.setType(content.getType()); + sContent.setValue(content.getValue()); + return sContent; + } + + protected List createAtomEntries(List syndEntries) { + List atomEntries = new ArrayList(); + for (int i=0;i 0) aEntry.setAlternateLinks(alternateLinks); + if (otherLinks.size() > 0) aEntry.setOtherLinks(otherLinks); + + List sCats = sEntry.getCategories(); + List aCats = new ArrayList(); + if (sCats != null) { + for (Iterator iter=sCats.iterator(); iter.hasNext();) { + SyndCategory sCat = (SyndCategory)iter.next(); + Category aCat = new Category(); + aCat.setTerm(sCat.getName()); + // TODO: aCat.setLabel(sCat.getLabel()); + aCat.setScheme(sCat.getTaxonomyUri()); + aCats.add(aCat); + } + } + if (aCats.size() > 0) aEntry.setCategories(aCats); + + List syndContents = sEntry.getContents(); + aEntry.setContents(createAtomContents(syndContents)); + + List authors = sEntry.getAuthors(); + if (authors!=null && authors.size() > 0) { + aEntry.setAuthors(ConverterForAtom03.createAtomPersons(authors)); + } else if (sEntry.getAuthor() != null) { + Person person = new Person(); + person.setName(sEntry.getAuthor()); + authors = new ArrayList(); + authors.add(person); + aEntry.setAuthors(authors); + } + + List contributors = sEntry.getContributors(); + if (contributors!=null && contributors.size() > 0) { + aEntry.setContributors(ConverterForAtom03.createAtomPersons(contributors)); + } + + aEntry.setPublished(sEntry.getPublishedDate()); + + // Fix for issue #41 "Use updated instead of published" + // And issue #42 "Atom 1.0 Date (Updated or Published) Not Set" + // Atom requires an updated date, if it's missing use the published date + if (sEntry.getUpdatedDate() != null) { + aEntry.setUpdated(sEntry.getUpdatedDate()); + } else { + aEntry.setUpdated(sEntry.getPublishedDate()); + } + + if (((List)sEntry.getForeignMarkup()).size() > 0) { + aEntry.setForeignMarkup((List)sEntry.getForeignMarkup()); + } + + SyndFeed sSource = sEntry.getSource(); + if (sSource != null) { + Feed aSource = (Feed) sSource.createWireFeed(getType()); + aEntry.setSource(aSource); + } + return aEntry; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS090.java b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS090.java new file mode 100644 index 0000000..1e4246d --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS090.java @@ -0,0 +1,172 @@ +/* + * 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 com.sun.syndication.feed.synd.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.module.impl.ModuleUtils; +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.feed.rss.Image; +import com.sun.syndication.feed.rss.Item; +import com.sun.syndication.feed.synd.*; + +import java.util.ArrayList; +import java.util.List; + +/** + */ +public class ConverterForRSS090 implements Converter { + private String _type; + + public ConverterForRSS090() { + this("rss_0.9"); + } + + protected ConverterForRSS090(String type) { + _type = type; + } + + public String getType() { + return _type; + } + + public void copyInto(WireFeed feed,SyndFeed syndFeed) { + syndFeed.setModules(ModuleUtils.cloneModules(feed.getModules())); + if (((List)feed.getForeignMarkup()).size() > 0) { + syndFeed.setForeignMarkup(feed.getForeignMarkup()); + } + syndFeed.setEncoding(feed.getEncoding()); + Channel channel = (Channel) feed; + syndFeed.setTitle(channel.getTitle()); + syndFeed.setLink(channel.getLink()); + syndFeed.setDescription(channel.getDescription()); + + Image image = channel.getImage(); + if (image!=null) { + syndFeed.setImage(createSyndImage(image)); + } + + List items = channel.getItems(); + if (items!=null) { + syndFeed.setEntries(createSyndEntries(items, syndFeed.isPreservingWireFeed())); + } + } + + protected SyndImage createSyndImage(Image rssImage) { + SyndImage syndImage = new SyndImageImpl(); + syndImage.setTitle(rssImage.getTitle()); + syndImage.setUrl(rssImage.getUrl()); + syndImage.setLink(rssImage.getLink()); + return syndImage; + } + + protected List createSyndEntries(List rssItems, boolean preserveWireItems) { + List syndEntries = new ArrayList(); + for (int i=0;i 0) { + syndEntry.setForeignMarkup(item.getForeignMarkup()); + } + + syndEntry.setUri(item.getUri()); + syndEntry.setLink(item.getLink()); + syndEntry.setTitle(item.getTitle()); + syndEntry.setLink(item.getLink()); + return syndEntry; + } + + public WireFeed createRealFeed(SyndFeed syndFeed) { + return createRealFeed(getType(),syndFeed); + } + + protected WireFeed createRealFeed(String type,SyndFeed syndFeed) { + Channel channel = new Channel(type); + channel.setModules(ModuleUtils.cloneModules(syndFeed.getModules())); + + channel.setEncoding(syndFeed.getEncoding()); + + channel.setTitle(syndFeed.getTitle()); + if (syndFeed.getLink() != null) { + channel.setLink(syndFeed.getLink()); + } + else + if (syndFeed.getLinks().size() > 0) { + channel.setLink(((SyndLink)syndFeed.getLinks().get(0)).getHref()); + } + channel.setDescription(syndFeed.getDescription()); + SyndImage sImage = syndFeed.getImage(); + if (sImage!=null) { + channel.setImage(createRSSImage(sImage)); + } + + List sEntries = syndFeed.getEntries(); + if (sEntries!=null) { + channel.setItems(createRSSItems(sEntries)); + } + + if (((List)syndFeed.getForeignMarkup()).size() > 0) { + channel.setForeignMarkup(syndFeed.getForeignMarkup()); + } + return channel; + } + + protected Image createRSSImage(SyndImage sImage) { + Image image = new Image(); + image.setTitle(sImage.getTitle()); + image.setUrl(sImage.getUrl()); + image.setLink(sImage.getLink()); + return image; + } + + protected List createRSSItems(List sEntries) { + List list = new ArrayList(); + for (int i=0;i 0) { + item.setForeignMarkup(sEntry.getForeignMarkup()); + } + + String uri = sEntry.getUri(); + if (uri != null) { + item.setUri(uri); + } + + + return item; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS091Netscape.java b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS091Netscape.java new file mode 100644 index 0000000..fe5ce26 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS091Netscape.java @@ -0,0 +1,33 @@ +/* + * 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 com.sun.syndication.feed.synd.impl; + + + +/** + */ +public class ConverterForRSS091Netscape extends ConverterForRSS091Userland { + + public ConverterForRSS091Netscape() { + this("rss_0.91N"); + } + + protected ConverterForRSS091Netscape(String type) { + super(type); + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS091Userland.java b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS091Userland.java new file mode 100644 index 0000000..e01157b --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS091Userland.java @@ -0,0 +1,153 @@ +/* + * 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 com.sun.syndication.feed.synd.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.module.DCModule; +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.feed.rss.Content; +import com.sun.syndication.feed.rss.Description; +import com.sun.syndication.feed.rss.Image; +import com.sun.syndication.feed.rss.Item; +import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.feed.synd.SyndContent; +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndImage; +import com.sun.syndication.feed.synd.SyndContentImpl; +import com.sun.syndication.feed.synd.SyndPerson; + +import java.util.*; + +/** + */ +public class ConverterForRSS091Userland extends ConverterForRSS090 { + + public ConverterForRSS091Userland() { + this("rss_0.91U"); + } + + protected ConverterForRSS091Userland(String type) { + super(type); + } + + public void copyInto(WireFeed feed,SyndFeed syndFeed) { + Channel channel = (Channel) feed; + super.copyInto(channel,syndFeed); + syndFeed.setLanguage(channel.getLanguage()); //c + syndFeed.setCopyright(channel.getCopyright()); //c + Date pubDate = channel.getPubDate(); + if (pubDate!=null) { + syndFeed.setPublishedDate(pubDate); //c + } else if (channel.getLastBuildDate() != null) { + syndFeed.setPublishedDate(channel.getLastBuildDate()); //c + } + + + String author = channel.getManagingEditor(); + if (author!=null) { + List creators = ((DCModule) syndFeed.getModule(DCModule.URI)).getCreators(); + if (!creators.contains(author)) { + Set s = new HashSet(); // using a set to remove duplicates + s.addAll(creators); // DC creators + s.add(author); // feed native author + creators.clear(); + creators.addAll(s); + } + } + + } + + protected SyndImage createSyndImage(Image rssImage) { + SyndImage syndImage = super.createSyndImage(rssImage); + syndImage.setDescription(rssImage.getDescription()); + return syndImage; + } + + // for rss -> synd + // rss.content -> synd.content + // rss.description -> synd.description + + protected SyndEntry createSyndEntry(Item item, boolean preserveWireItem) { + SyndEntry syndEntry = super.createSyndEntry(item, preserveWireItem); + Description desc = item.getDescription(); + if (desc != null) { + SyndContent descContent = new SyndContentImpl(); + descContent.setType(desc.getType()); + descContent.setValue(desc.getValue()); + syndEntry.setDescription(descContent); + } + Content cont = item.getContent(); + if (cont != null) { + SyndContent content = new SyndContentImpl(); + content.setType(cont.getType()); + content.setValue(cont.getValue()); + List syndContents = new ArrayList(); + syndContents.add(content); + syndEntry.setContents(syndContents); + } + return syndEntry; + } + + protected WireFeed createRealFeed(String type,SyndFeed syndFeed) { + Channel channel = (Channel) super.createRealFeed(type,syndFeed); + channel.setLanguage(syndFeed.getLanguage()); //c + channel.setCopyright(syndFeed.getCopyright()); //c + channel.setPubDate(syndFeed.getPublishedDate()); //c + if (syndFeed.getAuthors()!=null && syndFeed.getAuthors().size() > 0) { + SyndPerson author = (SyndPerson)syndFeed.getAuthors().get(0); + channel.setManagingEditor(author.getName()); + } + return channel; + } + + protected Image createRSSImage(SyndImage sImage) { + Image image = super.createRSSImage(sImage); + image.setDescription(sImage.getDescription()); + return image; + } + + // for synd -> rss + // synd.content -> rss.content + // synd.description -> rss.description + + protected Item createRSSItem(SyndEntry sEntry) { + Item item = super.createRSSItem(sEntry); + + SyndContent sContent = sEntry.getDescription(); + if (sContent!=null) { + item.setDescription(createItemDescription(sContent)); + } + List contents = sEntry.getContents(); + if (contents != null && contents.size() > 0) { + SyndContent syndContent = (SyndContent)contents.get(0); + Content cont = new Content(); + cont.setValue(syndContent.getValue()); + cont.setType(syndContent.getType()); + item.setContent(cont); + } + return item; + } + + protected Description createItemDescription(SyndContent sContent) { + Description desc = new Description(); + desc.setValue(sContent.getValue()); + desc.setType(sContent.getType()); + return desc; + } + + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS092.java b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS092.java new file mode 100644 index 0000000..e8bb4c1 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS092.java @@ -0,0 +1,125 @@ +/* + * 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 com.sun.syndication.feed.synd.impl; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import com.sun.syndication.feed.rss.Category; +import com.sun.syndication.feed.rss.Enclosure; +import com.sun.syndication.feed.rss.Item; +import com.sun.syndication.feed.synd.SyndCategory; +import com.sun.syndication.feed.synd.SyndCategoryImpl; +import com.sun.syndication.feed.synd.SyndEnclosure; +import com.sun.syndication.feed.synd.SyndEnclosureImpl; +import com.sun.syndication.feed.synd.SyndEntry; + +/** + */ +public class ConverterForRSS092 extends ConverterForRSS091Userland { + + public ConverterForRSS092() { + this("rss_0.92"); + } + + protected ConverterForRSS092(String type) { + super(type); + } + + protected SyndEntry createSyndEntry(Item item, boolean preserveWireItem) { + SyndEntry syndEntry = super.createSyndEntry(item, preserveWireItem); + List cats = item.getCategories(); + if (cats.size()>0) { + Set s = new LinkedHashSet(); // using a set to remove duplicates and use a LinkedHashSet to try to retain the document order + s.addAll(createSyndCategories(cats)); // feed native categories (as syndcat) + s.addAll(syndEntry.getCategories()); // DC subjects (as syndcat) + syndEntry.setCategories(new ArrayList(s)); //c + } + List enclosures = item.getEnclosures(); + if (enclosures.size()>0) { + syndEntry.setEnclosures(createSyndEnclosures(enclosures)); + } + return syndEntry; + } + + protected List createSyndCategories(List rssCats) { + List syndCats = new ArrayList(); + for (int i=0;i0) { + item.setCategories(createRSSCategories(sCats)); + } + List sEnclosures = sEntry.getEnclosures(); + if (sEnclosures.size()>0) { + item.setEnclosures(createEnclosures(sEnclosures)); + } + return item; + } + + protected List createRSSCategories(List sCats) { + List cats = new ArrayList(); + for (int i=0;i0) { + Set s = new HashSet(); // using a set to remove duplicates + s.addAll(createSyndCategories(cats)); // feed native categories (as syndcat) + s.addAll(syndFeed.getCategories()); // DC subjects (as syndcat) + syndFeed.setCategories(new ArrayList(s)); + } + } + + protected SyndEntry createSyndEntry(Item item, boolean preserveWireItem) { + SyndEntry syndEntry = super.createSyndEntry(item, preserveWireItem); + + // adding native feed author to DC creators list + String author = item.getAuthor(); + if (author!=null) { + List creators = ((DCModule)syndEntry.getModule(DCModule.URI)).getCreators(); + if (!creators.contains(author)) { + Set s = new HashSet(); // using a set to remove duplicates + s.addAll(creators); // DC creators + s.add(author); // feed native author + creators.clear(); + creators.addAll(s); + } + } + + Guid guid = item.getGuid(); + if (guid!=null) { + syndEntry.setUri(guid.getValue()); + if (item.getLink()==null && guid.isPermaLink()) { + syndEntry.setLink(guid.getValue()); + } + } + else { + syndEntry.setUri(item.getLink()); + } + return syndEntry; + } + + + protected WireFeed createRealFeed(String type,SyndFeed syndFeed) { + Channel channel = (Channel) super.createRealFeed(type,syndFeed); + List cats = syndFeed.getCategories(); //c + if (cats.size()>0) { + channel.setCategories(createRSSCategories(cats)); + } + return channel; + } + + protected Item createRSSItem(SyndEntry sEntry) { + Item item = super.createRSSItem(sEntry); + if (sEntry.getAuthors()!=null && sEntry.getAuthors().size() > 0) { + SyndPerson author = (SyndPerson)sEntry.getAuthors().get(0); + item.setAuthor(author.getEmail()); + } + + Guid guid = null; + String uri = sEntry.getUri(); + if (uri!=null) { + guid = new Guid(); + guid.setPermaLink(false); + guid.setValue(uri); + } + else { + String link = sEntry.getLink(); + if (link!=null) { + guid = new Guid(); + guid.setPermaLink(true); + guid.setValue(link); + } + } + item.setGuid(guid); + + return item; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS10.java b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS10.java new file mode 100644 index 0000000..868df14 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS10.java @@ -0,0 +1,131 @@ +/* + * 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 com.sun.syndication.feed.synd.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.feed.rss.Content; +import com.sun.syndication.feed.rss.Description; +import com.sun.syndication.feed.rss.Item; +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.SyndFeed; +import java.util.ArrayList; +import java.util.List; + +/** + */ +public class ConverterForRSS10 extends ConverterForRSS090 { + + public ConverterForRSS10() { + this("rss_1.0"); + } + + protected ConverterForRSS10(String type) { + super(type); + } + + public void copyInto(WireFeed feed,SyndFeed syndFeed) { + Channel channel = (Channel) feed; + super.copyInto(channel,syndFeed); + if (channel.getUri() != null) { + syndFeed.setUri(channel.getUri()); + } else { + // if URI is not set use the value for link + syndFeed.setUri(channel.getLink()); + } + } + + // for rss -> synd + // rss.content -> synd.content + // rss.description -> synd.description + + protected SyndEntry createSyndEntry(Item item, boolean preserveWireItem) { + SyndEntry syndEntry = super.createSyndEntry(item, preserveWireItem); + + Description desc = item.getDescription(); + if (desc!=null) { + SyndContent descContent = new SyndContentImpl(); + descContent.setType(desc.getType()); + descContent.setValue(desc.getValue()); + syndEntry.setDescription(descContent); + } + Content cont = item.getContent(); + if (cont!=null) { + SyndContent contContent = new SyndContentImpl(); + contContent.setType(cont.getType()); + contContent.setValue(cont.getValue()); + List contents = new ArrayList(); + contents.add(contContent); + syndEntry.setContents(contents); + } + + return syndEntry; + } + + protected WireFeed createRealFeed(String type,SyndFeed syndFeed) { + Channel channel = (Channel) super.createRealFeed(type,syndFeed); + if (syndFeed.getUri() != null) { + channel.setUri(syndFeed.getUri()); + } else { + // if URI is not set use the value for link + channel.setUri(syndFeed.getLink()); + } + + return channel; + } + + // for synd -> rss + // synd.content -> rss.content + // synd.description -> rss.description + + protected Item createRSSItem(SyndEntry sEntry) { + Item item = super.createRSSItem(sEntry); + + SyndContent desc = sEntry.getDescription(); + if (desc!=null) { + item.setDescription(createItemDescription(desc)); + } + List contents = sEntry.getContents(); + if (contents!=null && contents.size() > 0) { + item.setContent(createItemContent((SyndContent)contents.get(0))); + } + + String uri = sEntry.getUri(); + if (uri != null) { + item.setUri(uri); + } + + return item; + } + + protected Description createItemDescription(SyndContent sContent) { + Description desc = new Description(); + desc.setValue(sContent.getValue()); + desc.setType(sContent.getType()); + return desc; + } + + protected Content createItemContent(SyndContent sContent) { + Content cont = new Content(); + cont.setValue(sContent.getValue()); + cont.setType(sContent.getType()); + return cont; + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS20.java b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS20.java new file mode 100644 index 0000000..3e824be --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/impl/ConverterForRSS20.java @@ -0,0 +1,34 @@ +/* + * 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 com.sun.syndication.feed.synd.impl; + + + + +/** + */ +public class ConverterForRSS20 extends ConverterForRSS094 { + + public ConverterForRSS20() { + this("rss_2.0"); + } + + protected ConverterForRSS20(String type) { + super(type); + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/impl/Converters.java b/src/main/java/com/sun/syndication/feed/synd/impl/Converters.java new file mode 100644 index 0000000..7af49a3 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/impl/Converters.java @@ -0,0 +1,55 @@ +/* + * 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 com.sun.syndication.feed.synd.impl; + +import com.sun.syndication.io.impl.PluginManager; +import com.sun.syndication.feed.synd.Converter; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * User: tucu + * Date: May 21, 2004 + * Time: 5:26:04 PM + * To change this template use Options | File Templates. + */ +public class Converters extends PluginManager { + + /** + * Converter.classes= [className] ... + * + */ + public static final String CONVERTERS_KEY = "Converter.classes"; + + public Converters() { + super(CONVERTERS_KEY); + } + + public Converter getConverter(String feedType) { + return (Converter) getPlugin(feedType); + } + + protected String getKey(Object obj) { + return ((Converter)obj).getType(); + } + + public List getSupportedFeedTypes() { + return getKeys(); + } + +} diff --git a/src/main/java/com/sun/syndication/feed/synd/impl/URINormalizer.java b/src/main/java/com/sun/syndication/feed/synd/impl/URINormalizer.java new file mode 100644 index 0000000..34904e5 --- /dev/null +++ b/src/main/java/com/sun/syndication/feed/synd/impl/URINormalizer.java @@ -0,0 +1,23 @@ +package com.sun.syndication.feed.synd.impl; + +/** + * Utility class for normalizing an URI as specified in RFC 2396bis. + *

+ * @author Alejandro Abdelnur + */ +public class URINormalizer { + + /** + * Normalizes an URI as specified in RFC 2396bis. + *

+ * @param uri to normalize. + * @return the normalized value of the given URI, or null if the given URI was null. + */ + public static String normalize(String uri) { + String normalizedUri = null; + if (uri!=null) { + normalizedUri = uri; //TODO THIS HAS TO BE IMPLEMENTED + } + return normalizedUri; + } +} diff --git a/src/main/java/com/sun/syndication/io/DelegatingModuleGenerator.java b/src/main/java/com/sun/syndication/io/DelegatingModuleGenerator.java new file mode 100644 index 0000000..693e4c7 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/DelegatingModuleGenerator.java @@ -0,0 +1,17 @@ +package com.sun.syndication.io; + +/** + * Adds the ability to give a direct wire feed generator reference to plugin + * modules that need to call back to their wire feed to complete + * generation of their particular namespace. Examples of such parsers + * include the SSE091Generator. + */ +public interface DelegatingModuleGenerator extends ModuleGenerator { + /** + * Provides a parent wirefeed reference to this ModuleParser, + * or "plugin-in". + * + * @param feedGenerator the parent wirefeed generator for this plugin. + */ + void setFeedGenerator(WireFeedGenerator feedGenerator); +} diff --git a/src/main/java/com/sun/syndication/io/DelegatingModuleParser.java b/src/main/java/com/sun/syndication/io/DelegatingModuleParser.java new file mode 100644 index 0000000..71d157d --- /dev/null +++ b/src/main/java/com/sun/syndication/io/DelegatingModuleParser.java @@ -0,0 +1,17 @@ +package com.sun.syndication.io; + +/** + * Adds the ability to give a direct wire feed reference to plugin + * modules that need to call back to their wire feed to complete + * parsing of their particular namespace. Examples of such parsers + * include the SSE091Parser. + */ +public interface DelegatingModuleParser extends ModuleParser { + /** + * Provides a parent wirefeed reference to this ModuleParser, + * or "plugin-in". + * + * @param feedParser the parent wirefeed parser for this plugin. + */ + void setFeedParser(WireFeedParser feedParser); +} diff --git a/src/main/java/com/sun/syndication/io/FeedException.java b/src/main/java/com/sun/syndication/io/FeedException.java new file mode 100644 index 0000000..bb8ed37 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/FeedException.java @@ -0,0 +1,49 @@ +/* + * 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 com.sun.syndication.io; + +/** + * Exception thrown by WireFeedInput, WireFeedOutput, WireFeedParser and WireFeedGenerator instances if they + * can not parse or generate a feed. + *

+ * @author Alejandro Abdelnur + * + */ +public class FeedException extends Exception { + + /** + * Creates a FeedException with a message. + *

+ * @param msg exception message. + * + */ + public FeedException(String msg) { + super(msg); + } + + /** + * Creates a FeedException with a message and a root cause exception. + *

+ * @param msg exception message. + * @param rootCause root cause exception. + * + */ + public FeedException(String msg,Throwable rootCause) { + super(msg,rootCause); + } + +} diff --git a/src/main/java/com/sun/syndication/io/ModuleGenerator.java b/src/main/java/com/sun/syndication/io/ModuleGenerator.java new file mode 100644 index 0000000..2390d1e --- /dev/null +++ b/src/main/java/com/sun/syndication/io/ModuleGenerator.java @@ -0,0 +1,63 @@ +/* + * 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 com.sun.syndication.io; + +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.WireFeed; +import org.jdom.Element; + +import java.util.Set; + +/** + * Injects module metadata into a XML node (JDOM element). + *

+ * ModuleGenerator instances must thread safe. + *

+ * TODO: explain how developers can plugin their own implementations. + *

+ * @author Alejandro Abdelnur + * + */ +public interface ModuleGenerator { + + /** + * Returns the namespace URI this generator handles. + *

+ * @return the namespace URI. + * + */ + public String getNamespaceUri(); + + /** + * Returns a set with all the URIs (JDOM Namespace elements) this module generator uses. + *

+ * It is used by the the feed generators to add their namespace definition in + * the root element of the generated document (forward-missing of Java 5.0 Generics). + *

+ * + * @return a set with all the URIs (JDOM Namespace elements) this module generator uses. + */ + public Set getNamespaces(); + + /** + * Generates and injects module metadata into an XML node (JDOM element). + *

+ * @param module the module to inject into the XML node (JDOM element). + * @param element the XML node into which module meta-data will be injected. + */ + public void generate(Module module,Element element); +} diff --git a/src/main/java/com/sun/syndication/io/ModuleParser.java b/src/main/java/com/sun/syndication/io/ModuleParser.java new file mode 100644 index 0000000..c083000 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/ModuleParser.java @@ -0,0 +1,50 @@ +/* + * 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 com.sun.syndication.io; + +import com.sun.syndication.feed.module.Module; +import org.jdom.Element; + +/** + * Parses module metadata from a XML node (JDOM element). + *

+ * ModuleParser instances must thread safe. + *

+ * TODO: explain how developers can plugin their own implementations. + *

+ * @author Alejandro Abdelnur + * + */ +public interface ModuleParser { + + /** + * Returns the namespace URI this parser handles. + *

+ * @return the namespace URI. + * + */ + public String getNamespaceUri(); + + /** + * Parses the XML node (JDOM element) extracting module information. + *

+ * @param element the XML node (JDOM element) to extract module information from. + * @return a module instance, null if the element did not have module information. + * + */ + public Module parse(Element element); +} diff --git a/src/main/java/com/sun/syndication/io/ParsingFeedException.java b/src/main/java/com/sun/syndication/io/ParsingFeedException.java new file mode 100644 index 0000000..24e6d6c --- /dev/null +++ b/src/main/java/com/sun/syndication/io/ParsingFeedException.java @@ -0,0 +1,78 @@ +/* + * 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 com.sun.syndication.io; + +import org.jdom.input.JDOMParseException; + +/** + * Exception thrown by WireFeedInput instance if it can not parse a feed. + *

+ * @author Elaine Chien + * + */ +public class ParsingFeedException extends FeedException { + + /** + * Creates a FeedException with a message. + *

+ * @param msg exception message. + * + */ + public ParsingFeedException(String msg) { + super(msg); + } + + /** + * Creates a FeedException with a message and a root cause exception. + *

+ * @param msg exception message. + * @param rootCause root cause exception. + * + */ + public ParsingFeedException(String msg, Throwable rootCause) { + super(msg, rootCause); + } + + /** + * Returns the line number of the end of the text where the + * parse error occurred. + *

+ * The first line in the document is line 1.

+ * + * @return an integer representing the line number, or -1 + * if the information is not available. + */ + public int getLineNumber() { + return (getCause() instanceof JDOMParseException)? + ((JDOMParseException)getCause()).getLineNumber(): -1; + } + + /** + * Returns the column number of the end of the text where the + * parse error occurred. + *

+ * The first column in a line is position 1.

+ * + * @return an integer representing the column number, or -1 + * if the information is not available. + */ + public int getColumnNumber() { + return (getCause() instanceof JDOMParseException)? + ((JDOMParseException)getCause()).getColumnNumber(): -1; + } + +} diff --git a/src/main/java/com/sun/syndication/io/SAXBuilder.java b/src/main/java/com/sun/syndication/io/SAXBuilder.java new file mode 100644 index 0000000..974c0a7 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/SAXBuilder.java @@ -0,0 +1,27 @@ +package com.sun.syndication.io; + +import org.jdom.JDOMException; +import org.xml.sax.XMLReader; + +/* + * This code is needed to fix the security problem outlined in http://www.securityfocus.com/archive/1/297714 + * + * Unfortunately there isn't an easy way to check if an XML parser supports a particular feature, so + * we need to set it and catch the exception if it fails. We also need to subclass the JDom SAXBuilder + * class in order to get access to the underlying SAX parser - otherwise the features don't get set until + * we are already building the document, by which time it's too late to fix the problem. + * + * Crimson is one parser which is known not to support these features. + * + */ +public class SAXBuilder extends org.jdom.input.SAXBuilder { + + public SAXBuilder(boolean _validate) { + super(_validate); + } + + public XMLReader createParser() throws JDOMException { + return super.createParser(); + } + +} diff --git a/src/main/java/com/sun/syndication/io/SyndFeedInput.java b/src/main/java/com/sun/syndication/io/SyndFeedInput.java new file mode 100644 index 0000000..2353bb9 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/SyndFeedInput.java @@ -0,0 +1,181 @@ +/* + * 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 com.sun.syndication.io; + +import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.feed.synd.SyndFeedImpl; +import org.jdom.Document; +import org.xml.sax.InputSource; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Reader; + +/** + * Parses an XML document (File, InputStream, Reader, W3C SAX InputSource, W3C DOM Document or JDom DOcument) + * into an SyndFeedImpl. + *

+ * It delegates to a WireFeedInput to handle all feed types. + *

+ * @author Alejandro Abdelnur + * + */ +public class SyndFeedInput { + private WireFeedInput _feedInput; + private boolean preserveWireFeed = false; + + /** + * Creates a SyndFeedInput instance with input validation turned off. + *

+ * + */ + public SyndFeedInput() { + this(false); + } + + /** + * Creates a SyndFeedInput instance. + *

+ * @param validate indicates if the input should be validated. NOT IMPLEMENTED YET (validation does not happen) + * + */ + public SyndFeedInput(boolean validate) { + _feedInput = new WireFeedInput(validate); + } + + /** + * Enables XML healing in the WiredFeedInput instance. + *

+ * Healing trims leading chars from the stream (empty spaces and comments) until the XML prolog. + *

+ * Healing resolves HTML entities (from literal to code number) in the reader. + *

+ * The healing is done only with the build(File) and build(Reader) signatures. + *

+ * By default is TRUE. + *

+ * @param heals TRUE enables stream healing, FALSE disables it. + * + */ + public void setXmlHealerOn(boolean heals) { + _feedInput.setXmlHealerOn(heals); + } + + /** + * Indicates if the WiredFeedInput instance will XML heal (if necessary) the character stream. + *

+ * Healing trims leading chars from the stream (empty spaces and comments) until the XML prolog. + *

+ * Healing resolves HTML entities (from literal to code number) in the reader. + *

+ * The healing is done only with the build(File) and build(Reader) signatures. + *

+ * By default is TRUE. + *

+ * @return TRUE if healing is enabled, FALSE if not. + * + */ + public boolean getXmlHealerOn() { + return _feedInput.getXmlHealerOn(); + } + + + /** + * Builds SyndFeedImpl from a file. + *

+ * @param file file to read to create the SyndFeedImpl. + * @return the SyndFeedImpl read from the file. + * @throws FileNotFoundException thrown if the file could not be found. + * @throws IOException thrown if there is problem reading the file. + * @throws IllegalArgumentException thrown if feed type could not be understood by any of the underlying parsers. + * @throws FeedException if the feed could not be parsed + * + */ + public SyndFeed build(File file) throws FileNotFoundException,IOException,IllegalArgumentException,FeedException { + return new SyndFeedImpl(_feedInput.build(file), preserveWireFeed); + } + + /** + * Builds SyndFeedImpl from an Reader. + *

+ * @param reader Reader to read to create the SyndFeedImpl. + * @return the SyndFeedImpl read from the Reader. + * @throws IllegalArgumentException thrown if feed type could not be understood by any of the underlying parsers. + * @throws FeedException if the feed could not be parsed + * + */ + public SyndFeed build(Reader reader) throws IllegalArgumentException,FeedException { + return new SyndFeedImpl(_feedInput.build(reader), preserveWireFeed); + } + + /** + * Builds SyndFeedImpl from an W3C SAX InputSource. + *

+ * @param is W3C SAX InputSource to read to create the SyndFeedImpl. + * @return the SyndFeedImpl read from the W3C SAX InputSource. + * @throws IllegalArgumentException thrown if feed type could not be understood by any of the underlying parsers. + * @throws FeedException if the feed could not be parsed + * + */ + public SyndFeed build(InputSource is) throws IllegalArgumentException,FeedException { + return new SyndFeedImpl(_feedInput.build(is), preserveWireFeed); + } + + /** + * Builds SyndFeedImpl from an W3C DOM document. + *

+ * @param document W3C DOM document to read to create the SyndFeedImpl. + * @return the SyndFeedImpl read from the W3C DOM document. + * @throws IllegalArgumentException thrown if feed type could not be understood by any of the underlying parsers. + * @throws FeedException if the feed could not be parsed + * + */ + public SyndFeed build(org.w3c.dom.Document document) throws IllegalArgumentException,FeedException { + return new SyndFeedImpl(_feedInput.build(document), preserveWireFeed); + } + + /** + * Builds SyndFeedImpl from an JDOM document. + *

+ * @param document JDOM document to read to create the SyndFeedImpl. + * @return the SyndFeedImpl read from the JDOM document. + * @throws IllegalArgumentException thrown if feed type could not be understood by any of the underlying parsers. + * @throws FeedException if the feed could not be parsed + * + */ + public SyndFeed build(Document document) throws IllegalArgumentException,FeedException { + return new SyndFeedImpl(_feedInput.build(document), preserveWireFeed); + } + + /** + * + * @return true if the WireFeed is made available in the SyndFeed. False by default. + */ + public boolean isPreserveWireFeed() { + return preserveWireFeed; + } + + /** + * + * @param preserveWireFeed set to true to make the WireFeed is made available in the SyndFeed. False by default. + */ + public void setPreserveWireFeed(boolean preserveWireFeed) { + this.preserveWireFeed = preserveWireFeed; + } + +} diff --git a/src/main/java/com/sun/syndication/io/SyndFeedOutput.java b/src/main/java/com/sun/syndication/io/SyndFeedOutput.java new file mode 100644 index 0000000..9d3b107 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/SyndFeedOutput.java @@ -0,0 +1,186 @@ +/* + * 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 com.sun.syndication.io; + +import com.sun.syndication.feed.synd.SyndFeed; +import org.jdom.Document; + +import java.io.File; +import java.io.IOException; +import java.io.Writer; + +/** + * Generates an XML document (String, File, OutputStream, Writer, W3C DOM document or JDOM document) + * out of an SyndFeedImpl.. + *

+ * It delegates to a WireFeedOutput to generate all feed types. + *

+ * @author Alejandro Abdelnur + * + */ +public class SyndFeedOutput { + private WireFeedOutput _feedOutput; + + /** + * Creates a SyndFeedOutput instance. + *

+ * + */ + public SyndFeedOutput() { + _feedOutput = new WireFeedOutput(); + } + + /** + * Creates a String with the XML representation for the given SyndFeedImpl. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. It is the responsibility + * of the developer to ensure that if the String is written to a character stream the stream charset is the same as + * the feed encoding property. + *

+ * @param feed Abstract feed to create XML representation from. The type of the SyndFeedImpl must match + * the type given to the FeedOuptut constructor. + * @return a String with the XML representation for the given SyndFeedImpl. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public String outputString(SyndFeed feed) throws FeedException { + return _feedOutput.outputString(feed.createWireFeed()); + } + + /** + * Creates a String with the XML representation for the given SyndFeedImpl. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. It is the responsibility + * of the developer to ensure that if the String is written to a character stream the stream charset is the same as + * the feed encoding property. + *

+ * @param feed Abstract feed to create XML representation from. The type of the SyndFeedImpl must match + * the type given to the FeedOuptut constructor. + * @param prettyPrint pretty-print XML (true) oder collapsed + * @return a String with the XML representation for the given SyndFeedImpl. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public String outputString(SyndFeed feed,boolean prettyPrint) throws FeedException { + return _feedOutput.outputString(feed.createWireFeed(),prettyPrint); + } + + /** + * Creates a File containing with the XML representation for the given SyndFeedImpl. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. The platform + * default charset encoding is used to write the feed to the file. It is the responsibility + * of the developer to ensure the feed encoding is set to the platform charset encoding. + *

+ * @param feed Abstract feed to create XML representation from. The type of the SyndFeedImpl must match + * the type given to the FeedOuptut constructor. + * @param file the file where to write the XML representation for the given SyndFeedImpl. + * @throws IOException thrown if there was some problem writing to the File. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public void output(SyndFeed feed,File file) throws IOException, FeedException { + _feedOutput.output(feed.createWireFeed(),file); + } + + /** + * Creates a File containing with the XML representation for the given SyndFeedImpl. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. The platform + * default charset encoding is used to write the feed to the file. It is the responsibility + * of the developer to ensure the feed encoding is set to the platform charset encoding. + *

+ * @param feed Abstract feed to create XML representation from. The type of the SyndFeedImpl must match + * the type given to the FeedOuptut constructor. + * @param prettyPrint pretty-print XML (true) oder collapsed + * @param file the file where to write the XML representation for the given SyndFeedImpl. + * @throws IOException thrown if there was some problem writing to the File. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public void output(SyndFeed feed,File file,boolean prettyPrint) throws IOException, FeedException { + _feedOutput.output(feed.createWireFeed(),file,prettyPrint); + } + + /** + * Writes to an Writer the XML representation for the given SyndFeedImpl. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. It is the responsibility + * of the developer to ensure that if the String is written to a character stream the stream charset is the same as + * the feed encoding property. + *

+ * @param feed Abstract feed to create XML representation from. The type of the SyndFeedImpl must match + * the type given to the FeedOuptut constructor. + * @param writer Writer to write the XML representation for the given SyndFeedImpl. + * @throws IOException thrown if there was some problem writing to the Writer. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public void output(SyndFeed feed,Writer writer) throws IOException, FeedException { + _feedOutput.output(feed.createWireFeed(),writer); + } + + /** + * Writes to an Writer the XML representation for the given SyndFeedImpl. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. It is the responsibility + * of the developer to ensure that if the String is written to a character stream the stream charset is the same as + * the feed encoding property. + *

+ * @param feed Abstract feed to create XML representation from. The type of the SyndFeedImpl must match + * the type given to the FeedOuptut constructor. + * @param prettyPrint pretty-print XML (true) oder collapsed + * @param writer Writer to write the XML representation for the given SyndFeedImpl. + * @throws IOException thrown if there was some problem writing to the Writer. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public void output(SyndFeed feed,Writer writer,boolean prettyPrint) throws IOException, FeedException { + _feedOutput.output(feed.createWireFeed(),writer,prettyPrint); + } + + /** + * Creates a W3C DOM document for the given SyndFeedImpl. + *

+ * This method does not use the feed encoding property. + *

+ * @param feed Abstract feed to create W3C DOM document from. The type of the SyndFeedImpl must match + * the type given to the FeedOuptut constructor. + * @return the W3C DOM document for the given SyndFeedImpl. + * @throws FeedException thrown if the W3C DOM document for the feed could not be created. + * + */ + public org.w3c.dom.Document outputW3CDom(SyndFeed feed) throws FeedException { + return _feedOutput.outputW3CDom(feed.createWireFeed()); + } + + /** + * Creates a JDOM document for the given SyndFeedImpl. + *

+ * This method does not use the feed encoding property. + *

+ * @param feed Abstract feed to create JDOM document from. The type of the SyndFeedImpl must match + * the type given to the FeedOuptut constructor. + * @return the JDOM document for the given SyndFeedImpl. + * @throws FeedException thrown if the JDOM document for the feed could not be created. + * + */ + public Document outputJDom(SyndFeed feed) throws FeedException { + return _feedOutput.outputJDom(feed.createWireFeed()); + } + +} diff --git a/src/main/java/com/sun/syndication/io/WireFeedGenerator.java b/src/main/java/com/sun/syndication/io/WireFeedGenerator.java new file mode 100644 index 0000000..d1dabbb --- /dev/null +++ b/src/main/java/com/sun/syndication/io/WireFeedGenerator.java @@ -0,0 +1,57 @@ +/* + * 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 com.sun.syndication.io; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.io.FeedException; +import org.jdom.Document; + +/** + * Generates an XML document (JDOM) out of a feed for a specific real feed type. + *

+ * WireFeedGenerator instances must thread safe. + *

+ * TODO: explain how developers can plugin their own implementations. + *

+ * @author Alejandro Abdelnur + * + */ +public interface WireFeedGenerator { + + /** + * Returns the type of feed the generator creates. + *

+ * @see WireFeed for details on the format of this string. + *

+ * @return the type of feed the generator creates. + * + */ + public String getType(); + + /** + * Creates an XML document (JDOM) for the given feed bean. + *

+ * @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; + +} diff --git a/src/main/java/com/sun/syndication/io/WireFeedInput.java b/src/main/java/com/sun/syndication/io/WireFeedInput.java new file mode 100644 index 0000000..3d01c0b --- /dev/null +++ b/src/main/java/com/sun/syndication/io/WireFeedInput.java @@ -0,0 +1,334 @@ +/* + * 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 com.sun.syndication.io; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +import org.jdom.Document; +import org.jdom.JDOMException; +import org.jdom.input.DOMBuilder; +import org.jdom.input.JDOMParseException; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.io.impl.FeedParsers; +import com.sun.syndication.io.impl.XmlFixerReader; + +/** + * Parses an XML document (File, InputStream, Reader, W3C SAX InputSource, W3C DOM Document or JDom DOcument) + * into an WireFeed (RSS/Atom). + *

+ * It accepts all flavors of RSS (0.90, 0.91, 0.92, 0.93, 0.94, 1.0 and 2.0) and + * Atom 0.3 feeds. Parsers are plugable (they must implement the WireFeedParser interface). + *

+ * The WireFeedInput useds liberal parsers. + *

+ * @author Alejandro Abdelnur + * + */ +public class WireFeedInput { + + private static Map clMap = new WeakHashMap(); + + private static FeedParsers getFeedParsers() { + synchronized(WireFeedInput.class) { + FeedParsers parsers = (FeedParsers) + clMap.get(Thread.currentThread().getContextClassLoader()); + if (parsers == null) { + parsers = new FeedParsers(); + clMap.put(Thread.currentThread().getContextClassLoader(), parsers); + } + return parsers; + } + } + + private static final InputSource EMPTY_INPUTSOURCE = new InputSource(new ByteArrayInputStream(new byte[0])); + private static final EntityResolver RESOLVER = new EmptyEntityResolver(); + + private static class EmptyEntityResolver implements EntityResolver { + public InputSource resolveEntity(String publicId, String systemId) { + if(systemId != null && systemId.endsWith(".dtd")) return EMPTY_INPUTSOURCE; + return null; + } + } + + private boolean _validate; + + private boolean _xmlHealerOn; + + /** + * Returns the list of supported input feed types. + *

+ * @see WireFeed for details on the format of these strings. + *

+ * @return a list of String elements with the supported input feed types. + * + */ + public static List getSupportedFeedTypes() { + return getFeedParsers().getSupportedFeedTypes(); + } + + /** + * Creates a WireFeedInput instance with input validation turned off. + *

+ * + */ + public WireFeedInput() { + this (false); + } + + /** + * Creates a WireFeedInput instance. + *

+ * @param validate indicates if the input should be validated. NOT IMPLEMENTED YET (validation does not happen) + * + */ + public WireFeedInput(boolean validate) { + _validate = false; // TODO FIX THIS THINGY + _xmlHealerOn = true; + } + + /** + * Enables XML healing in the WiredFeedInput instance. + *

+ * Healing trims leading chars from the stream (empty spaces and comments) until the XML prolog. + *

+ * Healing resolves HTML entities (from literal to code number) in the reader. + *

+ * The healing is done only with the build(File) and build(Reader) signatures. + *

+ * By default is TRUE. + *

+ * @param heals TRUE enables stream healing, FALSE disables it. + * + */ + public void setXmlHealerOn(boolean heals) { + _xmlHealerOn = heals; + } + + /** + * Indicates if the WiredFeedInput instance will XML heal (if necessary) the character stream. + *

+ * Healing trims leading chars from the stream (empty spaces and comments) until the XML prolog. + *

+ * Healing resolves HTML entities (from literal to code number) in the reader. + *

+ * The healing is done only with the build(File) and build(Reader) signatures. + *

+ * By default is TRUE. + *

+ * @return TRUE if healing is enabled, FALSE if not. + * + */ + public boolean getXmlHealerOn() { + return _xmlHealerOn; + } + + /** + * Builds an WireFeed (RSS or Atom) from a file. + *

+ * NOTE: This method delages to the 'AsbtractFeed WireFeedInput#build(org.jdom.Document)'. + *

+ * @param file file to read to create the WireFeed. + * @return the WireFeed read from the file. + * @throws FileNotFoundException thrown if the file could not be found. + * @throws IOException thrown if there is problem reading the file. + * @throws IllegalArgumentException thrown if feed type could not be understood by any of the underlying parsers. + * @throws FeedException if the feed could not be parsed + * + */ + public WireFeed build(File file) throws FileNotFoundException,IOException,IllegalArgumentException,FeedException { + WireFeed feed; + Reader reader = new FileReader(file); + if (_xmlHealerOn) { + reader = new XmlFixerReader(reader); + } + feed = build(reader); + reader.close(); + return feed; + } + + /** + * Builds an WireFeed (RSS or Atom) from an Reader. + *

+ * NOTE: This method delages to the 'AsbtractFeed WireFeedInput#build(org.jdom.Document)'. + *

+ * @param reader Reader to read to create the WireFeed. + * @return the WireFeed read from the Reader. + * @throws IllegalArgumentException thrown if feed type could not be understood by any of the underlying parsers. + * @throws FeedException if the feed could not be parsed + * + */ + public WireFeed build(Reader reader) throws IllegalArgumentException,FeedException { + SAXBuilder saxBuilder = createSAXBuilder(); + try { + if (_xmlHealerOn) { + reader = new XmlFixerReader(reader); + } + Document document = saxBuilder.build(reader); + return build(document); + } + catch (JDOMParseException ex) { + throw new ParsingFeedException("Invalid XML: " + ex.getMessage(), ex); + } + catch (IllegalArgumentException ex) { + throw ex; + } + catch (Exception ex) { + throw new ParsingFeedException("Invalid XML",ex); + } + } + + /** + * Builds an WireFeed (RSS or Atom) from an W3C SAX InputSource. + *

+ * NOTE: This method delages to the 'AsbtractFeed WireFeedInput#build(org.jdom.Document)'. + *

+ * @param is W3C SAX InputSource to read to create the WireFeed. + * @return the WireFeed read from the W3C SAX InputSource. + * @throws IllegalArgumentException thrown if feed type could not be understood by any of the underlying parsers. + * @throws FeedException if the feed could not be parsed + * + */ + public WireFeed build(InputSource is) throws IllegalArgumentException,FeedException { + SAXBuilder saxBuilder = createSAXBuilder(); + try { + Document document = saxBuilder.build(is); + return build(document); + } + catch (JDOMParseException ex) { + throw new ParsingFeedException("Invalid XML: " + ex.getMessage(), ex); + } + catch (IllegalArgumentException ex) { + throw ex; + } + catch (Exception ex) { + throw new ParsingFeedException("Invalid XML",ex); + } + } + + /** + * Builds an WireFeed (RSS or Atom) from an W3C DOM document. + *

+ * NOTE: This method delages to the 'AsbtractFeed WireFeedInput#build(org.jdom.Document)'. + *

+ * @param document W3C DOM document to read to create the WireFeed. + * @return the WireFeed read from the W3C DOM document. + * @throws IllegalArgumentException thrown if feed type could not be understood by any of the underlying parsers. + * @throws FeedException if the feed could not be parsed + * + */ + public WireFeed build(org.w3c.dom.Document document) throws IllegalArgumentException,FeedException { + DOMBuilder domBuilder = new DOMBuilder(); + try { + Document jdomDoc = domBuilder.build(document); + return build(jdomDoc); + } + catch (IllegalArgumentException ex) { + throw ex; + } + catch (Exception ex) { + throw new ParsingFeedException("Invalid XML",ex); + } + } + + /** + * Builds an WireFeed (RSS or Atom) from an JDOM document. + *

+ * NOTE: All other build methods delegate to this method. + *

+ * @param document JDOM document to read to create the WireFeed. + * @return the WireFeed read from the JDOM document. + * @throws IllegalArgumentException thrown if feed type could not be understood by any of the underlying parsers. + * @throws FeedException if the feed could not be parsed + * + */ + public WireFeed build(Document document) throws IllegalArgumentException,FeedException { + WireFeedParser parser = getFeedParsers().getParserFor(document); + if (parser==null) { + throw new IllegalArgumentException("Invalid document"); + } + return parser.parse(document, _validate); + } + + /** + * Creates and sets up a org.jdom.input.SAXBuilder for parsing. + * + * @return a new org.jdom.input.SAXBuilder object + */ + protected SAXBuilder createSAXBuilder() { + SAXBuilder saxBuilder = new SAXBuilder(_validate); + saxBuilder.setEntityResolver(RESOLVER); + + // + // This code is needed to fix the security problem outlined in http://www.securityfocus.com/archive/1/297714 + // + // Unfortunately there isn't an easy way to check if an XML parser supports a particular feature, so + // we need to set it and catch the exception if it fails. We also need to subclass the JDom SAXBuilder + // class in order to get access to the underlying SAX parser - otherwise the features don't get set until + // we are already building the document, by which time it's too late to fix the problem. + // + // Crimson is one parser which is known not to support these features. + try { + XMLReader parser = saxBuilder.createParser(); + try { + parser.setFeature("http://xml.org/sax/features/external-general-entities", false); + saxBuilder.setFeature("http://xml.org/sax/features/external-general-entities", false); + } catch (SAXNotRecognizedException e) { + // ignore + } catch (SAXNotSupportedException e) { + // ignore + } + + try { + parser.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + saxBuilder.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } catch (SAXNotRecognizedException e) { + // ignore + } catch (SAXNotSupportedException e) { + // ignore + } + + try { + parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + saxBuilder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + } catch (SAXNotRecognizedException e) { + // ignore + } catch (SAXNotSupportedException e) { + // ignore + } + + } catch (JDOMException e) { + throw new IllegalStateException("JDOM could not create a SAX parser"); + } + + saxBuilder.setExpandEntities(false); + return saxBuilder; + } +} diff --git a/src/main/java/com/sun/syndication/io/WireFeedOutput.java b/src/main/java/com/sun/syndication/io/WireFeedOutput.java new file mode 100644 index 0000000..e5872d9 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/WireFeedOutput.java @@ -0,0 +1,274 @@ +/* + * 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 com.sun.syndication.io; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.io.impl.FeedGenerators; +import org.jdom.Document; +import org.jdom.JDOMException; +import org.jdom.output.DOMOutputter; +import org.jdom.output.Format; +import org.jdom.output.XMLOutputter; + +import java.io.IOException; +import java.io.Writer; +import java.io.File; +import java.io.FileWriter; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +/** + * Generates an XML document (String, File, OutputStream, Writer, W3C DOM document or JDOM document) + * out of an WireFeed (RSS/Atom). + *

+ * It generates all flavors of RSS (0.90, 0.91, 0.92, 0.93, 0.94, 1.0 and 2.0) and + * Atom 0.3 feeds. Generators are plugable (they must implement the ModuleParser interface). + *

+ * @author Alejandro Abdelnur + * + */ +public class WireFeedOutput { + private static Map clMap = new WeakHashMap(); + + private static FeedGenerators getFeedGenerators() { + synchronized(WireFeedOutput.class) { + FeedGenerators generators = (FeedGenerators) + clMap.get(Thread.currentThread().getContextClassLoader()); + if (generators == null) { + generators = new FeedGenerators(); + clMap.put(Thread.currentThread().getContextClassLoader(), generators); + } + return generators; + } + } + + /** + * Returns the list of supported output feed types. + *

+ * @see WireFeed for details on the format of these strings. + *

+ * @return a list of String elements with the supported output feed types. + * + */ + public static List getSupportedFeedTypes() { + return getFeedGenerators().getSupportedFeedTypes(); + } + + /** + * Creates a FeedOuput instance. + *

+ * + */ + public WireFeedOutput() { + } + + /** + * Creates a String with the XML representation for the given WireFeed. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. It is the responsibility + * of the developer to ensure that if the String is written to a character stream the stream charset is the same as + * the feed encoding property. + *

+ * NOTE: This method delages to the 'Document WireFeedOutput#outputJDom(WireFeed)'. + *

+ * @param feed Abstract feed to create XML representation from. The type of the WireFeed must match + * the type given to the FeedOuptut constructor. + * @return a String with the XML representation for the given WireFeed. + * @throws IllegalArgumentException thrown if the feed type of the WireFeedOutput and WireFeed don't match. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public String outputString(WireFeed feed) throws IllegalArgumentException,FeedException { + return outputString(feed, true); + } + + /** + * Creates a String with the XML representation for the given WireFeed. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. It is the responsibility + * of the developer to ensure that if the String is written to a character stream the stream charset is the same as + * the feed encoding property. + *

+ * NOTE: This method delages to the 'Document WireFeedOutput#outputJDom(WireFeed)'. + *

+ * @param feed Abstract feed to create XML representation from. The type of the WireFeed must match + * the type given to the FeedOuptut constructor. + * @param prettyPrint pretty-print XML (true) oder collapsed + * @return a String with the XML representation for the given WireFeed. + * @throws IllegalArgumentException thrown if the feed type of the WireFeedOutput and WireFeed don't match. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public String outputString(WireFeed feed, boolean prettyPrint) throws IllegalArgumentException,FeedException { + Document doc = outputJDom(feed); + String encoding = feed.getEncoding(); + Format format = prettyPrint ? Format.getPrettyFormat() : Format.getCompactFormat(); + if (encoding!=null) { + format.setEncoding(encoding); + } + XMLOutputter outputter = new XMLOutputter(format); + return outputter.outputString(doc); + } + + /** + * Creates a File containing with the XML representation for the given WireFeed. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. The platform + * default charset encoding is used to write the feed to the file. It is the responsibility + * of the developer to ensure the feed encoding is set to the platform charset encoding. + *

+ * NOTE: This method delages to the 'Document WireFeedOutput#outputJDom(WireFeed)'. + *

+ * @param feed Abstract feed to create XML representation from. The type of the WireFeed must match + * the type given to the FeedOuptut constructor. + * @param file the file where to write the XML representation for the given WireFeed. + * @throws IllegalArgumentException thrown if the feed type of the WireFeedOutput and WireFeed don't match. + * @throws IOException thrown if there was some problem writing to the File. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public void output(WireFeed feed,File file) throws IllegalArgumentException,IOException,FeedException { + output(feed,file,true); + } + + /** + * Creates a File containing with the XML representation for the given WireFeed. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. The platform + * default charset encoding is used to write the feed to the file. It is the responsibility + * of the developer to ensure the feed encoding is set to the platform charset encoding. + *

+ * NOTE: This method delages to the 'Document WireFeedOutput#outputJDom(WireFeed)'. + *

+ * @param feed Abstract feed to create XML representation from. The type of the WireFeed must match + * the type given to the FeedOuptut constructor. + * @param file the file where to write the XML representation for the given WireFeed. + * @param prettyPrint pretty-print XML (true) oder collapsed + * @throws IllegalArgumentException thrown if the feed type of the WireFeedOutput and WireFeed don't match. + * @throws IOException thrown if there was some problem writing to the File. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public void output(WireFeed feed,File file,boolean prettyPrint) throws IllegalArgumentException,IOException,FeedException { + Writer writer = new FileWriter(file); + output(feed,writer,prettyPrint); + writer.close(); + } + + /** + * Writes to an Writer the XML representation for the given WireFeed. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. It is the responsibility + * of the developer to ensure the Writer instance is using the same charset encoding. + *

+ * NOTE: This method delages to the 'Document WireFeedOutput#outputJDom(WireFeed)'. + *

+ * @param feed Abstract feed to create XML representation from. The type of the WireFeed must match + * the type given to the FeedOuptut constructor. + * @param writer Writer to write the XML representation for the given WireFeed. + * @throws IllegalArgumentException thrown if the feed type of the WireFeedOutput and WireFeed don't match. + * @throws IOException thrown if there was some problem writing to the Writer. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public void output(WireFeed feed,Writer writer) throws IllegalArgumentException,IOException, FeedException { + output(feed,writer,true); + } + + /** + * Writes to an Writer the XML representation for the given WireFeed. + *

+ * If the feed encoding is not NULL, it will be used in the XML prolog encoding attribute. It is the responsibility + * of the developer to ensure the Writer instance is using the same charset encoding. + *

+ * NOTE: This method delages to the 'Document WireFeedOutput#outputJDom(WireFeed)'. + *

+ * @param feed Abstract feed to create XML representation from. The type of the WireFeed must match + * the type given to the FeedOuptut constructor. + * @param writer Writer to write the XML representation for the given WireFeed. + * @param prettyPrint pretty-print XML (true) oder collapsed + * @throws IllegalArgumentException thrown if the feed type of the WireFeedOutput and WireFeed don't match. + * @throws IOException thrown if there was some problem writing to the Writer. + * @throws FeedException thrown if the XML representation for the feed could not be created. + * + */ + public void output(WireFeed feed,Writer writer,boolean prettyPrint) throws IllegalArgumentException,IOException, FeedException { + Document doc = outputJDom(feed); + String encoding = feed.getEncoding(); + Format format = prettyPrint ? Format.getPrettyFormat() : Format.getCompactFormat(); + if (encoding!=null) { + format.setEncoding(encoding); + } + XMLOutputter outputter = new XMLOutputter(format); + outputter.output(doc,writer); + } + + /** + * Creates a W3C DOM document for the given WireFeed. + *

+ * This method does not use the feed encoding property. + *

+ * NOTE: This method delages to the 'Document WireFeedOutput#outputJDom(WireFeed)'. + *

+ * @param feed Abstract feed to create W3C DOM document from. The type of the WireFeed must match + * the type given to the FeedOuptut constructor. + * @return the W3C DOM document for the given WireFeed. + * @throws IllegalArgumentException thrown if the feed type of the WireFeedOutput and WireFeed don't match. + * @throws FeedException thrown if the W3C DOM document for the feed could not be created. + * + */ + public org.w3c.dom.Document outputW3CDom(WireFeed feed) throws IllegalArgumentException,FeedException { + Document doc = outputJDom(feed); + DOMOutputter outputter = new DOMOutputter(); + try { + return outputter.output(doc); + } + catch (JDOMException jdomEx) { + throw new FeedException("Could not create DOM",jdomEx); + } + } + + /** + * Creates a JDOM document for the given WireFeed. + *

+ * This method does not use the feed encoding property. + *

+ * NOTE: All other output methods delegate to this method. + *

+ * @param feed Abstract feed to create JDOM document from. The type of the WireFeed must match + * the type given to the FeedOuptut constructor. + * @return the JDOM document for the given WireFeed. + * @throws IllegalArgumentException thrown if the feed type of the WireFeedOutput and WireFeed don't match. + * @throws FeedException thrown if the JDOM document for the feed could not be created. + * + */ + public Document outputJDom(WireFeed feed) throws IllegalArgumentException,FeedException { + String type = feed.getFeedType(); + WireFeedGenerator generator = getFeedGenerators().getGenerator(type); + if (generator==null) { + throw new IllegalArgumentException("Invalid feed type ["+type+"]"); + } + + if (!generator.getType().equals(type)) { + throw new IllegalArgumentException("WireFeedOutput type["+type+"] and WireFeed type ["+ + type+"] don't match"); + } + return generator.generate(feed); + } + +} diff --git a/src/main/java/com/sun/syndication/io/WireFeedParser.java b/src/main/java/com/sun/syndication/io/WireFeedParser.java new file mode 100644 index 0000000..e5e9af3 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/WireFeedParser.java @@ -0,0 +1,69 @@ +/* + * 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 com.sun.syndication.io; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.io.FeedException; +import org.jdom.Document; + +/** + * Parses an XML document (JDOM) into a feed bean. + *

+ * WireFeedParser instances must thread safe. + *

+ * TODO: explain how developers can plugin their own implementations. + *

+ * @author Alejandro Abdelnur + * + */ +public interface WireFeedParser { + + /** + * Returns the type of feed the parser handles. + *

+ * @see WireFeed for details on the format of this string. + *

+ * @return the type of feed the parser handles. + * + */ + public String getType(); + + /** + * Inspects an XML Document (JDOM) to check if it can parse it. + *

+ * It checks if the given document if the type of feeds the parser understands. + *

+ * @param document XML Document (JDOM) to check if it can be parsed by this parser. + * @return true if the parser know how to parser this feed, false otherwise. + * + */ + public boolean isMyType(Document document); + + /** + * Parses an XML document (JDOM Document) into a feed bean. + *

+ * @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; + + +} diff --git a/src/main/java/com/sun/syndication/io/XmlReader.java b/src/main/java/com/sun/syndication/io/XmlReader.java new file mode 100644 index 0000000..07c7915 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/XmlReader.java @@ -0,0 +1,694 @@ +/* + * 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 com.sun.syndication.io; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.net.HttpURLConnection; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.text.MessageFormat; + +/** + * Character stream that handles (or at least attemtps to) all the necessary Voodo to figure out + * the charset encoding of the XML document within the stream. + *

+ * IMPORTANT: This class is not related in any way to the org.xml.sax.XMLReader. This one IS a + * character stream. + *

+ * All this has to be done without consuming characters from the stream, if not the XML parser + * will not recognized the document as a valid XML. This is not 100% true, but it's close enough + * (UTF-8 BOM is not handled by all parsers right now, XmlReader handles it and things work in all + * parsers). + *

+ * The XmlReader class handles the charset encoding of XML documents in Files, raw streams and + * HTTP streams by offering a wide set of constructors. + *

+ * By default the charset encoding detection is lenient, the constructor with the lenient flag + * can be used for an script (following HTTP MIME and XML specifications). + * All this is nicely explained by Mark Pilgrim in his blog, + * + * Determining the character encoding of a feed. + *

+ * @author Alejandro Abdelnur + * + */ +public class XmlReader extends Reader { + private static final int BUFFER_SIZE = 4096; + + private static final String UTF_8 = "UTF-8"; + private static final String US_ASCII = "US-ASCII"; + private static final String UTF_16BE = "UTF-16BE"; + private static final String UTF_16LE = "UTF-16LE"; + private static final String UTF_16 = "UTF-16"; + + private static String _staticDefaultEncoding = null; + + private Reader _reader; + private String _encoding; + private String _defaultEncoding; + + /** + * Sets the default encoding to use if none is set in HTTP content-type, + * XML prolog and the rules based on content-type are not adequate. + *

+ * If it is set to NULL the content-type based rules are used. + *

+ * By default it is NULL. + *

+ * + * @param encoding charset encoding to default to. + */ + public static void setDefaultEncoding(String encoding) { + _staticDefaultEncoding = encoding; + } + + /** + * Returns the default encoding to use if none is set in HTTP content-type, + * XML prolog and the rules based on content-type are not adequate. + *

+ * If it is NULL the content-type based rules are used. + *

+ * + * @return the default encoding to use. + */ + public static String getDefaultEncoding() { + return _staticDefaultEncoding; + } + + /** + * Creates a Reader for a File. + *

+ * It looks for the UTF-8 BOM first, if none sniffs the XML prolog charset, if this is also + * missing defaults to UTF-8. + *

+ * It does a lenient charset encoding detection, check the constructor with the lenient parameter + * for details. + *

+ * @param file File to create a Reader from. + * @throws IOException thrown if there is a problem reading the file. + * + */ + public XmlReader(File file) throws IOException { + this(new FileInputStream(file)); + } + + /** + * Creates a Reader for a raw InputStream. + *

+ * It follows the same logic used for files. + *

+ * It does a lenient charset encoding detection, check the constructor with the lenient parameter + * for details. + *

+ * @param is InputStream to create a Reader from. + * @throws IOException thrown if there is a problem reading the stream. + * + */ + public XmlReader(InputStream is) throws IOException { + this(is,true); + } + + /** + * Creates a Reader for a raw InputStream and uses the provided default encoding if none is determined. + *

+ * It follows the same logic used for files. + *

+ * If lenient detection is indicated and the detection above fails as per specifications it then attempts + * the following: + *

+ * If the content type was 'text/html' it replaces it with 'text/xml' and tries the detection again. + *

+ * Else if the XML prolog had a charset encoding that encoding is used. + *

+ * Else if the content type had a charset encoding that encoding is used. + *

+ * Else 'UTF-8' is used. + *

+ * If lenient detection is indicated an XmlReaderException is never thrown. + *

+ * @param is InputStream to create a Reader from. + * @param lenient indicates if the charset encoding detection should be relaxed. + * @param defaultEncoding default encoding to use if one cannot be detected. + * @throws IOException thrown if there is a problem reading the stream. + * @throws XmlReaderException thrown if the charset encoding could not be determined according to the specs. + * + */ + public XmlReader(InputStream is, boolean lenient, String defaultEncoding) + throws IOException, XmlReaderException { + _defaultEncoding = (defaultEncoding == null) ? _staticDefaultEncoding : defaultEncoding; + try { + doRawStream(is,lenient); + } + catch (XmlReaderException ex) { + if (!lenient) { + throw ex; + } + else { + doLenientDetection(null,ex); + } + } + } + + /** + * Creates a Reader for a raw InputStream. + *

+ * It follows the same logic used for files. + *

+ * If lenient detection is indicated and the detection above fails as per specifications it then attempts + * the following: + *

+ * If the content type was 'text/html' it replaces it with 'text/xml' and tries the detection again. + *

+ * Else if the XML prolog had a charset encoding that encoding is used. + *

+ * Else if the content type had a charset encoding that encoding is used. + *

+ * Else 'UTF-8' is used. + *

+ * If lenient detection is indicated an XmlReaderException is never thrown. + *

+ * @param is InputStream to create a Reader from. + * @param lenient indicates if the charset encoding detection should be relaxed. + * @throws IOException thrown if there is a problem reading the stream. + * @throws XmlReaderException thrown if the charset encoding could not be determined according to the specs. + * + */ + public XmlReader(InputStream is,boolean lenient) throws IOException, XmlReaderException { + this(is, lenient, null); + } + + /** + * Creates a Reader using the InputStream of a URL. + *

+ * If the URL is not of type HTTP and there is not 'content-type' header in the fetched + * data it uses the same logic used for Files. + *

+ * If the URL is a HTTP Url or there is a 'content-type' header in the fetched + * data it uses the same logic used for an InputStream with content-type. + *

+ * It does a lenient charset encoding detection, check the constructor with the lenient parameter + * for details. + *

+ * @param url URL to create a Reader from. + * @throws IOException thrown if there is a problem reading the stream of the URL. + * + */ + public XmlReader(URL url) throws IOException { + this(url.openConnection()); + } + + /** + * Creates a Reader using the InputStream of a URLConnection. + *

+ * If the URLConnection is not of type HttpURLConnection and there is not + * 'content-type' header in the fetched data it uses the same logic used for files. + *

+ * If the URLConnection is a HTTP Url or there is a 'content-type' header in the fetched + * data it uses the same logic used for an InputStream with content-type. + *

+ * It does a lenient charset encoding detection, check the constructor with the lenient parameter + * for details. + *

+ * @param conn URLConnection to create a Reader from. + * @throws IOException thrown if there is a problem reading the stream of the URLConnection. + * + */ + public XmlReader(URLConnection conn) throws IOException { + _defaultEncoding = _staticDefaultEncoding; + boolean lenient = true; + if (conn instanceof HttpURLConnection) { + try { + doHttpStream(conn.getInputStream(),conn.getContentType(),lenient); + } + catch (XmlReaderException ex) { + doLenientDetection(conn.getContentType(),ex); + } + } + else + if (conn.getContentType()!=null) { + try { + doHttpStream(conn.getInputStream(),conn.getContentType(),lenient); + } + catch (XmlReaderException ex) { + doLenientDetection(conn.getContentType(),ex); + } + } + else { + try { + doRawStream(conn.getInputStream(),lenient); + } + catch (XmlReaderException ex) { + doLenientDetection(null,ex); + } + } + } + + /** + * Creates a Reader using an InputStream and the associated content-type header. + *

+ * First it checks if the stream has BOM. If there is not BOM checks the content-type encoding. + * If there is not content-type encoding checks the XML prolog encoding. If there is not XML + * prolog encoding uses the default encoding mandated by the content-type MIME type. + *

+ * It does a lenient charset encoding detection, check the constructor with the lenient parameter + * for details. + *

+ * @param is InputStream to create the reader from. + * @param httpContentType content-type header to use for the resolution of the charset encoding. + * @throws IOException thrown if there is a problem reading the file. + * + */ + public XmlReader(InputStream is,String httpContentType) throws IOException { + this(is,httpContentType,true); + } + + /** + * Creates a Reader using an InputStream and the associated content-type header. + *

+ * First it checks if the stream has BOM. If there is not BOM checks the content-type encoding. + * If there is not content-type encoding checks the XML prolog encoding. If there is not XML + * prolog encoding uses the default encoding mandated by the content-type MIME type. + *

+ * If lenient detection is indicated and the detection above fails as per specifications it then attempts + * the following: + *

+ * If the content type was 'text/html' it replaces it with 'text/xml' and tries the detection again. + *

+ * Else if the XML prolog had a charset encoding that encoding is used. + *

+ * Else if the content type had a charset encoding that encoding is used. + *

+ * Else 'UTF-8' is used. + *

+ * If lenient detection is indicated and XmlReaderException is never thrown. + *

+ * @param is InputStream to create the reader from. + * @param httpContentType content-type header to use for the resolution of the charset encoding. + * @param lenient indicates if the charset encoding detection should be relaxed. + * @param defaultEncoding default encoding to use if one cannot be detected. + * @throws IOException thrown if there is a problem reading the file. + * @throws XmlReaderException thrown if the charset encoding could not be determined according to the specs. + * + */ + public XmlReader(InputStream is,String httpContentType,boolean lenient, String defaultEncoding) + throws IOException, XmlReaderException { + _defaultEncoding = (defaultEncoding == null) ? _staticDefaultEncoding : defaultEncoding; + try { + doHttpStream(is,httpContentType,lenient); + } + catch (XmlReaderException ex) { + if (!lenient) { + throw ex; + } + else { + doLenientDetection(httpContentType,ex); + } + } + } + + /** + * Creates a Reader using an InputStream and the associated content-type header. + *

+ * First it checks if the stream has BOM. If there is not BOM checks the content-type encoding. + * If there is not content-type encoding checks the XML prolog encoding. If there is not XML + * prolog encoding uses the default encoding mandated by the content-type MIME type. + *

+ * If lenient detection is indicated and the detection above fails as per specifications it then attempts + * the following: + *

+ * If the content type was 'text/html' it replaces it with 'text/xml' and tries the detection again. + *

+ * Else if the XML prolog had a charset encoding that encoding is used. + *

+ * Else if the content type had a charset encoding that encoding is used. + *

+ * Else 'UTF-8' is used. + *

+ * If lenient detection is indicated and XmlReaderException is never thrown. + *

+ * @param is InputStream to create the reader from. + * @param httpContentType content-type header to use for the resolution of the charset encoding. + * @param lenient indicates if the charset encoding detection should be relaxed. + * @throws IOException thrown if there is a problem reading the file. + * @throws XmlReaderException thrown if the charset encoding could not be determined according to the specs. + * + */ + public XmlReader(InputStream is, String httpContentType, boolean lenient) + throws IOException, XmlReaderException { + this(is, httpContentType, lenient, null); + } + + private void doLenientDetection(String httpContentType,XmlReaderException ex) throws IOException { + if (httpContentType!=null) { + if (httpContentType.startsWith("text/html")) { + httpContentType = httpContentType.substring("text/html".length()); + httpContentType = "text/xml" + httpContentType; + try { + doHttpStream(ex.getInputStream(),httpContentType,true); + ex = null; + } + catch (XmlReaderException ex2) { + ex = ex2; + } + } + } + if (ex!=null) { + String encoding = ex.getXmlEncoding(); + if (encoding==null) { + encoding = ex.getContentTypeEncoding(); + } + if (encoding==null) { + encoding = (_defaultEncoding == null) ? UTF_8 : _defaultEncoding; + } + prepareReader(ex.getInputStream(),encoding); + } + } + + /** + * Returns the charset encoding of the XmlReader. + *

+ * @return charset encoding. + * + */ + public String getEncoding() { + return _encoding; + } + + public int read(char[] buf,int offset,int len) throws IOException { + return _reader.read(buf,offset,len); + } + + /** + * Closes the XmlReader stream. + *

+ * @throws IOException thrown if there was a problem closing the stream. + * + */ + public void close() throws IOException { + _reader.close(); + } + + private void doRawStream(InputStream is,boolean lenient) throws IOException { + BufferedInputStream pis = new BufferedInputStream(is, BUFFER_SIZE); + String bomEnc = getBOMEncoding(pis); + String xmlGuessEnc = getXMLGuessEncoding(pis); + String xmlEnc = getXmlProlog(pis,xmlGuessEnc); + String encoding = calculateRawEncoding(bomEnc, xmlGuessEnc, xmlEnc, pis); + prepareReader(pis,encoding); + } + + private void doHttpStream(InputStream is,String httpContentType,boolean lenient) throws IOException { + BufferedInputStream pis = new BufferedInputStream(is, BUFFER_SIZE); + String cTMime = getContentTypeMime(httpContentType); + String cTEnc = getContentTypeEncoding(httpContentType); + String bomEnc = getBOMEncoding(pis); + String xmlGuessEnc = getXMLGuessEncoding(pis); + String xmlEnc = getXmlProlog(pis,xmlGuessEnc); + String encoding = calculateHttpEncoding(cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc, pis,lenient); + prepareReader(pis,encoding); + } + + private void prepareReader(InputStream is,String encoding) throws IOException { + _reader = new InputStreamReader(is,encoding); + _encoding = encoding; + } + + // InputStream is passed for XmlReaderException creation only + private String calculateRawEncoding(String bomEnc, String xmlGuessEnc, String xmlEnc, InputStream is) throws IOException { + String encoding; + if (bomEnc==null) { + if (xmlGuessEnc==null || xmlEnc==null) { + encoding = (_defaultEncoding == null) ? UTF_8 : _defaultEncoding; + } + else + if (xmlEnc.equals(UTF_16) && (xmlGuessEnc.equals(UTF_16BE) || xmlGuessEnc.equals(UTF_16LE))) { + encoding = xmlGuessEnc; + } + else { + encoding = xmlEnc; + } + } + else + if (bomEnc.equals(UTF_8)) { + if (xmlGuessEnc!=null && !xmlGuessEnc.equals(UTF_8)) { + throw new XmlReaderException(RAW_EX_1.format(new Object[]{bomEnc,xmlGuessEnc,xmlEnc}), + bomEnc,xmlGuessEnc,xmlEnc,is); + } + if (xmlEnc!=null && !xmlEnc.equals(UTF_8)) { + throw new XmlReaderException(RAW_EX_1.format(new Object[]{bomEnc,xmlGuessEnc,xmlEnc}), + bomEnc,xmlGuessEnc,xmlEnc,is); + } + encoding = UTF_8; + } + else + if (bomEnc.equals(UTF_16BE) || bomEnc.equals(UTF_16LE)) { + if (xmlGuessEnc!=null && !xmlGuessEnc.equals(bomEnc)) { + throw new IOException(RAW_EX_1.format(new Object[]{bomEnc,xmlGuessEnc,xmlEnc})); + } + if (xmlEnc!=null && !xmlEnc.equals(UTF_16) && !xmlEnc.equals(bomEnc)) { + throw new XmlReaderException(RAW_EX_1.format(new Object[]{bomEnc,xmlGuessEnc,xmlEnc}), + bomEnc,xmlGuessEnc,xmlEnc,is); + } + encoding =bomEnc; + } + else { + throw new XmlReaderException(RAW_EX_2.format(new Object[]{bomEnc,xmlGuessEnc,xmlEnc}), + bomEnc,xmlGuessEnc,xmlEnc,is); + } + return encoding; + } + + // InputStream is passed for XmlReaderException creation only + private String calculateHttpEncoding(String cTMime, String cTEnc, String bomEnc, String xmlGuessEnc, String xmlEnc, InputStream is,boolean lenient) throws IOException { + String encoding; + if (lenient & xmlEnc!=null) { + encoding = xmlEnc; + } + else { + boolean appXml = isAppXml(cTMime); + boolean textXml = isTextXml(cTMime); + if (appXml || textXml) { + if (cTEnc==null) { + if (appXml) { + encoding = calculateRawEncoding(bomEnc, xmlGuessEnc, xmlEnc, is); + } + else { + encoding = (_defaultEncoding == null) ? US_ASCII : _defaultEncoding; + } + } + else + if (bomEnc!=null && (cTEnc.equals(UTF_16BE) || cTEnc.equals(UTF_16LE))) { + throw new XmlReaderException(HTTP_EX_1.format(new Object[]{cTMime,cTEnc,bomEnc,xmlGuessEnc,xmlEnc}), + cTMime,cTEnc,bomEnc,xmlGuessEnc,xmlEnc,is); + } + else + if (cTEnc.equals(UTF_16)) { + if (bomEnc!=null && bomEnc.startsWith(UTF_16)) { + encoding = bomEnc; + } + else { + throw new XmlReaderException(HTTP_EX_2.format(new Object[]{cTMime,cTEnc,bomEnc,xmlGuessEnc,xmlEnc}), + cTMime,cTEnc,bomEnc,xmlGuessEnc,xmlEnc,is); + } + } + else { + encoding = cTEnc; + } + } + else { + throw new XmlReaderException(HTTP_EX_3.format(new Object[]{cTMime,cTEnc,bomEnc,xmlGuessEnc,xmlEnc}), + cTMime,cTEnc,bomEnc,xmlGuessEnc,xmlEnc,is); + } + } + return encoding; + } + + // returns MIME type or NULL if httpContentType is NULL + private static String getContentTypeMime(String httpContentType) { + String mime = null; + if (httpContentType!=null) { + int i = httpContentType.indexOf(";"); + mime = ((i==-1) ? httpContentType : httpContentType.substring(0,i)).trim(); + } + return mime; + } + + private static final Pattern CHARSET_PATTERN = Pattern.compile("charset=([.[^; ]]*)"); + + // returns charset parameter value, NULL if not present, NULL if httpContentType is NULL + private static String getContentTypeEncoding(String httpContentType) { + String encoding = null; + if (httpContentType!=null) { + int i = httpContentType.indexOf(";"); + if (i>-1) { + String postMime = httpContentType.substring(i+1); + Matcher m = CHARSET_PATTERN.matcher(postMime); + encoding = (m.find()) ? m.group(1) : null; + encoding = (encoding!=null) ? encoding.toUpperCase() : null; + } + if (encoding != null && + ((encoding.startsWith("\"") && encoding.endsWith("\"")) || + (encoding.startsWith("'") && encoding.endsWith("'")) + )) { + encoding = encoding.substring(1, encoding.length() - 1); + } + } + return encoding; + } + + // returns the BOM in the stream, NULL if not present, + // if there was BOM the in the stream it is consumed + private static String getBOMEncoding(BufferedInputStream is) throws IOException { + String encoding = null; + int[] bytes = new int[3]; + is.mark(3); + bytes[0] = is.read(); + bytes[1] = is.read(); + bytes[2] = is.read(); + + if (bytes[0] == 0xFE && bytes[1] == 0xFF) { + encoding = UTF_16BE; + is.reset(); + is.read(); + is.read(); + } + else + if (bytes[0] == 0xFF && bytes[1] == 0xFE) { + encoding = UTF_16LE; + is.reset(); + is.read(); + is.read(); + } + else + if (bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) { + encoding = UTF_8; + } + else { + is.reset(); + } + return encoding; + } + + // returns the best guess for the encoding by looking the first bytes of the stream, ', NULL if none + private static String getXmlProlog(BufferedInputStream is,String guessedEnc) throws IOException { + String encoding = null; + if (guessedEnc!=null) { + byte[] bytes = new byte[BUFFER_SIZE]; + is.mark(BUFFER_SIZE); + int offset = 0; + int max = BUFFER_SIZE; + int c = is.read(bytes,offset,max); + int firstGT = -1; + while (c!=-1 && firstGT==-1 && offset< BUFFER_SIZE) { + offset += c; + max -= c; + c = is.read(bytes,offset,max); + firstGT = new String(bytes, 0, offset).indexOf(">"); + } + if (firstGT == -1) { + if (c == -1) { + throw new IOException("Unexpected end of XML stream"); + } + else { + throw new IOException("XML prolog or ROOT element not found on first " + offset + " bytes"); + } + } + int bytesRead = offset; + if (bytesRead>0) { + is.reset(); + Reader reader = new InputStreamReader(new ByteArrayInputStream(bytes,0,firstGT + 1), guessedEnc); + BufferedReader bReader = new BufferedReader(reader); + StringBuffer prolog = new StringBuffer(); + String line = bReader.readLine(); + while (line != null) { + prolog.append(line); + line = bReader.readLine(); + } + Matcher m = ENCODING_PATTERN.matcher(prolog); + if (m.find()) { + encoding = m.group(1).toUpperCase(); + encoding = encoding.substring(1,encoding.length()-1); + } + } + } + return encoding; + } + + // indicates if the MIME type belongs to the APPLICATION XML family + private static boolean isAppXml(String mime) { + return mime!=null && + (mime.equals("application/xml") || + mime.equals("application/xml-dtd") || + mime.equals("application/xml-external-parsed-entity") || + (mime.startsWith("application/") && mime.endsWith("+xml"))); + } + + // indicates if the MIME type belongs to the TEXT XML family + private static boolean isTextXml(String mime) { + return mime!=null && + (mime.equals("text/xml") || + mime.equals("text/xml-external-parsed-entity") || + (mime.startsWith("text/") && mime.endsWith("+xml"))); + } + + private static final MessageFormat RAW_EX_1 = new MessageFormat( + "Invalid encoding, BOM [{0}] XML guess [{1}] XML prolog [{2}] encoding mismatch"); + + private static final MessageFormat RAW_EX_2 = new MessageFormat( + "Invalid encoding, BOM [{0}] XML guess [{1}] XML prolog [{2}] unknown BOM"); + + private static final MessageFormat HTTP_EX_1 = new MessageFormat( + "Invalid encoding, CT-MIME [{0}] CT-Enc [{1}] BOM [{2}] XML guess [{3}] XML prolog [{4}], BOM must be NULL"); + + private static final MessageFormat HTTP_EX_2 = new MessageFormat( + "Invalid encoding, CT-MIME [{0}] CT-Enc [{1}] BOM [{2}] XML guess [{3}] XML prolog [{4}], encoding mismatch"); + + private static final MessageFormat HTTP_EX_3 = new MessageFormat( + "Invalid encoding, CT-MIME [{0}] CT-Enc [{1}] BOM [{2}] XML guess [{3}] XML prolog [{4}], Invalid MIME"); + +} diff --git a/src/main/java/com/sun/syndication/io/XmlReaderException.java b/src/main/java/com/sun/syndication/io/XmlReaderException.java new file mode 100644 index 0000000..62c51c6 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/XmlReaderException.java @@ -0,0 +1,129 @@ +package com.sun.syndication.io; + +import java.io.InputStream; +import java.io.IOException; + +/** + * The XmlReaderException is thrown by the XmlReader constructors if the charset encoding + * can not be determined according to the XML 1.0 specification and RFC 3023. + *

+ * The exception returns the unconsumed InputStream to allow the application to do an + * alternate processing with the stream. Note that the original InputStream given to the + * XmlReader cannot be used as that one has been already read. + *

+ * + * @author Alejandro Abdelnur + * + */ +public class XmlReaderException extends IOException { + private String _bomEncoding; + private String _xmlGuessEncoding; + private String _xmlEncoding; + private String _contentTypeMime; + private String _contentTypeEncoding; + private InputStream _is; + + /** + * Creates an exception instance if the charset encoding could not be determined. + *

+ * Instances of this exception are thrown by the XmlReader. + *

+ * @param msg message describing the reason for the exception. + * @param bomEnc BOM encoding. + * @param xmlGuessEnc XML guess encoding. + * @param xmlEnc XML prolog encoding. + * @param is the unconsumed InputStream. + * + */ + public XmlReaderException(String msg,String bomEnc,String xmlGuessEnc,String xmlEnc,InputStream is) { + this(msg,null,null,bomEnc,xmlGuessEnc,xmlEnc,is); + } + + /** + * Creates an exception instance if the charset encoding could not be determined. + *

+ * Instances of this exception are thrown by the XmlReader. + *

+ * @param msg message describing the reason for the exception. + * @param ctMime MIME type in the content-type. + * @param ctEnc encoding in the content-type. + * @param bomEnc BOM encoding. + * @param xmlGuessEnc XML guess encoding. + * @param xmlEnc XML prolog encoding. + * @param is the unconsumed InputStream. + * + */ + public XmlReaderException(String msg,String ctMime,String ctEnc, + String bomEnc,String xmlGuessEnc,String xmlEnc,InputStream is) { + super(msg); + _contentTypeMime = ctMime; + _contentTypeEncoding = ctEnc; + _bomEncoding = bomEnc; + _xmlGuessEncoding = xmlGuessEnc; + _xmlEncoding = xmlEnc; + _is = is; + } + + /** + * Returns the BOM encoding found in the InputStream. + *

+ * @return the BOM encoding, null if none. + * + */ + public String getBomEncoding() { + return _bomEncoding; + } + + /** + * Returns the encoding guess based on the first bytes of the InputStream. + *

+ * @return the encoding guess, null if it couldn't be guessed. + * + */ + public String getXmlGuessEncoding() { + return _xmlGuessEncoding; + } + + /** + * Returns the encoding found in the XML prolog of the InputStream. + *

+ * @return the encoding of the XML prolog, null if none. + * + */ + public String getXmlEncoding() { + return _xmlEncoding; + } + + /** + * Returns the MIME type in the content-type used to attempt determining the encoding. + *

+ * @return the MIME type in the content-type, null if there was not content-type or the encoding detection + * did not involve HTTP. + * + */ + public String getContentTypeMime() { + return _contentTypeMime; + } + + /** + * Returns the encoding in the content-type used to attempt determining the encoding. + *

+ * @return the encoding in the content-type, null if there was not content-type, no encoding in it + * or the encoding detection did not involve HTTP. + * + */ + public String getContentTypeEncoding() { + return _contentTypeEncoding; + } + + /** + * Returns the unconsumed InputStream to allow the application to do an alternate + * encoding detection on the InputStream. + *

+ * @return the unconsumed InputStream. + * + */ + public InputStream getInputStream() { + return _is; + } +} diff --git a/src/main/java/com/sun/syndication/io/impl/Atom03Generator.java b/src/main/java/com/sun/syndication/io/impl/Atom03Generator.java new file mode 100644 index 0000000..744e334 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/Atom03Generator.java @@ -0,0 +1,365 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.atom.*; +import com.sun.syndication.io.FeedException; +import org.jdom.Attribute; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Namespace; +import org.jdom.input.SAXBuilder; + +import java.io.StringReader; +import java.util.List; + +/** + * Feed Generator for Atom + *

+ * + * @author Elaine Chien + * + */ + +public class Atom03Generator extends BaseWireFeedGenerator { + private static final String ATOM_03_URI = "http://purl.org/atom/ns#"; + private static final Namespace ATOM_NS = Namespace.getNamespace(ATOM_03_URI); + + private String _version; + + public Atom03Generator() { + this("atom_0.3","0.3"); + } + + protected Atom03Generator(String type,String version) { + super(type); + _version = version; + } + + protected String getVersion() { + return _version; + } + + protected Namespace getFeedNamespace() { + return ATOM_NS; + } + + public Document generate(WireFeed wFeed) throws FeedException { + Feed feed = (Feed) wFeed; + Element root = createRootElement(feed); + populateFeed(feed,root); + purgeUnusedNamespaceDeclarations(root); + return createDocument(root); + } + + protected Document createDocument(Element root) { + return new Document(root); + } + + protected Element createRootElement(Feed feed) { + Element root = new Element("feed",getFeedNamespace()); + root.addNamespaceDeclaration(getFeedNamespace()); + Attribute version = new Attribute("version", getVersion()); + root.setAttribute(version); + generateModuleNamespaceDefs(root); + return root; + } + + protected void populateFeed(Feed feed,Element parent) throws FeedException { + addFeed(feed,parent); + addEntries(feed,parent); + } + + protected void addFeed(Feed feed, Element parent) throws FeedException { + Element eFeed = parent; + populateFeedHeader(feed,eFeed); + checkFeedHeaderConstraints(eFeed); + generateFeedModules(feed.getModules(),eFeed); + generateForeignMarkup(eFeed, (List)feed.getForeignMarkup()); + } + + protected void addEntries(Feed feed,Element parent) throws FeedException { + List items = feed.getEntries(); + for (int i=0;i 0) { + Element authorElement = new Element("author", getFeedNamespace()); + fillPersonElement(authorElement, (Person)feed.getAuthors().get(0)); + eFeed.addContent(authorElement); + } + + List contributors = feed.getContributors(); + for (int i = 0; i < contributors.size(); i++) { + Element contributorElement = new Element("contributor", getFeedNamespace()); + fillPersonElement(contributorElement, (Person)contributors.get(i)); + eFeed.addContent(contributorElement); + } + + if (feed.getTagline() != null) { + Element taglineElement = new Element("tagline", getFeedNamespace()); + fillContentElement(taglineElement, feed.getTagline()); + eFeed.addContent(taglineElement); + } + + if (feed.getId() != null) { + eFeed.addContent(generateSimpleElement("id", feed.getId())); + } + + if (feed.getGenerator() != null) { + eFeed.addContent(generateGeneratorElement(feed.getGenerator())); + } + + if (feed.getCopyright() != null) { + eFeed.addContent(generateSimpleElement("copyright", feed.getCopyright())); + } + + if (feed.getInfo() != null) { + Element infoElement = new Element("info", getFeedNamespace()); + fillContentElement(infoElement, feed.getInfo()); + eFeed.addContent(infoElement); + } + + if (feed.getModified() != null) { + Element modifiedElement = new Element("modified", getFeedNamespace()); + modifiedElement.addContent(DateParser.formatW3CDateTime(feed.getModified())); + eFeed.addContent(modifiedElement); + } + } + + protected void populateEntry(Entry entry, Element eEntry) throws FeedException { + if (entry.getTitleEx() != null) { + Element titleElement = new Element("title", getFeedNamespace()); + fillContentElement(titleElement, entry.getTitleEx()); + eEntry.addContent(titleElement); + } + List links = entry.getAlternateLinks(); + for (int i = 0; i < links.size(); i++) { + eEntry.addContent(generateLinkElement((Link)links.get(i))); + } + + links = entry.getOtherLinks(); + for (int i = 0; i < links.size(); i++) { + eEntry.addContent(generateLinkElement((Link)links.get(i))); + } + + if (entry.getAuthors()!=null && entry.getAuthors().size() > 0) { + Element authorElement = new Element("author", getFeedNamespace()); + fillPersonElement(authorElement, (Person)entry.getAuthors().get(0)); + eEntry.addContent(authorElement); + } + + List contributors = entry.getContributors(); + for (int i = 0; i < contributors.size(); i++) { + Element contributorElement = new Element("contributor", getFeedNamespace()); + fillPersonElement(contributorElement, (Person)contributors.get(i)); + eEntry.addContent(contributorElement); + } + if (entry.getId() != null) { + eEntry.addContent(generateSimpleElement("id", entry.getId())); + } + + if (entry.getModified() != null) { + Element modifiedElement = new Element("modified", getFeedNamespace()); + modifiedElement.addContent(DateParser.formatW3CDateTime(entry.getModified())); + eEntry.addContent(modifiedElement); + } + + if (entry.getIssued() != null) { + Element issuedElement = new Element("issued", getFeedNamespace()); + issuedElement.addContent(DateParser.formatW3CDateTime(entry.getIssued())); + eEntry.addContent(issuedElement); + } + + if (entry.getCreated() != null) { + Element createdElement = new Element("created", getFeedNamespace()); + createdElement.addContent(DateParser.formatW3CDateTime(entry.getCreated())); + eEntry.addContent(createdElement); + } + + if (entry.getSummary() != null) { + Element summaryElement = new Element("summary", getFeedNamespace()); + fillContentElement(summaryElement, entry.getSummary()); + eEntry.addContent(summaryElement); + } + + List contents = entry.getContents(); + for (int i = 0; i < contents.size(); i++) { + Element contentElement = new Element("content", getFeedNamespace()); + fillContentElement(contentElement, (Content)contents.get(i)); + eEntry.addContent(contentElement); + } + + generateForeignMarkup(eEntry, (List)entry.getForeignMarkup()); + } + + protected void checkFeedHeaderConstraints(Element eFeed) throws FeedException { + } + + protected void checkEntriesConstraints(Element parent) throws FeedException { + } + + protected void checkEntryConstraints(Element eEntry) throws FeedException { + } + + + protected Element generateLinkElement(Link link) { + Element linkElement = new Element("link", getFeedNamespace()); + + if (link.getRel() != null) { + Attribute relAttribute = new Attribute("rel", link.getRel().toString()); + linkElement.setAttribute(relAttribute); + } + + if (link.getType() != null) { + Attribute typeAttribute = new Attribute("type", link.getType()); + linkElement.setAttribute(typeAttribute); + } + + if (link.getHref() != null) { + Attribute hrefAttribute = new Attribute("href", link.getHref()); + linkElement.setAttribute(hrefAttribute); + } + return linkElement; + } + + + protected void fillPersonElement(Element element, Person person) { + if (person.getName() != null) { + element.addContent(generateSimpleElement("name", person.getName())); + } + if (person.getUrl() != null) { + element.addContent(generateSimpleElement("url", person.getUrl())); + } + + if (person.getEmail() != null) { + element.addContent(generateSimpleElement("email", person.getEmail())); + } + } + + protected Element generateTagLineElement(Content tagline) { + Element taglineElement = new Element("tagline", getFeedNamespace()); + + if (tagline.getType() != null) { + Attribute typeAttribute = new Attribute("type", tagline.getType()); + taglineElement.setAttribute(typeAttribute); + } + + if (tagline.getValue() != null) { + taglineElement.addContent(tagline.getValue()); + } + return taglineElement; + } + + protected void fillContentElement(Element contentElement, Content content) + throws FeedException { + + if (content.getType() != null) { + Attribute typeAttribute = new Attribute("type", content.getType()); + contentElement.setAttribute(typeAttribute); + } + + String mode = content.getMode(); + if (mode != null) { + Attribute modeAttribute = new Attribute("mode", content.getMode().toString()); + contentElement.setAttribute(modeAttribute); + } + + if (content.getValue() != null) { + + if (mode == null || mode.equals(Content.ESCAPED)) { + contentElement.addContent(content.getValue()); + } else if (mode.equals(Content.BASE64)) { + contentElement.addContent(Base64.encode(content.getValue())); + } else if (mode.equals(Content.XML)) { + + StringBuffer tmpDocString = new StringBuffer(""); + tmpDocString.append(content.getValue()); + tmpDocString.append(""); + StringReader tmpDocReader = new StringReader(tmpDocString.toString()); + Document tmpDoc; + + try { + SAXBuilder saxBuilder = new SAXBuilder(); + tmpDoc = saxBuilder.build(tmpDocReader); + } + catch (Exception ex) { + throw new FeedException("Invalid XML",ex); + } + + List children = tmpDoc.getRootElement().removeContent(); + contentElement.addContent(children); + } + } + } + + protected Element generateGeneratorElement(Generator generator) { + Element generatorElement = new Element("generator", getFeedNamespace()); + + if (generator.getUrl() != null) { + Attribute urlAttribute = new Attribute("url", generator.getUrl()); + generatorElement.setAttribute(urlAttribute); + } + + if (generator.getVersion() != null) { + Attribute versionAttribute = new Attribute("version", generator.getVersion()); + generatorElement.setAttribute(versionAttribute); + } + + if (generator.getValue() != null) { + generatorElement.addContent(generator.getValue()); + } + + return generatorElement; + + } + + protected Element generateSimpleElement(String name, String value) { + Element element = new Element(name, getFeedNamespace()); + element.addContent(value); + return element; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/Atom03Parser.java b/src/main/java/com/sun/syndication/io/impl/Atom03Parser.java new file mode 100644 index 0000000..6a3770d --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/Atom03Parser.java @@ -0,0 +1,341 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.atom.*; +import com.sun.syndication.io.FeedException; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Namespace; +import org.jdom.output.XMLOutputter; + +import java.util.*; + +/** + */ +public class Atom03Parser extends BaseWireFeedParser { + private static final String ATOM_03_URI = "http://purl.org/atom/ns#"; + private static final Namespace ATOM_03_NS = Namespace.getNamespace(ATOM_03_URI); + + public Atom03Parser() { + this("atom_0.3", ATOM_03_NS); + } + + protected Atom03Parser(String type, Namespace ns) { + super(type, ns); + } + + protected Namespace getAtomNamespace() { + return ATOM_03_NS; + } + + public boolean isMyType(Document document) { + Element rssRoot = document.getRootElement(); + Namespace defaultNS = rssRoot.getNamespace(); + return (defaultNS!=null) && defaultNS.equals(getAtomNamespace()); + } + + public WireFeed parse(Document document, boolean validate) throws IllegalArgumentException,FeedException { + if (validate) { + validateFeed(document); + } + Element rssRoot = document.getRootElement(); + return parseFeed(rssRoot); + } + + protected void validateFeed(Document document) throws FeedException { + // TBD + // here we have to validate the Feed against a schema or whatever + // not sure how to do it + // one posibility would be to produce an ouput and attempt to parse it again + // with validation turned on. + // otherwise will have to check the document elements by hand. + } + + protected WireFeed parseFeed(Element eFeed) { + + com.sun.syndication.feed.atom.Feed feed = new com.sun.syndication.feed.atom.Feed(getType()); + + Element e = eFeed.getChild("title",getAtomNamespace()); + if (e!=null) { + feed.setTitleEx(parseContent(e)); + } + + List eList = eFeed.getChildren("link",getAtomNamespace()); + feed.setAlternateLinks(parseAlternateLinks(eList)); + feed.setOtherLinks(parseOtherLinks(eList)); + + e = eFeed.getChild("author",getAtomNamespace()); + if (e!=null) { + List authors = new ArrayList(); + authors.add(parsePerson(e)); + feed.setAuthors(authors); + } + + eList = eFeed.getChildren("contributor",getAtomNamespace()); + if (eList.size()>0) { + feed.setContributors(parsePersons(eList)); + } + + e = eFeed.getChild("tagline",getAtomNamespace()); + if (e!=null) { + feed.setTagline(parseContent(e)); + } + + e = eFeed.getChild("id",getAtomNamespace()); + if (e!=null) { + feed.setId(e.getText()); + } + + e = eFeed.getChild("generator",getAtomNamespace()); + if (e!=null) { + Generator gen = new Generator(); + gen.setValue(e.getText()); + String att = getAttributeValue(e, "url"); + if (att!=null) { + gen.setUrl(att); + } + att = getAttributeValue(e, "version"); + if (att!=null) { + gen.setVersion(att); + } + feed.setGenerator(gen); + } + + e = eFeed.getChild("copyright",getAtomNamespace()); + if (e!=null) { + feed.setCopyright(e.getText()); + } + + e = eFeed.getChild("info",getAtomNamespace()); + if (e!=null) { + feed.setInfo(parseContent(e)); + } + + e = eFeed.getChild("modified",getAtomNamespace()); + if (e!=null) { + feed.setModified(DateParser.parseDate(e.getText())); + } + + feed.setModules(parseFeedModules(eFeed)); + + eList = eFeed.getChildren("entry",getAtomNamespace()); + if (eList.size()>0) { + feed.setEntries(parseEntries(eList)); + } + + List foreignMarkup = + extractForeignMarkup(eFeed, feed, getAtomNamespace()); + if (foreignMarkup.size() > 0) { + feed.setForeignMarkup(foreignMarkup); + } + return feed; + } + + private Link parseLink(Element eLink) { + Link link = new Link(); + String att = getAttributeValue(eLink, "rel"); + if (att!=null) { + link.setRel(att); + } + att = getAttributeValue(eLink, "type"); + if (att!=null) { + link.setType(att); + } + att = getAttributeValue(eLink, "href"); + if (att!=null) { + link.setHref(att); + } + return link; + } + + // List(Elements) -> List(Link) + private List parseLinks(List eLinks,boolean alternate) { + List links = new ArrayList(); + for (int i=0;i0) ? links : null; + } + + // List(Elements) -> List(Link) + private List parseAlternateLinks(List eLinks) { + return parseLinks(eLinks,true); + } + + // List(Elements) -> List(Link) + private List parseOtherLinks(List eLinks) { + return parseLinks(eLinks,false); + } + + private Person parsePerson(Element ePerson) { + Person person = new Person(); + Element e = ePerson.getChild("name",getAtomNamespace()); + if (e!=null) { + person.setName(e.getText()); + } + e = ePerson.getChild("url",getAtomNamespace()); + if (e!=null) { + person.setUrl(e.getText()); + } + e = ePerson.getChild("email",getAtomNamespace()); + if (e!=null) { + person.setEmail(e.getText()); + } + return person; + } + + // List(Elements) -> List(Persons) + private List parsePersons(List ePersons) { + List persons = new ArrayList(); + for (int i=0;i0) ? persons : null; + } + + private Content parseContent(Element e) { + String value = null; + String type = getAttributeValue(e, "type"); + type = (type!=null) ? type : "text/plain"; + String mode = getAttributeValue(e, "mode"); + if (mode == null) { + mode = Content.XML; // default to xml content + } + if (mode.equals(Content.ESCAPED)) { + // do nothing XML Parser took care of this + value = e.getText(); + } + else + if (mode.equals(Content.BASE64)) { + value = Base64.decode(e.getText()); + } + else + if (mode.equals(Content.XML)) { + XMLOutputter outputter = new XMLOutputter(); + List eContent = e.getContent(); + Iterator i = eContent.iterator(); + while (i.hasNext()) { + org.jdom.Content c = (org.jdom.Content) i.next(); + if (c instanceof Element) { + Element eC = (Element) c; + if (eC.getNamespace().equals(getAtomNamespace())) { + ((Element)c).setNamespace(Namespace.NO_NAMESPACE); + } + } + } + value = outputter.outputString(eContent); + } + + Content content = new Content(); + content.setType(type); + content.setMode(mode); + content.setValue(value); + return content; + } + + // List(Elements) -> List(Entries) + private List parseEntries(List eEntries) { + List entries = new ArrayList(); + for (int i=0;i0) ? entries : null; + } + + private Entry parseEntry(Element eEntry) { + Entry entry = new Entry(); + + Element e = eEntry.getChild("title",getAtomNamespace()); + if (e!=null) { + entry.setTitleEx(parseContent(e)); + } + + List eList = eEntry.getChildren("link",getAtomNamespace()); + entry.setAlternateLinks(parseAlternateLinks(eList)); + entry.setOtherLinks(parseOtherLinks(eList)); + + e = eEntry.getChild("author",getAtomNamespace()); + if (e!=null) { + List authors = new ArrayList(); + authors.add(parsePerson(e)); + entry.setAuthors(authors); + } + + eList = eEntry.getChildren("contributor",getAtomNamespace()); + if (eList.size()>0) { + entry.setContributors(parsePersons(eList)); + } + + e = eEntry.getChild("id",getAtomNamespace()); + if (e!=null) { + entry.setId(e.getText()); + } + + e = eEntry.getChild("modified",getAtomNamespace()); + if (e!=null) { + entry.setModified(DateParser.parseDate(e.getText())); + } + + e = eEntry.getChild("issued",getAtomNamespace()); + if (e!=null) { + entry.setIssued(DateParser.parseDate(e.getText())); + } + + e = eEntry.getChild("created",getAtomNamespace()); + if (e!=null) { + entry.setCreated(DateParser.parseDate(e.getText())); + } + + e = eEntry.getChild("summary",getAtomNamespace()); + if (e!=null) { + entry.setSummary(parseContent(e)); + } + + eList = eEntry.getChildren("content",getAtomNamespace()); + if (eList.size()>0) { + List content = new ArrayList(); + for (int i=0;i 0) { + entry.setForeignMarkup(foreignMarkup); + } + return entry; + } + + +} diff --git a/src/main/java/com/sun/syndication/io/impl/Atom10Generator.java b/src/main/java/com/sun/syndication/io/impl/Atom10Generator.java new file mode 100644 index 0000000..f074f67 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/Atom10Generator.java @@ -0,0 +1,473 @@ +/* + * 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 com.sun.syndication.io.impl; + +import java.io.StringReader; +import java.util.Iterator; +import java.util.List; + +import org.jdom.Attribute; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Namespace; +import org.jdom.input.SAXBuilder; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.atom.Category; +import com.sun.syndication.feed.atom.Content; +import com.sun.syndication.feed.atom.Entry; +import com.sun.syndication.feed.atom.Feed; +import com.sun.syndication.feed.atom.Generator; +import com.sun.syndication.feed.atom.Link; +import com.sun.syndication.feed.atom.Person; +import com.sun.syndication.io.FeedException; +import com.sun.syndication.io.WireFeedOutput; +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import org.jdom.output.XMLOutputter; + +/** + * Feed Generator for Atom + *

+ * + * @author Elaine Chien + * @author Dave Johnson (updated for Atom 1.0) + * + */ + +public class Atom10Generator extends BaseWireFeedGenerator { + private static final String ATOM_10_URI = "http://www.w3.org/2005/Atom"; + private static final Namespace ATOM_NS = Namespace.getNamespace(ATOM_10_URI); + + private String _version; + + public Atom10Generator() { + this("atom_1.0","1.0"); + } + + protected Atom10Generator(String type,String version) { + super(type); + _version = version; + } + + protected String getVersion() { + return _version; + } + + protected Namespace getFeedNamespace() { + return ATOM_NS; + } + + public Document generate(WireFeed wFeed) throws FeedException { + Feed feed = (Feed) wFeed; + Element root = createRootElement(feed); + populateFeed(feed,root); + purgeUnusedNamespaceDeclarations(root); + return createDocument(root); + } + + protected Document createDocument(Element root) { + return new Document(root); + } + + protected Element createRootElement(Feed feed) { + Element root = new Element("feed",getFeedNamespace()); + root.addNamespaceDeclaration(getFeedNamespace()); + //Attribute version = new Attribute("version", getVersion()); + //root.setAttribute(version); + if (feed.getXmlBase() != null) { + root.setAttribute("base", feed.getXmlBase(), Namespace.XML_NAMESPACE); + } + generateModuleNamespaceDefs(root); + return root; + } + + protected void populateFeed(Feed feed,Element parent) throws FeedException { + addFeed(feed,parent); + addEntries(feed,parent); + } + + protected void addFeed(Feed feed,Element parent) throws FeedException { + Element eFeed = parent; + populateFeedHeader(feed,eFeed); + generateForeignMarkup(eFeed, (List)feed.getForeignMarkup()); + checkFeedHeaderConstraints(eFeed); + generateFeedModules(feed.getModules(),eFeed); + } + + protected void addEntries(Feed feed,Element parent) throws FeedException { + List items = feed.getEntries(); + for (int i=0;i 0) { + for (int i = 0; i < authors.size(); i++) { + Element authorElement = new Element("author", getFeedNamespace()); + fillPersonElement(authorElement, (Person)feed.getAuthors().get(i)); + eFeed.addContent(authorElement); + } + } + + List contributors = feed.getContributors(); + if (contributors != null && contributors.size() > 0) { + for (int i = 0; i < contributors.size(); i++) { + Element contributorElement = new Element("contributor", getFeedNamespace()); + fillPersonElement(contributorElement, (Person)contributors.get(i)); + eFeed.addContent(contributorElement); + } + } + + if (feed.getSubtitle() != null) { + Element subtitleElement = new Element("subtitle", getFeedNamespace()); + fillContentElement(subtitleElement, feed.getSubtitle()); + eFeed.addContent(subtitleElement); + } + + if (feed.getId() != null) { + eFeed.addContent(generateSimpleElement("id", feed.getId())); + } + + if (feed.getGenerator() != null) { + eFeed.addContent(generateGeneratorElement(feed.getGenerator())); + } + + if (feed.getRights() != null) { + eFeed.addContent(generateSimpleElement("rights", feed.getRights())); + } + + if (feed.getIcon() != null) { + eFeed.addContent(generateSimpleElement("icon", feed.getIcon())); + } + + if (feed.getLogo() != null) { + eFeed.addContent(generateSimpleElement("logo", feed.getLogo())); + } + + if (feed.getUpdated() != null) { + Element updatedElement = new Element("updated", getFeedNamespace()); + updatedElement.addContent(DateParser.formatW3CDateTime(feed.getUpdated())); + eFeed.addContent(updatedElement); + } + } + + protected void populateEntry(Entry entry, Element eEntry) throws FeedException { + if (entry.getTitleEx() != null) { + Element titleElement = new Element("title", getFeedNamespace()); + fillContentElement(titleElement, entry.getTitleEx()); + eEntry.addContent(titleElement); + } + List links = entry.getAlternateLinks(); + if (links != null) { + for (int i = 0; i < links.size(); i++) { + eEntry.addContent(generateLinkElement((Link)links.get(i))); + } + } + links = entry.getOtherLinks(); + if (links != null) { + for (int i = 0; i < links.size(); i++) { + eEntry.addContent(generateLinkElement((Link)links.get(i))); + } + } + + List cats = entry.getCategories(); + if (cats != null) { + for (int i = 0; i < cats.size(); i++) { + eEntry.addContent(generateCategoryElement((Category)cats.get(i))); + } + } + + List authors = entry.getAuthors(); + if (authors != null && authors.size() > 0) { + for (int i = 0; i < authors.size(); i++) { + Element authorElement = new Element("author", getFeedNamespace()); + fillPersonElement(authorElement, (Person)entry.getAuthors().get(i)); + eEntry.addContent(authorElement); + } + } + + List contributors = entry.getContributors(); + if (contributors != null && contributors.size() > 0) { + for (int i = 0; i < contributors.size(); i++) { + Element contributorElement = new Element("contributor", getFeedNamespace()); + fillPersonElement(contributorElement, (Person)contributors.get(i)); + eEntry.addContent(contributorElement); + } + } + if (entry.getId() != null) { + eEntry.addContent(generateSimpleElement("id", entry.getId())); + } + + if (entry.getUpdated() != null) { + Element updatedElement = new Element("updated", getFeedNamespace()); + updatedElement.addContent(DateParser.formatW3CDateTime(entry.getUpdated())); + eEntry.addContent(updatedElement); + } + + if (entry.getPublished() != null) { + Element publishedElement = new Element("published", getFeedNamespace()); + publishedElement.addContent(DateParser.formatW3CDateTime(entry.getPublished())); + eEntry.addContent(publishedElement); + } + + if (entry.getContents() != null && entry.getContents().size() > 0) { + Element contentElement = new Element("content", getFeedNamespace()); + Content content = (Content)entry.getContents().get(0); + fillContentElement(contentElement, content); + eEntry.addContent(contentElement); + } + + if (entry.getSummary() != null) { + Element summaryElement = new Element("summary", getFeedNamespace()); + fillContentElement(summaryElement, entry.getSummary()); + eEntry.addContent(summaryElement); + } + + if (entry.getSource() != null) { + Element sourceElement = new Element("source", getFeedNamespace()); + populateFeedHeader(entry.getSource(), sourceElement); + eEntry.addContent(sourceElement); + } + } + + protected void checkFeedHeaderConstraints(Element eFeed) throws FeedException { + } + + protected void checkEntriesConstraints(Element parent) throws FeedException { + } + + protected void checkEntryConstraints(Element eEntry) throws FeedException { + } + + + protected Element generateCategoryElement(Category cat) { + Element catElement = new Element("category", getFeedNamespace()); + + if (cat.getTerm() != null) { + Attribute termAttribute = new Attribute("term", cat.getTerm()); + catElement.setAttribute(termAttribute); + } + + if (cat.getLabel() != null) { + Attribute labelAttribute = new Attribute("label", cat.getLabel()); + catElement.setAttribute(labelAttribute); + } + + if (cat.getScheme() != null) { + Attribute schemeAttribute = new Attribute("scheme", cat.getScheme()); + catElement.setAttribute(schemeAttribute); + } + return catElement; + } + + protected Element generateLinkElement(Link link) { + Element linkElement = new Element("link", getFeedNamespace()); + + if (link.getRel() != null) { + Attribute relAttribute = new Attribute("rel", link.getRel()); + linkElement.setAttribute(relAttribute); + } + + if (link.getType() != null) { + Attribute typeAttribute = new Attribute("type", link.getType()); + linkElement.setAttribute(typeAttribute); + } + + if (link.getHref() != null) { + Attribute hrefAttribute = new Attribute("href", link.getHref()); + linkElement.setAttribute(hrefAttribute); + } + + if (link.getHreflang() != null) { + Attribute hreflangAttribute = new Attribute("hreflang", link.getHreflang()); + linkElement.setAttribute(hreflangAttribute); + } + if (link.getTitle() != null) { + Attribute title = new Attribute("title", link.getTitle()); + linkElement.setAttribute(title); + } + if (link.getLength() != 0) { + Attribute lenght = new Attribute("length", Long.toString(link.getLength())); + linkElement.setAttribute(lenght); + } + return linkElement; + } + + + protected void fillPersonElement(Element element, Person person) { + if (person.getName() != null) { + element.addContent(generateSimpleElement("name", person.getName())); + } + if (person.getUri() != null) { + element.addContent(generateSimpleElement("uri", person.getUri())); + } + + if (person.getEmail() != null) { + element.addContent(generateSimpleElement("email", person.getEmail())); + } + generatePersonModules(person.getModules(), element); + } + + protected Element generateTagLineElement(Content tagline) { + Element taglineElement = new Element("subtitle", getFeedNamespace()); + + if (tagline.getType() != null) { + Attribute typeAttribute = new Attribute("type", tagline.getType()); + taglineElement.setAttribute(typeAttribute); + } + + if (tagline.getValue() != null) { + taglineElement.addContent(tagline.getValue()); + } + return taglineElement; + } + + protected void fillContentElement(Element contentElement, Content content) + throws FeedException { + + String type = content.getType(); + String atomType = type; + if (type != null) { + // Fix for issue #39 "Atom 1.0 Text Types Not Set Correctly" + // we're not sure who set this value, so ensure Atom types are used + if ("text/plain".equals(type)) atomType = Content.TEXT; + else if ("text/html".equals(type)) atomType = Content.HTML; + else if ("application/xhtml+xml".equals(type)) atomType = Content.XHTML; + + Attribute typeAttribute = new Attribute("type", atomType); + contentElement.setAttribute(typeAttribute); + } + String href = content.getSrc(); + if (href != null) { + Attribute srcAttribute = new Attribute("src", href); + contentElement.setAttribute(srcAttribute); + } + if (content.getValue() != null) { + if (atomType != null && (atomType.equals(Content.XHTML) || (atomType.indexOf("/xml")) != -1 || + (atomType.indexOf("+xml")) != -1)) { + + StringBuffer tmpDocString = new StringBuffer(""); + tmpDocString.append(content.getValue()); + tmpDocString.append(""); + StringReader tmpDocReader = new StringReader(tmpDocString.toString()); + Document tmpDoc; + try { + SAXBuilder saxBuilder = new SAXBuilder(); + tmpDoc = saxBuilder.build(tmpDocReader); + } + catch (Exception ex) { + throw new FeedException("Invalid XML",ex); + } + List children = tmpDoc.getRootElement().removeContent(); + contentElement.addContent(children); + } else { + // must be type html, text or some other non-XML format + // JDOM will escape property for XML + contentElement.addContent(content.getValue()); + } + } + } + + protected Element generateGeneratorElement(Generator generator) { + Element generatorElement = new Element("generator", getFeedNamespace()); + + if (generator.getUrl() != null) { + Attribute urlAttribute = new Attribute("uri", generator.getUrl()); + generatorElement.setAttribute(urlAttribute); + } + + if (generator.getVersion() != null) { + Attribute versionAttribute = new Attribute("version", generator.getVersion()); + generatorElement.setAttribute(versionAttribute); + } + + if (generator.getValue() != null) { + generatorElement.addContent(generator.getValue()); + } + + return generatorElement; + + } + + protected Element generateSimpleElement(String name, String value) { + Element element = new Element(name, getFeedNamespace()); + element.addContent(value); + return element; + } + + /** + * Utility method to serialize an entry to writer. + */ + public static void serializeEntry(Entry entry, Writer writer) + throws IllegalArgumentException, FeedException, IOException { + + // Build a feed containing only the entry + List entries = new ArrayList(); + entries.add(entry); + Feed feed1 = new Feed(); + feed1.setFeedType("atom_1.0"); + feed1.setEntries(entries); + + // Get Rome to output feed as a JDOM document + WireFeedOutput wireFeedOutput = new WireFeedOutput(); + Document feedDoc = wireFeedOutput.outputJDom(feed1); + + // Grab entry element from feed and get JDOM to serialize it + Element entryElement= (Element)feedDoc.getRootElement().getChildren().get(0); + + XMLOutputter outputter = new XMLOutputter(); + outputter.output(entryElement, writer); + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/Atom10Parser.java b/src/main/java/com/sun/syndication/io/impl/Atom10Parser.java new file mode 100644 index 0000000..1468c0e --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/Atom10Parser.java @@ -0,0 +1,655 @@ +/* + * 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 com.sun.syndication.io.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Namespace; +import org.jdom.output.XMLOutputter; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.atom.Category; +import com.sun.syndication.feed.atom.Content; +import com.sun.syndication.feed.atom.Entry; +import com.sun.syndication.feed.atom.Feed; +import com.sun.syndication.feed.atom.Generator; +import com.sun.syndication.feed.atom.Link; +import com.sun.syndication.feed.atom.Person; +import com.sun.syndication.io.FeedException; +import com.sun.syndication.io.WireFeedInput; +import com.sun.syndication.io.WireFeedOutput; +import java.io.IOException; +import java.io.Reader; +import java.net.MalformedURLException; +import java.util.regex.Pattern; +import org.jdom.Attribute; +import org.jdom.JDOMException; +import org.jdom.Parent; +import org.jdom.input.SAXBuilder; + +/** + * Parser for Atom 1.0 + * @author Dave Johnson + */ +public class Atom10Parser extends BaseWireFeedParser { + private static final String ATOM_10_URI = "http://www.w3.org/2005/Atom"; + private static final Namespace ATOM_10_NS = Namespace.getNamespace(ATOM_10_URI); + + private static boolean resolveURIs = false; + + public static void setResolveURIs(boolean resolveURIs) { + Atom10Parser.resolveURIs = resolveURIs; + } + + public static boolean getResolveURIs() { + return resolveURIs; + } + + public Atom10Parser() { + this("atom_1.0"); + } + + protected Atom10Parser(String type) { + super(type, ATOM_10_NS); + } + + protected Namespace getAtomNamespace() { + return ATOM_10_NS; + } + + public boolean isMyType(Document document) { + Element rssRoot = document.getRootElement(); + Namespace defaultNS = rssRoot.getNamespace(); + return (defaultNS!=null) && defaultNS.equals(getAtomNamespace()); + } + + public WireFeed parse(Document document, boolean validate) + throws IllegalArgumentException,FeedException { + if (validate) { + validateFeed(document); + } + Element rssRoot = document.getRootElement(); + return parseFeed(rssRoot); + } + + protected void validateFeed(Document document) throws FeedException { + // TBD + // here we have to validate the Feed against a schema or whatever + // not sure how to do it + // one posibility would be to produce an ouput and attempt to parse it again + // with validation turned on. + // otherwise will have to check the document elements by hand. + } + + protected WireFeed parseFeed(Element eFeed) throws FeedException { + + String baseURI = null; + try { + baseURI = findBaseURI(eFeed); + } catch (Exception e) { + throw new FeedException("ERROR while finding base URI of feed", e); + } + + Feed feed = parseFeedMetadata(baseURI, eFeed); + + String xmlBase = eFeed.getAttributeValue("base", Namespace.XML_NAMESPACE); + if (xmlBase != null) { + feed.setXmlBase(xmlBase); + } + + feed.setModules(parseFeedModules(eFeed)); + + List eList = eFeed.getChildren("entry",getAtomNamespace()); + if (eList.size()>0) { + feed.setEntries(parseEntries(feed, baseURI, eList)); + } + + List foreignMarkup = + extractForeignMarkup(eFeed, feed, getAtomNamespace()); + if (foreignMarkup.size() > 0) { + feed.setForeignMarkup(foreignMarkup); + } + return feed; + } + + private Feed parseFeedMetadata(String baseURI, Element eFeed) { + com.sun.syndication.feed.atom.Feed feed = + new com.sun.syndication.feed.atom.Feed(getType()); + + Element e = eFeed.getChild("title",getAtomNamespace()); + if (e!=null) { + Content c = new Content(); + c.setValue(parseTextConstructToString(e)); + c.setType(getAttributeValue(e, "type")); + feed.setTitleEx(c); + } + + List eList = eFeed.getChildren("link",getAtomNamespace()); + feed.setAlternateLinks(parseAlternateLinks(feed, null, baseURI, eList)); + feed.setOtherLinks(parseOtherLinks(feed, null, baseURI, eList)); + + List cList = eFeed.getChildren("category",getAtomNamespace()); + feed.setCategories(parseCategories(baseURI, cList)); + + eList = eFeed.getChildren("author", getAtomNamespace()); + if (eList.size()>0) { + feed.setAuthors(parsePersons(baseURI, eList)); + } + + eList = eFeed.getChildren("contributor",getAtomNamespace()); + if (eList.size()>0) { + feed.setContributors(parsePersons(baseURI, eList)); + } + + e = eFeed.getChild("subtitle",getAtomNamespace()); + if (e!=null) { + Content subtitle = new Content(); + subtitle.setValue(parseTextConstructToString(e)); + subtitle.setType(getAttributeValue(e, "type")); + feed.setSubtitle(subtitle); + } + + e = eFeed.getChild("id",getAtomNamespace()); + if (e!=null) { + feed.setId(e.getText()); + } + + e = eFeed.getChild("generator",getAtomNamespace()); + if (e!=null) { + Generator gen = new Generator(); + gen.setValue(e.getText()); + String att = getAttributeValue(e, "uri"); + if (att!=null) { + gen.setUrl(att); + } + att = getAttributeValue(e, "version"); + if (att!=null) { + gen.setVersion(att); + } + feed.setGenerator(gen); + } + + e = eFeed.getChild("rights",getAtomNamespace()); + if (e!=null) { + feed.setRights(parseTextConstructToString(e)); + } + + e = eFeed.getChild("icon",getAtomNamespace()); + if (e!=null) { + feed.setIcon(e.getText()); + } + + e = eFeed.getChild("logo",getAtomNamespace()); + if (e!=null) { + feed.setLogo(e.getText()); + } + + e = eFeed.getChild("updated",getAtomNamespace()); + if (e!=null) { + feed.setUpdated(DateParser.parseDate(e.getText())); + } + + return feed; + } + + private Link parseLink(Feed feed , Entry entry, String baseURI, Element eLink) { + Link link = new Link(); + String att = getAttributeValue(eLink, "rel"); + if (att!=null) { + link.setRel(att); + } + att = getAttributeValue(eLink, "type"); + if (att!=null) { + link.setType(att); + } + att = getAttributeValue(eLink, "href"); + if (att!=null) { + link.setHref(att); + if (isRelativeURI(att)) { + link.setHrefResolved(resolveURI(baseURI, eLink, att)); + } + } + att = getAttributeValue(eLink, "title"); + if (att!=null) { + link.setTitle(att); + } + att = getAttributeValue(eLink, "hreflang"); + if (att!=null) { + link.setHreflang(att); + } + att = getAttributeValue(eLink, "length"); + if (att!=null) { + Long val = NumberParser.parseLong(att); + if (val != null) { + link.setLength(val.longValue()); + } + } + return link; + } + + // List(Elements) -> List(Link) + private List parseAlternateLinks(Feed feed, Entry entry, String baseURI, List eLinks) { + List links = new ArrayList(); + for (int i=0;i0) ? links : null; + } + + private List parseOtherLinks(Feed feed, Entry entry, String baseURI, List eLinks) { + List links = new ArrayList(); + for (int i=0;i0) ? links : null; + } + + private Person parsePerson(String baseURI, Element ePerson) { + Person person = new Person(); + Element e = ePerson.getChild("name",getAtomNamespace()); + if (e!=null) { + person.setName(e.getText()); + } + e = ePerson.getChild("uri",getAtomNamespace()); + if (e!=null) { + person.setUri(e.getText()); + if (isRelativeURI(e.getText())) { + person.setUriResolved(resolveURI(baseURI, ePerson, e.getText())); + } + } + e = ePerson.getChild("email",getAtomNamespace()); + if (e!=null) { + person.setEmail(e.getText()); + } + person.setModules(parsePersonModules(ePerson)); + return person; + } + + // List(Elements) -> List(Persons) + private List parsePersons(String baseURI, List ePersons) { + List persons = new ArrayList(); + for (int i=0;i0) ? persons : null; + } + + private Content parseContent(Element e) { + String value = parseTextConstructToString(e); + String src = getAttributeValue(e, "src"); + String type = getAttributeValue(e, "type"); + Content content = new Content(); + content.setSrc(src); + content.setType(type); + content.setValue(value); + return content; + } + + private String parseTextConstructToString(Element e) { + String value = null; + String type = getAttributeValue(e, "type"); + type = (type!=null) ? type : Content.TEXT; + if (type.equals(Content.XHTML) || (type.indexOf("/xml")) != -1 || (type.indexOf("+xml")) != -1) { + // XHTML content needs special handling + XMLOutputter outputter = new XMLOutputter(); + List eContent = e.getContent(); + Iterator i = eContent.iterator(); + while (i.hasNext()) { + org.jdom.Content c = (org.jdom.Content) i.next(); + if (c instanceof Element) { + Element eC = (Element) c; + if (eC.getNamespace().equals(getAtomNamespace())) { + ((Element)c).setNamespace(Namespace.NO_NAMESPACE); + } + } + } + value = outputter.outputString(eContent); + } else { + // Everything else comes in verbatim + value = e.getText(); + } + return value; + } + + // List(Elements) -> List(Entries) + protected List parseEntries(Feed feed, String baseURI, List eEntries) { + List entries = new ArrayList(); + for (int i=0;i0) ? entries : null; + } + + protected Entry parseEntry(Feed feed, Element eEntry, String baseURI) { + Entry entry = new Entry(); + + String xmlBase = eEntry.getAttributeValue("base", Namespace.XML_NAMESPACE); + if (xmlBase != null) { + entry.setXmlBase(xmlBase); + } + + Element e = eEntry.getChild("title",getAtomNamespace()); + if (e!=null) { + Content c = new Content(); + c.setValue(parseTextConstructToString(e)); + c.setType(getAttributeValue(e, "type")); + entry.setTitleEx(c); + } + + List eList = eEntry.getChildren("link",getAtomNamespace()); + entry.setAlternateLinks(parseAlternateLinks(feed, entry, baseURI, eList)); + entry.setOtherLinks(parseOtherLinks(feed, entry, baseURI, eList)); + + eList = eEntry.getChildren("author", getAtomNamespace()); + if (eList.size()>0) { + entry.setAuthors(parsePersons(baseURI, eList)); + } + + eList = eEntry.getChildren("contributor",getAtomNamespace()); + if (eList.size()>0) { + entry.setContributors(parsePersons(baseURI, eList)); + } + + e = eEntry.getChild("id",getAtomNamespace()); + if (e!=null) { + entry.setId(e.getText()); + } + + e = eEntry.getChild("updated",getAtomNamespace()); + if (e!=null) { + entry.setUpdated(DateParser.parseDate(e.getText())); + } + + e = eEntry.getChild("published",getAtomNamespace()); + if (e!=null) { + entry.setPublished(DateParser.parseDate(e.getText())); + } + + e = eEntry.getChild("summary",getAtomNamespace()); + if (e!=null) { + entry.setSummary(parseContent(e)); + } + + e = eEntry.getChild("content",getAtomNamespace()); + if (e!=null) { + List contents = new ArrayList(); + contents.add(parseContent(e)); + entry.setContents(contents); + } + + e = eEntry.getChild("rights",getAtomNamespace()); + if (e!=null) { + entry.setRights(e.getText()); + } + + List cList = eEntry.getChildren("category",getAtomNamespace()); + entry.setCategories(parseCategories(baseURI, cList)); + + // TODO: SHOULD handle Atom entry source element + e = eEntry.getChild("source", getAtomNamespace()); + if (e!=null) { + entry.setSource(parseFeedMetadata(baseURI, e)); + } + + entry.setModules(parseItemModules(eEntry)); + + List foreignMarkup = + extractForeignMarkup(eEntry, entry, getAtomNamespace()); + if (foreignMarkup.size() > 0) { + entry.setForeignMarkup(foreignMarkup); + } + return entry; + } + + private List parseCategories(String baseURI, List eCategories) { + List cats = new ArrayList(); + for (int i=0;i0) ? cats : null; + } + + private Category parseCategory(String baseURI, Element eCategory) { + Category category = new Category(); + String att = getAttributeValue(eCategory, "term"); + if (att!=null) { + category.setTerm(att); + } + att = getAttributeValue(eCategory, "scheme"); + if (att!=null) { + category.setScheme(att); + if (isRelativeURI(att)) { + category.setSchemeResolved(resolveURI(baseURI, eCategory, att)); + } + } + att = getAttributeValue(eCategory, "label"); + if (att!=null) { + category.setLabel(att); + } + return category; + + } + + // Once following relative URI methods are made public in the ROME + // Atom10Parser, then use them instead and delete these. + + + // Fix for issue #34 "valid IRI href attributes are stripped for atom:link" + // URI's that didn't start with http were being treated as relative URIs. + // So now consider an absolute URI to be any alpha-numeric string followed + // by a colon, followed by anything -- specified by this regex: + static Pattern absoluteURIPattern = Pattern.compile("^[a-z0-9]*:.*$"); + + public static boolean isAbsoluteURI(String uri) { + return absoluteURIPattern.matcher(uri).find(); + } + + /** Returns true if URI is relative. */ + public static boolean isRelativeURI(String uri) { + return !isAbsoluteURI(uri); + } + + /** + * Resolve URI via base URL and parent element. + * Resolve URI based considering xml:base and baseURI. + * @param baseURI Base URI used to fetch the XML document + * @param parent Parent element from which to consider xml:base + * @param url URL to be resolved + */ + public static String resolveURI(String baseURI, Parent parent, String url) { + if (!resolveURIs) { + return url; + } + if (isRelativeURI(url)) { + url = (!".".equals(url) && !"./".equals(url)) ? url : ""; + + if (url.startsWith("/") && baseURI != null) { + String base = null; + int slashslash = baseURI.indexOf("//"); + int nextslash = baseURI.indexOf("/", slashslash + 2); + if (nextslash != -1) base = baseURI.substring(0, nextslash); + return formURI(base, url); + } + + // Relative URI with parent + if (parent != null && parent instanceof Element) { + + // Do we have an xml:base? + String xmlbase = ((Element)parent).getAttributeValue( + "base", Namespace.XML_NAMESPACE); + if (xmlbase != null && xmlbase.trim().length() > 0) { + if (isAbsoluteURI(xmlbase)) { + // Absolute xml:base, so form URI right now + if (url.startsWith("/")) { + // Host relative URI + int slashslash = xmlbase.indexOf("//"); + int nextslash = xmlbase.indexOf("/", slashslash + 2); + if (nextslash != -1) xmlbase = xmlbase.substring(0, nextslash); + return formURI(xmlbase, url); + } + if (!xmlbase.endsWith("/")) { + // Base URI is filename, strip it off + xmlbase = xmlbase.substring(0, xmlbase.lastIndexOf("/")); + } + return formURI(xmlbase, url); + } else { + // Relative xml:base, so walk up tree + return resolveURI(baseURI, parent.getParent(), + stripTrailingSlash(xmlbase) + "/"+ stripStartingSlash(url)); + } + } + // No xml:base so walk up tree + return resolveURI(baseURI, parent.getParent(), url); + + // Relative URI with no parent (i.e. top of tree), so form URI right now + } else if (parent == null || parent instanceof Document) { + return formURI(baseURI, url); + } + } + return url; + } + + /** + * Find base URI of feed considering relative URIs. + * @param root Root element of feed. + */ + private String findBaseURI(Element root) throws MalformedURLException { + String ret = null; + if (findAtomLink(root, "self") != null) { + ret = findAtomLink(root, "self"); + if (".".equals(ret) || "./".equals(ret)) ret = ""; + if (ret.indexOf("/") != -1) ret = ret.substring(0, ret.lastIndexOf("/")); + ret = resolveURI(null, root, ret); + } + return ret; + } + + /** + * Return URL string of Atom link element under parent element. + * Link with no rel attribute is considered to be rel="alternate" + * @param parent Consider only children of this parent element + * @param rel Consider only links with this relationship + */ + private String findAtomLink(Element parent, String rel) { + String ret = null; + List linksList = parent.getChildren("link", ATOM_10_NS); + if (linksList != null) { + for (Iterator links = linksList.iterator(); links.hasNext(); ) { + Element link = (Element)links.next(); + Attribute relAtt = getAttribute(link, "rel"); + Attribute hrefAtt = getAttribute(link, "href"); + if ( (relAtt == null && "alternate".equals(rel)) + || (relAtt != null && relAtt.getValue().equals(rel))) { + ret = hrefAtt.getValue(); + break; + } + } + } + return ret; + } + + /** + * Form URI by combining base with append portion and giving + * special consideration to append portions that begin with ".." + * @param base Base of URI, may end with trailing slash + * @param append String to append, may begin with slash or ".." + */ + private static String formURI(String base, String append) { + base = stripTrailingSlash(base); + append = stripStartingSlash(append); + if (append.startsWith("..")) { + String ret = null; + String[] parts = append.split("/"); + for (int i=0; i + * @author Alejandro Abdelnur + * + */ +public class Base64 { + + /** + * Encodes a String into a base 64 String. The resulting encoding is chunked at 76 bytes. + *

+ * @param s String to encode. + * @return encoded string. + * + */ + public static String encode(String s) { + byte[] sBytes = s.getBytes(); + sBytes = encode(sBytes); + s = new String(sBytes); + return s; + } + + /** + * Decodes a base 64 String into a String. + *

+ * @param s String to decode. + * @return encoded string. + * @throws java.lang.IllegalArgumentException thrown if the given byte array was not valid com.sun.syndication.io.impl.Base64 encoding. + * + */ + public static String decode(String s) throws IllegalArgumentException { + s = s.replaceAll("\n", ""); + s = s.replaceAll("\r", ""); + byte[] sBytes = s.getBytes(); + sBytes = decode(sBytes); + s = new String(sBytes); + return s; + } + + + private static final byte[] ALPHASET = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".getBytes(); + + private static final int I6O2 = 255 - 3; + private static final int O6I2 = 3; + private static final int I4O4 = 255 - 15; + private static final int O4I4 = 15; + private static final int I2O6 = 255 - 63; + private static final int O2I6 = 63; + + /** + * Encodes a byte array into a base 64 byte array. + *

+ * @param dData byte array to encode. + * @return encoded byte array. + * + */ + public static byte[] encode(byte[] dData) { + if (dData==null) { + throw new IllegalArgumentException("Cannot encode null"); + } + byte[] eData = new byte[((dData.length+2)/3)*4]; + + int eIndex = 0; + for (int i = 0; i>2]; + e2 = ALPHASET[(d1&O6I2)<<4 | (d2&I4O4)>>4]; + e3 = ALPHASET[(d2&O4I4)<<2 | (d3&I2O6)>>6]; + e4 = ALPHASET[(d3&O2I6)]; + + eData[eIndex++] = (byte)e1; + eData[eIndex++] = (byte)e2; + eData[eIndex++] = (pad<2) ?(byte)e3 : (byte)'='; + eData[eIndex++] = (pad<1) ?(byte)e4 : (byte)'='; + + } + return eData; + } + + private final static int[] CODES = new int[256]; + + static { + for (int i=0;i + * @param eData byte array to decode. + * @return decoded byte array. + * @throws java.lang.IllegalArgumentException thrown if the given byte array was not valid com.sun.syndication.io.impl.Base64 encoding. + * + */ + public static byte[] decode(byte[] eData) { + if (eData==null) { + throw new IllegalArgumentException("Cannot decode null"); + } + byte[] cleanEData = (byte[]) eData.clone(); + int cleanELength = 0; + for (int i=0;i eData.length) { + throw new IllegalArgumentException("byte array is not a valid com.sun.syndication.io.impl.Base64 encoding"); + } + int e1 = CODES[cleanEData[i]]; + int e2 = CODES[cleanEData[i+1]]; + int e3 = CODES[cleanEData[i+2]]; + int e4 = CODES[cleanEData[i+3]]; + dData[dIndex++] = (byte) ((e1<<2)|(e2>>4)); + if (dIndex>2)); + } + if (dIndex + * Note that the calling app could still add declarations/modules to the Feed tree after this. Which is fine. But + * those modules are then responsible for crawling to the root of the tree, at generate() time, to make sure their + * namespace declarations are present. + */ + protected static void purgeUnusedNamespaceDeclarations(Element root) { + java.util.Set usedPrefixes = new java.util.HashSet(); + collectUsedPrefixes(root, usedPrefixes); + + List list = root.getAdditionalNamespaces(); + List additionalNamespaces = new java.util.ArrayList(); + additionalNamespaces.addAll(list); // the duplication will prevent a ConcurrentModificationException below + + for (int i = 0; i < additionalNamespaces.size(); i++) { + Namespace ns = (Namespace) additionalNamespaces.get(i); + String prefix = ns.getPrefix(); + if (prefix != null && prefix.length() > 0 && !usedPrefixes.contains(prefix)) { + root.removeNamespaceDeclaration(ns); + } + } + } + + private static void collectUsedPrefixes(Element el, java.util.Set collector) { + String prefix = el.getNamespacePrefix(); + if (prefix != null && prefix.length() > 0 && !collector.contains(prefix)) { + collector.add(prefix); + } + List kids = el.getChildren(); + for (int i = 0; i < kids.size(); i++) { + collectUsedPrefixes((Element) kids.get(i), collector); // recursion - worth it + } + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/BaseWireFeedParser.java b/src/main/java/com/sun/syndication/io/impl/BaseWireFeedParser.java new file mode 100644 index 0000000..b9f9d86 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/BaseWireFeedParser.java @@ -0,0 +1,114 @@ +package com.sun.syndication.io.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.module.Extendable; +import com.sun.syndication.io.WireFeedParser; +import java.util.ArrayList; +import java.util.Iterator; +import org.jdom.Element; + +import java.util.List; +import org.jdom.Namespace; +import org.jdom.Attribute; + +/** + * @author Alejandro Abdelnur + */ +public abstract class BaseWireFeedParser implements WireFeedParser { + /** + * [TYPE].feed.ModuleParser.classes= [className] ... + * + */ + private static final String FEED_MODULE_PARSERS_POSFIX_KEY = ".feed.ModuleParser.classes"; + + /** + * [TYPE].item.ModuleParser.classes= [className] ... + * + */ + private static final String ITEM_MODULE_PARSERS_POSFIX_KEY = ".item.ModuleParser.classes"; + + /** + * [TYPE].person.ModuleParser.classes= [className] ... + * + */ + private static final String PERSON_MODULE_PARSERS_POSFIX_KEY = ".person.ModuleParser.classes"; + + + private String _type; + private ModuleParsers _feedModuleParsers; + private ModuleParsers _itemModuleParsers; + private ModuleParsers _personModuleParsers; + private Namespace _namespace; + + protected BaseWireFeedParser(String type, Namespace namespace) { + _type = type; + _namespace = namespace; + _feedModuleParsers = new ModuleParsers(type+FEED_MODULE_PARSERS_POSFIX_KEY, this); + _itemModuleParsers = new ModuleParsers(type+ITEM_MODULE_PARSERS_POSFIX_KEY, this); + _personModuleParsers = new ModuleParsers(type+PERSON_MODULE_PARSERS_POSFIX_KEY, this); + } + + /** + * Returns the type of feed the parser handles. + *

+ * @see WireFeed for details on the format of this string. + *

+ * @return the type of feed the parser handles. + * + */ + public String getType() { + return _type; + } + + protected List parseFeedModules(Element feedElement) { + return _feedModuleParsers.parseModules(feedElement); + } + + protected List parseItemModules(Element itemElement) { + return _itemModuleParsers.parseModules(itemElement); + } + + protected List parsePersonModules(Element itemElement) { + return _personModuleParsers.parseModules(itemElement); + } + + protected List extractForeignMarkup(Element e, Extendable ext, Namespace basens) { + ArrayList foreignMarkup = new ArrayList(); + Iterator children = e.getChildren().iterator(); + while (children.hasNext()) { + Element elem = (Element)children.next(); + if ( + // if elemet not in the RSS namespace + !basens.equals(elem.getNamespace()) + // and elem was not handled by a module + && null == ext.getModule(elem.getNamespaceURI())) { + + // save it as foreign markup, + // but we can't detach it while we're iterating + foreignMarkup.add(elem.clone()); + } + } + // Now we can detach the foreign markup elements + Iterator fm = foreignMarkup.iterator(); + while (fm.hasNext()) { + Element elem = (Element)fm.next(); + elem.detach(); + } + return foreignMarkup; + } + + protected Attribute getAttribute(Element e, String attributeName) { + Attribute attribute = e.getAttribute(attributeName); + if (attribute == null) { + attribute = e.getAttribute(attributeName, _namespace); + } + return attribute; + } + + protected String getAttributeValue(Element e, String attributeName) { + Attribute attr = getAttribute(e, attributeName); + return (attr != null) ? attr.getValue() : null; + } + +} + diff --git a/src/main/java/com/sun/syndication/io/impl/DCModuleGenerator.java b/src/main/java/com/sun/syndication/io/impl/DCModuleGenerator.java new file mode 100644 index 0000000..2ff8901 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/DCModuleGenerator.java @@ -0,0 +1,212 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.DCModule; +import com.sun.syndication.feed.module.DCSubject; +import com.sun.syndication.io.ModuleGenerator; +import org.jdom.Attribute; +import org.jdom.Element; +import org.jdom.Namespace; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; + + +/** + * Feed Generator for DublinCore Module. + *

+ * + * @author Elaine Chien + * + */ +public class DCModuleGenerator implements ModuleGenerator { + + private static final String DC_URI = "http://purl.org/dc/elements/1.1/"; + private static final String TAXO_URI = "http://purl.org/rss/1.0/modules/taxonomy/"; + private static final String RDF_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + + private static final Namespace DC_NS = Namespace.getNamespace("dc", DC_URI); + private static final Namespace TAXO_NS = Namespace.getNamespace("taxo", TAXO_URI); + private static final Namespace RDF_NS = Namespace.getNamespace("rdf", RDF_URI); + + private static final Set NAMESPACES; + + static { + Set nss = new HashSet(); + nss.add(DC_NS); + nss.add(TAXO_NS); + nss.add(RDF_NS); + NAMESPACES = Collections.unmodifiableSet(nss); + } + + public final String getNamespaceUri() { + return DC_URI; + } + + private final Namespace getDCNamespace() { + return DC_NS; + } + + private final Namespace getRDFNamespace() { + return RDF_NS; + } + + private final Namespace getTaxonomyNamespace() { + return TAXO_NS; + } + + /** + * Returns a set with all the URIs (JDOM Namespace elements) this module + * generator uses. + *

+ * It is used by the the feed generators to add their namespace definition + * in the root element of the generated document (forward-missing of + * Java 5.0 Generics). + *

+ * + * @return a set with all the URIs this module generator uses. + */ + public final Set getNamespaces() { + return NAMESPACES; + } + + /** + * Populate an element tree with elements for a module. + *

+ * @param module the module to populate from. + * @param element the root element to attach child elements to. + */ + public final void generate(Module module, Element element) { + DCModule dcModule = (DCModule) module; + + if (dcModule.getTitle() != null) { + element.addContent(generateSimpleElementList("title", dcModule.getTitles())); + } + if (dcModule.getCreator() != null) { + element.addContent(generateSimpleElementList("creator", dcModule.getCreators())); + } + List subjects = dcModule.getSubjects(); + for (int i = 0; i < subjects.size(); i++) { + element.addContent(generateSubjectElement((DCSubject) subjects.get(i))); + } + if (dcModule.getDescription() != null) { + element.addContent(generateSimpleElementList("description", dcModule.getDescriptions())); + } + if (dcModule.getPublisher() != null) { + element.addContent(generateSimpleElementList("publisher", dcModule.getPublishers())); + } + if (dcModule.getContributors() != null) { + element.addContent(generateSimpleElementList("contributor", dcModule.getContributors())); + } + if (dcModule.getDate() != null) { + for (Iterator i = dcModule.getDates().iterator(); i.hasNext();) { + element.addContent(generateSimpleElement("date", + DateParser.formatW3CDateTime((Date) i.next()))); + } + } + if (dcModule.getType() != null) { + element.addContent(generateSimpleElementList("type", dcModule.getTypes())); + } + if (dcModule.getFormat() != null) { + element.addContent(generateSimpleElementList("format", dcModule.getFormats())); + } + if (dcModule.getIdentifier() != null) { + element.addContent(generateSimpleElementList("identifier", dcModule.getIdentifiers())); + } + if (dcModule.getSource() != null) { + element.addContent(generateSimpleElementList("source", dcModule.getSources())); + } + if (dcModule.getLanguage() != null) { + element.addContent(generateSimpleElementList("language", dcModule.getLanguages())); + } + if (dcModule.getRelation() != null) { + element.addContent(generateSimpleElementList("relation", dcModule.getRelations())); + } + if (dcModule.getCoverage() != null) { + element.addContent(generateSimpleElementList("coverage", dcModule.getCoverages())); + } + if (dcModule.getRights() != null) { + element.addContent(generateSimpleElementList("rights", dcModule.getRightsList())); + } + } + + /** + * Utility method to generate an element for a subject. + *

+ * @param subject the subject to generate an element for. + * @return the element for the subject. + */ + protected final Element generateSubjectElement(DCSubject subject) { + Element subjectElement = new Element("subject", getDCNamespace()); + + if (subject.getTaxonomyUri() != null) { + Element descriptionElement = new Element("Description", getRDFNamespace()); + Element topicElement = new Element("topic", getTaxonomyNamespace()); + Attribute resourceAttribute = new Attribute("resource", subject.getTaxonomyUri(), getRDFNamespace()); + topicElement.setAttribute(resourceAttribute); + descriptionElement.addContent(topicElement); + + if (subject.getValue() != null) { + Element valueElement = new Element("value", getRDFNamespace()); + valueElement.addContent(subject.getValue()); + descriptionElement.addContent(valueElement); + } + subjectElement.addContent(descriptionElement); + } else { + subjectElement.addContent(subject.getValue()); + } + return subjectElement; + } + + + /** + * Utility method to generate a single element containing a string. + *

+ * @param name the name of the elment to generate. + * @param value the value of the text in the element. + * @return the element generated. + */ + protected final Element generateSimpleElement(String name, String value) { + Element element = new Element(name, getDCNamespace()); + element.addContent(value); + + return element; + } + + /** + * Utility method to generate a list of simple elements. + *

+ * @param name the name of the element list to generate. + * @param value the list of values for the elements. + * @return a list of Elements created. + */ + protected final List generateSimpleElementList(String name, List value) { + List elements = new ArrayList(); + for (Iterator i = value.iterator(); i.hasNext();) { + elements.add(generateSimpleElement(name, (String) i.next())); + } + + return elements; + } +} diff --git a/src/main/java/com/sun/syndication/io/impl/DCModuleParser.java b/src/main/java/com/sun/syndication/io/impl/DCModuleParser.java new file mode 100644 index 0000000..54f16af --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/DCModuleParser.java @@ -0,0 +1,231 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.module.DCModuleImpl; +import com.sun.syndication.feed.module.DCSubjectImpl; +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.DCModule; +import com.sun.syndication.feed.module.DCSubject; +import com.sun.syndication.io.ModuleParser; +import com.sun.syndication.io.WireFeedParser; +import org.jdom.Attribute; +import org.jdom.Element; +import org.jdom.Namespace; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Parser for the Dublin Core module. + */ +public class DCModuleParser implements ModuleParser { + + private static final String RDF_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + private static final String TAXO_URI = "http://purl.org/rss/1.0/modules/taxonomy/"; + + private static final Namespace DC_NS = Namespace.getNamespace(DCModule.URI); + private static final Namespace RDF_NS = Namespace.getNamespace(RDF_URI); + private static final Namespace TAXO_NS = Namespace.getNamespace(TAXO_URI); + + public final String getNamespaceUri() { + return DCModule.URI; + } + + private final Namespace getDCNamespace() { + return DC_NS; + } + + private final Namespace getRDFNamespace() { + return RDF_NS; + } + + private final Namespace getTaxonomyNamespace() { + return TAXO_NS; + } + + /** + * Parse an element tree and return the module found in it. + *

+ * @param dcRoot the root element containing the module elements. + * @return the module parsed from the element tree, null if none. + */ + public Module parse(Element dcRoot) { + boolean foundSomething = false; + DCModule dcm = new DCModuleImpl(); + + List eList = dcRoot.getChildren("title", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setTitles(parseElementList(eList)); + } + eList = dcRoot.getChildren("creator", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setCreators(parseElementList(eList)); + } + eList = dcRoot.getChildren("subject", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setSubjects(parseSubjects(eList)); + } + eList = dcRoot.getChildren("description", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setDescriptions(parseElementList(eList)); + } + eList = dcRoot.getChildren("publisher", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setPublishers(parseElementList(eList)); + } + eList = dcRoot.getChildren("contributor", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setContributors(parseElementList(eList)); + } + eList = dcRoot.getChildren("date", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setDates(parseElementListDate(eList)); + } + eList = dcRoot.getChildren("type", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setTypes(parseElementList(eList)); + } + eList = dcRoot.getChildren("format", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setFormats(parseElementList(eList)); + } + eList = dcRoot.getChildren("identifier", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setIdentifiers(parseElementList(eList)); + } + eList = dcRoot.getChildren("source", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setSources(parseElementList(eList)); + } + eList = dcRoot.getChildren("language", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setLanguages(parseElementList(eList)); + } + eList = dcRoot.getChildren("relation", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setRelations(parseElementList(eList)); + } + eList = dcRoot.getChildren("coverage", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setCoverages(parseElementList(eList)); + } + eList = dcRoot.getChildren("rights", getDCNamespace()); + if (eList.size() > 0) { + foundSomething = true; + dcm.setRightsList(parseElementList(eList)); + } + + return (foundSomething) ? dcm : null; + } + + /** + * Utility method to parse a taxonomy from an element. + *

+ * @param desc the taxonomy description element. + * @return the string contained in the resource of the element. + */ + protected final String getTaxonomy(Element desc) { + String d = null; + Element taxo = desc.getChild("topic", getTaxonomyNamespace()); + if (taxo!=null) { + Attribute a = taxo.getAttribute("resource", getRDFNamespace()); + if (a!=null) { + d = a.getValue(); + } + } + return d; + } + + /** + * Utility method to parse a list of subjects out of a list of elements. + *

+ * @param eList the element list to parse. + * @return a list of subjects parsed from the elements. + */ + protected final List parseSubjects(List eList) { + List subjects = new ArrayList(); + for (Iterator i = eList.iterator(); i.hasNext();) { + Element eSubject = (Element) i.next(); + Element eDesc = eSubject.getChild("Description", getRDFNamespace()); + if (eDesc != null) { + String taxonomy = getTaxonomy(eDesc); + List eValues = eDesc.getChildren("value", getRDFNamespace()); + for (Iterator v = eValues.iterator(); v.hasNext();) { + Element eValue = (Element) v.next(); + DCSubject subject = new DCSubjectImpl(); + subject.setTaxonomyUri(taxonomy); + subject.setValue(eValue.getText()); + subjects.add(subject); + } + } else { + DCSubject subject = new DCSubjectImpl(); + subject.setValue(eSubject.getText()); + subjects.add(subject); + } + } + + return subjects; + } + + /** + * Utility method to parse a list of strings out of a list of elements. + *

+ * @param eList the list of elements to parse. + * @return the list of strings + */ + protected final List parseElementList(List eList) { + List values= new ArrayList(); + for (Iterator i = eList.iterator(); i.hasNext();) { + Element e = (Element) i.next(); + values.add(e.getText()); + } + + return values; + } + + /** + * Utility method to parse a list of dates out of a list of elements. + *

+ * @param eList the list of elements to parse. + * @return the list of dates. + */ + protected final List parseElementListDate(List eList) { + List values = new ArrayList(); + for (Iterator i = eList.iterator(); i.hasNext();) { + Element e = (Element) i.next(); + values.add(DateParser.parseDate(e.getText())); + } + + return values; + } +} diff --git a/src/main/java/com/sun/syndication/io/impl/DateParser.java b/src/main/java/com/sun/syndication/io/impl/DateParser.java new file mode 100644 index 0000000..a55e5e7 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/DateParser.java @@ -0,0 +1,285 @@ +/* + * 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 com.sun.syndication.io.impl; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.text.ParsePosition; +import java.util.Date; +import java.util.TimeZone; +import java.util.Locale; + +/** + * A helper class that parses Dates out of Strings with date time in RFC822 and W3CDateTime + * formats plus the variants Atom (0.3) and RSS (0.9, 0.91, 0.92, 0.93, 0.94, 1.0 and 2.0) + * specificators added to those formats. + *

+ * It uses the JDK java.text.SimpleDateFormat class attemtping the parse using a mask for + * each one of the possible formats. + *

+ * + * @author Alejandro Abdelnur + * + */ +public class DateParser { + + private static String[] ADDITIONAL_MASKS; + + static { + ADDITIONAL_MASKS = PropertiesLoader.getPropertiesLoader().getTokenizedProperty("datetime.extra.masks","|"); + } + + // order is like this because the SimpleDateFormat.parse does not fail with exception + // if it can parse a valid date out of a substring of the full string given the mask + // so we have to check the most complete format first, then it fails with exception + private static final String[] RFC822_MASKS = { + "EEE, dd MMM yy HH:mm:ss z", + "EEE, dd MMM yy HH:mm z", + "dd MMM yy HH:mm:ss z", + "dd MMM yy HH:mm z" + }; + + + + // order is like this because the SimpleDateFormat.parse does not fail with exception + // if it can parse a valid date out of a substring of the full string given the mask + // so we have to check the most complete format first, then it fails with exception + private static final String[] W3CDATETIME_MASKS = { + "yyyy-MM-dd'T'HH:mm:ss.SSSz", + "yyyy-MM-dd't'HH:mm:ss.SSSz", + "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", + "yyyy-MM-dd't'HH:mm:ss.SSS'z'", + "yyyy-MM-dd'T'HH:mm:ssz", + "yyyy-MM-dd't'HH:mm:ssz", + "yyyy-MM-dd'T'HH:mm:ssZ", + "yyyy-MM-dd't'HH:mm:ssZ", + "yyyy-MM-dd'T'HH:mm:ss'Z'", + "yyyy-MM-dd't'HH:mm:ss'z'", + "yyyy-MM-dd'T'HH:mmz", // together with logic in the parseW3CDateTime they + "yyyy-MM'T'HH:mmz", // handle W3C dates without time forcing them to be GMT + "yyyy'T'HH:mmz", + "yyyy-MM-dd't'HH:mmz", + "yyyy-MM-dd'T'HH:mm'Z'", + "yyyy-MM-dd't'HH:mm'z'", + "yyyy-MM-dd", + "yyyy-MM", + "yyyy" + }; + + + + /** + * The masks used to validate and parse the input to this Atom date. + * These are a lot more forgiving than what the Atom spec allows. + * The forms that are invalid according to the spec are indicated. + */ + private static final String[] masks = { + "yyyy-MM-dd'T'HH:mm:ss.SSSz", + "yyyy-MM-dd't'HH:mm:ss.SSSz", // invalid + "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", + "yyyy-MM-dd't'HH:mm:ss.SSS'z'", // invalid + "yyyy-MM-dd'T'HH:mm:ssz", + "yyyy-MM-dd't'HH:mm:ssz", // invalid + "yyyy-MM-dd'T'HH:mm:ss'Z'", + "yyyy-MM-dd't'HH:mm:ss'z'", // invalid + "yyyy-MM-dd'T'HH:mmz", // invalid + "yyyy-MM-dd't'HH:mmz", // invalid + "yyyy-MM-dd'T'HH:mm'Z'", // invalid + "yyyy-MM-dd't'HH:mm'z'", // invalid + "yyyy-MM-dd", + "yyyy-MM", + "yyyy" + }; + + + + + /** + * Private constructor to avoid DateParser instances creation. + */ + private DateParser() { + } + + /** + * Parses a Date out of a string using an array of masks. + *

+ * It uses the masks in order until one of them succedes or all fail. + *

+ * + * @param masks array of masks to use for parsing the string + * @param sDate string to parse for a date. + * @return the Date represented by the given string using one of the given masks. + * It returns null if it was not possible to parse the the string with any of the masks. + * + */ + private static Date parseUsingMask(String[] masks,String sDate) { + sDate = (sDate!=null) ? sDate.trim() : null; + ParsePosition pp = null; + Date d = null; + for (int i=0;d==null && i + * It parsers the following formats: + *

+ *

+ * Refer to the java.text.SimpleDateFormat javadocs for details on the format of each element. + *

+ * @param sDate string to parse for a date. + * @return the Date represented by the given RFC822 string. + * It returns null if it was not possible to parse the given string into a Date. + * + */ + public static Date parseRFC822(String sDate) { + int utIndex = sDate.indexOf(" UT"); + if (utIndex>-1) { + String pre = sDate.substring(0,utIndex); + String post = sDate.substring(utIndex+3); + sDate = pre + " GMT" + post; + } + return parseUsingMask(RFC822_MASKS,sDate); + } + + + /** + * Parses a Date out of a String with a date in W3C date-time format. + *

+ * It parsers the following formats: + *

+ *

+ * Refer to the java.text.SimpleDateFormat javadocs for details on the format of each element. + *

+ * @param sDate string to parse for a date. + * @return the Date represented by the given W3C date-time string. + * It returns null if it was not possible to parse the given string into a Date. + * + */ + public static Date parseW3CDateTime(String sDate) { + // if sDate has time on it, it injects 'GTM' before de TZ displacement to + // allow the SimpleDateFormat parser to parse it properly + int tIndex = sDate.indexOf("T"); + if (tIndex>-1) { + if (sDate.endsWith("Z")) { + sDate = sDate.substring(0,sDate.length()-1)+"+00:00"; + } + int tzdIndex = sDate.indexOf("+",tIndex); + if (tzdIndex==-1) { + tzdIndex = sDate.indexOf("-",tIndex); + } + if (tzdIndex>-1) { + String pre = sDate.substring(0,tzdIndex); + int secFraction = pre.indexOf(","); + if (secFraction>-1) { + pre = pre.substring(0,secFraction); + } + String post = sDate.substring(tzdIndex); + sDate = pre + "GMT" + post; + } + } + else { + sDate += "T00:00GMT"; + } + return parseUsingMask(W3CDATETIME_MASKS,sDate); + } + + + /** + * Parses a Date out of a String with a date in W3C date-time format or + * in a RFC822 format. + *

+ * @param sDate string to parse for a date. + * @return the Date represented by the given W3C date-time string. + * It returns null if it was not possible to parse the given string into a Date. + * + * */ + public static Date parseDate(String sDate) { + Date d = parseW3CDateTime(sDate); + if (d==null) { + d = parseRFC822(sDate); + if (d==null && ADDITIONAL_MASKS.length>0) { + d = parseUsingMask(ADDITIONAL_MASKS,sDate); + } + } + return d; + } + + /** + * create a RFC822 representation of a date. + *

+ * Refer to the java.text.SimpleDateFormat javadocs for details on the format of each element. + *

+ * @param date Date to parse + * @return the RFC822 represented by the given Date + * It returns null if it was not possible to parse the date. + * + */ + public static String formatRFC822(Date date) { + SimpleDateFormat dateFormater = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'",Locale.US); + dateFormater.setTimeZone(TimeZone.getTimeZone("GMT")); + return dateFormater.format(date); + } + + /** + * create a W3C Date Time representation of a date. + *

+ * Refer to the java.text.SimpleDateFormat javadocs for details on the format of each element. + *

+ * @param date Date to parse + * @return the W3C Date Time represented by the given Date + * It returns null if it was not possible to parse the date. + * + */ + public static String formatW3CDateTime(Date date) { + SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",Locale.US); + dateFormater.setTimeZone(TimeZone.getTimeZone("GMT")); + return dateFormater.format(date); + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/FeedGenerators.java b/src/main/java/com/sun/syndication/io/impl/FeedGenerators.java new file mode 100644 index 0000000..f6e1a71 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/FeedGenerators.java @@ -0,0 +1,62 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.io.WireFeedGenerator; + +import java.util.List; + +/** + * Generates an XML document (JDOM Document) out of a Feed. + *

+ * It can generate all flavors of RSS (0.90, 0.91, 0.92, 0.93, 0.94, 1.0 and 2.0) and + * Atom 0.3 feed. + *

+ * WireFeedGenerator instances are thread safe. + *

+ * Generators for a specific type must extend this class and register in the generator list. + * (Right now registration is hardcoded in the WireFeedGenerator constructor). + *

+ * @author Alejandro Abdelnur + * + */ +public class FeedGenerators extends PluginManager { + + /** + * WireFeedGenerator.classes= [className] ... + * + */ + public static final String FEED_GENERATORS_KEY = "WireFeedGenerator.classes"; + + + public FeedGenerators() { + super(FEED_GENERATORS_KEY); + } + + public WireFeedGenerator getGenerator(String feedType) { + return (WireFeedGenerator) getPlugin(feedType); + } + + protected String getKey(Object obj) { + return ((WireFeedGenerator)obj).getType(); + } + + public List getSupportedFeedTypes() { + return getKeys(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sun/syndication/io/impl/FeedParsers.java b/src/main/java/com/sun/syndication/io/impl/FeedParsers.java new file mode 100644 index 0000000..86351c2 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/FeedParsers.java @@ -0,0 +1,83 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.io.WireFeedParser; +import org.jdom.Document; +import java.util.List; + +/** + * Parses an XML document (JDOM Document) into a Feed. + *

+ * It accepts all flavors of RSS (0.90, 0.91, 0.92, 0.93, 0.94, 1.0 and 2.0) and + * Atom 0.3 feeds. + *

+ * The WireFeedParser is a liberal parser. + *

+ * WireFeedParser instances are thread safe. + *

+ * Parsers for a specific type must extend this class and register in the parser list. + * (Right now registration is hardcoded in the WireFeedParser constructor). + *

+ * @author Alejandro Abdelnur + * + */ +public class FeedParsers extends PluginManager { + + /** + * WireFeedParser.classes= [className] ... + * + */ + public static final String FEED_PARSERS_KEY = "WireFeedParser.classes"; + + /** + * Creates a parser instance. + *

+ * + */ + public FeedParsers() { + super(FEED_PARSERS_KEY); + } + + public List getSupportedFeedTypes() { + return getKeys(); + } + + /** + * Finds the real parser type for the given document feed. + *

+ * @param document document feed to find the parser for. + * @return the parser for the given document or null if there is no parser for that document. + * + */ + public WireFeedParser getParserFor(Document document) { + List parsers = getPlugins(); + WireFeedParser parser = null; + for (int i=0;parser==null && i + * No method will throw any sort of Exception when parsing a string. + * All methods accept any Java String or null as legal input, if the + * input is non null, whitespace will be trimmed first, and then parsing + * will be attempted. + *

+ *

+ * :TODO: Add Integer, Float, and Double methods as needed. + *

+ */ +public class NumberParser { + + /** + * Private constructor to avoid NumberParser instances creation. + */ + private NumberParser() { + } + + /** + * Parses a Long out of a string. + * + * @param str string to parse for a Long. + * @return the Long represented by the given string, + * It returns null if it was not possible to parse the the string. + */ + public static Long parseLong(String str) { + if (null != str) { + try { + return new Long(Long.parseLong(str.trim())); + } catch (Exception e) { + // :IGNORE: + } + } + return null; + } + + /** + * Parse an Integer from a String. If the String is not an integer null is returned + * and no exception is thrown. + * + * @param str the String to parse + * @return The Integer represented by the String, or null if it could not be parsed. + */ + public static Integer parseInt(String str) { + if (null != str) { + try { + return new Integer(Integer.parseInt(str.trim())); + } catch (Exception e) { + // :IGNORE: + } + } + return null; + } + + /** + * Parse a Float from a String without exceptions. If the String is not a Float then null is returned + * + * @param str the String to parse + * @return The Float represented by the String, or null if it could not be parsed. + */ + public static Float parseFloat(String str) { + if (null != str) { + try { + return new Float(Float.parseFloat(str.trim())); + } catch (Exception e) { + // :IGNORE: + } + } + return null; + } + + /** + * Parse a float from a String, with a default value + * + * @param str + * @param def the value to return if the String cannot be parsed + * @return + */ + public static float parseFloat(String str, float def) { + Float result = parseFloat(str); + return (result == null) ? def : result.floatValue(); + } + + /** + * Parses a long out of a string. + * + * @param str string to parse for a long. + * @param def default value to return if it is not possible to parse the the string. + * @return the long represented by the given string, or the default. + */ + public static long parseLong(String str, long def) { + Long ret = parseLong(str); + return (null == ret) ? def : ret.longValue(); + } + + +} diff --git a/src/main/java/com/sun/syndication/io/impl/PluginManager.java b/src/main/java/com/sun/syndication/io/impl/PluginManager.java new file mode 100644 index 0000000..f10e5cc --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/PluginManager.java @@ -0,0 +1,144 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.io.DelegatingModuleGenerator; +import com.sun.syndication.io.DelegatingModuleParser; +import com.sun.syndication.io.WireFeedGenerator; +import com.sun.syndication.io.WireFeedParser; + +import java.util.*; + +/** + *

+ * @author Alejandro Abdelnur + * + */ +public abstract class PluginManager { + private String[] _propertyValues; + private Map _pluginsMap; + private List _pluginsList; + private List _keys; + private WireFeedParser _parentParser; + private WireFeedGenerator _parentGenerator; + + /** + * Creates a PluginManager + *

+ * @param propertyKey property key defining the plugins classes + * + */ + protected PluginManager(String propertyKey) { + this(propertyKey, null, null); + } + + protected PluginManager(String propertyKey, WireFeedParser parentParser, + WireFeedGenerator parentGenerator) + { + _parentParser = parentParser; + _parentGenerator = parentGenerator; + _propertyValues = PropertiesLoader.getPropertiesLoader().getTokenizedProperty(propertyKey,", "); + loadPlugins(); + _pluginsMap = Collections.unmodifiableMap(_pluginsMap); + _pluginsList = Collections.unmodifiableList(_pluginsList); + _keys = Collections.unmodifiableList(new ArrayList(_pluginsMap.keySet())); + } + + protected abstract String getKey(Object obj); + + protected List getKeys() { + return _keys; + } + + protected List getPlugins() { + return _pluginsList; + } + + protected Map getPluginMap() { + return _pluginsMap; + } + + protected Object getPlugin(String key) { + return _pluginsMap.get(key); + } + + // PRIVATE - LOADER PART + + private void loadPlugins() { + List finalPluginsList = new ArrayList(); + _pluginsList = new ArrayList(); + _pluginsMap = new HashMap(); + String className = null; + try { + Class[] classes = getClasses(); + for (int i=0;i + * @return array containing the classes defined in the properties files. + * @throws java.lang.ClassNotFoundException thrown if one of the classes defined in the properties file cannot be loaded + * and hard failure is ON. + * + */ + private Class[] getClasses() throws ClassNotFoundException { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + List classes = new ArrayList(); + boolean useLoadClass = Boolean.valueOf(System.getProperty("rome.pluginmanager.useloadclass", "false")).booleanValue(); + for (int i = 0; i <_propertyValues.length; i++) { + Class mClass = (useLoadClass ? classLoader.loadClass(_propertyValues[i]) : Class.forName(_propertyValues[i], true, classLoader)); + classes.add(mClass); + } + Class[] array = new Class[classes.size()]; + classes.toArray(array); + return array; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/PropertiesLoader.java b/src/main/java/com/sun/syndication/io/impl/PropertiesLoader.java new file mode 100644 index 0000000..2954bed --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/PropertiesLoader.java @@ -0,0 +1,155 @@ +package com.sun.syndication.io.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.*; + +/** + * Properties loader that aggregates a master properties file and several extra properties files, + * all from the current classpath. + *

+ * The master properties file has to be in a distinct location than the extra properties files. + * First the master properties file is loaded, then all the extra properties files in their order + * of appearance in the classpath. + *

+ * Current use cases (plugin manager for parsers/converters/generators for feeds and modules + * and date formats) assume properties are list of tokens, that why the only method to get + * property values is the getTokenizedProperty(). + *

+ * + * @author Alejandro Abdelnur + * + */ +public class PropertiesLoader { + + private static final String MASTER_PLUGIN_FILE = "com/sun/syndication/rome.properties"; + private static final String EXTRA_PLUGIN_FILE = "rome.properties"; + + + private static Map clMap = + new WeakHashMap(); + + + /** + * Returns the PropertiesLoader singleton used by ROME to load plugin components. + * + * @return PropertiesLoader singleton. + * + */ + public static PropertiesLoader getPropertiesLoader() { + synchronized(PropertiesLoader.class) { + PropertiesLoader loader = (PropertiesLoader) + clMap.get(Thread.currentThread().getContextClassLoader()); + if (loader == null) { + try { + loader = new PropertiesLoader(MASTER_PLUGIN_FILE, EXTRA_PLUGIN_FILE); + clMap.put(Thread.currentThread().getContextClassLoader(), loader); + } + catch (IOException ex) { + throw new RuntimeException(ex); + } + } + return loader; + } + } + + private Properties[] _properties; + + /** + * Creates a PropertiesLoader. + *

+ * @param masterFileLocation master file location, there must be only one. + * @param extraFileLocation extra file location, there may be many. + * @throws IOException thrown if one of the properties file could not be read. + * + */ + private PropertiesLoader(String masterFileLocation,String extraFileLocation) throws IOException { + List propertiesList = new ArrayList(); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + + try { + InputStream is = classLoader.getResourceAsStream(masterFileLocation); + Properties p = new Properties(); + p.load(is); + is.close(); + propertiesList.add(p); + } + catch (IOException ioex) { + IOException ex = new IOException("could not load ROME master plugins file ["+masterFileLocation+"], "+ + ioex.getMessage()); + ex.setStackTrace(ioex.getStackTrace()); + throw ex; + } + + Enumeration urls = classLoader.getResources(extraFileLocation); + while (urls.hasMoreElements()) { + URL url = (URL) urls.nextElement(); + Properties p = new Properties(); + try { + InputStream is = url.openStream(); + p.load(is); + is.close(); + } + catch (IOException ioex) { + IOException ex = new IOException("could not load ROME extensions plugins file ["+url.toString()+"], "+ + ioex.getMessage()); + ex.setStackTrace(ioex.getStackTrace()); + throw ex; + } + propertiesList.add(p); + } + + _properties = new Properties[propertiesList.size()]; + propertiesList.toArray(_properties); + } + + /** + * Returns an array of tokenized values stored under a property key in all properties files. + * If the master file has this property its tokens will be the first ones in the array. + *

+ * @param key property key to retrieve values + * @param separator String with all separator characters to tokenize from the values in all + * properties files. + * @return all the tokens for the given property key from all the properties files. + * + */ + public String[] getTokenizedProperty(String key,String separator) { + List entriesList = new ArrayList(); + for (int i=0;i<_properties.length;i++) { + String values = _properties[i].getProperty(key); + if (values!=null) { + StringTokenizer st = new StringTokenizer(values,separator); + while (st.hasMoreTokens()) { + String token = st.nextToken(); + entriesList.add(token); + } + } + } + String[] entries = new String[entriesList.size()]; + entriesList.toArray(entries); + return entries; + } + + /** + * Returns an array of values stored under a property key in all properties files. + * If the master file has this property it will be the first ones in the array. + *

+ * @param key property key to retrieve values + * @return all the values for the given property key from all the properties files. + * + */ + public String[] getProperty(String key) { + List entriesList = new ArrayList(); + for (int i=0;i<_properties.length;i++) { + String values = _properties[i].getProperty(key); + if (values!=null) { + entriesList.add(values); + } + } + String[] entries = new String[entriesList.size()]; + entriesList.toArray(entries); + return entries; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS090Generator.java b/src/main/java/com/sun/syndication/io/impl/RSS090Generator.java new file mode 100644 index 0000000..f2724b8 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS090Generator.java @@ -0,0 +1,271 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.rss.*; +import com.sun.syndication.io.FeedException; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Namespace; + +import java.util.List; + + +/** + * Feed Generator for RSS 0.90 + *

+ * + * @author Elaine Chien + */ +public class RSS090Generator extends BaseWireFeedGenerator { + + private static final String RDF_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + private static final String RSS_URI = "http://my.netscape.com/rdf/simple/0.9/"; + private static final String CONTENT_URI = "http://purl.org/rss/1.0/modules/content/"; + + private static final Namespace RDF_NS = Namespace.getNamespace("rdf", RDF_URI); + private static final Namespace RSS_NS = Namespace.getNamespace(RSS_URI); + private static final Namespace CONTENT_NS = Namespace.getNamespace("content", CONTENT_URI); + + public RSS090Generator() { + this("rss_0.9"); + } + + protected RSS090Generator(String type) { + super(type); + } + + public Document generate(WireFeed feed) throws FeedException { + Channel channel = (Channel)feed; + Element root = createRootElement(channel); + populateFeed(channel,root); + purgeUnusedNamespaceDeclarations(root); + return createDocument(root); + } + + protected Namespace getFeedNamespace() { + return RSS_NS; + } + + protected Namespace getRDFNamespace() { + return RDF_NS; + } + + protected Namespace getContentNamespace() { + return CONTENT_NS; + } + + protected Document createDocument(Element root) { + return new Document(root); + } + + protected Element createRootElement(Channel channel) { + Element root = new Element("RDF",getRDFNamespace()); + root.addNamespaceDeclaration(getFeedNamespace()); + root.addNamespaceDeclaration(getRDFNamespace()); + root.addNamespaceDeclaration(getContentNamespace()); + generateModuleNamespaceDefs(root); + return root; + } + + protected void populateFeed(Channel channel, Element parent) throws FeedException { + addChannel(channel,parent); + addImage(channel,parent); + addTextInput(channel,parent); + addItems(channel,parent); + generateForeignMarkup(parent, (List)channel.getForeignMarkup()); + } + + protected void addChannel(Channel channel,Element parent) throws FeedException { + Element eChannel = new Element("channel", getFeedNamespace()); + populateChannel(channel,eChannel); + checkChannelConstraints(eChannel); + parent.addContent(eChannel); + generateFeedModules(channel.getModules(),eChannel); + } + + /** + * Populates the given channel with parsed data from the ROME element that holds the + * channel data. + * + * @param channel the channel into which parsed data will be added. + * @param eChannel the XML element that holds the data for the channel. + */ + protected void populateChannel(Channel channel,Element eChannel) { + String title = channel.getTitle(); + if (title!=null) { + eChannel.addContent(generateSimpleElement("title",title)); + } + String link = channel.getLink(); + if (link!=null) { + eChannel.addContent(generateSimpleElement("link",link)); + } + String description = channel.getDescription(); + if (description!=null) { + eChannel.addContent(generateSimpleElement("description",description)); + } + } + + // maxLen == -1 means unlimited. + protected void checkNotNullAndLength(Element parent, String childName, int minLen, int maxLen) throws FeedException { + Element child = parent.getChild(childName,getFeedNamespace()); + if (child == null) { + throw new FeedException("Invalid "+getType()+" feed, missing "+parent.getName()+" "+childName); + } + checkLength(parent,childName,minLen,maxLen); + } + + // maxLen == -1 means unlimited. + protected void checkLength(Element parent, String childName, int minLen, int maxLen) throws FeedException { + Element child = parent.getChild(childName,getFeedNamespace()); + if (child != null) { + if (minLen>0 && child.getText().length()-1 && child.getText().length()>maxLen) { + throw new FeedException("Invalid "+getType()+" feed, "+parent.getName()+" "+childName + "exceeds "+maxLen+" length"); + } + } + } + + + protected void addImage(Channel channel,Element parent) throws FeedException { + Image image = channel.getImage(); + if (image!=null) { + Element eImage = new Element("image", getFeedNamespace()); + populateImage(image,eImage); + checkImageConstraints(eImage); + parent.addContent(eImage); + } + } + + protected void populateImage(Image image,Element eImage) { + String title = image.getTitle(); + if (title!=null) { + eImage.addContent(generateSimpleElement("title",title)); + } + String url = image.getUrl(); + if (url!=null) { + eImage.addContent(generateSimpleElement("url",url)); + } + String link = image.getLink(); + if (link!=null) { + eImage.addContent(generateSimpleElement("link",link)); + } + } + + // Thxs DW for this one + protected String getTextInputLabel() { + return "textInput"; + } + + protected void addTextInput(Channel channel,Element parent) throws FeedException { + TextInput textInput = channel.getTextInput(); + if (textInput!=null) { + Element eTextInput = new Element(getTextInputLabel(), getFeedNamespace()); + populateTextInput(textInput,eTextInput); + checkTextInputConstraints(eTextInput); + parent.addContent(eTextInput); + } + } + + protected void populateTextInput(TextInput textInput,Element eTextInput) { + String title = textInput.getTitle(); + if (title!=null) { + eTextInput.addContent(generateSimpleElement("title",title)); + } + String description = textInput.getDescription(); + if (description!=null) { + eTextInput.addContent(generateSimpleElement("description",description)); + } + String name = textInput.getName(); + if (name!=null) { + eTextInput.addContent(generateSimpleElement("name",name)); + } + String link = textInput.getLink(); + if (link!=null) { + eTextInput.addContent(generateSimpleElement("link",link)); + } + } + + protected void addItems(Channel channel,Element parent) throws FeedException { + List items = channel.getItems(); + for (int i=0;i15) { + throw new FeedException("Invalid "+getType()+" feed, item count is "+count+" it must be between 1 an 15"); + } + } + + protected void checkItemConstraints(Element eItem) throws FeedException { + checkNotNullAndLength(eItem,"title", 0, 100); + checkNotNullAndLength(eItem,"link", 0, 500); + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS090Parser.java b/src/main/java/com/sun/syndication/io/impl/RSS090Parser.java new file mode 100644 index 0000000..7b636a1 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS090Parser.java @@ -0,0 +1,346 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.feed.rss.Image; +import com.sun.syndication.feed.rss.Item; +import com.sun.syndication.feed.rss.TextInput; +import com.sun.syndication.io.FeedException; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Namespace; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + */ +public class RSS090Parser extends BaseWireFeedParser { + + private static final String RDF_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + private static final String RSS_URI = "http://my.netscape.com/rdf/simple/0.9/"; + private static final String CONTENT_URI = "http://purl.org/rss/1.0/modules/content/"; + + private static final Namespace RDF_NS = Namespace.getNamespace(RDF_URI); + private static final Namespace RSS_NS = Namespace.getNamespace(RSS_URI); + private static final Namespace CONTENT_NS = Namespace.getNamespace(CONTENT_URI); + + + public RSS090Parser() { + this("rss_0.9", RSS_NS); + } + + protected RSS090Parser(String type, Namespace ns) { + super(type, ns); + } + + public boolean isMyType(Document document) { + boolean ok = false; + + Element rssRoot = document.getRootElement(); + Namespace defaultNS = rssRoot.getNamespace(); + List additionalNSs = rssRoot.getAdditionalNamespaces(); + + ok = defaultNS!=null && defaultNS.equals(getRDFNamespace()); + if (ok) { + if (additionalNSs==null) { + ok = false; + } + else { + ok = false; + for (int i=0;!ok && i + * This implementation returns the EMTPY namespace. + *

+ * + * @return returns the EMPTY namespace. + */ + protected Namespace getRSSNamespace() { + return RSS_NS; + } + + /** + * Returns the namespace used by RDF elements in document of the RSS version the parser supports. + *

+ * This implementation returns the EMTPY namespace. + *

+ * + * @return returns the EMPTY namespace. + */ + protected Namespace getRDFNamespace() { + return RDF_NS; + } + + /** + * Returns the namespace used by Content Module elements in document. + *

+ * This implementation returns the EMTPY namespace. + *

+ * + * @return returns the EMPTY namespace. + */ + protected Namespace getContentNamespace() { + return CONTENT_NS; + } + + /** + * Parses the root element of an RSS document into a Channel bean. + *

+ * It reads title, link and description and delegates to parseImage, parseItems + * and parseTextInput. This delegation always passes the root element of the RSS + * document as different RSS version may have this information in different parts + * of the XML tree (no assumptions made thanks to the specs variaty) + *

+ * + * @param rssRoot the root element of the RSS document to parse. + * @return the parsed Channel bean. + */ + protected WireFeed parseChannel(Element rssRoot) { + Element eChannel = rssRoot.getChild("channel", getRSSNamespace()); + + Channel channel = new Channel(getType()); + + Element e = eChannel.getChild("title",getRSSNamespace()); + if (e!=null) { + channel.setTitle(e.getText()); + } + e = eChannel.getChild("link",getRSSNamespace()); + if (e!=null) { + channel.setLink(e.getText()); + } + e = eChannel.getChild("description",getRSSNamespace()); + if (e!=null) { + channel.setDescription(e.getText()); + } + + channel.setImage(parseImage(rssRoot)); + + channel.setTextInput(parseTextInput(rssRoot)); + + // Unfortunately Microsoft's SSE extension has a special case of + // effectively putting the sharing channel module inside the RSS tag + // and not inside the channel itself. So we also need to look for + // channel modules from the root RSS element. + List allFeedModules = new ArrayList(); + List rootModules = parseFeedModules(rssRoot); + List channelModules = parseFeedModules(eChannel); + if (rootModules != null) { + allFeedModules.addAll(rootModules); + } + if (channelModules != null) { + allFeedModules.addAll(channelModules); + } + channel.setModules(allFeedModules); + channel.setItems(parseItems(rssRoot)); + + List foreignMarkup = + extractForeignMarkup(eChannel, channel, getRSSNamespace()); + if (foreignMarkup.size() > 0) { + channel.setForeignMarkup(foreignMarkup); + } + return channel; + } + + + /** + * This method exists because RSS0.90 and RSS1.0 have the 'item' elements under the root elemment. + * And RSS0.91, RSS0.02, RSS0.93, RSS0.94 and RSS2.0 have the item elements under the 'channel' element. + *

+ */ + protected List getItems(Element rssRoot) { + return rssRoot.getChildren("item",getRSSNamespace()); + } + + /** + * This method exists because RSS0.90 and RSS1.0 have the 'image' element under the root elemment. + * And RSS0.91, RSS0.02, RSS0.93, RSS0.94 and RSS2.0 have it under the 'channel' element. + *

+ */ + protected Element getImage(Element rssRoot) { + return rssRoot.getChild("image",getRSSNamespace()); + } + + /** + * This method exists because RSS0.90 and RSS1.0 have the 'textinput' element under the root elemment. + * And RSS0.91, RSS0.02, RSS0.93, RSS0.94 and RSS2.0 have it under the 'channel' element. + *

+ */ + protected Element getTextInput(Element rssRoot) { + return rssRoot.getChild("textinput",getRSSNamespace()); + } + + /** + * Parses the root element of an RSS document looking for image information. + *

+ * It reads title and url out of the 'image' element. + *

+ * + * @param rssRoot the root element of the RSS document to parse for image information. + * @return the parsed image bean. + */ + protected Image parseImage(Element rssRoot) { + Image image = null; + Element eImage = getImage(rssRoot); + if (eImage!=null) { + image = new Image(); + + Element e = eImage.getChild("title",getRSSNamespace()); + if (e!=null) { + image.setTitle(e.getText()); + } + e = eImage.getChild("url",getRSSNamespace()); + if (e!=null) { + image.setUrl(e.getText()); + } + e = eImage.getChild("link",getRSSNamespace()); + if (e!=null) { + image.setLink(e.getText()); + } + } + return image; + } + + /** + * Parses the root element of an RSS document looking for all items information. + *

+ * It iterates through the item elements list, obtained from the getItems() method, and invoke parseItem() + * for each item element. The resulting RSSItem of each item element is stored in a list. + *

+ * + * @param rssRoot the root element of the RSS document to parse for all items information. + * @return a list with all the parsed RSSItem beans. + */ + protected List parseItems(Element rssRoot) { + Collection eItems = getItems(rssRoot); + + List items = new ArrayList(); + for (Iterator i=eItems.iterator();i.hasNext();) { + Element eItem = (Element) i.next(); + items.add(parseItem(rssRoot,eItem)); + } + return items; + } + + /** + * Parses an item element of an RSS document looking for item information. + *

+ * It reads title and link out of the 'item' element. + *

+ * + * @param rssRoot the root element of the RSS document in case it's needed for context. + * @param eItem the item element to parse. + * @return the parsed RSSItem bean. + */ + protected Item parseItem(Element rssRoot,Element eItem) { + Item item = new Item(); + Element e = eItem.getChild("title",getRSSNamespace()); + if (e!=null) { + item.setTitle(e.getText()); + } + e = eItem.getChild("link",getRSSNamespace()); + if (e!=null) { + item.setLink(e.getText()); + item.setUri(e.getText()); + } + + item.setModules(parseItemModules(eItem)); + + List foreignMarkup = + extractForeignMarkup(eItem, item, getRSSNamespace()); + //content:encoded elements are treated special, without a module, they have to be removed from the foreign + //markup to avoid duplication in case of read/write. Note that this fix will break if a content module is + //used + Iterator iterator = foreignMarkup.iterator(); + while (iterator.hasNext()) { + Element ie = (Element)iterator.next(); + if (getContentNamespace().equals(ie.getNamespace()) && ie.getName().equals("encoded")) { + iterator.remove(); + } + } + if (foreignMarkup.size() > 0) { + item.setForeignMarkup(foreignMarkup); + } + return item; + } + + + /** + * Parses the root element of an RSS document looking for text-input information. + *

+ * It reads title, description, name and link out of the 'textinput' or 'textInput' element. + *

+ * + * @param rssRoot the root element of the RSS document to parse for text-input information. + * @return the parsed RSSTextInput bean. + */ + protected TextInput parseTextInput(Element rssRoot) { + TextInput textInput = null; + Element eTextInput = getTextInput(rssRoot); + if (eTextInput!=null) { + textInput = new TextInput(); + Element e = eTextInput.getChild("title",getRSSNamespace()); + if (e!=null) { + textInput.setTitle(e.getText()); + } + e = eTextInput.getChild("description",getRSSNamespace()); + if (e!=null) { + textInput.setDescription(e.getText()); + } + e = eTextInput.getChild("name",getRSSNamespace()); + if (e!=null) { + textInput.setName(e.getText()); + } + e = eTextInput.getChild("link",getRSSNamespace()); + if (e!=null) { + textInput.setLink(e.getText()); + } + } + return textInput; + } + + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS091NetscapeGenerator.java b/src/main/java/com/sun/syndication/io/impl/RSS091NetscapeGenerator.java new file mode 100644 index 0000000..37950f3 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS091NetscapeGenerator.java @@ -0,0 +1,61 @@ +/* + * 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 com.sun.syndication.io.impl; + +import org.jdom.DocType; +import org.jdom.Document; +import org.jdom.Element; + +/** + * Feed Generator for RSS 0.91 + *

+ * + * @author Elaine Chien + * + */ +public class RSS091NetscapeGenerator extends RSS091UserlandGenerator { + private String _version; + + public RSS091NetscapeGenerator() { + this("rss_0.91N","0.91"); + } + + protected RSS091NetscapeGenerator(String type,String version) { + super(type,version); + } + + protected Document createDocument(Element root) { + Document doc = new Document(root); + DocType docType = new DocType(RSS091NetscapeParser.ELEMENT_NAME, + RSS091NetscapeParser.PUBLIC_ID, + RSS091NetscapeParser.SYSTEM_ID); + doc.setDocType(docType); + return doc; + } + + protected String getTextInputLabel() { + return "textinput"; + } + + /** + * To be overriden by RSS 0.91 Netscape and RSS 0.94 + */ + protected boolean isHourFormat24() { + return false; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS091NetscapeParser.java b/src/main/java/com/sun/syndication/io/impl/RSS091NetscapeParser.java new file mode 100644 index 0000000..aaf979b --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS091NetscapeParser.java @@ -0,0 +1,69 @@ +/* + * 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 com.sun.syndication.io.impl; + +import org.jdom.*; + +/** + */ +public class RSS091NetscapeParser extends RSS091UserlandParser { + + public RSS091NetscapeParser() { + this("rss_0.91N"); + } + + protected RSS091NetscapeParser(String type) { + super(type); + } + + static final String ELEMENT_NAME = "rss"; + static final String PUBLIC_ID = "-//Netscape Communications//DTD RSS 0.91//EN"; + static final String SYSTEM_ID = "http://my.netscape.com/publish/formats/rss-0.91.dtd"; + + public boolean isMyType(Document document) { + boolean ok = false; + Element rssRoot = document.getRootElement(); + ok = rssRoot.getName().equals("rss"); + if (ok) { + ok = false; + Attribute version = rssRoot.getAttribute("version"); + if (version!=null) { + ok = version.getValue().equals(getRSSVersion()); + if (ok) { + ok = false; + DocType docType = document.getDocType(); + + if (docType!=null) { + ok = ELEMENT_NAME.equals(docType.getElementName()); + ok = ok && PUBLIC_ID.equals(docType.getPublicID()); + ok = ok && SYSTEM_ID.equals(docType.getSystemID()); + } + } + } + } + return ok; + } + + protected boolean isHourFormat24(Element rssRoot) { + return false; + } + + protected String getTextInputLabel() { + return "textinput"; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS091UserlandGenerator.java b/src/main/java/com/sun/syndication/io/impl/RSS091UserlandGenerator.java new file mode 100644 index 0000000..317d831 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS091UserlandGenerator.java @@ -0,0 +1,251 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.feed.rss.Description; +import com.sun.syndication.feed.rss.Image; +import com.sun.syndication.feed.rss.Item; +import com.sun.syndication.io.FeedException; +import org.jdom.Attribute; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Namespace; + +import java.util.List; +import java.util.Date; + +/** + * Feed Generator for RSS 0.91 + *

+ * + * @author Elaine Chien + * + */ +public class RSS091UserlandGenerator extends RSS090Generator { + private String _version; + + public RSS091UserlandGenerator() { + this("rss_0.91U","0.91"); + } + + protected RSS091UserlandGenerator(String type,String version) { + super(type); + _version = version; + } + + protected String getVersion() { + return _version; + } + + protected Namespace getFeedNamespace() { + return Namespace.NO_NAMESPACE; + } + + protected Document createDocument(Element root) { + return new Document(root); + } + + protected Element createRootElement(Channel channel) { + Element root = new Element("rss",getFeedNamespace()); + Attribute version = new Attribute("version", getVersion()); + root.setAttribute(version); + root.addNamespaceDeclaration(getContentNamespace()); + generateModuleNamespaceDefs(root); + return root; + } + + protected void populateFeed(Channel channel,Element parent) throws FeedException { + addChannel(channel,parent); + } + + protected void addChannel(Channel channel,Element parent) throws FeedException { + super.addChannel(channel,parent); + Element eChannel = parent.getChild("channel",getFeedNamespace()); + + addImage(channel,eChannel); + addTextInput(channel,eChannel); + addItems(channel,eChannel); + } + + protected void populateChannel(Channel channel,Element eChannel) { + super.populateChannel(channel,eChannel); + String language = channel.getLanguage(); + if (language != null) { + eChannel.addContent(generateSimpleElement("language", language)); + } + + String rating = channel.getRating(); + if (rating != null) { + eChannel.addContent(generateSimpleElement("rating", rating)); + } + + String copyright = channel.getCopyright(); + if (copyright != null) { + eChannel.addContent(generateSimpleElement("copyright", copyright)); + } + + Date pubDate = channel.getPubDate(); + if (pubDate != null) { + eChannel.addContent(generateSimpleElement("pubDate", DateParser.formatRFC822(pubDate))); + } + + Date lastBuildDate = channel.getLastBuildDate(); + if (lastBuildDate != null) { + eChannel.addContent(generateSimpleElement("lastBuildDate", DateParser.formatRFC822(lastBuildDate))); + } + + String docs = channel.getDocs(); + if (docs != null) { + eChannel.addContent(generateSimpleElement("docs", docs)); + } + + String managingEditor = channel.getManagingEditor(); + if (managingEditor != null) { + eChannel.addContent(generateSimpleElement("managingEditor", managingEditor)); + } + + String webMaster = channel.getWebMaster(); + if (webMaster != null) { + eChannel.addContent(generateSimpleElement("webMaster", webMaster)); + } + + List skipHours = channel.getSkipHours(); + if (skipHours != null && skipHours.size()>0) { + eChannel.addContent(generateSkipHoursElement(skipHours)); + } + + List skipDays = channel.getSkipDays(); + if (skipDays != null && skipDays.size()>0) { + eChannel.addContent(generateSkipDaysElement(skipDays)); + } + } + + protected Element generateSkipHoursElement(List hours) { + Element skipHoursElement = new Element("skipHours",getFeedNamespace()); + for (int i = 0; i < hours.size(); i++) { + skipHoursElement.addContent(generateSimpleElement("hour", hours.get(i).toString())); + } + return skipHoursElement; + } + + protected Element generateSkipDaysElement(List days) { + Element skipDaysElement = new Element("skipDays"); + for (int i = 0; i < days.size(); i++) { + skipDaysElement.addContent(generateSimpleElement("day", days.get(i).toString())); + } + return skipDaysElement; + } + + protected void populateImage(Image image,Element eImage) { + super.populateImage(image,eImage); + + int width = image.getWidth(); + if (width>-1) { + eImage.addContent(generateSimpleElement("width",String.valueOf(width))); + } + int height = image.getHeight(); + if (height>-1) { + eImage.addContent(generateSimpleElement("height",String.valueOf(height))); + } + + String description = image.getDescription(); + if (description!=null) { + eImage.addContent(generateSimpleElement("description",description)); + } + } + + protected void populateItem(Item item, Element eItem, int index) { + super.populateItem(item,eItem, index); + Description description = item.getDescription(); + if (description!=null) { + eItem.addContent(generateSimpleElement("description",description.getValue())); + } + if (item.getModule(getContentNamespace().getURI()) == null && item.getContent() != null) { + Element elem = new Element("encoded", getContentNamespace()); + elem.addContent(item.getContent().getValue()); + eItem.addContent(elem); + } + } + + /** + * To be overriden by RSS 0.91 Netscape and RSS 0.94 + */ + protected boolean isHourFormat24() { + return true; + } + + protected void checkChannelConstraints(Element eChannel) throws FeedException { + checkNotNullAndLength(eChannel,"title", 1, 100); + checkNotNullAndLength(eChannel,"description", 1, 500); + checkNotNullAndLength(eChannel,"link", 1, 500); + checkNotNullAndLength(eChannel,"language", 2, 5); + + checkLength(eChannel,"rating", 20, 500); + checkLength(eChannel,"copyright", 1, 100); + checkLength(eChannel,"pubDate", 1, 100); + checkLength(eChannel,"lastBuildDate", 1, 100); + checkLength(eChannel,"docs", 1, 500); + checkLength(eChannel,"managingEditor", 1, 100); + checkLength(eChannel,"webMaster", 1, 100); + + Element skipHours = eChannel.getChild("skipHours"); + if (skipHours!=null) { + List hours = skipHours.getChildren(); + for (int i=0;i24) { + throw new FeedException("Invalid hour value "+value+", it must be between 1 and 24"); + } + } + else { + if (value<0 || value>23) { + throw new FeedException("Invalid hour value "+value+", it must be between 0 and 23"); + } + } + } + } + } + + protected void checkImageConstraints(Element eImage) throws FeedException { + checkNotNullAndLength(eImage,"title", 1, 100); + checkNotNullAndLength(eImage,"url", 1, 500); + + checkLength(eImage,"link", 1, 500); + checkLength(eImage,"width", 1, 3); + checkLength(eImage,"width", 1, 3); + checkLength(eImage,"description", 1, 100); + } + + + protected void checkTextInputConstraints(Element eTextInput) throws FeedException { + checkNotNullAndLength(eTextInput,"title", 1, 100); + checkNotNullAndLength(eTextInput,"description", 1, 500); + checkNotNullAndLength(eTextInput,"name", 1, 20); + checkNotNullAndLength(eTextInput,"link", 1, 500); + } + + protected void checkItemConstraints(Element eItem) throws FeedException { + checkNotNullAndLength(eItem,"title", 1, 100); + checkNotNullAndLength(eItem,"link", 1, 500); + + checkLength(eItem,"description", 1, 500); + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS091UserlandParser.java b/src/main/java/com/sun/syndication/io/impl/RSS091UserlandParser.java new file mode 100644 index 0000000..ab07bdb --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS091UserlandParser.java @@ -0,0 +1,250 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.feed.rss.Content; +import com.sun.syndication.feed.rss.Description; +import com.sun.syndication.feed.rss.Image; +import com.sun.syndication.feed.rss.Item; +import org.jdom.Attribute; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Namespace; + +import java.util.*; + +/** + */ +public class RSS091UserlandParser extends RSS090Parser { + + public RSS091UserlandParser() { + this("rss_0.91U"); + } + + protected RSS091UserlandParser(String type) { + super(type, null); + } + + public boolean isMyType(Document document) { + boolean ok; + Element rssRoot = document.getRootElement(); + ok = rssRoot.getName().equals("rss"); + if (ok) { + ok = false; + Attribute version = rssRoot.getAttribute("version"); + if (version!=null) { + ok = version.getValue().equals(getRSSVersion()); + } + } + return ok; + } + + protected String getRSSVersion() { + return "0.91"; + } + + protected Namespace getRSSNamespace() { + return Namespace.getNamespace(""); + } + + /** + * To be overriden by RSS 0.91 Netscape and RSS 0.94 + */ + protected boolean isHourFormat24(Element rssRoot) { + return true; + } + + /** + * Parses the root element of an RSS document into a Channel bean. + *

+ * It first invokes super.parseChannel and then parses and injects the following + * properties if present: language, pubDate, rating and copyright. + *

+ * + * @param rssRoot the root element of the RSS document to parse. + * @return the parsed Channel bean. + */ + protected WireFeed parseChannel(Element rssRoot) { + Channel channel = (Channel) super.parseChannel(rssRoot); + + Element eChannel = rssRoot.getChild("channel",getRSSNamespace()); + + Element e = eChannel.getChild("language",getRSSNamespace()); + if (e!=null) { + channel.setLanguage(e.getText()); + } + e = eChannel.getChild("rating",getRSSNamespace()); + if (e!=null) { + channel.setRating(e.getText()); + } + e = eChannel.getChild("copyright",getRSSNamespace()); + if (e!=null) { + channel.setCopyright(e.getText()); + } + e = eChannel.getChild("pubDate",getRSSNamespace()); + if (e!=null) { + channel.setPubDate(DateParser.parseDate(e.getText())); + } + e = eChannel.getChild("lastBuildDate",getRSSNamespace()); + if (e!=null) { + channel.setLastBuildDate(DateParser.parseDate(e.getText())); + } + e = eChannel.getChild("docs",getRSSNamespace()); + if (e!=null) { + channel.setDocs(e.getText()); + } + e = eChannel.getChild("docs",getRSSNamespace()); + if (e!=null) { + channel.setDocs(e.getText()); + } + e = eChannel.getChild("managingEditor",getRSSNamespace()); + if (e!=null) { + channel.setManagingEditor(e.getText()); + } + e = eChannel.getChild("webMaster",getRSSNamespace()); + if (e!=null) { + channel.setWebMaster(e.getText()); + } + e = eChannel.getChild("skipHours"); + if (e!=null) { + List skipHours = new ArrayList(); + List eHours = e.getChildren("hour",getRSSNamespace()); + for (int i=0;i + * It first invokes super.parseImage and then parses and injects the following + * properties if present: url, link, width, height and description. + *

+ * + * @param rssRoot the root element of the RSS document to parse for image information. + * @return the parsed RSSImage bean. + */ + protected Image parseImage(Element rssRoot) { + Image image = super.parseImage(rssRoot); + if (image!=null) { + Element eImage = getImage(rssRoot); + Element e = eImage.getChild("width",getRSSNamespace()); + if (e!=null) { + Integer val = NumberParser.parseInt(e.getText()); + if (val != null) { + image.setWidth(val.intValue()); + } + } + e = eImage.getChild("height",getRSSNamespace()); + if (e!=null) { + Integer val = NumberParser.parseInt(e.getText()); + if (val != null) { + image.setHeight(val.intValue()); + } + } + e = eImage.getChild("description",getRSSNamespace()); + if (e!=null) { + image.setDescription(e.getText()); + } + } + return image; + } + + + /** + * It looks for the 'item' elements under the 'channel' elemment. + */ + protected List getItems(Element rssRoot) { + Element eChannel = rssRoot.getChild("channel",getRSSNamespace()); + return (eChannel!=null) ? eChannel.getChildren("item",getRSSNamespace()) : Collections.EMPTY_LIST; + } + + /** + * It looks for the 'image' elements under the 'channel' elemment. + */ + protected Element getImage(Element rssRoot) { + Element eChannel = rssRoot.getChild("channel",getRSSNamespace()); + return (eChannel!=null) ? eChannel.getChild("image",getRSSNamespace()) : null; + } + + /** + * To be overriden by RSS 0.91 Netscape parser + */ + protected String getTextInputLabel() { + return "textInput"; + } + + /** + * It looks for the 'textinput' elements under the 'channel' elemment. + */ + protected Element getTextInput(Element rssRoot) { + String elementName = getTextInputLabel(); + Element eChannel = rssRoot.getChild("channel",getRSSNamespace()); + return (eChannel!=null) ? eChannel.getChild(elementName,getRSSNamespace()) : null; + } + + /** + * Parses an item element of an RSS document looking for item information. + *

+ * It first invokes super.parseItem and then parses and injects the description property if present. + *

+ * + * @param rssRoot the root element of the RSS document in case it's needed for context. + * @param eItem the item element to parse. + * @return the parsed RSSItem bean. + */ + protected Item parseItem(Element rssRoot, Element eItem) { + Item item = super.parseItem(rssRoot,eItem); + Element e = eItem.getChild("description", getRSSNamespace()); + if (e!=null) { + item.setDescription(parseItemDescription(rssRoot,e)); + } + Element ce = eItem.getChild("encoded", getContentNamespace()); + if (ce != null) { + Content content = new Content(); + content.setType(Content.HTML); + content.setValue(ce.getText()); + item.setContent(content); + } + return item; + } + + protected Description parseItemDescription(Element rssRoot,Element eDesc) { + Description desc = new Description(); + desc.setType("text/plain"); + desc.setValue(eDesc.getText()); + return desc; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS092Generator.java b/src/main/java/com/sun/syndication/io/impl/RSS092Generator.java new file mode 100644 index 0000000..e665c88 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS092Generator.java @@ -0,0 +1,160 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.rss.*; +import com.sun.syndication.io.FeedException; +import org.jdom.Attribute; +import org.jdom.Element; + +import java.util.List; + + +/** + * Feed Generator for RSS 0.92 + *

+ * + * @author Elaine Chien + * + */ + +public class RSS092Generator extends RSS091UserlandGenerator { + + public RSS092Generator() { + this("rss_0.92","0.92"); + } + + protected RSS092Generator(String type,String version) { + super(type,version); + } + + protected void populateChannel(Channel channel,Element eChannel) { + super.populateChannel(channel,eChannel); + + Cloud cloud = channel.getCloud(); + if (cloud!=null) { + eChannel.addContent(generateCloud(cloud)); + } + } + + protected Element generateCloud(Cloud cloud) { + Element eCloud = new Element("cloud",getFeedNamespace()); + + if (cloud.getDomain() != null) { + eCloud.setAttribute(new Attribute("domain", cloud.getDomain())); + } + + if (cloud.getPort() != 0) { + eCloud.setAttribute(new Attribute("port", String.valueOf(cloud.getPort()))); + } + + if (cloud.getPath() != null) { + eCloud.setAttribute(new Attribute("path", cloud.getPath())); + } + + if (cloud.getRegisterProcedure() != null) { + eCloud.setAttribute(new Attribute("registerProcedure", cloud.getRegisterProcedure())); + } + + if (cloud.getProtocol() != null) { + eCloud.setAttribute(new Attribute("protocol", cloud.getProtocol())); + } + return eCloud; + } + + // Another one to thanks DW for + protected int getNumberOfEnclosures(List enclosures) { + return (enclosures.size()>0) ? 1 : 0; + } + + protected void populateItem(Item item, Element eItem, int index) { + super.populateItem(item,eItem, index); + + Source source =item.getSource(); + if (source != null) { + eItem.addContent(generateSourceElement(source)); + } + + List enclosures = item.getEnclosures(); + for(int i = 0; i < getNumberOfEnclosures(enclosures); i++) { + eItem.addContent(generateEnclosure((Enclosure)enclosures.get(i))); + } + + List categories = item.getCategories(); + for(int i = 0; i < categories.size(); i++) { + eItem.addContent(generateCategoryElement((Category)categories.get(i))); + } + } + + protected Element generateSourceElement(Source source) { + Element sourceElement = new Element("source",getFeedNamespace()); + if (source.getUrl() != null) { + sourceElement.setAttribute(new Attribute("url", source.getUrl())); + } + sourceElement.addContent(source.getValue()); + return sourceElement; + } + + protected Element generateEnclosure(Enclosure enclosure) { + Element enclosureElement = new Element("enclosure",getFeedNamespace()); + if (enclosure.getUrl() != null) { + enclosureElement.setAttribute("url", enclosure.getUrl()); + } + if (enclosure.getLength() != 0) { + enclosureElement.setAttribute("length", String.valueOf(enclosure.getLength())); + } + if (enclosure.getType() != null) { + enclosureElement.setAttribute("type", enclosure.getType()); + } + return enclosureElement; + } + + protected Element generateCategoryElement(Category category) { + Element categoryElement = new Element("category",getFeedNamespace()); + if (category.getDomain() != null) { + categoryElement.setAttribute("domain", category.getDomain()); + } + categoryElement.addContent(category.getValue()); + return categoryElement; + } + + + protected void checkChannelConstraints(Element eChannel) throws FeedException { + checkNotNullAndLength(eChannel,"title", 0, -1); + checkNotNullAndLength(eChannel,"description", 0, -1); + checkNotNullAndLength(eChannel,"link", 0, -1); + } + + protected void checkImageConstraints(Element eImage) throws FeedException { + checkNotNullAndLength(eImage,"title", 0, -1); + checkNotNullAndLength(eImage,"url", 0, -1); + } + + protected void checkTextInputConstraints(Element eTextInput) throws FeedException { + checkNotNullAndLength(eTextInput,"title", 0, -1); + checkNotNullAndLength(eTextInput,"description", 0, -1); + checkNotNullAndLength(eTextInput,"name", 0, -1); + checkNotNullAndLength(eTextInput,"link", 0, -1); + } + + protected void checkItemsConstraints(Element parent) throws FeedException { + } + + protected void checkItemConstraints(Element eItem) throws FeedException { + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS092Parser.java b/src/main/java/com/sun/syndication/io/impl/RSS092Parser.java new file mode 100644 index 0000000..ea930cd --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS092Parser.java @@ -0,0 +1,147 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.rss.Category; +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.feed.rss.Cloud; +import com.sun.syndication.feed.rss.Description; +import com.sun.syndication.feed.rss.Enclosure; +import com.sun.syndication.feed.rss.Item; +import com.sun.syndication.feed.rss.Source; +import org.jdom.Element; + +import java.util.ArrayList; +import java.util.List; + +/** + */ +public class RSS092Parser extends RSS091UserlandParser { + + public RSS092Parser() { + this("rss_0.92"); + } + + protected RSS092Parser(String type) { + super(type); + } + + protected String getRSSVersion() { + return "0.92"; + } + + protected WireFeed parseChannel(Element rssRoot) { + Channel channel = (Channel) super.parseChannel(rssRoot); + + Element eChannel = rssRoot.getChild("channel",getRSSNamespace()); + Element eCloud = eChannel.getChild("cloud",getRSSNamespace()); + if (eCloud!=null) { + Cloud cloud = new Cloud(); + String att = eCloud.getAttributeValue("domain");//getRSSNamespace()); DONT KNOW WHY DOESN'T WORK + if (att!=null) { + cloud.setDomain(att); + } + att = eCloud.getAttributeValue("port");//getRSSNamespace()); DONT KNOW WHY DOESN'T WORK + if (att!=null) { + cloud.setPort(Integer.parseInt(att.trim())); + } + att = eCloud.getAttributeValue("path");//getRSSNamespace()); DONT KNOW WHY DOESN'T WORK + if (att!=null) { + cloud.setPath(att); + } + att = eCloud.getAttributeValue("registerProcedure");//getRSSNamespace()); DONT KNOW WHY DOESN'T WORK + if (att!=null) { + cloud.setRegisterProcedure(att); + } + att = eCloud.getAttributeValue("protocol");//getRSSNamespace()); DONT KNOW WHY DOESN'T WORK + if (att!=null) { + cloud.setProtocol(att); + } + channel.setCloud(cloud); + } + return channel; + } + + protected Item parseItem(Element rssRoot,Element eItem) { + Item item = super.parseItem(rssRoot,eItem); + + Element e = eItem.getChild("source",getRSSNamespace()); + if (e!=null) { + Source source = new Source(); + String url = e.getAttributeValue("url");//getRSSNamespace()); DONT KNOW WHY DOESN'T WORK + source.setUrl(url); + source.setValue(e.getText()); + item.setSource(source); + } + + // 0.92 allows one enclosure occurrence, 0.93 multiple + // just saving to write some code. + List eEnclosures = eItem.getChildren("enclosure");//getRSSNamespace()); DONT KNOW WHY DOESN'T WORK + if (eEnclosures.size()>0) { + List enclosures = new ArrayList(); + for (int i=0;i0) { + cats = new ArrayList(); + for (int i=0;i + * + * @author Elaine Chien + * + */ +public class RSS093Generator extends RSS092Generator { + + public RSS093Generator() { + this("rss_0.93","0.93"); + } + + protected RSS093Generator(String feedType,String version) { + super(feedType,version); + } + + protected void populateItem(Item item, Element eItem, int index) { + super.populateItem(item,eItem, index); + + Date pubDate = item.getPubDate(); + if (pubDate != null) { + eItem.addContent(generateSimpleElement("pubDate", DateParser.formatRFC822(pubDate))); + } + + Date expirationDate = item.getExpirationDate(); + if (expirationDate != null) { + eItem.addContent(generateSimpleElement("expirationDate", DateParser.formatRFC822(expirationDate))); + } + } + + // Another one to thanks DW for + protected int getNumberOfEnclosures(List enclosures) { + return enclosures.size(); + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS093Parser.java b/src/main/java/com/sun/syndication/io/impl/RSS093Parser.java new file mode 100644 index 0000000..61f6202 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS093Parser.java @@ -0,0 +1,58 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.rss.Item; +import org.jdom.Element; + +/** + */ +public class RSS093Parser extends RSS092Parser { + + public RSS093Parser() { + this("rss_0.93"); + } + + protected RSS093Parser(String type) { + super(type); + } + + protected String getRSSVersion() { + return "0.93"; + } + + protected Item parseItem(Element rssRoot,Element eItem) { + Item item = super.parseItem(rssRoot,eItem); + Element e = eItem.getChild("pubDate",getRSSNamespace()); + if (e!=null) { + item.setPubDate(DateParser.parseDate(e.getText())); + } + e = eItem.getChild("expirationDate",getRSSNamespace()); + if (e!=null) { + item.setExpirationDate(DateParser.parseDate(e.getText())); + } + e = eItem.getChild("description",getRSSNamespace()); + if (e!=null) { + String type = e.getAttributeValue("type"); + if (type!=null) { + item.getDescription().setType(type); + } + } + return item; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS094Generator.java b/src/main/java/com/sun/syndication/io/impl/RSS094Generator.java new file mode 100644 index 0000000..a0b3b1b --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS094Generator.java @@ -0,0 +1,53 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.rss.Description; +import com.sun.syndication.feed.rss.Item; +import org.jdom.Attribute; +import org.jdom.Element; + +/** + * Feed Generator for RSS 0.94 + *

+ * + * @author Elaine Chien + * + */ + +public class RSS094Generator extends RSS093Generator { + + public RSS094Generator() { + this("rss_0.94","0.94"); + } + + protected RSS094Generator(String feedType,String version) { + super(feedType,version); + } + + protected void populateItem(Item item, Element eItem, int index) { + super.populateItem(item,eItem, index); + + Description description = item.getDescription(); + if (description!=null && description.getType()!=null) { + Element eDescription = eItem.getChild("description",getFeedNamespace()); + eDescription.setAttribute(new Attribute("type",description.getType())); + } + eItem.removeChild("expirationDate",getFeedNamespace()); + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS094Parser.java b/src/main/java/com/sun/syndication/io/impl/RSS094Parser.java new file mode 100644 index 0000000..d2f84a6 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS094Parser.java @@ -0,0 +1,105 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.feed.rss.Description; +import com.sun.syndication.feed.rss.Guid; +import com.sun.syndication.feed.rss.Item; +import org.jdom.Element; + +import java.util.List; + +/** + */ +public class RSS094Parser extends RSS093Parser { + + public RSS094Parser() { + this("rss_0.94"); + } + + protected RSS094Parser(String type) { + super(type); + } + + protected String getRSSVersion() { + return "0.94"; + } + + protected WireFeed parseChannel(Element rssRoot) { + Channel channel = (Channel) super.parseChannel(rssRoot); + Element eChannel = rssRoot.getChild("channel",getRSSNamespace()); + + List eCats = eChannel.getChildren("category",getRSSNamespace()); + channel.setCategories(parseCategories(eCats)); + + Element eTtl = eChannel.getChild("ttl",getRSSNamespace()); + if (eTtl!=null && eTtl.getText() != null ) { + Integer ttlValue = null; + try{ + ttlValue = new Integer(eTtl.getText()); + } catch(NumberFormatException nfe ){ + ; //let it go by + } + if (ttlValue != null) { + channel.setTtl(ttlValue.intValue()); + } + } + + return channel; + } + + public Item parseItem(Element rssRoot,Element eItem) { + Item item = super.parseItem(rssRoot,eItem); + item.setExpirationDate(null); + + Element e = eItem.getChild("author",getRSSNamespace()); + if (e!=null) { + item.setAuthor(e.getText()); + } + + e = eItem.getChild("guid",getRSSNamespace()); + if (e!=null) { + Guid guid = new Guid(); + String att = e.getAttributeValue("isPermaLink");//getRSSNamespace()); DONT KNOW WHY DOESN'T WORK + if (att!=null) { + guid.setPermaLink(att.equalsIgnoreCase("true")); + } + guid.setValue(e.getText()); + item.setGuid(guid); + } + + e = eItem.getChild("comments",getRSSNamespace()); + if (e!=null) { + item.setComments(e.getText()); + } + + return item; + } + + protected Description parseItemDescription(Element rssRoot,Element eDesc) { + Description desc = super.parseItemDescription(rssRoot,eDesc); + String att = eDesc.getAttributeValue("type");//getRSSNamespace()); DONT KNOW WHY DOESN'T WORK + if (att==null) { + att = "text/html"; + } + desc.setType(att); + return desc; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS10Generator.java b/src/main/java/com/sun/syndication/io/impl/RSS10Generator.java new file mode 100644 index 0000000..5be2728 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS10Generator.java @@ -0,0 +1,126 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.rss.Description; +import com.sun.syndication.feed.rss.Item; +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.io.FeedException; +import org.jdom.Element; +import org.jdom.Namespace; + +import java.util.List; + +/** + * Feed Generator for RSS 1.0 + *

+ * + * @author Elaine Chien + * + */ + +public class RSS10Generator extends RSS090Generator { + + private static final String RSS_URI = "http://purl.org/rss/1.0/"; + private static final Namespace RSS_NS = Namespace.getNamespace(RSS_URI); + + public RSS10Generator() { + super("rss_1.0"); + } + + protected RSS10Generator(String feedType) { + super(feedType); + } + + protected Namespace getFeedNamespace() { + return RSS_NS; + } + + protected void populateChannel(Channel channel,Element eChannel) { + super.populateChannel(channel,eChannel); + if (channel.getUri() != null) { + eChannel.setAttribute("about", channel.getUri(), getRDFNamespace()); + } + List items = channel.getItems(); + if (items.size()>0) { + Element eItems = new Element("items",getFeedNamespace()); + Element eSeq = new Element("Seq",getRDFNamespace()); + for (int i=0;i + * It checks for RDF ("http://www.w3.org/1999/02/22-rdf-syntax-ns#") and + * RSS ("http://purl.org/rss/1.0/") namespaces being defined in the root element. + * + * @param document document to check if it can be parsed with this parser implementation. + * @return true if the document is RSS1., false otherwise. + */ + public boolean isMyType(Document document) { + boolean ok = false; + + Element rssRoot = document.getRootElement(); + Namespace defaultNS = rssRoot.getNamespace(); + List additionalNSs = rssRoot.getAdditionalNamespaces(); + + ok = defaultNS!=null && defaultNS.equals(getRDFNamespace()); + if (ok) { + if (additionalNSs==null) { + ok = false; + } + else { + ok = false; + for (int i=0;!ok && i + * + * @return returns "http://purl.org/rss/1.0/". + */ + protected Namespace getRSSNamespace() { + return Namespace.getNamespace(RSS_URI); + } + + /** + * Parses an item element of an RSS document looking for item information. + *

+ * It first invokes super.parseItem and then parses and injects the description property if present. + *

+ * + * @param rssRoot the root element of the RSS document in case it's needed for context. + * @param eItem the item element to parse. + * @return the parsed RSSItem bean. + */ + protected Item parseItem(Element rssRoot,Element eItem) { + Item item = super.parseItem(rssRoot,eItem); + Element e = eItem.getChild("description", getRSSNamespace()); + if (e!=null) { + item.setDescription(parseItemDescription(rssRoot,e)); + } + Element ce = eItem.getChild("encoded", getContentNamespace()); + if (ce != null) { + Content content = new Content(); + content.setType(Content.HTML); + content.setValue(ce.getText()); + item.setContent(content); + } + + String uri = eItem.getAttributeValue("about", getRDFNamespace()); + if (uri != null) { + item.setUri(uri); + } + + return item; + } + + protected WireFeed parseChannel(Element rssRoot) { + Channel channel = (Channel) super.parseChannel(rssRoot); + + Element eChannel = rssRoot.getChild("channel", getRSSNamespace()); + String uri = eChannel.getAttributeValue("about", getRDFNamespace()); + if (uri != null) { + channel.setUri(uri); + } + + return channel; + } + + protected Description parseItemDescription(Element rssRoot,Element eDesc) { + Description desc = new Description(); + desc.setType("text/plain"); + desc.setValue(eDesc.getText()); + return desc; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS20Generator.java b/src/main/java/com/sun/syndication/io/impl/RSS20Generator.java new file mode 100644 index 0000000..4df28dc --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS20Generator.java @@ -0,0 +1,92 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.rss.Category; +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.feed.rss.Guid; +import com.sun.syndication.feed.rss.Item; +import org.jdom.Element; + +import java.util.List; + + +/** + * Feed Generator for RSS 2.0 + *

+ * + * @author Elaine Chien + * + */ + +public class RSS20Generator extends RSS094Generator { + + public RSS20Generator() { + this("rss_2.0","2.0"); + } + + protected RSS20Generator(String feedType,String version) { + super(feedType,version); + } + + protected void populateChannel(Channel channel,Element eChannel) { + super.populateChannel(channel,eChannel); + + String generator = channel.getGenerator(); + if (generator != null) { + eChannel.addContent(generateSimpleElement("generator", generator)); + } + + int ttl = channel.getTtl(); + if (ttl>-1) { + eChannel.addContent(generateSimpleElement("ttl", String.valueOf(ttl))); + } + + List categories = channel.getCategories(); + for(int i = 0; i < categories.size(); i++) { + eChannel.addContent(generateCategoryElement((Category)categories.get(i))); + } + + } + + public void populateItem(Item item, Element eItem, int index) { + super.populateItem(item,eItem, index); + + Element eDescription = eItem.getChild("description",getFeedNamespace()); + if (eDescription != null) eDescription.removeAttribute("type"); + + String author = item.getAuthor(); + if (author != null) { + eItem.addContent(generateSimpleElement("author", author)); + } + + String comments = item.getComments(); + if (comments != null) { + eItem.addContent(generateSimpleElement("comments", comments)); + } + + Guid guid = item.getGuid(); + if (guid != null) { + Element eGuid = generateSimpleElement("guid",guid.getValue()); + if (!guid.isPermaLink()) { + eGuid.setAttribute("isPermaLink", "false"); + } + eItem.addContent(eGuid); + } + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS20Parser.java b/src/main/java/com/sun/syndication/io/impl/RSS20Parser.java new file mode 100644 index 0000000..d909fa1 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS20Parser.java @@ -0,0 +1,66 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.rss.Description; +import org.jdom.Attribute; +import org.jdom.Document; +import org.jdom.Element; + +/** + */ +public class RSS20Parser extends RSS094Parser { + + public RSS20Parser() { + this("rss_2.0"); + } + + protected RSS20Parser(String type) { + super(type); + } + + protected String getRSSVersion() { + return "2.0"; + } + + protected boolean isHourFormat24(Element rssRoot) { + return false; + } + + protected Description parseItemDescription(Element rssRoot,Element eDesc) { + Description desc = super.parseItemDescription(rssRoot,eDesc); + desc.setType("text/html"); // change as per https://rome.dev.java.net/issues/show_bug.cgi?id=26 + return desc; + } + + public boolean isMyType(Document document) { + boolean ok; + Element rssRoot = document.getRootElement(); + ok = rssRoot.getName().equals("rss"); + if (ok) { + ok = false; + Attribute version = rssRoot.getAttribute("version"); + if (version!=null) { + // At this point, as far ROME is concerned RSS 2.0, 2.00 and + // 2.0.X are all the same, so let's use startsWith for leniency. + ok = version.getValue().startsWith(getRSSVersion()); + } + } + return ok; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/RSS20wNSParser.java b/src/main/java/com/sun/syndication/io/impl/RSS20wNSParser.java new file mode 100644 index 0000000..0292458 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/RSS20wNSParser.java @@ -0,0 +1,73 @@ +/* + * 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 com.sun.syndication.io.impl; + +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Namespace; +import com.sun.syndication.feed.WireFeed; + + +/** + * To address issue with certain feeds (brought up by Charles Miller): + * + * "During the debacle that was the rollout of RSS2.0, this namespace was tried, + * and even appeared in Dave Winer's Scripting News feed for a while. It was + * then withdrawn, but the wonderful thing about standards is the moment you + * roll one out, even if it's marked as unfinished and subject to change, + * someone will end up stuck with it forever." + * + * Note that there is not counter part on the generator, we only generate the final RSS2 + * + */ +public class RSS20wNSParser extends RSS20Parser { + private static String RSS20_URI = "http://backend.userland.com/rss2"; + + public RSS20wNSParser() { + this("rss_2.0wNS"); + } + + protected RSS20wNSParser(String type) { + super(type); + } + + public boolean isMyType(Document document) { + Element rssRoot = document.getRootElement(); + Namespace defaultNS = rssRoot.getNamespace(); + boolean ok = defaultNS!=null && defaultNS.equals(getRSSNamespace()); + if (ok) { + ok = super.isMyType(document); + } + return ok; + } + + protected Namespace getRSSNamespace() { + return Namespace.getNamespace(RSS20_URI); + } + + /** + * After we parse the feed we put "rss_2.0" in it (so converters and generators work) + * this parser is a phantom. + * + */ + protected WireFeed parseChannel(Element rssRoot) { + WireFeed wFeed = super.parseChannel(rssRoot); + wFeed.setFeedType("rss_2.0"); + return wFeed; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/SyModuleGenerator.java b/src/main/java/com/sun/syndication/io/impl/SyModuleGenerator.java new file mode 100644 index 0000000..7e717c6 --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/SyModuleGenerator.java @@ -0,0 +1,87 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.SyModule; +import com.sun.syndication.io.ModuleGenerator; +import org.jdom.Element; +import org.jdom.Namespace; + +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; + +/** + * Feed Generator for SY ModuleImpl + *

+ * + * @author Elaine Chien + * + */ + +public class SyModuleGenerator implements ModuleGenerator { + + private static final String SY_URI = "http://purl.org/rss/1.0/modules/syndication/"; + private static final Namespace SY_NS = Namespace.getNamespace("sy", SY_URI); + + private static final Set NAMESPACES; + + static { + Set nss = new HashSet(); + nss.add(SY_NS); + NAMESPACES = Collections.unmodifiableSet(nss); + } + + public String getNamespaceUri() { + return SY_URI; + } + + /** + * Returns a set with all the URIs (JDOM Namespace elements) this module generator uses. + *

+ * It is used by the the feed generators to add their namespace definition in + * the root element of the generated document (forward-missing of Java 5.0 Generics). + *

+ * + * @return a set with all the URIs (JDOM Namespace elements) this module generator uses. + */ + public Set getNamespaces() { + return NAMESPACES; + } + + public void generate(Module module, Element element) { + + SyModule syModule = (SyModule)module; + + if (syModule.getUpdatePeriod() != null) { + Element updatePeriodElement = new Element("updatePeriod", SY_NS); + updatePeriodElement.addContent(syModule.getUpdatePeriod()); + element.addContent(updatePeriodElement); + } + + Element updateFrequencyElement = new Element("updateFrequency", SY_NS); + updateFrequencyElement.addContent(String.valueOf(syModule.getUpdateFrequency())); + element.addContent(updateFrequencyElement); + + if (syModule.getUpdateBase() != null) { + Element updateBaseElement = new Element("updateBase", SY_NS); + updateBaseElement.addContent(DateParser.formatW3CDateTime(syModule.getUpdateBase())); + element.addContent(updateBaseElement); + } + } +} diff --git a/src/main/java/com/sun/syndication/io/impl/SyModuleParser.java b/src/main/java/com/sun/syndication/io/impl/SyModuleParser.java new file mode 100644 index 0000000..3ec6adf --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/SyModuleParser.java @@ -0,0 +1,59 @@ +/* + * 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 com.sun.syndication.io.impl; + +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.SyModule; +import com.sun.syndication.feed.module.SyModuleImpl; +import com.sun.syndication.io.ModuleParser; +import org.jdom.Element; +import org.jdom.Namespace; + +/** + */ +public class SyModuleParser implements ModuleParser { + public String getNamespaceUri() { + return SyModule.URI; + } + + private Namespace getDCNamespace() { + return Namespace.getNamespace(SyModule.URI); + } + + public Module parse(Element syndRoot) { + boolean foundSomething = false; + SyModule sm = new SyModuleImpl(); + + Element e = syndRoot.getChild("updatePeriod",getDCNamespace()); + if (e!=null) { + foundSomething = true; + sm.setUpdatePeriod(e.getText()); + } + e = syndRoot.getChild("updateFrequency",getDCNamespace()); + if (e!=null) { + foundSomething = true; + sm.setUpdateFrequency(Integer.parseInt(e.getText().trim())); + } + e = syndRoot.getChild("updateBase",getDCNamespace()); + if (e!=null) { + foundSomething = true; + sm.setUpdateBase(DateParser.parseDate(e.getText())); + } + return (foundSomething) ? sm : null; + } + +} diff --git a/src/main/java/com/sun/syndication/io/impl/XmlFixerReader.java b/src/main/java/com/sun/syndication/io/impl/XmlFixerReader.java new file mode 100644 index 0000000..3ca695e --- /dev/null +++ b/src/main/java/com/sun/syndication/io/impl/XmlFixerReader.java @@ -0,0 +1,652 @@ +/* + * Copyright 2005 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 com.sun.syndication.io.impl; + +import java.io.IOException; +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +/** + * @author Alejandro Abdelnur + */ +public class XmlFixerReader extends Reader { + + protected Reader in; + + public XmlFixerReader(Reader in) { + super(in); + this.in = in; + _buffer = new StringBuffer(); + _state = 0; + } + + private boolean trimmed; + private StringBuffer _buffer; + private int _bufferPos; + private int _state = 0; + + private boolean trimStream() throws IOException { + boolean hasContent = true; + int state = 0; + boolean loop; + int c; + do { + switch (state) { + case 0: + c = in.read(); + if (c==-1) { + loop = false; + hasContent = false; + } + else + if (c==' ' || c=='\n') { + loop = true; + } + else + if (c=='<') { + state = 1; + _buffer.setLength(0); + _bufferPos = 0; + _buffer.append((char)c); + loop = true; + } + else { + _buffer.setLength(0); + _bufferPos = 0; + _buffer.append((char)c); + loop = false; + hasContent = true; + _state = 3; + } + break; + case 1: + c = in.read(); + if (c==-1) { + loop = false; + hasContent = true; + _state = 3; + } + else + if (c!='!') { + _buffer.append((char)c); + _state = 3; + loop = false; + hasContent = true; + _state = 3; + } + else { + _buffer.append((char)c); + state = 2; + loop = true; + } + break; + case 2: + c = in.read(); + if (c==-1) { + loop = false; + hasContent = true; + _state = 3; + } + else + if (c=='-') { + _buffer.append((char)c); + state = 3; + loop = true; + } + else { + _buffer.append((char)c); + loop = false; + hasContent = true; + _state = 3; + } + break; + case 3: + c = in.read(); + if (c==-1) { + loop = false; + hasContent = true; + _state = 3; + } + else + if (c=='-') { + _buffer.append((char)c); + state = 4; + loop = true; + } + else { + _buffer.append((char)c); + loop = false; + hasContent = true; + _state = 3; + } + break; + case 4: + c = in.read(); + if (c==-1) { + loop = false; + hasContent = true; + _state = 3; + } + else + if (c!='-') { + _buffer.append((char)c); + loop = true; + } + else { + _buffer.append((char)c); + state = 5; + loop = true; + } + break; + case 5: + c = in.read(); + if (c==-1) { + loop = false; + hasContent = true; + _state = 3; + } + else + if (c!='-') { + _buffer.append((char)c); + loop = true; + state = 4; + } + else { + _buffer.append((char)c); + state = 6; + loop = true; + } + break; + case 6: + c = in.read(); + if (c==-1) { + loop = false; + hasContent = true; + _state = 3; + } + else + if (c!='>') { + _buffer.append((char)c); + loop = true; + state = 4; + } + else { + _buffer.setLength(0); + state = 0; + loop = true; + } + break; + default: + throw new IOException("It shouldn't happen"); + } + } while (loop); + return hasContent; + } + + public int read() throws IOException { + boolean loop; + if (!trimmed) { // trims XML stream + trimmed = true; + if (!trimStream()) { + return -1; + } + } + int c; + do { // converts literal entities to coded entities + switch (_state) { + case 0: // reading chars from stream + c = in.read(); + if (c>-1) { + if (c=='&') { + _state = 1; + _buffer.setLength(0); + _bufferPos = 0; + _buffer.append((char)c); + _state = 1; + loop = true; + } + else { + loop = false; + } + } + else { + loop = false; + } + break; + case 1: // reading entity from stream + c = in.read(); + if (c>-1) { + if (c==';') { + _buffer.append((char)c); + _state = 2; + loop = true; + } + else + if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c=='#') || (c>='0' && c<='9')) { + _buffer.append((char)c); + loop = true; + } + else { + // no ';' to match the '&' lets just make the '&' + // a legal xml character entity '&' + _buffer.insert(1, "amp;"); + _buffer.append((char)c); + _state = 3; + loop = true; + } + } + else { + // no ';' to match the '&' lets just make the '&' + // a legal xml character entity '&' + _buffer.insert(1, "amp;"); + _state = 3; + loop = true; + } + break; + case 2: // replacing entity + c = 0; + String literalEntity = _buffer.toString(); + String codedEntity = (String) CODED_ENTITIES.get(literalEntity); + if (codedEntity!=null) { + _buffer.setLength(0); + _buffer.append(codedEntity); + } // else we leave what was in the stream + _state = 3; + loop = true; + break; + case 3: // consuming buffer + if (_bufferPos<_buffer.length()) { + c = _buffer.charAt(_bufferPos++); + loop = false; + } + else { + c = 0; + _state = 0; + loop = true; + } + break; + default: + throw new IOException("It shouldn't happen"); + } + } while (loop); + return c; + } + + public int read(char[] buffer,int offset,int len) throws IOException { + int charsRead = 0; + int c = read(); + if (c==-1) { + return -1; + } + buffer[offset+(charsRead++)] = (char) c; + while (charsRead-1) { + buffer[offset+(charsRead++)] = (char) c; + } + return charsRead; + } + + public long skip(long n) throws IOException { + if (n==0) { + return 0; + } + else + if (n<0) { + throw new IllegalArgumentException("'n' cannot be negative"); + } + int c = read(); + long counter = 1; + while (c>-1 && counterpos) { + sb.append(s.substring(pos,b)); + pos = b; + } + chunck = s.substring(pos,e); + String codedEntity = (String) CODED_ENTITIES.get(chunck); + if (codedEntity==null) { + codedEntity = chunck; + } + sb.append(codedEntity); + pos = e; + } + else { + sb.append(chunck); + pos += chunck.length(); + } + } + return sb.toString(); + } + +} diff --git a/src/main/resources/com/sun/syndication/rome.properties b/src/main/resources/com/sun/syndication/rome.properties new file mode 100644 index 0000000..b8c096a --- /dev/null +++ b/src/main/resources/com/sun/syndication/rome.properties @@ -0,0 +1,143 @@ +# +# 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. +# + + +# Feed Parser implementation classes +# +WireFeedParser.classes=com.sun.syndication.io.impl.RSS090Parser \ + com.sun.syndication.io.impl.RSS091NetscapeParser \ + com.sun.syndication.io.impl.RSS091UserlandParser \ + com.sun.syndication.io.impl.RSS092Parser \ + com.sun.syndication.io.impl.RSS093Parser \ + com.sun.syndication.io.impl.RSS094Parser \ + com.sun.syndication.io.impl.RSS10Parser \ + com.sun.syndication.io.impl.RSS20wNSParser \ + com.sun.syndication.io.impl.RSS20Parser \ + com.sun.syndication.io.impl.Atom10Parser \ + com.sun.syndication.io.impl.Atom03Parser + +# Parsers for Atom 1.0 feed modules +# +atom_1.0.feed.ModuleParser.classes=com.sun.syndication.io.impl.SyModuleParser \ + com.sun.syndication.io.impl.DCModuleParser + +# Parsers for Atom 1.0 entry modules +# +atom_1.0.item.ModuleParser.classes=com.sun.syndication.io.impl.DCModuleParser + +# Parsers for Atom 0.3 feed modules +# +atom_0.3.feed.ModuleParser.classes=com.sun.syndication.io.impl.SyModuleParser \ + com.sun.syndication.io.impl.DCModuleParser + +# Parsers for Atom 0.3 entry modules +# +atom_0.3.item.ModuleParser.classes=com.sun.syndication.io.impl.DCModuleParser + +# Parsers for RSS 1.0 feed modules +# +rss_1.0.feed.ModuleParser.classes=com.sun.syndication.io.impl.SyModuleParser \ + com.sun.syndication.io.impl.DCModuleParser + +# Parsers for RSS 1.0 item modules +# +rss_1.0.item.ModuleParser.classes=com.sun.syndication.io.impl.DCModuleParser + +# Parsers for RSS 2.0 (w/NS) feed modules +# +rss_2.0wNS.feed.ModuleParser.classes=com.sun.syndication.io.impl.DCModuleParser + +# Parsers for RSS 2.0 (w/NS) item modules +# +rss_2.0wNS.item.ModuleParser.classes=com.sun.syndication.io.impl.DCModuleParser + +# Parsers for RSS 2.0 feed modules +# +rss_2.0.feed.ModuleParser.classes=com.sun.syndication.io.impl.DCModuleParser + +# Parsers for RSS 2.0 item modules +# +rss_2.0.item.ModuleParser.classes=com.sun.syndication.io.impl.DCModuleParser + + + + +# Feed Generator implementation classes +# +WireFeedGenerator.classes=com.sun.syndication.io.impl.RSS090Generator \ + com.sun.syndication.io.impl.RSS091NetscapeGenerator \ + com.sun.syndication.io.impl.RSS091UserlandGenerator \ + com.sun.syndication.io.impl.RSS092Generator \ + com.sun.syndication.io.impl.RSS093Generator \ + com.sun.syndication.io.impl.RSS094Generator \ + com.sun.syndication.io.impl.RSS10Generator \ + com.sun.syndication.io.impl.RSS20Generator \ + com.sun.syndication.io.impl.Atom10Generator \ + com.sun.syndication.io.impl.Atom03Generator + +# Generators for Atom 1.0 feed modules +# +atom_1.0.feed.ModuleGenerator.classes=com.sun.syndication.io.impl.SyModuleGenerator \ + com.sun.syndication.io.impl.DCModuleGenerator + +# Generators for Atom 1.0 entry modules +# +atom_1.0.item.ModuleGenerator.classes=com.sun.syndication.io.impl.DCModuleGenerator + +# Generators for Atom 0.3 feed modules +# +atom_0.3.feed.ModuleGenerator.classes=com.sun.syndication.io.impl.SyModuleGenerator \ + com.sun.syndication.io.impl.DCModuleGenerator + +# Generators for Atom 0.3 entry modules +# +atom_0.3.item.ModuleGenerator.classes=com.sun.syndication.io.impl.DCModuleGenerator + +# Generators for RSS 1.0 feed modules +# +rss_1.0.feed.ModuleGenerator.classes=com.sun.syndication.io.impl.SyModuleGenerator \ + com.sun.syndication.io.impl.DCModuleGenerator + +# Generators for RSS_1.0 entry modules +# +rss_1.0.item.ModuleGenerator.classes=com.sun.syndication.io.impl.DCModuleGenerator + +# Generators for RSS 2.0 feed modules +# +rss_2.0.feed.ModuleGenerator.classes=com.sun.syndication.io.impl.DCModuleGenerator + +# Generators for RSS_2.0 entry modules +# +rss_2.0.item.ModuleGenerator.classes=com.sun.syndication.io.impl.DCModuleGenerator + + + + +# Feed Conversor implementation classes +# +Converter.classes=com.sun.syndication.feed.synd.impl.ConverterForAtom10 \ + com.sun.syndication.feed.synd.impl.ConverterForAtom03 \ + com.sun.syndication.feed.synd.impl.ConverterForRSS090 \ + com.sun.syndication.feed.synd.impl.ConverterForRSS091Netscape \ + com.sun.syndication.feed.synd.impl.ConverterForRSS091Userland \ + com.sun.syndication.feed.synd.impl.ConverterForRSS092 \ + com.sun.syndication.feed.synd.impl.ConverterForRSS093 \ + com.sun.syndication.feed.synd.impl.ConverterForRSS094 \ + com.sun.syndication.feed.synd.impl.ConverterForRSS10 \ + com.sun.syndication.feed.synd.impl.ConverterForRSS20 + + + diff --git a/src/test/data/atom_0.3.xml b/src/test/data/atom_0.3.xml new file mode 100644 index 0000000..9d0950d --- /dev/null +++ b/src/test/data/atom_0.3.xml @@ -0,0 +1,70 @@ + + + atom_0.3.feed.title + + rometest + + atom_0.3.feed.author.name + atom_0.3.feed.author.url + atom_0.3.feed.author.email + + + atom_0.3.feed.contributor.name + atom_0.3.feed.contributor.url + atom_0.3.feed.contributor.email + + atom_0.3.feed.tagline + atom_0.3.feed.id + atom_0.3.feed.generator + atom_0.3.feed.copyright + atom_0.3.feed.info + 2000-01-01T00:00:00Z + + atom_0.3.feed.entry[0].title + + atom_0.3.feed.entry[0]^id + + atom_0.3.feed.entry[0].author.name + atom_0.3.feed.entry[0].author.url + atom_0.3.feed.entry[0].author.email + + + atom_0.3.feed.entry[0].contributor.name + atom_0.3.feed.entry[0].contributor.url + atom_0.3.feed.entry[0].contributor.email + + 2000-01-01T00:00:00Z + 2000-01-01T01:00:00Z + 2000-01-01T02:00:00Z +

atom_0.3.feed.entry[0].summary + atom_0.3.feed.entry[0].content[0] + atom_0.3.feed.entry[0].content[1] + rometest + + + atom_0.3.feed.entry[1].title + + atom_0.3.feed.entry[1]^id + + atom_0.3.feed.entry[1].author.name + atom_0.3.feed.entry[1].author.url + atom_0.3.feed.entry[1].author.email + + + atom_0.3.feed.entry[1].contributor.name + atom_0.3.feed.entry[1].contributor.url + atom_0.3.feed.entry[1].contributor.email + + 2000-02-01T00:00:00Z + 2000-02-01T01:00:00Z + 2000-02-01T02:00:00Z + atom_0.3.feed.entry[1].summary + atom_0.3.feed.entry[1].content[0] + atom_0.3.feed.entry[1].content[1] + rometest + + diff --git a/src/test/data/atom_0.3_DC_Sy.xml b/src/test/data/atom_0.3_DC_Sy.xml new file mode 100644 index 0000000..0044d56 --- /dev/null +++ b/src/test/data/atom_0.3_DC_Sy.xml @@ -0,0 +1,141 @@ + + + + atom_0.3.feed.title + + + atom_0.3.feed.author.name + atom_0.3.feed.author.url + atom_0.3.feed.author.email + + + atom_0.3.feed.contributor.name + atom_0.3.feed.contributor.url + atom_0.3.feed.contributor.email + + atom_0.3.feed.tagline + atom_0.3.feed.id + atom_0.3.feed.generator + atom_0.3.feed.copyright + atom_0.3.feed.info + 2000-01-01T00:00:00Z + + atom_0.3.feed.dc:title + atom_0.3.feed.dc:creator + + + + atom_0.3.feed.dc:subject[0] + + + + + + atom_0.3.feed.dc:subject[1] + + + atom_0.3.feed.dc:description + atom_0.3.feed.dc:publisher + atom_0.3.feed.dc:contributor[0] + atom_0.3.feed.dc:contributor[1] + 2001-01-04T00:00+00:00 + atom_0.3.feed.dc:type + atom_0.3.feed.dc:format + atom_0.3.feed.dc:identifier + atom_0.3.feed.dc:source + atom_0.3.feed.dc:language + atom_0.3.feed.dc:relation + atom_0.3.feed.dc:coverage + atom_0.3.feed.dc:rights + + hourly + 100 + 2001-01-01T01:00+00:00 + + + atom_0.3.feed.entry[0].title + + atom_0.3.feed.entry[0]^id + + atom_0.3.feed.entry[0].author.name + atom_0.3.feed.entry[0].author.url + atom_0.3.feed.entry[0].author.email + + + atom_0.3.feed.entry[0].contributor.name + atom_0.3.feed.entry[0].contributor.url + atom_0.3.feed.entry[0].contributor.email + + 2000-01-01T00:00:00Z + 2000-01-02T01:00:00Z + 2000-01-03T02:00:00Z + atom_0.3.feed.entry[0].summary + atom_0.3.feed.entry[0].content[0] + atom_0.3.feed.entry[0].content[1] + + atom_0.3.feed.entry[0].dc:title + atom_0.3.feed.entry[0].dc:creator + atom_0.3.feed.entry[0].dc:subject[0] + atom_0.3.feed.entry[0].dc:subject[1] + atom_0.3.feed.entry[0].dc:description + atom_0.3.feed.entry[0].dc:publisher + atom_0.3.feed.entry[0].dc:contributor[0] + atom_0.3.feed.entry[0].dc:contributor[1] + 2001-01-04T00:00+00:00 + atom_0.3.feed.entry[0].dc:type + atom_0.3.feed.entry[0].dc:format + atom_0.3.feed.entry[0].dc:identifier + atom_0.3.feed.entry[0].dc:source + atom_0.3.feed.entry[0].dc:language + atom_0.3.feed.entry[0].dc:relation + atom_0.3.feed.entry[0].dc:coverage + atom_0.3.feed.entry[0].dc:rights + + + + atom_0.3.feed.entry[1].title + + atom_0.3.feed.entry[1]^id + + atom_0.3.feed.entry[1].author.name + atom_0.3.feed.entry[1].author.url + atom_0.3.feed.entry[1].author.email + + + atom_0.3.feed.entry[1].contributor.name + atom_0.3.feed.entry[1].contributor.url + atom_0.3.feed.entry[1].contributor.email + + 2000-02-01T00:00:00Z + 2000-02-02T01:00:00Z + 2000-02-03T02:00:00Z + atom_0.3.feed.entry[1].summary + atom_0.3.feed.entry[1].content[0] + atom_0.3.feed.entry[1].content[1] + + atom_0.3.feed.entry[1].dc:title + atom_0.3.feed.entry[1].dc:creator + atom_0.3.feed.entry[1].dc:subject[0] + atom_0.3.feed.entry[1].dc:subject[1] + atom_0.3.feed.entry[1].dc:description + atom_0.3.feed.entry[1].dc:publisher + atom_0.3.feed.entry[1].dc:contributor[0] + atom_0.3.feed.entry[1].dc:contributor[1] + 2001-02-04T00:00+00:00 + atom_0.3.feed.entry[1].dc:type + atom_0.3.feed.entry[1].dc:format + atom_0.3.feed.entry[1].dc:identifier + atom_0.3.feed.entry[1].dc:source + atom_0.3.feed.entry[1].dc:language + atom_0.3.feed.entry[1].dc:relation + atom_0.3.feed.entry[1].dc:coverage + atom_0.3.feed.entry[1].dc:rights + + + diff --git a/src/test/data/atom_1.0.xml b/src/test/data/atom_1.0.xml new file mode 100644 index 0000000..9d83939 --- /dev/null +++ b/src/test/data/atom_1.0.xml @@ -0,0 +1,78 @@ + + + atom_1.0.feed.title + + + + rometest + + atom_1.0.feed.author.name + http://example.com + author0@example.com + + + atom_1.0.feed.contributor.name + http://example.com + author1@example.com + + atom_1.0.feed.tagline + http://example.com/blog/atom_1.0.xml + atom_1.0.feed.generator +atom_1.0.feed.copyright + 2000-01-01T00:00:00Z + + atom_1.0.feed.entry[0].title + + + + + http://example.com/blog/entry1 + + atom_1.0.feed.entry[0].author.name + http://example.com + author0@example.com + + + atom_1.0.feed.entry[0].contributor.name + http://example.com + author1@example.com + + 2000-01-01T00:00:00Z + 2000-01-01T01:00:00Z + atom_1.0.feed.entry[0].summary + atom_1.0.feed.entry[0].content[0] + rometest + atom_1.0.feed.entry[0].rights + + + atom_1.0.feed.entry[1].title + + + + http://example.com/blog/entry2 + + atom_1.0.feed.entry[1].author.name + http://example.com + author0@example.com + + + atom_1.0.feed.entry[1].contributor.name + http://example.com + author1@example.com + + 2000-02-01T00:00:00Z + 2000-02-01T01:00:00Z + atom_1.0.feed.entry[1].summary + atom_1.0.feed.entry[1].content[0] + rometest + + diff --git a/src/test/data/atom_1.0_b.xml b/src/test/data/atom_1.0_b.xml new file mode 100644 index 0000000..cbbc080 --- /dev/null +++ b/src/test/data/atom_1.0_b.xml @@ -0,0 +1,134 @@ + + + xml:base support tests + All alternate links should point to <code>http://example.org/tests/base/result.html</code>; all links in content should point where their label says. + + + tag:plasmasturm.org,2005:Atom-Tests:xml-base + 2006-01-17T12:35:16+01:00 + + + 1: Alternate link: Absolute URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test1 + 2006-01-17T12:35:16+01:00 + + + + 2: Alternate link: Host-relative absolute URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test2 + 2006-01-17T12:35:15+01:00 + + + + 3: Alternate link: Relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test3 + 2006-01-17T12:35:14+01:00 + + + + 4: Alternate link: Relative URL with parent directory component + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test4 + 2006-01-17T12:35:13+01:00 + + + + 5: Content: Absolute URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test5 + <a href="http://example.org/tests/base/result.html">http://example.org/tests/base/result.html</a> + 2006-01-17T12:35:12+01:00 + + + + 6: Content: Host-relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test6 + <a href="/tests/base/result.html">http://example.org/tests/base/result.html</a> + 2006-01-17T12:35:11+01:00 + + + + 7: Content: Relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test7 + <a href="base/result.html">http://example.org/tests/base/result.html</a> + 2006-01-17T12:35:10+01:00 + + + + 8: Content: Relative URL with parent directory component + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test8 + <a href="../tests/base/result.html">http://example.org/tests/base/result.html</a> + 2006-01-17T12:35:9+01:00 + + + + 9: Content, <code>&lt;entry></code> has base: Absolute URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test9 + <a href="http://example.org/tests/entrybase/result.html">http://example.org/tests/entrybase/result.html</a> + 2006-01-17T12:35:8+01:00 + + + + 10: Content, <code>&lt;entry></code> has base: Host-relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test10 + <a href="/tests/entrybase/result.html">http://example.org/tests/entrybase/result.html</a> + 2006-01-17T12:35:7+01:00 + + + + 11: Content, <code>&lt;entry></code> has base: Relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test11 + <a href="result.html">http://example.org/tests/entrybase/result.html</a> + 2006-01-17T12:35:6+01:00 + + + + 12: Content, <code>&lt;entry></code> has base: Relative URL with parent directory component + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test12 + <a href="../entrybase/result.html">http://example.org/tests/entrybase/result.html</a> + 2006-01-17T12:35:5+01:00 + + + + 13: Content, <code>&lt;content></code> has base: Absolute URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test13 + <a href="http://example.org/tests/contentbase/result.html">http://example.org/tests/contentbase/result.html</a> + 2006-01-17T12:35:4+01:00 + + + + 14: Content, <code>&lt;content></code> has base: Host-relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test14 + <a href="/tests/contentbase/result.html">http://example.org/tests/contentbase/result.html</a> + 2006-01-17T12:35:3+01:00 + + + + 15: Content, <code>&lt;content></code> has base: Relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test15 + <a href="result.html">http://example.org/tests/contentbase/result.html</a> + 2006-01-17T12:35:2+01:00 + + + + 16: Content, <code>&lt;content></code> has base: Relative URL with parent directory component + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test16 + <a href="../contentbase/result.html">http://example.org/tests/contentbase/result.html</a> + 2006-01-17T12:35:1+01:00 + + + diff --git a/src/test/data/atom_1.0_bray.xml b/src/test/data/atom_1.0_bray.xml new file mode 100644 index 0000000..de72ea3 --- /dev/null +++ b/src/test/data/atom_1.0_bray.xml @@ -0,0 +1,35 @@ + + + + Tim Bray style feed + URIs must be determined from xml:base + + + + + http://www.example.com/blog + 2006-11-04T09:11:03-08:00 + John Doe + + + + Entry1 + http://www.example.com/blog/2006-11-05/entry1 + 2006-11-05T12:00:00-08:00 + 2006-11-06T09:09:13-08:00 +
Summary1
+
Content1
+
+ + + + Entry2 + http://www.example.com/blog/2006-11-02/entry2 + 2006-11-01T12:00:00-08:00 + 2006-11-02T09:09:12-08:00 +
Summary2
+
Content2
+
+ +
diff --git a/src/test/data/atom_1.0_prefix.xml b/src/test/data/atom_1.0_prefix.xml new file mode 100644 index 0000000..a4ed106 --- /dev/null +++ b/src/test/data/atom_1.0_prefix.xml @@ -0,0 +1,7 @@ + + + 1 + + + + diff --git a/src/test/data/atom_1.0_ruby.xml b/src/test/data/atom_1.0_ruby.xml new file mode 100644 index 0000000..1722fa3 --- /dev/null +++ b/src/test/data/atom_1.0_ruby.xml @@ -0,0 +1,37 @@ + + + + Sam Ruby style + Base URI must be determined from self link + + + + + http://www.example.com/blog + + John Doe + john.doe@example.com + . + + 2006-11-04T22:09:53-05:00 + + + + tag:example.com,2004:2429 + Bloggy-blog +
Summary1
+
Content1
+ 2006-11-04T18:23:33-05:00 +
+ + + + tag:example.com,2004:2430 + Froggy-frog +
Summary1
+
Content1
+ 2006-11-04T18:23:30-05:00 +
+ +
+ diff --git a/src/test/data/rss_0.9.xml b/src/test/data/rss_0.9.xml new file mode 100644 index 0000000..4bf3185 --- /dev/null +++ b/src/test/data/rss_0.9.xml @@ -0,0 +1,28 @@ + + + + rss_0.9.channel.title + rss_0.9.channel.link + rss_0.9.channel.description + + + rss_0.9.image.title + rss_0.9.image.url + rss_0.9.image.link + + + rss_0.9.textinput.title + rss_0.9.textinput.description + rss_0.9.textinput.name + rss_0.9.textinput.link + + + rss_0.9.item[0].title + rss_0.9.item[0].link + + + rss_0.9.item[1].title + rss_0.9.item[1].link + + \ No newline at end of file diff --git a/src/test/data/rss_0.91N.xml b/src/test/data/rss_0.91N.xml new file mode 100644 index 0000000..8770175 --- /dev/null +++ b/src/test/data/rss_0.91N.xml @@ -0,0 +1,77 @@ + + + + + + rss_0.91N.channel.title + rss_0.91N.channel.link + rss_0.91N.channel.description + rss_0.91N.channel.language + rss_0.91N.channel.rating + rss_0.91N.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.91N.channel.docs + rss_0.91N.channel.managingEditor + rss_0.91N.channel.webMaster + + rss_0.91N.channel.image.title + rss_0.91N.channel.image.url + rss_0.91N.channel.image.link + 100 + 200 + rss_0.91N.channel.image.description + + + rss_0.91N.channel.item[0].title + rss_0.91N.channel.item[0].description + rss_0.91N.channel.item[0].link + + + rss_0.91N.channel.item[1].title + rss_0.91N.channel.item[1].description + rss_0.91N.channel.item[1].link + + + rss_0.91N.channel.textinput.title + rss_0.91N.channel.textinput.description + rss_0.91N.channel.textinput.name + rss_0.91N.channel.textinput.link + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + diff --git a/src/test/data/rss_0.91U.xml b/src/test/data/rss_0.91U.xml new file mode 100644 index 0000000..713b7d1 --- /dev/null +++ b/src/test/data/rss_0.91U.xml @@ -0,0 +1,84 @@ + + + + + rss_0.91U.channel.title + rss_0.91U.channel.link + rss_0.91U.channel.description + rss_0.91U.channel.language + rss_0.91U.channel.rating + rss_0.91U.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.91U.channel.docs + rss_0.91U.channel.managingEditor + rss_0.91U.channel.webMaster + + rss_0.91U.channel.image.title + rss_0.91U.channel.image.url + rss_0.91U.channel.image.link + 100 + 200 + rss_0.91U.channel.image.description + + + rss_0.91U.channel.item[0].title + rss_0.91U.channel.item[0].description + rss_0.91U.channel.item[0].link + + + rss_0.91U.channel.item[1].title + rss_0.91U.channel.item[1].description + rss_0.91U.channel.item[1].link + + + rss_0.91U.channel.textInput.title + rss_0.91U.channel.textInput.description + rss_0.91U.channel.textInput.name + rss_0.91U.channel.textInput.link + + + 1 + + 2 + 3 + + + 4 + + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + 24 + + + Monday + Tuesday + Wednesday + + + Thursday + + Friday + Saturday + Sunday + + + + + diff --git a/src/test/data/rss_0.92.xml b/src/test/data/rss_0.92.xml new file mode 100644 index 0000000..1e33929 --- /dev/null +++ b/src/test/data/rss_0.92.xml @@ -0,0 +1,90 @@ + + + + rss_0.92.channel.title + rss_0.92.channel.link + rss_0.92.channel.description + rss_0.92.channel.language + rss_0.92.channel.rating + rss_0.92.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.92.channel.docs + rss_0.92.channel.managingEditor + rss_0.92.channel.webMaster + + + rss_0.92.channel.image.title + rss_0.92.channel.image.url + rss_0.92.channel.image.link + 100 + 200 + rss_0.92.channel.image.description + + + rss_0.92.channel.item[0].title + rss_0.92.channel.item[0].description + rss_0.92.channel.item[0].link + rss_0.92.channel.item[0].source + + rss_0.92.channel.item[0].category[0] + rss_0.92.channel.item[0].category[1] + + + rss_0.92.channel.item[1].title + rss_0.92.channel.item[1].description + rss_0.92.channel.item[1].link + rss_0.92.channel.item[1].source + + + rss_0.92.channel.item[1].category[0] + rss_0.92.channel.item[1].category[1] + + + + rss_0.92.channel.textInput.title + rss_0.92.channel.textInput.description + rss_0.92.channel.textInput.name + rss_0.92.channel.textInput.link + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + 24 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + diff --git a/src/test/data/rss_0.92_alt.xml b/src/test/data/rss_0.92_alt.xml new file mode 100644 index 0000000..ec0062c --- /dev/null +++ b/src/test/data/rss_0.92_alt.xml @@ -0,0 +1,92 @@ + + + + + rss_0.92.channel.title + rss_0.92.channel.link + rss_0.92.channel.description + rss_0.92.channel.language + rss_0.92.channel.rating + rss_0.92.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.92.channel.docs + rss_0.92.channel.managingEditor + rss_0.92.channel.webMaster + + + rss_0.92.channel.image.title + rss_0.92.channel.image.url + rss_0.92.channel.image.link + 100 + 200 + rss_0.92.channel.image.description + + + rss_0.92.channel.item[0].title + rss_0.92.channel.item[0].description + rss_0.92.channel.item[0].link + rss_0.92.channel.item[0].source + + + rss_0.92.channel.item[0].category[0] + rss_0.92.channel.item[0].category[1] + + + rss_0.92.channel.item[1].title + rss_0.92.channel.item[1].description + rss_0.92.channel.item[1].link + rss_0.92.channel.item[1].source + + + rss_0.92.channel.item[1].category[0] + rss_0.92.channel.item[1].category[1] + + + + rss_0.92.channel.textInput.title + rss_0.92.channel.textInput.description + rss_0.92.channel.textInput.name + rss_0.92.channel.textInput.link + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + 24 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + diff --git a/src/test/data/rss_0.93.xml b/src/test/data/rss_0.93.xml new file mode 100644 index 0000000..ab8f92c --- /dev/null +++ b/src/test/data/rss_0.93.xml @@ -0,0 +1,96 @@ + + + + rss_0.93.channel.title + rss_0.93.channel.link + rss_0.93.channel.description + rss_0.93.channel.language + rss_0.93.channel.rating + rss_0.93.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.93.channel.docs + rss_0.93.channel.managingEditor + rss_0.93.channel.webMaster + + + rss_0.93.channel.image.title + rss_0.93.channel.image.url + rss_0.93.channel.image.link + 100 + 200 + rss_0.93.channel.image.description + + + rss_0.93.channel.item[0].title + rss_0.93.channel.item[0].description + rss_0.93.channel.item[0].link + rss_0.93.channel.item[0].source + + + rss_0.93.channel.item[0].category[0] + rss_0.93.channel.item[0].category[1] + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + + + rss_0.93.channel.item[1].title + rss_0.93.channel.item[1].description + rss_0.93.channel.item[1].link + rss_0.93.channel.item[1].source + + + rss_0.93.channel.item[1].category[0] + rss_0.93.channel.item[1].category[1] + Tue, 02 Jan 2001 00:00:00 GMT + Tue, 02 Jan 2001 01:00:00 GMT + + + rss_0.93.channel.textInput.title + rss_0.93.channel.textInput.description + rss_0.93.channel.textInput.name + rss_0.93.channel.textInput.link + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + 24 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + \ No newline at end of file diff --git a/src/test/data/rss_0.94.xml b/src/test/data/rss_0.94.xml new file mode 100644 index 0000000..35f968f --- /dev/null +++ b/src/test/data/rss_0.94.xml @@ -0,0 +1,108 @@ + + + + rss_0.94.channel.title + rss_0.94.channel.link + rss_0.94.channel.description + rss_0.94.channel.language + rss_0.94.channel.rating + rss_0.94.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.94.channel.docs + rss_0.94.channel.managingEditor + rss_0.94.channel.webMaster + + rss_0.94.channel.category[0] + rss_0.94.channel.category[1] + rss_0.94.channel.generator + 100 + + + rss_0.94.channel.image.title + rss_0.94.channel.image.url + rss_0.94.channel.image.link + 100 + 200 + rss_0.94.channel.image.description + + + rss_0.94.channel.item[0].title + rss_0.94.channel.item[0].description + rss_0.94.channel.item[0].link + rss_0.94.channel.item[0].source + + + rss_0.94.channel.item[0].category[0] + rss_0.94.channel.item[0].category[1] + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.94.channel.item[0].author + rss_0.94.channel.item[0].comments + rss_0.94.channel.item[0].guid + + + rss_0.94.channel.item[1].title + rss_0.94.channel.item[1].description + rss_0.94.channel.item[1].link + rss_0.94.channel.item[1].source + + + rss_0.94.channel.item[1].category[0] + rss_0.94.channel.item[1].category[1] + Mon, 02 Jan 2001 00:00:00 GMT + Mon, 02 Jan 2001 01:00:00 GMT + rss_0.94.channel.item[1].author + rss_0.94.channel.item[1].comments + rss_0.94.channel.item[1].guid + + + + rss_0.94.channel.textInput.title + rss_0.94.channel.textInput.description + rss_0.94.channel.textInput.name + rss_0.94.channel.textInput.link + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + 24 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + \ No newline at end of file diff --git a/src/test/data/rss_1.0.xml b/src/test/data/rss_1.0.xml new file mode 100644 index 0000000..6498cb5 --- /dev/null +++ b/src/test/data/rss_1.0.xml @@ -0,0 +1,51 @@ + + + + + + test + rss_1.0.channel.title + rss_1.0.channel.link + rss_1.0.channel.description + + + + + + + + + + + + + rss_1.0.image.title + rss_1.0.image.url + rss_1.0.image.link + + + + rss_1.0.textinput.title + rss_1.0.textinput.description + rss_1.0.textinput.name + rss_1.0.textinput.link + + + rss_1.0.item[0].title + rss_1.0.item[0].link + rss_1.0.item[0].description + test + rss_1.0.item[0].content + + + rss_1.0.item[1].title + rss_1.0.item[1].link + rss_1.0.item[1].description + test + rss_1.0.item[1].content + + + diff --git a/src/test/data/rss_1.0_DC_Sy.xml b/src/test/data/rss_1.0_DC_Sy.xml new file mode 100644 index 0000000..dcf968b --- /dev/null +++ b/src/test/data/rss_1.0_DC_Sy.xml @@ -0,0 +1,118 @@ + + + + + + rss_1.0.channel.title + rss_1.0.channel.link + rss_1.0.channel.description + + + + + + + + + + + rss_1.0.channel.dc:title + rss_1.0.channel.dc:creator + + + + rss_1.0.channel.dc:subject[0] + + + + + + rss_1.0.channel.dc:subject[1] + + + rss_1.0.channel.dc:description + rss_1.0.channel.dc:publisher + rss_1.0.channel.dc:contributor[0] + rss_1.0.channel.dc:contributor[1] + 2001-01-01T00:00+00:00 + rss_1.0.channel.dc:type + rss_1.0.channel.dc:format + rss_1.0.channel.dc:identifier + rss_1.0.channel.dc:source + rss_1.0.channel.dc:language + rss_1.0.channel.dc:relation + rss_1.0.channel.dc:coverage + rss_1.0.channel.dc:rights + + hourly + 100 + 2001-01-01T01:00+00:00 + + + + + rss_1.0.image.title + rss_1.0.image.url + rss_1.0.image.link + + + + rss_1.0.textinput.title + rss_1.0.textinput.description + rss_1.0.textinput.name + rss_1.0.textinput.link + + + rss_1.0.item[0].title + rss_1.0.item[0].link + rss_1.0.item[0].description + + rss_1.0.item[0].dc:title + rss_1.0.item[0].dc:creator + rss_1.0.item[0].dc:subject[0] + rss_1.0.item[0].dc:subject[1] + rss_1.0.item[0].dc:description + rss_1.0.item[0].dc:publisher + rss_1.0.item[0].dc:contributor[0] + rss_1.0.item[0].dc:contributor[1] + 2001-01-01T00:00+00:00 + rss_1.0.item[0].dc:type + rss_1.0.item[0].dc:format + rss_1.0.item[0].dc:identifier + rss_1.0.item[0].dc:source + rss_1.0.item[0].dc:language + rss_1.0.item[0].dc:relation + rss_1.0.item[0].dc:coverage + rss_1.0.item[0].dc:rights + rss_1.0.item[0].content + + + rss_1.0.item[1].title + rss_1.0.item[1].link + rss_1.0.item[1].description + rss_1.0.item[1].dc:title + rss_1.0.item[1].dc:creator + rss_1.0.item[1].dc:subject[0] + rss_1.0.item[1].dc:subject[1] + rss_1.0.item[1].dc:description + rss_1.0.item[1].dc:publisher + rss_1.0.item[1].dc:contributor[0] + rss_1.0.item[1].dc:contributor[1] + 2001-01-01T00:00+00:00 + rss_1.0.item[1].dc:type + rss_1.0.item[1].dc:format + rss_1.0.item[1].dc:identifier + rss_1.0.item[1].dc:source + rss_1.0.item[1].dc:language + rss_1.0.item[1].dc:relation + rss_1.0.item[1].dc:coverage + rss_1.0.item[1].dc:rights + rss_1.0.item[1].content + + + diff --git a/src/test/data/rss_1.0_DC_multi.xml b/src/test/data/rss_1.0_DC_multi.xml new file mode 100644 index 0000000..965410c --- /dev/null +++ b/src/test/data/rss_1.0_DC_multi.xml @@ -0,0 +1,157 @@ + + + + + + rss_1.0.channel.title + rss_1.0.channel.link + rss_1.0.channel.description + + + + + + + + + + + rss_1.0.channel.dc:title[0] + rss_1.0.channel.dc:title[1] + rss_1.0.channel.dc:creator[0] + rss_1.0.channel.dc:creator[1] + + + + rss_1.0.channel.dc:subject[0] + + + + + + rss_1.0.channel.dc:subject[1] + + + rss_1.0.channel.dc:description[0] + rss_1.0.channel.dc:description[1] + rss_1.0.channel.dc:publisher[0] + rss_1.0.channel.dc:publisher[1] + rss_1.0.channel.dc:contributor[0] + rss_1.0.channel.dc:contributor[1] + 2001-01-01T00:00+00:00 + 2001-01-01T00:00+00:00 + rss_1.0.channel.dc:type[0] + rss_1.0.channel.dc:type[1] + rss_1.0.channel.dc:format[0] + rss_1.0.channel.dc:format[1] + rss_1.0.channel.dc:identifier[0] + rss_1.0.channel.dc:identifier[1] + rss_1.0.channel.dc:source[0] + rss_1.0.channel.dc:source[1] + rss_1.0.channel.dc:language[0] + rss_1.0.channel.dc:language[1] + rss_1.0.channel.dc:relation[0] + rss_1.0.channel.dc:relation[1] + rss_1.0.channel.dc:coverage[0] + rss_1.0.channel.dc:coverage[1] + rss_1.0.channel.dc:rights[0] + rss_1.0.channel.dc:rights[1] + + hourly + 100 + 2001-01-01T01:00+00:00 + + + + + rss_1.0.image.title + rss_1.0.image.url + rss_1.0.image.link + + + + rss_1.0.textinput.title + rss_1.0.textinput.description + rss_1.0.textinput.name + rss_1.0.textinput.link + + + rss_1.0.item[0].title + rss_1.0.item[0].link + rss_1.0.item[0].description + + rss_1.0.item[0].dc:title[0] + rss_1.0.item[0].dc:title[1] + rss_1.0.item[0].dc:creator[0] + rss_1.0.item[0].dc:creator[1] + rss_1.0.item[0].dc:subject[0] + rss_1.0.item[0].dc:subject[1] + rss_1.0.item[0].dc:description[0] + rss_1.0.item[0].dc:description[1] + rss_1.0.item[0].dc:publisher[0] + rss_1.0.item[0].dc:publisher[1] + rss_1.0.item[0].dc:contributor[0] + rss_1.0.item[0].dc:contributor[1] + 2001-01-01T00:00+00:00 + 2001-01-01T00:00+00:00 + rss_1.0.item[0].dc:type[0] + rss_1.0.item[0].dc:type[1] + rss_1.0.item[0].dc:format[0] + rss_1.0.item[0].dc:format[1] + rss_1.0.item[0].dc:identifier[0] + rss_1.0.item[0].dc:identifier[1] + rss_1.0.item[0].dc:source[0] + rss_1.0.item[0].dc:source[1] + rss_1.0.item[0].dc:language[0] + rss_1.0.item[0].dc:language[1] + rss_1.0.item[0].dc:relation[0] + rss_1.0.item[0].dc:relation[1] + rss_1.0.item[0].dc:coverage[0] + rss_1.0.item[0].dc:coverage[1] + rss_1.0.item[0].dc:rights[0] + rss_1.0.item[0].dc:rights[1] + rss_1.0.item[0].content + + + rss_1.0.item[1].title + rss_1.0.item[1].link + rss_1.0.item[1].description + rss_1.0.item[1].dc:title[0] + rss_1.0.item[1].dc:title[1] + rss_1.0.item[1].dc:creator[0] + rss_1.0.item[1].dc:creator[1] + rss_1.0.item[1].dc:subject[0] + rss_1.0.item[1].dc:subject[1] + rss_1.0.item[1].dc:description[0] + rss_1.0.item[1].dc:description[1] + rss_1.0.item[1].dc:publisher[0] + rss_1.0.item[1].dc:publisher[1] + rss_1.0.item[1].dc:contributor[0] + rss_1.0.item[1].dc:contributor[1] + 2001-01-01T00:00+00:00 + 2001-01-01T00:00+00:00 + rss_1.0.item[1].dc:type[0] + rss_1.0.item[1].dc:type[1] + rss_1.0.item[1].dc:format[0] + rss_1.0.item[1].dc:format[1] + rss_1.0.item[1].dc:identifier[0] + rss_1.0.item[1].dc:identifier[1] + rss_1.0.item[1].dc:source[0] + rss_1.0.item[1].dc:source[1] + rss_1.0.item[1].dc:language[0] + rss_1.0.item[1].dc:language[1] + rss_1.0.item[1].dc:relation[0] + rss_1.0.item[1].dc:relation[1] + rss_1.0.item[1].dc:coverage[0] + rss_1.0.item[1].dc:coverage[1] + rss_1.0.item[1].dc:rights[0] + rss_1.0.item[1].dc:rights[1] + rss_1.0.item[1].content + + + diff --git a/src/test/data/rss_2.0.xml b/src/test/data/rss_2.0.xml new file mode 100644 index 0000000..e033320 --- /dev/null +++ b/src/test/data/rss_2.0.xml @@ -0,0 +1,117 @@ + + + + test + rss_2.0.channel.title + rss_2.0.channel.link + rss_2.0.channel.description + rss_2.0.channel.language + rss_2.0.channel.rating + rss_2.0.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + + Mon, 01 Jan 2001 01:00:00 GMT + rss_2.0.channel.docs + rss_2.0.channel.managingEditor + rss_2.0.channel.webMaster + rss_2.0.channel.category[0] + rss_2.0.channel.category[1] + rss_2.0.channel.generator + 100 + + + rss_2.0.channel.image.title + rss_2.0.channel.image.url + rss_2.0.channel.image.link + 100 + 200 + rss_2.0.channel.image.description + + + + rss_2.0.channel.item[0].title + rss_2.0.channel.item[0].description + rss_2.0.channel.item[0].link + rss_2.0.channel.item[0].source + + + rss_2.0.channel.item[0].category[0] + rss_2.0.channel.item[0].category[1] + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_2.0.channel.item[0].author + rss_2.0.channel.item[0].comments + rss_2.0.channel.item[0].guid + test + rss_2.0.channel.item[0].content + + + rss_2.0.channel.item[1].title + rss_2.0.channel.item[1].description + rss_2.0.channel.item[1].link + rss_2.0.channel.item[1].source + + + rss_2.0.channel.item[1].category[0] + rss_2.0.channel.item[1].category[1] + Mon, 02 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_2.0.channel.item[1].author + rss_2.0.channel.item[1].comments + rss_2.0.channel.item[1].guid + test + rss_2.0.channel.item[1].content + + + + rss_2.0.channel.textInput.title + rss_2.0.channel.textInput.description + rss_2.0.channel.textInput.name + rss_2.0.channel.textInput.link + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + + diff --git a/src/test/java/com/sun/syndication/unittest/FeedOpsTest.java b/src/test/java/com/sun/syndication/unittest/FeedOpsTest.java new file mode 100644 index 0000000..81cfd29 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/FeedOpsTest.java @@ -0,0 +1,112 @@ +package com.sun.syndication.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.ObjectInputStream; + +/** + * + *

+ * @author Alejandro Abdelnur + * + */ +public abstract class FeedOpsTest extends FeedTest { + + protected FeedOpsTest(String feedType) { + super(feedType+".xml"); + System.out.println("Testing "+feedType+".xml"); + } + + //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); + + assertTrue(sFeed1.equals(sFeed2)); + } + + //1.7a + public void testSyndFeedEquals() throws Exception { + SyndFeed feed1 = getCachedSyndFeed(); + SyndFeed feed2 = getSyndFeed(false); + assertTrue(feed1.equals(feed2)); + } + + //1.7b + public void testSyndFeedNotEqual() throws Exception { + SyndFeed feed1 = getCachedSyndFeed(); + SyndFeed feed2 = getSyndFeed(false); + 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)); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/FeedTest.java b/src/test/java/com/sun/syndication/unittest/FeedTest.java new file mode 100644 index 0000000..2ce8b1b --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/FeedTest.java @@ -0,0 +1,88 @@ +package com.sun.syndication.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; + + private boolean preservingWireFeed = false; + + 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(boolean preserveWireFeed) throws Exception { + SyndFeedInput in = new SyndFeedInput(); + in.setPreserveWireFeed(preserveWireFeed); + 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(boolean preserveWireFeed) throws Exception { + + if (_syndFeed==null || preservingWireFeed != preserveWireFeed) { + _syndFeed = getSyndFeed(preserveWireFeed); + preservingWireFeed = preserveWireFeed; + } + return _syndFeed; + + } + + protected SyndFeed getCachedSyndFeed() throws Exception { + return getCachedSyndFeed(false); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/SyndFeedTest.java b/src/test/java/com/sun/syndication/unittest/SyndFeedTest.java new file mode 100644 index 0000000..b7694fe --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/SyndFeedTest.java @@ -0,0 +1,281 @@ +/* + * 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 com.sun.syndication.unittest; + +import java.util.Date; +import java.util.List; + +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndImage; +import com.sun.syndication.io.impl.DateParser; + + +/** + * @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); + } + + protected void assertEqualsStr(String expected, String actual) { + assertEquals(_prefix + "." + expected, actual); + } + + public void testPreserveWireFeed() throws Exception { + assertNotNull(getCachedSyndFeed(true).originalWireFeed()); + } + + public void testType() throws Exception { + assertEquals(getCachedSyndFeed().getFeedType(),getPrefix()); + } + + + 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); + assertEquals("channel.category[0]", cat.getName()); + assertEquals("channel.category[0]^domain", cat.getTaxonomyUri()); + cat = (SyndCategory)catlist.get(1); + assertEquals("channel.category[1]", cat.getName()); + assertEquals("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 { + // this only works for RSS 0.93+ + //assertEquals(DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"), getEntryPublishedDate(getCachedSyndFeed().getEntries().get(0))); + //assertEquals(DateParser.parseRFC822("Tue, 02 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); + assertEquals("channel.item[0].category[0]", cat.getName()); + assertEquals("channel.item[0].category[0]^domain", cat.getTaxonomyUri()); + cat = (SyndCategory)catlist.get(1); + assertEquals("channel.item[0].category[1]", cat.getName()); + assertEquals("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 +// item[0].source +// +// + item0.category0 + item0.category1 + Thu, 08 Jul 1999 08:00:00 GMT + Thu, 08 Jul 1999 09:00:00 GMT + item0.author + http://localhost:8080/item0/comments + http://localhost:8080/item0/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? +/* + * + Search + Search this site: + q + http://example.org/mt/mt-search.cgi + + + image height and width + * + //Copyright 2004, Mark Pilgrim + public void test() { + assertEqualsStr(getCachedSyndFeed()., ""); + } + + //Sample Toolkit + public void test() { + assertEqualsStr(feed, ""); + } + + // editor@example.org + public void test() { + assertEqualsStr(feed, ""); + } + + // webmaster@example.org + public void test() { + assertEqualsStr(feed, ""); + } + + http://blogs.law.harvard.edu/tech/rss + + 60 + (PICS-1.1 Òhttp://www.classify.org/safesurf/Ó l r (SS~~000 1)) + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9.5 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + +**/ + + + /* + * @see TestCase#tearDown() + */ + protected void tearDown() throws Exception { + super.tearDown(); + } + + + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestAtomContent.java b/src/test/java/com/sun/syndication/unittest/TestAtomContent.java new file mode 100644 index 0000000..7824f4e --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestAtomContent.java @@ -0,0 +1,46 @@ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.atom.Feed; +import com.sun.syndication.feed.atom.Content; +import com.sun.syndication.io.WireFeedOutput; +import com.sun.syndication.io.WireFeedInput; +import junit.framework.TestCase; + +import java.io.StringWriter; +import java.io.StringReader; + +public class TestAtomContent extends TestCase { + + private Feed createFeed() { + Feed feed = new Feed(); + Content content = new Content(); + content.setType("application/xml"); + content.setValue("Hello Hello"); + feed.setTitleEx(content); + feed.setFeedType("atom_1.0"); + return feed; + } + + public void testReadWrite() throws Exception { + Feed feed = createFeed(); + StringWriter sw = new StringWriter(); + WireFeedOutput output = new WireFeedOutput(); + output.output(feed, sw); + sw.close(); + StringReader reader = new StringReader(sw.toString()); + WireFeedInput input = new WireFeedInput(); + feed = (Feed) input.build(reader); + reader.close(); + assertEquals("Hello Hello", feed.getTitleEx().getValue().trim()); + } + + public void testXML() throws Exception { + Feed feed = createFeed(); + StringWriter sw = new StringWriter(); + WireFeedOutput output = new WireFeedOutput(); + output.output(feed, sw); + sw.close(); + assertTrue(sw.toString().contains("Hello Hello")); + } + +} \ No newline at end of file diff --git a/src/test/java/com/sun/syndication/unittest/TestBase64.java b/src/test/java/com/sun/syndication/unittest/TestBase64.java new file mode 100644 index 0000000..c373c2c --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestBase64.java @@ -0,0 +1,38 @@ +package com.sun.syndication.unittest; + +import junit.framework.TestCase; +import com.sun.syndication.io.impl.Base64; + +public class TestBase64 extends TestCase { + + private void _testEncodeDecode(String s) { + String encoded = Base64.encode(s); + String decoded = Base64.decode(encoded); + assertEquals(s, decoded); + } + + public void testEncodeDecode() { + _testEncodeDecode(""); + _testEncodeDecode("A"); + _testEncodeDecode("AB"); + _testEncodeDecode("ABC"); + _testEncodeDecode("ABCD"); + _testEncodeDecode("ABCDE"); + _testEncodeDecode("&"); + _testEncodeDecode("a&"); + _testEncodeDecode("ab&"); + _testEncodeDecode("abc&"); + _testEncodeDecode("abcd&"); + + } + + public void testDecodeWithEnters() { + String s = "Hello World!"; + String encoded = Base64.encode(s); + encoded = encoded.substring(0, 3) + "\n\r\n" + encoded.substring(3); + System.out.println(encoded); + String decoded = Base64.decode(encoded); + assertEquals(s, decoded); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestDateParser.java b/src/test/java/com/sun/syndication/unittest/TestDateParser.java new file mode 100644 index 0000000..79ec6d5 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestDateParser.java @@ -0,0 +1,128 @@ +/* + * Copyright 2004-2005 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 com.sun.syndication.unittest; + +import com.sun.syndication.io.impl.DateParser; +import junit.framework.TestCase; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.TimeZone; +import java.util.Date; + +/** + * + * Start of tests for DateParser + * + * @author Nick Lothian + * + */ +public class TestDateParser extends TestCase { + public void testParse() { + Calendar cal = new GregorianCalendar(); + cal.setTimeZone(TimeZone.getTimeZone("GMT")); + + // four-digit year + String sDate = "Tue, 19 Jul 2005 23:00:51 GMT"; + cal.setTime(DateParser.parseRFC822(sDate)); + + assertEquals(2005, cal.get(Calendar.YEAR)); + assertEquals(6, cal.get(Calendar.MONTH)); // month is zero-indexed + assertEquals(19, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(3, cal.get(Calendar.DAY_OF_WEEK)); + assertEquals(23, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(0, cal.get(Calendar.MINUTE)); + assertEquals(51, cal.get(Calendar.SECOND)); + + // two-digit year + sDate = "Tue, 19 Jul 05 23:00:51 GMT"; + cal.setTime(DateParser.parseRFC822(sDate)); + + assertEquals(2005, cal.get(Calendar.YEAR)); + assertEquals(6, cal.get(Calendar.MONTH)); // month is zero-indexed + assertEquals(19, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(3, cal.get(Calendar.DAY_OF_WEEK)); + assertEquals(23, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(0, cal.get(Calendar.MINUTE)); + assertEquals(51, cal.get(Calendar.SECOND)); + + // four-digit year + sDate = "Tue, 19 Jul 2005 23:00:51 UT"; + cal.setTime(DateParser.parseRFC822(sDate)); + + assertEquals(2005, cal.get(Calendar.YEAR)); + assertEquals(6, cal.get(Calendar.MONTH)); // month is zero-indexed + assertEquals(19, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(3, cal.get(Calendar.DAY_OF_WEEK)); + assertEquals(23, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(0, cal.get(Calendar.MINUTE)); + assertEquals(51, cal.get(Calendar.SECOND)); + + // two-digit year + sDate = "Tue, 19 Jul 05 23:00:51 UT"; + cal.setTime(DateParser.parseRFC822(sDate)); + + assertEquals(2005, cal.get(Calendar.YEAR)); + assertEquals(6, cal.get(Calendar.MONTH)); // month is zero-indexed + assertEquals(19, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(3, cal.get(Calendar.DAY_OF_WEEK)); + assertEquals(23, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(0, cal.get(Calendar.MINUTE)); + assertEquals(51, cal.get(Calendar.SECOND)); + + //RFC822 + sDate = "Tue, 19 Jul 2005 23:00:51 GMT"; + assertNotNull(DateParser.parseDate(sDate)); + + //RFC822 + sDate = "Tue, 19 Jul 05 23:00:51 GMT"; + assertNotNull(DateParser.parseDate(sDate)); + + Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + c.set(2000,Calendar.JANUARY,01,0,0,0); + Date expectedDate = c.getTime(); + + //W3C + sDate = "2000-01-01T00:00:00Z"; + assertEquals(expectedDate.getTime()/1000,DateParser.parseDate(sDate).getTime()/1000); + + //W3C + sDate = "2000-01-01T00:00Z"; + assertEquals(expectedDate.getTime()/1000,DateParser.parseDate(sDate).getTime()/1000); + + //W3C + sDate = "2000-01-01"; + assertEquals(expectedDate.getTime()/1000,DateParser.parseDate(sDate).getTime()/1000); + + //W3C + sDate = "2000-01"; + assertEquals(expectedDate.getTime()/1000,DateParser.parseDate(sDate).getTime()/1000); + + //W3C + sDate = "2000"; + assertEquals(expectedDate.getTime()/1000,DateParser.parseDate(sDate).getTime()/1000); + + //EXTRA + sDate = "18:10 2000/10/10"; + assertNotNull(DateParser.parseDate(sDate)); + + //INVALID + sDate = "X20:10 2000-10-10"; + assertNull(DateParser.parseDate(sDate)); + + } +} diff --git a/src/test/java/com/sun/syndication/unittest/TestEqualsBean.java b/src/test/java/com/sun/syndication/unittest/TestEqualsBean.java new file mode 100644 index 0000000..092d1af --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestEqualsBean.java @@ -0,0 +1,45 @@ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.atom.Feed; +import junit.framework.TestCase; + +public class TestEqualsBean extends TestCase { + + public void testEquals() { + Feed feed1 = new Feed(); + Feed feed2 = new Feed(); + Feed feed3 = new Feed(); + Feed feed4 = new Feed(); + feed4.setId("a"); + + //reflexive + assertTrue(feed1.equals(feed1)); + + //symmetric + assertTrue(feed1.equals(feed2)); + assertTrue(feed2.equals(feed1)); + + assertFalse(feed1.equals(feed4)); + assertFalse(feed4.equals(feed1)); + + //transitive + assertTrue(feed1.equals(feed2)); + assertTrue(feed2.equals(feed3)); + assertTrue(feed1.equals(feed3)); + + assertTrue(feed1.equals(feed2)); + assertFalse(feed2.equals(feed4)); + assertFalse(feed1.equals(feed4)); + + //consistent + assertTrue(feed1.equals(feed2)); + assertTrue(feed1.equals(feed2)); + + assertFalse(feed1.equals(feed4)); + assertFalse(feed1.equals(feed4)); + + //not-null to null is FALSE + assertFalse(feed1.equals(null)); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestOpsAtom03.java b/src/test/java/com/sun/syndication/unittest/TestOpsAtom03.java new file mode 100644 index 0000000..a3b62c0 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestOpsAtom03.java @@ -0,0 +1,15 @@ +package com.sun.syndication.unittest; + +/** + * + *

+ * @author Alejandro Abdelnur + * + */ +public class TestOpsAtom03 extends FeedOpsTest { + + public TestOpsAtom03() { + super("atom_0.3"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestOpsAtom10.java b/src/test/java/com/sun/syndication/unittest/TestOpsAtom10.java new file mode 100644 index 0000000..76bed30 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestOpsAtom10.java @@ -0,0 +1,15 @@ +package com.sun.syndication.unittest; + +/** + * + *

+ * @author Dave Johnson + * + */ +public class TestOpsAtom10 extends FeedOpsTest { + + public TestOpsAtom10() { + super("atom_1.0"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestOpsRSS090.java b/src/test/java/com/sun/syndication/unittest/TestOpsRSS090.java new file mode 100644 index 0000000..3bc08a5 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestOpsRSS090.java @@ -0,0 +1,15 @@ +package com.sun.syndication.unittest; + +/** + * + *

+ * @author Alejandro Abdelnur + * + */ +public class TestOpsRSS090 extends FeedOpsTest { + + public TestOpsRSS090() { + super("rss_0.9"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestOpsRSS091N.java b/src/test/java/com/sun/syndication/unittest/TestOpsRSS091N.java new file mode 100644 index 0000000..a90afd2 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestOpsRSS091N.java @@ -0,0 +1,20 @@ +package com.sun.syndication.unittest; + +/** + * + *

+ * @author Alejandro Abdelnur + * + */ +public class TestOpsRSS091N extends FeedOpsTest { + + public static void main(String[] args) throws Exception { + FeedOpsTest test = new TestOpsRSS091N(); + test.testWireFeedSyndFeedConversion(); + } + + public TestOpsRSS091N() { + super("rss_0.91N"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestOpsRSS091U.java b/src/test/java/com/sun/syndication/unittest/TestOpsRSS091U.java new file mode 100644 index 0000000..e3f8192 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestOpsRSS091U.java @@ -0,0 +1,15 @@ +package com.sun.syndication.unittest; + +/** + * + *

+ * @author Alejandro Abdelnur + * + */ +public class TestOpsRSS091U extends FeedOpsTest { + + public TestOpsRSS091U() { + super("rss_0.91U"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestOpsRSS092.java b/src/test/java/com/sun/syndication/unittest/TestOpsRSS092.java new file mode 100644 index 0000000..d8aed17 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestOpsRSS092.java @@ -0,0 +1,15 @@ +package com.sun.syndication.unittest; + +/** + * + *

+ * @author Alejandro Abdelnur + * + */ +public class TestOpsRSS092 extends FeedOpsTest { + + public TestOpsRSS092() { + super("rss_0.92"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestOpsRSS093.java b/src/test/java/com/sun/syndication/unittest/TestOpsRSS093.java new file mode 100644 index 0000000..c85135b --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestOpsRSS093.java @@ -0,0 +1,15 @@ +package com.sun.syndication.unittest; + +/** + * + *

+ * @author Alejandro Abdelnur + * + */ +public class TestOpsRSS093 extends FeedOpsTest { + + public TestOpsRSS093() { + super("rss_0.93"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestOpsRSS094.java b/src/test/java/com/sun/syndication/unittest/TestOpsRSS094.java new file mode 100644 index 0000000..cf1e013 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestOpsRSS094.java @@ -0,0 +1,20 @@ +package com.sun.syndication.unittest; + +/** + * + *

+ * @author Alejandro Abdelnur + * + */ +public class TestOpsRSS094 extends FeedOpsTest { + + public static void main(String[] args) throws Exception { + FeedOpsTest test = new TestOpsRSS094(); + test.testWireFeedSyndFeedConversion(); + } + + public TestOpsRSS094() { + super("rss_0.94"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestOpsRSS10.java b/src/test/java/com/sun/syndication/unittest/TestOpsRSS10.java new file mode 100644 index 0000000..57ec6b6 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestOpsRSS10.java @@ -0,0 +1,15 @@ +package com.sun.syndication.unittest; + +/** + * + *

+ * @author Alejandro Abdelnur + * + */ +public class TestOpsRSS10 extends FeedOpsTest { + + public TestOpsRSS10() { + super("rss_1.0"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestOpsRSS20.java b/src/test/java/com/sun/syndication/unittest/TestOpsRSS20.java new file mode 100644 index 0000000..54c9064 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestOpsRSS20.java @@ -0,0 +1,15 @@ +package com.sun.syndication.unittest; + +/** + * + *

+ * @author Alejandro Abdelnur + * + */ +public class TestOpsRSS20 extends FeedOpsTest { + + public TestOpsRSS20() { + super("rss_2.0"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom03.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom03.java new file mode 100644 index 0000000..2d51454 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom03.java @@ -0,0 +1,103 @@ +/* + * Created on Jun 24, 2004 + * + */ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndContent; +import com.sun.syndication.io.impl.DateParser; + +import java.util.List; +import java.util.Date; + +/** + * @author pat + * + */ +public class TestSyndFeedAtom03 extends SyndFeedTest { + + public TestSyndFeedAtom03() { + super("atom_0.3"); + } + + protected TestSyndFeedAtom03(String type) { + super(type); + } + + protected TestSyndFeedAtom03(String feedType,String feedFileName) { + super(feedType,feedFileName); + } + + public void testTitle() throws Exception { + assertProperty(getCachedSyndFeed().getTitle(),"feed.title"); + } + + public void testLink() throws Exception { + assertProperty( getCachedSyndFeed().getLink(),"feed.link^href"); + } + + public void getAuthor() throws Exception { + assertProperty(getCachedSyndFeed().getAuthor(),"feed.author.name"); + } + + public void testCopyright() throws Exception { + assertProperty(getCachedSyndFeed().getCopyright(),"feed.copyright"); + } + + public void testPublishedDate() throws Exception { + Date d = DateParser.parseW3CDateTime("2000-01-01T00:00:00Z"); + assertEquals(getCachedSyndFeed().getPublishedDate(),d); + } + + + protected void _testEntry(int i) throws Exception { + List items = getCachedSyndFeed().getEntries(); + SyndEntry entry = (SyndEntry) items.get(i); + assertProperty(entry.getTitle(),"feed.entry["+i+"].title"); + assertProperty(entry.getLink(),"feed.entry["+i+"].link^href"); + assertProperty(entry.getAuthor(),"feed.entry["+i+"].author.name"); + Date d = DateParser.parseW3CDateTime("2000-0"+(i+1)+"-01T00:00:00Z"); + assertEquals(entry.getPublishedDate(),d); + assertProperty(entry.getDescription().getValue(),"feed.entry["+i+"].summary"); + assertProperty(((SyndContent)entry.getContents().get(0)).getValue(),"feed.entry["+i+"].content[0]"); + assertProperty(((SyndContent)entry.getContents().get(1)).getValue(),"feed.entry["+i+"].content[1]"); + } + + public void testEntry0() throws Exception { + _testEntry(0); + } + + public void testEntry1() throws Exception { + _testEntry(1); + } + + public void testDescription() throws Exception { + assertEqualsStr("feed.tagline", getCachedSyndFeed().getDescription()); + } + + public void testEntryLink() throws Exception { + assertEqualsStr("feed.entry[0].link^href", getEntryLink(getCachedSyndFeed().getEntries().get(0))); + assertEqualsStr("feed.entry[1].link^href", getEntryLink(getCachedSyndFeed().getEntries().get(1))); + } + + public void testLanguage() throws Exception { + // not supported + } + + public void testImage() throws Exception { + // not supported + } + + public void testEntryTitle() throws Exception { + assertEqualsStr("feed.entry[0].title", getEntryTitle(getCachedSyndFeed().getEntries().get(0))); + assertEqualsStr("feed.entry[1].title", getEntryTitle(getCachedSyndFeed().getEntries().get(1))); + } + + public void testEntryDescription() throws Exception { + assertEqualsStr("feed.entry[0].summary", getEntryDescription(getCachedSyndFeed().getEntries().get(0))); + assertEqualsStr("feed.entry[1].summary", getEntryDescription(getCachedSyndFeed().getEntries().get(1))); + } + + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom03DCSyModules.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom03DCSyModules.java new file mode 100644 index 0000000..f71f59e --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom03DCSyModules.java @@ -0,0 +1,114 @@ +/* + * Created on Jun 25, 2004 + * + * TODO To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.module.DCModule; +import com.sun.syndication.feed.module.SyModule; +import com.sun.syndication.feed.module.DCSubject; +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.io.impl.DateParser; + +import java.util.Date; +import java.util.List; + + +/** + * @author pat + * + * TODO To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class TestSyndFeedAtom03DCSyModules extends TestSyndFeedAtom03 { + + public TestSyndFeedAtom03DCSyModules() { + super("atom_0.3", "atom_0.3_DC_Sy.xml"); + } + + protected TestSyndFeedAtom03DCSyModules(String type) { + super(type); + } + + protected TestSyndFeedAtom03DCSyModules(String feedType,String feedFileName) { + super(feedType,feedFileName); + } + + public void testModules() throws Exception { + DCModule dc = (DCModule) getCachedSyndFeed().getModule(DCModule.URI); + assertNotNull(dc); + SyModule sy = (SyModule) getCachedSyndFeed().getModule(SyModule.URI); + assertNotNull(sy); + } + + public void testFeedDCModule() throws Exception { + DCModule dc = (DCModule) getCachedSyndFeed().getModule(DCModule.URI); + _testDCModule(dc,"feed.",false,0); + } + + protected void _testDCModule(DCModule dc,String prefix,boolean isEntry,int index) throws Exception { + assertNotNull(dc); + assertProperty(dc.getTitle(),prefix+"dc:title"); + + assertProperty(dc.getCreator(),prefix+"dc:creator"); // Convenience method + + assertProperty(((DCSubject)dc.getSubjects().get(0)).getValue(),prefix+"dc:subject[0]"); + String taxo0 = ((DCSubject)dc.getSubjects().get(0)).getTaxonomyUri(); + if (taxo0!=null) { + assertProperty(taxo0,prefix+"dc:subject[0].taxo:topic^resource"); + } + assertProperty(((DCSubject)dc.getSubjects().get(1)).getValue(),prefix+"dc:subject[1]"); + String taxo1 = ((DCSubject)dc.getSubjects().get(1)).getTaxonomyUri(); + if (taxo1!=null) { + assertProperty(taxo1,prefix+"dc:subject[1].taxo:topic^resource"); + } + assertProperty(dc.getDescription(),prefix+"dc:description"); + assertProperty(dc.getPublisher(),prefix+"dc:publisher"); + assertProperty((String)dc.getContributors().get(0),prefix+"dc:contributor[0]"); + assertProperty((String)dc.getContributors().get(1),prefix+"dc:contributor[1]"); + Date date = DateParser.parseW3CDateTime("2000-0"+(index+1)+"-01T00:00:00Z"); + assertEquals(dc.getDate(),date); + assertProperty(dc.getType(),prefix+"dc:type"); + assertProperty(dc.getFormat(),prefix+"dc:format"); + assertProperty(dc.getIdentifier(),prefix+"dc:identifier"); + assertProperty(dc.getSource(),prefix+"dc:source"); + assertProperty(dc.getLanguage(),prefix+"dc:language"); + assertProperty(dc.getRelation(),prefix+"dc:relation"); + assertProperty(dc.getCoverage(),prefix+"dc:coverage"); + + if (isEntry) { + assertProperty(dc.getRights(),prefix+"dc:rights"); + } + else { + assertProperty(dc.getRights(),prefix+"copyright"); // in header is convenience method + } + } + + public void testFeedSyModule() throws Exception { + SyModule sy = (SyModule) getCachedSyndFeed().getModule(SyModule.URI); + assertNotNull(sy); + assertEquals(sy.getUpdatePeriod(),SyModule.HOURLY); + assertEquals(sy.getUpdateFrequency(),100); + Date date = DateParser.parseW3CDateTime("2001-01-01T01:00+00:00"); + assertEquals(sy.getUpdateBase(),date); + } + + public void testEntriesDCModule() throws Exception { + _testEntryDCModule(0); + _testEntryDCModule(1); + } + + protected void _testEntryDCModule(int i) throws Exception { + List entries = getCachedSyndFeed().getEntries(); + SyndEntry entry = (SyndEntry) entries.get(i); + DCModule dc = (DCModule) entry.getModule(DCModule.URI); + _testDCModule(dc,"feed.entry["+i+"].",true,i); + + } + + public void testLanguage() throws Exception { + assertEqualsStr("feed.dc:language", getCachedSyndFeed().getLanguage()); + } +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10.java new file mode 100644 index 0000000..af731c4 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10.java @@ -0,0 +1,134 @@ +/* + * Created on Jun 24, 2004 + * + */ +package com.sun.syndication.unittest; + +import java.util.Date; +import java.util.List; + +import com.sun.syndication.feed.atom.Entry; +import com.sun.syndication.feed.rss.Item; +import com.sun.syndication.feed.synd.SyndContent; +import com.sun.syndication.feed.synd.SyndEnclosure; +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndLink; +import com.sun.syndication.io.impl.DateParser; + +/** + * @author pat + * @author Dave Johnson (modified for Atom 1.0) + * + */ +public class TestSyndFeedAtom10 extends TestSyndFeedAtom03 { + + public TestSyndFeedAtom10() { + super("atom_1.0"); + } + + protected TestSyndFeedAtom10(String type) { + super(type); + } + + protected TestSyndFeedAtom10(String feedType,String feedFileName) { + super(feedType,feedFileName); + } + + public void testTitle() throws Exception { + assertProperty(getCachedSyndFeed().getTitle(),"feed.title"); + assertProperty(getCachedSyndFeed().getTitleEx().getValue(),"feed.title"); + assertEquals("html", getCachedSyndFeed().getTitleEx().getType()); + + List altLinks = getCachedSyndFeed().getLinks(); + assertEquals(3, altLinks.size()); + + assertEquals("http://example.com/blog", ((SyndLink)altLinks.get(0)).getHref()); + assertEquals("text/html", ((SyndLink)altLinks.get(0)).getType()); + + assertEquals("http://example.com/blog_plain", ((SyndLink)altLinks.get(1)).getHref()); + assertEquals("text/plain", ((SyndLink)altLinks.get(1)).getType()); + } + + public void testLink() throws Exception { + assertEquals( getCachedSyndFeed().getLink(),"http://example.com/blog"); + } + + public void getAuthor() throws Exception { + assertProperty(getCachedSyndFeed().getAuthor(),"feed.author.name"); + } + + public void testCopyright() throws Exception { + assertProperty(getCachedSyndFeed().getCopyright(),"feed.copyright"); + } + + public void testForeignMarkup() throws Exception { + assertEquals(1, ((List)getCachedSyndFeed().getForeignMarkup()).size()); + } + + public void testPublishedDate() throws Exception { + Date d = DateParser.parseW3CDateTime("2000-01-01T00:00:00Z"); + assertEquals(getCachedSyndFeed().getPublishedDate(),d); + } + + + protected void _testEntry(int i) throws Exception { + List items = getCachedSyndFeed().getEntries(); + SyndEntry entry = (SyndEntry) items.get(i); + + assertProperty(entry.getTitle(),"feed.entry["+i+"].title"); + assertProperty(entry.getTitleEx().getValue(),"feed.entry["+i+"].title"); + assertEquals("text",entry.getTitleEx().getType()); + + assertEquals("http://example.com/blog/entry" + (i + 1), entry.getLink()); + assertEquals(((SyndEnclosure)entry.getEnclosures().get(0)).getUrl(),"http://example.com/blog/enclosure"+(i+1)+".gif"); + assertProperty(entry.getAuthor(),"feed.entry["+i+"].author.name"); + Date d = DateParser.parseW3CDateTime("2000-0"+(i+1)+"-01T01:00:00Z"); + assertEquals(entry.getPublishedDate(),d); + assertProperty(entry.getDescription().getValue(),"feed.entry["+i+"].summary"); + assertProperty(((SyndContent)entry.getContents().get(0)).getValue(),"feed.entry["+i+"].content[0]"); + assertEquals(1, ((List)entry.getForeignMarkup()).size()); + + if (i == 0) { + List links = entry.getLinks(); + assertEquals(4, links.size()); + + assertEquals("http://example.com/blog/entry1", ((SyndLink)links.get(0)).getHref()); + assertEquals("text/html", ((SyndLink)links.get(0)).getType()); + + assertEquals("http://example.com/blog/entry1_plain", ((SyndLink)links.get(1)).getHref()); + assertEquals("text/plain", ((SyndLink)links.get(1)).getType()); + + SyndLink slink = (SyndLink)entry.getLinks().get(3); + assertTrue(slink.getHref().startsWith("tag:")); + } else { + SyndLink slink = (SyndLink)entry.getLinks().get(2); + assertTrue(slink.getHref().startsWith("tag:")); + + } + } + + public void testEntry0() throws Exception { + _testEntry(0); + } + + public void testEntry1() throws Exception { + _testEntry(1); + } + + public void testEntryLink() throws Exception { + assertEquals("http://example.com/blog/entry1", getEntryLink(getCachedSyndFeed().getEntries().get(0))); + assertEquals("http://example.com/blog/entry2", getEntryLink(getCachedSyndFeed().getEntries().get(1))); + } + + public void testPreservedWireItems() throws Exception { + SyndEntry syndEntry1 = (SyndEntry) getCachedSyndFeed(true).getEntries().get(0); + Object o = syndEntry1.getWireEntry(); + assertNotNull(o); + assertTrue(o instanceof Entry); + if (o instanceof Entry) { + Entry entry = (Entry) o; + assertEquals("atom_1.0.feed.entry[0].rights", entry.getRights()); + } + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10Bray.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10Bray.java new file mode 100644 index 0000000..1896905 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10Bray.java @@ -0,0 +1,41 @@ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.io.impl.Atom10Parser; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class TestSyndFeedAtom10Bray extends FeedTest { + + protected void setUp() throws Exception { + super.setUp(); + Atom10Parser.setResolveURIs(true); + } + + protected void tearDown() throws Exception { + Atom10Parser.setResolveURIs(false); + super.tearDown(); + } + + public TestSyndFeedAtom10Bray() { + super("atom_1.0_bray.xml"); + } + + public void testFeedURI() throws Exception { + SyndFeed feed = getSyndFeed(false); + assertEquals("Bad URL: "+feed.getUri(), "http://www.example.com/blog", feed.getUri()); + } + public void testEntry1URI() throws Exception { + SyndFeed feed = getSyndFeed(false); + SyndEntry entry = (SyndEntry)feed.getEntries().get(0); + assertEquals("Bad URL: "+entry.getLink(), "http://www.example.com/blog/2006-11-05/entry1", entry.getLink()); + } + public void testEntry2URI() throws Exception { + SyndFeed feed = getSyndFeed(false); + SyndEntry entry = (SyndEntry)feed.getEntries().get(1); + assertEquals("Bad URL: "+entry.getLink(), "http://www.example.com/blog/2006-11-02/entry2", entry.getLink()); + } +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10Ruby.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10Ruby.java new file mode 100644 index 0000000..fa3743d --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10Ruby.java @@ -0,0 +1,37 @@ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.io.impl.Atom10Parser; + +public class TestSyndFeedAtom10Ruby extends FeedTest { + + protected void setUp() throws Exception { + super.setUp(); + Atom10Parser.setResolveURIs(true); + } + + protected void tearDown() throws Exception { + Atom10Parser.setResolveURIs(false); + super.tearDown(); + } + + public TestSyndFeedAtom10Ruby() { + super("atom_1.0_ruby.xml"); + } + + public void testFeedURI() throws Exception { + SyndFeed feed = getSyndFeed(false); + assertEquals("http://www.example.com/blog", feed.getUri()); + } + public void testEntry1URI() throws Exception { + SyndFeed feed = getSyndFeed(false); + SyndEntry entry = (SyndEntry)feed.getEntries().get(0); + assertEquals("http://www.example.com/blog/bloggy-blog", entry.getLink()); + } + public void testEntry2URI() throws Exception { + SyndFeed feed = getSyndFeed(false); + SyndEntry entry = (SyndEntry)feed.getEntries().get(1); + assertEquals("http://www.example.com/frog/froggy-frog", entry.getLink()); + } +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10b.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10b.java new file mode 100644 index 0000000..0850c87 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10b.java @@ -0,0 +1,39 @@ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.io.impl.Atom10Parser; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class TestSyndFeedAtom10b extends FeedTest { + + + protected void setUp() throws Exception { + super.setUp(); + Atom10Parser.setResolveURIs(true); + } + + protected void tearDown() throws Exception { + Atom10Parser.setResolveURIs(false); + super.tearDown(); + } + + public TestSyndFeedAtom10b() { + super("atom_1.0_b.xml"); + } + + public void testXmlBaseConformance() throws Exception { + List errors = new ArrayList(); + SyndFeed feed = getSyndFeed(false); + List entries = feed.getEntries(); + for (int index = 0; index < entries.size(); index++) { + SyndEntry entry = (SyndEntry) entries.get(index); + assertEquals( + "Incorrect URI: " + entry.getLink() + " in entry [" + entry.getTitle() + "]", + "http://example.org/tests/base/result.html", entry.getLink()); + } + } +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10prefix.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10prefix.java new file mode 100644 index 0000000..f5962f7 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedAtom10prefix.java @@ -0,0 +1,31 @@ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.synd.SyndLink; +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndEnclosure; +import com.sun.syndication.feed.synd.SyndContent; +import com.sun.syndication.feed.atom.Feed; +import com.sun.syndication.feed.atom.Link; +import com.sun.syndication.io.impl.DateParser; + +import java.util.List; +import java.util.Date; + +public class TestSyndFeedAtom10prefix extends FeedTest { + + public TestSyndFeedAtom10prefix() { + super("atom_1.0_prefix.xml"); + } + + public void testTitle() throws Exception { + Feed feed = (Feed) getWireFeed(); + assertEquals("1", feed.getId()); + assertEquals("xxx1", ((Link)feed.getOtherLinks().get(0)).getRel()); + assertEquals("xxx2", ((Link)feed.getOtherLinks().get(1)).getRel()); + assertEquals("xxx11", ((Link)feed.getOtherLinks().get(0)).getType()); + assertEquals("xxx22", ((Link)feed.getOtherLinks().get(1)).getType()); + assertEquals("http://foo.com/1", ((Link)feed.getOtherLinks().get(0)).getHref()); + assertEquals("http://foo.com/2", ((Link)feed.getOtherLinks().get(1)).getHref()); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS090.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS090.java new file mode 100644 index 0000000..ea865dc --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS090.java @@ -0,0 +1,105 @@ +/* + * Created on Jun 24, 2004 + * + */ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.synd.SyndEntry; + +import java.util.List; + +/** + * @author pat + * + */ +public class TestSyndFeedRSS090 extends SyndFeedTest { + + public TestSyndFeedRSS090() { + super("rss_0.9"); + } + + protected TestSyndFeedRSS090(String type) { + super(type); + } + + protected TestSyndFeedRSS090(String feedType,String feedFileName) { + super(feedType,feedFileName); + } + + public void testTitle() throws Exception { + assertProperty(getCachedSyndFeed().getTitle(),"channel.title"); + } + + public void testLink() throws Exception { + assertProperty( getCachedSyndFeed().getLink(),"channel.link"); + } + + public void testDescription() throws Exception { + assertProperty(getCachedSyndFeed().getDescription(),"channel.description"); + } + + public void testImageTitle() throws Exception { + assertProperty(getCachedSyndFeed().getImage().getTitle(),"image.title"); + } + + public void testImageUrl() throws Exception { + assertProperty(getCachedSyndFeed().getImage().getUrl(),"image.url"); + } + + public void testImageLink() throws Exception { + assertProperty(getCachedSyndFeed().getImage().getLink(),"image.link"); + } + + protected void _testItem(int i) throws Exception { + List items = getCachedSyndFeed().getEntries(); + SyndEntry entry = (SyndEntry) items.get(i); + assertProperty(entry.getTitle(),"item["+i+"].title"); + assertProperty(entry.getLink(),"item["+i+"].link"); + + _testUri(entry,i); + } + + public void testItem0() throws Exception { + _testItem(0); + } + + public void testItem1() throws Exception { + _testItem(1); + } + + protected void _testUri(SyndEntry entry,int i) throws Exception { + assertProperty(entry.getUri(),"item["+i+"].link"); + } + + public void testLanguage() throws Exception { + // not supported + } + + public void testPublishedDate() throws Exception { + // not supported + } + + public void testImage() throws Exception { + // not supported + } + + public void testEntryTitle() throws Exception { + assertEqualsStr("item[0].title", getEntryTitle(getCachedSyndFeed().getEntries().get(0))); + assertEqualsStr("item[1].title", getEntryTitle(getCachedSyndFeed().getEntries().get(1))); + } + + public void testEntryDescription() throws Exception { + // I think this should be should work, but it can't seem to find the description + //System.out.println(((SyndEntry)getCachedSyndFeed().getEntries().get(0)).getDescription()); + } + + public void testEntryLink() throws Exception { + assertEqualsStr("item[0].link", getEntryLink(getCachedSyndFeed().getEntries().get(0))); + assertEqualsStr("item[1].link", getEntryLink(getCachedSyndFeed().getEntries().get(1))); + } + + public void testEntryPublishedDate() throws Exception { + // not supported + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS091N.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS091N.java new file mode 100644 index 0000000..302093a --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS091N.java @@ -0,0 +1,78 @@ +/* + * Created on Jun 24, 2004 + * + */ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.io.impl.DateParser; + +import java.util.List; +import java.util.Date; + +/** + * @author pat + * + */ +public class TestSyndFeedRSS091N extends SyndFeedTest { + + public TestSyndFeedRSS091N() { + super("rss_0.91N", "rss_0.91N.xml"); + } + + protected TestSyndFeedRSS091N(String type) { + super(type); + } + + protected TestSyndFeedRSS091N(String feedType,String feedFileName) { + super(feedType,feedFileName); + } + + public void testLanguage() throws Exception { + assertProperty(getCachedSyndFeed().getLanguage(),"channel.language"); + } + + public void testCopyright() throws Exception { + assertProperty(getCachedSyndFeed().getCopyright(),"channel.copyright"); + } + + public void testPublishedDate() throws Exception { + Date d = DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"); + assertEquals(getCachedSyndFeed().getPublishedDate(),d); + } + + public void testAuthor() throws Exception { + assertProperty(getCachedSyndFeed().getAuthor(),"channel.managingEditor"); + } + + public void testImageTitle() throws Exception { + assertProperty(getCachedSyndFeed().getImage().getTitle(),"channel.image.title"); + } + + public void testImageUrl() throws Exception { + assertProperty(getCachedSyndFeed().getImage().getUrl(),"channel.image.url"); + } + + public void testImageLink() throws Exception { + assertProperty(getCachedSyndFeed().getImage().getLink(),"channel.image.link"); + } + + public void testImageDescription() throws Exception { + assertProperty(getCachedSyndFeed().getImage().getDescription(),"channel.image.description"); + } + + protected void _testItem(int i) throws Exception { + List items = getCachedSyndFeed().getEntries(); + SyndEntry entry = (SyndEntry) items.get(i); + assertProperty(entry.getTitle(),"channel.item["+i+"].title"); + assertProperty(entry.getLink(),"channel.item["+i+"].link"); + assertProperty(entry.getDescription().getValue(),"channel.item["+i+"].description"); + } + + protected void _testUri(SyndEntry entry,int i) throws Exception { + assertProperty(entry.getUri(),"channel.item["+i+"].link"); + } + + + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS091U.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS091U.java new file mode 100644 index 0000000..a09c37b --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS091U.java @@ -0,0 +1,17 @@ +/* + * Created on Jun 24, 2004 + * + */ +package com.sun.syndication.unittest; + +/** + * @author pat + * + */ +public class TestSyndFeedRSS091U extends TestSyndFeedRSS091N { + + public TestSyndFeedRSS091U() { + super("rss_0.91U", "rss_0.91U.xml"); + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS092.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS092.java new file mode 100644 index 0000000..c77808a --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS092.java @@ -0,0 +1,68 @@ +/* + * Created on Jun 24, 2004 + * + */ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.synd.SyndCategory; +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndEnclosure; + +import java.util.List; +import java.util.Set; +import java.util.HashSet; + +/** + * @author pat + * + */ +public class TestSyndFeedRSS092 extends TestSyndFeedRSS091N { + + public TestSyndFeedRSS092() { + super("rss_0.92"); + } + + protected TestSyndFeedRSS092(String type) { + super(type); + } + + protected TestSyndFeedRSS092(String feedType,String feedFileName) { + super(feedType,feedFileName); + } + + protected void _testItem(int i) throws Exception { + super._testItem(i); + List items = getCachedSyndFeed().getEntries(); + SyndEntry entry = (SyndEntry) items.get(i); + + assertProperty(entry.getTitle(),"channel.item["+i+"].title"); + assertProperty(entry.getLink(),"channel.item["+i+"].link"); + assertProperty(entry.getDescription().getValue(),"channel.item["+i+"].description"); + _testCategories(entry.getCategories(),"channel.item["+i+"]"); + _testEnclosures(entry.getEnclosures(),"channel.item["+i+"]"); + } + + protected void _testCategories(List cats,String prefix) throws Exception { + Set s1 = new HashSet(); + Set s2 = new HashSet(); + for (int i=0;i + * @author Paul Dlug + */ +public class TestSyndFeedRSS10DCMulti extends TestSyndFeedRSS10 { + + public TestSyndFeedRSS10DCMulti() { + super("rss_1.0", "rss_1.0_DC_multi.xml"); + } + + protected TestSyndFeedRSS10DCMulti(String type) { + super(type); + } + + protected TestSyndFeedRSS10DCMulti(String feedType, String feedFileName) { + super(feedType, feedFileName); + } + + public void testChannelDCModule() throws Exception { + DCModule dc = (DCModule) getCachedSyndFeed().getModule(DCModule.URI); + _testDCModule(dc, "channel."); + } + + protected void _testDCModule(DCModule dc,String prefix) throws Exception { + assertNotNull(dc); + + assertProperty((String)dc.getTitles().get(0), prefix + "dc:title[0]"); + assertProperty((String)dc.getTitles().get(1), prefix + "dc:title[1]"); + + assertProperty((String)dc.getCreators().get(0), prefix + "dc:creator[0]"); + assertProperty((String)dc.getCreators().get(1), prefix + "dc:creator[1]"); + + assertProperty(((DCSubject)dc.getSubjects().get(0)).getValue(), prefix + "dc:subject[0]"); + String taxo0 = ((DCSubject)dc.getSubjects().get(0)).getTaxonomyUri(); + if (taxo0 != null) { + assertProperty(taxo0, prefix + "dc:subject[0].taxo:topic^resource"); + } + assertProperty(((DCSubject)dc.getSubjects().get(1)).getValue(), prefix + "dc:subject[1]"); + String taxo1 = ((DCSubject)dc.getSubjects().get(1)).getTaxonomyUri(); + if (taxo1 != null) { + assertProperty(taxo1, prefix + "dc:subject[1].taxo:topic^resource"); + } + + assertProperty((String)dc.getDescriptions().get(0), prefix + "dc:description[0]"); + assertProperty((String)dc.getDescriptions().get(1), prefix + "dc:description[1]"); + + assertProperty((String)dc.getPublishers().get(0), prefix + "dc:publisher[0]"); + assertProperty((String)dc.getPublishers().get(1), prefix + "dc:publisher[1]"); + + assertProperty((String)dc.getContributors().get(0),prefix + "dc:contributor[0]"); + assertProperty((String)dc.getContributors().get(1),prefix + "dc:contributor[1]"); + Date date = DateParser.parseW3CDateTime("2001-01-01T00:00+00:00"); + assertEquals((Date)dc.getDates().get(0), date); + assertEquals((Date)dc.getDates().get(1), date); + + assertProperty((String)dc.getTypes().get(0), prefix + "dc:type[0]"); + assertProperty((String)dc.getTypes().get(1), prefix +"dc:type[1]"); + + assertProperty((String)dc.getFormats().get(0), prefix + "dc:format[0]"); + assertProperty((String)dc.getFormats().get(1), prefix + "dc:format[1]"); + + assertProperty((String)dc.getIdentifiers().get(0), prefix + "dc:identifier[0]"); + assertProperty((String)dc.getIdentifiers().get(1), prefix + "dc:identifier[1]"); + + assertProperty((String)dc.getSources().get(0), prefix + "dc:source[0]"); + assertProperty((String)dc.getSources().get(1), prefix + "dc:source[1]"); + + assertProperty((String)dc.getLanguages().get(0), prefix + "dc:language[0]"); + assertProperty((String)dc.getLanguages().get(1), prefix + "dc:language[1]"); + + assertProperty((String)dc.getRelations().get(0), prefix + "dc:relation[0]"); + assertProperty((String)dc.getRelations().get(1), prefix + "dc:relation[1]"); + + assertProperty((String)dc.getCoverages().get(0), prefix + "dc:coverage[0]"); + assertProperty((String)dc.getCoverages().get(1), prefix + "dc:coverage[1]"); + + assertProperty((String)dc.getRightsList().get(0), prefix + "dc:rights[0]"); + assertProperty((String)dc.getRightsList().get(1), prefix + "dc:rights[1]"); + } + + public void testItemsDCModule() throws Exception { + _testItemDCModule(0); + _testItemDCModule(1); + } + + protected void _testItemDCModule(int i) throws Exception { + List entries = getCachedSyndFeed().getEntries(); + SyndEntry entry = (SyndEntry) entries.get(i); + DCModule dc = (DCModule) entry.getModule(DCModule.URI); + _testDCModule(dc, "item[" + i + "]."); + } +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS10DCSyModules.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS10DCSyModules.java new file mode 100644 index 0000000..7bd8375 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS10DCSyModules.java @@ -0,0 +1,97 @@ +/* + * Created on Jun 25, 2004 + * + * TODO To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.sun.syndication.unittest; + +import com.sun.syndication.feed.module.DCModule; +import com.sun.syndication.feed.module.SyModule; +import com.sun.syndication.feed.module.DCSubject; +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.io.impl.DateParser; + +import java.util.List; +import java.util.Date; + + +/** + * @author pat + * + * TODO To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class TestSyndFeedRSS10DCSyModules extends TestSyndFeedRSS10 { + + public TestSyndFeedRSS10DCSyModules() { + super("rss_1.0", "rss_1.0_DC_Sy.xml"); + } + + protected TestSyndFeedRSS10DCSyModules(String type) { + super(type); + } + + protected TestSyndFeedRSS10DCSyModules(String feedType,String feedFileName) { + super(feedType,feedFileName); + } + + public void testChannelDCModule() throws Exception { + DCModule dc = (DCModule) getCachedSyndFeed().getModule(DCModule.URI); + _testDCModule(dc,"channel."); + } + + protected void _testDCModule(DCModule dc,String prefix) throws Exception { + assertNotNull(dc); + assertProperty(dc.getTitle(),prefix+"dc:title"); + assertProperty(dc.getCreator(),prefix+"dc:creator"); + assertProperty(((DCSubject)dc.getSubjects().get(0)).getValue(),prefix+"dc:subject[0]"); + String taxo0 = ((DCSubject)dc.getSubjects().get(0)).getTaxonomyUri(); + if (taxo0!=null) { + assertProperty(taxo0,prefix+"dc:subject[0].taxo:topic^resource"); + } + assertProperty(((DCSubject)dc.getSubjects().get(1)).getValue(),prefix+"dc:subject[1]"); + String taxo1 = ((DCSubject)dc.getSubjects().get(1)).getTaxonomyUri(); + if (taxo1!=null) { + assertProperty(taxo1,prefix+"dc:subject[1].taxo:topic^resource"); + } + assertProperty(dc.getDescription(),prefix+"dc:description"); + assertProperty(dc.getPublisher(),prefix+"dc:publisher"); + assertProperty((String)dc.getContributors().get(0),prefix+"dc:contributor[0]"); + assertProperty((String)dc.getContributors().get(1),prefix+"dc:contributor[1]"); + Date date = DateParser.parseW3CDateTime("2001-01-01T00:00+00:00"); + assertEquals(dc.getDate(),date); + assertProperty(dc.getType(),prefix+"dc:type"); + assertProperty(dc.getFormat(),prefix+"dc:format"); + assertProperty(dc.getIdentifier(),prefix+"dc:identifier"); + assertProperty(dc.getSource(),prefix+"dc:source"); + assertProperty(dc.getLanguage(),prefix+"dc:language"); + assertProperty(dc.getRelation(),prefix+"dc:relation"); + assertProperty(dc.getCoverage(),prefix+"dc:coverage"); + assertProperty(dc.getRights(),prefix+"dc:rights"); + } + + public void testChannelSyModule() throws Exception { + SyModule sy = (SyModule) getCachedSyndFeed().getModule(SyModule.URI); + assertNotNull(sy); + assertEquals(sy.getUpdatePeriod(),SyModule.HOURLY); + assertEquals(sy.getUpdateFrequency(),100); + Date date = DateParser.parseW3CDateTime("2001-01-01T01:00+00:00"); + assertEquals(sy.getUpdateBase(),date); + } + + public void testItemsDCModule() throws Exception { + _testItemDCModule(0); + _testItemDCModule(1); + } + + protected void _testItemDCModule(int i) throws Exception { + List entries = getCachedSyndFeed().getEntries(); + SyndEntry entry = (SyndEntry) entries.get(i); + DCModule dc = (DCModule) entry.getModule(DCModule.URI); + _testDCModule(dc,"item["+i+"]."); + + } + + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS20.java b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS20.java new file mode 100644 index 0000000..9e07eb1 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestSyndFeedRSS20.java @@ -0,0 +1,66 @@ +/* + * Created on Jun 24, 2004 + * + */ +package com.sun.syndication.unittest; + +import java.util.List; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.rss.Channel; +import com.sun.syndication.feed.rss.Item; +import com.sun.syndication.feed.synd.SyndContent; +import com.sun.syndication.feed.synd.SyndEntry; + +/** + * @author pat + * + */ +public class TestSyndFeedRSS20 extends TestSyndFeedRSS094 { + + public TestSyndFeedRSS20() { + super("rss_2.0"); + } + + protected TestSyndFeedRSS20(String type) { + super(type); + } + + protected TestSyndFeedRSS20(String feedType,String feedFileName) { + super(feedType,feedFileName); + } + + protected void _testItem(int i) throws Exception { + super._testItem(i); + List items = getCachedSyndFeed().getEntries(); + SyndEntry entry = (SyndEntry) items.get(i); + assertProperty(((SyndContent)entry.getContents().get(0)).getValue(), "channel.item["+i+"].content"); + } + + /** + * Test we can get to RSS attributes which aren't exposed in the SyndEntry object + * @throws Exception + */ + public void testPreservedWireItems() throws Exception { + SyndEntry syndEntry1 = (SyndEntry) getCachedSyndFeed(true).getEntries().get(0); + Object o = syndEntry1.getWireEntry(); + assertNotNull(o); + assertTrue(o instanceof Item); + if (o instanceof Item) { + Item item = (Item) o; + assertEquals("rss_2.0.channel.item[0].comments", item.getComments()); + } + } + + public void testPreserveWireFeedComments() throws Exception { + WireFeed wf = getCachedSyndFeed(true).originalWireFeed(); + assertNotNull(wf); + assertTrue(wf instanceof Channel); + if (wf instanceof Channel) { + Channel channel = (Channel) wf; + assertEquals("rss_2.0.channel.item[0].comments", ((Item)channel.getItems().get(0)).getComments()); + assertEquals("rss_2.0.channel.item[1].comments", ((Item)channel.getItems().get(1)).getComments()); + } + } + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestXmlFixerReader.java b/src/test/java/com/sun/syndication/unittest/TestXmlFixerReader.java new file mode 100644 index 0000000..a0b7ef7 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestXmlFixerReader.java @@ -0,0 +1,157 @@ +/* + * 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 com.sun.syndication.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 = ""; + + public void testTrim() throws Exception { + _testValidTrim("",""); + _testValidTrim("",XML_PROLOG+""); + _testValidTrim(" ",""); + _testValidTrim(" ",XML_PROLOG+""); + _testValidTrim(" \n",""); + _testValidTrim(" \n",XML_PROLOG+""); + _testValidTrim("",""); + _testValidTrim("",XML_PROLOG+""); + _testValidTrim(" ",""); + _testValidTrim(" ",XML_PROLOG+""); + _testValidTrim(" ",""); + _testValidTrim(" ",XML_PROLOG+""); + _testValidTrim(" ",""); + _testValidTrim(" ",XML_PROLOG+""); + _testValidTrim(" \n ",""); + _testValidTrim(" \n ",XML_PROLOG+""); + + _testInvalidTrim("x",""); + _testInvalidTrim("x",XML_PROLOG+""); + _testInvalidTrim(" x",""); + _testInvalidTrim(" x",XML_PROLOG+""); + _testInvalidTrim(" x\n",""); + _testInvalidTrim(" x\n",XML_PROLOG+""); + _testInvalidTrim("x ",""); + _testInvalidTrim(" x ",XML_PROLOG+""); + _testInvalidTrim(" x ",""); + _testInvalidTrim(" x ",XML_PROLOG+""); + _testInvalidTrim(" x\n ",""); + _testInvalidTrim(" x\n ",XML_PROLOG+""); + } + + public void testAmpHandling() throws Exception { + String input = "& &aa &"; + BufferedReader reader = new BufferedReader(new XmlFixerReader(new StringReader(input))); + String output = reader.readLine(); + reader.close(); + assertEquals("& &aa &", output); + } + + public void testHtmlEntities() throws Exception { + _testValidEntities(""); + _testValidEntities(XML_PROLOG+""); + _testValidEntities(" \n"+XML_PROLOG+""); + + _testValidEntities("'¥ú¥"); + _testValidEntities(XML_PROLOG+"'¥ú¥"); + _testValidEntities(" \n"+XML_PROLOG+"'¥ú¥"); + + _testValidEntities("ΠΡ#913;Ρ"); + _testValidEntities(XML_PROLOG+"ΠΡΑΡ"); + _testValidEntities(" \n"+XML_PROLOG+"ΠΡΑΡ"); + + _testValidEntities("Œ—–—"); + _testValidEntities(XML_PROLOG+"Œ—–—"); + _testValidEntities(" \n"+XML_PROLOG+"Œ—–—"); + + _testInvalidEntities("'&yexn;ú¥"); + _testInvalidEntities(XML_PROLOG+"'&yexn;ú¥"); + _testInvalidEntities(" \n"+XML_PROLOG+"'&yexn;ú¥"); + + _testInvalidEntities("Π&Rhox;#913;Ρ"); + _testInvalidEntities(XML_PROLOG+"Π&Rhox;ΑΡ"); + _testInvalidEntities(" \n"+XML_PROLOG+"Π&Rhox;ΑΡ"); + + _testInvalidEntities("'¥x50;¥"); + _testInvalidEntities(XML_PROLOG+"'¥x50;¥"); + _testInvalidEntities(" \n"+XML_PROLOG+"'¥x50;¥"); + + _testInvalidEntities("ΠΡ x13;Ρ"); + _testInvalidEntities(XML_PROLOG+"ΠΡ x13;Ρ"); + _testInvalidEntities(" \n"+XML_PROLOG+"ΠΡ x13;Ρ"); + } + + 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()); + } + + +} diff --git a/src/test/java/com/sun/syndication/unittest/TestXmlReader.java b/src/test/java/com/sun/syndication/unittest/TestXmlReader.java new file mode 100644 index 0000000..859dbfb --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/TestXmlReader.java @@ -0,0 +1,317 @@ +/* + * 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 com.sun.syndication.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 { + private static final String XML5 = "xml-prolog-encoding-spaced-single-quotes"; + private static final String XML4 = "xml-prolog-encoding-single-quotes"; + private static final String XML3 = "xml-prolog-encoding-double-quotes"; + private static final String XML2 = "xml-prolog"; + private static final String XML1 = "xml"; + + 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",XML1,encoding,encoding); + XmlReader xmlReader = new XmlReader(is,false); + assertEquals(xmlReader.getEncoding(),"UTF-8"); + + is = getXmlStream("no-bom",XML2,encoding,encoding); + xmlReader = new XmlReader(is); + assertEquals(xmlReader.getEncoding(),"UTF-8"); + + is = getXmlStream("no-bom",XML3,encoding,encoding); + xmlReader = new XmlReader(is); + assertEquals(xmlReader.getEncoding(),encoding); + + is = getXmlStream("no-bom", XML4, encoding, encoding); + xmlReader = new XmlReader(is); + assertEquals(xmlReader.getEncoding(), encoding); + + is = getXmlStream("no-bom", XML5, encoding, encoding); + xmlReader = new XmlReader(is); + assertEquals(xmlReader.getEncoding(), encoding); + } + + protected void _testRawNoBomInvalid(String encoding) throws Exception { + InputStream is = getXmlStream("no-bom",XML3,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",XML3,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,XML3,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",null); + _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); + + _testAlternateDefaultEncoding("application/xml", "UTF-8-bom", "UTF-8", null, null); + _testAlternateDefaultEncoding("application/xml", "no-bom", "US-ASCII", null, "US-ASCII"); + _testAlternateDefaultEncoding("application/xml", "UTF-8-bom", "UTF-8", null, "UTF-8"); + _testAlternateDefaultEncoding("text/xml", "no-bom", "US-ASCII", null, null); + _testAlternateDefaultEncoding("text/xml", "no-bom", "US-ASCII", null, "US-ASCII"); + _testAlternateDefaultEncoding("text/xml", "no-bom", "US-ASCII", null, "UTF-8"); + + _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 _testAlternateDefaultEncoding(String cT, String bomEnc, String streamEnc, String prologEnc, String alternateEnc) throws Exception { + try { + InputStream is = getXmlStream(bomEnc, (prologEnc == null) ? XML1 : XML3, streamEnc, prologEnc); + XmlReader.setDefaultEncoding(alternateEnc); + 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 { + String enc = (alternateEnc != null) ? alternateEnc : streamEnc; + assertEquals(xmlReader.getEncoding().substring(0, streamEnc.length()), streamEnc); + } + } + finally { + XmlReader.setDefaultEncoding(null); + } + } + + public void _testHttpValid(String cT, String bomEnc, String streamEnc, String prologEnc) throws Exception { + InputStream is = getXmlStream(bomEnc,(prologEnc==null)?XML1 :XML3,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)?XML2 :XML3,streamEnc,prologEnc); + try { + 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)?XML2 :XML3,streamEnc,prologEnc); + XmlReader xmlReader = new XmlReader(is,cT,true); + assertEquals(xmlReader.getEncoding(),shouldbe); + } + + private static final String ENCODING_ATTRIBUTE_XML = + " \n" + + "\n" + + "\n" + + " \n" + + " {2}"); + private static final MessageFormat XML_WITH_PROLOG = new MessageFormat( + "\n{2}"); + private static final MessageFormat XML_WITH_PROLOG_AND_ENCODING_DOUBLE_QUOTES = new MessageFormat( + "\n{2}"); + private static final MessageFormat XML_WITH_PROLOG_AND_ENCODING_SINGLE_QUOTES = new MessageFormat( + "\n{2}"); + private static final MessageFormat XML_WITH_PROLOG_AND_ENCODING_SPACED_SINGLE_QUOTES = new MessageFormat( + "\n{2}"); + + 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(XML1, XML); + XMLs.put(XML2, XML_WITH_PROLOG); + XMLs.put(XML3, XML_WITH_PROLOG_AND_ENCODING_DOUBLE_QUOTES); + XMLs.put(XML4, XML_WITH_PROLOG_AND_ENCODING_SINGLE_QUOTES); + XMLs.put(XML5, XML_WITH_PROLOG_AND_ENCODING_SPACED_SINGLE_QUOTES); + } + + /** + * + * @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\n"); + for (int i=0;i<10000;i++) { + writer.write("\n"); + } + writer.write("\n"); + + writer.close(); + return new ByteArrayInputStream(baos.toByteArray()); + } + + +} diff --git a/src/test/java/com/sun/syndication/unittest/issues/Issue1Test.java b/src/test/java/com/sun/syndication/unittest/issues/Issue1Test.java new file mode 100644 index 0000000..66f2356 --- /dev/null +++ b/src/test/java/com/sun/syndication/unittest/issues/Issue1Test.java @@ -0,0 +1,32 @@ +/* + * Copyright 2011 robert.cooper. + * + * 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. + * under the License. + */ + +package com.sun.syndication.unittest.issues; + +import com.sun.syndication.unittest.SyndFeedTest; + +/** + * + * @author robert.cooper + */ +public class Issue1Test extends SyndFeedTest { + + public Issue1Test(){ + super("rss_2.0", "jira_issue1.xml"); + } + +} diff --git a/src/test/resources/atom_0.3.xml b/src/test/resources/atom_0.3.xml new file mode 100644 index 0000000..9d0950d --- /dev/null +++ b/src/test/resources/atom_0.3.xml @@ -0,0 +1,70 @@ + + + atom_0.3.feed.title + + rometest + + atom_0.3.feed.author.name + atom_0.3.feed.author.url + atom_0.3.feed.author.email + + + atom_0.3.feed.contributor.name + atom_0.3.feed.contributor.url + atom_0.3.feed.contributor.email + + atom_0.3.feed.tagline + atom_0.3.feed.id + atom_0.3.feed.generator + atom_0.3.feed.copyright + atom_0.3.feed.info + 2000-01-01T00:00:00Z + + atom_0.3.feed.entry[0].title + + atom_0.3.feed.entry[0]^id + + atom_0.3.feed.entry[0].author.name + atom_0.3.feed.entry[0].author.url + atom_0.3.feed.entry[0].author.email + + + atom_0.3.feed.entry[0].contributor.name + atom_0.3.feed.entry[0].contributor.url + atom_0.3.feed.entry[0].contributor.email + + 2000-01-01T00:00:00Z + 2000-01-01T01:00:00Z + 2000-01-01T02:00:00Z +

atom_0.3.feed.entry[0].summary + atom_0.3.feed.entry[0].content[0] + atom_0.3.feed.entry[0].content[1] + rometest + + + atom_0.3.feed.entry[1].title + + atom_0.3.feed.entry[1]^id + + atom_0.3.feed.entry[1].author.name + atom_0.3.feed.entry[1].author.url + atom_0.3.feed.entry[1].author.email + + + atom_0.3.feed.entry[1].contributor.name + atom_0.3.feed.entry[1].contributor.url + atom_0.3.feed.entry[1].contributor.email + + 2000-02-01T00:00:00Z + 2000-02-01T01:00:00Z + 2000-02-01T02:00:00Z + atom_0.3.feed.entry[1].summary + atom_0.3.feed.entry[1].content[0] + atom_0.3.feed.entry[1].content[1] + rometest + + diff --git a/src/test/resources/atom_0.3_DC_Sy.xml b/src/test/resources/atom_0.3_DC_Sy.xml new file mode 100644 index 0000000..0044d56 --- /dev/null +++ b/src/test/resources/atom_0.3_DC_Sy.xml @@ -0,0 +1,141 @@ + + + + atom_0.3.feed.title + + + atom_0.3.feed.author.name + atom_0.3.feed.author.url + atom_0.3.feed.author.email + + + atom_0.3.feed.contributor.name + atom_0.3.feed.contributor.url + atom_0.3.feed.contributor.email + + atom_0.3.feed.tagline + atom_0.3.feed.id + atom_0.3.feed.generator + atom_0.3.feed.copyright + atom_0.3.feed.info + 2000-01-01T00:00:00Z + + atom_0.3.feed.dc:title + atom_0.3.feed.dc:creator + + + + atom_0.3.feed.dc:subject[0] + + + + + + atom_0.3.feed.dc:subject[1] + + + atom_0.3.feed.dc:description + atom_0.3.feed.dc:publisher + atom_0.3.feed.dc:contributor[0] + atom_0.3.feed.dc:contributor[1] + 2001-01-04T00:00+00:00 + atom_0.3.feed.dc:type + atom_0.3.feed.dc:format + atom_0.3.feed.dc:identifier + atom_0.3.feed.dc:source + atom_0.3.feed.dc:language + atom_0.3.feed.dc:relation + atom_0.3.feed.dc:coverage + atom_0.3.feed.dc:rights + + hourly + 100 + 2001-01-01T01:00+00:00 + + + atom_0.3.feed.entry[0].title + + atom_0.3.feed.entry[0]^id + + atom_0.3.feed.entry[0].author.name + atom_0.3.feed.entry[0].author.url + atom_0.3.feed.entry[0].author.email + + + atom_0.3.feed.entry[0].contributor.name + atom_0.3.feed.entry[0].contributor.url + atom_0.3.feed.entry[0].contributor.email + + 2000-01-01T00:00:00Z + 2000-01-02T01:00:00Z + 2000-01-03T02:00:00Z + atom_0.3.feed.entry[0].summary + atom_0.3.feed.entry[0].content[0] + atom_0.3.feed.entry[0].content[1] + + atom_0.3.feed.entry[0].dc:title + atom_0.3.feed.entry[0].dc:creator + atom_0.3.feed.entry[0].dc:subject[0] + atom_0.3.feed.entry[0].dc:subject[1] + atom_0.3.feed.entry[0].dc:description + atom_0.3.feed.entry[0].dc:publisher + atom_0.3.feed.entry[0].dc:contributor[0] + atom_0.3.feed.entry[0].dc:contributor[1] + 2001-01-04T00:00+00:00 + atom_0.3.feed.entry[0].dc:type + atom_0.3.feed.entry[0].dc:format + atom_0.3.feed.entry[0].dc:identifier + atom_0.3.feed.entry[0].dc:source + atom_0.3.feed.entry[0].dc:language + atom_0.3.feed.entry[0].dc:relation + atom_0.3.feed.entry[0].dc:coverage + atom_0.3.feed.entry[0].dc:rights + + + + atom_0.3.feed.entry[1].title + + atom_0.3.feed.entry[1]^id + + atom_0.3.feed.entry[1].author.name + atom_0.3.feed.entry[1].author.url + atom_0.3.feed.entry[1].author.email + + + atom_0.3.feed.entry[1].contributor.name + atom_0.3.feed.entry[1].contributor.url + atom_0.3.feed.entry[1].contributor.email + + 2000-02-01T00:00:00Z + 2000-02-02T01:00:00Z + 2000-02-03T02:00:00Z + atom_0.3.feed.entry[1].summary + atom_0.3.feed.entry[1].content[0] + atom_0.3.feed.entry[1].content[1] + + atom_0.3.feed.entry[1].dc:title + atom_0.3.feed.entry[1].dc:creator + atom_0.3.feed.entry[1].dc:subject[0] + atom_0.3.feed.entry[1].dc:subject[1] + atom_0.3.feed.entry[1].dc:description + atom_0.3.feed.entry[1].dc:publisher + atom_0.3.feed.entry[1].dc:contributor[0] + atom_0.3.feed.entry[1].dc:contributor[1] + 2001-02-04T00:00+00:00 + atom_0.3.feed.entry[1].dc:type + atom_0.3.feed.entry[1].dc:format + atom_0.3.feed.entry[1].dc:identifier + atom_0.3.feed.entry[1].dc:source + atom_0.3.feed.entry[1].dc:language + atom_0.3.feed.entry[1].dc:relation + atom_0.3.feed.entry[1].dc:coverage + atom_0.3.feed.entry[1].dc:rights + + + diff --git a/src/test/resources/atom_1.0.xml b/src/test/resources/atom_1.0.xml new file mode 100644 index 0000000..9d83939 --- /dev/null +++ b/src/test/resources/atom_1.0.xml @@ -0,0 +1,78 @@ + + + atom_1.0.feed.title + + + + rometest + + atom_1.0.feed.author.name + http://example.com + author0@example.com + + + atom_1.0.feed.contributor.name + http://example.com + author1@example.com + + atom_1.0.feed.tagline + http://example.com/blog/atom_1.0.xml + atom_1.0.feed.generator +atom_1.0.feed.copyright + 2000-01-01T00:00:00Z + + atom_1.0.feed.entry[0].title + + + + + http://example.com/blog/entry1 + + atom_1.0.feed.entry[0].author.name + http://example.com + author0@example.com + + + atom_1.0.feed.entry[0].contributor.name + http://example.com + author1@example.com + + 2000-01-01T00:00:00Z + 2000-01-01T01:00:00Z + atom_1.0.feed.entry[0].summary + atom_1.0.feed.entry[0].content[0] + rometest + atom_1.0.feed.entry[0].rights + + + atom_1.0.feed.entry[1].title + + + + http://example.com/blog/entry2 + + atom_1.0.feed.entry[1].author.name + http://example.com + author0@example.com + + + atom_1.0.feed.entry[1].contributor.name + http://example.com + author1@example.com + + 2000-02-01T00:00:00Z + 2000-02-01T01:00:00Z + atom_1.0.feed.entry[1].summary + atom_1.0.feed.entry[1].content[0] + rometest + + diff --git a/src/test/resources/atom_1.0_b.xml b/src/test/resources/atom_1.0_b.xml new file mode 100644 index 0000000..cbbc080 --- /dev/null +++ b/src/test/resources/atom_1.0_b.xml @@ -0,0 +1,134 @@ + + + xml:base support tests + All alternate links should point to <code>http://example.org/tests/base/result.html</code>; all links in content should point where their label says. + + + tag:plasmasturm.org,2005:Atom-Tests:xml-base + 2006-01-17T12:35:16+01:00 + + + 1: Alternate link: Absolute URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test1 + 2006-01-17T12:35:16+01:00 + + + + 2: Alternate link: Host-relative absolute URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test2 + 2006-01-17T12:35:15+01:00 + + + + 3: Alternate link: Relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test3 + 2006-01-17T12:35:14+01:00 + + + + 4: Alternate link: Relative URL with parent directory component + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test4 + 2006-01-17T12:35:13+01:00 + + + + 5: Content: Absolute URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test5 + <a href="http://example.org/tests/base/result.html">http://example.org/tests/base/result.html</a> + 2006-01-17T12:35:12+01:00 + + + + 6: Content: Host-relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test6 + <a href="/tests/base/result.html">http://example.org/tests/base/result.html</a> + 2006-01-17T12:35:11+01:00 + + + + 7: Content: Relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test7 + <a href="base/result.html">http://example.org/tests/base/result.html</a> + 2006-01-17T12:35:10+01:00 + + + + 8: Content: Relative URL with parent directory component + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test8 + <a href="../tests/base/result.html">http://example.org/tests/base/result.html</a> + 2006-01-17T12:35:9+01:00 + + + + 9: Content, <code>&lt;entry></code> has base: Absolute URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test9 + <a href="http://example.org/tests/entrybase/result.html">http://example.org/tests/entrybase/result.html</a> + 2006-01-17T12:35:8+01:00 + + + + 10: Content, <code>&lt;entry></code> has base: Host-relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test10 + <a href="/tests/entrybase/result.html">http://example.org/tests/entrybase/result.html</a> + 2006-01-17T12:35:7+01:00 + + + + 11: Content, <code>&lt;entry></code> has base: Relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test11 + <a href="result.html">http://example.org/tests/entrybase/result.html</a> + 2006-01-17T12:35:6+01:00 + + + + 12: Content, <code>&lt;entry></code> has base: Relative URL with parent directory component + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test12 + <a href="../entrybase/result.html">http://example.org/tests/entrybase/result.html</a> + 2006-01-17T12:35:5+01:00 + + + + 13: Content, <code>&lt;content></code> has base: Absolute URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test13 + <a href="http://example.org/tests/contentbase/result.html">http://example.org/tests/contentbase/result.html</a> + 2006-01-17T12:35:4+01:00 + + + + 14: Content, <code>&lt;content></code> has base: Host-relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test14 + <a href="/tests/contentbase/result.html">http://example.org/tests/contentbase/result.html</a> + 2006-01-17T12:35:3+01:00 + + + + 15: Content, <code>&lt;content></code> has base: Relative URL + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test15 + <a href="result.html">http://example.org/tests/contentbase/result.html</a> + 2006-01-17T12:35:2+01:00 + + + + 16: Content, <code>&lt;content></code> has base: Relative URL with parent directory component + + tag:plasmasturm.org,2005:Atom-Tests:xml-base:Test16 + <a href="../contentbase/result.html">http://example.org/tests/contentbase/result.html</a> + 2006-01-17T12:35:1+01:00 + + + diff --git a/src/test/resources/atom_1.0_bray.xml b/src/test/resources/atom_1.0_bray.xml new file mode 100644 index 0000000..de72ea3 --- /dev/null +++ b/src/test/resources/atom_1.0_bray.xml @@ -0,0 +1,35 @@ + + + + Tim Bray style feed + URIs must be determined from xml:base + + + + + http://www.example.com/blog + 2006-11-04T09:11:03-08:00 + John Doe + + + + Entry1 + http://www.example.com/blog/2006-11-05/entry1 + 2006-11-05T12:00:00-08:00 + 2006-11-06T09:09:13-08:00 +
Summary1
+
Content1
+
+ + + + Entry2 + http://www.example.com/blog/2006-11-02/entry2 + 2006-11-01T12:00:00-08:00 + 2006-11-02T09:09:12-08:00 +
Summary2
+
Content2
+
+ +
diff --git a/src/test/resources/atom_1.0_prefix.xml b/src/test/resources/atom_1.0_prefix.xml new file mode 100644 index 0000000..a4ed106 --- /dev/null +++ b/src/test/resources/atom_1.0_prefix.xml @@ -0,0 +1,7 @@ + + + 1 + + + + diff --git a/src/test/resources/atom_1.0_ruby.xml b/src/test/resources/atom_1.0_ruby.xml new file mode 100644 index 0000000..1722fa3 --- /dev/null +++ b/src/test/resources/atom_1.0_ruby.xml @@ -0,0 +1,37 @@ + + + + Sam Ruby style + Base URI must be determined from self link + + + + + http://www.example.com/blog + + John Doe + john.doe@example.com + . + + 2006-11-04T22:09:53-05:00 + + + + tag:example.com,2004:2429 + Bloggy-blog +
Summary1
+
Content1
+ 2006-11-04T18:23:33-05:00 +
+ + + + tag:example.com,2004:2430 + Froggy-frog +
Summary1
+
Content1
+ 2006-11-04T18:23:30-05:00 +
+ +
+ diff --git a/src/test/resources/jira_issue1.xml b/src/test/resources/jira_issue1.xml new file mode 100644 index 0000000..05fc910 --- /dev/null +++ b/src/test/resources/jira_issue1.xml @@ -0,0 +1,275 @@ + + + + Periodico Diario Horizonte - Noticias para Hispanos en Connecticut, Hispanic newspaper,spanish newspaper:Deportes + + + es-ES + + Periodico Diario Horizonte - Noticias para Hispanos en Connecticut, Hispanic newspaper,spanish newspaper + http://www.diariohorizonte.com/images/pleca_01.jpg + http://www.diariohorizonte.com + 100 + 60 + + Club Hemingway presenta campeón y subcampeón de Pádel + + + + + DECLARACION DE LA COMISION ELECTORAL A LA PRENSA. + + + + + Stamford pierde de Westhill por lazos de tenis + + + + Mutus deberá pagar $23 millones por romper contrato de fútbol + + + + Ciro Pérez empata serie final torneo de basket Superior de SC + + + + + Águilas rechazan protesta de los Leones + + + + 116-91. Udrih ayudó a los Kings a romper una racha perdedora + + + + + Independiente, el quinto clasificado de Argentina a la Copa Libertadores 2011 + + + + + Ciro Pérez gana en el inicio serie final torneo basket superior de SC + + + + + El dominicano Peña se va con los Cachorros por un año y 10 millones de dólares + + + + + Los Dodgers llegan a acuerdos con Padilla y Gwyn Jr. + + + + + Colón y Luna lideran Águilas al triunfo 3-2 sobre los Leones + + + + + El Atlético Nacional destituye al entrenador y prepara poda de extranjeros + + + + + Ciro Pérez y Buitres inician este miércoles serie final basket superior de SC + + + + + Choque de estrellas en un partido entre República Dominicana y Puerto Rico + + + + + La NBA rescata a los Hornets para que no pierdan valor ni cambien de sede + + + + + Sólo Messi puede privar a España del Balón de Oro que buscan Iniesta y Xavi + + + + + Muerte entrenador boxeo Pastor Ralph consterna comunidad deportiva internacional + + + + + Medias Rojas dan otro giro en negociaciones con González + + + + + Los Leones se afirman en la clasificación tras vencer a Caribes + + + + + Estrellas, Gigantes y Toros ganan en el béisbol dominicano + + + + + Berkman llega a un acuerdo con los Cardenales + + + + + Los Eagles se quejan de que su mariscal Vick recibe muchos golpes + + + + + Jeter y los Yankees llegan a un acuerdo para firmar contrato + + + + + Los Toros siguen firmes en la cima de la pelota dominicana + + + + + Los Navegantes del Magallanes nuevo líder al caer las Águilas en Venezuela + + + + + 104-92. Garnett y Rondo dieron a los Celtics el sexto triunfo consecutivo + + + + + 92-100. Stoudemire mantuvo ganadores a los Knicks + + + + + 113-80. Los Lakers cortan la racha de derrotas y arrollan a los Kings + + + + + Cinco clubes colombianos de fútbol investigados por vínculos por narcotráfico + + + + + James ganó a los Cavaliers y reivindicó su marcha como un acierto + + + + + 101-107. Richardson, Hill y Nash fueron la combinación ganadora + + + + + "King" James hizo historia y silenció a los críticos en regreso a Cleveland + + + + + Tiger Woods a punto de recuperar primer lugar mundialmente + + + + Ramírez sale del contrato para obtener un mejor sueldo con Medias Blancas + + + + + LeBron James regresa a Cleveland con problemas en el avión de los Heat + + + + + Agüero jura la Constitución Española y obtiene la doble nacionalidad + + + + + \ No newline at end of file diff --git a/src/test/resources/rome.properties b/src/test/resources/rome.properties new file mode 100644 index 0000000..da7342f --- /dev/null +++ b/src/test/resources/rome.properties @@ -0,0 +1 @@ +datetime.extra.masks=HH:mm yyyy/MM/dd diff --git a/src/test/resources/rss_0.9.xml b/src/test/resources/rss_0.9.xml new file mode 100644 index 0000000..4bf3185 --- /dev/null +++ b/src/test/resources/rss_0.9.xml @@ -0,0 +1,28 @@ + + + + rss_0.9.channel.title + rss_0.9.channel.link + rss_0.9.channel.description + + + rss_0.9.image.title + rss_0.9.image.url + rss_0.9.image.link + + + rss_0.9.textinput.title + rss_0.9.textinput.description + rss_0.9.textinput.name + rss_0.9.textinput.link + + + rss_0.9.item[0].title + rss_0.9.item[0].link + + + rss_0.9.item[1].title + rss_0.9.item[1].link + + \ No newline at end of file diff --git a/src/test/resources/rss_0.91N.xml b/src/test/resources/rss_0.91N.xml new file mode 100644 index 0000000..8770175 --- /dev/null +++ b/src/test/resources/rss_0.91N.xml @@ -0,0 +1,77 @@ + + + + + + rss_0.91N.channel.title + rss_0.91N.channel.link + rss_0.91N.channel.description + rss_0.91N.channel.language + rss_0.91N.channel.rating + rss_0.91N.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.91N.channel.docs + rss_0.91N.channel.managingEditor + rss_0.91N.channel.webMaster + + rss_0.91N.channel.image.title + rss_0.91N.channel.image.url + rss_0.91N.channel.image.link + 100 + 200 + rss_0.91N.channel.image.description + + + rss_0.91N.channel.item[0].title + rss_0.91N.channel.item[0].description + rss_0.91N.channel.item[0].link + + + rss_0.91N.channel.item[1].title + rss_0.91N.channel.item[1].description + rss_0.91N.channel.item[1].link + + + rss_0.91N.channel.textinput.title + rss_0.91N.channel.textinput.description + rss_0.91N.channel.textinput.name + rss_0.91N.channel.textinput.link + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + diff --git a/src/test/resources/rss_0.91U.xml b/src/test/resources/rss_0.91U.xml new file mode 100644 index 0000000..713b7d1 --- /dev/null +++ b/src/test/resources/rss_0.91U.xml @@ -0,0 +1,84 @@ + + + + + rss_0.91U.channel.title + rss_0.91U.channel.link + rss_0.91U.channel.description + rss_0.91U.channel.language + rss_0.91U.channel.rating + rss_0.91U.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.91U.channel.docs + rss_0.91U.channel.managingEditor + rss_0.91U.channel.webMaster + + rss_0.91U.channel.image.title + rss_0.91U.channel.image.url + rss_0.91U.channel.image.link + 100 + 200 + rss_0.91U.channel.image.description + + + rss_0.91U.channel.item[0].title + rss_0.91U.channel.item[0].description + rss_0.91U.channel.item[0].link + + + rss_0.91U.channel.item[1].title + rss_0.91U.channel.item[1].description + rss_0.91U.channel.item[1].link + + + rss_0.91U.channel.textInput.title + rss_0.91U.channel.textInput.description + rss_0.91U.channel.textInput.name + rss_0.91U.channel.textInput.link + + + 1 + + 2 + 3 + + + 4 + + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + 24 + + + Monday + Tuesday + Wednesday + + + Thursday + + Friday + Saturday + Sunday + + + + + diff --git a/src/test/resources/rss_0.92.xml b/src/test/resources/rss_0.92.xml new file mode 100644 index 0000000..1e33929 --- /dev/null +++ b/src/test/resources/rss_0.92.xml @@ -0,0 +1,90 @@ + + + + rss_0.92.channel.title + rss_0.92.channel.link + rss_0.92.channel.description + rss_0.92.channel.language + rss_0.92.channel.rating + rss_0.92.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.92.channel.docs + rss_0.92.channel.managingEditor + rss_0.92.channel.webMaster + + + rss_0.92.channel.image.title + rss_0.92.channel.image.url + rss_0.92.channel.image.link + 100 + 200 + rss_0.92.channel.image.description + + + rss_0.92.channel.item[0].title + rss_0.92.channel.item[0].description + rss_0.92.channel.item[0].link + rss_0.92.channel.item[0].source + + rss_0.92.channel.item[0].category[0] + rss_0.92.channel.item[0].category[1] + + + rss_0.92.channel.item[1].title + rss_0.92.channel.item[1].description + rss_0.92.channel.item[1].link + rss_0.92.channel.item[1].source + + + rss_0.92.channel.item[1].category[0] + rss_0.92.channel.item[1].category[1] + + + + rss_0.92.channel.textInput.title + rss_0.92.channel.textInput.description + rss_0.92.channel.textInput.name + rss_0.92.channel.textInput.link + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + 24 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + diff --git a/src/test/resources/rss_0.92_alt.xml b/src/test/resources/rss_0.92_alt.xml new file mode 100644 index 0000000..ec0062c --- /dev/null +++ b/src/test/resources/rss_0.92_alt.xml @@ -0,0 +1,92 @@ + + + + + rss_0.92.channel.title + rss_0.92.channel.link + rss_0.92.channel.description + rss_0.92.channel.language + rss_0.92.channel.rating + rss_0.92.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.92.channel.docs + rss_0.92.channel.managingEditor + rss_0.92.channel.webMaster + + + rss_0.92.channel.image.title + rss_0.92.channel.image.url + rss_0.92.channel.image.link + 100 + 200 + rss_0.92.channel.image.description + + + rss_0.92.channel.item[0].title + rss_0.92.channel.item[0].description + rss_0.92.channel.item[0].link + rss_0.92.channel.item[0].source + + + rss_0.92.channel.item[0].category[0] + rss_0.92.channel.item[0].category[1] + + + rss_0.92.channel.item[1].title + rss_0.92.channel.item[1].description + rss_0.92.channel.item[1].link + rss_0.92.channel.item[1].source + + + rss_0.92.channel.item[1].category[0] + rss_0.92.channel.item[1].category[1] + + + + rss_0.92.channel.textInput.title + rss_0.92.channel.textInput.description + rss_0.92.channel.textInput.name + rss_0.92.channel.textInput.link + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + 24 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + diff --git a/src/test/resources/rss_0.93.xml b/src/test/resources/rss_0.93.xml new file mode 100644 index 0000000..ab8f92c --- /dev/null +++ b/src/test/resources/rss_0.93.xml @@ -0,0 +1,96 @@ + + + + rss_0.93.channel.title + rss_0.93.channel.link + rss_0.93.channel.description + rss_0.93.channel.language + rss_0.93.channel.rating + rss_0.93.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.93.channel.docs + rss_0.93.channel.managingEditor + rss_0.93.channel.webMaster + + + rss_0.93.channel.image.title + rss_0.93.channel.image.url + rss_0.93.channel.image.link + 100 + 200 + rss_0.93.channel.image.description + + + rss_0.93.channel.item[0].title + rss_0.93.channel.item[0].description + rss_0.93.channel.item[0].link + rss_0.93.channel.item[0].source + + + rss_0.93.channel.item[0].category[0] + rss_0.93.channel.item[0].category[1] + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + + + rss_0.93.channel.item[1].title + rss_0.93.channel.item[1].description + rss_0.93.channel.item[1].link + rss_0.93.channel.item[1].source + + + rss_0.93.channel.item[1].category[0] + rss_0.93.channel.item[1].category[1] + Tue, 02 Jan 2001 00:00:00 GMT + Tue, 02 Jan 2001 01:00:00 GMT + + + rss_0.93.channel.textInput.title + rss_0.93.channel.textInput.description + rss_0.93.channel.textInput.name + rss_0.93.channel.textInput.link + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + 24 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + \ No newline at end of file diff --git a/src/test/resources/rss_0.94.xml b/src/test/resources/rss_0.94.xml new file mode 100644 index 0000000..35f968f --- /dev/null +++ b/src/test/resources/rss_0.94.xml @@ -0,0 +1,108 @@ + + + + rss_0.94.channel.title + rss_0.94.channel.link + rss_0.94.channel.description + rss_0.94.channel.language + rss_0.94.channel.rating + rss_0.94.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.94.channel.docs + rss_0.94.channel.managingEditor + rss_0.94.channel.webMaster + + rss_0.94.channel.category[0] + rss_0.94.channel.category[1] + rss_0.94.channel.generator + 100 + + + rss_0.94.channel.image.title + rss_0.94.channel.image.url + rss_0.94.channel.image.link + 100 + 200 + rss_0.94.channel.image.description + + + rss_0.94.channel.item[0].title + rss_0.94.channel.item[0].description + rss_0.94.channel.item[0].link + rss_0.94.channel.item[0].source + + + rss_0.94.channel.item[0].category[0] + rss_0.94.channel.item[0].category[1] + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_0.94.channel.item[0].author + rss_0.94.channel.item[0].comments + rss_0.94.channel.item[0].guid + + + rss_0.94.channel.item[1].title + rss_0.94.channel.item[1].description + rss_0.94.channel.item[1].link + rss_0.94.channel.item[1].source + + + rss_0.94.channel.item[1].category[0] + rss_0.94.channel.item[1].category[1] + Mon, 02 Jan 2001 00:00:00 GMT + Mon, 02 Jan 2001 01:00:00 GMT + rss_0.94.channel.item[1].author + rss_0.94.channel.item[1].comments + rss_0.94.channel.item[1].guid + + + + rss_0.94.channel.textInput.title + rss_0.94.channel.textInput.description + rss_0.94.channel.textInput.name + rss_0.94.channel.textInput.link + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + 24 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + \ No newline at end of file diff --git a/src/test/resources/rss_1.0.xml b/src/test/resources/rss_1.0.xml new file mode 100644 index 0000000..6498cb5 --- /dev/null +++ b/src/test/resources/rss_1.0.xml @@ -0,0 +1,51 @@ + + + + + + test + rss_1.0.channel.title + rss_1.0.channel.link + rss_1.0.channel.description + + + + + + + + + + + + + rss_1.0.image.title + rss_1.0.image.url + rss_1.0.image.link + + + + rss_1.0.textinput.title + rss_1.0.textinput.description + rss_1.0.textinput.name + rss_1.0.textinput.link + + + rss_1.0.item[0].title + rss_1.0.item[0].link + rss_1.0.item[0].description + test + rss_1.0.item[0].content + + + rss_1.0.item[1].title + rss_1.0.item[1].link + rss_1.0.item[1].description + test + rss_1.0.item[1].content + + + diff --git a/src/test/resources/rss_1.0_DC_Sy.xml b/src/test/resources/rss_1.0_DC_Sy.xml new file mode 100644 index 0000000..dcf968b --- /dev/null +++ b/src/test/resources/rss_1.0_DC_Sy.xml @@ -0,0 +1,118 @@ + + + + + + rss_1.0.channel.title + rss_1.0.channel.link + rss_1.0.channel.description + + + + + + + + + + + rss_1.0.channel.dc:title + rss_1.0.channel.dc:creator + + + + rss_1.0.channel.dc:subject[0] + + + + + + rss_1.0.channel.dc:subject[1] + + + rss_1.0.channel.dc:description + rss_1.0.channel.dc:publisher + rss_1.0.channel.dc:contributor[0] + rss_1.0.channel.dc:contributor[1] + 2001-01-01T00:00+00:00 + rss_1.0.channel.dc:type + rss_1.0.channel.dc:format + rss_1.0.channel.dc:identifier + rss_1.0.channel.dc:source + rss_1.0.channel.dc:language + rss_1.0.channel.dc:relation + rss_1.0.channel.dc:coverage + rss_1.0.channel.dc:rights + + hourly + 100 + 2001-01-01T01:00+00:00 + + + + + rss_1.0.image.title + rss_1.0.image.url + rss_1.0.image.link + + + + rss_1.0.textinput.title + rss_1.0.textinput.description + rss_1.0.textinput.name + rss_1.0.textinput.link + + + rss_1.0.item[0].title + rss_1.0.item[0].link + rss_1.0.item[0].description + + rss_1.0.item[0].dc:title + rss_1.0.item[0].dc:creator + rss_1.0.item[0].dc:subject[0] + rss_1.0.item[0].dc:subject[1] + rss_1.0.item[0].dc:description + rss_1.0.item[0].dc:publisher + rss_1.0.item[0].dc:contributor[0] + rss_1.0.item[0].dc:contributor[1] + 2001-01-01T00:00+00:00 + rss_1.0.item[0].dc:type + rss_1.0.item[0].dc:format + rss_1.0.item[0].dc:identifier + rss_1.0.item[0].dc:source + rss_1.0.item[0].dc:language + rss_1.0.item[0].dc:relation + rss_1.0.item[0].dc:coverage + rss_1.0.item[0].dc:rights + rss_1.0.item[0].content + + + rss_1.0.item[1].title + rss_1.0.item[1].link + rss_1.0.item[1].description + rss_1.0.item[1].dc:title + rss_1.0.item[1].dc:creator + rss_1.0.item[1].dc:subject[0] + rss_1.0.item[1].dc:subject[1] + rss_1.0.item[1].dc:description + rss_1.0.item[1].dc:publisher + rss_1.0.item[1].dc:contributor[0] + rss_1.0.item[1].dc:contributor[1] + 2001-01-01T00:00+00:00 + rss_1.0.item[1].dc:type + rss_1.0.item[1].dc:format + rss_1.0.item[1].dc:identifier + rss_1.0.item[1].dc:source + rss_1.0.item[1].dc:language + rss_1.0.item[1].dc:relation + rss_1.0.item[1].dc:coverage + rss_1.0.item[1].dc:rights + rss_1.0.item[1].content + + + diff --git a/src/test/resources/rss_1.0_DC_multi.xml b/src/test/resources/rss_1.0_DC_multi.xml new file mode 100644 index 0000000..965410c --- /dev/null +++ b/src/test/resources/rss_1.0_DC_multi.xml @@ -0,0 +1,157 @@ + + + + + + rss_1.0.channel.title + rss_1.0.channel.link + rss_1.0.channel.description + + + + + + + + + + + rss_1.0.channel.dc:title[0] + rss_1.0.channel.dc:title[1] + rss_1.0.channel.dc:creator[0] + rss_1.0.channel.dc:creator[1] + + + + rss_1.0.channel.dc:subject[0] + + + + + + rss_1.0.channel.dc:subject[1] + + + rss_1.0.channel.dc:description[0] + rss_1.0.channel.dc:description[1] + rss_1.0.channel.dc:publisher[0] + rss_1.0.channel.dc:publisher[1] + rss_1.0.channel.dc:contributor[0] + rss_1.0.channel.dc:contributor[1] + 2001-01-01T00:00+00:00 + 2001-01-01T00:00+00:00 + rss_1.0.channel.dc:type[0] + rss_1.0.channel.dc:type[1] + rss_1.0.channel.dc:format[0] + rss_1.0.channel.dc:format[1] + rss_1.0.channel.dc:identifier[0] + rss_1.0.channel.dc:identifier[1] + rss_1.0.channel.dc:source[0] + rss_1.0.channel.dc:source[1] + rss_1.0.channel.dc:language[0] + rss_1.0.channel.dc:language[1] + rss_1.0.channel.dc:relation[0] + rss_1.0.channel.dc:relation[1] + rss_1.0.channel.dc:coverage[0] + rss_1.0.channel.dc:coverage[1] + rss_1.0.channel.dc:rights[0] + rss_1.0.channel.dc:rights[1] + + hourly + 100 + 2001-01-01T01:00+00:00 + + + + + rss_1.0.image.title + rss_1.0.image.url + rss_1.0.image.link + + + + rss_1.0.textinput.title + rss_1.0.textinput.description + rss_1.0.textinput.name + rss_1.0.textinput.link + + + rss_1.0.item[0].title + rss_1.0.item[0].link + rss_1.0.item[0].description + + rss_1.0.item[0].dc:title[0] + rss_1.0.item[0].dc:title[1] + rss_1.0.item[0].dc:creator[0] + rss_1.0.item[0].dc:creator[1] + rss_1.0.item[0].dc:subject[0] + rss_1.0.item[0].dc:subject[1] + rss_1.0.item[0].dc:description[0] + rss_1.0.item[0].dc:description[1] + rss_1.0.item[0].dc:publisher[0] + rss_1.0.item[0].dc:publisher[1] + rss_1.0.item[0].dc:contributor[0] + rss_1.0.item[0].dc:contributor[1] + 2001-01-01T00:00+00:00 + 2001-01-01T00:00+00:00 + rss_1.0.item[0].dc:type[0] + rss_1.0.item[0].dc:type[1] + rss_1.0.item[0].dc:format[0] + rss_1.0.item[0].dc:format[1] + rss_1.0.item[0].dc:identifier[0] + rss_1.0.item[0].dc:identifier[1] + rss_1.0.item[0].dc:source[0] + rss_1.0.item[0].dc:source[1] + rss_1.0.item[0].dc:language[0] + rss_1.0.item[0].dc:language[1] + rss_1.0.item[0].dc:relation[0] + rss_1.0.item[0].dc:relation[1] + rss_1.0.item[0].dc:coverage[0] + rss_1.0.item[0].dc:coverage[1] + rss_1.0.item[0].dc:rights[0] + rss_1.0.item[0].dc:rights[1] + rss_1.0.item[0].content + + + rss_1.0.item[1].title + rss_1.0.item[1].link + rss_1.0.item[1].description + rss_1.0.item[1].dc:title[0] + rss_1.0.item[1].dc:title[1] + rss_1.0.item[1].dc:creator[0] + rss_1.0.item[1].dc:creator[1] + rss_1.0.item[1].dc:subject[0] + rss_1.0.item[1].dc:subject[1] + rss_1.0.item[1].dc:description[0] + rss_1.0.item[1].dc:description[1] + rss_1.0.item[1].dc:publisher[0] + rss_1.0.item[1].dc:publisher[1] + rss_1.0.item[1].dc:contributor[0] + rss_1.0.item[1].dc:contributor[1] + 2001-01-01T00:00+00:00 + 2001-01-01T00:00+00:00 + rss_1.0.item[1].dc:type[0] + rss_1.0.item[1].dc:type[1] + rss_1.0.item[1].dc:format[0] + rss_1.0.item[1].dc:format[1] + rss_1.0.item[1].dc:identifier[0] + rss_1.0.item[1].dc:identifier[1] + rss_1.0.item[1].dc:source[0] + rss_1.0.item[1].dc:source[1] + rss_1.0.item[1].dc:language[0] + rss_1.0.item[1].dc:language[1] + rss_1.0.item[1].dc:relation[0] + rss_1.0.item[1].dc:relation[1] + rss_1.0.item[1].dc:coverage[0] + rss_1.0.item[1].dc:coverage[1] + rss_1.0.item[1].dc:rights[0] + rss_1.0.item[1].dc:rights[1] + rss_1.0.item[1].content + + + diff --git a/src/test/resources/rss_2.0.xml b/src/test/resources/rss_2.0.xml new file mode 100644 index 0000000..e033320 --- /dev/null +++ b/src/test/resources/rss_2.0.xml @@ -0,0 +1,117 @@ + + + + test + rss_2.0.channel.title + rss_2.0.channel.link + rss_2.0.channel.description + rss_2.0.channel.language + rss_2.0.channel.rating + rss_2.0.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + + Mon, 01 Jan 2001 01:00:00 GMT + rss_2.0.channel.docs + rss_2.0.channel.managingEditor + rss_2.0.channel.webMaster + rss_2.0.channel.category[0] + rss_2.0.channel.category[1] + rss_2.0.channel.generator + 100 + + + rss_2.0.channel.image.title + rss_2.0.channel.image.url + rss_2.0.channel.image.link + 100 + 200 + rss_2.0.channel.image.description + + + + rss_2.0.channel.item[0].title + rss_2.0.channel.item[0].description + rss_2.0.channel.item[0].link + rss_2.0.channel.item[0].source + + + rss_2.0.channel.item[0].category[0] + rss_2.0.channel.item[0].category[1] + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_2.0.channel.item[0].author + rss_2.0.channel.item[0].comments + rss_2.0.channel.item[0].guid + test + rss_2.0.channel.item[0].content + + + rss_2.0.channel.item[1].title + rss_2.0.channel.item[1].description + rss_2.0.channel.item[1].link + rss_2.0.channel.item[1].source + + + rss_2.0.channel.item[1].category[0] + rss_2.0.channel.item[1].category[1] + Mon, 02 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_2.0.channel.item[1].author + rss_2.0.channel.item[1].comments + rss_2.0.channel.item[1].guid + test + rss_2.0.channel.item[1].content + + + + rss_2.0.channel.textInput.title + rss_2.0.channel.textInput.description + rss_2.0.channel.textInput.name + rss_2.0.channel.textInput.link + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + +