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 @@
+
+
+ * 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;i
+ * 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:
+ *
+ *
+ * @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;i
+ * 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:
+ *
+ *
+ * @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
+ * 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 uses the CloneableBean, EqualsBean and ToStringBean classes in a delegation pattern.
+ *
+ *
+ * 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:
+ *
+ *
+ * @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
+ * @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
+ *
+ */
+ 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;i
+ * @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
+ * @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
+ * 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.
+ *
+ * @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.
+ *
+ * @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
+ * @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.
+ *
+ * @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.
+ * The first column in a line is position 1.
+ * 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.
+ *
+ * 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, ''
+ private static String getXMLGuessEncoding(BufferedInputStream is) throws IOException {
+ String encoding = null;
+ int[] bytes = new int[4];
+ is.mark(4);
+ bytes[0] = is.read();
+ bytes[1] = is.read();
+ bytes[2] = is.read();
+ bytes[3] = is.read();
+ is.reset();
+
+ if (bytes[0] == 0x00 && bytes[1] == 0x3C && bytes[2] == 0x00 && bytes[3] == 0x3F) {
+ encoding = UTF_16BE;
+ }
+ else
+ if (bytes[0] == 0x3C && bytes[1] == 0x00 && bytes[2] == 0x3F && bytes[3] == 0x00) {
+ encoding = UTF_16LE;
+ }
+ else
+ if (bytes[0] == 0x3C && bytes[1] == 0x3F && bytes[2] == 0x78 && bytes[3] == 0x6D) {
+ encoding = UTF_8;
+ }
+ return encoding;
+ }
+
+
+ private static final Pattern ENCODING_PATTERN =
+ Pattern.compile("<\\?xml.*encoding[\\s]*=[\\s]*((?:\".[^\"]*\")|(?:'.[^']*'))", Pattern.MULTILINE);
+
+ // returns the encoding declared in the , 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
+ *
+ * @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
+ * @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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * 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
+ * :TODO: Add Integer, Float, and Double methods as needed.
+ *
+ * @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
+ * 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
+ *
+ *
+ * @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.
+ *
+ * @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
+//
+//
+ * @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
+ * public class Foo implements Cloneable {
+ * private CloneableBean _cloneableBean;
+ *
+ * public Foo() {
+ * _cloneableBean = new CloneableBean(this);
+ * }
+ *
+ * public Object clone() throws CloneNotSupportedException {
+ * return _cloneableBean.beanClone();
+ * }
+ *
+ * }
+ *
+ *
+ * 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();
+ * }
+ *
+ * }
+ *
+ * ObjectBean programming conventions
+ *
+ * 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");
+ * }
+ *
+ * }
+ *
+ *
+ * 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.
+ *
+ *
+ *
+ * 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.
+ *