diff --git a/.gitignore b/.gitignore index 5966e2d..6ef042a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -/.checkstyle -/.classpath -/.project /.settings +/.project /target \ No newline at end of file diff --git a/LICENSE b/LICENSE index d4ba69e..ad410e1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,16 +1,201 @@ -Copyright 2004 Sun Microsystems, Inc. -Copyright 2011 The ROME Team +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -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 + 1. Definitions. - http://www.apache.org/licenses/LICENSE-2.0 + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -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. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. \ No newline at end of file diff --git a/README.md b/README.md index b1c6816..716e0ab 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,4 @@ -# ROME +rome-parent +=========== -ROME is a set of RSS and Atom Utilities for Java. It makes it easy to work in Java with most syndication formats: RSS 0.90, RSS 0.91 Netscape, -RSS 0.91 Userland, RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, RSS 2.0, Atom 0.3, Atom 1.0 - -More Information: http://rometools.github.io/rome/ - -## Changelog - -### 1.5.1 - -- solved an [XML bomb](https://en.wikipedia.org/wiki/Billion_laughs) vulnerability - -Important note: due to the security fix ROME now forbids all Doctype declarations by default. This will break compatibility with RSS 0.91 Netscape -because it requires a Doctype declaration. When you experience problems you have to activate the property **allowDoctypes** on the SyndFeedInput object. You -should only use this possibility when the feeds that you process are absolutely trustful. - -### 1.5.0 - -- many (untracked) enhancements -- code cleanup -- renamed packages (was required to be able to push to Maven Central after years again) -- updated sourcecode to Java 1.6 - -### Prior to 1.5.0 - -- see [http://rometools.github.io/rome/ROMEReleases](http://rometools.github.io/rome/ROMEReleases) \ No newline at end of file +Parent for all ROME projects diff --git a/conf/checkstyle/checkstyle.xml b/conf/checkstyle/checkstyle.xml new file mode 100644 index 0000000..2a344a7 --- /dev/null +++ b/conf/checkstyle/checkstyle.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/eclipse/cleanup.xml b/conf/eclipse/cleanup.xml new file mode 100644 index 0000000..feca0d5 --- /dev/null +++ b/conf/eclipse/cleanup.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/eclipse/formatter.xml b/conf/eclipse/formatter.xml new file mode 100644 index 0000000..f3d99da --- /dev/null +++ b/conf/eclipse/formatter.xml @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index de35703..f9f21cd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,130 +4,133 @@ 4.0.0 - com.rometools - rome-parent - 1.6.0-SNAPSHOT + org.sonatype.oss + oss-parent + 9 - rome + com.rometools + rome-parent 1.6.0-SNAPSHOT - jar + pom - rome + + rome + rome-certiorem + rome-certiorem-webapp + rome-fetcher + rome-modules + rome-opml + rome-propono + rome-utils + - All Roads Lead to ROME. ROME is a set of Atom/RSS Java utilities that make it - easy to work in Java with most syndication formats. Today it accepts all flavors of RSS - (0.90, 0.91, 0.92, 0.93, 0.94, 1.0 and 2.0), Atom 0.3 and Atom 1.0 feeds. Rome includes - a set of parsers and generators for the various flavors of feeds, as well as converters - to convert from one format to another. The parsers can give you back Java objects that - are either specific for the format you want to work with, or a generic normalized - SyndFeed object that lets you work on with the data without bothering about the - underlying format. - + rome-parent - http://rometools.github.io/rome/ + Parent for all ROME projects + + http://rometools.github.io/rome-parent/ + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + - scm:git:ssh://github.com/rometools/rome.git - scm:git:ssh://git@github.com/rometools/rome.git - https://github.com/rometools/rome + scm:git:ssh://github.com/rometools/rome-parent.git + scm:git:ssh://git@github.com/rometools/rome-parent.git + https://github.com/rometools/rome-parent - - Alejandro Abdelnur - http://blog.sun.com/roller/page/tucu - 0 - - - Dave Johnson - http://rollerweblogger.org/roller - -5 - - - Elaine Chien - 0 - - - Patrick Chanezon - http://www.chanezon.com/pat/weblog - -9 - Patrick Gotthard + patrick@patrick-gotthard.de http://www.patrick-gotthard.de +1 - - Robert Cooper - kebernet@gmail.com - http://www.screaming-penguin.com - -4 - - - farrukhnajmi - Farrukh Najmi - http://www.wellfleetsoftware.com/farrukh - - - imk - Martin Kurz - Europe/Berlin - - - - sonatype-nexus-snapshots - https://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - - + + UTF-8 + UTF-8 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.6 + 1.6 + + + + org.apache.maven.plugins + maven-site-plugin + 3.3 + + + org.apache.maven.plugins + maven-scm-publish-plugin + 1.0 + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + [1.0.0,) + + enforce + + + + + + + + + + + + org.apache.felix + maven-bundle-plugin + 3.0.1 + + + bundle + package + + bundle + + + + + + + + + org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - true - true - - - - - - org.apache.maven.plugins - maven-site-plugin - - - org.apache.maven.doxia - doxia-module-markdown - 1.5 - - - org.apache.maven.doxia - doxia-module-confluence - 1.5 - - - - - org.apache.maven.plugins - maven-scm-publish-plugin - - gh-pages - ${project.scm.developerConnection} - ${project.build.directory}/site - + maven-project-info-reports-plugin + 2.7 org.apache.felix @@ -159,32 +162,96 @@ - + - - - com.rometools - rome-utils - 1.6.0-SNAPSHOT - - - org.jdom - jdom2 - - - org.slf4j - slf4j-api - - - ch.qos.logback - logback-classic - test - - - junit - junit - test - - + + + + + org.jdom + jdom2 + 2.0.5 + + + + org.slf4j + slf4j-api + 1.7.10 + + + ch.qos.logback + logback-classic + 1.1.2 + + + + junit + junit + 4.12 + + + + org.hamcrest + hamcrest-library + 1.3 + + + + javax.servlet + servlet-api + 2.5 + + + javax.servlet.jsp + jsp-api + 2.1 + + + javax.persistence + persistence-api + 1.0.2 + + + + com.google.inject.extensions + guice-servlet + 2.0 + + + + commons-httpclient + commons-httpclient + 3.1 + + + org.apache.commons + commons-lang3 + 3.3.2 + + + commons-beanutils + commons-beanutils + 1.9.2 + + + + jetty + jetty + 4.2.12 + + + + org.apache.xmlrpc + xmlrpc-client + 3.1.3 + + + + net.oauth.core + oauth + 20100527 + + + diff --git a/rome-certiorem-webapp/.gitignore b/rome-certiorem-webapp/.gitignore new file mode 100644 index 0000000..2e975ff --- /dev/null +++ b/rome-certiorem-webapp/.gitignore @@ -0,0 +1,4 @@ +/.classpath +/.project +/.settings +/target \ No newline at end of file diff --git a/rome-certiorem-webapp/README.md b/rome-certiorem-webapp/README.md new file mode 100644 index 0000000..4679522 --- /dev/null +++ b/rome-certiorem-webapp/README.md @@ -0,0 +1,4 @@ +rome-certiorem-webapp +===================== + +Example project using rome-certiorem diff --git a/rome-certiorem-webapp/pom.xml b/rome-certiorem-webapp/pom.xml new file mode 100644 index 0000000..1d3f5a1 --- /dev/null +++ b/rome-certiorem-webapp/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + + com.rometools + rome-parent + 1.6.0-SNAPSHOT + + + rome-certiorem-webapp + war + + rome-certiorem-webapp + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + scm:git:git@github.com:rometools/rome-certiorem-webapp.git + scm:git:git@github.com:rometools/rome-certiorem-webapp.git + https://github.com/rometools/rome-certiorem-webapp/ + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + com.rometools + rome-certiorem + 1.5.0 + + + com.google.inject.extensions + guice-servlet + + + javax.servlet + servlet-api + provided + + + + diff --git a/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/HubServlet.java b/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/HubServlet.java new file mode 100644 index 0000000..ea4e3bc --- /dev/null +++ b/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/HubServlet.java @@ -0,0 +1,27 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package com.rometools.certiorem.webapp; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.rometools.certiorem.hub.Hub; +import com.rometools.certiorem.web.AbstractHubServlet; + +/** + * + * @author robert.cooper + */ +@Singleton +public class HubServlet extends AbstractHubServlet { + + private static final long serialVersionUID = 1L; + + @Inject + public HubServlet(final Hub hub) { + super(hub); + } + +} diff --git a/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/NotifyTest.java b/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/NotifyTest.java new file mode 100644 index 0000000..3430e0f --- /dev/null +++ b/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/NotifyTest.java @@ -0,0 +1,42 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package com.rometools.certiorem.webapp; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.Singleton; +import com.rometools.certiorem.pub.NotificationException; +import com.rometools.certiorem.pub.Publisher; + +/** + * + * @author robert.cooper + */ +@Singleton +public class NotifyTest extends HttpServlet { + + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(NotifyTest.class); + + @Override + public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException { + final Publisher pub = new Publisher(); + try { + pub.sendUpdateNotification("http://localhost/webapp/hub", "http://localhost/webapp/research-atom.xml"); + } catch (final NotificationException ex) { + LOG.error(null, ex); + throw new ServletException(ex); + } + } + +} diff --git a/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/ServerModule.java b/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/ServerModule.java new file mode 100644 index 0000000..865cc55 --- /dev/null +++ b/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/ServerModule.java @@ -0,0 +1,71 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.rometools.certiorem.webapp; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.servlet.GuiceServletContextListener; +import com.google.inject.servlet.ServletModule; +import com.rometools.certiorem.hub.Hub; +import com.rometools.certiorem.hub.data.ram.InMemoryHubDAO; +import com.rometools.certiorem.hub.notify.standard.UnthreadedNotifier; +import com.rometools.certiorem.hub.verify.standard.UnthreadedVerifier; +import com.rometools.certiorem.sub.Subscriptions; +import com.rometools.certiorem.sub.data.ram.InMemorySubDAO; +import com.rometools.certiorem.sub.request.AsyncRequester; +import com.rometools.fetcher.FeedFetcher; +import com.rometools.fetcher.impl.HashMapFeedInfoCache; +import com.rometools.fetcher.impl.HttpURLFeedFetcher; + +/** + * + * @author robert.cooper + */ +public class ServerModule extends GuiceServletContextListener { + + private static final Logger LOG = LoggerFactory.getLogger(ServerModule.class); + + @Override + protected Injector getInjector() { + return Guice.createInjector(new AbstractModule() { + @Override + protected void configure() { + } + + @Provides + @Singleton + public Hub buildHub() { + final FeedFetcher fetcher = new HttpURLFeedFetcher(new HashMapFeedInfoCache()); + final Hub hub = new Hub(new InMemoryHubDAO(), new UnthreadedVerifier(), new UnthreadedNotifier(), fetcher); + + return hub; + } + + @Provides + @Singleton + public Subscriptions buildSubs() { + LOG.debug("buildSubs"); + final Subscriptions subs = new Subscriptions(new HashMapFeedInfoCache(), new AsyncRequester(), "http://localhost/webapp/subscriptions/", + new InMemorySubDAO()); + + return subs; + } + }, new ServletModule() { + @Override + protected void configureServlets() { + serve("/hub*").with(HubServlet.class); + serve("/subscriptions/*").with(SubServlet.class); + serve("/test/sub").with(SubTest.class); + serve("/test/pub").with(NotifyTest.class); + } + }); + } +} diff --git a/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/SubServlet.java b/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/SubServlet.java new file mode 100644 index 0000000..8e78ece --- /dev/null +++ b/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/SubServlet.java @@ -0,0 +1,27 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package com.rometools.certiorem.webapp; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.rometools.certiorem.sub.Subscriptions; +import com.rometools.certiorem.web.AbstractSubServlet; + +/** + * + * @author robert.cooper + */ +@Singleton +public class SubServlet extends AbstractSubServlet { + + private static final long serialVersionUID = 1L; + + @Inject + public SubServlet(final Subscriptions subscriptions) { + super(subscriptions); + } + +} diff --git a/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/SubTest.java b/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/SubTest.java new file mode 100644 index 0000000..c728b16 --- /dev/null +++ b/rome-certiorem-webapp/src/main/java/com/rometools/certiorem/webapp/SubTest.java @@ -0,0 +1,67 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package com.rometools.certiorem.webapp; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.rometools.certiorem.sub.Subscriptions; +import com.rometools.certiorem.sub.data.Subscription; +import com.rometools.certiorem.sub.data.SubscriptionCallback; +import com.rometools.fetcher.impl.SyndFeedInfo; + +/** + * + * @author robert.cooper + */ +@Singleton +public class SubTest extends HttpServlet { + + private static final Logger LOG = LoggerFactory.getLogger(SubTest.class); + + private static final long serialVersionUID = 1L; + + private final Subscriptions subs; + + @Inject + public SubTest(final Subscriptions subs) { + this.subs = subs; + } + + @Override + public void doGet(final HttpServletRequest request, final HttpServletResponse response) { + subs.subscribe("http://localhost/webapp/hub", "http://localhost/webapp/research-atom.xml", true, -1L, null, new SubscriptionCallback() { + + @Override + public void onFailure(final Exception e) { + e.printStackTrace(); + } + + @Override + public void onSubscribe(final Subscription subscribed) { + LOG.debug("Subscribed {} {}", subscribed.getId(), subscribed.getSourceUrl()); + } + + @Override + public void onNotify(final Subscription subscribed, final SyndFeedInfo feedInfo) { + // TODO Auto-generated method stub + } + + @Override + public void onUnsubscribe(final Subscription subscribed) { + // TODO Auto-generated method stub + } + + }); + } + +} diff --git a/rome-certiorem-webapp/src/main/resources/.gitignore b/rome-certiorem-webapp/src/main/resources/.gitignore new file mode 100644 index 0000000..53b845b --- /dev/null +++ b/rome-certiorem-webapp/src/main/resources/.gitignore @@ -0,0 +1 @@ +# needed to commit empty folder \ No newline at end of file diff --git a/rome-certiorem-webapp/src/main/webapp/WEB-INF/sun-web.xml b/rome-certiorem-webapp/src/main/webapp/WEB-INF/sun-web.xml new file mode 100644 index 0000000..0599c81 --- /dev/null +++ b/rome-certiorem-webapp/src/main/webapp/WEB-INF/sun-web.xml @@ -0,0 +1,11 @@ + + + + /webapp + + + + Keep a copy of the generated servlet class' java code. + + + diff --git a/rome-certiorem-webapp/src/main/webapp/WEB-INF/web.xml b/rome-certiorem-webapp/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..bec632b --- /dev/null +++ b/rome-certiorem-webapp/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,31 @@ + + + + rome-certiorem-webapp + + + 30 + + + + index.jsp + + + + guiceFilter + com.google.inject.servlet.GuiceFilter + + + + guiceFilter + /* + + + + Guice config + com.rometools.certiorem.example.ServerModule + + + diff --git a/rome-certiorem-webapp/src/main/webapp/index.jsp b/rome-certiorem-webapp/src/main/webapp/index.jsp new file mode 100644 index 0000000..ab292c3 --- /dev/null +++ b/rome-certiorem-webapp/src/main/webapp/index.jsp @@ -0,0 +1,13 @@ +<%@page contentType="text/html" pageEncoding="UTF-8"%> + + + + + + JSP Page + + +

Hello World!

+ + diff --git a/rome-certiorem-webapp/src/main/webapp/research-atom.xml b/rome-certiorem-webapp/src/main/webapp/research-atom.xml new file mode 100644 index 0000000..fcac7d3 --- /dev/null +++ b/rome-certiorem-webapp/src/main/webapp/research-atom.xml @@ -0,0 +1,59 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Analysis of tsunami on the economy + Analysis of the recent tsumani on the economy + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Economy + Tsunami + + 2005-02-25 + James Smith + Tsunami and the Economy + III + 5 + + + + + + Google and the internet + Analysis of Google's impact on the internet + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Internet + Search Engine + + 2004-01-29 + Sue Smith + Google and the Internet + VI + 23 + + + diff --git a/rome-certiorem-webapp/src/test/java/.gitignore b/rome-certiorem-webapp/src/test/java/.gitignore new file mode 100644 index 0000000..53b845b --- /dev/null +++ b/rome-certiorem-webapp/src/test/java/.gitignore @@ -0,0 +1 @@ +# needed to commit empty folder \ No newline at end of file diff --git a/rome-certiorem-webapp/src/test/resources/.gitignore b/rome-certiorem-webapp/src/test/resources/.gitignore new file mode 100644 index 0000000..53b845b --- /dev/null +++ b/rome-certiorem-webapp/src/test/resources/.gitignore @@ -0,0 +1 @@ +# needed to commit empty folder \ No newline at end of file diff --git a/rome-certiorem/.gitignore b/rome-certiorem/.gitignore new file mode 100644 index 0000000..2e975ff --- /dev/null +++ b/rome-certiorem/.gitignore @@ -0,0 +1,4 @@ +/.classpath +/.project +/.settings +/target \ No newline at end of file diff --git a/rome-certiorem/LICENSE b/rome-certiorem/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/rome-certiorem/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/rome-certiorem/README b/rome-certiorem/README new file mode 100644 index 0000000..dc568e4 --- /dev/null +++ b/rome-certiorem/README @@ -0,0 +1,9 @@ +ROME Certiorem + +Build Instructions +------------------------------------------------------------------------------- + +To build with Maven 2+: + +> mvn package + diff --git a/rome-certiorem/pom.xml b/rome-certiorem/pom.xml new file mode 100644 index 0000000..a92e869 --- /dev/null +++ b/rome-certiorem/pom.xml @@ -0,0 +1,111 @@ + + + 4.0.0 + + + com.rometools + rome-parent + 1.6.0-SNAPSHOT + + + rome-certiorem + 1.6.0-SNAPSHOT + jar + + rome-certiorem + + A PubSubHubub implementation for Java based on ROME + + + scm:git:ssh://github.com/rometools/rome-certiorem.git + scm:git:ssh://git@github.com/rometools/rome-certiorem.git + https://github.com/rometools/rome-certiorem + + + + + Robert Cooper + kebernet@gmail.comM + http://www.kebernet.net + + + Farrukh Najmi + http://wellfleetsoftware.com + + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + org.apache.maven.plugins + maven-site-plugin + + 9000 + ${basedir}/target/site/tempdir + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + gh-pages + ${project.scm.developerConnection} + ${project.build.directory}/site + + + + + + + + com.rometools + rome-fetcher + 1.6.0-SNAPSHOT + + + commons-httpclient + commons-httpclient + + + + + javax.servlet + servlet-api + provided + + + javax.persistence + persistence-api + provided + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + test + + + junit + junit + test + + + + diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/HttpStatusCodeException.java b/rome-certiorem/src/main/java/com/rometools/certiorem/HttpStatusCodeException.java new file mode 100644 index 0000000..013ce71 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/HttpStatusCodeException.java @@ -0,0 +1,40 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem; + +/** + * + * @author robert.cooper + */ +public class HttpStatusCodeException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private final int status; + + public HttpStatusCodeException(final int status, final String message, final Throwable cause) { + super(message, cause); + this.status = status; + } + + public int getStatus() { + return status; + } + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/DeltaFeedInfoCache.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/DeltaFeedInfoCache.java new file mode 100644 index 0000000..d197fd1 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/DeltaFeedInfoCache.java @@ -0,0 +1,51 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.rometools.certiorem.hub; + +import java.net.URL; + +import com.rometools.fetcher.impl.FeedFetcherCache; +import com.rometools.fetcher.impl.SyndFeedInfo; + +/** + * Wrapper FeedFetcherCache that wraps a backing FeedFetcherCache and makes sure that any + * SyndFeedInfo used within it are replaced with a DeltaSyndFeedInfo which is capable of tracking + * changes to entries in the underlying feed. + * + * @author najmi + */ +public class DeltaFeedInfoCache implements FeedFetcherCache { + + FeedFetcherCache backingCache; + + public DeltaFeedInfoCache(final FeedFetcherCache backingCache) { + this.backingCache = backingCache; + } + + @Override + public SyndFeedInfo getFeedInfo(final URL feedUrl) { + return backingCache.getFeedInfo(feedUrl); + } + + @Override + public void setFeedInfo(final URL feedUrl, SyndFeedInfo syndFeedInfo) { + // Make sure that syndFeedInfo is an instance of DeltaSyndFeedInfo + if (!(syndFeedInfo instanceof DeltaSyndFeedInfo)) { + syndFeedInfo = new DeltaSyndFeedInfo(syndFeedInfo); + } + backingCache.setFeedInfo(feedUrl, syndFeedInfo); + } + + @Override + public void clear() { + backingCache.clear(); + } + + @Override + public SyndFeedInfo remove(final URL feedUrl) { + return backingCache.remove(feedUrl); + } + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/DeltaSyndFeedInfo.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/DeltaSyndFeedInfo.java new file mode 100644 index 0000000..9f14f47 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/DeltaSyndFeedInfo.java @@ -0,0 +1,133 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.rometools.certiorem.hub; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.rometools.fetcher.impl.SyndFeedInfo; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; + +/** + * Extends SyndFeedInfo to also track etags for individual entries. This may be used with + * DeltaFeedInfoCache to only return feed with a subset of entries that have changed since last + * fetch. + * + * @author najmi + */ +public class DeltaSyndFeedInfo extends SyndFeedInfo { + + /** + * + */ + private static final long serialVersionUID = 1L; + Map entryTagsMap = new HashMap(); + Map changedMap = new HashMap(); + + public DeltaSyndFeedInfo(final SyndFeedInfo backingFeedInfo) { + setETag(backingFeedInfo.getETag()); + setId(backingFeedInfo.getId()); + setLastModified(backingFeedInfo.getLastModified()); + setSyndFeed(backingFeedInfo.getSyndFeed()); + } + + /** + * Gets a filtered version of the SyndFeed that only has entries that were changed in the last + * setSyndFeed() call. + * + * @return + */ + @Override + public synchronized SyndFeed getSyndFeed() { + try { + final SyndFeed feed = (SyndFeed) super.getSyndFeed().clone(); + + final List changedEntries = new ArrayList(); + + final List entries = feed.getEntries(); + for (final SyndEntry entry : entries) { + if (changedMap.containsKey(entry.getUri())) { + changedEntries.add(entry); + } + } + + feed.setEntries(changedEntries); + + return feed; + } catch (final CloneNotSupportedException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Overrides super class method to update changedMap and entryTagsMap for tracking changed + * entries. + * + * @param feed + */ + @Override + public final synchronized void setSyndFeed(final SyndFeed feed) { + super.setSyndFeed(feed); + + changedMap.clear(); + final List entries = feed.getEntries(); + for (final SyndEntry entry : entries) { + final String currentEntryTag = computeEntryTag(entry); + final String previousEntryTag = entryTagsMap.get(entry.getUri()); + + if (previousEntryTag == null || !currentEntryTag.equals(previousEntryTag)) { + // Entry has changed + changedMap.put(entry.getUri(), Boolean.TRUE); + } + entryTagsMap.put(entry.getUri(), currentEntryTag); + } + } + + private String computeEntryTag(final SyndEntry entry) { + + // Following hash algorithm suggested by Robert Cooper needs to be + // evaluated in future. + // int hash = ( entry.getUri() != null ? entry.getUri().hashCode() : + // entry.getLink().hashCode() ) ^ + // (entry.getUpdatedDate() != null ? entry.getUpdatedDate().hashCode() : + // entry.getPublishedDate().hashCode()) ^ + // entry.getTitle().hashCode() ^ + // entry.getDescription().hashCode(); + + final String id = entry.getUri(); + Date updateDate = entry.getUpdatedDate(); + final Date publishedDate = entry.getPublishedDate(); + if (updateDate == null) { + if (publishedDate != null) { + updateDate = publishedDate; + } else { + // For misbehaving feeds that do not set updateDate or + // publishedDate we use current tiem which pretty mucg assures + // that it will be viewed as + // changed even when it is not + updateDate = new Date(); + } + } + final String key = id + ":" + entry.getUpdatedDate(); + return computeDigest(key); + } + + private String computeDigest(final String content) { + try { + final MessageDigest md = MessageDigest.getInstance("SHA"); + final byte[] digest = md.digest(content.getBytes()); + final BigInteger bi = new BigInteger(digest); + return bi.toString(16); + } catch (final Exception e) { + return ""; + } + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/Hub.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/Hub.java new file mode 100644 index 0000000..81feb4f --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/Hub.java @@ -0,0 +1,259 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.certiorem.HttpStatusCodeException; +import com.rometools.certiorem.hub.Notifier.SubscriptionSummaryCallback; +import com.rometools.certiorem.hub.Verifier.VerificationCallback; +import com.rometools.certiorem.hub.data.HubDAO; +import com.rometools.certiorem.hub.data.Subscriber; +import com.rometools.certiorem.hub.data.SubscriptionSummary; +import com.rometools.fetcher.FeedFetcher; +import com.rometools.rome.feed.synd.SyndFeed; + +/** + * The basic business logic controller for the Hub implementation. It is intended to be usable under + * a very thin servlet wrapper, or other, non-HTTP notification methods you might want to use. + * + * @author robert.cooper + */ +public class Hub { + + private static final Logger LOG = LoggerFactory.getLogger(Hub.class); + + private static final HashSet STANDARD_SCHEMES = new HashSet(); + + static { + STANDARD_SCHEMES.add("http"); + STANDARD_SCHEMES.add("https"); + } + + private final FeedFetcher fetcher; + private final HubDAO dao; + private final Notifier notifier; + private final Set validPorts; + private final Set validSchemes; + private final Set validTopics; + private final Verifier verifier; + + /** + * Constructs a new Hub instance + * + * @param dao The persistence HubDAO to use + * @param verifier The verification strategy to use. + */ + public Hub(final HubDAO dao, final Verifier verifier, final Notifier notifier, final FeedFetcher fetcher) { + this.dao = dao; + this.verifier = verifier; + this.notifier = notifier; + this.fetcher = fetcher; + validSchemes = STANDARD_SCHEMES; + validPorts = Collections.emptySet(); + validTopics = Collections.emptySet(); + } + + /** + * Constructs a new Hub instance. + * + * @param dao The persistence HubDAO to use + * @param verifier The verification strategy to use + * @param validSchemes A list of valid URI schemes for callbacks (default: http, https) + * @param validPorts A list of valid port numbers for callbacks (default: any) + * @param validTopics A set of valid topic URIs which can be subscribed to (default: any) + */ + public Hub(final HubDAO dao, final Verifier verifier, final Notifier notifier, final FeedFetcher fetcher, final Set validSchemes, + final Set validPorts, final Set validTopics) { + this.dao = dao; + this.verifier = verifier; + this.notifier = notifier; + this.fetcher = fetcher; + + final Set readOnlySchemes = Collections.unmodifiableSet(validSchemes); + this.validSchemes = readOnlySchemes == null ? STANDARD_SCHEMES : readOnlySchemes; + + final Set readOnlyPorts = Collections.unmodifiableSet(validPorts); + if (readOnlyPorts == null) { + this.validPorts = Collections.emptySet(); + } else { + this.validPorts = readOnlyPorts; + } + + final Set readOnlyTopics = Collections.unmodifiableSet(validTopics); + if (validTopics == null) { + this.validTopics = Collections.emptySet(); + } else { + this.validTopics = readOnlyTopics; + } + + } + + /** + * Sends a notification to the subscribers + * + * @param requestHost the host name the hub is running on. (Used for the user agent) + * @param topic the URL of the topic that was updated. + * @throws HttpStatusCodeException a wrapper exception with a recommended status code for the + * request. + */ + public void sendNotification(final String requestHost, final String topic) { + // FIXME assert should not be used for validation because it can be disabled + assert validTopics.isEmpty() || validTopics.contains(topic) : "That topic is not supported by this hub. " + topic; + LOG.debug("Sending notification for {}", topic); + try { + final List subscribers = dao.subscribersForTopic(topic); + + if (subscribers.isEmpty()) { + LOG.debug("No subscribers to notify for {}", topic); + return; + } + + final List summaries = dao.summariesForTopic(topic); + int total = 0; + final StringBuilder hosts = new StringBuilder(); + + for (final SubscriptionSummary s : summaries) { + if (s.getSubscribers() > 0) { + total += s.getSubscribers(); + hosts.append(" (").append(s.getHost()).append("; ").append(s.getSubscribers()).append(" subscribers)"); + } + } + + final StringBuilder userAgent = new StringBuilder("ROME-Certiorem (+http://").append(requestHost).append("; ").append(total) + .append(" subscribers)").append(hosts); + final SyndFeed feed = fetcher.retrieveFeed(userAgent.toString(), new URL(topic)); + LOG.debug("Got feed for {} Sending to {} subscribers.", topic, subscribers.size()); + notifier.notifySubscribers(subscribers, feed, new SubscriptionSummaryCallback() { + @Override + public void onSummaryInfo(final SubscriptionSummary summary) { + dao.handleSummary(topic, summary); + } + }); + } catch (final Exception ex) { + LOG.debug("Exception getting " + topic, ex); + throw new HttpStatusCodeException(500, ex.getMessage(), ex); + } + } + + /** + * Subscribes to a topic. + * + * @param callback Callback URI + * @param topic Topic URI + * @param verify Verification Type + * @param lease_seconds Duration of the lease + * @param secret Secret value + * @param verify_token verify_token; + * @return Boolean.TRUE if the subscription succeeded synchronously, Boolean.FALSE if the + * subscription failed synchronously, or null if the request is asynchronous. + * @throws HttpStatusCodeException a wrapper exception with a recommended status code for the + * request. + */ + public Boolean subscribe(final String callback, final String topic, final String verify, final long lease_seconds, final String secret, + final String verify_token) { + LOG.debug("{} wants to subscribe to {}", callback, topic); + try { + try { + // FIXME assert should not be used for validation because it can be disabled + assert callback != null : "Callback URL is required."; + assert topic != null : "Topic URL is required."; + + final URI uri = new URI(callback); + assert validSchemes.contains(uri.getScheme()) : "Not a valid protocol " + uri.getScheme(); + assert validPorts.isEmpty() || validPorts.contains(uri.getPort()) : "Not a valid port " + uri.getPort(); + assert validTopics.isEmpty() || validTopics.contains(topic) : "Not a supported topic " + topic; + } catch (final URISyntaxException ex) { + assert false : "Not a valid URI " + callback; + } + assert verify != null && (verify.equals(Subscriber.VERIFY_ASYNC) || verify.equals(Subscriber.VERIFY_SYNC)) : "Unexpected verify value " + verify; + + final Subscriber subscriber = new Subscriber(); + subscriber.setCallback(callback); + subscriber.setLeaseSeconds(lease_seconds); + subscriber.setSecret(secret); + subscriber.setTopic(topic); + subscriber.setVerify(verify); + subscriber.setVertifyToken(verify_token); + + final VerificationCallback verified = new VerificationCallback() { + @Override + public void onVerify(final boolean verified) { + if (verified) { + LOG.debug("Verified {} subscribed to {}", subscriber.getCallback(), subscriber.getTopic()); + dao.addSubscriber(subscriber); + } + } + }; + + if (Subscriber.VERIFY_SYNC.equals(subscriber.getVerify())) { + final boolean result = verifier.verifySubcribeSyncronously(subscriber); + verified.onVerify(result); + + return result; + } else { + verifier.verifySubscribeAsyncronously(subscriber, verified); + + return null; + } + } catch (final AssertionError ae) { + throw new HttpStatusCodeException(400, ae.getMessage(), ae); + } catch (final Exception e) { + throw new HttpStatusCodeException(500, e.getMessage(), e); + } + } + + public Boolean unsubscribe(final String callback, final String topic, final String verify, final String secret, final String verifyToken) { + final Subscriber subscriber = dao.findSubscriber(topic, callback); + if (subscriber == null) { + throw new HttpStatusCodeException(400, "Not a valid subscription.", null); + } + subscriber.setVertifyToken(verifyToken); + subscriber.setSecret(secret); + if (Subscriber.VERIFY_SYNC.equals(verify)) { + + final boolean ret = verifier.verifyUnsubcribeSyncronously(subscriber); + if (ret) { + dao.removeSubscriber(topic, callback); + } + } else { + verifier.verifyUnsubscribeAsyncronously(subscriber, new VerificationCallback() { + + @Override + public void onVerify(final boolean verified) { + LOG.debug("Unsubscribe for {} at {} verified {}", subscriber.getTopic(), subscriber.getCallback(), verified); + if (verified) { + dao.removeSubscriber(topic, callback); + } + } + + }); + } + return null; + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/Notifier.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/Notifier.java new file mode 100644 index 0000000..b7f7ae3 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/Notifier.java @@ -0,0 +1,51 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub; + +import java.util.List; + +import com.rometools.certiorem.hub.data.Subscriber; +import com.rometools.certiorem.hub.data.SubscriptionSummary; +import com.rometools.rome.feed.synd.SyndFeed; + +/** + * + * @author robert.cooper + */ +public interface Notifier { + /** + * Instructs the notifier to begin sending notifications to the list of subscribers + * + * @param subscribers Subscribers to notify + * @param value The SyndFeed to send them + * @param callback A callback that is invoked each time a subscriber is notified. + */ + public void notifySubscribers(List subscribers, SyndFeed value, SubscriptionSummaryCallback callback); + + /** + * A callback that is invoked each time a subscriber is notified. + */ + public static interface SubscriptionSummaryCallback { + /** + * + * @param summary A summary of the data received from the subscriber + */ + public void onSummaryInfo(SubscriptionSummary summary); + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/Verifier.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/Verifier.java new file mode 100644 index 0000000..b50a3f1 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/Verifier.java @@ -0,0 +1,81 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub; + +import com.rometools.certiorem.hub.data.Subscriber; + +/** + * A strategy interface for verification of subscriptions. + * + * @author robert.cooper + */ +public interface Verifier { + + /** + * Value for hub.mode = subscribe + */ + public static final String MODE_SUBSCRIBE = "subscribe"; + /** + * Value for hub.mode = unsubscribe + */ + public static final String MODE_UNSUBSCRIBE = "unsubscribe"; + + /** + * Verifies a subscriber (possibly) asyncronously + * + * @param subscriber the Subscriber to verify + * @param callback a callback with the result of the verification. + */ + public void verifySubscribeAsyncronously(Subscriber subscriber, VerificationCallback callback); + + /** + * Verifies a subscriber syncronously + * + * @param subscriber The subscriber data + * @return boolean result; + */ + public boolean verifySubcribeSyncronously(Subscriber subscriber); + + /** + * Verifies am unsubscribe (possibly) asyncronously + * + * @param subscriber The subscriber data + * @param callback result + */ + public void verifyUnsubscribeAsyncronously(Subscriber subscriber, VerificationCallback callback); + + /** + * Verifies an unsubscribe syncronously + * + * @param subscriber The subscriber data + * @return boolean result; + */ + public boolean verifyUnsubcribeSyncronously(Subscriber subscriber); + + /** + * An interface for capturing the result of a verification (subscribe or unsubscribe) + */ + public static interface VerificationCallback { + /** + * + * @param verified success state of the verification + */ + public void onVerify(boolean verified); + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/HubDAO.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/HubDAO.java new file mode 100644 index 0000000..b942746 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/HubDAO.java @@ -0,0 +1,41 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.data; + +import java.util.List; + +/** + * + * @author robert.cooper + */ +public interface HubDAO { + + public List subscribersForTopic(String topic); + + public Subscriber addSubscriber(Subscriber subscriber); + + public Subscriber findSubscriber(String topic, String callbackUrl); + + public void removeSubscriber(String topic, String callback); + + public void handleSummary(String topic, SubscriptionSummary summary); + + public List summariesForTopic(String topic); + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/Subscriber.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/Subscriber.java new file mode 100644 index 0000000..01b2b42 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/Subscriber.java @@ -0,0 +1,224 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.data; + +import java.io.Serializable; + +/** + * + * @author robert.cooper + */ +public class Subscriber implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + public static final String VERIFY_SYNC = "sync"; + public static final String VERIFY_ASYNC = "async"; + private String callback; + private String secret; + private String topic; + private String verify; + private String vertifyToken; + private long creationTime = System.currentTimeMillis(); + private long leaseSeconds; + + /** + * Set the value of callback + * + * @param newcallback new value of callback + */ + public void setCallback(final String newcallback) { + callback = newcallback; + } + + /** + * Get the value of callback + * + * @return the value of callback + */ + public String getCallback() { + return callback; + } + + /** + * Set the value of creationTime + * + * @param newcreationTime new value of creationTime + */ + public void setCreationTime(final long newcreationTime) { + creationTime = newcreationTime; + } + + /** + * Get the value of creationTime + * + * @return the value of creationTime + */ + public long getCreationTime() { + return creationTime; + } + + /** + * Set the value of leaseSeconds + * + * @param newleaseSeconds new value of leaseSeconds + */ + public void setLeaseSeconds(final long newleaseSeconds) { + leaseSeconds = newleaseSeconds; + } + + /** + * Get the value of leaseSeconds + * + * @return the value of leaseSeconds + */ + public long getLeaseSeconds() { + return leaseSeconds; + } + + /** + * Set the value of secret + * + * @param newsecret new value of secret + */ + public void setSecret(final String newsecret) { + secret = newsecret; + } + + /** + * Get the value of secret + * + * @return the value of secret + */ + public String getSecret() { + return secret; + } + + /** + * Set the value of topic + * + * @param newtopic new value of topic + */ + public void setTopic(final String newtopic) { + topic = newtopic; + } + + /** + * Get the value of topic + * + * @return the value of topic + */ + public String getTopic() { + return topic; + } + + /** + * Set the value of verify + * + * @param newverify new value of verify + */ + public void setVerify(final String newverify) { + verify = newverify; + } + + /** + * Get the value of verify + * + * @return the value of verify + */ + public String getVerify() { + return verify; + } + + /** + * Set the value of vertifyToken + * + * @param newvertifyToken new value of vertifyToken + */ + public void setVertifyToken(final String newvertifyToken) { + vertifyToken = newvertifyToken; + } + + /** + * Get the value of vertifyToken + * + * @return the value of vertifyToken + */ + public String getVertifyToken() { + return vertifyToken; + } + + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + + if (!(obj instanceof Subscriber)) { + return false; + } + + final Subscriber other = (Subscriber) obj; + + if (callback == null ? other.callback != null : !callback.equals(other.callback)) { + return false; + } + + if (secret == null ? other.secret != null : !secret.equals(other.secret)) { + return false; + } + + if (topic == null ? other.topic != null : !topic.equals(other.topic)) { + return false; + } + + if (verify == null ? other.verify != null : !verify.equals(other.verify)) { + return false; + } + + if (vertifyToken == null ? other.vertifyToken != null : !vertifyToken.equals(other.vertifyToken)) { + return false; + } + + if (creationTime != other.creationTime) { + return false; + } + + if (leaseSeconds != other.leaseSeconds) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 67 * hash + (callback != null ? callback.hashCode() : 0); + hash = 67 * hash + (secret != null ? secret.hashCode() : 0); + hash = 67 * hash + (topic != null ? topic.hashCode() : 0); + hash = 67 * hash + (verify != null ? verify.hashCode() : 0); + hash = 67 * hash + (vertifyToken != null ? vertifyToken.hashCode() : 0); + hash = 67 * hash + (int) (creationTime ^ creationTime >>> 32); + hash = 67 * hash + (int) (leaseSeconds ^ leaseSeconds >>> 32); + + return hash; + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/SubscriptionSummary.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/SubscriptionSummary.java new file mode 100644 index 0000000..42e63fa --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/SubscriptionSummary.java @@ -0,0 +1,89 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.data; + +import java.io.Serializable; + +/** + * + * @author robert.cooper + */ +public class SubscriptionSummary implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + private String host; + private boolean lastPublishSuccessful = true; + private int subscribers = 0; + + /** + * Set the value of host + * + * @param newhost new value of host + */ + public void setHost(final String newhost) { + host = newhost; + } + + /** + * Get the value of host + * + * @return the value of host + */ + public String getHost() { + return host; + } + + /** + * Set the value of lastPublishSuccessful + * + * @param newlastPublishSuccessful new value of lastPublishSuccessful + */ + public void setLastPublishSuccessful(final boolean newlastPublishSuccessful) { + lastPublishSuccessful = newlastPublishSuccessful; + } + + /** + * Get the value of lastPublishSuccessful + * + * @return the value of lastPublishSuccessful + */ + public boolean isLastPublishSuccessful() { + return lastPublishSuccessful; + } + + /** + * Set the value of subscribers + * + * @param newsubscribers new value of subscribers + */ + public void setSubscribers(final int newsubscribers) { + subscribers = newsubscribers; + } + + /** + * Get the value of subscribers + * + * @return the value of subscribers + */ + public int getSubscribers() { + return subscribers; + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/jpa/JPADAO.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/jpa/JPADAO.java new file mode 100644 index 0000000..4c084a3 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/jpa/JPADAO.java @@ -0,0 +1,131 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.data.jpa; + +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.NoResultException; +import javax.persistence.Query; + +import com.rometools.certiorem.hub.data.HubDAO; +import com.rometools.certiorem.hub.data.Subscriber; +import com.rometools.certiorem.hub.data.SubscriptionSummary; + +/** + * + * @author robert.cooper + */ +public class JPADAO implements HubDAO { + + private final EntityManagerFactory factory; + private final boolean purgeExpired; + + public JPADAO(final EntityManagerFactory factory, final boolean purgeExpired) { + this.factory = factory; + this.purgeExpired = purgeExpired; + } + + @Override + public List subscribersForTopic(final String topic) { + final LinkedList result = new LinkedList(); + final EntityManager em = factory.createEntityManager(); + final EntityTransaction tx = em.getTransaction(); + tx.begin(); + + final Query query = em.createNamedQuery("Subcriber.forTopic"); + query.setParameter("topic", topic); + + try { + @SuppressWarnings("unchecked") + final List subscribers = query.getResultList(); + for (final JPASubscriber subscriber : subscribers) { + if (subscriber.getLeaseSeconds() == -1) { + result.add(subscriber); + continue; + } + + if (subscriber.getSubscribedAt().getTime() < System.currentTimeMillis() - 1000 * subscriber.getLeaseSeconds()) { + subscriber.setExpired(true); + } else { + result.add(subscriber); + } + + if (subscriber.isExpired() && purgeExpired) { + em.remove(subscriber); + } + } + } catch (final NoResultException e) { + tx.rollback(); + em.close(); + + return result; + } + + if (!tx.getRollbackOnly()) { + tx.commit(); + } else { + tx.rollback(); + } + + em.close(); + + return result; + } + + @Override + public Subscriber addSubscriber(final Subscriber subscriber) { + // FIXME assert should not be used for validation because it can be disabled + assert subscriber != null : "Attempt to store a null subscriber"; + final EntityManager em = factory.createEntityManager(); + final EntityTransaction tx = em.getTransaction(); + tx.begin(); + final JPASubscriber data = new JPASubscriber(); + data.copyFrom(subscriber); + data.setId(UUID.randomUUID().toString()); + em.persist(data); + tx.commit(); + em.close(); + return data; + } + + @Override + public Subscriber findSubscriber(final String topic, final String callbackUrl) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void handleSummary(final String topic, final SubscriptionSummary summary) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List summariesForTopic(final String topic) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void removeSubscriber(final String topic, final String callback) { + throw new UnsupportedOperationException("Not supported yet."); + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/jpa/JPASubscriber.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/jpa/JPASubscriber.java new file mode 100644 index 0000000..7620bf4 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/jpa/JPASubscriber.java @@ -0,0 +1,111 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.data.jpa; + +import java.io.Serializable; +import java.util.Date; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import com.rometools.certiorem.hub.data.Subscriber; + +/** + * + * @author robert.cooper + */ +@Entity +@NamedQueries({ @NamedQuery(name = "Subcriber.forTopic", query = "SELECT o FROM JPASubscriber o WHERE o.topic = :topic AND o.expired = false ORDER BY o.subscribedAt") }) +public class JPASubscriber extends Subscriber implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + private Date subscribedAt = new Date(); + private String id; + private boolean expired = false; + + /** + * Set the value of expired + * + * @param newexpired new value of expired + */ + public void setExpired(final boolean newexpired) { + expired = newexpired; + } + + /** + * Get the value of expired + * + * @return the value of expired + */ + public boolean isExpired() { + return expired; + } + + /** + * Set the value of id + * + * @param newid new value of id + */ + public void setId(final String newid) { + id = newid; + } + + /** + * Get the value of id + * + * @return the value of id + */ + @Id + public String getId() { + return id; + } + + /** + * Set the value of subscribedAt + * + * @param newsubscribedAt new value of subscribedAt + */ + public void setSubscribedAt(final Date newsubscribedAt) { + subscribedAt = newsubscribedAt; + } + + /** + * Get the value of subscribedAt + * + * @return the value of subscribedAt + */ + @Temporal(TemporalType.TIMESTAMP) + public Date getSubscribedAt() { + return subscribedAt; + } + + public void copyFrom(final Subscriber source) { + setLeaseSeconds(source.getLeaseSeconds()); + setSecret(source.getSecret()); + setTopic(source.getTopic()); + setVerify(source.getVerify()); + setVertifyToken(source.getVertifyToken()); + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/jpa/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/jpa/package.html new file mode 100644 index 0000000..a5c2c5e --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/jpa/package.html @@ -0,0 +1,28 @@ + + + + + jpa + + + A stock data implementation based on the Java Persistence API. + + \ No newline at end of file diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/package.html new file mode 100644 index 0000000..663de72 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/package.html @@ -0,0 +1,29 @@ + + + + + data + + + This package defines the basic data types and persistence mechanisms + that are required for a hub implementation. + + \ No newline at end of file diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/ram/InMemoryHubDAO.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/ram/InMemoryHubDAO.java new file mode 100644 index 0000000..b9ed4a3 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/ram/InMemoryHubDAO.java @@ -0,0 +1,136 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.data.ram; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import com.rometools.certiorem.hub.data.HubDAO; +import com.rometools.certiorem.hub.data.Subscriber; +import com.rometools.certiorem.hub.data.SubscriptionSummary; + +/** + * A Simple In-Memory HubDAO for subscribers. + * + * @author robert.cooper + */ +public class InMemoryHubDAO implements HubDAO { + private final ConcurrentHashMap> subscribers = new ConcurrentHashMap>(); + private final ConcurrentHashMap> summaries = new ConcurrentHashMap>(); + + @Override + public Subscriber addSubscriber(final Subscriber subscriber) { + // FIXME assert should not be used for validation because it can be disabled + assert subscriber != null : "Attempt to store a null subscriber"; + + List subList = subscribers.get(subscriber.getTopic()); + + if (subList == null) { + synchronized (this) { + subList = new CopyOnWriteArrayList(); + subscribers.put(subscriber.getTopic(), subList); + } + } + + subList.add(subscriber); + + return subscriber; + } + + @Override + public void handleSummary(final String topic, final SubscriptionSummary summary) { + ConcurrentHashMap hostsToSummaries = summaries.get(topic); + + if (hostsToSummaries == null) { + synchronized (this) { + hostsToSummaries = new ConcurrentHashMap(); + summaries.put(topic, hostsToSummaries); + } + } + + hostsToSummaries.put(summary.getHost(), summary); + } + + @Override + public List subscribersForTopic(final String topic) { + if (subscribers.containsKey(topic)) { + final List result = new LinkedList(); + final LinkedList expired = new LinkedList(); + + for (final Subscriber s : subscribers.get(topic)) { + if (s.getLeaseSeconds() > 0 && System.currentTimeMillis() >= s.getCreationTime() + s.getLeaseSeconds() * 1000L) { + expired.add(s); + } else { + result.add(s); + } + } + + if (!expired.isEmpty()) { + subscribers.get(topic).removeAll(expired); + } + + return result; + } else { + return Collections.emptyList(); + } + } + + @Override + public List summariesForTopic(final String topic) { + final LinkedList result = new LinkedList(); + + if (summaries.containsKey(topic)) { + result.addAll(summaries.get(topic).values()); + } + + return result; + } + + @Override + public Subscriber findSubscriber(final String topic, final String callbackUrl) { + + for (final Subscriber s : subscribersForTopic(topic)) { + if (callbackUrl.equals(s.getCallback())) { + return s; + } + } + return null; + } + + @Override + public void removeSubscriber(final String topic, final String callback) { + final List subs = subscribers.get(topic); + if (subs == null) { + return; + } + Subscriber match = null; + for (final Subscriber s : subs) { + if (s.getCallback().equals(callback)) { + match = s; + break; + } + } + if (match != null) { + subs.remove(match); + } + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/ram/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/ram/package.html new file mode 100644 index 0000000..daecce8 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/data/ram/package.html @@ -0,0 +1,25 @@ + + + + Contains a Memory-Resident implemtnation of the Hub DAO. + + + diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/AbstractNotifier.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/AbstractNotifier.java new file mode 100644 index 0000000..4195ef1 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/AbstractNotifier.java @@ -0,0 +1,162 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.notify.standard; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.certiorem.hub.Notifier; +import com.rometools.certiorem.hub.data.Subscriber; +import com.rometools.certiorem.hub.data.SubscriptionSummary; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedOutput; + +/** + * + * @author robert.cooper + */ +public abstract class AbstractNotifier implements Notifier { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractNotifier.class); + + /** + * This method will serialize the synd feed and build Notifications for the implementation class + * to handle. + * + * @see enqueueNotification + * + * @param subscribers List of subscribers to notify + * @param value The SyndFeed object to send + * @param callback A callback that will be invoked each time a subscriber is notified. + * + */ + @Override + public void notifySubscribers(final List subscribers, final SyndFeed value, final SubscriptionSummaryCallback callback) { + + String mimeType = null; + + if (value.getFeedType().startsWith("rss")) { + mimeType = "application/rss+xml"; + } else { + mimeType = "application/atom+xml"; + } + + final SyndFeedOutput output = new SyndFeedOutput(); + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + try { + output.output(value, new OutputStreamWriter(baos)); + baos.close(); + } catch (final IOException ex) { + LOG.error("Unable to output the feed", ex); + throw new RuntimeException("Unable to output the feed.", ex); + } catch (final FeedException ex) { + LOG.error("Unable to output the feed", ex); + throw new RuntimeException("Unable to output the feed.", ex); + } + + final byte[] payload = baos.toByteArray(); + + for (final Subscriber s : subscribers) { + final Notification not = new Notification(); + not.callback = callback; + not.lastRun = 0; + not.mimeType = mimeType; + not.payload = payload; + not.retryCount = 0; + not.subscriber = s; + enqueueNotification(not); + } + } + + /** + * Implementation method that queues/sends a notification + * + * @param not notification to send. + */ + protected abstract void enqueueNotification(Notification not); + + /** + * POSTs the payload to the subscriber's callback and returns a SubscriptionSummary with + * subscriber counts (where possible) and the success state of the notification. + * + * @param subscriber subscriber data. + * @param mimeType MIME type for the request + * @param payload payload of the feed to send + * @return SubscriptionSummary with the returned data. + */ + protected SubscriptionSummary postNotification(final Subscriber subscriber, final String mimeType, final byte[] payload) { + final SubscriptionSummary result = new SubscriptionSummary(); + + try { + final URL target = new URL(subscriber.getCallback()); + LOG.info("Posting notification to subscriber {}", subscriber.getCallback()); + result.setHost(target.getHost()); + + final HttpURLConnection connection = (HttpURLConnection) target.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", mimeType); + connection.setDoOutput(true); + connection.connect(); + + final OutputStream os = connection.getOutputStream(); + os.write(payload); + os.close(); + + final int responseCode = connection.getResponseCode(); + final String subscribers = connection.getHeaderField("X-Hub-On-Behalf-Of"); + connection.disconnect(); + + if (responseCode != 200) { + LOG.warn("Got code {} from {}", responseCode, target); + result.setLastPublishSuccessful(false); + return result; + } + + if (subscribers != null) { + try { + result.setSubscribers(Integer.parseInt(subscribers)); + } catch (final NumberFormatException nfe) { + LOG.warn("Invalid subscriber value " + subscribers + " " + target, nfe); + result.setSubscribers(-1); + } + } else { + result.setSubscribers(-1); + } + } catch (final MalformedURLException ex) { + LOG.warn(null, ex); + result.setLastPublishSuccessful(false); + } catch (final IOException ex) { + LOG.error(null, ex); + result.setLastPublishSuccessful(false); + } + + return result; + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/Notification.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/Notification.java new file mode 100644 index 0000000..d3ffdff --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/Notification.java @@ -0,0 +1,37 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.notify.standard; + +import com.rometools.certiorem.hub.Notifier.SubscriptionSummaryCallback; +import com.rometools.certiorem.hub.data.Subscriber; + +/** + * + * @author robert.cooper + */ +public class Notification { + + int retryCount = 0; + long lastRun = 0; + Subscriber subscriber; + String mimeType; + byte[] payload; + SubscriptionSummaryCallback callback; + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/ThreadPoolNotifier.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/ThreadPoolNotifier.java new file mode 100644 index 0000000..12e30e1 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/ThreadPoolNotifier.java @@ -0,0 +1,112 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.notify.standard; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import com.rometools.certiorem.hub.data.SubscriptionSummary; + +/** + * A notifier implementation that uses a thread pool to deliver notifications to subscribers + * + * @author robert.cooper + */ +public class ThreadPoolNotifier extends AbstractNotifier { + private static final long TWO_MINUTES = 2 * 60 * 1000; + protected final ThreadPoolExecutor exeuctor; + private final Timer timer = new Timer(); + private final ConcurrentSkipListSet pendings = new ConcurrentSkipListSet(); + + public ThreadPoolNotifier() { + this(2, 5, 5); + } + + public ThreadPoolNotifier(final int startPoolSize, final int maxPoolSize, final int queueSize) { + exeuctor = new ThreadPoolExecutor(startPoolSize, maxPoolSize, 300, TimeUnit.SECONDS, new LinkedBlockingQueue(queueSize)); + } + + protected ThreadPoolNotifier(final ThreadPoolExecutor executor) { + exeuctor = executor; + } + + /** + * Enqueues a notification to run. If the notification fails, it will be retried every two + * minutes until 5 attempts are completed. Notifications to the same callback should be + * delivered successfully in order. + * + * @param not + */ + @Override + protected void enqueueNotification(final Notification not) { + final Runnable r = new Runnable() { + @Override + public void run() { + not.lastRun = System.currentTimeMillis(); + + final SubscriptionSummary summary = postNotification(not.subscriber, not.mimeType, not.payload); + + if (!summary.isLastPublishSuccessful()) { + not.retryCount++; + + if (not.retryCount <= 5) { + retry(not); + } + } + + not.callback.onSummaryInfo(summary); + } + }; + + exeuctor.execute(r); + } + + /** + * Schedules a notification to retry in two minutes. + * + * @param not Notification to retry + */ + protected void retry(final Notification not) { + if (!pendings.contains(not.subscriber.getCallback())) { + // We don't have a current retry for this callback pending, so we + // will schedule the retry + pendings.add(not.subscriber.getCallback()); + timer.schedule(new TimerTask() { + @Override + public void run() { + pendings.remove(not.subscriber.getCallback()); + enqueueNotification(not); + } + }, TWO_MINUTES); + } else { + // There is a retry in front of this one, so we will just schedule + // it to retry again in a bit + timer.schedule(new TimerTask() { + @Override + public void run() { + retry(not); + } + }, TWO_MINUTES); + } + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/UnthreadedNotifier.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/UnthreadedNotifier.java new file mode 100644 index 0000000..b1228eb --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/UnthreadedNotifier.java @@ -0,0 +1,43 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.notify.standard; + +import com.rometools.certiorem.hub.data.SubscriptionSummary; + +/** + * A notifier that does not use threads. All calls are blocking and synchronous. + * + * @author robert.cooper + */ +public class UnthreadedNotifier extends AbstractNotifier { + + /** + * A blocking call that performs a notification. If there are pending retries that are older + * than two minutes old, they will be retried before the method returns. + * + * @param not + */ + @Override + protected void enqueueNotification(final Notification not) { + not.lastRun = System.currentTimeMillis(); + final SubscriptionSummary summary = postNotification(not.subscriber, not.mimeType, not.payload); + not.callback.onSummaryInfo(summary); + } + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/package.html new file mode 100644 index 0000000..c38c288 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/notify/standard/package.html @@ -0,0 +1,32 @@ + + + + + verify + + + This package contains a set of standard Verifier implementations. +

+ These implementations all use the standard java.net.* classes for + making requests to URLs. +

+ + \ No newline at end of file diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/package.html new file mode 100644 index 0000000..9e6bac7 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/package.html @@ -0,0 +1,30 @@ + + + + + hub + + + This package contains the core of the Hub implementation. +

Getting Started

+

The Hub implementation

+ + \ No newline at end of file diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/AbstractVerifier.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/AbstractVerifier.java new file mode 100644 index 0000000..7a8398c --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/AbstractVerifier.java @@ -0,0 +1,99 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.verify.standard; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.certiorem.hub.Verifier; +import com.rometools.certiorem.hub.data.Subscriber; + +/** + * An abstract verifier based on the java.net HTTP classes. This implements only synchronous + * operations, and expects a child class to do Async ops. + * + * @author robert.cooper + */ +public abstract class AbstractVerifier implements Verifier { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractVerifier.class); + + @Override + public boolean verifySubcribeSyncronously(final Subscriber subscriber) { + return doOp(Verifier.MODE_SUBSCRIBE, subscriber); + } + + @Override + public boolean verifyUnsubcribeSyncronously(final Subscriber subscriber) { + return doOp(Verifier.MODE_UNSUBSCRIBE, subscriber); + } + + private boolean doOp(final String mode, final Subscriber subscriber) { + try { + final String challenge = UUID.randomUUID().toString(); + final StringBuilder queryString = new StringBuilder(); + queryString.append("hub.mode=").append(mode).append("&hub.topic=").append(URLEncoder.encode(subscriber.getTopic(), "UTF-8")) + .append("&hub.challenge=").append(challenge); + + if (subscriber.getLeaseSeconds() != -1) { + queryString.append("&hub.lease_seconds=").append(subscriber.getLeaseSeconds()); + } + + if (subscriber.getVertifyToken() != null) { + queryString.append("&hub.verify_token=").append(URLEncoder.encode(subscriber.getVertifyToken(), "UTF-8")); + } + + final URL url = new URL(subscriber.getCallback() + "?" + queryString.toString()); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setDoInput(true); + // connection.setRequestProperty("Host", url.getHost()); + // connection.setRequestProperty("Port", + // Integer.toString(url.getPort())); + connection.setRequestProperty("User-Agent", "ROME-Certiorem"); + connection.connect(); + final int rc = connection.getResponseCode(); + final InputStream is = connection.getInputStream(); + final BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + final String result = reader.readLine(); + reader.close(); + connection.disconnect(); + if (rc != 200 || !challenge.equals(result.trim())) { + return false; + } else { + return true; + } + } catch (final UnsupportedEncodingException ex) { + LOG.error("Unsupported encoding", ex); + throw new RuntimeException("Should not happen. UTF-8 threw unsupported encoding", ex); + } catch (final IOException ex) { + LOG.error("An IOException occured", ex); + return false; + } + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/ThreadPoolVerifier.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/ThreadPoolVerifier.java new file mode 100644 index 0000000..1c5f599 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/ThreadPoolVerifier.java @@ -0,0 +1,66 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.verify.standard; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import com.rometools.certiorem.hub.data.Subscriber; + +/** + * Uses a ThreadPoolExecutor to do async verifications. + * + * @author robert.cooper + */ +public class ThreadPoolVerifier extends AbstractVerifier { + protected final ThreadPoolExecutor exeuctor; + + protected ThreadPoolVerifier(final ThreadPoolExecutor executor) { + exeuctor = executor; + } + + public ThreadPoolVerifier() { + this(2, 5, 5); + } + + public ThreadPoolVerifier(final int startPoolSize, final int maxPoolSize, final int queueSize) { + exeuctor = new ThreadPoolExecutor(startPoolSize, maxPoolSize, 300, TimeUnit.SECONDS, new LinkedBlockingQueue(queueSize)); + } + + @Override + public void verifySubscribeAsyncronously(final Subscriber subscriber, final VerificationCallback callback) { + exeuctor.execute(new Runnable() { + @Override + public void run() { + callback.onVerify(verifySubcribeSyncronously(subscriber)); + } + }); + } + + @Override + public void verifyUnsubscribeAsyncronously(final Subscriber subscriber, final VerificationCallback callback) { + exeuctor.execute(new Runnable() { + @Override + public void run() { + callback.onVerify(verifyUnsubcribeSyncronously(subscriber)); + } + }); + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/ThreadpoolVerifierAdvanced.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/ThreadpoolVerifierAdvanced.java new file mode 100644 index 0000000..8751b27 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/ThreadpoolVerifierAdvanced.java @@ -0,0 +1,33 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.verify.standard; + +import java.util.concurrent.ThreadPoolExecutor; + +/** + * + * @author robert.cooper + */ +public class ThreadpoolVerifierAdvanced extends ThreadPoolVerifier { + + public ThreadpoolVerifierAdvanced(final ThreadPoolExecutor executor) { + super(executor); + } + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/UnthreadedVerifier.java b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/UnthreadedVerifier.java new file mode 100644 index 0000000..8f2fac9 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/UnthreadedVerifier.java @@ -0,0 +1,40 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.verify.standard; + +import com.rometools.certiorem.hub.data.Subscriber; + +/** + * A verifier that does not use threads. Suitable for Google App Engine. + * + * @author robert.cooper + */ +public class UnthreadedVerifier extends AbstractVerifier { + + @Override + public void verifySubscribeAsyncronously(final Subscriber subscriber, final VerificationCallback callback) { + callback.onVerify(verifySubcribeSyncronously(subscriber)); + } + + @Override + public void verifyUnsubscribeAsyncronously(final Subscriber subscriber, final VerificationCallback callback) { + callback.onVerify(verifyUnsubcribeSyncronously(subscriber)); + } + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/package.html new file mode 100644 index 0000000..c38c288 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/hub/verify/standard/package.html @@ -0,0 +1,32 @@ + + + + + verify + + + This package contains a set of standard Verifier implementations. +

+ These implementations all use the standard java.net.* classes for + making requests to URLs. +

+ + \ No newline at end of file diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/package.html new file mode 100644 index 0000000..3da23c0 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/package.html @@ -0,0 +1,30 @@ + + + + + A pub sub hubub implementation for Java. + + + + + + + diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/pub/NotificationException.java b/rome-certiorem/src/main/java/com/rometools/certiorem/pub/NotificationException.java new file mode 100644 index 0000000..91c5c58 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/pub/NotificationException.java @@ -0,0 +1,40 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.pub; + +/** + * + * @author robert.cooper + */ +public class NotificationException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public NotificationException(final String message) { + super(message); + } + + public NotificationException(final String message, final Throwable cause) { + super(message, cause); + } + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/pub/Publisher.java b/rome-certiorem/src/main/java/com/rometools/certiorem/pub/Publisher.java new file mode 100644 index 0000000..6857d55 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/pub/Publisher.java @@ -0,0 +1,251 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.pub; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.concurrent.ThreadPoolExecutor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndLink; + +/** + * A class for sending update notifications to a hub. + * + * @author robert.cooper + */ +public class Publisher { + + private static final Logger LOG = LoggerFactory.getLogger(Publisher.class); + + private ThreadPoolExecutor executor; + + /** + * Constructs a new publisher. This publisher will spawn a new thread for each async send. + */ + public Publisher() { + } + + /** + * Constructs a new publisher with an optional ThreadPoolExector for sending updates. + */ + public Publisher(final ThreadPoolExecutor executor) { + this.executor = executor; + } + + /** + * Sends the HUB url a notification of a change in topic + * + * @param hub URL of the hub to notify. + * @param topic The Topic that has changed + * @throws NotificationException Any failure + */ + public void sendUpdateNotification(final String hub, final String topic) throws NotificationException { + try { + final StringBuilder sb = new StringBuilder("hub.mode=publish&hub.url=").append(URLEncoder.encode(topic, "UTF-8")); + final URL hubUrl = new URL(hub); + final HttpURLConnection connection = (HttpURLConnection) hubUrl.openConnection(); + // connection.setRequestProperty("Host", hubUrl.getHost()); + connection.setRequestProperty("User-Agent", "ROME-Certiorem"); + connection.setRequestProperty("ContentType", "application/x-www-form-urlencoded"); + connection.setDoOutput(true); + connection.connect(); + + final OutputStream os = connection.getOutputStream(); + os.write(sb.toString().getBytes("UTF-8")); + os.close(); + + final int rc = connection.getResponseCode(); + connection.disconnect(); + + if (rc != 204) { + throw new NotificationException("Server returned an unexcepted response code: " + rc + " " + connection.getResponseMessage()); + } + + } catch (final UnsupportedEncodingException ex) { + LOG.error("Could not encode URL", ex); + throw new NotificationException("Could not encode URL", ex); + } catch (final IOException ex) { + LOG.error("Communication error", ex); + throw new NotificationException("Unable to communicate with " + hub, ex); + } + } + + /** + * Sends a notification for a feed located at "topic". The feed MUST contain rel="hub". + * + * @param topic URL for the feed + * @param feed The feed itself + * @throws NotificationException Any failure + */ + public void sendUpdateNotification(final String topic, final SyndFeed feed) throws NotificationException { + for (final SyndLink link : feed.getLinks()) { + if ("hub".equals(link.getRel())) { + sendUpdateNotification(link.getRel(), topic); + + return; + } + } + throw new NotificationException("Hub link not found."); + } + + /** + * Sends a notification for a feed. The feed MUST contain rel="hub" and rel="self" links. + * + * @param feed The feed to notify + * @throws NotificationException Any failure + */ + public void sendUpdateNotification(final SyndFeed feed) throws NotificationException { + SyndLink hub = null; + SyndLink self = null; + + for (final SyndLink link : feed.getLinks()) { + if ("hub".equals(link.getRel())) { + hub = link; + } + + if ("self".equals(link.getRel())) { + self = link; + } + + if (hub != null && self != null) { + break; + } + } + + if (hub == null) { + throw new NotificationException("A link rel='hub' was not found in the feed."); + } + + if (self == null) { + throw new NotificationException("A link rel='self' was not found in the feed."); + } + + sendUpdateNotification(hub.getRel(), self.getHref()); + } + + /** + * Sends the HUB url a notification of a change in topic asynchronously + * + * @param hub URL of the hub to notify. + * @param topic The Topic that has changed + * @param callback A callback invoked when the notification completes. + * @throws NotificationException Any failure + */ + public void sendUpdateNotificationAsyncronously(final String hub, final String topic, final AsyncNotificationCallback callback) { + final Runnable r = new Runnable() { + @Override + public void run() { + try { + sendUpdateNotification(hub, topic); + callback.onSuccess(); + } catch (final Throwable t) { + callback.onFailure(t); + } + } + }; + + if (executor != null) { + executor.execute(r); + } else { + new Thread(r).start(); + } + } + + /** + * Asynchronously sends a notification for a feed located at "topic". The feed MUST contain + * rel="hub". + * + * @param topic URL for the feed + * @param feed The feed itself + * @param callback A callback invoked when the notification completes. + * @throws NotificationException Any failure + */ + public void sendUpdateNotificationAsyncronously(final String topic, final SyndFeed feed, final AsyncNotificationCallback callback) { + final Runnable r = new Runnable() { + @Override + public void run() { + try { + sendUpdateNotification(topic, feed); + callback.onSuccess(); + } catch (final Throwable t) { + callback.onFailure(t); + } + } + }; + + if (executor != null) { + executor.execute(r); + } else { + new Thread(r).start(); + } + } + + /** + * Asyncronously sends a notification for a feed. The feed MUST contain rel="hub" and rel="self" + * links. + * + * @param feed The feed to notify + * @param callback A callback invoked when the notification completes. + * @throws NotificationException Any failure + */ + public void sendUpdateNotificationAsyncronously(final SyndFeed feed, final AsyncNotificationCallback callback) { + final Runnable r = new Runnable() { + @Override + public void run() { + try { + sendUpdateNotification(feed); + callback.onSuccess(); + } catch (final Throwable t) { + callback.onFailure(t); + } + } + }; + + if (executor != null) { + executor.execute(r); + } else { + new Thread(r).start(); + } + } + + /** + * A callback interface for asynchronous notifications. + */ + public static interface AsyncNotificationCallback { + /** + * Called when a notification fails + * + * @param thrown Whatever was thrown during the failure + */ + public void onFailure(Throwable thrown); + + /** + * Invoked with the asyncronous notification completes successfully. + */ + public void onSuccess(); + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/pub/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/pub/package.html new file mode 100644 index 0000000..9f56bb1 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/pub/package.html @@ -0,0 +1,29 @@ + + + + + pub + + + This package contains a utility class to send update notifications. + + + \ No newline at end of file diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/Requester.java b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/Requester.java new file mode 100644 index 0000000..016f37d --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/Requester.java @@ -0,0 +1,38 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.sub; + +import com.rometools.certiorem.sub.data.Subscription; + +/** + * + * @author robert.cooper + */ +public interface Requester { + public void sendSubscribeRequest(String hubUrl, Subscription subscription, String verifySync, long leaseSeconds, String secret, String callbackUrl, + RequestCallback callback); + + public void sendUnsubscribeRequest(String hubUrl, Subscription subscription, String verifySync, String secret, String callbackUrl, RequestCallback callback); + + public static interface RequestCallback { + public void onFailure(Exception e); + + public void onSuccess(); + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/Subscriptions.java b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/Subscriptions.java new file mode 100644 index 0000000..5989389 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/Subscriptions.java @@ -0,0 +1,284 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.sub; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.certiorem.HttpStatusCodeException; +import com.rometools.certiorem.sub.Requester.RequestCallback; +import com.rometools.certiorem.sub.data.SubDAO; +import com.rometools.certiorem.sub.data.Subscription; +import com.rometools.certiorem.sub.data.SubscriptionCallback; +import com.rometools.fetcher.impl.FeedFetcherCache; +import com.rometools.fetcher.impl.SyndFeedInfo; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndLink; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedInput; + +/** + * + * @author robert.cooper + */ +public class Subscriptions { + + private static final Logger LOG = LoggerFactory.getLogger(Subscriptions.class); + + // TODO unsubscribe. + private FeedFetcherCache cache; + private Requester requester; + private String callbackPrefix; + private SubDAO dao; + + public Subscriptions() { + } + + public Subscriptions(final FeedFetcherCache cache, final Requester requester, final String callbackPrefix, final SubDAO dao) { + this.cache = cache; + this.requester = requester; + this.callbackPrefix = callbackPrefix; + this.dao = dao; + } + + public void callback(final String callbackPath, final String feed) { + try { + this.callback(callbackPath, feed.getBytes("UTF-8")); + } catch (final UnsupportedEncodingException ex) { + LOG.error("Unable to parse feed", ex); + throw new HttpStatusCodeException(400, "Unable to parse feed.", ex); + } + } + + public void callback(final String callbackPath, final InputStream feed) { + final SyndFeedInput input = new SyndFeedInput(); + + try { + this.callback(callbackPath, input.build(new InputStreamReader(feed))); + } catch (final IllegalArgumentException ex) { + LOG.error("Unable to parse feed", ex); + throw new HttpStatusCodeException(500, "Unable to parse feed.", ex); + } catch (final FeedException ex) { + LOG.error("Unable to parse feed", ex); + throw new HttpStatusCodeException(400, "Unable to parse feed.", ex); + } + } + + public void callback(final String callbackPath, final byte[] feed) { + this.callback(callbackPath, new ByteArrayInputStream(feed)); + } + + public void callback(final String callbackPath, final SyndFeed feed) { + + if (!callbackPath.startsWith(callbackPrefix)) { + throw new HttpStatusCodeException(404, "Not a valid callback prefix.", new Exception(callbackPath + " doesnt start with " + callbackPrefix)); + } + + final String id = callbackPath.substring(callbackPrefix.length()); + LOG.debug("Got callback for {}", id); + final Subscription s = dao.findById(id); + + if (s == null) { + throw new HttpStatusCodeException(404, "Not a valid callback.", null); + } + + validateLink(feed, s.getSourceUrl()); + + SyndFeedInfo info = null; + URL url = null; + + try { + url = new URL(s.getSourceUrl()); + info = cache.getFeedInfo(url); + } catch (final MalformedURLException ex) { + LOG.error("Malformed URL", ex); + } + + if (info == null) { + info = new SyndFeedInfo(); + info.setId(s.getId()); + info.setUrl(url); + } + + info.setLastModified(System.currentTimeMillis()); + info.setSyndFeed(feed); + cache.setFeedInfo(url, info); + + s.getCallback().onNotify(s, info); + } + + public void unsubscribe(final Subscription subscription, final String hubUrl, final boolean sync, final String secret, final SubscriptionCallback callback) { + + subscription.setUnsubscribed(true); + requester.sendUnsubscribeRequest(hubUrl, subscription, sync ? "sync" : "async", secret, callbackPrefix + subscription.getId(), new RequestCallback() { + @Override + public void onSuccess() { + callback.onUnsubscribe(subscription); + } + + @Override + public void onFailure(final Exception e) { + callback.onFailure(e); + } + }); + } + + public void subscribe(final String hubUrl, final String topic, final boolean sync, final long leaseSeconds, final String secret, + final SubscriptionCallback callback) { + final Subscription s = new Subscription(); + s.setId(UUID.randomUUID().toString()); + s.setVerifyToken(UUID.randomUUID().toString()); + s.setSourceUrl(topic); + s.setCallback(callback); + if (leaseSeconds > 0) { + s.setExpirationTime(System.currentTimeMillis() + leaseSeconds * 1000); + } + + final Subscription stored = dao.addSubscription(s); + + requester.sendSubscribeRequest(hubUrl, stored, sync ? "sync" : "async", leaseSeconds, secret, callbackPrefix + stored.getId(), new RequestCallback() { + @Override + public void onSuccess() { + callback.onSubscribe(stored); + } + + @Override + public void onFailure(final Exception e) { + callback.onFailure(e); + } + }); + } + + public void subscribe(final String topic, final boolean sync, final long leaseSeconds, final String secret, final SubscriptionCallback callback) + throws IllegalArgumentException, IOException, FeedException { + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed feed = input.build(new InputStreamReader(new URL(topic).openStream())); + final String hubUrl = findHubUrl(feed); + + if (hubUrl == null) { + throw new FeedException("No hub link"); + } + + this.subscribe(hubUrl, topic, sync, leaseSeconds, secret, callback); + } + + public String validate(final String callbackPath, final String topic, final String mode, final String challenge, final String leaseSeconds, + final String verifyToken) { + if (!callbackPath.startsWith(callbackPrefix)) { + throw new HttpStatusCodeException(404, "Not a valid callback prefix.", new Exception(callbackPath + " doesnt start with " + callbackPrefix)); + } + + final String id = callbackPath.substring(callbackPrefix.length()); + LOG.debug("Handling validation request for id {}", id); + final Subscription s = dao.findById(id); + if (s == null) { + throw new HttpStatusCodeException(404, "Not a valid subscription id", null); + } + if (!s.getVerifyToken().equals(verifyToken)) { + throw new HttpStatusCodeException(403, "Verification Token Mismatch.", null); + } + + if ("unsubscribe".equals(mode)) { + if (!s.isUnsubscribed()) { + throw new HttpStatusCodeException(400, "Unsubscribe not requested.", null); + } + + dao.removeSubscription(s); + } else if ("subscribe".equals(mode)) { + if (s.isValidated()) { + throw new HttpStatusCodeException(400, "Duplicate validation.", null); + } + + s.setValidated(true); + dao.updateSubscription(s); + } else { + throw new HttpStatusCodeException(400, "Unsupported mode " + mode, null); + } + LOG.debug("Validated. Returning {}", challenge); + return challenge; + } + + private String findHubUrl(final SyndFeed feed) { + for (final SyndLink l : feed.getLinks()) { + if ("hub".equals(l.getRel())) { + return l.getHref(); + } + } + + return null; + } + + private void validateLink(final SyndFeed feed, final String source) { + for (final SyndLink l : feed.getLinks()) { + if ("self".equalsIgnoreCase(l.getRel())) { + try { + final URI u = new URI(l.getHref()); + final URI t = new URI(source); + + if (!u.equals(t)) { + throw new HttpStatusCodeException(400, "Feed self link does not match the subscribed URI.", null); + } + + break; + } catch (final URISyntaxException ex) { + LOG.error(null, ex); + } + } + } + } + + /** + * @param cache the cache to set + */ + public void setCache(final FeedFetcherCache cache) { + this.cache = cache; + } + + /** + * @param requester the requester to set + */ + public void setRequester(final Requester requester) { + this.requester = requester; + } + + /** + * @param callbackPrefix the callbackPrefix to set + */ + public void setCallbackPrefix(final String callbackPrefix) { + this.callbackPrefix = callbackPrefix; + } + + /** + * @param dao the dao to set + */ + public void setDao(final SubDAO dao) { + this.dao = dao; + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/SubDAO.java b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/SubDAO.java new file mode 100644 index 0000000..cef1930 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/SubDAO.java @@ -0,0 +1,35 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.sub.data; + +/** + * + * @author robert.cooper + */ +public interface SubDAO { + + public Subscription findById(String id); + + public Subscription addSubscription(Subscription s); + + public Subscription updateSubscription(Subscription s); + + public void removeSubscription(Subscription s); + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/Subscription.java b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/Subscription.java new file mode 100644 index 0000000..8344df0 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/Subscription.java @@ -0,0 +1,161 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.sub.data; + +import java.io.Serializable; + +/** + * + * @author robert.cooper + */ +public class Subscription implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + private String id; + private String sourceUrl; + private String verifyToken; + private boolean unsubscribed; + private boolean validated; + private long expirationTime; + private SubscriptionCallback callback; + + /** + * Set the value of expirationTime + * + * @param newexpirationTime new value of expirationTime + */ + public void setExpirationTime(final long newexpirationTime) { + expirationTime = newexpirationTime; + } + + /** + * Get the value of expirationTime + * + * @return the value of expirationTime + */ + public long getExpirationTime() { + return expirationTime; + } + + /** + * Set the value of id + * + * @param newid new value of id + */ + public void setId(final String newid) { + id = newid; + } + + /** + * Get the value of id + * + * @return the value of id + */ + public String getId() { + return id; + } + + /** + * Set the value of sourceUrl + * + * @param newsourceUrl new value of sourceUrl + */ + public void setSourceUrl(final String newsourceUrl) { + sourceUrl = newsourceUrl; + } + + /** + * Get the value of sourceUrl + * + * @return the value of sourceUrl + */ + public String getSourceUrl() { + return sourceUrl; + } + + /** + * Set the value of unsubscribed + * + * @param newunsubscribed new value of unsubscribed + */ + public void setUnsubscribed(final boolean newunsubscribed) { + unsubscribed = newunsubscribed; + } + + /** + * Get the value of unsubscribed + * + * @return the value of unsubscribed + */ + public boolean isUnsubscribed() { + return unsubscribed; + } + + /** + * Set the value of validated + * + * @param newvalidated new value of validated + */ + public void setValidated(final boolean newvalidated) { + validated = newvalidated; + } + + /** + * Get the value of validated + * + * @return the value of validated + */ + public boolean isValidated() { + return validated; + } + + /** + * Set the value of verifyToken + * + * @param newverifyToken new value of verifyToken + */ + public void setVerifyToken(final String newverifyToken) { + verifyToken = newverifyToken; + } + + /** + * Get the value of verifyToken + * + * @return the value of verifyToken + */ + public String getVerifyToken() { + return verifyToken; + } + + /** + * @return the callback + */ + public SubscriptionCallback getCallback() { + return callback; + } + + /** + * @param callback the callback to set + */ + public void setCallback(final SubscriptionCallback callback) { + this.callback = callback; + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/SubscriptionCallback.java b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/SubscriptionCallback.java new file mode 100644 index 0000000..ce9e560 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/SubscriptionCallback.java @@ -0,0 +1,23 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package com.rometools.certiorem.sub.data; + +import com.rometools.fetcher.impl.SyndFeedInfo; + +/** + * + * @author najmi + */ +public interface SubscriptionCallback { + + void onNotify(Subscription subscribed, SyndFeedInfo feedInfo); + + void onFailure(Exception e); + + void onSubscribe(Subscription subscribed); + + void onUnsubscribe(Subscription subscribed); +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/package.html new file mode 100644 index 0000000..625b5a4 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/package.html @@ -0,0 +1,28 @@ + + + + + data + + + Data classes for the Subscription management. + + diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/ram/InMemorySubDAO.java b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/ram/InMemorySubDAO.java new file mode 100644 index 0000000..d631d6c --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/ram/InMemorySubDAO.java @@ -0,0 +1,78 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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. + */ + +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package com.rometools.certiorem.sub.data.ram; + +import java.util.Date; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.certiorem.sub.data.SubDAO; +import com.rometools.certiorem.sub.data.Subscription; + +/** + * + * @author robert.cooper + */ +public class InMemorySubDAO implements SubDAO { + + private static final Logger LOG = LoggerFactory.getLogger(InMemorySubDAO.class); + + private final ConcurrentHashMap subscriptions = new ConcurrentHashMap(); + + @Override + public Subscription findById(final String id) { + final Subscription s = subscriptions.get(id); + if (s == null) { + return null; + } + if (s.getExpirationTime() > 0 && s.getExpirationTime() <= System.currentTimeMillis()) { + LOG.debug("Subscription {} expired at {}", s.getSourceUrl(), new Date(s.getExpirationTime())); + subscriptions.remove(id); + + return null; + } + return s; + } + + @Override + public Subscription addSubscription(final Subscription s) { + subscriptions.put(s.getId(), s); + LOG.debug("Stored subscription {} {}", s.getSourceUrl(), s.getId()); + return s; + } + + @Override + public Subscription updateSubscription(final Subscription s) { + subscriptions.put(s.getId(), s); + return s; + } + + @Override + public void removeSubscription(final Subscription s) { + subscriptions.remove(s.getId()); + } + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/ram/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/ram/package.html new file mode 100644 index 0000000..3333549 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/data/ram/package.html @@ -0,0 +1,28 @@ + + + + + ram + + + An In-Memory DAO for subscriptions. + + \ No newline at end of file diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/package.html new file mode 100644 index 0000000..44aab1c --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/package.html @@ -0,0 +1,30 @@ + + + + + sub + + + This package contains the business class Subscriptions that manages subscriptions and updates a + FeedInfoCache. + + + diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/AbstractRequester.java b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/AbstractRequester.java new file mode 100644 index 0000000..ec663df --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/AbstractRequester.java @@ -0,0 +1,72 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.sub.request; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; + +import com.rometools.certiorem.sub.Requester; +import com.rometools.certiorem.sub.data.Subscription; + +/** + * + * @author robert.cooper + */ +public abstract class AbstractRequester implements Requester { + + protected boolean sendRequest(final String hubUrl, final String mode, final Subscription subscription, final String verifySync, final long leaseSeconds, + final String secret, final String callbackUrl, final RequestCallback callback) throws IOException { + final StringBuilder sb = new StringBuilder("hub.callback=").append(URLEncoder.encode(callbackUrl, "UTF-8")).append("&hub.topic=") + .append(URLEncoder.encode(subscription.getSourceUrl(), "UTF-8")).append("&hub.verify=").append(URLEncoder.encode(verifySync, "UTF-8")) + .append("&hub.mode=").append(URLEncoder.encode(mode, "UTF-8")); + + if (leaseSeconds > 0) { + sb.append("&hub.lease_seconds=").append(Long.toString(leaseSeconds)); + } + + if (secret != null) { + sb.append("&hub.secret=").append(URLEncoder.encode(secret, "UTF-8")); + } + + if (subscription.getVerifyToken() != null) { + sb.append("&hub.verify_token=").append(URLEncoder.encode(subscription.getVerifyToken(), "UTF-8")); + } + + final URL url = new URL(hubUrl); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + connection.setDoOutput(true); + // connection.setRequestProperty("Host", url.getHost()); + connection.setRequestProperty("User-Agent", "ROME-Certiorem"); + connection.connect(); + connection.getOutputStream().write(sb.toString().getBytes("UTF-8")); + + final int rc = connection.getResponseCode(); + connection.disconnect(); + + if (rc != 204) { + throw new RuntimeException("Unexpected repsonse code. " + rc); + } + + return true; + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/AsyncRequester.java b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/AsyncRequester.java new file mode 100644 index 0000000..bae5291 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/AsyncRequester.java @@ -0,0 +1,72 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.sub.request; + +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.certiorem.sub.data.Subscription; + +/** + * A simple requester implementation that always makes requests as Async. + * + * @author robert.cooper + */ +public class AsyncRequester extends AbstractRequester { + + private static final Logger LOG = LoggerFactory.getLogger(AsyncRequester.class); + + @Override + public void sendSubscribeRequest(final String hubUrl, final Subscription subscription, final String verifySync, final long leaseSeconds, + final String secret, final String callbackUrl, final RequestCallback callback) { + LOG.debug("Sending subscribe request to {} for {} to {}", hubUrl, subscription.getSourceUrl(), callbackUrl); + final Runnable r = new Runnable() { + @Override + public void run() { + try { + sendRequest(hubUrl, "subscribe", subscription, verifySync, leaseSeconds, secret, callbackUrl, callback); + } catch (final Exception ex) { + LOG.error(null, ex); + callback.onFailure(ex); + } + } + }; + new Thread(r).start(); + } + + @Override + public void sendUnsubscribeRequest(final String hubUrl, final Subscription subscription, final String verifySync, final String secret, + final String callbackUrl, final RequestCallback callback) { + LOG.debug("Sending unsubscribe request to {} for {} to {}", hubUrl, subscription.getSourceUrl(), callbackUrl); + final Runnable r = new Runnable() { + @Override + public void run() { + try { + sendRequest(hubUrl, "unsubscribe", subscription, verifySync, -1, secret, callbackUrl, callback); + } catch (final IOException ex) { + LOG.error(null, ex); + callback.onFailure(ex); + } + } + }; + new Thread(r).start(); + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/SyncRequester.java b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/SyncRequester.java new file mode 100644 index 0000000..721b0c8 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/SyncRequester.java @@ -0,0 +1,66 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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. + */ + +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.rometools.certiorem.sub.request; + +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.certiorem.sub.data.Subscription; + +/** + * A simple requester implementation that always makes requests as Async. + * + * @author Farrukh Najmi + */ +public class SyncRequester extends AbstractRequester { + + private static final Logger LOG = LoggerFactory.getLogger(SyncRequester.class); + + @Override + public void sendSubscribeRequest(final String hubUrl, final Subscription subscription, final String verifySync, final long leaseSeconds, + final String secret, final String callbackUrl, final RequestCallback callback) { + LOG.info("Sending subscribe request to {} for {} to {}", hubUrl, subscription.getSourceUrl(), callbackUrl); + try { + sendRequest(hubUrl, "subscribe", subscription, verifySync, leaseSeconds, secret, callbackUrl, callback); + callback.onSuccess(); + } catch (final Exception ex) { + LOG.error(null, ex); + callback.onFailure(ex); + } + } + + @Override + public void sendUnsubscribeRequest(final String hubUrl, final Subscription subscription, final String verifySync, final String secret, + final String callbackUrl, final RequestCallback callback) { + LOG.info("Sending unsubscribe request to {} for {} to {}", hubUrl, subscription.getSourceUrl(), callbackUrl); + try { + sendRequest(hubUrl, "unsubscribe", subscription, verifySync, -1, secret, callbackUrl, callback); + callback.onSuccess(); + } catch (final IOException ex) { + LOG.error(null, ex); + callback.onFailure(ex); + } + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/package.html new file mode 100644 index 0000000..b2bd746 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/sub/request/package.html @@ -0,0 +1,28 @@ + + + + + request + + + Standard requester implementations. + + \ No newline at end of file diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/web/AbstractHubServlet.java b/rome-certiorem/src/main/java/com/rometools/certiorem/web/AbstractHubServlet.java new file mode 100644 index 0000000..28ee4bf --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/web/AbstractHubServlet.java @@ -0,0 +1,84 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.web; + +import java.io.IOException; +import java.util.Arrays; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.rometools.certiorem.HttpStatusCodeException; +import com.rometools.certiorem.hub.Hub; + +/** + * + * @author robert.cooper + */ +public abstract class AbstractHubServlet extends HttpServlet { + /** + * + */ + private static final long serialVersionUID = 1L; + public static final String HUBMODE = "hub.mode"; + private final Hub hub; + + protected AbstractHubServlet(final Hub hub) { + super(); + this.hub = hub; + } + + @Override + protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { + try { + if ("publish".equals(req.getParameter(HUBMODE))) { + hub.sendNotification(req.getServerName(), req.getParameter("hub.url")); + } else { + final String callback = req.getParameter("hub.callback"); + final String topic = req.getParameter("hub.topic"); + final String[] verifies = req.getParameterValues("hub.verify"); + final String leaseString = req.getParameter("hub.lease_seconds"); + final String secret = req.getParameter("hub.secret"); + final String verifyToken = req.getParameter("hub.verify_token"); + final String verifyMode = Arrays.asList(verifies).contains("async") ? "async" : "sync"; + Boolean result = null; + + if ("subscribe".equals(req.getParameter(HUBMODE))) { + final long leaseSeconds = leaseString != null ? Long.parseLong(leaseString) : -1; + result = hub.subscribe(callback, topic, verifyMode, leaseSeconds, secret, verifyToken); + } else if ("unsubscribe".equals(req.getParameter(HUBMODE))) { + result = hub.unsubscribe(callback, topic, verifyMode, secret, verifyToken); + } + + if (result != null && !result) { + throw new HttpStatusCodeException(500, "Operation failed.", null); + } + } + } catch (final HttpStatusCodeException sc) { + resp.setStatus(sc.getStatus()); + resp.getWriter().println(sc.getMessage()); + + return; + } + + resp.setStatus(204); + } +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/web/AbstractSubServlet.java b/rome-certiorem/src/main/java/com/rometools/certiorem/web/AbstractSubServlet.java new file mode 100644 index 0000000..3b6f343 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/web/AbstractSubServlet.java @@ -0,0 +1,77 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.web; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.rometools.certiorem.HttpStatusCodeException; +import com.rometools.certiorem.sub.Subscriptions; + +/** + * + * @author robert.cooper + */ +public abstract class AbstractSubServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + private final Subscriptions subscriptions; + + protected AbstractSubServlet(final Subscriptions subscriptions) { + this.subscriptions = subscriptions; + } + + @Override + protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { + final String mode = req.getParameter("hub.mode"); + final String topic = req.getParameter("hub.topic"); + final String challenge = req.getParameter("hub.challenge"); + final String leaseString = req.getParameter("hub.lease_seconds"); + final String verifyToken = req.getParameter("hub.verify_token"); + try { + final String result = subscriptions.validate(req.getRequestURL().toString(), topic, mode, challenge, leaseString, verifyToken); + resp.setStatus(200); + resp.getWriter().print(result); + } catch (final HttpStatusCodeException e) { + e.printStackTrace(); + resp.setStatus(e.getStatus()); + resp.getWriter().print(e.getMessage()); + } + } + + @Override + protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { + try { + final String requestUrl = req.getRequestURL().toString(); + final ServletInputStream inputStream = req.getInputStream(); + subscriptions.callback(requestUrl, inputStream); + } catch (final HttpStatusCodeException e) { + e.printStackTrace(); + resp.setStatus(e.getStatus()); + resp.getWriter().println(e.getMessage()); + } + } + +} diff --git a/rome-certiorem/src/main/java/com/rometools/certiorem/web/package.html b/rome-certiorem/src/main/java/com/rometools/certiorem/web/package.html new file mode 100644 index 0000000..17f6703 --- /dev/null +++ b/rome-certiorem/src/main/java/com/rometools/certiorem/web/package.html @@ -0,0 +1,31 @@ + + + + + web + + + Contains base servlet implementations for doing hub and sub services. +

+ Extends these as needed in your web application. +

+ + \ No newline at end of file diff --git a/rome-certiorem/src/main/resources/META-INF/persistence.xml b/rome-certiorem/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000..6237669 --- /dev/null +++ b/rome-certiorem/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,30 @@ + + + + + + jdbc/certiorem-datasource + + + + + + \ No newline at end of file diff --git a/rome-certiorem/src/site/apt/CertioremTutorial.apt b/rome-certiorem/src/site/apt/CertioremTutorial.apt new file mode 100644 index 0000000..6a81dfc --- /dev/null +++ b/rome-certiorem/src/site/apt/CertioremTutorial.apt @@ -0,0 +1,124 @@ + ----- + Certiorem Tutorial + ----- + kebernet + ----- + 2011-12-06 19:23:15.220 + ----- + +Certiorem Tutorial + + Certiorem is a PubSubHubub (PSH) implementation for ROME. It isn't an application, but an API for building each of the three components (Publisher, Subscriber and Hub) into your web apps. + + You can see an {{{https://github.com/rometools/rome-incubator/tree/master/pubsubhubub/webapp}example webapp here}}. + +Creating a Hub + + Hubs take notifications, or "Pings" that tell it the content of a feed has been updated, fetch the feed, then notify each of the subscribers of the change. As you will begin to see, Certiorem is very much about "Composition" of classes. The Hub class is a prime example of this. + + Looking at the example webapp we see: + ++------+ +@Provides +@Singleton +public Hub buildHub() { + FeedFetcher fetcher = new HttpURLFeedFetcher(new DeltaFeedInfoCache()); +    Hub hub = new Hub(new InMemoryHubDAO(), new UnthreadedVerifier(), new UnthreadedNotifier(), fetcher); + +    return hub; +} ++------+ + + First we construct an instance of FeedFetcher, from the Fetcher subproject. This will be used to fetch feeds from remote hosts. There are a number of implementations for FeedFetcher and FeedInfoCache in the Fetcher project. Please look there for info on what is what. + + Next we need a HubDAO implementation. This is a DAO for managing Subscriber and SubscriptionSummary classes. Here we are using an in\-memory DAO, which like the HashMapFeedInfoCache will evaporate if we restart our web application. A JPA implementation for persistence is also available, but incomplete at time of writing. + + Next we need two implementations of network client interfaces: a Verifier, and a Notifier. The Verifier calls back to the Subscribers and verifies their subscribe/unsubscribe operations. A Notifier is used to send updates to to the clients. There are two basic implementations of these provided: A ThreadPool\* and Unthreaded\* version of each. The thread pool version uses a ThreadPoolExecutor to run queues of outbound calls. The Unthreaded version of each, makes the network calls in\-line with the request to the hub. These are suitable for environments like Google App Engine where spawning threads from servlets is absolutely verboten. + + There are other constructors that contain lists of restrictions for what the hub will support: acceptable topic feeds, ports, protocols, etc. + + The hub here is just a business logic class. In order to have a functioning hub, we need a servlet exposing the Hub. In the "web" package, there is an abstract servlet you can use to do just this. In the Guice wired example, we simply create a servlet with an injected Hub implementation. + ++------+ +@Singleton +public class HubServlet extends AbstractHubServlet { + + @Inject + public HubServlet(final Hub hub){ + super(hub); + } +} +//... in the ServerModule... + +serve("/hub*").with(HubServlet.class); ++------+ + + We can now include a \ value in our feeds and publish notifications of changes.  + +Publishing Ping Notifications + + This is perhaps the easiest thing to do. The Publisher class will take various combinations of URLs and SyndFeeds and send the appropriate notification. If your SyndFeed contains a \ and \ you can just pass the SyndFeed object. Otherwise, you can use the URL strings where appropriate. + + The example couldn't be simpler: + ++------+ +Publisher pub = new Publisher(); +try { + pub.sendUpdateNotification("http://localhost/webapp/hub", "http://localhost/webapp/research-atom.xml"); +} catch (NotificationException ex) { + Logger.getLogger(NotifyTest.class.getName()).log(Level.SEVERE, null, ex); + throw new ServletException(ex); +} ++------+ + + Once this notification is sent, the hub will make a request to the feed and notify the clients of new entries. + +Subscribing to Feeds + + To set up a feed subscriber, you need to go through a process very much like setting up a Hub. First, create the Subscriptions class by composition: + ++------+ +@Provides +@Singleton +public Subscriptions buildSubs(){ +    Subscriptions subs = new Subscriptions(new HashMapFeedInfoCache(), new AsyncRequester(), +            "http://localhost/webapp/subscriptions/", new InMemorySubDAO()); +    return subs; +} ++------+ + + First we need a FeedInfoCache implementation. This will be updated as notifications come in, so in your web app, you want to make sure this is shared with the FeedFetcher implementation you are using to read feeds. Next you need a Requester, this is a network class that makes subscription requests to remote hubs. Next, a URL prefix for where the callbacks will live. This really means the URL to the SubServlet that is resolvable externally. Finally, a DAO for storing and retrieving Subscription objects. + + As in the Hub, we need a wrapper servlet to call into the Subscriptions class + ++------+ +@Singleton +public class SubServlet extends AbstractSubServlet { + + @Inject + public SubServlet(final Subscriptions subscriptions){ + super(subscriptions); + } +} + +// In the ServerModule... +serve("/subscriptions/*").with(SubServlet.class) ++------+ + + Now if we want to subscribe to a feed, we get a reference to the Subscriptions object, and pass in either the SyndFeed (with appropriate rel\="hub" and rel\="self" links) or simply a couple of URLs: + ++------+ + subs.subscribe("http://localhost/webapp/hub", "http://localhost/webapp/research-atom.xml", true, -1, null, new SubscriptionCallback(){ + + public void onFailure(Exception e) { + e.printStackTrace(); + } + + public void onSubscribe(Subscription subscribed) { + System.out.println("Subscribed "+subscribed.getId() +" "+subscribed.getSourceUrl()); + } + + }); ++------+ + + Here we pass in the URL of the Hub, the URL of the feed, a boolean indicating we want to make the subscription request synchronously, the lease seconds we want to keep the subscription for, a null cryptographic secret, and a Callback invoked when the subscribe request completes. diff --git a/rome-certiorem/src/site/apt/index.apt b/rome-certiorem/src/site/apt/index.apt new file mode 100644 index 0000000..d240e48 --- /dev/null +++ b/rome-certiorem/src/site/apt/index.apt @@ -0,0 +1,47 @@ + ----- + certiorem + ----- + kebernet + ----- + 2011-03-19 10:30:35.292 + ----- + +Certiorem + + Certiorem is an implementation of the {{{http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub\-core\-0.3.html}PubSubHubub }}protocol for ROME. + + It is dependent on ROME and ROME\-Fetcher for the base implementations, and will provide standard plugins for Propono to allow for publish eventing, where applicable. + +*Primary Components + +*Hub Implementation and Scaffolding (Done) + + The first part of Certiorem is a basic set of scaffolding classes that can be used to create a PSH notification hub. Initially, this will include a non\-guaranteed delivery hub, with standard implementations suitable for deployment on most JavaEE application servers or Google App Engine. It is intended that there should be at least one simple, drop in WAR file, utilizing JavaEE classes that can work in a default configuration for various standard web containers. Subsequently,  each of the classes in the PSH implementation up through the primary Controller class use constructor\-time composition/configuration so that the user/developer can easily construct a custom configuration of the Hub. + +**Client Implementation Integrated with ROME\-Fetcher (Done) + + For web\-based applications that use ROME\-Fetcher, an extended push\-notified store wrapper that will update based on callbacks from a Hub of change notifications. This will include a highly configurable callback servlet to write into the Fetcher cache as changes are made. Additionally, the system should support (semi\-)real time notifications of changes in the form of a listener that exectutes in a TBD thread state relative to the callback servlet. This should be packaged as a simple JAR with no more deps than fetcher that defines the callback servlet, and automagically does subscribes where link\=rel appropriate. + +**Notification Implementation for Propono based and JAX\-RS based Servers (In Progress) + + This should be a simple API call to notify a Hub of changes to topics. Again, this should provide real\-time notifications either synchronously or asynchronously. Importantly for Asynchronous notifications, they should block subsequent change notifications pending a notification to the Hub. + + References:  + + {{{https://github.com/nlothian/RTUpdates/blob/master/src/com/nicklothian/pubsubhub/PubSubHubSubscriptionServlet.java}https://github.com/nlothian/RTUpdates/blob/master/src/com/nicklothian/pubsubhub/PubSubHubSubscriptionServlet.java}} + + {{{http://grack.com/blog/2009/09/09/parsing\-the\-pubsubhubbub\-notifications/}http://grack.com/blog/2009/09/09/parsing\-the\-pubsubhubbub\-notifications/}} + +Notes on the Code + + It is still mostly a rough sketch, but the big outlines are there: + + There are three main packages: pub, sub and hub. + + The pub package is basically just a single utility class for pushing notifications to a hub. + + The hub package contains the Hub class. This is a general business controller that is intended to allow you to build a servlet around it with a very, very thin veneer, but you could also use it to drive an XMPP or JMS version too. It is basically built by composition of a number of classes, for which there are some default implementations: A Verifier, which makes the callback to verify new subscriptions, the HubDAO which stores the current subscriptions and subscriber statistics, and a Notifier which actually sends notifications to the subscribers. There are a couple of implementations of each of these (though the JPA HubDAO is still in process). Mostly the implementations for the Verifier and Notifier support threadpooling or no\-threads (for App Engine use). + + I have just started sketching out the sub package, but it basically has a "Subscriptions" class that will take in notifications (using the same "thin veneer" pattern that the Hub class uses). It is also constructed with some impls: A SubscriptionDAO that stores you current subscription information, a FeedFetcherCache that holds the received data, and a Requester that makes the subscription requests to hubs. + + I am hoping to have a basic end to end example working sometime in the next week or so, but if anyone wants to look over what is there, feel free. diff --git a/src/site/resources/.nojekyll b/rome-certiorem/src/site/resources/.nojekyll similarity index 100% rename from src/site/resources/.nojekyll rename to rome-certiorem/src/site/resources/.nojekyll diff --git a/src/site/resources/css/site.css b/rome-certiorem/src/site/resources/css/site.css similarity index 100% rename from src/site/resources/css/site.css rename to rome-certiorem/src/site/resources/css/site.css diff --git a/src/site/resources/images/romelogo.png b/rome-certiorem/src/site/resources/images/romelogo.png similarity index 100% rename from src/site/resources/images/romelogo.png rename to rome-certiorem/src/site/resources/images/romelogo.png diff --git a/rome-certiorem/src/site/site.xml b/rome-certiorem/src/site/site.xml new file mode 100644 index 0000000..61433df --- /dev/null +++ b/rome-certiorem/src/site/site.xml @@ -0,0 +1,42 @@ + + + + + org.apache.maven.skins + maven-fluido-skin + 1.3.0 + + + + + + rometools/rome-certiorem + right + gray + + + + + + ROME + images/romelogo.png + http://github.com/rometools/ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rome-certiorem/src/test/java/com/rometools/certiorem/hub/AlwaysVerifier.java b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/AlwaysVerifier.java new file mode 100644 index 0000000..af5f9fb --- /dev/null +++ b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/AlwaysVerifier.java @@ -0,0 +1,50 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub; + +import com.rometools.certiorem.hub.Verifier; +import com.rometools.certiorem.hub.data.Subscriber; + +/** + * + * @author robert.cooper + */ +public class AlwaysVerifier implements Verifier { + + @Override + public void verifySubscribeAsyncronously(final Subscriber subscriber, final VerificationCallback callback) { + callback.onVerify(true); + } + + @Override + public boolean verifySubcribeSyncronously(final Subscriber subscriber) { + return true; + } + + @Override + public void verifyUnsubscribeAsyncronously(final Subscriber subscriber, final VerificationCallback callback) { + callback.onVerify(true); + } + + @Override + public boolean verifyUnsubcribeSyncronously(final Subscriber subscriber) { + return true; + } + +} diff --git a/rome-certiorem/src/test/java/com/rometools/certiorem/hub/ControllerTest.java b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/ControllerTest.java new file mode 100644 index 0000000..7d5b1cd --- /dev/null +++ b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/ControllerTest.java @@ -0,0 +1,131 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.certiorem.HttpStatusCodeException; +import com.rometools.certiorem.hub.Hub; +import com.rometools.certiorem.hub.Notifier; +import com.rometools.certiorem.hub.data.HubDAO; +import com.rometools.certiorem.hub.data.ram.InMemoryHubDAO; +import com.rometools.fetcher.FeedFetcher; +import com.rometools.fetcher.impl.HashMapFeedInfoCache; +import com.rometools.fetcher.impl.HttpURLFeedFetcher; + +/** + * + * @author robert.cooper + */ +public class ControllerTest { + + private static final Logger LOG = LoggerFactory.getLogger(ControllerTest.class); + + public ControllerTest() { + } + + @BeforeClass + public static void setUpClass() throws Exception { + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Test of subscribe method, of class Hub. + */ + @Test + public void testSubscribe() { + + LOG.info("subscribe"); + + final String callback = "http://localhost/doNothing"; + final String topic = "http://feeds.feedburner.com/screaming-penguin"; + final long lease_seconds = -1; + final String secret = null; + final String verify_token = "MyVoiceIsMyPassport"; + final HubDAO dao = new InMemoryHubDAO(); + final Notifier notifier = null; + final FeedFetcher fetcher = new HttpURLFeedFetcher(HashMapFeedInfoCache.getInstance()); + Hub instance = new Hub(dao, new AlwaysVerifier(), notifier, fetcher); + + Boolean result = instance.subscribe(callback, topic, "sync", lease_seconds, secret, verify_token); + assertEquals(true, result); + + instance = new Hub(dao, new NeverVerifier(), notifier, fetcher); + result = instance.subscribe(callback, topic, "sync", lease_seconds, secret, verify_token); + assertEquals(false, result); + + result = instance.subscribe(callback, topic, "async", lease_seconds, secret, verify_token); + assertEquals(null, result); + + // Test internal assertions + try { + instance.subscribe(null, topic, "async", lease_seconds, secret, verify_token); + fail(); + } catch (final HttpStatusCodeException e) { + assertEquals(400, e.getStatus()); + LOG.info(e.getMessage()); + } + + try { + instance.subscribe(callback, null, "async", lease_seconds, secret, verify_token); + fail(); + } catch (final HttpStatusCodeException e) { + assertEquals(400, e.getStatus()); + LOG.info(e.getMessage()); + } + + try { + instance.subscribe(callback, topic, "foo", lease_seconds, secret, verify_token); + fail(); + } catch (final HttpStatusCodeException e) { + assertEquals(400, e.getStatus()); + LOG.info(e.getMessage()); + } + + // test general exception + instance = new Hub(dao, new ExceptionVerifier(), notifier, fetcher); + + try { + result = instance.subscribe(callback, topic, "sync", lease_seconds, secret, verify_token); + fail(); + } catch (final HttpStatusCodeException e) { + assertEquals(500, e.getStatus()); + } + } +} diff --git a/rome-certiorem/src/test/java/com/rometools/certiorem/hub/DeltaSyndFeedInfoTest.java b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/DeltaSyndFeedInfoTest.java new file mode 100644 index 0000000..00b25f0 --- /dev/null +++ b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/DeltaSyndFeedInfoTest.java @@ -0,0 +1,62 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.rometools.certiorem.hub; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.URL; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import com.rometools.certiorem.hub.DeltaFeedInfoCache; +import com.rometools.fetcher.impl.HashMapFeedInfoCache; +import com.rometools.fetcher.impl.HttpURLFeedFetcher; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; + +/** + * + * @author najmi + */ +public class DeltaSyndFeedInfoTest { + + private DeltaFeedInfoCache feedInfoCache; + private HttpURLFeedFetcher feedFetcher; + private SyndFeed feed; + + @Before + public void setUp() { + feedInfoCache = new DeltaFeedInfoCache(new HashMapFeedInfoCache()); + feedFetcher = new HttpURLFeedFetcher(feedInfoCache); + } + + /** + * Test of getSyndFeed method, of class DeltaSyndFeedInfo. + */ + @Test + public void testGetSyndFeed() throws Exception { + + feed = feedFetcher.retrieveFeed(getFeedUrl()); + List entries = feed.getEntries(); + assertTrue(!entries.isEmpty()); + + // Fetch again and this time the entries should be empty as none have + // changed. + feed = feedFetcher.retrieveFeed(getFeedUrl()); + entries = feed.getEntries(); + assertTrue(entries.isEmpty()); + } + + private URL getFeedUrl() throws IOException { + final URL feedUrl = new URL("http://news.google.com/news?pz=1&cf=all&ned=us&hl=en&output=rss"); + // URL feedUrl = new + // URL("http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml"); + return feedUrl; + } + +} diff --git a/rome-certiorem/src/test/java/com/rometools/certiorem/hub/ExceptionVerifier.java b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/ExceptionVerifier.java new file mode 100644 index 0000000..3aa877c --- /dev/null +++ b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/ExceptionVerifier.java @@ -0,0 +1,50 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub; + +import com.rometools.certiorem.hub.Verifier; +import com.rometools.certiorem.hub.data.Subscriber; + +/** + * + * @author robert.cooper + */ +public class ExceptionVerifier implements Verifier { + + @Override + public void verifySubscribeAsyncronously(final Subscriber subscriber, final VerificationCallback callback) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean verifySubcribeSyncronously(final Subscriber subscriber) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void verifyUnsubscribeAsyncronously(final Subscriber subscriber, final VerificationCallback callback) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean verifyUnsubcribeSyncronously(final Subscriber subscriber) { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/rome-certiorem/src/test/java/com/rometools/certiorem/hub/NeverVerifier.java b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/NeverVerifier.java new file mode 100644 index 0000000..a5aa95e --- /dev/null +++ b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/NeverVerifier.java @@ -0,0 +1,50 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub; + +import com.rometools.certiorem.hub.Verifier; +import com.rometools.certiorem.hub.data.Subscriber; + +/** + * + * @author robert.cooper + */ +public class NeverVerifier implements Verifier { + + @Override + public void verifySubscribeAsyncronously(final Subscriber subscriber, final VerificationCallback callback) { + callback.onVerify(false); + } + + @Override + public boolean verifySubcribeSyncronously(final Subscriber subscriber) { + return false; + } + + @Override + public void verifyUnsubscribeAsyncronously(final Subscriber subscriber, final VerificationCallback callback) { + callback.onVerify(false); + } + + @Override + public boolean verifyUnsubcribeSyncronously(final Subscriber subscriber) { + return false; + } + +} diff --git a/rome-certiorem/src/test/java/com/rometools/certiorem/hub/data/AbstractDAOTest.java b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/data/AbstractDAOTest.java new file mode 100644 index 0000000..e70016a --- /dev/null +++ b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/data/AbstractDAOTest.java @@ -0,0 +1,97 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.data; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.certiorem.hub.data.HubDAO; +import com.rometools.certiorem.hub.data.Subscriber; + +/** + * + * @author robert.cooper + */ +public abstract class AbstractDAOTest { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractDAOTest.class); + + protected abstract HubDAO get(); + + @Test + public void testSubscribe() { + final HubDAO instance = get(); + LOG.info("{} testSubscribe", instance.getClass().getName()); + final Subscriber subscriber = new Subscriber(); + subscriber.setCallback("http://localhost:9797/noop"); + subscriber.setTopic("http://feeds.feedburner.com/screaming-penguin"); + subscriber.setLeaseSeconds(-1); + subscriber.setVerify("VerifyMe"); + + final Subscriber result = instance.addSubscriber(subscriber); + + Assert.assertTrue("Subscriber not equal", result.equals(subscriber)); + + final List subscribers = instance.subscribersForTopic(subscriber.getTopic()); + + Assert.assertTrue("Subscriber not in result", subscribers.contains(result)); + + } + + @Test + public void testLeaseExpire() throws InterruptedException { + final HubDAO instance = get(); + LOG.info("{} testLeaseExpire", instance.getClass().getName()); + final Subscriber subscriber = new Subscriber(); + subscriber.setCallback("http://localhost:9797/noop"); + subscriber.setTopic("http://feeds.feedburner.com/screaming-penguin"); + subscriber.setLeaseSeconds(1); + subscriber.setVerify("VerifyMe"); + + final Subscriber result = instance.addSubscriber(subscriber); + + Assert.assertEquals("Subscriber not equal", subscriber, result); + // quick test for store. + List subscribers = instance.subscribersForTopic(subscriber.getTopic()); + Assert.assertTrue("Subscriber not in result", subscribers.contains(result)); + // sleep past expiration + Thread.sleep(1100); + subscribers = instance.subscribersForTopic(subscriber.getTopic()); + Assert.assertFalse("Subscriber should have expired", subscribers.contains(result)); + } + + @Test + public void testUnsubscribe() throws InterruptedException { + final HubDAO instance = get(); + LOG.info("{} testUnsubscribe", instance.getClass().getName()); + final Subscriber subscriber = new Subscriber(); + subscriber.setCallback("http://localhost:9797/noop"); + subscriber.setTopic("http://feeds.feedburner.com/screaming-penguin"); + subscriber.setLeaseSeconds(1); + subscriber.setVerify("VerifyMe"); + + // TODO + // final Subscriber result = instance.addSubscriber(subscriber); + + } +} diff --git a/rome-certiorem/src/test/java/com/rometools/certiorem/hub/data/ram/InMemoryDAOTest.java b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/data/ram/InMemoryDAOTest.java new file mode 100644 index 0000000..26917e3 --- /dev/null +++ b/rome-certiorem/src/test/java/com/rometools/certiorem/hub/data/ram/InMemoryDAOTest.java @@ -0,0 +1,40 @@ +/** + * + * Copyright (C) The ROME Team 2011 + * + * + * 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.rometools.certiorem.hub.data.ram; + +import com.rometools.certiorem.hub.data.AbstractDAOTest; +import com.rometools.certiorem.hub.data.HubDAO; +import com.rometools.certiorem.hub.data.ram.InMemoryHubDAO; + +/** + * + * @author robert.cooper + */ +public class InMemoryDAOTest extends AbstractDAOTest { + private final InMemoryHubDAO dao = new InMemoryHubDAO(); + + public InMemoryDAOTest() { + } + + @Override + protected HubDAO get() { + return dao; + } + +} \ No newline at end of file diff --git a/rome-certiorem/src/test/resources/.gitignore b/rome-certiorem/src/test/resources/.gitignore new file mode 100644 index 0000000..53b845b --- /dev/null +++ b/rome-certiorem/src/test/resources/.gitignore @@ -0,0 +1 @@ +# needed to commit empty folder \ No newline at end of file diff --git a/src/test/resources/logback-test.xml b/rome-certiorem/src/test/resources/logback-test.xml similarity index 90% rename from src/test/resources/logback-test.xml rename to rome-certiorem/src/test/resources/logback-test.xml index 44dea42..c34b099 100644 --- a/src/test/resources/logback-test.xml +++ b/rome-certiorem/src/test/resources/logback-test.xml @@ -1,13 +1,13 @@ - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n - - - - - - - + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + \ No newline at end of file diff --git a/rome-fetcher/.gitignore b/rome-fetcher/.gitignore new file mode 100644 index 0000000..83a7c0c --- /dev/null +++ b/rome-fetcher/.gitignore @@ -0,0 +1,7 @@ +.classpath +.project +.settings +target +.idea +*.iml +atlassian-ide-plugin.xml diff --git a/rome-fetcher/LICENSE b/rome-fetcher/LICENSE new file mode 100644 index 0000000..f43cdb1 --- /dev/null +++ b/rome-fetcher/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/rome-fetcher/README.md b/rome-fetcher/README.md new file mode 100644 index 0000000..49d2dfe --- /dev/null +++ b/rome-fetcher/README.md @@ -0,0 +1,7 @@ +rome +==== + +ROME is a set of RSS and Atom Utilities for Java. It makes it easy to work in Java with most syndication formats: RSS 0.90, RSS 0.91 Netscape, +RSS 0.91 Userland, RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, RSS 2.0, Atom 0.3, Atom 1.0 + +More Information: http://rometools.github.io/rome-fetcher/ diff --git a/rome-fetcher/pom.xml b/rome-fetcher/pom.xml new file mode 100644 index 0000000..5d86063 --- /dev/null +++ b/rome-fetcher/pom.xml @@ -0,0 +1,123 @@ + + + + 4.0.0 + + + com.rometools + rome-parent + 1.6.0-SNAPSHOT + + + rome-fetcher + 1.6.0-SNAPSHOT + jar + + rome-fetcher + + A well behaved feed fetcher API for ROME + + http://rometools.github.io/rome-fetcher/ + + + scm:git:ssh://github.com/rometools/rome-fetcher.git + scm:git:ssh://git@github.com/rometools/rome-fetcher.git + https://github.com/rometools/rome-fetcher + + + + + Nick Lothian + http://nicklothian.com + + + Robert Cooper + kebernet@gmail.comM + + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + gh-pages + ${project.scm.developerConnection} + ${project.build.directory}/site + + + + org.apache.felix + maven-bundle-plugin + + + + com.rometools.fetcher, + com.rometools.fetcher.impl + + + com.rometools.rome.feed.impl, + com.rometools.rome.feed.synd, + com.rometools.rome.io, + com.rometools.utils, + org.apache.commons.httpclient;resolution:=optional, + org.apache.commons.httpclient.auth;resolution:=optional, + org.apache.commons.httpclient.methods;resolution:=optional, + org.apache.commons.httpclient.params;resolution:=optional, + org.slf4j + + + + + + + + + + + com.rometools + rome + 1.6.0-SNAPSHOT + + + commons-httpclient + commons-httpclient + + + + javax.servlet + servlet-api + test + + + jetty + jetty + test + + + ch.qos.logback + logback-classic + test + + + junit + junit + test + + + + diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/FeedFetcher.java b/rome-fetcher/src/main/java/com/rometools/fetcher/FeedFetcher.java new file mode 100644 index 0000000..05f0868 --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/FeedFetcher.java @@ -0,0 +1,120 @@ +/* + * 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.rometools.fetcher; + +import java.io.IOException; +import java.net.URL; + +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.FeedException; + +public interface FeedFetcher { + /** + *

+ * The default user agent. It is not marked final so buggy java compiler will not write this + * string into all classes that reference it. + *

+ * + *

+ * http://tinyurl.com/64t5n points to https://rome.dev.java.net Some servers ban user agents + * with "Java" in the name. + *

+ * + */ + public static String DEFAULT_USER_AGENT = "Rome Client (http://tinyurl.com/64t5n)"; + + /** + * @param string The User-Agent to sent to servers + */ + public abstract void setUserAgent(String string); + + /** + * @return the User-Agent currently being sent to servers + */ + public abstract String getUserAgent(); + + /** + *

+ * Turn on or off rfc3229 delta encoding + *

+ * + *

+ * See http://www.ietf.org/rfc/rfc3229.txt and + * http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html + *

+ * + *

+ * NOTE: This is experimental and feedback is welcome! + *

+ * + * @param useDeltaEncoding + */ + public abstract void setUsingDeltaEncoding(boolean useDeltaEncoding); + + /** + *

+ * Is this fetcher using rfc3229 delta encoding? + *

+ * + * @return + */ + public abstract boolean isUsingDeltaEncoding(); + + /** + *

+ * Add a FetcherListener. + *

+ * + *

+ * The FetcherListener will receive an FetcherEvent when a Fetcher event (feed polled, + * retrieved, etc) occurs + *

+ * + * @param listener The FetcherListener to recieve the event + */ + public abstract void addFetcherEventListener(FetcherListener listener); + + /** + *

+ * Remove a FetcherListener + *

+ * + * @param listener The FetcherListener to remove + */ + public abstract void removeFetcherEventListener(FetcherListener listener); + + /** + * Retrieve a feed over HTTP + * + * @param feedUrl A non-null URL of a RSS/Atom feed to retrieve + * @return A {@link com.rometools.rome.feed.synd.SyndFeed} object + * @throws IllegalArgumentException if the URL is null; + * @throws IOException if a TCP error occurs + * @throws FeedException if the feed is not valid + * @throws FetcherException if a HTTP error occurred + */ + public abstract SyndFeed retrieveFeed(URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException; + + public SyndFeed retrieveFeed(String userAgent, URL url) throws IllegalArgumentException, IOException, FeedException, FetcherException; + + /** + * If set to true, the WireFeed will be made accessible from the SyndFeed object returned from + * the Fetcher via the originalWireFeed() method. Each Entry in the feed will have the + * corresponding wireEntry property set. + */ + void setPreserveWireFeed(boolean preserveWireFeed); +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/FetcherEvent.java b/rome-fetcher/src/main/java/com/rometools/fetcher/FetcherEvent.java new file mode 100644 index 0000000..6ed4a0c --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/FetcherEvent.java @@ -0,0 +1,90 @@ +package com.rometools.fetcher; + +import java.util.EventObject; + +import com.rometools.rome.feed.synd.SyndFeed; + +/** + * Implementation note: FetcherEvent is not thread safe. Make sure that they are only ever accessed + * by one thread. If necessary, make all getters and setters synchronized, or alternatively make all + * fields final. + * + * @author nl + */ +public class FetcherEvent extends EventObject { + + private static final long serialVersionUID = 1L; + + public static final String EVENT_TYPE_FEED_POLLED = "FEED_POLLED"; + public static final String EVENT_TYPE_FEED_RETRIEVED = "FEED_RETRIEVED"; + public static final String EVENT_TYPE_FEED_UNCHANGED = "FEED_UNCHANGED"; + + private String eventType; + private String urlString; + private SyndFeed feed; + + public FetcherEvent(final Object source) { + super(source); + } + + public FetcherEvent(final Object source, final String urlStr, final String eventType) { + this(source); + setUrlString(urlStr); + setEventType(eventType); + } + + public FetcherEvent(final Object source, final String urlStr, final String eventType, final SyndFeed feed) { + this(source, urlStr, eventType); + setFeed(feed); + } + + /** + * @return Returns the feed. + * + *

+ * The feed will only be set if the eventType is EVENT_TYPE_FEED_RETRIEVED + *

+ */ + public SyndFeed getFeed() { + return feed; + } + + /** + * @param feed The feed to set. + * + *

+ * The feed will only be set if the eventType is EVENT_TYPE_FEED_RETRIEVED + *

+ */ + public void setFeed(final SyndFeed feed) { + this.feed = feed; + } + + /** + * @return Returns the eventType. + */ + public String getEventType() { + return eventType; + } + + /** + * @param eventType The eventType to set. + */ + public void setEventType(final String eventType) { + this.eventType = eventType; + } + + /** + * @return Returns the urlString. + */ + public String getUrlString() { + return urlString; + } + + /** + * @param urlString The urlString to set. + */ + public void setUrlString(final String urlString) { + this.urlString = urlString; + } +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/FetcherException.java b/rome-fetcher/src/main/java/com/rometools/fetcher/FetcherException.java new file mode 100644 index 0000000..447ab2f --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/FetcherException.java @@ -0,0 +1,51 @@ +/* + * 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.rometools.fetcher; + +/** + * @author Nick Lothian + * + */ +public class FetcherException extends Exception { + private static final long serialVersionUID = 1L; + + int responseCode; + + public FetcherException(final Throwable cause) { + super(); + initCause(cause); + } + + public FetcherException(final String message, final Throwable cause) { + super(message); + initCause(cause); + } + + public FetcherException(final String message) { + super(message); + } + + public FetcherException(final int responseCode, final String message) { + this(message); + this.responseCode = responseCode; + } + + public int getResponseCode() { + return responseCode; + } + +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/FetcherListener.java b/rome-fetcher/src/main/java/com/rometools/fetcher/FetcherListener.java new file mode 100644 index 0000000..617532c --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/FetcherListener.java @@ -0,0 +1,16 @@ +package com.rometools.fetcher; + +import java.util.EventListener; + +public interface FetcherListener extends EventListener { + + /** + *

+ * Called when a fetcher event occurs + *

+ * + * @param event the event that fired + */ + public void fetcherEvent(FetcherEvent event); + +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/impl/AbstractFeedFetcher.java b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/AbstractFeedFetcher.java new file mode 100644 index 0000000..15f07ac --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/AbstractFeedFetcher.java @@ -0,0 +1,225 @@ +/* + * 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.rometools.fetcher.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URLConnection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.fetcher.FeedFetcher; +import com.rometools.fetcher.FetcherEvent; +import com.rometools.fetcher.FetcherException; +import com.rometools.fetcher.FetcherListener; +import com.rometools.rome.feed.synd.SyndFeed; + +public abstract class AbstractFeedFetcher implements FeedFetcher { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractFeedFetcher.class); + + private final Set listeners; + private String userAgent; + private boolean usingDeltaEncoding; + private boolean preserveWireFeed; + + public AbstractFeedFetcher() { + + listeners = Collections.synchronizedSet(new HashSet()); + + final Properties props = new Properties(System.getProperties()); + final String resourceName = "fetcher.properties"; + + try { + + InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resourceName); + if (inputStream == null) { + inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName); + } + + if (inputStream != null) { + props.load(inputStream); + System.getProperties().putAll(props); + inputStream.close(); + } else { + LOG.warn("Could not find {} on classpath", resourceName); + } + + } catch (final IOException e) { + // do nothing - we don't want to fail just because we could not find the version + LOG.error("Error reading {} from classpath: {}", resourceName, e.getMessage()); + } + + setUserAgent(DEFAULT_USER_AGENT + " Ver: " + System.getProperty("rome.fetcher.version", "UNKNOWN")); + } + + /** + * @return the User-Agent currently being sent to servers + */ + @Override + public synchronized String getUserAgent() { + return userAgent; + } + + /** + * @param string The User-Agent to sent to servers + */ + @Override + public synchronized void setUserAgent(final String string) { + userAgent = string; + } + + /** + * @param eventType The event type to fire + * @param connection the current connection + */ + protected void fireEvent(final String eventType, final URLConnection connection) { + fireEvent(eventType, connection.getURL().toExternalForm(), null); + } + + /** + * @param eventType The event type to fire + * @param connection the current connection + * @param feed The feed to pass to the event + */ + protected void fireEvent(final String eventType, final URLConnection connection, final SyndFeed feed) { + fireEvent(eventType, connection.getURL().toExternalForm(), feed); + } + + /** + * @param eventType The event type to fire + * @param urlStr the current url as a string + */ + protected void fireEvent(final String eventType, final String urlStr) { + fireEvent(eventType, urlStr, null); + } + + /** + * @param eventType The event type to fire + * @param urlStr the current url as a string + * @param feed The feed to pass to the event + */ + protected void fireEvent(final String eventType, final String urlStr, final SyndFeed feed) { + final FetcherEvent fetcherEvent = new FetcherEvent(this, urlStr, eventType, feed); + synchronized (listeners) { + for (final FetcherListener fetcherEventListener : listeners) { + fetcherEventListener.fetcherEvent(fetcherEvent); + } + } + } + + @Override + public void addFetcherEventListener(final FetcherListener listener) { + if (listener != null) { + listeners.add(listener); + } + } + + @Override + public void removeFetcherEventListener(final FetcherListener listener) { + if (listener != null) { + listeners.remove(listener); + } + } + + /** + * @return Returns the useDeltaEncoding. + */ + @Override + public synchronized boolean isUsingDeltaEncoding() { + return usingDeltaEncoding; + } + + /** + * @param useDeltaEncoding The useDeltaEncoding to set. + */ + @Override + public synchronized void setUsingDeltaEncoding(final boolean useDeltaEncoding) { + usingDeltaEncoding = useDeltaEncoding; + } + + /** + *

+ * Handles HTTP error codes. + *

+ * + * @param responseCode the HTTP response code + * @throws FetcherException if response code is in the range 400 to 599 inclusive + */ + protected void handleErrorCodes(final int responseCode) throws FetcherException { + // Handle 2xx codes as OK, so ignore them here + // 3xx codes are handled by the HttpURLConnection class + if (responseCode == 403) { + // Authentication is required + throwAuthenticationError(responseCode); + } else if (responseCode >= 400 && responseCode < 500) { + throw4XXError(responseCode); + } else if (responseCode >= 500 && responseCode < 600) { + throw new FetcherException(responseCode, "The server encounted an error. HTTP Response code was:" + responseCode); + } + } + + protected void throw4XXError(final int responseCode) throws FetcherException { + throw new FetcherException(responseCode, "The requested resource could not be found. HTTP Response code was:" + responseCode); + } + + protected void throwAuthenticationError(final int responseCode) throws FetcherException { + throw new FetcherException(responseCode, "Authentication required for that resource. HTTP Response code was:" + responseCode); + } + + /** + *

+ * Combine the entries in two feeds into a single feed. + *

+ * + *

+ * The returned feed will have the same data as the newFeed parameter, with the entries from + * originalFeed appended to the end of its entries. + *

+ * + * @param originalFeed + * @param newFeed + * @return + */ + public static SyndFeed combineFeeds(final SyndFeed originalFeed, final SyndFeed newFeed) { + try { + final SyndFeed result = (SyndFeed) newFeed.clone(); + result.getEntries().addAll(result.getEntries().size(), originalFeed.getEntries()); + return result; + } catch (final CloneNotSupportedException e) { + final IllegalArgumentException iae = new IllegalArgumentException("Cannot clone feed"); + iae.initCause(e); + throw iae; + } + } + + public boolean isPreserveWireFeed() { + return preserveWireFeed; + } + + @Override + public void setPreserveWireFeed(final boolean preserveWireFeed) { + this.preserveWireFeed = preserveWireFeed; + } + +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/impl/AbstractFeedFetcherBeanInfo.java b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/AbstractFeedFetcherBeanInfo.java new file mode 100644 index 0000000..5bac21e --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/AbstractFeedFetcherBeanInfo.java @@ -0,0 +1,33 @@ +package com.rometools.fetcher.impl; + +import java.beans.EventSetDescriptor; +import java.beans.SimpleBeanInfo; +import java.lang.reflect.Method; + +import com.rometools.fetcher.FetcherEvent; +import com.rometools.fetcher.FetcherListener; + +public class AbstractFeedFetcherBeanInfo extends SimpleBeanInfo { + + @Override + public EventSetDescriptor[] getEventSetDescriptors() { + + try { + + // get the class object which we'll describe + final Class clz = AbstractFeedFetcher.class; + final Method addMethod = clz.getMethod("addFetcherEventListener", new Class[] { FetcherListener.class }); + final Method removeMethod = clz.getMethod("removeFetcherEventListener", new Class[] { FetcherListener.class }); + final Method listenerMethod = FetcherListener.class.getMethod("fetcherEvent", new Class[] { FetcherEvent.class }); + final EventSetDescriptor est = new EventSetDescriptor("fetcherEvent", clz, new Method[] { listenerMethod }, addMethod, removeMethod); + return new EventSetDescriptor[] { est }; + + } catch (final Exception e) { + // IntrospectionException, SecurityException and/or NoSuchMethodException can be thrown + // here. The best we can do is to convert them to runtime exceptions + throw new RuntimeException(e); + } + + } + +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/impl/DiskFeedInfoCache.java b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/DiskFeedInfoCache.java new file mode 100644 index 0000000..92bc9b1 --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/DiskFeedInfoCache.java @@ -0,0 +1,158 @@ +/* + * Copyright 2005 Sun Microsystems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.fetcher.impl; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.URL; + +import com.rometools.utils.IO; + +/** + * Disk based feed cache. + */ +public class DiskFeedInfoCache implements FeedFetcherCache { + + protected String cachePath = null; + + public DiskFeedInfoCache(final String cachePath) { + this.cachePath = cachePath; + } + + @Override + public SyndFeedInfo getFeedInfo(final URL url) { + final String fileName = generateFilename(url); + return getFeedInfo(fileName); + } + + @Override + public void setFeedInfo(final URL url, final SyndFeedInfo feedInfo) { + + final String fileName = generateFilename(url); + + FileOutputStream fos = null; + ObjectOutputStream oos = null; + + try { + + fos = new FileOutputStream(fileName); + oos = new ObjectOutputStream(fos); + oos.writeObject(feedInfo); + fos.flush(); + + } catch (final FileNotFoundException e) { + + throw new RuntimeException("Error while writing to cache", e); + + } catch (final IOException e) { + + throw new RuntimeException("Error while writing to cache", e); + + } finally { + + IO.closeQuietly(fos); + IO.closeQuietly(oos); + + } + + } + + @Override + public synchronized void clear() { + final File file = new File(cachePath); + // only do the delete if the directory exists + if (file.exists() && file.canWrite()) { + // make the directory empty + final String[] files = file.list(); + final int len = files.length; + for (int i = 0; i < len; i++) { + final File deleteMe = new File(cachePath + File.separator + files[i]); + deleteMe.delete(); + } + // don't delete the cache directory + } + } + + @Override + public SyndFeedInfo remove(final URL url) { + final String fileName = generateFilename(url); + final SyndFeedInfo info = getFeedInfo(fileName); + if (info != null) { + final File file = new File(fileName); + if (file.exists()) { + file.delete(); + } + } + return info; + } + + private SyndFeedInfo getFeedInfo(final String fileName) { + + SyndFeedInfo info = null; + FileInputStream fis = null; + ObjectInputStream ois = null; + + try { + + fis = new FileInputStream(fileName); + ois = new ObjectInputStream(fis); + info = (SyndFeedInfo) ois.readObject(); + + } catch (final FileNotFoundException e) { + + // feed is not cached yet + + } catch (final ClassNotFoundException e) { + + throw new RuntimeException("Unable to read from cache", e); + + } catch (final IOException e) { + + throw new RuntimeException("Unable to read from cache", e); + + } finally { + + IO.closeQuietly(fis); + IO.closeQuietly(ois); + + } + + return info; + + } + + private static String replaceNonAlphanumeric(final String string, final char character) { + final StringBuffer buffer = new StringBuffer(string.length()); + for (final char singleChar : string.toCharArray()) { + if (Character.isLetterOrDigit(singleChar)) { + buffer.append(singleChar); + } else { + buffer.append(character); + } + } + return buffer.toString(); + } + + private String generateFilename(final URL url) { + return cachePath + File.separator + "feed_" + replaceNonAlphanumeric(url.toString(), '_').trim(); + } + +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/impl/FeedFetcherCache.java b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/FeedFetcherCache.java new file mode 100644 index 0000000..4c0ff0a --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/FeedFetcherCache.java @@ -0,0 +1,60 @@ +/* + * 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.rometools.fetcher.impl; + +import java.net.URL; + +/** + *

+ * An interface to allow caching of feed details. Implementing this allows the + * {@link com.rometools.fetcher.io.HttpURLFeedFetcher} class to enable conditional gets + *

+ * + * @author Nick Lothian + * + */ +public interface FeedFetcherCache { + + /** + * Get a SyndFeedInfo object from the cache. + * + * @param feedUrl The url of the feed + * @return A SyndFeedInfo or null if it is not in the cache + */ + public SyndFeedInfo getFeedInfo(URL feedUrl); + + /** + * Add a SyndFeedInfo object to the cache + * + * @param feedUrl The url of the feed + * @param syndFeedInfo A SyndFeedInfo for the feed + */ + public void setFeedInfo(URL feedUrl, SyndFeedInfo syndFeedInfo); + + /** + * Removes all items from the cache. + */ + public void clear(); + + /** + * Removes the SyndFeedInfo identified by the url from the cache. + * + * @return The removed SyndFeedInfo + */ + public SyndFeedInfo remove(URL feedUrl); + +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/impl/HashMapFeedInfoCache.java b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/HashMapFeedInfoCache.java new file mode 100644 index 0000000..7508ce7 --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/HashMapFeedInfoCache.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.rometools.fetcher.impl; + +import java.io.Serializable; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + *

+ * A very simple implementation of the {@link com.rometools.fetcher.impl.FeedFetcherCache} + * interface. + *

+ * + *

+ * This implementation uses a HashMap to cache retrieved feeds. This implementation is most suitible + * for sort term (client aggregator?) use, as the memory usage will increase over time as the number + * of feeds in the cache increases. + *

+ * + * @author Nick Lothian + * + */ +public class HashMapFeedInfoCache implements FeedFetcherCache, Serializable { + + private static final long serialVersionUID = 1L; + + static HashMapFeedInfoCache instance; + + private Map infoCache; + + /** + *

+ * Constructor for HashMapFeedInfoCache + *

+ * + *

+ * Only use this if you want multiple instances of the cache. Usually getInstance() is more + * appropriate. + *

+ * + */ + public HashMapFeedInfoCache() { + setInfoCache(createInfoCache()); + } + + /** + * Get the global instance of the cache + * + * @return an implementation of FeedFetcherCache + */ + public static synchronized FeedFetcherCache getInstance() { + if (instance == null) { + instance = new HashMapFeedInfoCache(); + } + return instance; + } + + protected Map createInfoCache() { + return Collections.synchronizedMap(new HashMap()); + } + + protected Object get(final Object key) { + return getInfoCache().get(key); + } + + /** + * @see extensions.io.FeedFetcherCache#getFeedInfo(java.net.URL) + */ + @Override + public SyndFeedInfo getFeedInfo(final URL feedUrl) { + return (SyndFeedInfo) get(feedUrl.toString()); + } + + protected void put(final String key, final SyndFeedInfo value) { + getInfoCache().put(key, value); + } + + /** + * @see extensions.io.FeedFetcherCache#setFeedInfo(java.net.URL, extensions.io.SyndFeedInfo) + */ + @Override + public void setFeedInfo(final URL feedUrl, final SyndFeedInfo syndFeedInfo) { + put(feedUrl.toString(), syndFeedInfo); + } + + protected synchronized final Map getInfoCache() { + return infoCache; + } + + /** + * The API of this class indicates that map must thread safe. In other words, be sure to wrap it + * in a synchronized map unless you know what you are doing. + * + * @param map the map to use as the info cache. + */ + protected synchronized final void setInfoCache(final Map map) { + infoCache = map; + } + + /** + * @see com.rometools.rome.fetcher.impl.FeedFetcherCache#clear() + */ + @Override + public void clear() { + synchronized (infoCache) { + infoCache.clear(); + } + } + + /** + * @see com.rometools.rome.fetcher.impl.FeedFetcherCache#remove(java.net.URL) + */ + @Override + public SyndFeedInfo remove(final URL url) { + if (url == null) { + return null; + } + + return infoCache.remove(url.toString()); + } + +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/impl/HttpClientFeedFetcher.java b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/HttpClientFeedFetcher.java new file mode 100644 index 0000000..c15833f --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/HttpClientFeedFetcher.java @@ -0,0 +1,386 @@ +/* + * 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.rometools.fetcher.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; +import java.util.zip.GZIPInputStream; + +import org.apache.commons.httpclient.Credentials; +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpMethod; +import org.apache.commons.httpclient.HttpMethodRetryHandler; +import org.apache.commons.httpclient.HttpState; +import org.apache.commons.httpclient.auth.AuthScope; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.params.HttpClientParams; +import org.apache.commons.httpclient.params.HttpMethodParams; + +import com.rometools.fetcher.FetcherEvent; +import com.rometools.fetcher.FetcherException; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.XmlReader; +import com.rometools.utils.IO; + +/** + * @author Nick Lothian + */ +public class HttpClientFeedFetcher extends AbstractFeedFetcher { + + private CredentialSupplier credentialSupplier; + private FeedFetcherCache feedInfoCache; + private volatile HttpClientMethodCallbackIntf httpClientMethodCallback; + private volatile HttpClientParams httpClientParams; + private Map customRequestHeaders; + + public HttpClientFeedFetcher() { + this(null, null); + } + + public HttpClientFeedFetcher(final FeedFetcherCache cache) { + this(cache, null); + } + + public HttpClientFeedFetcher(final FeedFetcherCache cache, final CredentialSupplier credentialSupplier) { + setHttpClientParams(new HttpClientParams()); + setFeedInfoCache(cache); + setCredentialSupplier(credentialSupplier); + } + + @Override + public SyndFeed retrieveFeed(final URL url) throws IllegalArgumentException, IOException, FeedException, FetcherException { + return this.retrieveFeed(getUserAgent(), url); + } + + @Override + public SyndFeed retrieveFeed(final String userAgent, final URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException { + + if (feedUrl == null) { + throw new IllegalArgumentException("null is not a valid URL"); + } + + final HttpClient client = new HttpClient(httpClientParams); + + if (credentialSupplier != null) { + + final HttpClientParams params = client.getParams(); + params.setAuthenticationPreemptive(true); + + final String host = feedUrl.getHost(); + final Credentials credentials = credentialSupplier.getCredentials(null, host); + if (credentials != null) { + final AuthScope authScope = new AuthScope(host, -1); + final HttpState state = client.getState(); + state.setCredentials(authScope, credentials); + } + + } + + System.setProperty("httpclient.useragent", userAgent); + + final String urlStr = feedUrl.toString(); + final HttpMethod method = new GetMethod(urlStr); + + if (customRequestHeaders == null) { + method.addRequestHeader("Accept-Encoding", "gzip"); + method.addRequestHeader("User-Agent", userAgent); + + } else { + for (final Map.Entry entry : customRequestHeaders.entrySet()) { + method.addRequestHeader(entry.getKey(), entry.getValue()); + } + if (!customRequestHeaders.containsKey("Accept-Encoding")) { + method.addRequestHeader("Accept-Encoding", "gzip"); + } + if (!customRequestHeaders.containsKey("User-Agent")) { + method.addRequestHeader("User-Agent", userAgent); + } + } + + method.setFollowRedirects(true); + + if (httpClientMethodCallback != null) { + synchronized (httpClientMethodCallback) { + httpClientMethodCallback.afterHttpClientMethodCreate(method); + } + } + + final FeedFetcherCache cache = getFeedInfoCache(); + + if (cache != null) { + // retrieve feed + try { + + if (isUsingDeltaEncoding()) { + method.setRequestHeader("A-IM", "feed"); + } + + // try to get the feed info from the cache + SyndFeedInfo syndFeedInfo = cache.getFeedInfo(feedUrl); + + if (syndFeedInfo != null) { + + method.setRequestHeader("If-None-Match", syndFeedInfo.getETag()); + + final Object lastModifiedHeader = syndFeedInfo.getLastModified(); + if (lastModifiedHeader instanceof String) { + method.setRequestHeader("If-Modified-Since", (String) lastModifiedHeader); + } + + } + + final int statusCode = client.executeMethod(method); + fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, urlStr); + handleErrorCodes(statusCode); + + SyndFeed feed = getFeed(syndFeedInfo, urlStr, method, statusCode); + + syndFeedInfo = buildSyndFeedInfo(feedUrl, urlStr, method, feed, statusCode); + + cache.setFeedInfo(feedUrl, syndFeedInfo); + + // the feed may have been modified to pick up cached values + // (eg - for delta encoding) + feed = syndFeedInfo.getSyndFeed(); + + return feed; + + } finally { + + method.releaseConnection(); + + } + + } else { + + // cache is not in use + try { + + final int statusCode = client.executeMethod(method); + fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, urlStr); + handleErrorCodes(statusCode); + + return getFeed(null, urlStr, method, statusCode); + + } finally { + + method.releaseConnection(); + + } + + } + + } + + private SyndFeed getFeed(final SyndFeedInfo syndFeedInfo, final String urlStr, final HttpMethod method, final int statusCode) throws IOException, + HttpException, FetcherException, FeedException { + + if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED && syndFeedInfo != null) { + fireEvent(FetcherEvent.EVENT_TYPE_FEED_UNCHANGED, urlStr); + return syndFeedInfo.getSyndFeed(); + } + + final SyndFeed feed = retrieveFeed(urlStr, method); + fireEvent(FetcherEvent.EVENT_TYPE_FEED_RETRIEVED, urlStr, feed); + return feed; + } + + private SyndFeedInfo buildSyndFeedInfo(final URL feedUrl, final String urlStr, final HttpMethod method, SyndFeed feed, final int statusCode) + throws MalformedURLException { + + SyndFeedInfo syndFeedInfo; + syndFeedInfo = new SyndFeedInfo(); + + // this may be different to feedURL because of 3XX redirects + syndFeedInfo.setUrl(new URL(urlStr)); + syndFeedInfo.setId(feedUrl.toString()); + + final Header imHeader = method.getResponseHeader("IM"); + if (imHeader != null && imHeader.getValue().contains("feed") && isUsingDeltaEncoding()) { + + final FeedFetcherCache cache = getFeedInfoCache(); + + if (cache != null && statusCode == 226) { + // client is setup to use http delta encoding and the server supports it and has + // returned a delta encoded response. This response only includes new items + final SyndFeedInfo cachedInfo = cache.getFeedInfo(feedUrl); + + if (cachedInfo != null) { + final SyndFeed cachedFeed = cachedInfo.getSyndFeed(); + + // set the new feed to be the orginal feed plus the new items + feed = combineFeeds(cachedFeed, feed); + } + } + } + + final Header lastModifiedHeader = method.getResponseHeader("Last-Modified"); + if (lastModifiedHeader != null) { + syndFeedInfo.setLastModified(lastModifiedHeader.getValue()); + } + + final Header eTagHeader = method.getResponseHeader("ETag"); + if (eTagHeader != null) { + syndFeedInfo.setETag(eTagHeader.getValue()); + } + + syndFeedInfo.setSyndFeed(feed); + + return syndFeedInfo; + } + + private SyndFeed retrieveFeed(final String urlStr, final HttpMethod method) throws IOException, HttpException, FetcherException, FeedException { + + final Header contentEncodingHeader = method.getResponseHeader("Content-Encoding"); + + final InputStream stream; + if (contentEncodingHeader != null && "gzip".equalsIgnoreCase(contentEncodingHeader.getValue())) { + stream = new GZIPInputStream(method.getResponseBodyAsStream()); + } else { + stream = method.getResponseBodyAsStream(); + } + + try { + + final Header contentTypeHeader = method.getResponseHeader("Content-Type"); + + final XmlReader reader; + if (contentTypeHeader != null) { + reader = new XmlReader(stream, contentTypeHeader.getValue(), true); + } else { + reader = new XmlReader(stream, true); + } + + final SyndFeedInput syndFeedInput = new SyndFeedInput(); + syndFeedInput.setPreserveWireFeed(isPreserveWireFeed()); + + return syndFeedInput.build(reader); + + } finally { + + IO.close(stream); + + } + + } + + public synchronized void setRetryHandler(final HttpMethodRetryHandler handler) { + httpClientParams.setParameter(HttpMethodParams.RETRY_HANDLER, handler); + } + + /** + * @param timeout Sets the connect timeout for the HttpClient but using the URLConnection method + * name. Uses the HttpClientParams method setConnectionManagerTimeout instead of + * setConnectTimeout + * + */ + public synchronized void setConnectTimeout(final int timeout) { + httpClientParams.setConnectionManagerTimeout(timeout); + } + + /** + * @return The currently used connect timeout for the HttpClient but using the URLConnection + * method name. Uses the HttpClientParams method getConnectionManagerTimeout instead of + * getConnectTimeout + * + */ + public int getConnectTimeout() { + return (int) getHttpClientParams().getConnectionManagerTimeout(); + } + + public synchronized void setCredentialSupplier(final CredentialSupplier credentialSupplier) { + this.credentialSupplier = credentialSupplier; + } + + public synchronized CredentialSupplier getCredentialSupplier() { + return credentialSupplier; + } + + public synchronized void setFeedInfoCache(final FeedFetcherCache feedInfoCache) { + this.feedInfoCache = feedInfoCache; + } + + public synchronized FeedFetcherCache getFeedInfoCache() { + return feedInfoCache; + } + + public synchronized void setHttpClientMethodCallback(final HttpClientMethodCallbackIntf httpClientMethodCallback) { + this.httpClientMethodCallback = httpClientMethodCallback; + } + + public HttpClientMethodCallbackIntf getHttpClientMethodCallback() { + return httpClientMethodCallback; + } + + public synchronized void setHttpClientParams(final HttpClientParams httpClientParams) { + this.httpClientParams = httpClientParams; + } + + public synchronized HttpClientParams getHttpClientParams() { + return httpClientParams; + } + + /** + * @return The currently used read timeout for the URLConnection, 0 is unlimited, i.e. no + * timeout + */ + public synchronized void setReadTimeout(final int timeout) { + httpClientParams.setSoTimeout(timeout); + } + + /** + * @return timeout the read timeout for the URLConnection to a specified timeout, in + * milliseconds. + */ + public int getReadTimeout() { + return getHttpClientParams().getSoTimeout(); + } + + /** + * Apply any request headers to the HTTP method call. + * + * @param customRequestHeaders + */ + public synchronized void setCustomRequestHeaders(final Map customRequestHeaders) { + this.customRequestHeaders = customRequestHeaders; + } + + public interface CredentialSupplier { + public Credentials getCredentials(String realm, String host); + } + + public interface HttpClientMethodCallbackIntf { + + /** + * Allows access to the underlying HttpClient HttpMethod object. Note that in most cases, + * method.setRequestHeader(String, String) is what you want to do (rather than + * method.addRequestHeader(String, String)) + * + * @param method + */ + public void afterHttpClientMethodCreate(HttpMethod method); + } + +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/impl/HttpURLFeedFetcher.java b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/HttpURLFeedFetcher.java new file mode 100644 index 0000000..70a8863 --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/HttpURLFeedFetcher.java @@ -0,0 +1,329 @@ +/* + * 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.rometools.fetcher.impl; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.zip.GZIPInputStream; + +import com.rometools.fetcher.FetcherEvent; +import com.rometools.fetcher.FetcherException; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.XmlReader; +import com.rometools.utils.IO; + +/** + *

+ * Class to retrieve syndication files via HTTP. + *

+ * + *

+ * If passed a {@link com.rometools.fetcher.impl.FeedFetcherCache} in the constructor it will use + * conditional gets to only retrieve modified content. + *

+ * + *

+ * The class uses the Accept-Encoding: gzip header to retrieve gzipped feeds where supported by the + * server. + *

+ * + *

+ * Simple usage: + * + *

+ * // create the cache
+ * FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getFeedInfoCache();
+ * // retrieve the feed the first time
+ * // any subsequent request will use conditional gets and only
+ * // retrieve the resource if it has changed
+ * SyndFeed feed = new HttpURLFeedFetcher(feedInfoCache).retrieveFeed(feedUrl);
+ * 
+ * + *

+ * + * @see http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers + * @see http://diveintomark.org/archives/2003/07/21/atom_aggregator_behavior_http_level + * @see http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html + * @author Nick Lothian + */ +public class HttpURLFeedFetcher extends AbstractFeedFetcher { + + private volatile int connectTimeout = -1; + + static final int POLL_EVENT = 1; + static final int RETRIEVE_EVENT = 2; + static final int UNCHANGED_EVENT = 3; + + private FeedFetcherCache feedInfoCache; + + /** + * Constructor to use HttpURLFeedFetcher without caching of feeds + * + */ + public HttpURLFeedFetcher() { + this(null); + } + + /** + * Constructor to enable HttpURLFeedFetcher to cache feeds + * + * @param feedInfoCache - an instance of the FeedFetcherCache interface + */ + public HttpURLFeedFetcher(final FeedFetcherCache feedInfoCache) { + setFeedInfoCache(feedInfoCache); + } + + @Override + public SyndFeed retrieveFeed(final URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException { + return this.retrieveFeed(getUserAgent(), feedUrl); + } + + /** + * Retrieve a feed over HTTP + * + * @param feedUrl A non-null URL of a RSS/Atom feed to retrieve + * @return A {@link com.rometools.rome.feed.synd.SyndFeed} object + * @throws IllegalArgumentException if the URL is null; + * @throws IOException if a TCP error occurs + * @throws FeedException if the feed is not valid + * @throws FetcherException if a HTTP error occurred + */ + @Override + public SyndFeed retrieveFeed(final String userAgent, final URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException { + if (feedUrl == null) { + throw new IllegalArgumentException("null is not a valid URL"); + } + + final URLConnection connection = feedUrl.openConnection(); + if (!(connection instanceof HttpURLConnection)) { + throw new IllegalArgumentException(feedUrl.toExternalForm() + " is not a valid HTTP Url"); + } + final HttpURLConnection httpConnection = (HttpURLConnection) connection; + if (connectTimeout >= 0) { + httpConnection.setConnectTimeout(connectTimeout); + } + // httpConnection.setInstanceFollowRedirects(true); // this is true by default, but can be + // changed on a claswide basis + + final FeedFetcherCache cache = getFeedInfoCache(); + if (cache != null) { + SyndFeedInfo syndFeedInfo = cache.getFeedInfo(feedUrl); + setRequestHeaders(connection, syndFeedInfo, userAgent); + httpConnection.connect(); + try { + fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, connection); + + if (syndFeedInfo == null) { + // this is a feed that hasn't been retrieved + syndFeedInfo = new SyndFeedInfo(); + retrieveAndCacheFeed(feedUrl, syndFeedInfo, httpConnection); + } else { + // check the response code + final int responseCode = httpConnection.getResponseCode(); + if (responseCode != HttpURLConnection.HTTP_NOT_MODIFIED) { + // the response code is not 304 NOT MODIFIED + // This is either because the feed server + // does not support condition gets + // or because the feed hasn't changed + retrieveAndCacheFeed(feedUrl, syndFeedInfo, httpConnection); + } else { + // the feed does not need retrieving + fireEvent(FetcherEvent.EVENT_TYPE_FEED_UNCHANGED, connection); + } + } + + return syndFeedInfo.getSyndFeed(); + } finally { + httpConnection.disconnect(); + } + } else { + fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, connection); + InputStream inputStream = null; + setRequestHeaders(connection, null, userAgent); + + httpConnection.connect(); + try { + inputStream = httpConnection.getInputStream(); + return getSyndFeedFromStream(inputStream, connection); + } catch (final java.io.IOException e) { + handleErrorCodes(((HttpURLConnection) connection).getResponseCode()); + } finally { + IO.close(inputStream); + httpConnection.disconnect(); + } + // we will never actually get to this line + return null; + } + } + + protected void retrieveAndCacheFeed(final URL feedUrl, final SyndFeedInfo syndFeedInfo, final HttpURLConnection connection) + throws IllegalArgumentException, FeedException, FetcherException, IOException { + handleErrorCodes(connection.getResponseCode()); + + resetFeedInfo(feedUrl, syndFeedInfo, connection); + final FeedFetcherCache cache = getFeedInfoCache(); + // resetting feed info in the cache + // could be needed for some implementations + // of FeedFetcherCache (eg, distributed HashTables) + if (cache != null) { + cache.setFeedInfo(feedUrl, syndFeedInfo); + } + } + + protected void resetFeedInfo(final URL orignalUrl, final SyndFeedInfo syndFeedInfo, final HttpURLConnection connection) throws IllegalArgumentException, + IOException, FeedException { + // need to always set the URL because this may have changed due to 3xx redirects + syndFeedInfo.setUrl(connection.getURL()); + + // the ID is a persistant value that should stay the same even if the URL for the + // feed changes (eg, by 3xx redirects) + syndFeedInfo.setId(orignalUrl.toString()); + + // This will be 0 if the server doesn't support or isn't setting the last modified header + syndFeedInfo.setLastModified(connection.getLastModified()); + + // This will be null if the server doesn't support or isn't setting the ETag header + syndFeedInfo.setETag(connection.getHeaderField("ETag")); + + // get the contents + InputStream inputStream = null; + try { + inputStream = connection.getInputStream(); + SyndFeed syndFeed = getSyndFeedFromStream(inputStream, connection); + + final String imHeader = connection.getHeaderField("IM"); + if (isUsingDeltaEncoding() && imHeader != null && imHeader.contains("feed")) { + final FeedFetcherCache cache = getFeedInfoCache(); + if (cache != null && connection.getResponseCode() == 226) { + // client is setup to use http delta encoding and the server supports it and has + // returned a delta encoded response + // This response only includes new items + final SyndFeedInfo cachedInfo = cache.getFeedInfo(orignalUrl); + if (cachedInfo != null) { + final SyndFeed cachedFeed = cachedInfo.getSyndFeed(); + + // set the new feed to be the orginal feed plus the new items + syndFeed = combineFeeds(cachedFeed, syndFeed); + } + } + } + + syndFeedInfo.setSyndFeed(syndFeed); + } finally { + IO.close(inputStream); + } + } + + /** + *

+ * Set appropriate HTTP headers, including conditional get and gzip encoding headers + *

+ * + * @param connection A URLConnection + * @param syndFeedInfo The SyndFeedInfo for the feed to be retrieved. May be null + * @param userAgent the name of the user-agent to be placed in HTTP-header. + */ + protected void setRequestHeaders(final URLConnection connection, final SyndFeedInfo syndFeedInfo, final String userAgent) { + if (syndFeedInfo != null) { + // set the headers to get feed only if modified + // we support the use of both last modified and eTag headers + if (syndFeedInfo.getLastModified() != null) { + final Object lastModified = syndFeedInfo.getLastModified(); + if (lastModified instanceof Long) { + connection.setIfModifiedSince((Long) syndFeedInfo.getLastModified()); + } + } + if (syndFeedInfo.getETag() != null) { + connection.setRequestProperty("If-None-Match", syndFeedInfo.getETag()); + } + + } + // header to retrieve feed gzipped + connection.setRequestProperty("Accept-Encoding", "gzip"); + connection.addRequestProperty("User-Agent", userAgent); + + if (isUsingDeltaEncoding()) { + connection.addRequestProperty("A-IM", "feed"); + } + } + + private SyndFeed readSyndFeedFromStream(final InputStream inputStream, final URLConnection connection) throws IOException, IllegalArgumentException, + FeedException { + BufferedInputStream is; + if ("gzip".equalsIgnoreCase(connection.getContentEncoding())) { + // handle gzip encoded content + is = new BufferedInputStream(new GZIPInputStream(inputStream)); + } else { + is = new BufferedInputStream(inputStream); + } + + // InputStreamReader reader = new InputStreamReader(is, + // ResponseHandler.getCharacterEncoding(connection)); + + // SyndFeedInput input = new SyndFeedInput(); + + final XmlReader reader; + if (connection.getHeaderField("Content-Type") != null) { + reader = new XmlReader(is, connection.getHeaderField("Content-Type"), true); + } else { + reader = new XmlReader(is, true); + } + + final SyndFeedInput syndFeedInput = new SyndFeedInput(); + syndFeedInput.setPreserveWireFeed(isPreserveWireFeed()); + + return syndFeedInput.build(reader); + + } + + private SyndFeed getSyndFeedFromStream(final InputStream inputStream, final URLConnection connection) throws IOException, IllegalArgumentException, + FeedException { + final SyndFeed feed = readSyndFeedFromStream(inputStream, connection); + fireEvent(FetcherEvent.EVENT_TYPE_FEED_RETRIEVED, connection, feed); + return feed; + } + + /** + * @return The FeedFetcherCache used by this fetcher (Could be null) + */ + public synchronized FeedFetcherCache getFeedInfoCache() { + return feedInfoCache; + } + + /** + * @param cache The cache to be used by this fetcher (pass null to stop using a cache) + */ + public synchronized void setFeedInfoCache(final FeedFetcherCache cache) { + feedInfoCache = cache; + } + + /** + * @param timeout see java.net.URLConnection.setConnectTimeout(int timeout) + */ + public synchronized void setConnectTimeout(final int timeout) { + connectTimeout = timeout; + } +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/impl/LinkedHashMapFeedInfoCache.java b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/LinkedHashMapFeedInfoCache.java new file mode 100644 index 0000000..a398bf6 --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/LinkedHashMapFeedInfoCache.java @@ -0,0 +1,81 @@ +package com.rometools.fetcher.impl; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + *

+ * An implementation of the {@link com.rometools.fetcher.impl.FeedFetcherCache} interface. + *

+ * + *

+ * Unlike the HashMapFeedInfoCache this implementation will not grow unbound + *

+ * + * @author Javier Kohen + * @author Nick Lothian + * + */ +public class LinkedHashMapFeedInfoCache extends HashMapFeedInfoCache { + + private final class CacheImpl extends LinkedHashMap { + + private static final long serialVersionUID = 1L; + + public CacheImpl() { + super(16, 0.75F, true); + } + + @Override + protected boolean removeEldestEntry(final Map.Entry eldest) { + return size() > getMaxEntries(); + } + + } + + private static final int DEFAULT_MAX_ENTRIES = 20; + private static final long serialVersionUID = 1L; + private static final LinkedHashMapFeedInfoCache _instance = new LinkedHashMapFeedInfoCache(); + + private int maxEntries = DEFAULT_MAX_ENTRIES; + + /** + * Get the global instance of the cache + * + * @return an implementation of FeedFetcherCache + */ + public static final FeedFetcherCache getInstance() { + return _instance; + } + + /** + *

+ * Constructor for HashMapFeedInfoCache + *

+ * + *

+ * Only use this if you want multiple instances of the cache. Usually {@link #getInstance()} is + * more appropriate. + *

+ * + * @see #getInstance() + */ + public LinkedHashMapFeedInfoCache() { + super(); + } + + @Override + protected Map createInfoCache() { + return Collections.synchronizedMap(new CacheImpl()); + } + + public synchronized final int getMaxEntries() { + return maxEntries; + } + + public synchronized final void setMaxEntries(final int maxEntries) { + this.maxEntries = maxEntries; + } + +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/impl/ResponseHandler.java b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/ResponseHandler.java new file mode 100644 index 0000000..56b3ab8 --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/ResponseHandler.java @@ -0,0 +1,60 @@ +/* + * 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.rometools.fetcher.impl; + +import java.net.URLConnection; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Utility class to help deal with HTTP responses + * + */ +public class ResponseHandler { + public static final String defaultCharacterEncoding = "ISO-8859-1"; + + private final static Pattern characterEncodingPattern = Pattern.compile("charset=([.[^; ]]*)"); + + public static String getCharacterEncoding(final URLConnection connection) { + return getCharacterEncoding(connection.getContentType()); + } + + /** + * + *

+ * Gets the character encoding of a response. (Note that this is different to the + * content-encoding) + *

+ * + * @param contentTypeHeader the value of the content-type HTTP header eg: text/html; + * charset=ISO-8859-4 + * @return the character encoding, eg: ISO-8859-4 + */ + public static String getCharacterEncoding(final String contentTypeHeader) { + if (contentTypeHeader == null) { + return defaultCharacterEncoding; + } + + final Matcher m = characterEncodingPattern.matcher(contentTypeHeader); + // if (!m.matches()) { + if (!m.find()) { + return defaultCharacterEncoding; + } else { + return m.group(1); + } + } +} diff --git a/rome-fetcher/src/main/java/com/rometools/fetcher/impl/SyndFeedInfo.java b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/SyndFeedInfo.java new file mode 100644 index 0000000..07c9bfe --- /dev/null +++ b/rome-fetcher/src/main/java/com/rometools/fetcher/impl/SyndFeedInfo.java @@ -0,0 +1,160 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.fetcher.impl; + +import java.io.Serializable; +import java.net.URL; + +import com.rometools.rome.feed.impl.ObjectBean; +import com.rometools.rome.feed.synd.SyndFeed; + +/** + *

+ * A class to represent a {@link com.rometools.rome.feed.synd.SyndFeed} and some useful information + * about it. + *

+ * + *

+ * This class is thread safe, as expected by the different feed fetcher implementations. + *

+ * + * @author Nick Lothian + */ +public class SyndFeedInfo implements Cloneable, Serializable { + private static final long serialVersionUID = 1L; + + private final ObjectBean _objBean; + private String id; + private URL url; + private Object lastModified; + private String eTag; + private SyndFeed syndFeed; + + public SyndFeedInfo() { + _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. + * + */ + @Override + 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. + * + */ + @Override + public boolean equals(final 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. + * + */ + @Override + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

+ * + * @return String representation for the object. + * + */ + @Override + public String toString() { + return _objBean.toString(); + } + + /** + * @return the ETag the feed was last retrieved with + */ + public synchronized String getETag() { + return eTag; + } + + /** + * @return the last modified date for the feed + */ + public synchronized Object getLastModified() { + return lastModified; + } + + /** + * @return the URL the feed was served from + */ + public synchronized URL getUrl() { + return url; + } + + public synchronized void setETag(final String string) { + eTag = string; + } + + public synchronized void setLastModified(final Object o) { + lastModified = o; + } + + public synchronized void setUrl(final URL url) { + this.url = url; + } + + public synchronized SyndFeed getSyndFeed() { + return syndFeed; + } + + public synchronized void setSyndFeed(final SyndFeed feed) { + syndFeed = feed; + } + + /** + * @return A unique ID to identify the feed + */ + public synchronized String getId() { + return id; + } + + /** + * @param string A unique ID to identify the feed. Note that if the URL of the feed changes this + * will remain the same + */ + public synchronized void setId(final String string) { + id = string; + } + +} diff --git a/rome-fetcher/src/main/resources/.gitignore b/rome-fetcher/src/main/resources/.gitignore new file mode 100644 index 0000000..53b845b --- /dev/null +++ b/rome-fetcher/src/main/resources/.gitignore @@ -0,0 +1 @@ +# needed to commit empty folder \ No newline at end of file diff --git a/rome-fetcher/src/site/apt/BuildingTheRomeFetcher.apt b/rome-fetcher/src/site/apt/BuildingTheRomeFetcher.apt new file mode 100644 index 0000000..83ecc7d --- /dev/null +++ b/rome-fetcher/src/site/apt/BuildingTheRomeFetcher.apt @@ -0,0 +1,11 @@ + ----- + Building the Rome Fetcher + ----- + mkurz + ----- + 2011-08-15 17:34:51.402 + ----- + +Building the Rome Fetcher + + The Rome Fetcher can build using Maven 2. diff --git a/rome-fetcher/src/site/apt/ChangeLog.apt b/rome-fetcher/src/site/apt/ChangeLog.apt new file mode 100644 index 0000000..135af0c --- /dev/null +++ b/rome-fetcher/src/site/apt/ChangeLog.apt @@ -0,0 +1,113 @@ + ----- + Change Log + ----- + mkurz + ----- + 2011-08-15 17:27:20.212 + ----- + +Change Log + +*Prior to first release (on the way to v0.3) + + [[1]] Updated to handle removal of IO methods using byte streams\ + Byte Stream IO was removed from Rome itself. The Rome Fetcher is now updated to support this + + [[1]] Add FeedFetcherI interface and FeedFetcherFactory class\ + There is now a FeedFetcherI interface, which FeedFetcher implements. Use FeedFetcherFactory to create instances of + FeedFetcher (as suggested by Joseph Ottinger) (FeedFetcherFactory was later removed) + + [[1]] Event Support Added to FeedFetcherI\ + The FeedFetcherI interface now supports feed polled, feed retrieved and feed unchanged events + + [[1]] Samples added\ + Samples are now included with the Rome Fetcher + + [[1]] Unit Tests Added\ + JUnit based tests which invoke the Rome Fetcher against an embedded Jetty webserver are now included + + [[1]] Bug fixes in the FeedFetcher event model\ + The JUnit test suite uncovered some bugs in the event model used by the FeedFetcher. These bugs are now fixed. + + [[1]] Refactored the SyndFeedInfo class\ + SyndFeedInfo now extends ObjectBean + + [[1]] Removed FeedFetcherFactory\ + The benefit of the FeedFetcherFactory was arguable. Now the client code will need to manage the creation of specific implementations of the FeedFetcher + + [] + +*Prior to second release (on the way to v0.4) + + [[1]] Refectored to match Rome naming standards\ + FeedFetcherI renamed to FeedFetcher\ + #. New FeedFetcher Implementation\ + HttpClientFeedFetcher uses the Apache Commons HTTP Client + + [[1]] Abstract test classes excluded in project.xml\ + Tests now run correctly under Maven + + [[1]] Added GZip support to HttpClientFeedFetcher\ + HttpClientFeedFetcher now supports GZip compression. Tests have been added. + + [] + +*Prior to third release (on the way to v0.5) + + [[1]] SyndFeedInfo implements Serializable\ + SyndFeedInfo implements Serializable to make it easier to store + + [[1]] Support for rfc3229 delta encoding\ + The Fetcher now supports rfc3229 delta encoding. See {{{http://www.ietf.org/rfc/rfc3229.txt}http://www.ietf.org/rfc/rfc3229.txt}} and + {{{http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html}http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html}}. + Note that this is support is experimental and disabled by default + + [] + +*Prior to 0.6 + + [[1]] Feed passed to FetcherEvents\ + When a feed is retrieved it is now passed to the Fetcher Event. This makes it easier to code applications using an event oriented style. + + [] + +*Prior to 0.7 + + [[1]] Fix for URL Connection leak\ + In some circumstances URLConnection objects were not closed. This could cause problems in long\-running application. + + [] + +*0.8 was never released + +*Prior to 0.9 + + [[1]] Fix for potential synchronization issue\ + There was the possibility of synchronization issues in the FeedFetcher. Fixed, thanks to suggestions from Javier Kohen. + + [[1]] New LinkedHashMapFeedInfoCache FeedFetcherCache implementation\ + The new LinkedHashMapFeedInfoCache has the advantage that it will not grow unbound + + [] + +*Prior to 1.0RC2 + + [[1]] BeanInfo class added for AbstractFeedFetcher\ + com.rometools.rome.fetcher.impl.AbstractFeedFetcherBeanInfo was created to allow introspection to correctly find the events + + [[1]] Callback to allow access to HttpClient HttpMethod object\ + Add a HttpClientMethodCallbackIntf to allow the calling code to modify the HttpClient HttpMethod used to make the request + (eg, add additinal headers, etc.) Also fixes a reported bug where the user agent wasn't being set properly + + [[1]] Support for clearing cache\ + See {{{http://java.net/jira/browse/ROME\-119}http://java.net/jira/browse/ROME\-119}} for details + + [] + +*Prior to 1.0 + + [[1]] Support for preserving wire feed data.\ + The fetcher now has a setPreserveWireFeed() method which will setup ROME to preserve WireFeed data. See + {{{http://rometools.github.io/rome/PreservingWireFeeds.html}PreservingWireFeeds}} for further information. + + [] diff --git a/rome-fetcher/src/site/apt/Dependencies/HttpClientFeedFetcher.apt b/rome-fetcher/src/site/apt/Dependencies/HttpClientFeedFetcher.apt new file mode 100644 index 0000000..e67bfdc --- /dev/null +++ b/rome-fetcher/src/site/apt/Dependencies/HttpClientFeedFetcher.apt @@ -0,0 +1,13 @@ + ----- + HttpClientFeedFetcher + ----- + mkurz + ----- + 2011-08-15 17:40:11.468 + ----- + +HttpClientFeedFetcher + + + An implementation of the <<>> which uses the Jakarta HTTP Client. This HTTP client has many benefits over the standard Java implementation. + diff --git a/rome-fetcher/src/site/apt/Dependencies/index.apt b/rome-fetcher/src/site/apt/Dependencies/index.apt new file mode 100644 index 0000000..e890d1c --- /dev/null +++ b/rome-fetcher/src/site/apt/Dependencies/index.apt @@ -0,0 +1,36 @@ + ----- + Dependencies + ----- + mkurz + ----- + 2011-08-15 17:42:31.999 + ----- + +Dependencies + + The Rome Fetcher aims to introduce the absolute minimum number of extra dependencies. Currently (30\-June\-2004) no extra dependencies over those required + by Rome are required to use the fetcher. + + The current dependencies required to use the Rome Fetcher are: + + * JDK 1.4\+ + + * Current version of Rome + + * JDom v 1.0 + + [] + + To build the Rome Fetcher the {{{http://jakarta.apache.org/commons/httpclient/}Jakarta HTTP Client}} is required. + + If the {{{./HttpClientFeedFetcher.html}HttpClientFeedFetcher (fetcher)}} fetcher implementation is used then the Jakarta HTTP Client and Jakarta Commons Logging is required. + + To build and run the unit tests for the Rome Fetcher the following additional dependencies are required: + + * servletapi version 2.3 + + * jetty 4.2.12 + + [] + + Note that Maven will automatically download the correct versions of all dependancies. diff --git a/rome-fetcher/src/site/apt/KnownIssues.apt b/rome-fetcher/src/site/apt/KnownIssues.apt new file mode 100644 index 0000000..38263e7 --- /dev/null +++ b/rome-fetcher/src/site/apt/KnownIssues.apt @@ -0,0 +1,43 @@ + ----- + Known Issues + ----- + mkurz + ----- + 2011-08-15 17:30:28.420 + ----- + +Known Issues + +*Version 0.3 + + * The Maven build does not run the <<>> tests because of a bug in Maven + + * Version 0.3 does not have <<>> included in the project.xml (it is required to run the samples). Either get the latest <<>> from CVS, or + {{{https://rome.dev.java.net/source/browse/rome/subprojects/fetcher/project.xml?r1\=1.1&r2\=1.2}patch it yourself}} + + * 0.3 had a bug that caused it to overwite system properties. + + [] + +*Version 0.4 + + * No known issues (yet!) + + [] + +*Version 0.5 + + * When listening to feed events using <<>>, there is no way to get to the retrieved content, because it is set after firing the event. + \-\- {{{http://wiki.java.net/twiki/bin/view/Javawsxml/Jawe}jawe}} + + * When listening to feed events using <<>>, the feed URLs returned by the <<>> are prepended with + "sun.net.www.protocol.http.HttpURLConnection:" \-\- {{{http://wiki.java.net/twiki/bin/view/Javawsxml/Jawe}jawe}} + + [] + +*Version 0.7 + + * <<>> doesn't work quite right because <<>> does hostname resolution and treats virtual hosts with the same IP as equal, + so e.g. all RSS feeds from <<>> collide in the cache. Also, it's really slow. Fix is to use <<>> as the hash key instead of the URL itself. + + [] diff --git a/rome-fetcher/src/site/apt/Releases/ROMEFetcher0.6.apt b/rome-fetcher/src/site/apt/Releases/ROMEFetcher0.6.apt new file mode 100644 index 0000000..7a6e396 --- /dev/null +++ b/rome-fetcher/src/site/apt/Releases/ROMEFetcher0.6.apt @@ -0,0 +1,49 @@ + ----- + ROME Fetcher 0.6 + ----- + mkurz + ----- + 2011-08-15 17:50:02.821 + ----- + +ROME Fetcher 0.6 + +*Downloads + + * {{{./rome\-fetcher\-0.6\-src.zip}rome\-fetcher\-0.6\-src.zip}} + + * {{{./rome\-fetcher\-0.6.tar.gz}rome\-fetcher\-0.6.tar.gz}} + + * {{{./rome\-fetcher\-0.6.zip}rome\-fetcher\-0.6.zip}} + + * {{{./rome\-fetcher\-0.6\-src.tar.gz}rome\-fetcher\-0.6\-src.tar.gz}} + + [] + +*Tutorials + + * {{{../BuildingTheRomeFetcher.html}Building the Rome Fetcher (fetcher)}} + + * {{{../UsingTheRomeFetcherModuleToRetrieveFeeds.html}Using the Rome Fetcher module to retrieve feeds (fetcher)}} + + * {{{../SampleProgramsIncluded.html}Sample programs included (fetcher)}} + + [] + +*Todo list + + * {{{../TodoList.html}Todo list (fetcher)}} + + [] + +*Issues + + * {{{../KnownIssues.html}Known Issues (fetcher)}} + + [] + +*Change Log + + * {{{../ChangeLog.html}Change Log (fetcher)}} + + [] diff --git a/rome-fetcher/src/site/apt/Releases/ROMEFetcher0.7.apt b/rome-fetcher/src/site/apt/Releases/ROMEFetcher0.7.apt new file mode 100644 index 0000000..d574307 --- /dev/null +++ b/rome-fetcher/src/site/apt/Releases/ROMEFetcher0.7.apt @@ -0,0 +1,49 @@ + ----- + ROME Fetcher 0.7 + ----- + mkurz + ----- + 2011-08-15 17:50:31.833 + ----- + +ROME Fetcher 0.7 + +*Downloads + + * {{{./rome\-fetcher\-0.7\-src.zip}rome\-fetcher\-0.7\-src.zip}} + + * {{{./rome\-fetcher\-0.7.tar.gz}rome\-fetcher\-0.7.tar.gz}} + + * {{{./rome\-fetcher\-0.7.zip}rome\-fetcher\-0.7.zip}} + + * {{{./rome\-fetcher\-0.7\-src.tar.gz}rome\-fetcher\-0.7\-src.tar.gz}} + + [] + +*Tutorials + + * {{{../BuildingTheRomeFetcher.html}Building the Rome Fetcher (fetcher)}} + + * {{{../UsingTheRomeFetcherModuleToRetrieveFeeds.html}Using the Rome Fetcher module to retrieve feeds (fetcher)}} + + * {{{../SampleProgramsIncluded.html}Sample programs included (fetcher)}} + + [] + +*Todo list + + * {{{../TodoList.html}Todo list (fetcher)}} + + [] + +*Issues + + * {{{../KnownIssues.html}Known Issues (fetcher)}} + + [] + +*Change Log + + * {{{../ChangeLog.html}Change Log (fetcher)}} + + [] diff --git a/rome-fetcher/src/site/apt/Releases/ROMEFetcher0.9.apt b/rome-fetcher/src/site/apt/Releases/ROMEFetcher0.9.apt new file mode 100644 index 0000000..5bb4964 --- /dev/null +++ b/rome-fetcher/src/site/apt/Releases/ROMEFetcher0.9.apt @@ -0,0 +1,51 @@ + ----- + ROME Fetcher 0.9 + ----- + mkurz + ----- + 2011-08-15 17:51:04.383 + ----- + +ROME Fetcher 0.9 + + Note that there was no 0.8 Fetcher release + +*Downloads + + * {{{./rome\-fetcher\-0.9\-src.zip}rome\-fetcher\-0.9\-src.zip}} + + * {{{./rome\-fetcher\-0.9.tar.gz}rome\-fetcher\-0.9.tar.gz}} + + * {{{./rome\-fetcher\-0.9.zip}rome\-fetcher\-0.9.zip}} + + * {{{./rome\-fetcher\-0.9\-src.tar.gz}rome\-fetcher\-0.9\-src.tar.gz}} + + [] + +*Tutorials + + * {{{../BuildingTheRomeFetcher.html}Building the Rome Fetcher (fetcher)}} + + * {{{../UsingTheRomeFetcherModuleToRetrieveFeeds.html}Using the Rome Fetcher module to retrieve feeds (fetcher)}} + + * {{{../SampleProgramsIncluded.html}Sample programs included (fetcher)}} + + [] + +*Todo list + + * {{{../TodoList.html}Todo list (fetcher)}} + + [] + +*Issues + + * {{{../KnownIssues.html}Known Issues (fetcher)}} + + [] + +*Change Log + + * {{{../ChangeLog.html}Change Log (fetcher)}} + + [] diff --git a/rome-fetcher/src/site/apt/Releases/ROMEFetcher1.0.apt b/rome-fetcher/src/site/apt/Releases/ROMEFetcher1.0.apt new file mode 100644 index 0000000..992a9b9 --- /dev/null +++ b/rome-fetcher/src/site/apt/Releases/ROMEFetcher1.0.apt @@ -0,0 +1,53 @@ + ----- + ROME Fetcher 1.0 + ----- + mkurz + ----- + 2011-08-15 17:52:18.652 + ----- + +ROME Fetcher 1.0 + +*Downloads + + * {{{./rome\-fetcher\-1.0.jar}rome\-fetcher\-1.0.jar}} + + * {{{./rome\-fetcher\-1.0\-javadoc.jar}rome\-fetcher\-1.0\-javadoc.jar}} + + * {{{./rome\-fetcher\-1.0\-sources.jar}rome\-fetcher\-1.0\-sources.jar}} + + [] + +*Tutorials + + * {{{../BuildingTheRomeFetcher.html}Building the Rome Fetcher (fetcher)}} + + * {{{../UsingTheRomeFetcherModuleToRetrieveFeeds.html}Using the Rome Fetcher module to retrieve feeds (fetcher)}} + + * {{{../SampleProgramsIncluded.html}Sample programs included (fetcher)}} + + [] + +*API Docs + + * {{{./rome-fetcher-1.0-javadoc.jar}Fetcher API Docs}} + + [] + +*Todo list + + * {{{../TodoList.html}Todo list (fetcher)}} + + [] + +*Issues + + * {{{../KnownIssues.html}Known Issues (fetcher)}} + + [] + +*Change Log + + * {{{../ChangeLog.html}Change Log (fetcher)}} + + [] diff --git a/rome-fetcher/src/site/apt/Releases/ROMEFetcher1.0RC2.apt b/rome-fetcher/src/site/apt/Releases/ROMEFetcher1.0RC2.apt new file mode 100644 index 0000000..0519218 --- /dev/null +++ b/rome-fetcher/src/site/apt/Releases/ROMEFetcher1.0RC2.apt @@ -0,0 +1,57 @@ + ----- + ROME Fetcher 1.0 RC2 + ----- + mkurz + ----- + 2011-08-15 17:51:50.236 + ----- + +ROME Fetcher 1.0 RC2 + + Note that there was no 1.0 RC1 Fetcher release + +*Downloads + + * {{{./rome\-fetcher\-1.0RC2\-src.zip}rome\-fetcher\-1.0RC2\-src.zip}} + + * {{{./rome\-fetcher\-1.0RC2.jar}rome\-fetcher\-1.0RC2.jar}} + + * {{{./rome\-fetcher\-1.0RC2\-javadoc.jar}rome\-fetcher\-1.0RC2\-javadoc.jar}} + + * {{{./rome\-fetcher\-1.0RC2\-sources.jar}rome\-fetcher\-1.0RC2\-sources.jar}} + + [] + +*Tutorials + + * {{{../BuildingTheRomeFetcher.html}Building the Rome Fetcher (fetcher)}} + + * {{{../UsingTheRomeFetcherModuleToRetrieveFeeds.html}Using the Rome Fetcher module to retrieve feeds (fetcher)}} + + * {{{../SampleProgramsIncluded.html}Sample programs included (fetcher)}} + + [] + +*API Docs + + * {{{./rome-fetcher-1.0RC2-javadoc.jar}Fetcher API Docs}} + + [] + +*Todo list + + * {{{../TodoList.html}Todo list (fetcher)}} + + [] + +*Issues + + * {{{../KnownIssues.html}Known Issues (fetcher)}} + + [] + +*Change Log + + * {{{../ChangeLog.html}Change Log (fetcher)}} + + [] diff --git a/rome-fetcher/src/site/apt/Releases/RomeFetcher0.3.apt b/rome-fetcher/src/site/apt/Releases/RomeFetcher0.3.apt new file mode 100644 index 0000000..21d024e --- /dev/null +++ b/rome-fetcher/src/site/apt/Releases/RomeFetcher0.3.apt @@ -0,0 +1,51 @@ + ----- + Rome Fetcher 0.3 + ----- + mkurz + ----- + 2011-08-15 17:46:45.860 + ----- + +Rome Fetcher 0.3 + + Rome Fetcher version 0.3 is inital release of the Rome Fetcher. It is released as version 0.3 to synchronize with the version number of the core Rome project release. + +*Downloads + + * {{{./rome\-fetcher\-0.3\-src.zip}rome\-fetcher\-0.3\-src.zip}} + + * {{{./rome\-fetcher\-0.3.tar.gz}rome\-fetcher\-0.3.tar.gz}} + + * {{{./rome\-fetcher\-0.3.zip}rome\-fetcher\-0.3.zip}} + + * {{{./rome\-fetcher\-0.3\-src.tar.gz}rome\-fetcher\-0.3\-src.tar.gz}} + + [] + +*Tutorials + + * {{{../BuildingTheRomeFetcher.html}Building the Rome Fetcher (fetcher)}} + + * {{{../UsingTheRomeFetcherModuleToRetrieveFeeds.html}Using the Rome Fetcher module to retrieve feeds (fetcher)}} + + * {{{../SampleProgramsIncluded.html}Sample programs included (fetcher)}} + + [] + +*Todo list + + * {{{../TodoList.html}Todo list (fetcher)}} + + [] + +*Issues + + * {{{../KnownIssues.html}Known Issues (fetcher)}} + + [] + +*Change Log + + * {{{../ChangeLog.html}Change Log (fetcher)}} + + [] diff --git a/rome-fetcher/src/site/apt/Releases/RomeFetcher0.4.apt b/rome-fetcher/src/site/apt/Releases/RomeFetcher0.4.apt new file mode 100644 index 0000000..a9abd8a --- /dev/null +++ b/rome-fetcher/src/site/apt/Releases/RomeFetcher0.4.apt @@ -0,0 +1,49 @@ + ----- + Rome Fetcher 0.4 + ----- + mkurz + ----- + 2011-08-15 17:47:58.203 + ----- + +Rome Fetcher 0.4 + +*Downloads + + * {{{./rome\-fetcher\-0.4\-src.zip}rome\-fetcher\-0.4\-src.zip}} + + * {{{./rome\-fetcher\-0.4.tar.gz}rome\-fetcher\-0.4.tar.gz}} + + * {{{./rome\-fetcher\-0.4.zip}rome\-fetcher\-0.4.zip}} + + * {{{./rome\-fetcher\-0.4\-src.tar.gz}rome\-fetcher\-0.4\-src.tar.gz}} + + [] + +*Tutorials + + * {{{../BuildingTheRomeFetcher.html}Building the Rome Fetcher (fetcher)}} + + * {{{../UsingTheRomeFetcherModuleToRetrieveFeeds.html}Using the Rome Fetcher module to retrieve feeds (fetcher)}} + + * {{{../SampleProgramsIncluded.html}Sample programs included (fetcher)}} + + [] + +*Todo list + + * {{{../TodoList.html}Todo list (fetcher)}} + + [] + +*Issues + + * {{{../KnownIssues.html}Known Issues (fetcher)}} + + [] + +*Change Log + + * {{{../ChangeLog.html}Change Log (fetcher)}} + + [] diff --git a/rome-fetcher/src/site/apt/Releases/RomeFetcher0.5.apt b/rome-fetcher/src/site/apt/Releases/RomeFetcher0.5.apt new file mode 100644 index 0000000..9959793 --- /dev/null +++ b/rome-fetcher/src/site/apt/Releases/RomeFetcher0.5.apt @@ -0,0 +1,51 @@ + ----- + Rome Fetcher 0.5 + ----- + mkurz + ----- + 2011-08-15 17:49:03.166 + ----- + +Rome Fetcher 0.5 + + The ROME Fetcher v 0.6 is now released. This page exists for historical purposes only. + +*Downloads + + * {{{./rome\-fetcher\-0.5\-src.zip}rome\-fetcher\-0.5\-src.zip}} + + * {{{./rome\-fetcher\-0.5.zip}rome\-fetcher\-0.5.zip}} + + * {{{./rome\-fetcher\-0.5.tar.gz}rome\-fetcher\-0.5.tar.gz}} + + * {{{./rome\-fetcher\-0.5\-src.tar.gz}rome\-fetcher\-0.5\-src.tar.gz}} + + [] + +*Tutorials + + * {{{../BuildingTheRomeFetcher.html}Building the Rome Fetcher (fetcher)}} + + * {{{../UsingTheRomeFetcherModuleToRetrieveFeeds.html}Using the Rome Fetcher module to retrieve feeds (fetcher)}} + + * {{{../SampleProgramsIncluded.html}Sample programs included (fetcher)}} + + [] + +*Todo list + + * {{{../TodoList.html}Todo list (fetcher)}} + + [] + +*Issues + + * {{{../KnownIssues.html}Known Issues (fetcher)}} + + [] + +*Change Log + + * {{{../ChangeLog.html}Change Log (fetcher)}} + + [] diff --git a/rome-fetcher/src/site/apt/Releases/index.apt b/rome-fetcher/src/site/apt/Releases/index.apt new file mode 100644 index 0000000..f5715b8 --- /dev/null +++ b/rome-fetcher/src/site/apt/Releases/index.apt @@ -0,0 +1,10 @@ + ----- + Releases + ----- + mkurz + ----- + 2011-08-15 17:57:59.422 + ----- + +Releases + diff --git a/rome-fetcher/src/site/apt/SampleProgramsIncluded.apt b/rome-fetcher/src/site/apt/SampleProgramsIncluded.apt new file mode 100644 index 0000000..7c12649 --- /dev/null +++ b/rome-fetcher/src/site/apt/SampleProgramsIncluded.apt @@ -0,0 +1,18 @@ + ----- + Sample programs included + ----- + mkurz + ----- + 2011-08-15 17:38:21.664 + ----- + +Sample programs included + + There are two sample programs included with Rome Fetcher. + + {{{https://github.com/rometools/rome-fetcher/tree/master/src/main/java/org/rometools/fetcher/samples/FeedReader.java}FeedReader}} + is a program which demonstrates the use of the Fetcher to retrieve a feed and then to use the conditional get support to retrieve + it again only if it has changed. It also shows how to use the event API in the Fetcher. It can be run using the <<>> target. + + {{{https://github.com/rometools/rome-fetcher/tree/master/src/main/java/org/rometools/fetcher/samples/FeedAggregator.java}FeedAggregator}} + is a program which aggregates a number of feeds together into a single feed. It can be run using the <<>> target. diff --git a/rome-fetcher/src/site/apt/TodoList.apt b/rome-fetcher/src/site/apt/TodoList.apt new file mode 100644 index 0000000..d6c2582 --- /dev/null +++ b/rome-fetcher/src/site/apt/TodoList.apt @@ -0,0 +1,29 @@ + ----- + Todo list + ----- + mkurz + ----- + 2011-08-15 17:33:17.559 + ----- + +Todo list + + Please discuss items here on the rome dev mailing list + + * Automatically update the + \-{{{https://github.com/rometools/rome-fetcher/blob/master/src/java/org/rometools/fetcher/FeedFetcher.java}default User\-Agent version number}} + via the build\- Done: 23\-June\-2004 + + * Listener Architecture (for URL changes via 3xx redirection etc) Done: 30\-June\-2004 + + * {{{http://radio.userland.com/userGuide/reference/howToRedirectRss}RSS Redirection}} + + * Unit Tests: smart unit tests along the lines of Mark Pilgrim's tests, in his + \-{{{http://diveintomark.org/projects/feed_parser/}Python Universal Feed Parser}}. He instantiates a web server to a local directory where the samples live, + and then fetches the feeds from the server, which allows him to test in depth the behavior of gzip compression and etags handling.\- Done 30\-June\-2004 + + * Better character encoding handling \- See {{{http://diveintomark.org/archives/2004/02/13/xml\-media\-types}http://diveintomark.org/archives/2004/02/13/xml\-media\-types}} + + * A caching feed fetcher + + [] diff --git a/rome-fetcher/src/site/apt/UsingTheRomeFetcherModuleToRetrieveFeeds.apt b/rome-fetcher/src/site/apt/UsingTheRomeFetcherModuleToRetrieveFeeds.apt new file mode 100644 index 0000000..cc2bcfa --- /dev/null +++ b/rome-fetcher/src/site/apt/UsingTheRomeFetcherModuleToRetrieveFeeds.apt @@ -0,0 +1,36 @@ + ----- + Using the Rome Fetcher module to retrieve feeds + ----- + mkurz + ----- + 2011-08-15 17:36:41.844 + ----- + +Using the Rome Fetcher module to retrieve feeds + + The HttpURLFeedFetcher class does the actual HTTP request. It relies on the FeedInfoCacheI interface which stores information + about each feed required for conditional gets. Currently there is a single implementation of FeedInfoCacheI supplied: <<>>. + + The basic usage of FeedFetcher is as follows: + ++------+ +FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance(); +FeedFetcher feedFetcher = new HttpURLFeedFetcher(feedInfoCache); +SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://blogs.sun.com/roller/rss/pat")); +System.out.println(feed); ++------+ + + Any subsequent fetches of {{{http://blogs.sun.com/roller/rss/pat}http://blogs.sun.com/roller/rss/pat}} by any FeedFetcher using feedInfoCache + will now only retrieve the feed if it has changed. + + FeedFetcher can be used without a cache if required. Simply create it using the zero\-parameter constructor: + ++------+ +FeedFetcher feedFetcher = new HttpURLFeedFetcher(); ++------+ + + A more complete sample (including the use of listener on Fetcher events) + {{{https://github.com/rometools/rome-fetcher/blob/master/src/java/org/rometools/fetcher/samples/FeedReader.java}is included in the Rome Fetcher project}} + + Note that there has been considerable discussion on the rome\-dev list about the best way to manage the creation of the feed fetcher. + Currently the client code needs to be responsible for creating specific implementations of the FeedFetcherI interface. diff --git a/rome-fetcher/src/site/apt/WishList.apt b/rome-fetcher/src/site/apt/WishList.apt new file mode 100644 index 0000000..f4cd90f --- /dev/null +++ b/rome-fetcher/src/site/apt/WishList.apt @@ -0,0 +1,17 @@ + ----- + Wish list + ----- + mkurz + ----- + 2011-08-15 17:33:55.774 + ----- + +Wish list + + * {{{http://diveintomark.org/archives/2002/05/31}RSS Autodiscovery}} + + * {{{http://www.intertwingly.net/wiki/pie/PaceAutoDisco}Atom Autodiscovery}} + + * Connection timeout and read settings. + + [] diff --git a/rome-fetcher/src/site/apt/index.apt b/rome-fetcher/src/site/apt/index.apt new file mode 100644 index 0000000..d3ae974 --- /dev/null +++ b/rome-fetcher/src/site/apt/index.apt @@ -0,0 +1,72 @@ + ----- + Home + ----- + mkurz + ----- + 2011-08-15 17:44:31.665 + ----- + +Rome Fetcher + + The Rome Fetcher (see modules/fetcher) allows the retrieval of feeds via HTTP. It supports + {{{http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers}HTTP conditional gets}} + (ie: last modified and ETag handling) and GZip encoded feeds. It should enable user to write aggregators that follow the + {{{http://diveintomark.org/archives/2003/07/21/atom_aggregator_behavior_http_level}Atom aggregator behaviour recommendations}} + + As with the rest of Rome, the Fetcher subproject is ultra\-lean \- it requires {{{./Dependencies/index.html}no new dependencies}} + over the requirements for Rome. + +Tutorials + + * {{{./BuildingTheRomeFetcher.html}Building the Rome Fetcher (fetcher)}} + + * {{{./UsingTheRomeFetcherModuleToRetrieveFeeds.html}Using the Rome Fetcher module to retrieve feeds (fetcher)}} + + * {{{./SampleProgramsIncluded.html}Sample programs included (fetcher)}} + + [] + +Todo list + + * {{{./TodoList.html}Todo list (fetcher)}} + + [] + +Wish list + + * {{{./WishList.html}Wish list (fetcher)}} + + [] + +Issues + + * {{{./KnownIssues.html}Known Issues (fetcher)}} + + [] + +Releases + + * {{{./Releases/RomeFetcher0.3.html}Rome Fetcher 0.3 (fetcher)}} + + * {{{./Releases/RomeFetcher0.4.html}Rome Fetcher 0.4 (fetcher)}} + + * {{{./Releases/RomeFetcher0.5.html}Rome Fetcher 0.5 (fetcher)}} + + * {{{./Releases/ROMEFetcher0.6.html}ROME Fetcher 0.6 (fetcher)}} + + * {{{./Releases/ROMEFetcher0.7.html}ROME Fetcher 0.7 (fetcher)}} + + * {{{./Releases/ROMEFetcher0.9.html}ROME Fetcher 0.9 (fetcher)}} + + * {{{./Releases/ROMEFetcher1.0RC2.html}ROME Fetcher 1.0 RC2 (fetcher)}} + + * {{{./Releases/ROMEFetcher1.0.html}ROME Fetcher 1.0 (fetcher)}} + + [] + +Change Log + + * {{{./ChangeLog.html}Change Log (fetcher)}} + + [] + \ No newline at end of file diff --git a/rome-fetcher/src/site/resources/.nojekyll b/rome-fetcher/src/site/resources/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3-src.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3-src.tar.gz new file mode 100644 index 0000000..0043cc9 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3-src.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3-src.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3-src.zip new file mode 100644 index 0000000..b806b31 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3-src.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3.tar.gz new file mode 100644 index 0000000..958b25e Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3.zip new file mode 100644 index 0000000..ba85cd1 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.3.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4-src.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4-src.tar.gz new file mode 100644 index 0000000..0af41b0 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4-src.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4-src.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4-src.zip new file mode 100644 index 0000000..697c2a6 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4-src.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4.tar.gz new file mode 100644 index 0000000..93adbc0 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4.zip new file mode 100644 index 0000000..44f1d64 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.4.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5-src.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5-src.tar.gz new file mode 100644 index 0000000..ee71caa Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5-src.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5-src.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5-src.zip new file mode 100644 index 0000000..eb6ce42 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5-src.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5.tar.gz new file mode 100644 index 0000000..cc58dd8 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5.zip new file mode 100644 index 0000000..27c9b55 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.5.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6-src.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6-src.tar.gz new file mode 100644 index 0000000..0d69b1b Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6-src.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6-src.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6-src.zip new file mode 100644 index 0000000..67ab51a Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6-src.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6.tar.gz new file mode 100644 index 0000000..c5a996a Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6.zip new file mode 100644 index 0000000..8890994 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.6.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7-src.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7-src.tar.gz new file mode 100644 index 0000000..30bc5a8 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7-src.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7-src.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7-src.zip new file mode 100644 index 0000000..ee788d4 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7-src.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7.tar.gz new file mode 100644 index 0000000..804aa97 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7.zip new file mode 100644 index 0000000..45934eb Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.7.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9-src.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9-src.tar.gz new file mode 100644 index 0000000..2b1bdf9 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9-src.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9-src.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9-src.zip new file mode 100644 index 0000000..1899ac7 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9-src.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9.tar.gz b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9.tar.gz new file mode 100644 index 0000000..1560db9 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9.tar.gz differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9.zip new file mode 100644 index 0000000..43c48a9 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-0.9.zip differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0-javadoc.jar b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0-javadoc.jar new file mode 100644 index 0000000..7ea9678 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0-javadoc.jar differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0-sources.jar b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0-sources.jar new file mode 100644 index 0000000..bf1be0f Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0-sources.jar differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0.jar b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0.jar new file mode 100644 index 0000000..b889d47 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0.jar differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2-javadoc.jar b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2-javadoc.jar new file mode 100644 index 0000000..4b08a4a Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2-javadoc.jar differ diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2-sources.jar b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2-sources.jar new file mode 100644 index 0000000..a471611 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2-sources.jar differ diff --git a/src/site/resources/ROMEReleases/rome-fetcher-1.0RC2-src.zip b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-fetcher-1.0RC2-src.zip rename to rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2-src.zip diff --git a/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2.jar b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2.jar new file mode 100644 index 0000000..c8a3f85 Binary files /dev/null and b/rome-fetcher/src/site/resources/Releases/rome-fetcher-1.0RC2.jar differ diff --git a/rome-fetcher/src/site/resources/css/site.css b/rome-fetcher/src/site/resources/css/site.css new file mode 100644 index 0000000..43c3cd8 --- /dev/null +++ b/rome-fetcher/src/site/resources/css/site.css @@ -0,0 +1,8 @@ +h1 { + padding: 4px 4px 4px 6px; + border: 1px solid #999; + color: #900; + background-color: #ddd; + font-weight:900; + font-size: x-large; +} \ No newline at end of file diff --git a/src/site/resources/romelogo.png b/rome-fetcher/src/site/resources/images/romelogo.png similarity index 100% rename from src/site/resources/romelogo.png rename to rome-fetcher/src/site/resources/images/romelogo.png diff --git a/rome-fetcher/src/site/site.xml b/rome-fetcher/src/site/site.xml new file mode 100644 index 0000000..4e8df2e --- /dev/null +++ b/rome-fetcher/src/site/site.xml @@ -0,0 +1,41 @@ + + + + + org.apache.maven.skins + maven-fluido-skin + 1.3.0 + + + + ROME fetcher + images/romelogo.png + http://github.com/rometools/ + + + + + + + +

+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rome-fetcher/src/test/java/com/rometools/fetcher/AbstractJettyTest.java b/rome-fetcher/src/test/java/com/rometools/fetcher/AbstractJettyTest.java new file mode 100644 index 0000000..141c2b2 --- /dev/null +++ b/rome-fetcher/src/test/java/com/rometools/fetcher/AbstractJettyTest.java @@ -0,0 +1,424 @@ +/* + * 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.rometools.fetcher; + +import java.net.URL; + +import junit.framework.TestCase; + +import org.mortbay.http.BasicAuthenticator; +import org.mortbay.http.HashUserRealm; +import org.mortbay.http.HttpContext; +import org.mortbay.http.HttpServer; +import org.mortbay.http.SecurityConstraint; +import org.mortbay.http.SocketListener; +import org.mortbay.http.UserRealm; +import org.mortbay.http.handler.SecurityHandler; +import org.mortbay.jetty.servlet.ServletHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.fetcher.impl.FeedFetcherCache; +import com.rometools.fetcher.impl.HashMapFeedInfoCache; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; + +/** + * @author nl + */ +public abstract class AbstractJettyTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractJettyTest.class); + + private HttpServer server; + private final int testPort = 8283; + + /** + * @param s + */ + public AbstractJettyTest(final String s) { + super(s); + } + + protected HttpServer getServer() { + return server; + } + + protected abstract FeedFetcher getFeedFetcher(); + + protected abstract FeedFetcher getFeedFetcher(FeedFetcherCache cache); + + /** + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + setupServer(); + + final HttpContext context = createContext(); + + final ServletHandler servlets = createServletHandler(); + context.addHandler(servlets); + + server.addContext(context); + + server.start(); + } + + /** + * @throws InterruptedException + */ + private void setupServer() throws InterruptedException { + + // Create the server + if (server != null) { + server.stop(); + server = null; + } + server = new HttpServer(); + + // Create a port listener + final SocketListener listener = new SocketListener(); + listener.setPort(testPort); + server.addListener(listener); + } + + /** + * @return + */ + private ServletHandler createServletHandler() { + final ServletHandler servlets = new ServletHandler(); + servlets.addServlet("FetcherTestServlet", FetcherTestServlet.SERVLET_MAPPING, "com.rometools.fetcher.FetcherTestServlet"); + servlets.addServlet("FetcherTestServlet", FetcherTestServlet.SERVLET_MAPPING2, "com.rometools.fetcher.FetcherTestServlet"); + return servlets; + } + + /** + * @return + */ + private HttpContext createContext() { + final HttpContext context = new HttpContext(); + context.setContextPath("/rome/*"); + return context; + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + if (server != null) { + server.stop(); + server.destroy(); + server = null; + } + } + + class FetcherEventListenerImpl implements FetcherListener { + boolean polled = false; + boolean retrieved = false; + boolean unchanged = false; + + public void reset() { + polled = false; + retrieved = false; + unchanged = false; + } + + /** + * @see com.rometools.rome.fetcher.FetcherListener#fetcherEvent(com.rometools.rome.fetcher.FetcherEvent) + */ + @Override + public void fetcherEvent(final FetcherEvent event) { + final String eventType = event.getEventType(); + if (FetcherEvent.EVENT_TYPE_FEED_POLLED.equals(eventType)) { + LOG.debug("\tEVENT: Feed Polled. URL = " + event.getUrlString()); + polled = true; + } else if (FetcherEvent.EVENT_TYPE_FEED_RETRIEVED.equals(eventType)) { + LOG.debug("\tEVENT: Feed Retrieved. URL = " + event.getUrlString()); + retrieved = true; + } else if (FetcherEvent.EVENT_TYPE_FEED_UNCHANGED.equals(eventType)) { + LOG.debug("\tEVENT: Feed Unchanged. URL = " + event.getUrlString()); + unchanged = true; + } + } + } + + public void testRetrieveFeed() { + final FeedFetcher feedFetcher = getFeedFetcher(); + try { + final SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/")); + assertNotNull(feed); + assertEquals("atom_1.0.feed.title", feed.getTitle()); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + public void testBasicAuthentication() { + try { + setupServer(); + + final HttpContext context = createContext(); + + final URL url = this.getClass().getResource("/testuser.properties"); + final UserRealm ur = new HashUserRealm("test", url.getFile()); + context.setRealm(ur); + + final BasicAuthenticator ba = new BasicAuthenticator(); + context.setAuthenticator(ba); + + final SecurityHandler sh = new SecurityHandler(); + context.addHandler(sh); + + final SecurityConstraint sc = new SecurityConstraint(); + sc.setName("test"); + sc.addRole("*"); + sc.setAuthenticate(true); + context.addSecurityConstraint("/", sc); + + final ServletHandler servlets = createServletHandler(); + context.addHandler(servlets); + + server.addContext(context); + + server.start(); + + final FeedFetcher feedFetcher = getAuthenticatedFeedFetcher(); + final SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/")); + assertNotNull(feed); + assertEquals("atom_1.0.feed.title", feed.getTitle()); + + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + } + + public abstract FeedFetcher getAuthenticatedFeedFetcher(); + + /** + * Test getting a feed via a http 301 redirect + * + */ + public void testRetrieveRedirectedFeed() { + final FeedFetcher feedFetcher = getFeedFetcher(); + try { + final SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet?redirect=TRUE")); + assertNotNull(feed); + assertEquals("atom_1.0.feed.title", feed.getTitle()); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + /** + * Test error handling + * + */ + public void testErrorHandling() { + final FeedFetcher feedFetcher = getFeedFetcher(); + try { + feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet?error=404")); + fail("4xx error handling did not work correctly"); + } catch (final FetcherException e) { + // expect this exception + assertEquals(404, e.getResponseCode()); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + try { + feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet?error=500")); + fail("5xx error handling did not work correctly"); + } catch (final FetcherException e) { + // expect this exception + assertEquals(500, e.getResponseCode()); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + public void testUserAgent() { + final FeedFetcher feedFetcher = getFeedFetcher(); + // LOG.debug(feedFetcher.getUserAgent()); + // LOG.debug(System.getProperty("rome.fetcher.version", "UNKNOWN")); + assertEquals("Rome Client (http://tinyurl.com/64t5n) Ver: " + System.getProperty("rome.fetcher.version", "UNKNOWN"), feedFetcher.getUserAgent()); + } + + /** + * Test events fired when there is no cache in use + * + */ + public void testFetchEvents() { + final FeedFetcher feedFetcher = getFeedFetcher(); + final FetcherEventListenerImpl listener = new FetcherEventListenerImpl(); + feedFetcher.addFetcherEventListener(listener); + try { + SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/")); + assertNotNull(feed); + assertTrue(listener.polled); + assertTrue(listener.retrieved); + assertFalse(listener.unchanged); + listener.reset(); + + // since there is no cache, the events fired should be exactly the same if + // we re-retrieve the feed + feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/")); + assertNotNull(feed); + assertTrue(listener.polled); + assertTrue(listener.retrieved); + assertFalse(listener.unchanged); + listener.reset(); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + /** + * Test events fired when there is a cache in use + * + */ + public void testFetchEventsWithCache() { + final FeedFetcherCache feedInfoCache = new HashMapFeedInfoCache(); + final FeedFetcher feedFetcher = getFeedFetcher(feedInfoCache); + final FetcherEventListenerImpl listener = new FetcherEventListenerImpl(); + feedFetcher.addFetcherEventListener(listener); + try { + SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/")); + assertNotNull(feed); + assertTrue(listener.polled); + assertTrue(listener.retrieved); + assertFalse(listener.unchanged); + listener.reset(); + + // Since the feed is cached, the second request should not + // actually retrieve the feed + feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/")); + assertNotNull(feed); + assertTrue(listener.polled); + assertFalse(listener.retrieved); + assertTrue(listener.unchanged); + listener.reset(); + + // now simulate getting the feed after it has changed + feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet?refreshfeed=TRUE")); + assertNotNull(feed); + assertTrue(listener.polled); + assertTrue(listener.retrieved); + assertFalse(listener.unchanged); + listener.reset(); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + /** + * Test handling of GZipped feed + * + */ + public void testGZippedFeed() { + final FeedFetcher feedFetcher = getFeedFetcher(); + try { + final SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet?gzipfeed=TRUE")); + assertNotNull(feed); + assertEquals("atom_1.0.feed.title", feed.getTitle()); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + public void testPreserveWireFeed() throws Exception { + final FeedFetcher feedFetcher = getFeedFetcher(); + + // first check we the WireFeed is not preserved by default + SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/")); + assertNotNull(feed); + assertEquals("atom_1.0.feed.title", feed.getTitle()); + assertNull(feed.originalWireFeed()); + + SyndEntry syndEntry = feed.getEntries().get(0); + assertNotNull(syndEntry); + assertNull(syndEntry.getWireEntry()); + + // now turn on WireFeed preservation + feedFetcher.setPreserveWireFeed(true); + try { + feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/")); + assertNotNull(feed); + assertEquals("atom_1.0.feed.title", feed.getTitle()); + assertNotNull(feed.originalWireFeed()); + + syndEntry = feed.getEntries().get(0); + assertNotNull(syndEntry); + assertNotNull(syndEntry.getWireEntry()); + + final Entry entry = (Entry) syndEntry.getWireEntry(); + assertEquals("atom_1.0.feed.entry[0].rights", entry.getRights()); + + } finally { + feedFetcher.setPreserveWireFeed(false); // reset + } + + } + + public void testDeltaEncoding() { + final FeedFetcherCache feedInfoCache = new HashMapFeedInfoCache(); + final FeedFetcher feedFetcher = getFeedFetcher(feedInfoCache); + try { + feedFetcher.setUsingDeltaEncoding(true); + + // first retrieval should just grab the default feed + final SyndFeed feed1 = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + + "/rome/FetcherTestServlet?deltaencode=TRUE&refreshfeed=TRUE")); + assertNotNull(feed1); + assertEquals("atom_1.0.feed.title", feed1.getTitle()); + assertEquals(2, feed1.getEntries().size()); + SyndEntry entry1 = feed1.getEntries().get(0); + assertEquals("atom_1.0.feed.entry[0].title", entry1.getTitle()); + + // second retrieval should get only the new item + /* + * This is breaking with Rome 0.5 ?? + */ + final SyndFeed feed2 = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + + "/rome/FetcherTestServlet?deltaencode=TRUE&refreshfeed=TRUE")); + assertNotNull(feed2); + assertEquals(FetcherTestServlet.DELTA_FEED_TITLE, feed2.getTitle()); + assertEquals(3, feed2.getEntries().size()); + entry1 = feed2.getEntries().get(0); + assertEquals(FetcherTestServlet.DELTA_FEED_ENTRY_TITLE, entry1.getTitle()); + + final SyndEntry entry2 = feed2.getEntries().get(1); + assertEquals("atom_1.0.feed.entry[0].title", entry2.getTitle()); + + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + +} diff --git a/rome-fetcher/src/test/java/com/rometools/fetcher/FetcherTestServlet.java b/rome-fetcher/src/test/java/com/rometools/fetcher/FetcherTestServlet.java new file mode 100644 index 0000000..c967517 --- /dev/null +++ b/rome-fetcher/src/test/java/com/rometools/fetcher/FetcherTestServlet.java @@ -0,0 +1,248 @@ +/* + * 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.rometools.fetcher; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.GZIPOutputStream; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.rometools.rome.feed.synd.SyndContent; +import com.rometools.rome.feed.synd.SyndContentImpl; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndEntryImpl; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndFeedImpl; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedOutput; + +public class FetcherTestServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + public static final String ETAG_1 = "ETAG-1"; + public static final String ETAG_2 = "ETAG-2"; + + public static final String DELTA_FEED_TITLE = "Delta Encoded Feed"; + public static final String DELTA_FEED_ENTRY_TITLE = "Delta Encoded Feed Entry"; + + public static final String SERVLET_MAPPING = "/FetcherTestServlet/*"; + public static final String SERVLET_MAPPING2 = "/FetcherTestServlet2/*"; + + /** + * @throws IOException + * @throws + * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { + + if ("TRUE".equalsIgnoreCase(request.getParameter("redirect"))) { + // testing redirection support + response.sendRedirect("/rome/FetcherTestServlet2/"); + return; + } else if (request.getParameter("error") != null) { + // response.sendError(HttpServletResponse.SC_NOT_FOUND); + final int errorToThrow = Integer.parseInt(request.getParameter("error")); + response.sendError(errorToThrow); + return; + } else { + + // We manually set the date headers using strings + // instead of the get/setDateHeader methods because + // those methods return longs, which has too much + // precision for the real date headers + // this is just a random date + String lastModifiedDate = "Thu, 08 Jan 2009 23:06:39 GMT"; + String eTag = ETAG_1; + + if ("TRUE".equalsIgnoreCase(request.getParameter("refreshfeed"))) { + lastModifiedDate = "Fri, 09 Jan 2009 12:06:39 GMT"; + eTag = ETAG_2; + } + + final boolean serveFeed = checkModified(request, lastModifiedDate, eTag) || "TRUE".equalsIgnoreCase(request.getParameter("deltaencode")); + final boolean gzip = "TRUE".equalsIgnoreCase(request.getParameter("gzipfeed")); + + if (serveFeed) { + final String aimHeader = request.getHeader("A-IM"); + final boolean serveDeltaEncodedFeed = aimHeader != null && aimHeader.indexOf("feed") >= 0 + && "TRUE".equalsIgnoreCase(request.getParameter("deltaencode")); + if (serveDeltaEncodedFeed) { + try { + sendDeltaEncodedData(response, lastModifiedDate, request.getHeader("If-None-Match"), eTag, gzip); + } catch (final FeedException e) { + throw new ServletException(e); + } + } else { + sendFeedData(response, lastModifiedDate, eTag, gzip); + } + return; + } else { + response.sendError(HttpServletResponse.SC_NOT_MODIFIED); + return; + } + } + } + + private boolean checkModified(final HttpServletRequest request, final String lastModifiedDate, final String eTag) { + + final String requestedETag = request.getHeader("If-None-Match"); + final String requestedLastModified = request.getHeader("If-Modified-Since"); + boolean modified = true; + boolean mustServer = false; + if (requestedETag != null) { + if (eTag.equals(requestedETag)) { + modified = false; + } else { + modified = true; + mustServer = true; + } + } + if (requestedLastModified != null) { + if (lastModifiedDate.equals(requestedLastModified)) { + modified = false; + } else { + modified = true; + mustServer = true; + } + } + final boolean serveFeed = modified || mustServer; + return serveFeed; + } + + /** + * @param request + * @param lastModifiedDate + * @param tag + * @param gzip + * @throws IOException + * @throws FeedException + */ + private void sendDeltaEncodedData(final HttpServletResponse response, final String lastModifiedDate, final String requestedETag, final String responseETag, + final boolean gzip) throws IOException, FeedException { + if (ETAG_1.equals(requestedETag) || ETAG_2.equals(requestedETag)) { + OutputStream out = null; + if (gzip) { + response.setHeader("Content-Encoding", "gzip"); + out = new GZIPOutputStream(response.getOutputStream()); + } else { + out = response.getOutputStream(); + } + + response.setContentType("text/xml"); + response.setStatus(226); + if (gzip) { + response.setHeader("IM", "feed, gzip"); + } else { + response.setHeader("IM", "feed"); + } + + if (responseETag != null) { + response.setHeader("ETag", responseETag); + } + if (lastModifiedDate != null) { + response.setHeader("Last-Modified", lastModifiedDate); + } + + final SyndFeed feed = new SyndFeedImpl(); + feed.setFeedType("atom_1.0"); + + feed.setTitle(DELTA_FEED_TITLE); + feed.setLink("http://rome.dev.java.net"); + feed.setDescription("This tests using rfc3229 delta encoding."); + + final List entries = new ArrayList(); + SyndEntry entry; + SyndContent description; + + entry = new SyndEntryImpl(); + entry.setTitle(DELTA_FEED_ENTRY_TITLE); + entry.setLink("http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html"); + try { + final DateFormat dateParser = new SimpleDateFormat("yyyy-MM-dd"); + entry.setPublishedDate(dateParser.parse("2004-11-25")); + } catch (final ParseException ex) { + // + } + description = new SyndContentImpl(); + description.setType("text/plain"); + description.setValue("Test for RFC3229 Delta Encoding"); + entry.setDescription(description); + entries.add(entry); + + feed.setEntries(entries); + + final SyndFeedOutput output = new SyndFeedOutput(); + output.output(feed, new OutputStreamWriter(out)); + } else { + sendFeedData(response, lastModifiedDate, responseETag, gzip); + } + } + + private void sendFeedData(final HttpServletResponse response, final String lastModifiedDate, final String eTag, final boolean gzip) throws IOException { + OutputStream out = null; + if (gzip) { + response.setHeader("Content-Encoding", "gzip"); + out = new GZIPOutputStream(response.getOutputStream()); + } else { + out = response.getOutputStream(); + } + + response.setContentType("text/xml"); + if (eTag != null) { + response.setHeader("ETag", eTag); + } + if (lastModifiedDate != null) { + response.setHeader("Last-Modified", lastModifiedDate); + } + + InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("/atom_1.0.xml"); + if (inputStream == null) { + inputStream = this.getClass().getResourceAsStream("/atom_1.0.xml"); + } + + final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + try { + String line; + while ((line = reader.readLine()) != null) { + out.write(line.getBytes()); + line = null; + } + } finally { + if (reader != null) { + reader.close(); + } + } + + out.close(); + } +} diff --git a/rome-fetcher/src/test/java/com/rometools/fetcher/TestBasicAuthenticator.java b/rome-fetcher/src/test/java/com/rometools/fetcher/TestBasicAuthenticator.java new file mode 100644 index 0000000..355dd4b --- /dev/null +++ b/rome-fetcher/src/test/java/com/rometools/fetcher/TestBasicAuthenticator.java @@ -0,0 +1,38 @@ +/* + * 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.rometools.fetcher; + +import java.net.Authenticator; +import java.net.PasswordAuthentication; + +/** + * @author nl + */ +public class TestBasicAuthenticator extends Authenticator { + + /** + * @see java.net.Authenticator#getPasswordAuthentication() + */ + @Override + protected PasswordAuthentication getPasswordAuthentication() { + if ("localhost".equals(getRequestingHost())) { + return new PasswordAuthentication("username", "password".toCharArray()); + } else { + return null; + } + } +} diff --git a/rome-fetcher/src/test/java/com/rometools/fetcher/impl/DiskFeedInfoCacheTest.java b/rome-fetcher/src/test/java/com/rometools/fetcher/impl/DiskFeedInfoCacheTest.java new file mode 100644 index 0000000..59b17bc --- /dev/null +++ b/rome-fetcher/src/test/java/com/rometools/fetcher/impl/DiskFeedInfoCacheTest.java @@ -0,0 +1,44 @@ +package com.rometools.fetcher.impl; + +import java.io.File; +import java.net.URL; + +import junit.framework.TestCase; + +import com.rometools.fetcher.impl.DiskFeedInfoCache; +import com.rometools.fetcher.impl.SyndFeedInfo; + +public class DiskFeedInfoCacheTest extends TestCase { + + public void testClear() throws Exception { + final File cacheDir = new File("test-cache"); + cacheDir.mkdir(); + cacheDir.deleteOnExit(); + + final DiskFeedInfoCache cache = new DiskFeedInfoCache(cacheDir.getCanonicalPath()); + final SyndFeedInfo info = new SyndFeedInfo(); + final URL url = new URL("http://nowhere.com"); + cache.setFeedInfo(url, info); + + cache.clear(); + final Object returned = cache.getFeedInfo(url); + assertTrue(returned == null); + } + + public void testRemove() throws Exception { + final File cacheDir = new File("test-cache"); + cacheDir.mkdir(); + cacheDir.deleteOnExit(); + + final DiskFeedInfoCache cache = new DiskFeedInfoCache(cacheDir.getCanonicalPath()); + final SyndFeedInfo info = new SyndFeedInfo(); + final URL url = new URL("http://nowhere.com"); + cache.setFeedInfo(url, info); + + final SyndFeedInfo removedInfo = cache.remove(url); + assertTrue(removedInfo.equals(info)); + final SyndFeedInfo shouldBeNull = cache.remove(url); + assertTrue(null == shouldBeNull); + } + +} diff --git a/rome-fetcher/src/test/java/com/rometools/fetcher/impl/HashMapFeedInfoCacheTest.java b/rome-fetcher/src/test/java/com/rometools/fetcher/impl/HashMapFeedInfoCacheTest.java new file mode 100644 index 0000000..1ab7878 --- /dev/null +++ b/rome-fetcher/src/test/java/com/rometools/fetcher/impl/HashMapFeedInfoCacheTest.java @@ -0,0 +1,42 @@ +package com.rometools.fetcher.impl; + +import java.net.URL; + +import junit.framework.TestCase; + +import com.rometools.fetcher.impl.HashMapFeedInfoCache; +import com.rometools.fetcher.impl.SyndFeedInfo; + +public class HashMapFeedInfoCacheTest extends TestCase { + + public void testRemove() throws Exception { + final HashMapFeedInfoCache cache = new HashMapFeedInfoCache(); + assertNotNull(cache); + + final URL url = new URL("http://foo.com"); + final SyndFeedInfo syndFeedInfo = new SyndFeedInfo(); + syndFeedInfo.setUrl(url); + cache.setFeedInfo(url, syndFeedInfo); + + final SyndFeedInfo returned = cache.remove(url); + assertTrue(returned.equals(syndFeedInfo)); + assertTrue(url.equals(returned.getUrl())); + } + + public void testClear() throws Exception { + final HashMapFeedInfoCache cache = new HashMapFeedInfoCache(); + assertNotNull(cache); + + final URL url = new URL("http://foo.com"); + final SyndFeedInfo syndFeedInfo = new SyndFeedInfo(); + syndFeedInfo.setUrl(url); + cache.setFeedInfo(url, syndFeedInfo); + + // clear it + cache.clear(); + + // we should not get a result back + final Object returned = cache.getFeedInfo(url); + assertTrue(returned == null); + } +} diff --git a/rome-fetcher/src/test/java/com/rometools/fetcher/impl/HttpClientFeedFetcherTest.java b/rome-fetcher/src/test/java/com/rometools/fetcher/impl/HttpClientFeedFetcherTest.java new file mode 100644 index 0000000..c64339b --- /dev/null +++ b/rome-fetcher/src/test/java/com/rometools/fetcher/impl/HttpClientFeedFetcherTest.java @@ -0,0 +1,65 @@ +/* + * 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.rometools.fetcher.impl; + +import org.apache.commons.httpclient.Credentials; +import org.apache.commons.httpclient.UsernamePasswordCredentials; + +import com.rometools.fetcher.AbstractJettyTest; +import com.rometools.fetcher.FeedFetcher; +import com.rometools.fetcher.impl.FeedFetcherCache; +import com.rometools.fetcher.impl.HttpClientFeedFetcher; + +/** + * @author Nick Lothian + */ +public class HttpClientFeedFetcherTest extends AbstractJettyTest { + + public HttpClientFeedFetcherTest(final String s) { + super(s); + } + + /** + * @see com.rometools.rome.fetcher.impl.AbstractJettyTest#getFeedFetcher() + */ + @Override + protected FeedFetcher getFeedFetcher() { + return new HttpClientFeedFetcher(); + } + + @Override + protected FeedFetcher getFeedFetcher(final FeedFetcherCache cache) { + return new HttpClientFeedFetcher(cache); + } + + /** + * @see com.rometools.rome.fetcher.impl.AbstractJettyTest#getAuthenticatedFeedFetcher() + */ + @Override + public FeedFetcher getAuthenticatedFeedFetcher() { + return new HttpClientFeedFetcher(null, new HttpClientFeedFetcher.CredentialSupplier() { + @Override + public Credentials getCredentials(final String realm, final String host) { + if ("localhost".equals(host)) { + return new UsernamePasswordCredentials("username", "password"); + } else { + return null; + } + } + }); + } +} diff --git a/rome-fetcher/src/test/java/com/rometools/fetcher/impl/HttpURLFeedFetcherTest.java b/rome-fetcher/src/test/java/com/rometools/fetcher/impl/HttpURLFeedFetcherTest.java new file mode 100644 index 0000000..c0ba1fe --- /dev/null +++ b/rome-fetcher/src/test/java/com/rometools/fetcher/impl/HttpURLFeedFetcherTest.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.rometools.fetcher.impl; + +import com.rometools.fetcher.AbstractJettyTest; +import com.rometools.fetcher.FeedFetcher; +import com.rometools.fetcher.TestBasicAuthenticator; +import com.rometools.fetcher.impl.FeedFetcherCache; +import com.rometools.fetcher.impl.HttpURLFeedFetcher; + +public class HttpURLFeedFetcherTest extends AbstractJettyTest { + + public HttpURLFeedFetcherTest(final String s) { + super(s); + } + + /** + * @see com.rometools.rome.fetcher.impl.AbstractJettyTest#getFeedFetcher() + */ + @Override + protected FeedFetcher getFeedFetcher() { + return new HttpURLFeedFetcher(); + } + + @Override + protected FeedFetcher getFeedFetcher(final FeedFetcherCache cache) { + return new HttpURLFeedFetcher(cache); + } + + /** + * @see com.rometools.rome.fetcher.impl.AbstractJettyTest#getAuthenticatedFeedFetcher() + */ + @Override + public FeedFetcher getAuthenticatedFeedFetcher() { + // setup the authenticator + java.net.Authenticator.setDefault(new TestBasicAuthenticator()); + + final FeedFetcher feedFetcher = getFeedFetcher(); + + return feedFetcher; + } + +} diff --git a/rome-fetcher/src/test/java/com/rometools/fetcher/impl/ResponseHandlerTest.java b/rome-fetcher/src/test/java/com/rometools/fetcher/impl/ResponseHandlerTest.java new file mode 100644 index 0000000..71bfb4f --- /dev/null +++ b/rome-fetcher/src/test/java/com/rometools/fetcher/impl/ResponseHandlerTest.java @@ -0,0 +1,42 @@ +/* + * 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.rometools.fetcher.impl; + +import junit.framework.TestCase; + +import com.rometools.fetcher.impl.ResponseHandler; + +public class ResponseHandlerTest extends TestCase { + + /** + * Constructor for ResponseHandlerTest. + */ + public ResponseHandlerTest(final String arg0) { + super(arg0); + } + + public void testGetCharacterEncodingString() { + assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding((String) null)); + assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding("text/xml")); + assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding("text/xml;")); + assertEquals("ISO-8859-4", ResponseHandler.getCharacterEncoding("text/xml; charset=ISO-8859-4")); + assertEquals("ISO-8859-4", ResponseHandler.getCharacterEncoding("text/xml;charset=ISO-8859-4")); + assertEquals("ISO-8859-4", ResponseHandler.getCharacterEncoding("text/xml;charset=ISO-8859-4;something")); + assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding("text/xml;something")); + } + +} diff --git a/rome-fetcher/src/test/java/com/rometools/fetcher/samples/FeedAggregator.java b/rome-fetcher/src/test/java/com/rometools/fetcher/samples/FeedAggregator.java new file mode 100644 index 0000000..32b7907 --- /dev/null +++ b/rome-fetcher/src/test/java/com/rometools/fetcher/samples/FeedAggregator.java @@ -0,0 +1,102 @@ +/* + * 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.rometools.fetcher.samples; + +import java.io.PrintWriter; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import com.rometools.fetcher.FeedFetcher; +import com.rometools.fetcher.impl.FeedFetcherCache; +import com.rometools.fetcher.impl.HashMapFeedInfoCache; +import com.rometools.fetcher.impl.HttpURLFeedFetcher; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndFeedImpl; +import com.rometools.rome.io.SyndFeedOutput; + +/** + *

+ * It aggregates a list of RSS/Atom feeds (they can be of different types) into a single feed of the + * specified type. + *

+ * + *

+ * Converted from the original FeedAggregator sample + *

+ * + * @author Alejandro Abdelnur + * @author Nick Lothian + * + */ +public class FeedAggregator { + + public static void main(final String[] args) { + + boolean ok = false; + + if (args.length >= 2) { + + try { + + final String outputType = args[0]; + + final SyndFeed feed = new SyndFeedImpl(); + feed.setFeedType(outputType); + + feed.setTitle("Aggregated Feed"); + feed.setDescription("Anonymous Aggregated Feed"); + feed.setAuthor("anonymous"); + feed.setLink("http://www.anonymous.com"); + + final List entries = new ArrayList(); + feed.setEntries(entries); + + final FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance(); + final FeedFetcher feedFetcher = new HttpURLFeedFetcher(feedInfoCache); + + for (int i = 1; i < args.length; i++) { + final URL inputUrl = new URL(args[i]); + final SyndFeed inFeed = feedFetcher.retrieveFeed(inputUrl); + entries.addAll(inFeed.getEntries()); + } + + final SyndFeedOutput output = new SyndFeedOutput(); + output.output(feed, new PrintWriter(System.out)); + + ok = true; + + } catch (final Exception ex) { + System.out.println("ERROR: " + ex.getMessage()); + ex.printStackTrace(); + } + + } + + if (!ok) { + System.out.println(); + System.out.println("FeedAggregator aggregates different feeds into a single one."); + System.out.println("The first parameter must be the feed type for the aggregated feed."); + System.out.println(" [valid values are: rss_0.9, rss_0.91, rss_0.92, rss_0.93, ]"); + System.out.println(" [ rss_0.94, rss_1.0, rss_2.0 & atom_0.3 ]"); + System.out.println("The second to last parameters are the URLs of feeds to aggregate."); + System.out.println(); + } + } + +} diff --git a/rome-fetcher/src/test/java/com/rometools/fetcher/samples/FeedReader.java b/rome-fetcher/src/test/java/com/rometools/fetcher/samples/FeedReader.java new file mode 100644 index 0000000..54d4be7 --- /dev/null +++ b/rome-fetcher/src/test/java/com/rometools/fetcher/samples/FeedReader.java @@ -0,0 +1,104 @@ +/* + * 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.rometools.fetcher.samples; + +import java.net.URL; + +import com.rometools.fetcher.FeedFetcher; +import com.rometools.fetcher.FetcherEvent; +import com.rometools.fetcher.FetcherListener; +import com.rometools.fetcher.impl.FeedFetcherCache; +import com.rometools.fetcher.impl.HashMapFeedInfoCache; +import com.rometools.fetcher.impl.HttpURLFeedFetcher; +import com.rometools.rome.feed.synd.SyndFeed; + +/** + * Reads and prints any RSS/Atom feed type. Converted from the original Rome sample FeedReader + *

+ * + * @author Alejandro Abdelnur + * @author Nick Lothian + * + */ +public class FeedReader { + + public static void main(final String[] args) { + + boolean ok = false; + + if (args.length == 1) { + + try { + final URL feedUrl = new URL(args[0]); + final FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance(); + final FeedFetcher fetcher = new HttpURLFeedFetcher(feedInfoCache); + + final FetcherEventListenerImpl listener = new FetcherEventListenerImpl(); + + fetcher.addFetcherEventListener(listener); + + System.err.println("Retrieving feed " + feedUrl); + // Retrieve the feed. + // We will get a Feed Polled Event and then a + // Feed Retrieved event (assuming the feed is valid) + final SyndFeed feed = fetcher.retrieveFeed(feedUrl); + + System.err.println(feedUrl + " retrieved"); + System.err.println(feedUrl + " has a title: " + feed.getTitle() + " and contains " + feed.getEntries().size() + " entries."); + // We will now retrieve the feed again. If the feed is unmodified + // and the server supports conditional gets, we will get a "Feed + // Unchanged" event after the Feed Polled event + System.err.println("Polling " + feedUrl + " again to test conditional get support."); + fetcher.retrieveFeed(feedUrl); + System.err.println("If a \"Feed Unchanged\" event fired then the server supports conditional gets."); + + ok = true; + + } catch (final Exception ex) { + System.out.println("ERROR: " + ex.getMessage()); + ex.printStackTrace(); + } + + } + + if (!ok) { + System.out.println(); + System.out.println("FeedReader reads and prints any RSS/Atom feed type."); + System.out.println("The first parameter must be the URL of the feed to read."); + System.out.println(); + } + + } + + static class FetcherEventListenerImpl implements FetcherListener { + /** + * @see com.rometools.rome.fetcher.FetcherListener#fetcherEvent(com.rometools.rome.fetcher.FetcherEvent) + */ + @Override + public void fetcherEvent(final FetcherEvent event) { + final String eventType = event.getEventType(); + if (FetcherEvent.EVENT_TYPE_FEED_POLLED.equals(eventType)) { + System.err.println("\tEVENT: Feed Polled. URL = " + event.getUrlString()); + } else if (FetcherEvent.EVENT_TYPE_FEED_RETRIEVED.equals(eventType)) { + System.err.println("\tEVENT: Feed Retrieved. URL = " + event.getUrlString()); + } else if (FetcherEvent.EVENT_TYPE_FEED_UNCHANGED.equals(eventType)) { + System.err.println("\tEVENT: Feed Unchanged. URL = " + event.getUrlString()); + } + } + } +} diff --git a/src/test/data/atom_1.0.xml b/rome-fetcher/src/test/resources/atom_1.0.xml similarity index 100% rename from src/test/data/atom_1.0.xml rename to rome-fetcher/src/test/resources/atom_1.0.xml diff --git a/rome-fetcher/src/test/resources/logback-test.xml b/rome-fetcher/src/test/resources/logback-test.xml new file mode 100644 index 0000000..c34b099 --- /dev/null +++ b/rome-fetcher/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + \ No newline at end of file diff --git a/rome-fetcher/src/test/resources/testuser.properties b/rome-fetcher/src/test/resources/testuser.properties new file mode 100644 index 0000000..28bc8e6 --- /dev/null +++ b/rome-fetcher/src/test/resources/testuser.properties @@ -0,0 +1 @@ +username: password diff --git a/rome-modules/.gitignore b/rome-modules/.gitignore new file mode 100644 index 0000000..998692d --- /dev/null +++ b/rome-modules/.gitignore @@ -0,0 +1,5 @@ +/.classpath +/.project +/.settings +/target +/.checkstyle diff --git a/rome-modules/LICENSE b/rome-modules/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/rome-modules/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/rome-modules/README.md b/rome-modules/README.md new file mode 100644 index 0000000..8504b20 --- /dev/null +++ b/rome-modules/README.md @@ -0,0 +1,6 @@ +rome +==== + +ROME is a set of RSS and Atom Utilities for Java. It makes it easy to work in Java with most syndication formats: RSS 0.90, RSS 0.91 Netscape, RSS 0.91 Userland, RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, RSS 2.0, Atom 0.3, Atom 1.0 + +More Information: http://rometools.github.io/rome-modules/ diff --git a/rome-modules/pom.xml b/rome-modules/pom.xml new file mode 100644 index 0000000..d49ed96 --- /dev/null +++ b/rome-modules/pom.xml @@ -0,0 +1,119 @@ + + + 4.0.0 + + + com.rometools + rome-parent + 1.6.0-SNAPSHOT + + + rome-modules + 1.6.0-SNAPSHOT + jar + + rome-modules + + Plugin collection for the ROME RSS and Atom Utilities + + http://rometools.github.io/rome-modules/ + + + scm:git:ssh://github.com/rometools/rome-modules.git + scm:git:ssh://git@github.com/rometools/rome-modules.git + https://github.com/rometools/rome-modules + + + + + kebernet + kebernet@gmail.com + Robert Cooper + + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + gh-pages + ${project.scm.developerConnection} + ${project.build.directory}/site + + + + org.apache.felix + maven-bundle-plugin + + + + !com.rometools.modules.*.io, + com.rometools.modules.*, + + + org.jdom2, + org.jdom2.filter, + org.jdom2.input, + org.jdom2.input.sax, + org.jdom2.output, + org.slf4j, + org.w3c.dom, + org.xml.sax + + <_exportcontents> + com.rometools.rome.feed, + com.rometools.rome.feed.atom, + com.rometools.rome.feed.module, + com.rometools.rome.feed.rss, + com.rometools.rome.feed.synd, + com.rometools.rome.io, + com.rometools.utils + + *;artifactId=rome|rome-utils + true + + + + + + + + + com.rometools + rome + 1.6.0-SNAPSHOT + + + ch.qos.logback + logback-classic + test + + + junit + junit + test + + + org.hamcrest + hamcrest-library + test + + + + diff --git a/rome-modules/src/main/etc/header.txt b/rome-modules/src/main/etc/header.txt new file mode 100644 index 0000000..09cdc51 --- /dev/null +++ b/rome-modules/src/main/etc/header.txt @@ -0,0 +1,17 @@ +/* + * Copyright (C) The ROME Team ${year} + * + * + * 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. + * + */ \ No newline at end of file diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/ActivityStreamModule.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/ActivityStreamModule.java new file mode 100644 index 0000000..e4b0f4c --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/ActivityStreamModule.java @@ -0,0 +1,46 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams; + +import com.rometools.modules.activitystreams.types.ActivityObject; +import com.rometools.modules.activitystreams.types.Mood; +import com.rometools.modules.activitystreams.types.Verb; + +/** + * + * @author robert.cooper + */ +public interface ActivityStreamModule { + + public Verb getVerb(); + + public void setVerb(Verb verb); + + public ActivityObject getObject(); + + public void setObject(ActivityObject object); + + public ActivityObject getTarget(); + + public void setTarget(ActivityObject object); + + public Mood getMood(); + + public void setMood(Mood mood); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/ActivityStreamModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/ActivityStreamModuleImpl.java new file mode 100644 index 0000000..797ed63 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/ActivityStreamModuleImpl.java @@ -0,0 +1,90 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ +package com.rometools.modules.activitystreams; + +import com.rometools.modules.activitystreams.types.ActivityObject; +import com.rometools.modules.activitystreams.types.Mood; +import com.rometools.modules.activitystreams.types.Verb; + +/** + * + * @author robert.cooper + */ +public class ActivityStreamModuleImpl implements ActivityStreamModule { + private ActivityObject object; + private Verb verb; + + /** + * Set the value of object + * + * @param newobject new value of object + */ + @Override + public void setObject(final ActivityObject newobject) { + object = newobject; + } + + /** + * Get the value of object + * + * @return the value of object + */ + @Override + public ActivityObject getObject() { + return object; + } + + /** + * Set the value of verb + * + * @param newverb new value of verb + */ + @Override + public void setVerb(final Verb newverb) { + verb = newverb; + } + + /** + * Get the value of verb + * + * @return the value of verb + */ + @Override + public Verb getVerb() { + return verb; + } + + @Override + public ActivityObject getTarget() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setTarget(final ActivityObject object) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Mood getMood() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setMood(final Mood mood) { + throw new UnsupportedOperationException("Not supported yet."); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/ActivityObject.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/ActivityObject.java new file mode 100644 index 0000000..513e359 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/ActivityObject.java @@ -0,0 +1,57 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +import com.rometools.modules.georss.GeoRSSModule; +import com.rometools.modules.portablecontacts.ContactModule; +import com.rometools.rome.feed.atom.Entry; + +/** + * + * @author robert.cooper + */ +public abstract class ActivityObject extends Entry implements HasLocation { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public abstract String getTypeIRI(); + + @Override + public GeoRSSModule getLocation() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setLocation(final GeoRSSModule location) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ContactModule getAddress() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setAddress(final ContactModule address) { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Article.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Article.java new file mode 100644 index 0000000..62e139b --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Article.java @@ -0,0 +1,60 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "article" Object type indicates that the Object is an article, such as a news article, a + * knowledge base entry, or other similar construct. + *

+ *

+ * Articles generally consist of paragraphs of text, in some cases incorporating embedded media such + * as photos and inline hyperlinks to other resources. + *

+ *

+ * The "Article" Object type is identified by the URL + * http://activitystrea.ms/schema/1.0/article. + *

+ *

+ * An article has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Name
+ *
The title of the article. Represented by the Name component of the base Object Construct.
+ *
Content
+ *
The main body content of the article. Represented in JSON as a property called + * content whose value is a JSON string containing a fragment of HTML that represents the + * content.
+ *
+ *
+ * + * @author robert.cooper + */ +public class Article extends ActivityObject { + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/article"; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Audio.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Audio.java new file mode 100644 index 0000000..2fa0a0d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Audio.java @@ -0,0 +1,94 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "audio" Object type represents audio content. + *

+ *

+ * The "audio" Object type is identified by the URI + * http://activitystrea.ms/schema/1.0/audio. + *

+ *

+ * An audio has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Audio Stream Link
+ *
A Media Link Construct linking to the audio content itself. Represented in JSON as a property + * called stream whose value is a JSON object with properties as defined in [TODO: xref the + * JSON serialization of a Media Link Construct]
+ *
Embed Code
+ *
An HTML fragment that, when embedded in an HTML page, will provide an interactive player UI + * for the audio stream. Represented in JSON as a property called embedCode whose value is + * a JSON string containing the fragment of HTML.
+ *
+ * + * @author robert.cooper + */ +public class Audio extends ActivityObject { + /** + * + */ + private static final long serialVersionUID = 1L; + private String embedCode; + private String streamLink; + + /** + * Set the value of embedCode + * + * @param newembedCode new value of embedCode + */ + public void setEmbedCode(final String newembedCode) { + embedCode = newembedCode; + } + + /** + * Get the value of embedCode + * + * @return the value of embedCode + */ + public String getEmbedCode() { + return embedCode; + } + + /** + * Set the value of streamLink + * + * @param newstreamLink new value of streamLink + */ + public void setStreamLink(final String newstreamLink) { + streamLink = newstreamLink; + } + + /** + * Get the value of streamLink + * + * @return the value of streamLink + */ + public String getStreamLink() { + return streamLink; + } + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/audio"; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Bookmark.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Bookmark.java new file mode 100644 index 0000000..5a229cf --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Bookmark.java @@ -0,0 +1,117 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +import com.rometools.rome.feed.atom.Link; + +/** + *

+ * The "bookmark" Object type represents a pointer to some URL -- typically a web page. In most + * cases, a bookmark is specific to a given user and contains metadata chosen by that user. Bookmark + * Objects are similar in principle to the concept of bookmarks or favorites in a web browser. A + * bookmark represents a pointer to the URL, not the URL or the associated resource itself. + *

+ *

+ * When dealing with bookmarks it is important to note the distinction between the title, + * description, and URL of the bookmark itself and the title, content, and URL of the resource that + * is the target of the bookmark. In some implementations these MAY be the same, but bookmark + * managers often allow a user to edit the title and description of his or her own bookmarks to + * differ from the metadata on the target itself. + *

+ *

+ * Some implementations refer to this Object type as a "link". This specification uses the term + * "bookmark" to avoid confusion with the general concept of hyperlinks which apply to all Object + * types. + *

+ *

+ * Since bookmarks are often specific to a particular user, even though multiple users might have + * bookmarks pointing at the same resource, it is appropriate to use the "post" Verb to describe the + * publication of such a bookmark. The "mark as favorite" Verb SHOULD be used when a user flags + * another user's bookmark as being a favorite without creating his own bookmark, or when a user + * flags his own bookmark as being a favorite as a special classification within his own bookmark + * collection. + *

+ *

+ * The "bookmark" Object type is identified by the URI + * http://activitystrea.ms/schema/1.0/bookmark. + *

+ *

+ * A bookmark has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Title
+ *
The title of the bookmark, as entered by the user who created the bookmark. Represented by + * the Name component of the base Object Construct. Publishers MAY use the title of the target + * resource as a default for this property where a user hasn't entered a customized value.
+ *
Target URL
+ *
The URL of the item that is the target of the bookmark. Represented in JSON by a property + * called targetUrl whose value is a JSON string containing the target URL.
+ *
Thumbnail
+ *
The URL and metadata for a thumbnail version of the page. Represented by the Representative + * Image component of the base Object Construct. Processors MAY ignore thumbnails that are of an + * inappropriate size for their user interface.
+ *
+ *
+ * + * @author robert.cooper + */ +public class Bookmark extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/bookmark"; + } + + /** + * Get the value of thumbnail + * + * @return the value of thumbnail + */ + public Link getThumbnail() { + return findRelatedLink("thumbnail"); + } + + /** + * Set the value of thumbnail + * + * @param newthumbnail new value of thumbnail + */ + public void setThumbnail(final Link newthumbnail) { + Link old = null; + for (final Link l : getOtherLinks()) { + if ("thumbnail".equals(l.getRel())) { + old = l; + break; + } + } + if (old != null) { + getOtherLinks().remove(old); + newthumbnail.setRel("thumbnail"); + } + getOtherLinks().add(newthumbnail); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Comment.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Comment.java new file mode 100644 index 0000000..7de8614 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Comment.java @@ -0,0 +1,67 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "comment" object type represents a textual response to another object. + *

+ *

+ * The comment object type MUST NOT be used for other kinds of replies, such as video replies or + * reviews. + *

+ *

+ * The "comment" object type is identified by the URI + * http://activitystrea.ms/schema/1.0/comment. + *

+ *

+ * A comment has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Subject
+ *
The subject of the comment. Represented by the Name component of the base Object Construct. + * Many systems do not have the concept of a title or subject for a comment; such systems MUST omit + * the Name component. Processors SHOULD refer to such comments as simply being "a comment", with + * appropriate localization, if they are to be described in a sentence.
+ *
Content
+ *
The content of the comment. Represented in JSON as a property called content whose + * value is a JSON string containing a fragment of HTML that represents the content. Publishers + * SHOULD include any markup necessary to achieve a similar presentation to that on the publisher's + * own HTML pages, including any links that the service automatically adds. Processors MAY remove + * all HTML markup and consider the comment to be plain text.
+ *
+ *
+ * + * @author robert.cooper + */ +public class Comment extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/comment"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Event.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Event.java new file mode 100644 index 0000000..f2c1be1 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Event.java @@ -0,0 +1,61 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "event" object type represents an event that occurs in a certain place during a particular + * interval of time. + *

+ *

+ * The object type URL for the "event" object type is + * http://activitystrea.ms/schema/1.0/event. + *

+ *

+ * An event has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Start Date and Time
+ *
The date and time that the event begins. Represented in JSON as a property called + * startTime whose value is JSON string containing a W3CDTF timestamp. [TODO: Reference + * W3CDTF spec.] [TODO: Include prose describing how to represent just a date vs. a date and time.]
+ *
End Date and Time
+ *
The date and time that the event ends. Represented in JSON as a property called + * endTime whose value is JSON string containing a W3CDTF timestamp. [TODO: Reference + * W3CDTF spec.] [TODO: Include prose describing how to represent just a date vs. a date and time.]
+ *
+ *
+ * + * @author robert.cooper + */ +public class Event extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/event"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/File.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/File.java new file mode 100644 index 0000000..862c2dc --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/File.java @@ -0,0 +1,63 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "file" Object type represents some document or other file with no additional machine-readable + * semantics. + *

+ *

+ * It is intended that this type be used as a base type for other Objects that manifest as files, so + * that additional semantics can be added while providing a fallback ability for clients that do not + * support the more specific Object type. + *

+ *

+ * The "file" Object type is identified by the URI http://activitystrea.ms/schema/1.0/file. + *

+ *

+ * A file has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Associated File URL
+ *
The URL of the file described by this Object Construct. Represented in JSON by a property + * called fileUrl whose value is a JSON string containing the URL.
+ *
File MIME Type
+ *
The MIME type of the file described by this Object Construct. Represented in JSON by a + * property called mimeType whose value is a JSON string containing the MIME type.
+ *
+ *
+ * + * @author robert.cooper + */ +public class File extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/file"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Folder.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Folder.java new file mode 100644 index 0000000..2694940 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Folder.java @@ -0,0 +1,57 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "folder" object type represents a collection of files or media objects. This is similar to + * the "photo album" object type, but not specifically representing a collection of "photos." + *

+ *

+ * The "folder" object type is identified by the URI + * http://activitystrea.ms/schema/1.0/folder. + *

+ *

+ * A folder has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Preview Image Link
+ *
A Media Link Construct describing an image file that can be used as a preview image for the + * folder. Represented by the Representative Image component of the base Object Construct. + * Processors MAY ignore thumbnails that are of an inappropriate size for their user interface.
+ *
+ *
+ * + * @author robert.cooper + */ +public class Folder extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/folder"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Group.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Group.java new file mode 100644 index 0000000..952e2f0 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Group.java @@ -0,0 +1,36 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "group" Object type represents a social networking group. A group is a collection of people + * which people can join and leave. + *

+ *

+ * The "group" Object type is identified by the URI + * http://activitystrea.ms/schema/1.0/group. + *

+ *

+ * A group has no additional components. + * + * @author robert.cooper + */ +public class Group { + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/HasLocation.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/HasLocation.java new file mode 100644 index 0000000..8b1705c --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/HasLocation.java @@ -0,0 +1,104 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +import com.rometools.modules.georss.GeoRSSModule; +import com.rometools.modules.portablecontacts.ContactModule; + +/** + *

+ * Location is a concept which can be used inside the atom:entry level, atom:author and + * activity:object. Location can be specified via geographic coordinates, a street address, a + * free-form location name or a combination of these. Geographic coordinates should be included as a + * geo:point element as described by the GeoRSS specification. Addresses should be included using a + * poco:address element defined at Portable Contacts specification. The entry level location + * represents the location of the author at the time the activity was performed. The author level + * location represents the primary location of the author. Finally, the location within other + * objects represents the physical location of those objects. All location fields are optional. For + * free form addresses use the poco:formatted field. + *

+ *

+ * Figure 1 (Location + * Example) + *

+ *

+ *
+ *


+ * + *

+ *
+ * + *
+ * <entry>
+ *   <id>tag:world:activity:1212121212121</id>
+ *   <title>Rob liked Goldeberg's Deli</title>
+ *   <author>
+ *     <name>Rob Dolin</name>
+ *     <id>tag:world:person:1212121212121</id>
+ *     <link rel="alternate" type="text/html" href="http://robdolin.com" />
+ *     <poco:address>
+ *       <poco:locality>Marina del Rey</poco:locality>
+ *       <poco:region>CA</poco:region>
+ *       <poco:postalCode>90292</poco:postalCode>
+ *       <poco:country>US</poco:country>
+ *     </poco:address>
+ *   </author>
+ *   <activity:object>
+ *     <activity:object-type>http://activitystrea.ms/schema/1.0/place</object-type>
+ *     <id>tag:world:place:1212121212121</id>
+ *     <title>Goldberg's Deli</title>
+ *     <link rel="alternate" type="text/html" href="http://www.deli.com" />
+ *     <geo:point>33.9777 -118.4351</geo:point>
+ *     <poco:address>
+ *       <poco:streetAddress>14016 Bora Bora Way</poco:streetAddress>
+ *       <poco:locality>Marina del Rey</poco:locality>
+ *       <poco:region>CA</poco:region>
+ *       <poco:postalCode>90292</poco:postalCode>
+ *       <poco:country>US</poco:country>
+ *     </poco:address>
+ *   </activity:object>
+ *   <geo:point>33.9777 -119.4351</geo:point>
+ *   <activity:verb>http://activitystrea.ms/schema/1.0/like</activity:verb>
+ * </entry>
+ * 
+ * + *
+ *

+ * + * + * + * + *
 Figure 1: Location + * Example 
+ *
+ *


+ * + *

+ * + * @author robert.cooper + */ +public interface HasLocation { + + public GeoRSSModule getLocation(); + + public void setLocation(GeoRSSModule location); + + public ContactModule getAddress(); + + public void setAddress(ContactModule address); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/List.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/List.java new file mode 100644 index 0000000..d2a5010 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/List.java @@ -0,0 +1,45 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "list" object type represents a collection of related objects. + *

+ *

+ * The "list" object type is identified by the URI http://activitystrea.ms/schema/1.0/list. + *

+ *

+ * A list has no additional components. + *

+ * + * @author robert.cooper + */ +public class List extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/list"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Mood.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Mood.java new file mode 100644 index 0000000..c215f67 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Mood.java @@ -0,0 +1,80 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ +package com.rometools.modules.activitystreams.types; + +/** + * + *

+ * Mood describes the mood of the user when the activity was performed. This is usually collected + * via an extra field in the user interface used to perform the activity. For the purpose of this + * schema, a mood is a freeform, short mood keyword or phrase along with an optional mood icon + * image. + *

+ *

+ * Moods are included via a mood element in the namespace http://activitystrea.ms/context/. + *

+ *

+ * The content of the mood element is the mood keyword or phrase. + *

+ *

+ * The mood element may have an optional icon attribute which contains the URL of a mood + * icon image. The mood icon image SHOULD be small and appropriate to be displayed alongside the + * mood keyword at a normal text size. + *

+ * + * @author robert.cooper + */ +public class Mood { + private String iconUrl; + private String text; + + /** + * Set the value of iconUrl + * + * @param newiconUrl new value of iconUrl + */ + public void setIconUrl(final String newiconUrl) { + iconUrl = newiconUrl; + } + + /** + * Get the value of iconUrl + * + * @return the value of iconUrl + */ + public String getIconUrl() { + return iconUrl; + } + + /** + * Set the value of text + * + * @param newtext new value of text + */ + public void setText(final String newtext) { + text = newtext; + } + + /** + * Get the value of text + * + * @return the value of text + */ + public String getText() { + return text; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Note.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Note.java new file mode 100644 index 0000000..8dd0128 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Note.java @@ -0,0 +1,64 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "note" Object type represents short-form text messages. This Object type is intended for use + * in "micro-blogging" and in systems where users are invited to publish short, often plain-text + * messages whose useful lifespan is generally shorter than that of an article or weblog entry. + *

+ *

+ * A note is similar in structure to an article, but it does not have a title and its body tends to + * be shorter. Applications will often display the entire content of a note in an activity stream + * UI, whereas they MAY display only the title or the title and summary for a weblog entry. + *

+ *

+ * The "note" Object type is identified by the URI http://activitystrea.ms/schema/1.0/note. + *

+ *

+ * A note has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Content
+ *
The content of the comment. Represented in JSON as a property called content whose + * value is a JSON string containing a fragment of HTML that represents the content. Publishers + * SHOULD include any markup necessary to achieve a similar presentation to that on the publisher's + * own HTML pages, including any links that the service automatically adds. Processors MAY remove + * all HTML markup and consider the comment to be plain text.
+ *
+ *
+ * + * @author robert.cooper + */ +public class Note extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/note"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Person.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Person.java new file mode 100644 index 0000000..6858773 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Person.java @@ -0,0 +1,89 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +import com.rometools.rome.feed.atom.Link; + +/** + *

+ * The "person" Object type represents a user account. This is often represents a person, but might + * also be a company or fictitious character that is being represented by a user account. + *

+ *

+ * The "person" Object type is identified by the URI + * http://activitystrea.ms/schema/1.0/person. + *

+ *

+ * A person has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Display Name
+ *
A name that can be used for the person in the user interface. This is often a name by which + * the individual is known in a given context; no restriction is placed on what kind of name may be + * used here. Represented by the Name component of the base Object Construct.
+ *
Avatar
+ *
A link to an "avatar" or "userpic" image for the user. Represented by the Representative + * Image component of the base Object Construct.
+ *
+ *
+ * + * @author robert.cooper + */ +public class Person extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/person"; + } + + /** + * Get the value of avatar + * + * @return the value of avatar + */ + public Link getAvatar() { + final Link result = findRelatedLink("avatar"); + if (result != null) { + return result; + } + return findRelatedLink("userpic"); + } + + /** + * Set the value of avatar + * + * @param newavatar new value of avatar + */ + public void setAvatar(final Link newavatar) { + final Link old = getAvatar(); + if (old != null) { + getOtherLinks().remove(old); + } + newavatar.setRel("avatar"); + getOtherLinks().add(newavatar); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Photo.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Photo.java new file mode 100644 index 0000000..d7ebe85 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Photo.java @@ -0,0 +1,61 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "photo" object type represents a graphical still image. + *

+ *

+ * The "photo" Object type is identified by the URI + * http://activitystrea.ms/schema/1.0/photo. + *

+ *

+ * A photo has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Thumbnail
+ *
A link to a thumbnail version of the image. Represented by the Representative Image component + * of the base Object Construct. Processors MAY ignore thumbnails that are of an inappropriate size + * for their user interface.
+ *
Larger Image
+ *
A Media Link Construct linking to a larger -- ideally, full-size -- version of the photo + * intended for standalone viewing. Represented in JSON as a property named fullImage whose + * value is a JSON object with properties as defined in [TODO: xref the JSON serialization of a + * Media Link Construct].
+ *
+ *
+ * + * @author robert.cooper + */ +public class Photo extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/photo"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/PhotoAlbum.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/PhotoAlbum.java new file mode 100644 index 0000000..b912057 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/PhotoAlbum.java @@ -0,0 +1,56 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "photo album" object type represents a collection of images. + *

+ *

+ * The "photo album" object type is identified by the URI + * http://activitystrea.ms/schema/1.0/photo-album. + *

+ *

+ * The photo album has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Preview Image Link
+ *
A Media Link Construct describing an image file that can be used as a preview image for the + * album. Represented by the Representative Image component of the base Object Construct. Processors + * MAY ignore thumbnails that are of an inappropriate size for their user interface.
+ *
+ *
+ * + * @author robert.cooper + */ +public class PhotoAlbum extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/photo-album"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Place.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Place.java new file mode 100644 index 0000000..ec3b645 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Place.java @@ -0,0 +1,60 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "place" object type represents a location on Earth. + *

+ *

+ * The "place" object type is identified by the URI + * http://activitystrea.ms/schema/1.0/place. + *

+ *

+ * A place has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Latitude
+ *
The latitude of the place as a point on Earth. Represented in JSON as a property named + * latitude whose value is a JSON number containing a decimal representation of the + * latitude in degrees.
+ *
Longitude
+ *
The longitude of the place as a point on Earth. Represented in JSON as a property named + * longitude whose value is a JSON number containing a decimal representation of the + * longitude in degrees.
+ *
+ *
+ * + * @author robert.cooper + */ +public class Place extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/place"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Playlist.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Playlist.java new file mode 100644 index 0000000..e12a04f --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Playlist.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + * + *

+ * The "playlist" object type represents an ordered list of time-based media items, such as video + * and audio objects. + *

+ *

+ * The "playlist" object type is identified by the URI + * http://activitystrea.ms/schema/1.0/playlist. + *

+ *

+ * A playlist has no additional components. + *

+ * + * @author robert.cooper + */ +public class Playlist extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/playlist"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Product.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Product.java new file mode 100644 index 0000000..f293283 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Product.java @@ -0,0 +1,61 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "product" object type represents a commercial good or service. + *

+ *

+ * The "product" object type is identified by the URI + * http://activitystrea.ms/schema/1.0/product. + *

+ *

+ * A product has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Thumbnail
+ *
A link to a thumbnail-sized image that contains a photo of the product. Represented by the + * Representative Image component of the base Object Construct. Processors MAY ignore thumbnails + * that are of an inappropriate size for their user interface.
+ *
Larger Image
+ *
A Media Link Construct linking to a larger -- ideally, full-size -- version of the photo of + * the product. Represented in JSON as a property named fullImage whose value is a JSON + * object with properties as defined in [TODO: xref the JSON serialization of a Media Link + * Construct].
+ *
+ *
+ * + * @author robert.cooper + */ +public class Product extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/product"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Review.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Review.java new file mode 100644 index 0000000..047211d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Review.java @@ -0,0 +1,70 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "review" object type represents a primarily prose-based commentary on another object. + *

+ *

+ * The "review" object type is identified by the URI + * http://activitystrea.ms/schema/1.0/review. + *

+ *

+ * A review has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Title
+ *
The title of the review. Represented by the Name component of the base Object Construct. Many + * systems do not have the concept of a title for a review; such systems MUST omit the Name + * component. Processors SHOULD refer to such reviews as simply being "a review", with appropriate + * localization, if they are to be described in a sentence.
+ *
Content
+ *
The content of the comment. Represented in JSON as a property called content whose + * value is a JSON string containing a fragment of HTML that represents the content. Publishers + * SHOULD include any markup necessary to achieve a similar presentation to that on the publisher's + * own HTML pages, including any links that the service automatically adds. Processors MAY remove + * all HTML markup and consider the comment to be plain text.
+ *
Reviewed Object
+ *
The Object Construct representing the item that this review applies to. Represented as the In + * Reply To Object component of the base Object Construct.
+ *
Rating
+ *
A rating for the item, given as a number between 1.0 and 5.0 inclusive with one decimal place + * of precision. Represented in JSON as a property called rating whose value is a JSON + * number giving the rating.
+ *
+ *
+ * + * @author robert.cooper + */ +public class Review extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/review"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Service.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Service.java new file mode 100644 index 0000000..a882d68 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Service.java @@ -0,0 +1,60 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "service" Object type represents a website, personal website or blog, business, brand, or + * other entity that performs some kind of work for other entities, people, or services, or acts as + * kind of container for other objects. + *

+ *

+ * The "service" Object type is identified by the URI + * http://activitystrea.ms/schema/1.0/service. + *

+ *

+ * A service has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
icon
+ *
A Media Link Construct representing a link to a small image representing the service. + * Represented in JSON as a property named icon whose value is a JSON object with + * properties as defined in [TODO: xref the JSON serialization of a Media Link Construct]. The + * linked image MUST have an aspect ratio of one (horizontal) to one (vertical) and SHOULD be + * suitable for presentation at a small size.
+ *
+ *
+ * + * @author robert.cooper + */ +public class Service extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/service"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Song.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Song.java new file mode 100644 index 0000000..b651bbb --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Song.java @@ -0,0 +1,70 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "song" Object type represents a song or a recording of a song. + *

+ *

+ * Objects of type Song might contain information about the song or recording, or they might contain + * some representation of the recording itself. In the latter case, the song SHOULD also be + * annotated with the "audio" object type as described in Section 3.2.2 (Audio) + * and use its properties. This type should only be used when the publisher can guarantee that the + * object is a song rather than merely a generic audio stream. + *

+ *

+ * The Object type URL for the "song" Object type is + * http://activitystrea.ms/schema/1.0/song. + *

+ *

+ * A song has no additional components. + *

+ * + * @author robert.cooper + */ +public class Song extends ActivityObject { + /** + * + */ + private static final long serialVersionUID = 1L; + private Audio audio; + + /** + * Set the value of audio + * + * @param newaudio new value of audio + */ + public void setAudio(final Audio newaudio) { + audio = newaudio; + } + + /** + * Get the value of audio + * + * @return the value of audio + */ + public Audio getAudio() { + return audio; + } + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/song"; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Status.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Status.java new file mode 100644 index 0000000..8492684 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Status.java @@ -0,0 +1,56 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "status" Object type represents a human-readable update of the author's situation, mood, + * location or other status. + *

+ *

+ * A status is similar in structure to a note, but carries the additional meaning that the content + * is primarily describing something its author is doing, feeling or experiencing. + *

+ *

+ * A consumers MAY consider the content of the most recent status object it encountered to be the + * user's current status, unless the most recent status update is old. When a status becomes too old + * is not defined by this specification. + *

+ *

+ * The "status" object type is identified by the URI + * http://activitystrea.ms/schema/1.0/status. + *

+ *

+ * A status has the same components as a note. + *

+ * + * @author robert.cooper + */ +public class Status extends ActivityObject { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public String getTypeIRI() { + return "http://activitystrea.ms/schema/1.0/status"; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Verb.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Verb.java new file mode 100644 index 0000000..39aabaf --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Verb.java @@ -0,0 +1,214 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the icense for the specific language governing permissions and + * limitations under the License. + * under the License. + */ +package com.rometools.modules.activitystreams.types; + +/** + * + * @author robert.cooper + */ +public enum Verb { + /** + * The "mark as favorite" Verb indicates that the Subject marked the Object as an item of + * special interest. Objects so marked often appear in a collection of such Objects which MAY be + * published as a feed of entries annotated with this Verb. If a particular service uses + * favorites as a mechanism by which a user can recall items that were earlier marked, it MAY be + * appropriate to also mark activities of this type with the "save" Verb as described in Section + * 3.1.8. The verb URI for the "mark as favorite" Verb is + * http://activitystrea.ms/schema/1.0/favorite. + */ + MARK_AS_FAVORITE("http://activitystrea.ms/schema/1.0/favorite"), + /** + * The "start following" Verb indicates that the Subject began following the activity of the + * Object. In most cases, the Object of this Verb will be a user, but it can potentially be of + * any type that can sensibly generate activity. + * + * The verb URI for the "start following" Verb is http://activitystrea.ms/schema/1.0/follow. + * + * Processors MAY ignore (silently drop) successive identical "start following" activities + * regardless of whether they maintain state sufficient to determine (A), (B), or (C) above. + */ + START_FOLLOWING("http://activitystrea.ms/schema/1.0/follow"), + /** + * The "mark as liked" verb indicates that the actor indicated that it likes the object. + * + * The verb URI for the "mark as liked" Verb is http://activitystrea.ms/schema/1.0/like. + */ + MARK_AS_LIKED("http://activitystrea.ms/schema/1.0/like"), + /** + * The "make friend" Verb indicates the creation of a friendship that is reciprocated by the + * object. + * + * Since this verb implies an activity on the part of its object, processors MUST NOT accept + * activities with this Verb unless they are able to verify through some external means that + * there is in fact a reciprocated connection. For example, a processor MAY have received a + * guarantee from a particular publisher that the publisher will only use this Verb in cases + * where a reciprocal relationship exists. + * + * The verb URI for the "make friend" Verb is http://activitystrea.ms/schema/1.0/make-friend. + */ + MAKE_FRIEND("http://activitystrea.ms/schema/1.0/make-friend"), + /** + * The "join" Verb indicates that the actor has become a member of the Object. This + * specification only defines the meaning of this Verb when its Object is a Group, though + * implementors SHOULD be prepared to handle other Object types as meaning MAY be provided by + * extension specifications. + * + * Processors MAY ignore (silently drop) successive identical "join" activities regardless of + * whether they maintain state sufficient to determine (A) or (B) above. + * + * The "join" Verb is identified by the URI http://activitystrea.ms/schema/1.0/join. + */ + JOIN("http://activitystrea.ms/schema/1.0/join"), + /** + * The "play" verb indicates that the subject spent some time enjoying the object. For example, + * if the object is a video this indicates that the subject watched all or part of the video. + * + * The "play" Verb is identified by the URI http://activitystrea.ms/schema/1.0/play. + */ + PLAY("http://activitystrea.ms/schema/1.0/play"), + /** + * The "Post" Verb is described in section 8 of the AtomActivity specification. It is only + * referenced here for completeness. + * + * http://activitystrea.ms/schema/1.0/post + */ + POST("http://activitystrea.ms/schema/1.0/post"), + /** + * The "save" Verb indicates that the Subject has called out the Object as being of interest + * primarily to him- or herself. Though this action MAY be shared publicly, the implication is + * that the Object has been saved primarily for the actor's own benefit rather than to show it + * to others as would be indicated by the "share" Verb (Section 3.1.9). + * + * The "save" Verb is identified by the URI http://activitystrea.ms/schema/1.0/save. + */ + SAVE("http://activitystrea.ms/schema/1.0/save"), + /** + * The "share" Verb indicates that the Subject has called out the Object to readers. In most + * cases, the actor did not create the Object being shared, but is instead drawing attention to + * it. + * + * The "share" Verb is identified by the URI http://activitystrea.ms/schema/1.0/share. + */ + SHARE("http://activitystrea.ms/schema/1.0/share"), + /** + * The "tag" verb indicates that the actor has identified the presence of a target inside + * another object. For example, the actor may have specified that a particular user appears in a + * photo. + * + * The "tag" verb is identified by the URI http://activitystrea.ms/schema/1.0/tag. + * + * The target of the "tag" verb gives the object in which the tag has been added. For example, + * if a user appears in a photo, the activity:object is the user and the activity:target is the + * photo. + */ + TAG("http://activitystrea.ms/schema/1.0/tag"), + /** + * The "update" Verb indicates that the Subject has modified the referenced Object. + * + * Implementors SHOULD use verbs such as Section 3.1.7 where the Subject is adding new items to + * a Section 3.2.8 or similar. Update is reserved for modifications to existing Objects or data + * such as changing a user's profile information. + * + * The "update" Verb is identified by the URI http://activitystrea.ms/schema/1.0/update. + */ + UPDATE("http://activitystrea.ms/schema/1.0/update"), + /** + * + *

+ * The "positive RSVP" verb indicates that the actor has made a positive RSVP for the object. + * This specification only defines the meaning of this verb when its object is an event (see Section 4.2.1 (Event)), though implementors SHOULD be prepared to + * handle other object types as meaning MAY be provided by extension specifications. + *

+ *

+ * The use of this Verb is only appropriate when the RSVP was created by an explicit action by + * the actor. It is not appropriate to use this verb when a user has been added as an attendee + * by an event organiser or administrator. + *

+ *

+ * The verb URI for the "positive RSVP" Verb is + * http://activitystrea.ms/schema/1.0/rsvp-yes. + *

+ */ + RSVP_YES("http://activitystrea.ms/schema/1.0/rsvp-yes"), + /** + *

+ * The "possible RSVP" verb indicates that the actor has made a possible RSVP for the object. + * This specification only defines the meaning of this verb when its object is an event (see Section 4.2.1 (Event)), though implementors SHOULD be prepared to + * handle other object types as meaning MAY be provided by extension specifications. + *

+ *

+ * The use of this Verb is only appropriate when the RSVP was created by an explicit action by + * the actor. It is not appropriate to use this verb when a user has been added as an attendee + * by an event organiser or administrator. + *

+ *

+ * The verb URI for the "possible RSVP" Verb is + * http://activitystrea.ms/schema/1.0/rsvp-maybe. + *

+ */ + RSVP_MAYBE("http://activitystrea.ms/schema/1.0/rsvp-maybe"), + /** + *

+ * The "negative RSVP" verb indicates that the actor has made a negative RSVP for the object. + * This specification only defines the meaning of this verb when its object is an event (see Section 4.2.1 (Event)), though implementors SHOULD be prepared to + * handle other object types as meaning MAY be provided by extension specifications. + *

+ *

+ * The use of this Verb is only appropriate when the RSVP was created by an explicit action by + * the actor. It is not appropriate to use this verb when a user has been added as an attendee + * by an event organiser or administrator. + *

+ *

+ * The verb URI for the "negative RSVP" Verb is + * http://activitystrea.ms/schema/1.0/rsvp-no. + *

+ */ + RSVP_NO("http://activitystrea.ms/schema/1.0/rsvp-no"); + private final String iri; + + /** + * @param iri + */ + Verb(final String iri) { + this.iri = iri; + } + + @Override + public String toString() { + return iri; + } + + /** + * + * @param iri + * @return + */ + public static Verb fromIRI(final String iri) { + for (final Verb v : Verb.values()) { + if (v.toString().equals(iri)) { + return v; + } + } + return null; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Video.java b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Video.java new file mode 100644 index 0000000..8cc07fb --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/activitystreams/types/Video.java @@ -0,0 +1,51 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +/** + *

+ * The "video" Object type represents video content, which usually consists of a motion picture + * track and an audio track. + *

+ *

+ * The "video" Object type is identified by the URI + * http://activitystrea.ms/schema/1.0/video. + *

+ *

+ * A video has the following additional components: + *

+ *

+ *

+ *
+ *
+ *
Video Stream Link
+ *
A Media Link Construct linking to the video content itself. Represented in JSON as a property + * called stream whose value is a JSON object with properties as defined in [TODO: xref the + * JSON serialization of a Media Link Construct]
+ *
Embed Code
+ *
An HTML fragment that, when embedded in an HTML page, will provide an interactive player UI + * for the video stream. Represented in JSON as a property called embedCode whose value is + * a JSON string containing the fragment of HTML.
+ *
+ *
+ * + * @author robert.cooper + */ +public class Video { + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/atom/io/AtomLinkAttribute.java b/rome-modules/src/main/java/com/rometools/modules/atom/io/AtomLinkAttribute.java new file mode 100644 index 0000000..1ccfbfb --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/atom/io/AtomLinkAttribute.java @@ -0,0 +1,10 @@ +package com.rometools.modules.atom.io; + +public interface AtomLinkAttribute { + String REL = "rel"; + String TYPE = "type"; + String HREF = "href"; + String TITLE = "title"; + String HREF_LANG = "hreflang"; + String LENGTH = "length"; +} diff --git a/rome-modules/src/main/java/com/rometools/modules/atom/io/AtomModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/atom/io/AtomModuleGenerator.java new file mode 100644 index 0000000..a683a6c --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/atom/io/AtomModuleGenerator.java @@ -0,0 +1,82 @@ +package com.rometools.modules.atom.io; + +import com.rometools.modules.atom.modules.AtomLinkModule; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; +import org.jdom2.Attribute; +import org.jdom2.Element; +import org.jdom2.Namespace; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class AtomModuleGenerator implements ModuleGenerator { + + static final Namespace NS = Namespace.getNamespace("atom", AtomLinkModule.URI); + private static final Set NAMESPACES; + + static { + final Set nss = new HashSet(); + nss.add(NS); + NAMESPACES = Collections.unmodifiableSet(nss); + } + + @Override + public final String getNamespaceUri() { + return AtomLinkModule.URI; + } + + @Override + public final Set getNamespaces() { + return NAMESPACES; + } + + @Override + public void generate(Module module, Element element) { + if (module instanceof AtomLinkModule) { + AtomLinkModule m = (AtomLinkModule) module; + generateLinc(m.getLink(), element); + } + } + + private void generateLinc(Link link, Element element) { + if (link == null) { + return; + } + + Element linkElement = new Element("link", NS); + + if (link.getHref() != null) { + Attribute href = new Attribute(AtomLinkAttribute.HREF, link.getHref()); + linkElement.setAttribute(href); + } + if (link.getType() != null) { + Attribute type = new Attribute(AtomLinkAttribute.TYPE, link.getType()); + linkElement.setAttribute(type); + } + if (link.getRel() != null) { + Attribute rel = new Attribute(AtomLinkAttribute.REL, link.getRel()); + linkElement.setAttribute(rel); + } + + if (link.getHreflang() != null) { + final Attribute hreflangAttribute = new Attribute(AtomLinkAttribute.HREF_LANG, link.getHreflang()); + linkElement.setAttribute(hreflangAttribute); + } + + if (link.getTitle() != null) { + final Attribute title = new Attribute(AtomLinkAttribute.TITLE, link.getTitle()); + linkElement.setAttribute(title); + } + + if (link.getLength() != 0) { + final Attribute lenght = new Attribute(AtomLinkAttribute.LENGTH, Long.toString(link.getLength())); + linkElement.setAttribute(lenght); + } + + element.addContent(linkElement); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/atom/io/AtomModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/atom/io/AtomModuleParser.java new file mode 100644 index 0000000..36cdfba --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/atom/io/AtomModuleParser.java @@ -0,0 +1,90 @@ +package com.rometools.modules.atom.io; + +import com.rometools.modules.atom.modules.AtomLinkModule; +import com.rometools.modules.atom.modules.AtomLinkModuleImpl; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; +import com.rometools.rome.io.impl.NumberParser; +import org.jdom2.Attribute; +import org.jdom2.Element; +import org.jdom2.Namespace; + +import java.util.Locale; + +public class AtomModuleParser implements ModuleParser { + + private static final Namespace NS = Namespace.getNamespace(AtomLinkModule.URI); + + @Override + public String getNamespaceUri() { + return null; + } + + @Override + public Module parse(Element element, Locale locale) { + AtomLinkModuleImpl mod = new AtomLinkModuleImpl(); + if (element.getName().equals("channel") || element.getName().equals("item")) { + Element link = element.getChild("link", NS); + if (link != null) { + Link l = parseLink(link); + mod.setLink(l); + return mod; + } + } + return null; + } + + private Link parseLink(final Element eLink) { + + final Link link = new Link(); + + final String rel = getAttributeValue(eLink, AtomLinkAttribute.REL); + if (rel != null) { + link.setRel(rel); + } + + final String type = getAttributeValue(eLink, AtomLinkAttribute.TYPE); + if (type != null) { + link.setType(type); + } + + final String href = getAttributeValue(eLink, AtomLinkAttribute.HREF); + if (href != null) { + link.setHref(href); + } + + final String title = getAttributeValue(eLink, AtomLinkAttribute.TITLE); + if (title != null) { + link.setTitle(title); + } + + final String hrefLang = getAttributeValue(eLink, AtomLinkAttribute.HREF_LANG); + if (hrefLang != null) { + link.setHreflang(hrefLang); + } + + final String length = getAttributeValue(eLink, AtomLinkAttribute.LENGTH); + if (length != null) { + final Long val = NumberParser.parseLong(length); + if (val != null) { + link.setLength(val.longValue()); + } + } + + return link; + + } + + protected String getAttributeValue(final Element e, final String attributeName) { + Attribute attr = e.getAttribute(attributeName); + if (attr == null) { + attr = e.getAttribute(attributeName, NS); + } + if (attr != null) { + return attr.getValue(); + } else { + return null; + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/atom/modules/AtomLinkModule.java b/rome-modules/src/main/java/com/rometools/modules/atom/modules/AtomLinkModule.java new file mode 100644 index 0000000..22e3f6d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/atom/modules/AtomLinkModule.java @@ -0,0 +1,13 @@ +package com.rometools.modules.atom.modules; + +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.module.Module; + +public interface AtomLinkModule extends Module { + + public static final String URI = "http://www.w3.org/2005/Atom"; + + public Link getLink(); + + public void setLink(Link link); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/atom/modules/AtomLinkModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/atom/modules/AtomLinkModuleImpl.java new file mode 100644 index 0000000..ec5e9e2 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/atom/modules/AtomLinkModuleImpl.java @@ -0,0 +1,83 @@ +package com.rometools.modules.atom.modules; + +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +import java.io.Serializable; + +public class AtomLinkModuleImpl implements AtomLinkModule, Cloneable, Serializable { + + private Link link; + + @Override + public Link getLink() { + return link; + } + + @Override + public void setLink(Link link) { + this.link = link; + } + + @Override + public String getUri() { + return URI; + } + + @Override + public Class getInterface() { + return AtomLinkModule.class; + } + + @Override + public void copyFrom(CopyFrom obj) { + AtomLinkModule other = (AtomLinkModule) obj; + Link link = other.getLink(); + if (link != null) { + Link l = new Link(); + l.setHref(link.getHref()); + l.setType(link.getType()); + l.setRel(link.getRel()); + l.setHreflang(link.getHreflang()); + l.setTitle(link.getTitle()); + l.setLength(link.getLength()); + setLink(l); + } + } + + @Override + public Object clone() { + final AtomLinkModuleImpl m = new AtomLinkModuleImpl(); + if (link != null) { + Link l = new Link(); + l.setHref(link.getHref()); + l.setType(link.getType()); + l.setRel(link.getRel()); + l.setHreflang(link.getHreflang()); + l.setTitle(link.getTitle()); + l.setLength(link.getLength()); + m.setLink(l); + } + return m; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(AtomLinkModuleImpl.class, this); + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(AtomLinkModuleImpl.class, this); + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(AtomLinkModuleImpl.class, this); + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Article.java b/rome-modules/src/main/java/com/rometools/modules/base/Article.java new file mode 100644 index 0000000..0f90578 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Article.java @@ -0,0 +1,380 @@ +/* + * Article.java + * + * Created on November 16, 2005, 1:01 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import java.util.Date; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for Article or News + * entry types. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public interface Article extends GlobalInterface { + /** + * Array of Author Names. Limit 10. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
author
Details Author of the item.
Example <g:author>John Steinbeck</g:author>
Attribute of Reference Items, News and Articles
Content type string
+ * + * @param authors Array of Author Names. Limit 10. + */ + public void setAuthors(String[] authors); + + /** + * Array of Author Names. Limit 10. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
author
Details Author of the item.
Example <g:author>John Steinbeck</g:author>
Attribute of Reference Items, News and Articles
Content type string
+ * + * @return Array of author names. + */ + public String[] getAuthors(); + + /** + * Source for this article. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
news_source
Details The source of news content.
Example <g:news_source>Journal</g:news_source>
Attribute of News and Articles
+ * + * Content type string
+ * + * @param newsSource Source for this article + */ + public void setNewsSource(String newsSource); + + /** + * Source for this article. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
news_source
Details The source of news content.
Example <g:news_source>Journal</g:news_source>
Attribute of News and Articles
+ * + * Content type string
+ * + * @return source for this article. + */ + public String getNewsSource(); + + /** + * Number of pages in the article. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
pages
Details + * + * The number of pages in the publication.
Example <g:pages>18</g:pages>
Attribute of Reference Items, News and Articles
+ * + * Content type integer
+ * + * @param pages Number of pages in the article + */ + public void setPages(Integer pages); + + /** + * Number of pages in the article. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
pages
Details + * + * The number of pages in the publication.
Example <g:pages>18</g:pages>
Attribute of Reference Items, News and Articles
+ * + * Content type integer
+ * + * @return Number of pages in the article + */ + public Integer getPages(); + + /** + * Date article was published. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
publish_date
+ * + * Details Date the item was published in ISO 8601 + * format: YYYY-MM-DD
+ * + * Example <g:publish_date>2005-12-20</g:publish_date>
Attribute of Reference Items
+ * + * Content type + * + * date
+ * + * @param publishDate Date article was published + */ + public void setPublishDate(Date publishDate); + + /** + * Date article was published. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
publish_date
+ * + * Details Date the item was published in ISO 8601 + * format: YYYY-MM-DD
+ * + * Example <g:publish_date>2005-12-20</g:publish_date>
Attribute of Reference Items
+ * + * Content type + * + * date
+ * + * @return Date article was published + */ + public Date getPublishDate(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Course.java b/rome-modules/src/main/java/com/rometools/modules/base/Course.java new file mode 100644 index 0000000..9b2a80d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Course.java @@ -0,0 +1,565 @@ +/* + * CourseInformation.java + * + * Created on November 16, 2005, 11:12 AM + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import com.rometools.modules.base.types.DateTimeRange; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for Class or Course + * information entry types. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public interface Course extends GlobalInterface { + /** + * The timeframe a course is running. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
course_date_range
DetailsDate and time range a class is in session, in ISO 8601. Two + * sub-attributes are included in course_date_range attribute. + *
    + * + *
  • start = Start date and time of a trip in format YYYY-MM-DDThh:mm:ss
  • + *
  • end = End date and time of a trip in format YYYY-MM-DDThh:mm:ss
  • + *
+ *
Example <g:course_date_range>
+ * + * <g:start>2005-12-20T09:30:01</g:start>
+ * <g:end>2005-12-29T10:30:59</g:end>
+ * </g:course_date_range>
+ * + * Attribute of Course schedules
+ * + * Content type dateTimeRange
+ * + * @param courseDateRange The timeframe a course is running + */ + public void setCourseDateRange(DateTimeRange courseDateRange); + + /** + * The timeframe a course is running. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
course_date_range
DetailsDate and time range a class is in session, in ISO 8601. Two + * sub-attributes are included in course_date_range attribute. + *
    + * + *
  • start = Start date and time of a trip in format YYYY-MM-DDThh:mm:ss
  • + *
  • end = End date and time of a trip in format YYYY-MM-DDThh:mm:ss
  • + *
+ *
Example <g:course_date_range>
+ * + * <g:start>2005-12-20T09:30:01</g:start>
+ * <g:end>2005-12-29T10:30:59</g:end>
+ * </g:course_date_range>
+ * + * Attribute of Course schedules
+ * + * Content type dateTimeRange
+ * + * @return The timeframe a course is running + */ + public DateTimeRange getCourseDateRange(); + + /** + * ID code associated with a course. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
course_number
DetailsID code associated with a course
Example<g:course_number>HIST-90A</g:course_number>
Attribute ofCourse schedules
Content typestring
+ * + * @param courseNumber ID code associated with a course + */ + public void setCourseNumber(String courseNumber); + + /** + * ID code associated with a course. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
course_number
DetailsID code associated with a course
Example<g:course_number>HIST-90A</g:course_number>
Attribute ofCourse schedules
Content typestring
+ * + * @return ID code associated with a course + */ + public String getCourseNumber(); + + /** + * Time a class is in session. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
course_times
DetailsTime a class is in session.
Example<g:course_times>MWF 08:30 - 09:45</g:course_times>
Attribute ofCourse schedules
Content typestring
+ * + * @param courseTimes Time a class is in session + */ + public void setCourseTimes(String courseTimes); + + /** + * Time a class is in session. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
course_times
DetailsTime a class is in session.
Example<g:course_times>MWF 08:30 - 09:45</g:course_times>
Attribute ofCourse schedules
Content typestring
+ * + * @return Time a class is in session + */ + public String getCourseTimes(); + + /** + * Salary for this position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
salary
Details Salary for this position. Non-numeric values such as "$" symbols are not + * acceptable.
+ * + * Example <g:salary>55000</g:salary>
+ * + * Attribute of Jobs
Content type + * + * float
+ * + * @param salary Salary for this position + */ + public void setSalary(Float salary); + + /** + * Salary for this position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
salary
Details Salary for this position. Non-numeric values such as "$" symbols are not + * acceptable.
+ * + * Example <g:salary>55000</g:salary>
+ * + * Attribute of Jobs
Content type + * + * float
+ * + * @return Salary for this position + */ + public Float getSalary(); + + /** + * Topics of study for a course. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
subject
+ * + * Details Topic of study for a course.
Example <g:subject>Trigonometry</g:subject>
Attribute of + * + * Course schedules
Content type string
+ * + * @param subject Topics of study for a course + */ + public void setSubjects(String[] subject); + + /** + * Topics of study for a course. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
subject
+ * + * Details Topic of study for a course.
Example <g:subject>Trigonometry</g:subject>
Attribute of + * + * Course schedules
Content type string
+ * + * @return Topics of study for a course + */ + public String[] getSubjects(); + + /** + * Name of the school at which a class is offered. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
university
Details Name of the school a class is offered at.
Example <g:university>Stanford</g:university>
+ * + * Attribute of Course schedules
Content type + * + * string
+ * + * @param university Name of the school at which a class is offered. + */ + public void setUniversity(String university); + + /** + * Name of the school at which a class is offered. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
university
Details Name of the school a class is offered at.
Example <g:university>Stanford</g:university>
+ * + * Attribute of Course schedules
Content type + * + * string
+ * + * @return Name of the school at which a class is offered. + */ + public String getUniversity(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/CustomTag.java b/rome-modules/src/main/java/com/rometools/modules/base/CustomTag.java new file mode 100644 index 0000000..5ec4373 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/CustomTag.java @@ -0,0 +1,149 @@ +/* + * CustomTag.java + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +/** + * This class represents a custom tag name and value. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public interface CustomTag { + + /** + * Returns the tag name used. + * + * @return Returns the tag name used. + */ + public String getName(); + + /** + * The value of the custom tag.
+ *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Type (JavaType)DescriptionExamples
string (String)Any stringBlue
int (Integer)Whole number values1000
float (Float)Numbers with decimal digits3.5
intUnit (IntUnit)Whole number value and a string10 km
floatUnit (FloatUnit)Numbers with decimal digits and a string1.5 km
date (ShortDate)Date of an event, in format YYYY-MM-DD2005-12-12
dateTime (java.util.Date)Date and time for an event, in format YYYY-MM-DDThh:mm:ss2005-12-12T12:00:00
dateTimeRange (DateTimeRange)Start and end dates for an event. An attribute of this type will contain + * two sub-attributes, <start> and <end> in format YYYY-MM-DD<start>1975-09-25</start>
+ * <end>1975-09-25</end> + * + *
url (java.net.URL)HTTP URL http://www.google.com
boolean (Boolean)Value may be either true or false.true
location (CustomTagImpl.Location)Location921 W. Dana Street, Mtn View, CA-94103
+ * + * @return The value of the tag. The objects class is determined by the "type" attribute on the + * tag. + */ + public Object getValue(); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/CustomTagImpl.java b/rome-modules/src/main/java/com/rometools/modules/base/CustomTagImpl.java new file mode 100644 index 0000000..45e5891 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/CustomTagImpl.java @@ -0,0 +1,246 @@ +/* + * CustomTagImpl.java + * + * Created on February 6, 2006, 12:06 AM + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.rometools.modules.base; + +import java.net.URL; +import java.util.Date; + +import com.rometools.modules.base.types.DateTimeRange; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.IntUnit; +import com.rometools.modules.base.types.ShortDate; + +/** + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public class CustomTagImpl implements CustomTag { + private Object value; + private final String name; + + /** Creates a new instance of CustomTagImpl */ + public CustomTagImpl(final String name, final String value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + public CustomTagImpl(final String name, final Integer value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + public CustomTagImpl(final String name, final Float value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + public CustomTagImpl(final String name, final IntUnit value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + public CustomTagImpl(final String name, final FloatUnit value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + public CustomTagImpl(final String name, final ShortDate value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + public CustomTagImpl(final String name, final Date value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + public CustomTagImpl(final String name, final DateTimeRange value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + public CustomTagImpl(final String name, final URL value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + public CustomTagImpl(final String name, final Boolean value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + public CustomTagImpl(final String name, final Location value) { + if (name == null || value == null) { + throw new NullPointerException("Name and Value cannont be null."); + } + this.name = name; + this.value = value; + } + + @Override + public String getName() { + return name; + } + + @Override + public Object getValue() { + return value; + } + + @Override + public boolean equals(final Object o) { + if (o instanceof CustomTag) { + final CustomTag tag = (CustomTag) o; + if (name.equals(tag.getName()) && value.equals(tag.getValue())) { + return true; + } + } + return false; + } + + /** + * Creates and returns a copy of this object. The precise meaning of "copy" may depend on the + * class of the object. The general intent is that, for any object x, the expression: + *
+ * + *
+     * x.clone() != x
+     * 
+ * + *
will be true, and that the expression:
+ * + *
+     * x.clone().getClass() == x.getClass()
+     * 
+ * + *
will be true, but these are not absolute requirements. While it is + * typically the case that:
+ * + *
+     * x.clone().equals(x)
+     * 
+ * + *
will be true, this is not an absolute requirement. + *

+ * By convention, the returned object should be obtained by calling super.clone. If a + * class and all of its superclasses (except Object) obey this convention, it will be + * the case that x.clone().getClass() == x.getClass(). + *

+ * By convention, the object returned by this method should be independent of this object (which + * is being cloned). To achieve this independence, it may be necessary to modify one or more + * fields of the object returned by super.clone before returning it. Typically, this + * means copying any mutable objects that comprise the internal "deep structure" of the object + * being cloned and replacing the references to these objects with references to the copies. If + * a class contains only primitive fields or references to immutable objects, then it is usually + * the case that no fields in the object returned by super.clone need to be modified. + *

+ * The method clone for class Object performs a specific cloning operation. + * First, if the class of this object does not implement the interface Cloneable, then + * a CloneNotSupportedException is thrown. Note that all arrays are considered to + * implement the interface Cloneable. Otherwise, this method creates a new instance of + * the class of this object and initializes all its fields with exactly the contents of the + * corresponding fields of this object, as if by assignment; the contents of the fields are not + * themselves cloned. Thus, this method performs a "shallow copy" of this object, not a + * "deep copy" operation. + *

+ * The class Object does not itself implement the interface Cloneable, so + * calling the clone method on an object whose class is Object will result in + * throwing an exception at run time. + * + * @return a clone of this instance. + * @exception CloneNotSupportedException if the object's class does not support the + * Cloneable interface. Subclasses that override the + * clone method can also throw this exception to indicate that an + * instance cannot be cloned. + * @see java.lang.Cloneable + */ + @Override + public Object clone() throws CloneNotSupportedException { + final CustomTagImpl cti = new CustomTagImpl(name, ""); + cti.value = value; + return cti; + } + + @Override + public String toString() { + return "[custom name=\"" + name + "\" value=\"" + value.toString() + "\"]"; + } + + public static class Location { + private final String value; + + public Location(final String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public Object clone() { + return new Location(value); + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(final Object o) { + if (o instanceof Location && ((Location) o).value.equals(value)) { + return true; + } else { + return false; + } + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/CustomTags.java b/rome-modules/src/main/java/com/rometools/modules/base/CustomTags.java new file mode 100644 index 0000000..8d5159a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/CustomTags.java @@ -0,0 +1,57 @@ +/* + * CustomTags.java + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import java.util.List; + +import com.rometools.rome.feed.module.Module; + +/** + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public interface CustomTags extends Module { + + public static final String URI = "http://base.google.com/cns/1.0"; + + public List getValues(); + + public void setValues(List values); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/CustomTagsImpl.java b/rome-modules/src/main/java/com/rometools/modules/base/CustomTagsImpl.java new file mode 100644 index 0000000..595bdc5 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/CustomTagsImpl.java @@ -0,0 +1,90 @@ +/* + * CustomTagsImpl.java + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import java.util.ArrayList; +import java.util.List; + +import com.rometools.rome.feed.CopyFrom; + +/** + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public class CustomTagsImpl implements CustomTags { + + private static final long serialVersionUID = 1L; + + private List values; + + @Override + public List getValues() { + values = values == null ? new ArrayList() : values; + return values; + } + + @Override + public void setValues(final List values) { + this.values = values; + } + + @Override + public void copyFrom(final CopyFrom object) { + final CustomTags ct = (CustomTags) object; + values = new ArrayList(ct.getValues()); + } + + @Override + public Object clone() { + final CustomTagsImpl cti = new CustomTagsImpl(); + cti.values = new ArrayList(values); + return cti; + } + + @Override + public Class getInterface() { + return CustomTags.class; + } + + @Override + public String getUri() { + return CustomTags.URI; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Event.java b/rome-modules/src/main/java/com/rometools/modules/base/Event.java new file mode 100644 index 0000000..578ea16 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Event.java @@ -0,0 +1,1346 @@ +/* + * Event.java + * + * Created on November 16, 2005, 11:38 AM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.DateTimeRange; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.PaymentTypeEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; +import com.rometools.modules.base.types.ShippingType; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for Event entry types. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface Event extends GlobalInterface { + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @param value Currency of the price amount for an item. + */ + public void setCurrency(CurrencyEnumeration value); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @return Currency of the price amount for an item. + */ + public CurrencyEnumeration getCurrency(); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @param deliveryNotes Additional instructions to explain the item’s delivery process. + */ + public void setDeliveryNotes(String deliveryNotes); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @return Additional instructions to explain the item’s delivery process. + */ + public String getDeliveryNotes(); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @param deliveryRadius The maximum distance you will deliver an item in any direction. + */ + public void setDeliveryRadius(FloatUnit deliveryRadius); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @return The maximum distance you will deliver an item in any direction. + */ + public FloatUnit getDeliveryRadius(); + + /** + * The time during which this event takes place. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
event_date_range
Details + * + * Information on the date and time an event will take place, in ISO 8601 + * format. Two sub-attributes are included in the event_date_range attribute: + *
    + * + *
  • from = Date and time an event will begin in format YYYY-MM-DDThh:mm:ss
  • + *
  • to = (Optional). Date and time an event will end, in format YYYY-MM-DDThh:mm:ss
  • + *
+ *
Example <g:event_dateTime>
+ * + * <g:from>2005-12-20T14:00:00</g:from>
+ * <g:to>2005-12-20T19:00:00</g:to>
+ * + * </g:eventdateTime>
Attribute of Events
Content type dateTimeRange
+ * + * @param eventDateRange The time during which this event takes place. + */ + public void setEventDateRange(DateTimeRange eventDateRange); + + /** + * The time during which this event takes place. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
event_date_range
Details + * + * Information on the date and time an event will take place, in ISO 8601 + * format. Two sub-attributes are included in the event_date_range attribute: + *
    + * + *
  • from = Date and time an event will begin in format YYYY-MM-DDThh:mm:ss
  • + *
  • to = (Optional). Date and time an event will end, in format YYYY-MM-DDThh:mm:ss
  • + *
+ *
Example <g:event_dateTime>
+ * + * <g:from>2005-12-20T14:00:00</g:from>
+ * <g:to>2005-12-20T19:00:00</g:to>
+ * + * </g:eventdateTime>
Attribute of Events
Content type dateTimeRange
+ * + * @return The time during which this event takes place. + */ + public DateTimeRange getEventDateRange(); + + /** + * Location where the event will be held. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @param location Location where the event will be held. + */ + public void setLocation(String location); + + /** + * Location where the event will be held. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @return Location where the event will be held. + */ + public String getLocation(); + + /** + * Payment Methods acceptable for the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * "Cash," "Check," "Traveler’s Check," "Visa," "MasterCard," + * + * "American Express," "Discover," "Wire transfer" or "Paypal." If you accept more than one + * method, include multiple instances of the <payment_accepted> attribute for each + * acceptable method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * + * <g:payment_accepted>Paypal</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check Paypal</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type paymentMethodEnumeration
+ * + * @param paymentAccepted Payment Methods acceptable for the event. + */ + public void setPaymentAccepted(PaymentTypeEnumeration[] paymentAccepted); + + /** + * Payment Methods acceptable for the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * "Cash," "Check," "Traveler’s Check," "Visa," "MasterCard," + * + * "American Express," "Discover," "Wire transfer" or "Paypal." If you accept more than one + * method, include multiple instances of the <payment_accepted> attribute for each + * acceptable method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * + * <g:payment_accepted>Paypal</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check Paypal</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type paymentMethodEnumeration
+ * + * @return Payment Methods acceptable for the event. + */ + public PaymentTypeEnumeration[] getPaymentAccepted(); + + /** + * Additional information about payment. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
Content type string
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
Content type string
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
Content type string
+ * + * @param paymentNotes Additional information about payment. + */ + public void setPaymentNotes(String paymentNotes); + + /** + * Additional information about payment. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
Content type string
+ * + * + * @return Additional information about payment. + */ + public String getPaymentNotes(); + + /** + * Price of the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
+ * + * Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * + * <g:price>5,95</g:price>
+ * <g:price>5.00 – 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @param price Price of the event. + */ + public void setPrice(FloatUnit price); + + /** + * Price of the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
+ * + * Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * + * <g:price>5,95</g:price>
+ * <g:price>5.00 – 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @return Price of the event. + */ + public FloatUnit getPrice(); + + /** + * Price qualifier for the even cost. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are "negotiable," or + * "starting." The default is "starting"
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @param priceType Price qualifier for the even cost. + */ + public void setPriceType(PriceTypeEnumeration priceType); + + /** + * Price qualifier for the even cost. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are "negotiable," or + * "starting." The default is "starting"
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @return Price qualifier for the even cost. + */ + public PriceTypeEnumeration getPriceType(); + + /** + * Quantity available. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
quantity
Details The number of units available for purchase. This attribute can be left + * blank if you have a large quantity or if it is not applicable.
Example Acceptable:
+ * <g:quantity>18</g:quantity>
+ * + * <g:quantity>0</g:quantity>
+ * + * Not acceptable:
+ * <g:quantity>out of stock</g:quantity>
+ * + * Attribute of Events, Products, Services, Travel, Vehicles
Content type + * + * integer
+ * + * @param quantity Quantity available. + */ + public void setQuantity(Integer quantity); + + /** + * Quantity available. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
quantity
Details The number of units available for purchase. This attribute can be left + * blank if you have a large quantity or if it is not applicable.
Example Acceptable:
+ * <g:quantity>18</g:quantity>
+ * + * <g:quantity>0</g:quantity>
+ * + * Not acceptable:
+ * <g:quantity>out of stock</g:quantity>
+ * + * Attribute of Events, Products, Services, Travel, Vehicles
Content type + * + * integer
+ * + * @return Quantity available. + */ + public Integer getQuantity(); + + /** + * Shipping information related to the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * shipping
Details Shipping options available for an item. Up to 10 shipping options can be + * included for each item. Three sub-attributes are included in the shipping attribute: + *
    + * + *
  • service = The type of service used to ship an item. Acceptable values are 'FedEx', 'UPS', + * 'DHL', 'Mail', and 'Other'
  • + *
  • country = The country an item will ship to. Only acceptable values are ISO 3166 + * country codes.
  • + *
  • price = the price of shipping.
  • + *
+ *
+ * + * Example <g:shipping>
+ * <g:country>US</g:country>
+ * + * <g:service>UPS</g:shipping>
+ * + * <g:price>35.95</g:price>
+ * </g:shipping>
Attribute of Products
+ * + * Content type shippingType
+ * + * @param shipping Shipping information related to the event. + */ + public void setShipping(ShippingType[] shipping); + + /** + * Shipping information related to the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * shipping
Details Shipping options available for an item. Up to 10 shipping options can be + * included for each item. Three sub-attributes are included in the shipping attribute: + *
    + * + *
  • service = The type of service used to ship an item. Acceptable values are 'FedEx', 'UPS', + * 'DHL', 'Mail', and 'Other'
  • + *
  • country = The country an item will ship to. Only acceptable values are ISO 3166 + * country codes.
  • + *
  • price = the price of shipping.
  • + *
+ *
+ * + * Example <g:shipping>
+ * <g:country>US</g:country>
+ * + * <g:service>UPS</g:shipping>
+ * + * <g:price>35.95</g:price>
+ * </g:shipping>
Attribute of Products
+ * + * Content type shippingType
+ * + * @return Shipping information related to the event. + */ + public ShippingType[] getShipping(); + + /** + * Tax rate associated with the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @param taxPercent Tax rate associated with the event. + */ + public void setTaxPercent(Float taxPercent); + + /** + * Tax rate associated with the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @return Tax rate associated with the event. + */ + public Float getTaxPercent(); + + /** + * Region where tax applies. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @param taxRegion Region where tax applies. + */ + public void setTaxRegion(String taxRegion); + + /** + * Region where tax applies. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @return Region where tax applies. + */ + public String getTaxRegion(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/GlobalInterface.java b/rome-modules/src/main/java/com/rometools/modules/base/GlobalInterface.java new file mode 100644 index 0000000..1760248 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/GlobalInterface.java @@ -0,0 +1,554 @@ +/* + * GlobalInterface.java + * + * Created on November 16, 2005, 5:27 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import java.io.Serializable; +import java.net.URL; +import java.util.Date; + +/** + * This is an interface representing the universals. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public interface GlobalInterface extends Serializable { + /** + * Expiration Date for this item.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
expiration_date
Details Date that the item expires in ISO 8601 + * format: YYYY-MM-DD
Example <g:expiration_date>2005-20-12</g:expiration_date> + * + *
Attribute of Reference Items, Events, Housing, Jobs, People profiles, Products, + * Services, Travel, Vehicles, Wanted Ads.
Content type date
+ * + * @param expirationDate the date this entry will expire + */ + public void setExpirationDate(Date expirationDate); + + /** + * Expiration Date for this item.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
expiration_date
Details Date that the item expires in ISO 8601 + * format: YYYY-MM-DD
Example <g:expiration_date>2005-20-12</g:expiration_date> + * + *
Attribute of Reference Items, Events, Housing, Jobs, People profiles, Products, + * Services, Travel, Vehicles, Wanted Ads.
Content type date
+ * + * @return the date this entry will expire + */ + public Date getExpirationDate(); + + /** + * Date and time that the item expires. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
expiration_date_time
Details Date and time that the item expires in ISO 8601 + * format: YYYY-MM-DDThh:mm:ss
Example + * <g:expiration_date_time>12-20-05T11:59:59</g:expiration_date_time>
Attribute of Reference Items, Events, Housing, Jobs, People profiles, Products, + * Services, Travel, Vehicles, Wanted Ads.
Content type dateTime
+ * + * @param expirationDateTime Date and time that the item expires. + */ + public void setExpirationDateTime(Date expirationDateTime); + + /** + * Date and time that the item expires. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
expiration_date_time
Details Date and time that the item expires in ISO 8601 + * format: YYYY-MM-DDThh:mm:ss
Example + * <g:expiration_date_time>12-20-05T11:59:59</g:expiration_date_time>
Attribute of Reference Items, Events, Housing, Jobs, People profiles, Products, + * Services, Travel, Vehicles, Wanted Ads.
Content type dateTime
+ * + * @return Date and time that the item expires. + */ + public Date getExpirationDateTime(); + + /** + * Unique id for this item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
id
Details Unique alphanumeric identifier for each item - e.g., your internal ID + * code.
+ * IMPORTANT: Once you submit an item with a unique id, this identifier must not change when you + * send in a new bulk upload. Each item must retain the same id in subsequent bulk + * uploads.
Example + * + * <g:id>01flx</g:id>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type string
+ * + * @param id unique identifier for this entry + */ + public void setId(String id); + + /** + * Unique id for this item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
id
Details Unique alphanumeric identifier for each item - e.g., your internal ID + * code.
+ * IMPORTANT: Once you submit an item with a unique id, this identifier must not change when you + * send in a new bulk upload. Each item must retain the same id in subsequent bulk + * uploads.
Example + * + * <g:id>01flx</g:id>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type string
+ * + * @return unique identifier for this entry + */ + public String getId(); + + /** + * Images for this item.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
image_link
Details URL of an associated image if available online. Use your full-sized + * images; do not use thumbnail images. Up to ten image_links, all placed in between their own + * <image_link> and </image_link> attributes, can be included with each item. If you + * do not have an image available, do not include this attribute. Please do not include an image + * that says "Image not available." Relative URLs and logo images are not acceptable.
Example Acceptable:
+ * <image_link>http://example.com/images/1006.jpg</image_link>
+ * + * <image_link>http://example.com/i/6.jpg,http://example.com/i/9.jpg</image_link>
+ * + * Not acceptable:
+ * <image_link>/images/1006.jpg</image_link>
+ * <image_link>example.com/images/1006.jpg</image_link>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type url
+ * + * @param imageLinks URLs to images. Limit 10. + */ + public void setImageLinks(URL[] imageLinks); + + /** + * Images for this item.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
image_link
Details URL of an associated image if available online. Use your full-sized + * images; do not use thumbnail images. Up to ten image_links, all placed in between their own + * <image_link> and </image_link> attributes, can be included with each item. If you + * do not have an image available, do not include this attribute. Please do not include an image + * that says "Image not available." Relative URLs and logo images are not acceptable.
Example Acceptable:
+ * <image_link>http://example.com/images/1006.jpg</image_link>
+ * + * <image_link>http://example.com/i/6.jpg,http://example.com/i/9.jpg</image_link>
+ * + * Not acceptable:
+ * <image_link>/images/1006.jpg</image_link>
+ * <image_link>example.com/images/1006.jpg</image_link>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type url
+ * + * @return URLs to images + */ + public URL[] getImageLinks(); + + /** + * Labels for this item.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * label
+ * + * Details + * A list of classifications the item may fall under. Up to ten user-selected + * label, each placed in between their own <label> + * + * and </label> tags, can be included with each item. These attributes will be used to + * match your items to search queries. Each attribute value will be checked for policy + * compliance.
+ * Example + * + * Acceptable:
+ * For an automobile in a Vehicles information type:

+ *
+ * + * <g:label>Leather</g:label>
+ *
<g:label>Power locks</g:label>
+ * + *
<g:label>sunroof</g:label>
+ * + *
<g:label>ABS</g:label>
+ *
+ *
For a concert in an Events information type:
+ * + * <g:label>VIP</g:label>
+ * + *
<g:label>front row</g:label>
+ *
<g:label>backstage</g:label>
+ * + *
+ * + * <g:label>KROCK 101.5</g:label>
+ *
<g:label>parking passes</g:label>
+ *
+ *
Not acceptable:
+ * + *
<g:label> leater, power locks, sunroof, ABS + * </g:label>
+ * Attribute of + * Reference Items, Events, Housing, Jobs, News and Articles, People profiles, + * Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
+ * Content type + * + * string
+ * + * @param labels labels for this entry. Limit 10. + */ + public void setLabels(String[] labels); + + /** + * Labels for this item.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * label
+ * + * Details + * A list of classifications the item may fall under. Up to ten user-selected + * label, each placed in between their own <label> + * + * and </label> tags, can be included with each item. These attributes will be used to + * match your items to search queries. Each attribute value will be checked for policy + * compliance.
+ * Example + * + * Acceptable:
+ * For an automobile in a Vehicles information type:

+ *
+ * + * <g:label>Leather</g:label>
+ *
<g:label>Power locks</g:label>
+ * + *
<g:label>sunroof</g:label>
+ * + *
<g:label>ABS</g:label>
+ *
+ *
For a concert in an Events information type:
+ * + * <g:label>VIP</g:label>
+ * + *
<g:label>front row</g:label>
+ *
<g:label>backstage</g:label>
+ * + *
+ * + * <g:label>KROCK 101.5</g:label>
+ *
<g:label>parking passes</g:label>
+ *
+ *
Not acceptable:
+ * + *
<g:label> leater, power locks, sunroof, ABS + * </g:label>
+ * Attribute of + * Reference Items, Events, Housing, Jobs, News and Articles, People profiles, + * Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
+ * Content type + * + * string
+ * + * @return labels for this entry + */ + public String[] getLabels(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/GoogleBase.java b/rome-modules/src/main/java/com/rometools/modules/base/GoogleBase.java new file mode 100644 index 0000000..db9b121 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/GoogleBase.java @@ -0,0 +1,60 @@ +/* + * GoogleBase.java + * + * Created on November 16, 2005, 4:37 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import com.rometools.rome.feed.module.Module; + +/** + * This is the root interface for the Google Base module. + * + *

+ * It supports all the individual data "types". If you want to work with, for instance, just the + * Article or Job datatype, you can cast it to the respective interface and see only methods related + * to a particular entry type. + *

+ * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface GoogleBase extends Module, Article, Course, Event, Job, Person, Product, Review, ScholarlyArticle, Service, Travel, Unknown, Vehicle, Wanted, + Housing { + /** This is the URI for the Google Base Schema. */ + public static final String URI = "http://base.google.com/ns/1.0"; +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/GoogleBaseImpl.java b/rome-modules/src/main/java/com/rometools/modules/base/GoogleBaseImpl.java new file mode 100644 index 0000000..73f0840 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/GoogleBaseImpl.java @@ -0,0 +1,1444 @@ +/* + * GoogleBaseImpl.java + * + * Created on November 16, 2005, 2:06 PM + * + * This library is provided under dual licenses. You may choose the terms of the Lesser General + * Public License or the Apache License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; either version + * 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import java.lang.reflect.Array; +import java.net.URL; +import java.util.Date; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.base.types.CloneableType; +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.DateTimeRange; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.GenderEnumeration; +import com.rometools.modules.base.types.IntUnit; +import com.rometools.modules.base.types.PaymentTypeEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; +import com.rometools.modules.base.types.ShippingType; +import com.rometools.modules.base.types.ShortDate; +import com.rometools.modules.base.types.Size; +import com.rometools.modules.base.types.YearType; +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.impl.EqualsBean; + +/** + * This is the implementation class for the GoogleBase module interface. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public class GoogleBaseImpl implements GoogleBase { + /** + * + */ + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(GoogleBaseImpl.class); + + /** boolean:listing_type */ + private Boolean listingType; + + /** Can this item be picked up. */ + private Boolean pickup; + + /** currencyCodeEnumeration:currency */ + private CurrencyEnumeration currency; + + /** dateTime:expiration_date_time */ + private Date expirationDateTime; + + /** dateTimeRange:course_date_range */ + private DateTimeRange courseDateRange; + + /** dateTimeRange:event_date_range */ + private DateTimeRange eventDateRange; + + /** dateTimeRange:travel_date_range */ + private DateTimeRange travelDateRange; + + /** float:bathrooms */ + private Float bathrooms; + + /** float:hoa_dues */ + private Float hoaDues; + + /** string:rating thoug this a value from 1 to 5 */ + private Float rating; + + /** float:salary */ + private Float salary; + + /** percentType:tax_percent */ + private Float taxPercent; + + /** floatUnit:delivery_radius */ + private FloatUnit deliveryRadius; + + /** floatUnit:megapixels */ + private FloatUnit megapixels; + + /** floatUnit:memory */ + private FloatUnit memory; + + /** floatUnit:price */ + private FloatUnit price; + + /** floatUnit:processor_speed */ + private FloatUnit processorSpeed; + + /** floatUnit:weight */ + private FloatUnit weight; + + /** genderEnumeration:gender */ + private GenderEnumeration gender; + + /** intUnit:area */ + private IntUnit area; + + /** integer:age */ + private Integer age; + + /** integer:bedrooms */ + private Integer bedrooms; + + /** integer:mileage */ + private Integer mileage; + + /** integer:pages */ + private Integer pages; + + /** integer:quantity */ + private Integer quantity; + + /** locationType:from_location */ + private String fromLocation; + + /** locationType:location */ + private String location; + + /** locationType:to_location */ + private String toLocation; + + /** priceTypeEnumeration:price_type */ + private PriceTypeEnumeration priceType; + + /** starting/neg:salary_type */ + private PriceTypeEnumeration salaryType; + + /** date:expiration_date */ + private ShortDate expirationDate; + + /** date:publishedDate */ + private ShortDate publishDate; + + /** string:size */ + private Size size; + + /** string:sexual_orientation */ + private String SexualOrientation; + + /** string apparel_type */ + private String apparelType; + + /** string:brand */ + private String brand; + + /** string:condition */ + private String condition; + + /** string:course_number */ + private String courseNumber; + + /** string:course_times */ + private String courseTimes; + + /** string:delivery_notes */ + private String deliveryNotes; + + /** string:education */ + private String education; + + /** string:employer */ + private String employer; + + /** string:id */ + private String id; + + /** string:immigration_status */ + private String immigrationStatus; + + /** stirng:isbn */ + private String isbn; + + /** string:make */ + private String make; + + /** string:manufacturer */ + private String manufacturer; + + /** string:manufacturer_id */ + private String manufacturerId; + + /** string:marital_status */ + private String maritalStatus; + + /** string:model */ + private String model; + + /** string:model_number */ + private String modelNumber; + + /** string:name_of_item_being_reviewed */ + private String nameOfItemBeingReviewed; + + /** string:news_source */ + private String newsSource; + + /** string:occupation */ + private String occupation; + + /** string:operating_systems */ + private String operatingSystems; + + /** string:payment_notes */ + private String paymentNotes; + + /** string:publication_name */ + private String publicationName; + + /** string:publication_volume */ + private String publicationVolume; + + /** string:review_type */ + private String reviewType; + + /** string:reviewer_type */ + private String reviewerType; + + /** string:school_district */ + private String schoolDistrict; + + /** string:service_type */ + private String serviceType; + + /** string:taxRegion */ + private String taxRegion; + + /** string:university */ + private String university; + + /** string:upc */ + private String upc; + + /** string:vehicle_type */ + private String vehicleType; + + /** string:vin */ + private String vin; + + /** string:url_of_item_being_reviewed */ + private URL urlOfItemBeingReviewed; + + /** string:year */ + private YearType year; + + /** string:actor */ + private String[] actors; + + /** string:agent */ + private String[] agents; + + /** string:artist */ + private String[] artists; + + /** string:author */ + private String[] authors; + + /** string:color */ + private String[] color; + + /** string:ethnicities */ + private String[] ethnicities; + + /** string:format */ + private String[] format; + + /** url:image_links */ + private URL[] imageLinks; + + /** string:interested_in */ + private String[] interestedIn; + + /** string:job_function */ + private String[] jobFunctions; + + /** string:job_industry */ + private String[] jobIndustries; + + /** string:job_type */ + private String[] jobTypes; + + /** string:label */ + private String[] labels; + + /** string:license */ + private String[] licenses; + + /** paymentTypeEnumeration:payment_accepted */ + private PaymentTypeEnumeration[] paymentAccepted; + + /** string:product_type */ + private String[] productTypes; + + /** string:programming_language */ + private String[] programmingLanguages; + + /** string:property_type */ + private String[] propertyTypes; + + /** url:related_link */ + private URL[] relatedLinks; + + /** shippingType:shipping */ + private ShippingType[] shipping; + + /** intUnitType:square_footage */ + private IntUnit[] squareFootages; + + /** string:subject_area */ + private String[] subjectAreas; + + /** string:subject */ + private String[] subjects; + + /** + * DOCUMENT ME! + * + * @param actors + */ + @Override + public void setActors(final String[] actors) { + this.actors = actors; + } + + @Override + public String[] getActors() { + return actors == null ? new String[0] : actors; + } + + @Override + public void setAge(final Integer age) { + this.age = age; + } + + @Override + public Integer getAge() { + return age; + } + + @Override + public void setAgents(final String[] agents) { + this.agents = agents == null ? new String[0] : agents; + } + + @Override + public String[] getAgents() { + return agents; + } + + @Override + public void setApparelType(final String apparelType) { + this.apparelType = apparelType; + } + + @Override + public String getApparelType() { + return apparelType; + } + + @Override + public void setArea(final IntUnit area) { + this.area = area; + } + + @Override + public IntUnit getArea() { + return area; + } + + @Override + public void setArtists(final String[] artists) { + this.artists = artists; + } + + @Override + public String[] getArtists() { + return artists == null ? new String[0] : artists; + } + + @Override + public void setAuthors(final String[] authors) { + this.authors = authors; + } + + @Override + public String[] getAuthors() { + return authors == null ? new String[0] : authors; + } + + @Override + public void setBathrooms(final Float bathrooms) { + this.bathrooms = bathrooms; + } + + @Override + public Float getBathrooms() { + return bathrooms; + } + + @Override + public void setBedrooms(final Integer bedrooms) { + this.bedrooms = bedrooms; + } + + @Override + public Integer getBedrooms() { + return bedrooms; + } + + @Override + public void setBrand(final String brand) { + this.brand = brand; + } + + @Override + public String getBrand() { + return brand; + } + + @Override + public void setColors(final String[] color) { + this.color = color; + } + + @Override + public String[] getColors() { + return color == null ? new String[0] : color; + } + + @Override + public void setCondition(final String condition) { + this.condition = condition; + } + + @Override + public String getCondition() { + return condition; + } + + @Override + public void setCourseDateRange(final DateTimeRange courseDateRange) { + this.courseDateRange = courseDateRange; + } + + @Override + public DateTimeRange getCourseDateRange() { + return courseDateRange; + } + + @Override + public void setCourseNumber(final String courseNumber) { + this.courseNumber = courseNumber; + } + + @Override + public String getCourseNumber() { + return courseNumber; + } + + @Override + public void setCourseTimes(final String courseTimes) { + this.courseTimes = courseTimes; + } + + @Override + public String getCourseTimes() { + return courseTimes; + } + + @Override + public void setCurrency(final CurrencyEnumeration currency) { + this.currency = currency; + } + + @Override + public CurrencyEnumeration getCurrency() { + return currency; + } + + @Override + public void setDeliveryNotes(final String deliveryNotes) { + this.deliveryNotes = deliveryNotes; + } + + @Override + public String getDeliveryNotes() { + return deliveryNotes; + } + + @Override + public void setDeliveryRadius(final FloatUnit deliveryRadius) { + this.deliveryRadius = deliveryRadius; + } + + @Override + public FloatUnit getDeliveryRadius() { + return deliveryRadius; + } + + @Override + public void setEducation(final String education) { + this.education = education; + } + + @Override + public String getEducation() { + return education; + } + + @Override + public void setEmployer(final String employer) { + this.employer = employer; + } + + @Override + public String getEmployer() { + return employer; + } + + @Override + public void setEthnicities(final String[] ethnicities) { + this.ethnicities = ethnicities; + } + + @Override + public String[] getEthnicities() { + return ethnicities == null ? new String[0] : ethnicities; + } + + @Override + public void setEventDateRange(final DateTimeRange eventDateRange) { + this.eventDateRange = eventDateRange; + } + + @Override + public DateTimeRange getEventDateRange() { + return eventDateRange; + } + + @Override + public void setExpirationDate(final Date expirationDate) { + if (expirationDate != null && !(expirationDate instanceof ShortDate)) { + this.expirationDate = new ShortDate(expirationDate); + } else { + this.expirationDate = null; + } + } + + @Override + public Date getExpirationDate() { + return expirationDate; + } + + @Override + public void setExpirationDateTime(final Date expirationDateTime) { + this.expirationDateTime = expirationDateTime; + } + + @Override + public Date getExpirationDateTime() { + return expirationDateTime; + } + + @Override + public void setFormat(final String[] format) { + this.format = format; + } + + @Override + public String[] getFormat() { + return format == null ? new String[0] : format; + } + + @Override + public void setFromLocation(final String fromLocation) { + this.fromLocation = fromLocation; + } + + @Override + public String getFromLocation() { + return fromLocation; + } + + @Override + public void setGender(final GenderEnumeration gender) { + this.gender = gender; + } + + @Override + public GenderEnumeration getGender() { + return gender; + } + + @Override + public void setHoaDues(final Float hoaDues) { + this.hoaDues = hoaDues; + } + + @Override + public Float getHoaDues() { + return hoaDues; + } + + @Override + public void setId(final String id) { + this.id = id; + } + + @Override + public String getId() { + return id; + } + + @Override + public void setImageLinks(final URL[] imageLinks) { + this.imageLinks = imageLinks; + } + + @Override + public URL[] getImageLinks() { + return imageLinks == null ? new URL[0] : imageLinks; + } + + @Override + public void setImmigrationStatus(final String immigrationStatus) { + this.immigrationStatus = immigrationStatus; + } + + @Override + public String getImmigrationStatus() { + return immigrationStatus; + } + + @Override + public void setInterestedIn(final String[] interestedIn) { + this.interestedIn = interestedIn; + } + + @Override + public String[] getInterestedIn() { + return interestedIn == null ? new String[0] : interestedIn; + } + + @Override + public Class getInterface() { + return GoogleBase.class; + } + + @Override + public void setIsbn(final String isbn) { + this.isbn = isbn; + } + + @Override + public String getIsbn() { + return isbn; + } + + @Override + public void setJobFunctions(final String[] jobFunctions) { + this.jobFunctions = jobFunctions; + } + + @Override + public String[] getJobFunctions() { + return jobFunctions == null ? new String[0] : jobFunctions; + } + + @Override + public void setJobIndustries(final String[] jobIndustries) { + this.jobIndustries = jobIndustries; + } + + @Override + public String[] getJobIndustries() { + return jobIndustries == null ? new String[0] : jobIndustries; + } + + @Override + public void setJobTypes(final String[] jobTypes) { + this.jobTypes = jobTypes; + } + + @Override + public String[] getJobTypes() { + return jobTypes == null ? new String[0] : jobTypes; + } + + @Override + public void setLabels(final String[] labels) { + this.labels = labels; + } + + @Override + public String[] getLabels() { + return labels == null ? new String[0] : labels; + } + + @Override + public void setLicenses(final String[] licenses) { + this.licenses = licenses; + } + + @Override + public String[] getLicenses() { + return licenses == null ? new String[0] : licenses; + } + + @Override + public void setListingType(final Boolean listingType) { + this.listingType = listingType; + } + + @Override + public Boolean getListingType() { + return listingType; + } + + @Override + public void setLocation(final String location) { + this.location = location; + } + + @Override + public String getLocation() { + return location; + } + + @Override + public void setMake(final String make) { + this.make = make; + } + + @Override + public String getMake() { + return make; + } + + @Override + public void setManufacturer(final String manufacturer) { + this.manufacturer = manufacturer; + } + + @Override + public String getManufacturer() { + return manufacturer; + } + + @Override + public void setManufacturerId(final String manufacturerId) { + this.manufacturerId = manufacturerId; + } + + @Override + public String getManufacturerId() { + return manufacturerId; + } + + @Override + public void setMaritalStatus(final String maritalStatus) { + this.maritalStatus = maritalStatus; + } + + @Override + public String getMaritalStatus() { + return maritalStatus; + } + + @Override + public void setMegapixels(final FloatUnit megapixels) { + this.megapixels = megapixels; + } + + @Override + public FloatUnit getMegapixels() { + return megapixels; + } + + @Override + public void setMemory(final FloatUnit memory) { + this.memory = memory; + } + + @Override + public FloatUnit getMemory() { + return memory; + } + + @Override + public void setMileage(final Integer mileage) { + this.mileage = mileage; + } + + @Override + public Integer getMileage() { + return mileage; + } + + @Override + public void setModel(final String model) { + this.model = model; + } + + @Override + public String getModel() { + return model; + } + + @Override + public void setModelNumber(final String modelNumber) { + this.modelNumber = modelNumber; + } + + @Override + public String getModelNumber() { + return modelNumber; + } + + @Override + public void setNameOfItemBeingReviewed(final String nameOfItemBeingReviewed) { + this.nameOfItemBeingReviewed = nameOfItemBeingReviewed; + } + + @Override + public String getNameOfItemBeingReviewed() { + return nameOfItemBeingReviewed; + } + + @Override + public void setNewsSource(final String newsSource) { + this.newsSource = newsSource; + } + + @Override + public String getNewsSource() { + return newsSource; + } + + @Override + public void setOccupation(final String occupation) { + this.occupation = occupation; + } + + @Override + public String getOccupation() { + return occupation; + } + + @Override + public void setOperatingSystems(final String operatingSystems) { + this.operatingSystems = operatingSystems; + } + + @Override + public String getOperatingSystems() { + return operatingSystems; + } + + @Override + public void setPages(final Integer pages) { + this.pages = pages; + } + + @Override + public Integer getPages() { + return pages; + } + + @Override + public void setPaymentAccepted(final PaymentTypeEnumeration[] paymentAccepted) { + this.paymentAccepted = paymentAccepted; + } + + @Override + public PaymentTypeEnumeration[] getPaymentAccepted() { + return paymentAccepted == null ? new PaymentTypeEnumeration[0] : paymentAccepted; + } + + @Override + public void setPaymentNotes(final String paymentNotes) { + this.paymentNotes = paymentNotes; + } + + @Override + public String getPaymentNotes() { + return paymentNotes; + } + + @Override + public void setPickup(final Boolean pickup) { + this.pickup = pickup; + } + + @Override + public Boolean getPickup() { + return pickup; + } + + @Override + public void setPrice(final FloatUnit price) { + this.price = price; + } + + @Override + public FloatUnit getPrice() { + return price; + } + + @Override + public void setPriceType(final PriceTypeEnumeration priceType) { + this.priceType = priceType; + } + + @Override + public PriceTypeEnumeration getPriceType() { + return priceType; + } + + @Override + public void setProcessorSpeed(final FloatUnit processorSpeed) { + this.processorSpeed = processorSpeed; + } + + @Override + public FloatUnit getProcessorSpeed() { + return processorSpeed; + } + + @Override + public void setProductTypes(final String[] productTypes) { + this.productTypes = productTypes; + } + + @Override + public String[] getProductTypes() { + return productTypes == null ? new String[0] : productTypes; + } + + @Override + public void setProgrammingLanguages(final String[] programmingLanguages) { + this.programmingLanguages = programmingLanguages; + } + + @Override + public String[] getProgrammingLanguages() { + return programmingLanguages == null ? new String[0] : programmingLanguages; + } + + @Override + public void setPropertyTypes(final String[] propertyTypes) { + this.propertyTypes = propertyTypes; + } + + @Override + public String[] getPropertyTypes() { + return propertyTypes == null ? new String[0] : propertyTypes; + } + + @Override + public void setPublicationName(final String publicationName) { + this.publicationName = publicationName; + } + + @Override + public String getPublicationName() { + return publicationName; + } + + @Override + public void setPublicationVolume(final String publicationVolume) { + this.publicationVolume = publicationVolume; + } + + @Override + public String getPublicationVolume() { + return publicationVolume; + } + + @Override + public void setPublishDate(final Date publishDate) { + if (publishDate != null && !(publishDate instanceof ShortDate)) { + this.publishDate = new ShortDate(publishDate); + } else { + this.publishDate = null; + } + } + + @Override + public Date getPublishDate() { + return publishDate; + } + + @Override + public void setQuantity(final Integer quantity) { + this.quantity = quantity; + } + + @Override + public Integer getQuantity() { + return quantity; + } + + @Override + public void setRating(final Float rating) { + this.rating = rating; + } + + @Override + public Float getRating() { + return rating; + } + + @Override + public void setRelatedLinks(final URL[] relatedLinks) { + this.relatedLinks = relatedLinks; + } + + @Override + public URL[] getRelatedLinks() { + return relatedLinks == null ? new URL[0] : relatedLinks; + } + + @Override + public void setReviewType(final String reviewType) { + this.reviewType = reviewType; + } + + @Override + public String getReviewType() { + return reviewType; + } + + @Override + public void setReviewerType(final String reviewerType) { + this.reviewerType = reviewerType; + } + + @Override + public String getReviewerType() { + return reviewerType; + } + + @Override + public void setSalary(final Float salary) { + this.salary = salary; + } + + @Override + public Float getSalary() { + return salary; + } + + @Override + public void setSalaryType(final PriceTypeEnumeration salaryType) { + this.salaryType = salaryType; + } + + @Override + public PriceTypeEnumeration getSalaryType() { + return salaryType; + } + + @Override + public void setSchoolDistrict(final String schoolDistrict) { + this.schoolDistrict = schoolDistrict; + } + + @Override + public String getSchoolDistrict() { + return schoolDistrict; + } + + @Override + public void setServiceType(final String serviceType) { + this.serviceType = serviceType; + } + + @Override + public String getServiceType() { + return serviceType; + } + + @Override + public void setSexualOrientation(final String SexualOrientation) { + this.SexualOrientation = SexualOrientation; + } + + @Override + public String getSexualOrientation() { + return SexualOrientation; + } + + @Override + public void setShipping(final ShippingType[] shipping) { + this.shipping = shipping; + } + + @Override + public ShippingType[] getShipping() { + return shipping == null ? new ShippingType[0] : shipping; + } + + @Override + public void setSize(final Size size) { + this.size = size; + } + + @Override + public Size getSize() { + return size; + } + + @Override + public void setSquareFootages(final IntUnit[] squareFootages) { + this.squareFootages = squareFootages; + } + + @Override + public IntUnit[] getSquareFootages() { + return squareFootages == null ? new IntUnit[0] : squareFootages; + } + + @Override + public void setSubjectAreas(final String[] subjectAreas) { + this.subjectAreas = subjectAreas; + } + + @Override + public String[] getSubjectAreas() { + return subjectAreas == null ? new String[0] : subjectAreas; + } + + @Override + public void setSubjects(final String[] subjects) { + this.subjects = subjects; + } + + @Override + public String[] getSubjects() { + return subjects == null ? new String[0] : subjects; + } + + @Override + public void setTaxPercent(final Float taxPercent) { + this.taxPercent = taxPercent; + } + + @Override + public Float getTaxPercent() { + return taxPercent; + } + + @Override + public void setTaxRegion(final String taxRegion) { + this.taxRegion = taxRegion; + } + + @Override + public String getTaxRegion() { + return taxRegion; + } + + @Override + public void setToLocation(final String toLocation) { + this.toLocation = toLocation; + } + + @Override + public String getToLocation() { + return toLocation; + } + + @Override + public void setTravelDateRange(final DateTimeRange travelDateRange) { + this.travelDateRange = travelDateRange; + } + + @Override + public DateTimeRange getTravelDateRange() { + return travelDateRange; + } + + @Override + public void setUniversity(final String university) { + this.university = university; + } + + @Override + public String getUniversity() { + return university; + } + + @Override + public void setUpc(final String upc) { + this.upc = upc; + } + + @Override + public String getUpc() { + return upc; + } + + @Override + public String getUri() { + return GoogleBase.URI; + } + + @Override + public void setUrlOfItemBeingReviewed(final URL urlOfItemBeingReviewed) { + this.urlOfItemBeingReviewed = urlOfItemBeingReviewed; + } + + @Override + public URL getUrlOfItemBeingReviewed() { + return urlOfItemBeingReviewed; + } + + @Override + public void setVehicleType(final String vehicleType) { + this.vehicleType = vehicleType; + } + + @Override + public String getVehicleType() { + return vehicleType; + } + + @Override + public void setVin(final String vin) { + this.vin = vin; + } + + @Override + public String getVin() { + return vin; + } + + @Override + public void setWeight(final FloatUnit weight) { + this.weight = weight; + } + + @Override + public FloatUnit getWeight() { + return weight; + } + + @Override + public void setYear(final YearType year) { + this.year = year; + } + + @Override + public YearType getYear() { + return year; + } + + // TODO: Finish + @Override + public Object clone() throws CloneNotSupportedException { + try { + final GoogleBaseImpl gbi = new GoogleBaseImpl(); + gbi.copyFrom(this); + + return gbi; + } catch (final Exception e) { + LOG.error("Error", e); + throw new CloneNotSupportedException(); + } + } + + @Override + public void copyFrom(final CopyFrom obj) { + if (!(obj instanceof GoogleBase)) { + return; + } + + final GoogleBase source = (GoogleBase) obj; + + setActors((String[]) arrayCopy(source.getActors())); + setAge(source.getAge()); + setAgents((String[]) arrayCopy(source.getAgents())); + setApparelType(source.getApparelType()); + setArea(source.getArea()); + setArtists((String[]) arrayCopy(source.getArtists())); + setAuthors((String[]) arrayCopy(source.getAuthors())); + setBathrooms(source.getBathrooms()); + setBedrooms(source.getBedrooms()); + setBrand(source.getBrand()); + setColors((String[]) arrayCopy(source.getColors())); + setCondition(source.getCondition()); + setCourseDateRange((DateTimeRange) cloneOrNull(source.getCourseDateRange())); + setCourseNumber(source.getCourseNumber()); + setCourseTimes(source.getCourseTimes()); + setDeliveryNotes(source.getDeliveryNotes()); + setDeliveryRadius(source.getDeliveryRadius()); + setEducation(source.getEducation()); + setEmployer(source.getEmployer()); + setEthnicities((String[]) arrayCopy(source.getEthnicities())); + setEventDateRange((DateTimeRange) cloneOrNull(source.getEventDateRange())); + setExpirationDate(dateOrNull(source.getExpirationDate())); + setExpirationDateTime(dateOrNull(source.getExpirationDateTime())); + setFormat(source.getFormat()); + setFromLocation(source.getFromLocation()); + setGender(source.getGender()); + setHoaDues(source.getHoaDues()); + setId(source.getId()); + setImageLinks((URL[]) arrayCopy(source.getImageLinks())); + setImmigrationStatus(source.getImmigrationStatus()); + setInterestedIn(source.getInterestedIn()); + setIsbn(source.getIsbn()); + setJobFunctions((String[]) arrayCopy(source.getJobFunctions())); + setJobIndustries((String[]) arrayCopy(source.getJobIndustries())); + setJobTypes((String[]) arrayCopy(source.getJobTypes())); + setLabels((String[]) arrayCopy(source.getLabels())); + setListingType(source.getListingType()); + setLocation(source.getLocation()); + setMake(source.getMake()); + setManufacturer(source.getManufacturer()); + setManufacturerId(source.getManufacturerId()); + setMaritalStatus(source.getMaritalStatus()); + setMegapixels(source.getMegapixels()); + setMemory(source.getMemory()); + setMileage(source.getMileage()); + setModel(source.getModel()); + setModelNumber(source.getModelNumber()); + setNameOfItemBeingReviewed(source.getNameOfItemBeingReviewed()); + setNewsSource(source.getNewsSource()); + setOccupation(source.getOccupation()); + setPages(source.getPages()); + setPaymentAccepted((PaymentTypeEnumeration[]) arrayCopy(source.getPaymentAccepted())); + setPaymentNotes(source.getPaymentNotes()); + setPickup(source.getPickup()); + setPrice(source.getPrice()); + setPriceType(source.getPriceType()); + setProcessorSpeed(source.getProcessorSpeed()); + setProductTypes((String[]) arrayCopy(source.getProductTypes())); + setPropertyTypes((String[]) arrayCopy(source.getPropertyTypes())); + setPublicationName(source.getPublicationName()); + setPublicationVolume(source.getPublicationVolume()); + setPublishDate(dateOrNull(source.getPublishDate())); + setQuantity(source.getQuantity()); + setRating(source.getRating()); + setReviewType(source.getReviewType()); + setReviewerType(source.getReviewerType()); + setSalary(source.getSalary()); + setSalaryType(source.getSalaryType()); + setServiceType(source.getServiceType()); + setSexualOrientation(source.getSexualOrientation()); + setShipping((ShippingType[]) arrayCopy(source.getShipping())); + setSize(source.getSize()); + setSubjects((String[]) arrayCopy(source.getSubjects())); + setTaxPercent(source.getTaxPercent()); + setTaxRegion(source.getTaxRegion()); + setToLocation(source.getToLocation()); + setTravelDateRange((DateTimeRange) cloneOrNull(source.getTravelDateRange())); + setUpc(source.getUpc()); + setUrlOfItemBeingReviewed(source.getUrlOfItemBeingReviewed()); + setVehicleType(source.getVehicleType()); + setVin(source.getVin()); + setYear(source.getYear()); + setLicenses((String[]) arrayCopy(source.getLicenses())); + setRelatedLinks((URL[]) arrayCopy(source.getRelatedLinks())); + setSubjectAreas((String[]) arrayCopy(source.getSubjectAreas())); + setProgrammingLanguages((String[]) arrayCopy(source.getProgrammingLanguages())); + setSquareFootages((IntUnit[]) arrayCopy(source.getSquareFootages())); + setCurrency(source.getCurrency()); + setSchoolDistrict(source.getSchoolDistrict()); + setUniversity(source.getUniversity()); + setWeight(source.getWeight()); + setOperatingSystems(source.getOperatingSystems()); + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + private Object arrayCopy(final Object[] source) { + if (source == null) { + return null; + } + + final Object[] array = (Object[]) Array.newInstance(source.getClass().getComponentType(), source.length); + + for (int i = 0; i < source.length; i++) { + array[i] = source[i]; + } + + return array; + } + + private Object cloneOrNull(final CloneableType o) { + if (o == null) { + return null; + } else { + return o.clone(); + } + } + + private Date dateOrNull(final Date date) { + if (date == null) { + return null; + } else { + return new Date(date.getTime()); + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Housing.java b/rome-modules/src/main/java/com/rometools/modules/base/Housing.java new file mode 100644 index 0000000..f5b56d4 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Housing.java @@ -0,0 +1,1541 @@ +/* + * Housing.java + * + * Created on November 16, 2005, 12:48 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.IntUnit; +import com.rometools.modules.base.types.PaymentTypeEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; +import com.rometools.modules.base.types.YearType; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for Housing entry + * types. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface Housing extends GlobalInterface { + /** + * An array of agent name Strings, not to exceed 10 in lenght. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
agent
DetailsIndividual who is negotiating and arranging the real estate sale.
Example<g:agent>Sue Smith</g:agent>
Attribute ofHousing
Content typestring
+ * + * @param agents An array of agent name Strings, not to exceed 10 in lenght. + */ + public void setAgents(String[] agents); + + /** + * An array of agent name Strings, not to exceed 10 in lenght. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
agent
DetailsIndividual who is negotiating and arranging the real estate sale.
Example<g:agent>Sue Smith</g:agent>
Attribute ofHousing
Content typestring
+ * + * @return An array of agent name Strings, not to exceed 10 in lenght. + */ + public String[] getAgents(); + + /** + * The area of the real estate. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
area
DetailsThe size of an area of real estate.
Example<g:area>1000</g:area>
Attribute ofHousing
Content typeintUnit
+ * + * @param area The area of the real estate + */ + public void setArea(IntUnit area); + + /** + * The area of the real estate. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
area
DetailsThe size of an area of real estate.
Example<g:area>1000</g:area>
Attribute ofHousing
Content typeintUnit
+ * + * @return The area of the real estate + */ + public IntUnit getArea(); + + /** + * The number of bathrooms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
bathrooms
+ * + * Details + * + * Number of bathrooms. Numeric values only.
Example Acceptable:
+ * + * <g:bathrooms>2</g:bathrooms>
+ * Not acceptable:
+ * <g:bathrooms>2 bathrooms</g:bathrooms>
+ * + * Attribute of Housing
Content type float
+ * + * @param bathrooms The number of bathrooms. + */ + public void setBathrooms(Float bathrooms); + + /** + * The number of bathrooms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
bathrooms
+ * + * Details + * + * Number of bathrooms. Numeric values only.
Example Acceptable:
+ * + * <g:bathrooms>2</g:bathrooms>
+ * Not acceptable:
+ * <g:bathrooms>2 bathrooms</g:bathrooms>
+ * + * Attribute of Housing
Content type float
+ * + * @return number of bathrooms + */ + public Float getBathrooms(); + + /** + * Number of bedrooms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
bedrooms
Details Number of bedrooms. Numeric values only.
Example Acceptable:
+ * <g:bedrooms>3</g:bedrooms>
+ * Not acceptable:
+ * + * <g:bedrooms>3 bedrooms</g:bedrooms>
Attribute of Housing
Content type integer
+ * + * @param bedrooms Number of bedrooms. + */ + public void setBedrooms(Integer bedrooms); + + /** + * Number of bedrooms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
bedrooms
Details Number of bedrooms. Numeric values only.
Example Acceptable:
+ * <g:bedrooms>3</g:bedrooms>
+ * Not acceptable:
+ * + * <g:bedrooms>3 bedrooms</g:bedrooms>
Attribute of Housing
Content type integer
+ * + * @return Number of bedrooms + */ + public Integer getBedrooms(); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @param value Currency of the price amount for an item. + */ + public void setCurrency(CurrencyEnumeration value); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @return Currency of the price amount for an item. + */ + public CurrencyEnumeration getCurrency(); + + /** + * Homeowners association dues on the property. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
hoa_dues
Details Monthly dues paid to a homeowners association.
Example<g:hoa_dues>100</g:hoa_dues>
Attribute of Housing
Content type float
+ * + * @param hoaDues Homeowners association dues on the property. + */ + public void setHoaDues(Float hoaDues); + + /** + * Homeowners association dues on the property. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
hoa_dues
Details Monthly dues paid to a homeowners association.
Example<g:hoa_dues>100</g:hoa_dues>
Attribute of Housing
Content type float
+ * + * @return Homeowners association dues on the property. + */ + public Float getHoaDues(); + + /** + * Indicates whether this property is for sale or not. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
listing_type
Details Information about whether or not a property is for sale or not. + * Acceptable values are "True" or "False".
Example Acceptable:
+ * + * <g:for_sale>true</g:for_sale>
+ * <g:for_sale>false</g:for_sale>
+ * Not acceptable:
+ * + * <g:for_sale>Sale</g:for_sale>
+ * + * <g:for_sale>Rent</g:for_sale>
Attribute of Housing
Content type Boolean
+ * + * @param forSale Indicates whether this property is for sale or not. + */ + public void setListingType(Boolean forSale); + + /** + * Indicates whether this property is for sale or not. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
listing_type
Details Information about whether or not a property is for sale or not. + * Acceptable values are "True" or "False".
Example Acceptable:
+ * + * <g:for_sale>true</g:for_sale>
+ * <g:for_sale>false</g:for_sale>
+ * Not acceptable:
+ * + * <g:for_sale>Sale</g:for_sale>
+ * + * <g:for_sale>Rent</g:for_sale>
Attribute of Housing
Content type Boolean
+ * + * @return Indicates whether this property is for sale or not. + */ + public Boolean getListingType(); + + /** + * Location of the property. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @param location Location of the property. + */ + public void setLocation(String location); + + /** + * Location of the property. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @return Location of the property. + */ + public String getLocation(); + + /** + * Payment Methods acceptable for the property. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * "Cash," "Check," "Traveler’s Check," "Visa," "MasterCard," + * + * "American Express," "Discover," "Wire transfer" or "Paypal." If you accept more than one + * method, include multiple instances of the <payment_accepted> attribute for each + * acceptable method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * + * <g:payment_accepted>Paypal</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check Paypal</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type paymentMethodEnumeration
+ * + * @param paymentAccepted Payment Methods acceptable for the property. + */ + public void setPaymentAccepted(PaymentTypeEnumeration[] paymentAccepted); + + /** + * Payment Methods acceptable for the property. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * "Cash," "Check," "Traveler’s Check," "Visa," "MasterCard," + * + * "American Express," "Discover," "Wire transfer" or "Paypal." If you accept more than one + * method, include multiple instances of the <payment_accepted> attribute for each + * acceptable method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * + * <g:payment_accepted>Paypal</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check Paypal</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type paymentMethodEnumeration
+ * + * @return Payment Methods acceptable for the property. + */ + public PaymentTypeEnumeration[] getPaymentAccepted(); + + /** + * Additional payment information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
Content type string
+ * + * @param paymentNotes Additional payment information. + */ + public void setPaymentNotes(String paymentNotes); + + /** + * Additional payment information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
Content type string
+ * + * @return Additional payment information. + */ + public String getPaymentNotes(); + + /** + * Price for the property.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * <g:price>5,95</g:price>
+ * <g:price>5.00 � 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @param price Price for the property. + */ + public void setPrice(FloatUnit price); + + /** + * Price for the property.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * <g:price>5,95</g:price>
+ * <g:price>5.00 � 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @return Price for the property. + */ + public FloatUnit getPrice(); + + /** + * Price type information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are �negotiable,� or + * �starting.� The default is �starting�
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @param priceType Price type information. + */ + public void setPriceType(PriceTypeEnumeration priceType); + + /** + * Price type information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are �negotiable,� or + * �starting.� The default is �starting�
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @return Price type information. + */ + public PriceTypeEnumeration getPriceType(); + + /** + * Types of property represented here. Limit 10. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
property_type
+ * + * Details + * + * Type of property: house, apartment, condominium, etc.
Example <g:property_type>house</g:property_type>
Attribute of + * + * Housing
Content type string
+ * + * @param propertyTypes Types of property represented here. Limit 10. + */ + public void setPropertyTypes(String[] propertyTypes); + + /** + * Types of property represented here. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
property_type
+ * + * Details + * + * Type of property: house, apartment, condominium, etc.
Example <g:property_type>house</g:property_type>
Attribute of + * + * Housing
Content type string
+ * + * @return Types of property represented here. Limit 10. + */ + public String[] getPropertyTypes(); + + /** + * School district a property is in. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
school_district
Details The school district the property is in.
Example <g:school_district>Union + * School District</g:school_district>
Attribute of Housing
+ * + * Content type string
+ * + * @param schoolDistrict School district a property is in. + */ + public void setSchoolDistrict(String schoolDistrict); + + /** + * School district a property is in. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
school_district
Details The school district the property is in.
Example <g:school_district>Union + * School District</g:school_district>
Attribute of Housing
+ * + * Content type string
+ * + * @return School district a property is in. + */ + public String getSchoolDistrict(); + + /** + * Percentage tax rate. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @param taxPercent Percentage tax rate. + */ + public void setTaxPercent(Float taxPercent); + + /** + * Percentage tax rate. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @return Percentage tax rate. + */ + public Float getTaxPercent(); + + /** + * Geographical region a tax rate applies to. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @param taxRegion Geographical region a tax rate applies to. + */ + public void setTaxRegion(String taxRegion); + + /** + * Geographical region a tax rate applies to. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @return Geographical region a tax rate applies to. + */ + public String getTaxRegion(); + + /** + * The four digit model year or year built. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
year
Details The four digit model year or year built. Format YYYY
+ * + * Example Acceptable:
+ * + * <g:year>2005</g:year>
+ * Not acceptable:
+ * <g:year>79</g:year>
+ * + * <g:year>26</g:year>
Attribute of Housing, Vehicles
+ * + * Content type year
+ * + * @param year The four digit model year or year built. + */ + public void setYear(YearType year); + + /** + * The four digit model year or year built. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
year
Details The four digit model year or year built. Format YYYY
+ * + * Example Acceptable:
+ * + * <g:year>2005</g:year>
+ * Not acceptable:
+ * <g:year>79</g:year>
+ * + * <g:year>26</g:year>
Attribute of Housing, Vehicles
+ * + * Content type year
+ * + * @return The four digit model year or year built. + */ + public YearType getYear(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Job.java b/rome-modules/src/main/java/com/rometools/modules/base/Job.java new file mode 100644 index 0000000..342867e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Job.java @@ -0,0 +1,870 @@ +/* + * Job.java + * + * Created on November 16, 2005, 12:39 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for Job listing entry + * types. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface Job extends GlobalInterface { + /** + * Level of education required for an employment position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
education
Details Level of education required for an employment position.
Example<g:education>PhD</g:education>
Attribute of Jobs
Content type string
+ * + * @param education Level of education required for an employment position. + */ + public void setEducation(String education); + + /** + * Level of education required for an employment position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
education
Details Level of education required for an employment position.
Example<g:education>PhD</g:education>
Attribute of Jobs
Content type string
+ * + * @return Level of education required for an employment position. + */ + public String getEducation(); + + /** + * Company providing employment. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
employer
Details Company providing employment.
Example<g:employer>Google, Inc</g:employer>
Attribute of Jobs
Content type string
+ * + * @param employer Company providing employment. + */ + public void setEmployer(String employer); + + /** + * Company providing employment. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
employer
Details Company providing employment.
Example<g:employer>Google, Inc</g:employer>
Attribute of Jobs
Content type string
+ * + * @return Company providing employment. + */ + public String getEmployer(); + + /** + * Legal residency requirements for an employment position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
immigration_status
Details Legal residency requirements for an employment position.
Example<g:immigration_status>Permanent + * resident</g:immigration_status>
Attribute of Jobs
Content type string
+ * + * @param immigrationStatus Legal residency requirements for an employment position. + */ + public void setImmigrationStatus(String immigrationStatus); + + /** + * Legal residency requirements for an employment position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
immigration_status
Details Legal residency requirements for an employment position.
Example<g:immigration_status>Permanent + * resident</g:immigration_status>
Attribute of Jobs
Content type string
+ * + * @return Legal residency requirements for an employment position. + */ + public String getImmigrationStatus(); + + /** + * The functions of an employment position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
job_function
Details The function of an employment position.
Example <g:job_function>Product Manager</g:job_function>
+ * + * Attribute of Jobs
+ * + * Content type string
+ * + * @param function The functions of an employment position. + */ + public void setJobFunctions(String[] function); + + /** + * The functions of an employment position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
job_function
Details The function of an employment position.
Example <g:job_function>Product Manager</g:job_function>
+ * + * Attribute of Jobs
+ * + * Content type string
+ * + * @return The functions of an employment position. + */ + public String[] getJobFunctions(); + + /** + * The industry of an employment position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * job_industry
Details The industry of an employment position.
Example <g:job_industry>Government</g:job_industry>
Attribute of Jobs
+ * + * Content type string
+ * + * @param jobIndustries The industry of an employment position. + */ + public void setJobIndustries(String[] jobIndustries); + + /** + * The industry of an employment position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * job_industry
Details The industry of an employment position.
Example <g:job_industry>Government</g:job_industry>
Attribute of Jobs
+ * + * Content type string
+ * + * @return The industry of an employment position. + */ + public String[] getJobIndustries(); + + /** + * Type of employment position. Example: Full-time, part-time, contractor, etc. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
job_type
Details Type of employment position. Example: Full-time, part-time, contractor, + * etc.
Example <g:job_type>contractor</g:job_type>
Attribute of Jobs
+ * + * Content type string
+ * + * @param jobTypes Type of employment position. Example: Full-time, part-time, contractor, etc. + */ + public void setJobTypes(String[] jobTypes); + + /** + * Type of employment position. Example: Full-time, part-time, contractor, etc. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
job_type
Details Type of employment position. Example: Full-time, part-time, contractor, + * etc.
Example <g:job_type>contractor</g:job_type>
Attribute of Jobs
+ * + * Content type string
+ * + * @return Type of employment position. Example: Full-time, part-time, contractor, etc. + */ + public String[] getJobTypes(); + + /** + * Location of the position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @param location Location of the position. + */ + public void setLocation(String location); + + /** + * Location of the position. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @return Location of the position. + */ + public String getLocation(); + + /** + * Salary for this position. Non-numeric values such as "$" symbols are not acceptable. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
salary
Details Salary for this position. Non-numeric values such as "$" symbols are not + * acceptable.
+ * + * Example <g:salary>55000</g:salary>
+ * + * Attribute of Jobs
Content type + * + * float
+ * + * @param salary Salary for this position. Non-numeric values such as "$" symbols are not + * acceptable. + */ + public void setSalary(Float salary); + + /** + * Salary for this position. Non-numeric values such as "$" symbols are not acceptable. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
salary
Details Salary for this position. Non-numeric values such as "$" symbols are not + * acceptable.
+ * + * Example <g:salary>55000</g:salary>
+ * + * Attribute of Jobs
Content type + * + * float
+ * + * @return Salary for this position. Non-numeric values such as "$" symbols are not acceptable. + */ + public Float getSalary(); + + /** + * The type of salary included. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
salary_type
Details The type of salary included. Accepted values are �starting� or + * �negotiable;� The default is �starting at.�
+ * + * Example <g:salary_type>negotiable</g:salary_type>
Attribute of Jobs
+ * + * Content type + * + * "starting" or "negotiable"
+ * + * @param salaryType The type of salary included. + */ + public void setSalaryType(PriceTypeEnumeration salaryType); + + /** + * The type of salary included. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
salary_type
Details The type of salary included. Accepted values are �starting� or + * �negotiable;� The default is �starting at.�
+ * + * Example <g:salary_type>negotiable</g:salary_type>
Attribute of Jobs
+ * + * Content type + * + * "starting" or "negotiable"
+ * + * @return The type of salary included. + */ + public PriceTypeEnumeration getSalaryType(); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @param value Currency of the price amount for an item. + */ + public void setCurrency(CurrencyEnumeration value); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @return Currency of the price amount for an item. + */ + public CurrencyEnumeration getCurrency(); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Person.java b/rome-modules/src/main/java/com/rometools/modules/base/Person.java new file mode 100644 index 0000000..8d9038d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Person.java @@ -0,0 +1,865 @@ +/* + * Person.java + * + * Created on November 16, 2005, 1:26 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import com.rometools.modules.base.types.GenderEnumeration; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for Person (personal + * ad, resume, profile) entry types. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public interface Person extends GlobalInterface { + /** + * Age of the individual. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
age + *
DetailsMinimum age requirement for the event or the age of the individual in a + * People profiles bulk upload entry.
ExampleAcceptable:
+ * < g:age>18</g:age>
+ * Not acceptable:
+ * + * < g:age>18 and over</g:age>
Attribute ofEvents, People profiles
Content typeinteger
+ * + * @param age Age of the individual. + */ + public void setAge(Integer age); + + /** + * Age of the individual. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
age + *
DetailsMinimum age requirement for the event or the age of the individual in a + * People profiles bulk upload entry.
ExampleAcceptable:
+ * < g:age>18</g:age>
+ * Not acceptable:
+ * + * < g:age>18 and over</g:age>
Attribute ofEvents, People profiles
Content typeinteger
+ * + * @return Age of the individual. + */ + public Integer getAge(); + + /** + * Education of the individual. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
education
Details Level of education required for an employment position.
Example<g:education>PhD</g:education>
Attribute of Jobs
Content type string
+ * + * @param education Education of the individual. + */ + public void setEducation(String education); + + /** + * Education of the individual. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
education
Details Level of education required for an employment position.
Example<g:education>PhD</g:education>
Attribute of Jobs
Content type string
+ * + * @return Education of the individual. + */ + public String getEducation(); + + /** + * Individuals employer. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
employer
Details Company providing employment.
Example<g:employer>Google, Inc</g:employer>
Attribute of Jobs
Content type string
+ * + * @param employer Individuals employer. + */ + public void setEmployer(String employer); + + /** + * Individuals employer. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
employer
Details Company providing employment.
Example<g:employer>Google, Inc</g:employer>
Attribute of Jobs
Content type string
+ * + * @return Individuals employer. + */ + public String getEmployer(); + + /** + * Ethnicity of the individual in the People profiles bulk upload entry. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
ethnicity
Details Ethnicity of the individual in the People profiles bulk upload + * entry.
Example<g:ethnicity>Latino</g:ethnicity>
Attribute of People profiles
Content type string
+ * + * @param ethnicities Ethnicity of the individual in the People profiles bulk upload entry. + */ + public void setEthnicities(String[] ethnicities); + + /** + * Ethnicity of the individual in the People profiles bulk upload entry. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
ethnicity
Details Ethnicity of the individual in the People profiles bulk upload + * entry.
Example<g:ethnicity>Latino</g:ethnicity>
Attribute of People profiles
Content type string
+ * + * @return Ethnicity of the individual in the People profiles bulk upload entry. + */ + public String[] getEthnicities(); + + /** + * Gender of an individual in a People profiles bulk upload. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
gender
Details Gender of an individual in a People profiles bulk upload item. + * Acceptable values are �Male�, �M�, �Female�, or �F�.
Example <gender>Female</gender>
Attribute of People profiles
Content type genderEnumeration
+ * + * @param gender Gender of an individual in a People profiles bulk upload. + */ + public void setGender(GenderEnumeration gender); + + /** + * Gender of an individual in a People profiles bulk upload. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
gender
Details Gender of an individual in a People profiles bulk upload item. + * Acceptable values are �Male�, �M�, �Female�, or �F�.
Example <gender>Female</gender>
Attribute of People profiles
Content type genderEnumeration
+ * + * @return Gender of an individual in a People profiles bulk upload. + */ + public GenderEnumeration getGender(); + + /** + * Interest of a person being profiled. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
interested_in
Details Interest of a person being profiled.
Example <g:interested_in>Long walks on the + * beach.</g:interested_in>
Attribute ofPeople profiles
Content type string
+ * + * @param interestedIn Interest of a person being profiled. + */ + public void setInterestedIn(String[] interestedIn); + + /** + * Interest of a person being profiled. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
interested_in
Details Interest of a person being profiled.
Example <g:interested_in>Long walks on the + * beach.</g:interested_in>
Attribute ofPeople profiles
Content type string
+ * + * @return Interest of a person being profiled. + */ + public String[] getInterestedIn(); + + /** + * Location of a person. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @param location Location of a person. + */ + public void setLocation(String location); + + /** + * Location of a person. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @return Location of a person. + */ + public String getLocation(); + + /** + * Marital status of an individual. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
marital_status
+ * + * Details Marital status of an individual in a People profiles bulk upload entry. + * For example -single, divorced, separated, widowed, married, and �in relationship.�
Example <g:marital_status>single</g:marital_status>
+ * + *
Attribute of People profiles
+ * + * Content type + * + * string
+ * + * @param maritalStatus Marital status of an individual. + */ + public void setMaritalStatus(String maritalStatus); + + /** + * Marital status of an individual. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
marital_status
+ * + * Details Marital status of an individual in a People profiles bulk upload entry. + * For example -single, divorced, separated, widowed, married, and �in relationship.�
Example <g:marital_status>single</g:marital_status>
+ * + *
Attribute of People profiles
+ * + * Content type + * + * string
+ * + * @return Marital status of an individual. + */ + public String getMaritalStatus(); + + /** + * Occupation of an individual. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
occupation
+ * + * Details Industry the individual in a People profiles bulk upload is employed + * in.
Example <g:occupation>Sales</g:occupation>
Attribute of + * + * People profiles
+ * + * Content type string
+ * + * @param occupation Occupation of an individual. + */ + public void setOccupation(String occupation); + + /** + * Occupation of an individual. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
occupation
+ * + * Details Industry the individual in a People profiles bulk upload is employed + * in.
Example <g:occupation>Sales</g:occupation>
Attribute of + * + * People profiles
+ * + * Content type string
+ * + * @return Occupation of an individual. + */ + public String getOccupation(); + + /** + * Individual's sexual orientation. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
sexual_orientation
+ * + * Details Sexual orientation of an individual in a People profiles information + * type..
Example <g:sexual_orientation>straight</g:sexual_orientation> + *
Attribute of + * + * Personal
Content type string
+ * + * @param sexualOrientation Individual's sexual orientation. + */ + public void setSexualOrientation(String sexualOrientation); + + /** + * Individual's sexual orientation. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
sexual_orientation
+ * + * Details Sexual orientation of an individual in a People profiles information + * type..
Example <g:sexual_orientation>straight</g:sexual_orientation> + *
Attribute of + * + * Personal
Content type string
+ * + * @return Individual's sexual orientation. + */ + public String getSexualOrientation(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Product.java b/rome-modules/src/main/java/com/rometools/modules/base/Product.java new file mode 100644 index 0000000..0764e6a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Product.java @@ -0,0 +1,2742 @@ +/* + * Product.java + * + * Created on November 16, 2005, 1:39 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.PaymentTypeEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; +import com.rometools.modules.base.types.ShippingType; +import com.rometools.modules.base.types.Size; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for Products. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface Product extends GlobalInterface { + /** + * Actor featured in the video. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
actor
DetailsActor featured in the video.
Example<g:actor>Charlie Chaplin</g:actor>
Attribute ofProducts
Content typestring
+ * + * @param actors Actor featured in the video. + */ + public void setActors(String[] actors); + + /** + * Actor featured in the video. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
actor
DetailsActor featured in the video.
Example<g:actor>Charlie Chaplin</g:actor>
Attribute ofProducts
Content typestring
+ * + * @return Actor featured in the video. + */ + public String[] getActors(); + + /** + * The type of apparel being offered.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
apparel_type
Details The type of apparel being offered. Skirt, pants, sleepwear, etc.
Example<g:apparel_type>sweater</g:apparel_type>
Attribute ofProducts
Content typestring
+ * + * @param apparelType The type of apparel being offered. + */ + public void setApparelType(String apparelType); + + /** + * The type of apparel being offered.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
apparel_type
Details The type of apparel being offered. Skirt, pants, sleepwear, etc.
Example<g:apparel_type>sweater</g:apparel_type>
Attribute ofProducts
Content typestring
+ * + * @return The type of apparel being offered. + */ + public String getApparelType(); + + /** + * Artist that created the work. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
artist
Details Artist that created the work.
Example <g:artist>Vincent van Gogh</g:artist>
Attribute of Products
+ * + * Content type string
+ * + * @param artists Artist that created the work. + */ + public void setArtists(String[] artists); + + /** + * Artist that created the work. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
artist
Details Artist that created the work.
Example <g:artist>Vincent van Gogh</g:artist>
Attribute of Products
+ * + * Content type string
+ * + * @return Artist that created the work. + */ + public String[] getArtists(); + + /** + * Author of the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
author
Details Author of the item.
Example <g:author>John Steinbeck</g:author>
Attribute of Reference Items, News and Articles
Content type string
+ * + * @param authors Author of the item. + */ + public void setAuthors(String[] authors); + + /** + * Author of the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
author
Details Author of the item.
Example <g:author>John Steinbeck</g:author>
Attribute of Reference Items, News and Articles
Content type string
+ * + * @return Author of the item. + */ + public String[] getAuthors(); + + /** + * The brand name of an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
brand
Details The brand name of an item.
Example <g:brand>Acme</g:brand>
Attribute of Products
Content type string
+ * + * @param brand The brand name of an item. + */ + public void setBrand(String brand); + + /** + * The brand name of an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
brand
Details The brand name of an item.
Example <g:brand>Acme</g:brand>
Attribute of Products
Content type string
+ * + * @return The brand name of an item. + */ + public String getBrand(); + + /** + * Color of an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
color
Details Color of an item.
Example <g:color>Black</g:color>
+ * + * Attribute of Products, Vehicles
Content type string
+ * + * @param color Color of an item. + */ + public void setColors(String[] color); + + /** + * Color of an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
color
Details Color of an item.
Example <g:color>Black</g:color>
+ * + * Attribute of Products, Vehicles
Content type string
+ * + * @return Color of an item. + */ + public String[] getColors(); + + /** + * Condition of the item. For example: new, used, or refurbished. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
condition
DetailsCondition of the item. For example: new, used, or refurbished.
Example + * <g:condition>refurbished</g:condition>
Attribute ofProducts, Vehicles
Content typestring
+ * + * @param condition Condition of the item. For example: new, used, or refurbished. + */ + public void setCondition(String condition); + + /** + * Condition of the item. For example: new, used, or refurbished. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
condition
DetailsCondition of the item. For example: new, used, or refurbished.
Example + * <g:condition>refurbished</g:condition>
Attribute ofProducts, Vehicles
Content typestring
+ * + * @return Condition of the item. For example: new, used, or refurbished. + */ + public String getCondition(); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @param value Currency of the price amount for an item. + */ + public void setCurrency(CurrencyEnumeration value); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @return Currency of the price amount for an item. + */ + public CurrencyEnumeration getCurrency(); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @param deliveryNotes Additional instructions to explain the item’s delivery process. + */ + public void setDeliveryNotes(String deliveryNotes); + + /** + * Additional instructions to explain the item;s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item�s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @return Additional instructions to explain the item�s delivery process. + */ + public String getDeliveryNotes(); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @param deliveryRadius The maximum distance you will deliver an item in any direction. + */ + public void setDeliveryRadius(FloatUnit deliveryRadius); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @return The maximum distance you will deliver an item in any direction. + */ + public FloatUnit getDeliveryRadius(); + + /** + * Format of the content. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
format
Details Format of the content.
Example<g:format>DVD</g:format>
+ * + * <g:format>CD</g:format>
Attribute of Products
Content type string
+ * + * @param format Format of the content. + */ + public void setFormat(String[] format); + + /** + * Format of the content. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
format
Details Format of the content.
Example<g:format>DVD</g:format>
+ * + * <g:format>CD</g:format>
Attribute of Products
Content type string
+ * + * @return Format of the content. + */ + public String[] getFormat(); + + /** + * A unique 10 or 13 digit number assigned to every printed book. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
isbn
DetailsA unique 10 or 13 digit number assigned to every printed book.
Example<g:isbn>0451524233</g:isbn>
Attribute ofProducts
Content typestring
+ * + * @param isbn A unique 10 or 13 digit number assigned to every printed book. + */ + public void setIsbn(String isbn); + + /** + * A unique 10 or 13 digit number assigned to every printed book. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
isbn
DetailsA unique 10 or 13 digit number assigned to every printed book.
Example<g:isbn>0451524233</g:isbn>
Attribute ofProducts
Content typestring
+ * + * @return A unique 10 or 13 digit number assigned to every printed book. + */ + public String getIsbn(); + + /** + * Location of a property. Should include street, city, state, postal code, and country, in that + * order. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @param location Location of a property. Should include street, city, state, postal code, and + * country, in that order. + */ + public void setLocation(String location); + + /** + * Location of a property. Should include street, city, state, postal code, and country, in that + * order. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @return Location of a property. Should include street, city, state, postal code, and country, + * in that order. + */ + public String getLocation(); + + /** + * Company that manufactures the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * manufacturer
+ * Details + * + * Company that manufactures the item.
+ * Example + * <g:manufacturer>Acme, Inc</g:manufacturer>
+ * Attribute of + * Products
+ * + * Content type + * string
+ * + * @param manufacturer Company that manufactures the item. + */ + public void setManufacturer(String manufacturer); + + /** + * Company that manufactures the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * manufacturer
+ * Details + * + * Company that manufactures the item.
+ * Example + * <g:manufacturer>Acme, Inc</g:manufacturer>
+ * Attribute of + * Products
+ * + * Content type + * string
+ * + * @return Company that manufactures the item. + */ + public String getManufacturer(); + + /** + * Unique product ID code assigned by its manufacturer. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
manufacturer_id
Details + * + * Unique product ID code assigned by its manufacturer.
Example <g:manufacturer_id>030779A</g:manufacturer_id>
Attribute of Products
Content type string
+ * + * @param manufacturerId Unique product ID code assigned by its manufacturer. + */ + public void setManufacturerId(String manufacturerId); + + /** + * Unique product ID code assigned by its manufacturer. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
manufacturer_id
Details + * + * Unique product ID code assigned by its manufacturer.
Example <g:manufacturer_id>030779A</g:manufacturer_id>
Attribute of Products
Content type string
+ * + * @return Unique product ID code assigned by its manufacturer. + */ + public String getManufacturerId(); + + /** + * Resolution of a digital imaging device. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * megapixels
Details Resolution of a digital imaging device.
Example <g:megapixels>5.2 MP</g:megapixels>
Attribute of Products
+ * + * Content type floatUnit
+ * + * @param megapixels Resolution of a digital imaging device. + */ + public void setMegapixels(FloatUnit megapixels); + + /** + * Resolution of a digital imaging device. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * megapixels
Details Resolution of a digital imaging device.
Example <g:megapixels>5.2 MP</g:megapixels>
Attribute of Products
+ * + * Content type floatUnit
+ * + * @return Resolution of a digital imaging device. + */ + public FloatUnit getMegapixels(); + + /** + * The amount of memory included in an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
memory
Details The amount of memory included in an item.
Example <g:memory>128 MB</g:memory>
+ * + * Attribute of Products
+ * + * Content type floatUnit
+ * + * @param memory The amount of memory included in an item. + */ + public void setMemory(FloatUnit memory); + + /** + * The amount of memory included in an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
memory
Details The amount of memory included in an item.
Example <g:memory>128 MB</g:memory>
+ * + * Attribute of Products
+ * + * Content type floatUnit
+ * + * @return The amount of memory included in an item. + */ + public FloatUnit getMemory(); + + /** + * Model number of the product. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
model_number
Details + * + * Model number of the product.
Example <g:model_number>1924863</g:model_number>
Attribute of Products
Content type string
+ * + * @param modelNumber Model number of the product. + */ + public void setModelNumber(String modelNumber); + + /** + * Model number of the product. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
model_number
Details + * + * Model number of the product.
Example <g:model_number>1924863</g:model_number>
Attribute of Products
Content type string
+ * + * @return Model number of the product. + */ + public String getModelNumber(); + + /** + * Acceptable payment methods for item purchases. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * “Cash,” “Check,” “Traveler’s Check,” “Visa,” “MasterCard,” + * + * “American Express,” “Discover,” or “Wire transfer.” If you accept more than one method, + * include multiple instances of the <payment_accepted> attribute for each acceptable + * method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type + * + * paymentMethodEnumeration
+ * + * @param paymentAccepted Acceptable payment methods for item purchases. + */ + public void setPaymentAccepted(PaymentTypeEnumeration[] paymentAccepted); + + /** + * Acceptable payment methods for item purchases. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * “Cash,” “Check,” “Traveler’s Check,” “Visa,” “MasterCard,” + * + * “American Express,” “Discover,” or “Wire transfer.” If you accept more than one method, + * include multiple instances of the <payment_accepted> attribute for each acceptable + * method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type + * + * paymentMethodEnumeration
+ * + * @return Acceptable payment methods for item purchases. + */ + public PaymentTypeEnumeration[] getPaymentAccepted(); + + /** + * Additional instructions to explain a payment policy. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
+ * + * Content type string
+ * + * @param paymentNotes Additional instructions to explain a payment policy. + */ + public void setPaymentNotes(String paymentNotes); + + /** + * Additional instructions to explain a payment policy. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
+ * + * Content type string
+ * + * @return Additional instructions to explain a payment policy. + */ + public String getPaymentNotes(); + + /** + * Whether or not an item is available for pick up. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
pickup
Details Information about whether or not an item is available for pick up. + * Acceptable values are "True and "False".
Example + * + * Acceptable:
+ * <g:pickup>True</g:pickup>
+ * Not acceptable:
+ * <g:pickup>Not on Tuesdays</g:pickup>
Attribute of Products
+ * + * Content type boolean
+ * + * @param pickup Whether or not an item is available for pick up. + */ + public void setPickup(Boolean pickup); + + /** + * Whether or not an item is available for pick up. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
pickup
Details Information about whether or not an item is available for pick up. + * Acceptable values are "True and "False".
Example + * + * Acceptable:
+ * <g:pickup>True</g:pickup>
+ * Not acceptable:
+ * <g:pickup>Not on Tuesdays</g:pickup>
Attribute of Products
+ * + * Content type boolean
+ * + * @return Whether or not an item is available for pick up. + */ + public Boolean getPickup(); + + /** + * Price of the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * <g:price>5,95</g:price>
+ * <g:price>5.00 – 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @param price Price of the item. + */ + public void setPrice(FloatUnit price); + + /** + * Price of the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * <g:price>5,95</g:price>
+ * <g:price>5.00 – 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @return Price of the item. + */ + public FloatUnit getPrice(); + + /** + * The type of pricing for the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are “negotiable,” or + * “starting.” The default is “starting”
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @param priceType The type of pricing for the item. + */ + public void setPriceType(PriceTypeEnumeration priceType); + + /** + * The type of pricing for the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are “negotiable,” or + * “starting.” The default is “starting”
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @return The type of pricing for the item. + */ + public PriceTypeEnumeration getPriceType(); + + /** + * The processor speed for the product. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * processor_speed
Details The processor speed for the product.
Example <g:processor_speed>2</g:processor_speed>
Attribute of Products
Content type floatUnit
+ * + * @param processorSpeed The processor speed for the product. + */ + public void setProcessorSpeed(FloatUnit processorSpeed); + + /** + * The processor speed for the product. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * processor_speed
Details The processor speed for the product.
Example <g:processor_speed>2</g:processor_speed>
Attribute of Products
Content type floatUnit
+ * + * @return The processor speed for the product. + */ + public FloatUnit getProcessorSpeed(); + + /** + * The type of product being offered. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
product_type
Details + * + * The type of product being offered. Toys, books, flowers, etc.
Example <g:product_type>electronics</g:product_type>
Attribute of Products
Content type string
+ * + * @param productTypes The type of product being offered. + */ + public void setProductTypes(String[] productTypes); + + /** + * The type of product being offered. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
product_type
Details + * + * The type of product being offered. Toys, books, flowers, etc.
Example <g:product_type>electronics</g:product_type>
Attribute of Products
Content type string
+ * + * @return The type of product being offered. + */ + public String[] getProductTypes(); + + /** + * Quantity available. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
quantity
Details The number of units available for purchase. This attribute can be left + * blank if you have a large quantity or if it is not applicable.
Example Acceptable:
+ * <g:quantity>18</g:quantity>
+ * + * <g:quantity>0</g:quantity>
+ * + * Not acceptable:
+ * <g:quantity>out of stock</g:quantity>
+ * + * Attribute of Events, Products, Services, Travel, Vehicles
Content type + * + * integer
+ * + * @param quantity Quantity available. + */ + public void setQuantity(Integer quantity); + + /** + * Quantity available. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
quantity
Details The number of units available for purchase. This attribute can be left + * blank if you have a large quantity or if it is not applicable.
Example Acceptable:
+ * <g:quantity>18</g:quantity>
+ * + * <g:quantity>0</g:quantity>
+ * + * Not acceptable:
+ * <g:quantity>out of stock</g:quantity>
+ * + * Attribute of Events, Products, Services, Travel, Vehicles
Content type + * + * integer
+ * + * @return Quantity available. + */ + public Integer getQuantity(); + + /** + * Shipping options available for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * shipping
Details Shipping options available for an item. Up to 10 shipping options can be + * included for each item. Three sub-attributes are included in the shipping attribute: + *
    + * + *
  • service = The type of service used to ship an item. Acceptable values are 'FedEx', 'UPS', + * 'DHL', 'Mail', and 'Other'
  • + *
  • country = The country an item will ship to. Only acceptable values are ISO 3166 + * country codes.
  • + *
  • price = the price of shipping.
  • + *
+ *
+ * + * Example <g:shipping>
+ * <g:country>US</g:country>
+ * + * <g:service>UPS</g:shipping>
+ * + * <g:price>35.95</g:price>
+ * </g:shipping>
Attribute of Products
+ * + * Content type shippingType
+ * + * @param shipping Shipping options available for an item. + */ + public void setShipping(ShippingType[] shipping); + + /** + * Shipping options available for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * shipping
Details Shipping options available for an item. Up to 10 shipping options can be + * included for each item. Three sub-attributes are included in the shipping attribute: + *
    + * + *
  • service = The type of service used to ship an item. Acceptable values are 'FedEx', 'UPS', + * 'DHL', 'Mail', and 'Other'
  • + *
  • country = The country an item will ship to. Only acceptable values are ISO 3166 + * country codes.
  • + *
  • price = the price of shipping.
  • + *
+ *
+ * + * Example <g:shipping>
+ * <g:country>US</g:country>
+ * + * <g:service>UPS</g:shipping>
+ * + * <g:price>35.95</g:price>
+ * </g:shipping>
Attribute of Products
+ * + * Content type shippingType
+ * + * @return Shipping options available for an item. + */ + public ShippingType[] getShipping(); + + /** + * Dimensions of the item, expressed in either two or three dimensions. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
size
Details Dimensions of the item, expressed in either two or three + * dimensions.
Example <g:size>12x10x4</g:size>
+ * + * Attribute of Products
Content type string
+ * + * @param size Dimensions of the item, expressed in either two or three dimensions. + */ + public void setSize(Size size); + + /** + * Dimensions of the item, expressed in either two or three dimensions. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
size
Details Dimensions of the item, expressed in either two or three + * dimensions.
Example <g:size>12x10x4</g:size>
+ * + * Attribute of Products
Content type string
+ * + * @return Dimensions of the item, expressed in either two or three dimensions. + */ + public Size getSize(); + + /** + * Tax rate associated with the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @param taxPercent Tax rate associated with the event. + */ + public void setTaxPercent(Float taxPercent); + + /** + * Tax rate associated with the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @return Tax rate associated with the event. + */ + public Float getTaxPercent(); + + /** + * Region where tax applies. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @param taxRegion Region where tax applies. + */ + public void setTaxRegion(String taxRegion); + + /** + * Region where tax applies. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @return Region where tax applies. + */ + public String getTaxRegion(); + + /** + * Product UPC code (Isn't that redundant?). + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * upc
Details Product UPC code.
Example <g:upc>834721479305</g:upc>
Attribute of Products
+ * + * Content type string
+ * + * @param upc Product UPC code (Isn't that redundant?). + */ + public void setUpc(String upc); + + /** + * Product UPC code (Isn't that redundant?). + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * upc
Details Product UPC code.
Example <g:upc>834721479305</g:upc>
Attribute of Products
+ * + * Content type string
+ * + * @return Product UPC code (Isn't that redundant?). + */ + public String getUpc(); + + /** + * Weight of the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
weight
Details Weight of the item.
Example <g:weight>5</g:weight>
Attribute of Products
+ * + * Content type floatUnit
+ * + * @param weight Weight of the item. + */ + public void setWeight(FloatUnit weight); + + /** + * Weight of the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
weight
Details Weight of the item.
Example <g:weight>5</g:weight>
Attribute of Products
+ * + * Content type floatUnit
+ * + * @return Weight of the item. + */ + public FloatUnit getWeight(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Review.java b/rome-modules/src/main/java/com/rometools/modules/base/Review.java new file mode 100644 index 0000000..dfdd8cf --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Review.java @@ -0,0 +1,798 @@ +/* + * Review.java + * + * Created on November 16, 2005, 1:58 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import java.net.URL; +import java.util.Date; + +import com.rometools.modules.base.types.FloatUnit; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for critical reviews of + * other things. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface Review extends GlobalInterface { + /** + * Author of the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
author
Details Author of the item.
Example <g:author>John Steinbeck</g:author>
Attribute of Reference Items, News and Articles
Content type string
+ * + * @param authors Author of the item. + */ + public void setAuthors(String[] authors); + + /** + * Author of the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
author
Details Author of the item.
Example <g:author>John Steinbeck</g:author>
Attribute of Reference Items, News and Articles
Content type string
+ * + * @return Author of the item. + */ + public String[] getAuthors(); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @param deliveryNotes Additional instructions to explain the item’s delivery process. + */ + public void setDeliveryNotes(String deliveryNotes); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @return Additional instructions to explain the item’s delivery process. + */ + public String getDeliveryNotes(); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @param deliveryRadius The maximum distance you will deliver an item in any direction. + */ + public void setDeliveryRadius(FloatUnit deliveryRadius); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @return The maximum distance you will deliver an item in any direction. + */ + public FloatUnit getDeliveryRadius(); + + /** + * The name of an item being reviewed. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
name_of_item_being_reviewed
Details + * + * The name of an item being reviewed.
Example <g:name_of_item_being__reviewed>Fleur de lys + * Restaurant</g:name_of_item_being_reviewed>
Attribute of Reviews
Content type string
+ * + * @param nameOfItemBeingReviewed The name of an item being reviewed. + */ + public void setNameOfItemBeingReviewed(String nameOfItemBeingReviewed); + + /** + * The name of an item being reviewed. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
name_of_item_being_reviewed
Details + * + * The name of an item being reviewed.
Example <g:name_of_item_being__reviewed>Fleur de lys + * Restaurant</g:name_of_item_being_reviewed>
Attribute of Reviews
Content type string
+ * + * @return The name of an item being reviewed. + */ + public String getNameOfItemBeingReviewed(); + + /** + * Date the item was published. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
publish_date
Details Date the item was published in ISO 8601 + * format: YYYY-MM-DD
Example <g:publish_date>2005-12-20</g:publish_date>
Attribute of + * + * Reference Items
+ * + * Content type date
+ * + * @param publishDate Date the item was published. + */ + public void setPublishDate(Date publishDate); + + /** + * Date the item was published. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
publish_date
Details Date the item was published in ISO 8601 + * format: YYYY-MM-DD
Example <g:publish_date>2005-12-20</g:publish_date>
Attribute of + * + * Reference Items
+ * + * Content type date
+ * + * @return Date the item was published. + */ + public Date getPublishDate(); + + /** + * Rating of the product or service on a scale of 1-5, with 5 as the best. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
rating
Details Rating of the product or service on a scale of 1-5, with 5 as the best. + * Numeric values only.
Example Acceptable:
+ * <g:rating>4</g:rating>
+ * + * Not acceptable:
+ * + * <g:rating>good</g:rating>
Attribute of Reviews
Content type + * + * string
+ * + * @param rating Rating of the product or service on a scale of 1-5, with 5 as the best. + */ + public void setRating(Float rating); + + /** + * Rating of the product or service on a scale of 1-5, with 5 as the best. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
rating
Details Rating of the product or service on a scale of 1-5, with 5 as the best. + * Numeric values only.
Example Acceptable:
+ * <g:rating>4</g:rating>
+ * + * Not acceptable:
+ * + * <g:rating>good</g:rating>
Attribute of Reviews
Content type + * + * string
+ * + * @return Rating of the product or service on a scale of 1-5, with 5 as the best. + */ + public Float getRating(); + + /** + * The category of the item being reviewed. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
review_type
+ * + * Details The category of the item being reviewed.
Example <g:review_type>toy</g:review_type>
+ * + * <g:review_type>music</g:review_type>
+ * <g:review_type>restaraunt</g:review_type>
Attribute of Reviews
Content type string
+ * + * @param reviewType The category of the item being reviewed. + */ + public void setReviewType(String reviewType); + + /** + * The category of the item being reviewed. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
review_type
+ * + * Details The category of the item being reviewed.
Example <g:review_type>toy</g:review_type>
+ * + * <g:review_type>music</g:review_type>
+ * <g:review_type>restaraunt</g:review_type>
Attribute of Reviews
Content type string
+ * + * @return The category of the item being reviewed. + */ + public String getReviewType(); + + /** + * The type of rating being provided: editorial (a review written by a member of your staff) or + * “user” ( a review written by a user of your site). + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
reviewer_type
Details The type of rating being provided: editorial (a review written by a + * member of your staff) or “user” ( a review written by a user of your site)
+ * + * Example <g:reviewer_type>editorial</g:reviewer_type>
Attribute of Reviews
Content type string
+ * + * @param reviewerType The type of rating being provided: editorial (a review written by a + * member of your staff) or “user” ( a review written by a user of your site). + */ + public void setReviewerType(String reviewerType); + + /** + * The type of rating being provided: editorial (a review written by a member of your staff) or + * “user” ( a review written by a user of your site). + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
reviewer_type
Details The type of rating being provided: editorial (a review written by a + * member of your staff) or “user” ( a review written by a user of your site)
+ * + * Example <g:reviewer_type>editorial</g:reviewer_type>
Attribute of Reviews
Content type string
+ * + * @return The type of rating being provided: editorial (a review written by a member of your + * staff) or “user” ( a review written by a user of your site). + */ + public String getReviewerType(); + + /** + * The web page of an item being reviewed. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
url_of_item_being_reviewed
+ * + * Details The web page of an item being reviewed.
Example <g:url_of_item_being_reviewed>http://www.fleurdelyssf.com/</g: + * url_of_item_being_reviewed>
Attribute of + * + * Reviews
+ * + * Content type uri
+ * + * @param urlOfItemBeingReviewed The web page of an item being reviewed. + */ + public void setUrlOfItemBeingReviewed(URL urlOfItemBeingReviewed); + + /** + * The web page of an item being reviewed. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
url_of_item_being_reviewed
+ * + * Details The web page of an item being reviewed.
Example <g:url_of_item_being_reviewed>http://www.fleurdelyssf.com/</g: + * url_of_item_being_reviewed>
Attribute of + * + * Reviews
+ * + * Content type uri
+ * + * @return The web page of an item being reviewed. + */ + public URL getUrlOfItemBeingReviewed(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/ScholarlyArticle.java b/rome-modules/src/main/java/com/rometools/modules/base/ScholarlyArticle.java new file mode 100644 index 0000000..b0dc686 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/ScholarlyArticle.java @@ -0,0 +1,463 @@ +/* + * ScholarlyArticle.java + * + * Created on November 16, 2005, 1:55 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import java.util.Date; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for Scholarly + * publication, research studies and reference materials. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public interface ScholarlyArticle extends GlobalInterface { + /** + * Array of Author Names. Limit 10. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
author
Details Author of the item.
Example <g:author>John Steinbeck</g:author>
Attribute of Reference Items, News and Articles
Content type string
+ * + * @param authors Array of Author Names. Limit 10. + */ + public void setAuthors(String[] authors); + + /** + * Array of Author Names. Limit 10. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
author
Details Author of the item.
Example <g:author>John Steinbeck</g:author>
Attribute of Reference Items, News and Articles
Content type string
+ * + * @return Array of author names. + */ + public String[] getAuthors(); + + /** + * Number of pages in the article. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
pages
Details + * + * The number of pages in the publication.
Example <g:pages>18</g:pages>
Attribute of Reference Items, News and Articles
+ * + * Content type integer
+ * + * @param pages Number of pages in the article + */ + public void setPages(Integer pages); + + /** + * Number of pages in the article. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
pages
Details + * + * The number of pages in the publication.
Example <g:pages>18</g:pages>
Attribute of Reference Items, News and Articles
+ * + * Content type integer
+ * + * @return Number of pages in the article + */ + public Integer getPages(); + + /** + * Name of the publication. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
publication_name
Details + * + * Name of the publication.
Example <g:publication_name> Journal of Appropriate + * Technology</g:publication_name>
Attribute of Research studies and publications
+ * + * Content type string
+ * + * @param publicationName Name of the publication. + */ + public void setPublicationName(String publicationName); + + /** + * Name of the publication. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
publication_name
Details + * + * Name of the publication.
Example <g:publication_name> Journal of Appropriate + * Technology</g:publication_name>
Attribute of Research studies and publications
+ * + * Content type string
+ * + * @return Name of the publication. + */ + public String getPublicationName(); + + /** + * Volume of the publication. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
publication_volume
Details + * + * Volume of the publication.
Example<g:publication_volume>VI</g:publication_volume>
Attribute of Reference Items
Content type string
+ * + * @param publicationVolume Volume of the publication. + */ + public void setPublicationVolume(String publicationVolume); + + /** + * Volume of the publication. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
publication_volume
Details + * + * Volume of the publication.
Example<g:publication_volume>VI</g:publication_volume>
Attribute of Reference Items
Content type string
+ * + * @return Volume of the publication. + */ + public String getPublicationVolume(); + + /** + * Date article was published. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
publish_date
+ * + * Details Date the item was published in ISO 8601 + * format: YYYY-MM-DD
+ * + * Example <g:publish_date>2005-12-20</g:publish_date>
Attribute of Reference Items
+ * + * Content type + * + * date
+ * + * @param publishDate Date article was published + */ + public void setPublishDate(Date publishDate); + + /** + * Date article was published. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
publish_date
+ * + * Details Date the item was published in ISO 8601 + * format: YYYY-MM-DD
+ * + * Example <g:publish_date>2005-12-20</g:publish_date>
Attribute of Reference Items
+ * + * Content type + * + * date
+ * + * @return Date article was published + */ + public Date getPublishDate(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Service.java b/rome-modules/src/main/java/com/rometools/modules/base/Service.java new file mode 100644 index 0000000..cd5f142 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Service.java @@ -0,0 +1,1232 @@ +/* + * Service.java + * + * Created on November 16, 2005, 2:14 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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. + * ee the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.base; + +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.PaymentTypeEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; +import com.rometools.modules.base.types.ShippingType; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for service offerings. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface Service extends GlobalInterface { + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @param value Currency of the price amount for an item. + */ + public void setCurrency(CurrencyEnumeration value); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @return Currency of the price amount for an item. + */ + public CurrencyEnumeration getCurrency(); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @param deliveryNotes Additional instructions to explain the item’s delivery process. + */ + public void setDeliveryNotes(String deliveryNotes); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @return Additional instructions to explain the item’s delivery process. + */ + public String getDeliveryNotes(); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @param deliveryRadius The maximum distance you will deliver an item in any direction. + */ + public void setDeliveryRadius(FloatUnit deliveryRadius); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @return The maximum distance you will deliver an item in any direction. + */ + public FloatUnit getDeliveryRadius(); + + /** + * Location of the where the service is offered. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @param location Location of the where the service is offered. + */ + public void setLocation(String location); + + /** + * Location of the where the service is offered. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @return Location of the where the service is offered. + */ + public String getLocation(); + + /** + * Payment Methods acceptable for the service. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * "Cash," "Check," "Traveler’s Check," "Visa," "MasterCard," + * + * "American Express," "Discover," "Wire transfer" or "Paypal." If you accept more than one + * method, include multiple instances of the <payment_accepted> attribute for each + * acceptable method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * + * <g:payment_accepted>Paypal</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check Paypal</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type paymentMethodEnumeration
+ * + * @param paymentAccepted Payment Methods acceptable for the service. + */ + public void setPaymentAccepted(PaymentTypeEnumeration[] paymentAccepted); + + /** + * Payment Methods acceptable for the service. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * "Cash," "Check," "Traveler’s Check," "Visa," "MasterCard," + * + * "American Express," "Discover," "Wire transfer" or "Paypal." If you accept more than one + * method, include multiple instances of the <payment_accepted> attribute for each + * acceptable method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * + * <g:payment_accepted>Paypal</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check Paypal</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type paymentMethodEnumeration
+ * + * @return Payment Methods acceptable for the service. + */ + public PaymentTypeEnumeration[] getPaymentAccepted(); + + /** + * Additional payment information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
Content type string
+ * + * @param paymentNotes Additional payment information. + */ + public void setPaymentNotes(String paymentNotes); + + /** + * Additional payment information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
Content type string
+ * + * @return Additional payment information. + */ + public String getPaymentNotes(); + + /** + * Price for the service.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * <g:price>5,95</g:price>
+ * <g:price>5.00 � 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @param price Price for the service. + */ + public void setPrice(FloatUnit price); + + /** + * Price for the service.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * <g:price>5,95</g:price>
+ * <g:price>5.00 � 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @return Price for the service. + */ + public FloatUnit getPrice(); + + /** + * Price type information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are �negotiable,� or + * �starting.� The default is �starting�
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @param priceType Price type information. + */ + public void setPriceType(PriceTypeEnumeration priceType); + + /** + * Price type information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are �negotiable,� or + * �starting.� The default is �starting�
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @return Price type information. + */ + public PriceTypeEnumeration getPriceType(); + + /** + * Quantity available. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
quantity
Details The number of units available for purchase. This attribute can be left + * blank if you have a large quantity or if it is not applicable.
Example Acceptable:
+ * <g:quantity>18</g:quantity>
+ * + * <g:quantity>0</g:quantity>
+ * + * Not acceptable:
+ * <g:quantity>out of stock</g:quantity>
+ * + * Attribute of Events, Products, Services, Travel, Vehicles
Content type + * + * integer
+ * + * @param quantity Quantity available. + */ + public void setQuantity(Integer quantity); + + /** + * Quantity available. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
quantity
Details The number of units available for purchase. This attribute can be left + * blank if you have a large quantity or if it is not applicable.
Example Acceptable:
+ * <g:quantity>18</g:quantity>
+ * + * <g:quantity>0</g:quantity>
+ * + * Not acceptable:
+ * <g:quantity>out of stock</g:quantity>
+ * + * Attribute of Events, Products, Services, Travel, Vehicles
Content type + * + * integer
+ * + * @return Quantity available. + */ + public Integer getQuantity(); + + /** + * The type of service being offered. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
service_type
Details The type of service being offered. Web hosting, legal, gardening, + * etc.
Example <g:service_type>consulting</g:service_type>
Attribute of Housing
Content type string
+ * + * @param serviceType The type of service being offered. + */ + public void setServiceType(String serviceType); + + /** + * The type of service being offered. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
service_type
Details The type of service being offered. Web hosting, legal, gardening, + * etc.
Example <g:service_type>consulting</g:service_type>
Attribute of Housing
Content type string
+ * + * @return The type of service being offered. + */ + public String getServiceType(); + + /** + * Shipping options available for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * shipping
Details Shipping options available for an item. Up to 10 shipping options can be + * included for each item. Three sub-attributes are included in the shipping attribute: + *
    + * + *
  • service = The type of service used to ship an item. Acceptable values are 'FedEx', 'UPS', + * 'DHL', 'Mail', and 'Other'
  • + *
  • country = The country an item will ship to. Only acceptable values are ISO 3166 + * country codes.
  • + *
  • price = the price of shipping.
  • + *
+ *
+ * + * Example <g:shipping>
+ * <g:country>US</g:country>
+ * + * <g:service>UPS</g:shipping>
+ * + * <g:price>35.95</g:price>
+ * </g:shipping>
Attribute of Products
+ * + * Content type shippingType
+ * + * @param shipping Shipping options available for an item. + */ + public void setShipping(ShippingType[] shipping); + + /** + * Shipping options available for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * shipping
Details Shipping options available for an item. Up to 10 shipping options can be + * included for each item. Three sub-attributes are included in the shipping attribute: + *
    + * + *
  • service = The type of service used to ship an item. Acceptable values are 'FedEx', 'UPS', + * 'DHL', 'Mail', and 'Other'
  • + *
  • country = The country an item will ship to. Only acceptable values are ISO 3166 + * country codes.
  • + *
  • price = the price of shipping.
  • + *
+ *
+ * + * Example <g:shipping>
+ * <g:country>US</g:country>
+ * + * <g:service>UPS</g:shipping>
+ * + * <g:price>35.95</g:price>
+ * </g:shipping>
Attribute of Products
+ * + * Content type shippingType
+ * + * @return Shipping options available for an item. + */ + public ShippingType[] getShipping(); + + /** + * Tax rate associated with the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @param taxPercent Tax rate associated with the event. + */ + public void setTaxPercent(Float taxPercent); + + /** + * Tax rate associated with the service. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @return Tax rate associated with the event. + */ + public Float getTaxPercent(); + + /** + * Region where tax applies. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @param taxRegion Region where tax applies. + */ + public void setTaxRegion(String taxRegion); + + /** + * Region where tax applies. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @return Region where tax applies. + */ + public String getTaxRegion(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Travel.java b/rome-modules/src/main/java/com/rometools/modules/base/Travel.java new file mode 100644 index 0000000..bfd9ae9 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Travel.java @@ -0,0 +1,1352 @@ +/* + * Travel.java + * + * Created on November 16, 2005, 3:15 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.DateTimeRange; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.PaymentTypeEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; +import com.rometools.modules.base.types.ShippingType; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for travel items. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface Travel extends GlobalInterface { + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @param value Currency of the price amount for an item. + */ + public void setCurrency(CurrencyEnumeration value); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @return Currency of the price amount for an item. + */ + public CurrencyEnumeration getCurrency(); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @param deliveryNotes Additional instructions to explain the item’s delivery process. + */ + public void setDeliveryNotes(String deliveryNotes); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @return Additional instructions to explain the item’s delivery process. + */ + public String getDeliveryNotes(); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @param deliveryRadius The maximum distance you will deliver an item in any direction. + */ + public void setDeliveryRadius(FloatUnit deliveryRadius); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @return The maximum distance you will deliver an item in any direction. + */ + public FloatUnit getDeliveryRadius(); + + /** + * Starting city and state/country of the trip. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
from_location
Details Starting city and state/country of the trip.
Example Acceptable:
+ * <g:from_location>San Francisco, + * CA</g:from_location>
+ * + * <g:from_location>Paris, + * France</g:from_location>
+ * + * Not acceptable:
+ * <g:from_location> San Francisco + * International + * Airport</g:from_location>
Attribute of Travel
Content type location
+ * + * @param fromLocation Starting city and state/country of the trip. + */ + public void setFromLocation(String fromLocation); + + /** + * Starting city and state/country of the trip. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
from_location
Details Starting city and state/country of the trip.
Example Acceptable:
+ * <g:from_location>San Francisco, + * CA</g:from_location>
+ * + * <g:from_location>Paris, + * France</g:from_location>
+ * + * Not acceptable:
+ * <g:from_location> San Francisco + * International + * Airport</g:from_location>
Attribute of Travel
Content type location
+ * + * @return Starting city and state/country of the trip. + */ + public String getFromLocation(); + + /** + * Acceptable payment methods for item purchases. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * “Cash,” “Check,” “Traveler’s Check,” “Visa,” “MasterCard,” + * + * “American Express,” “Discover,” or “Wire transfer.” If you accept more than one method, + * include multiple instances of the <payment_accepted> attribute for each acceptable + * method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type + * + * paymentMethodEnumeration
+ * + * @param paymentAccepted Acceptable payment methods for item purchases. + */ + public void setPaymentAccepted(PaymentTypeEnumeration[] paymentAccepted); + + /** + * Acceptable payment methods for item purchases. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * “Cash,” “Check,” “Traveler’s Check,” “Visa,” “MasterCard,” + * + * “American Express,” “Discover,” or “Wire transfer.” If you accept more than one method, + * include multiple instances of the <payment_accepted> attribute for each acceptable + * method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type + * + * paymentMethodEnumeration
+ * + * @return Acceptable payment methods for item purchases. + */ + public PaymentTypeEnumeration[] getPaymentAccepted(); + + /** + * Additional instructions to explain a payment policy. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
+ * + * Content type string
+ * + * @param paymentNotes Additional instructions to explain a payment policy. + */ + public void setPaymentNotes(String paymentNotes); + + /** + * Additional instructions to explain a payment policy. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
+ * + * Content type string
+ * + * @return Additional instructions to explain a payment policy. + */ + public String getPaymentNotes(); + + /** + * Price of the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * <g:price>5,95</g:price>
+ * <g:price>5.00 – 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @return Price of the item. + */ + public FloatUnit getPrice(); + + /** + * The type of pricing for the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are “negotiable,” or + * “starting.” The default is “starting”
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @param priceType The type of pricing for the item. + */ + public void setPriceType(PriceTypeEnumeration priceType); + + /** + * The type of pricing for the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are “negotiable,” or + * “starting.” The default is “starting”
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @return The type of pricing for the item. + */ + public PriceTypeEnumeration getPriceType(); + + /** + * Quantity available. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
quantity
Details The number of units available for purchase. This attribute can be left + * blank if you have a large quantity or if it is not applicable.
Example Acceptable:
+ * <g:quantity>18</g:quantity>
+ * + * <g:quantity>0</g:quantity>
+ * + * Not acceptable:
+ * <g:quantity>out of stock</g:quantity>
+ * + * Attribute of Events, Products, Services, Travel, Vehicles
Content type + * + * integer
+ * + * @param quantity Quantity available. + */ + public void setQuantity(Integer quantity); + + /** + * Quantity available. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
quantity
Details The number of units available for purchase. This attribute can be left + * blank if you have a large quantity or if it is not applicable.
Example Acceptable:
+ * <g:quantity>18</g:quantity>
+ * + * <g:quantity>0</g:quantity>
+ * + * Not acceptable:
+ * <g:quantity>out of stock</g:quantity>
+ * + * Attribute of Events, Products, Services, Travel, Vehicles
Content type + * + * integer
+ * + * @return Quantity available. + */ + public Integer getQuantity(); + + /** + * Tax rate associated with the event. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @param taxPercent Tax rate associated with the event. + */ + public void setTaxPercent(Float taxPercent); + + /** + * Tax rate associated with the service. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @return Tax rate associated with the event. + */ + public Float getTaxPercent(); + + /** + * Region where tax applies. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @param taxRegion Region where tax applies. + */ + public void setTaxRegion(String taxRegion); + + /** + * Region where tax applies. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @return Region where tax applies. + */ + public String getTaxRegion(); + + /** + * Destination city and state/country of the trip. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
to_location
+ * + * Details Destination city and state/country of the trip.
+ * + * Example Acceptable:
+ * <g:to_location>San Francisco, + * CA</g:to_location>
+ * <g:to_location>Paris, + * France</g:to_location>
+ * + * Not acceptable:
+ * <g:to_location>San Francisco + * International + * Airport</g:to_location>
+ * + * Attribute of Travel
Content type locationyTpe
+ * + * @param toLocation Destination city and state/country of the trip. + */ + public void setToLocation(String toLocation); + + /** + * Destination city and state/country of the trip. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
to_location
+ * + * Details Destination city and state/country of the trip.
+ * + * Example Acceptable:
+ * <g:to_location>San Francisco, + * CA</g:to_location>
+ * <g:to_location>Paris, + * France</g:to_location>
+ * + * Not acceptable:
+ * <g:to_location>San Francisco + * International + * Airport</g:to_location>
+ * + * Attribute of Travel
Content type locationyTpe
+ * + * @return Destination city and state/country of the trip. + */ + public String getToLocation(); + + /** + * Departure date and time of the trip. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
travel_date_range
Details Departure date and time of the trip in ISO 8601 + * format: YYYY-MM-DD,hh:mmAM (12 hour clock) or YYYY-MM-DD,hh:mm (24 hour clock). Two + * sub-attributes are included in travel_date_range attribute. + *
    + * + *
  • start = Start date and time of a trip in format YYYY-MM-DDThh:mm:ss
  • + *
  • end = End date and time of a trip in format YYYY-MM-DDThh:mm:ss
  • + *
+ *
Example <g:travel_date_range>
+ * + * <g:start>2005-12-20T06:00:00</g:start>
+ * <g:end>2005-12-29T13:00:00</g:end>
+ * </g:travel_date_range>
+ * + * Attribute of Travel
+ * + * Content type dateTimeRange
+ * + * @param travelDateRange Departure date and time of the trip. + */ + public void setTravelDateRange(DateTimeRange travelDateRange); + + /** + * Departure date and time of the trip. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
travel_date_range
Details Departure date and time of the trip in ISO 8601 + * format: YYYY-MM-DD,hh:mmAM (12 hour clock) or YYYY-MM-DD,hh:mm (24 hour clock). Two + * sub-attributes are included in travel_date_range attribute. + *
    + * + *
  • start = Start date and time of a trip in format YYYY-MM-DDThh:mm:ss
  • + *
  • end = End date and time of a trip in format YYYY-MM-DDThh:mm:ss
  • + *
+ *
Example <g:travel_date_range>
+ * + * <g:start>2005-12-20T06:00:00</g:start>
+ * <g:end>2005-12-29T13:00:00</g:end>
+ * </g:travel_date_range>
+ * + * Attribute of Travel
+ * + * Content type dateTimeRange
+ * + * @return Departure date and time of the trip. + */ + public DateTimeRange getTravelDateRange(); + + /** + * Location of the property. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @param location Location of the property. + */ + public void setLocation(String location); + + /** + * Location of the property. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @return Location of the property. + */ + public String getLocation(); + + /** + * Shipping options available for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * shipping
Details Shipping options available for an item. Up to 10 shipping options can be + * included for each item. Three sub-attributes are included in the shipping attribute: + *
    + * + *
  • service = The type of service used to ship an item. Acceptable values are 'FedEx', 'UPS', + * 'DHL', 'Mail', and 'Other'
  • + *
  • country = The country an item will ship to. Only acceptable values are ISO 3166 + * country codes.
  • + *
  • price = the price of shipping.
  • + *
+ *
+ * + * Example <g:shipping>
+ * <g:country>US</g:country>
+ * + * <g:service>UPS</g:shipping>
+ * + * <g:price>35.95</g:price>
+ * </g:shipping>
Attribute of Products
+ * + * Content type shippingType
+ * + * @return Shipping options available for an item. + */ + public ShippingType[] getShipping(); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Unknown.java b/rome-modules/src/main/java/com/rometools/modules/base/Unknown.java new file mode 100644 index 0000000..1e231a6 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Unknown.java @@ -0,0 +1,76 @@ +/* + * Unknown.java + * + * Created on November 18, 2005, 1:34 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import java.net.URL; + +import com.rometools.modules.base.types.IntUnit; + +/** + * This interface contains all the other schema elements that the document doesn't associate with a + * particular type. + * + * @author Robert "kebernet" Cooper + */ +public interface Unknown extends GlobalInterface { + public void setLicenses(String[] licenses); + + public String[] getLicenses(); + + public void setOperatingSystems(String systems); + + public String getOperatingSystems(); + + public void setProgrammingLanguages(String[] languages); + + public String[] getProgrammingLanguages(); + + public void setRelatedLinks(URL[] links); + + public URL[] getRelatedLinks(); + + public void setSquareFootages(IntUnit[] squareFootages); + + public IntUnit[] getSquareFootages(); + + public void setSubjectAreas(String[] subjectAreas); + + public String[] getSubjectAreas(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/ValidationException.java b/rome-modules/src/main/java/com/rometools/modules/base/ValidationException.java new file mode 100644 index 0000000..f7ec67b --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/ValidationException.java @@ -0,0 +1,62 @@ +/* + * ValidationException.java + * + * Created on November 20, 2005, 3:14 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +/** + * This is an unchecked exception that is thrown when a data value violates the Google Schema + * limits. + * + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public class ValidationException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** Creates a new instance of ValidationException */ + public ValidationException(final String message) { + super(message); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Vehicle.java b/rome-modules/src/main/java/com/rometools/modules/base/Vehicle.java new file mode 100644 index 0000000..3cb3286 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Vehicle.java @@ -0,0 +1,1827 @@ +/* + * Vehicle.java + * + * Created on November 16, 2005, 3:26 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.PaymentTypeEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; +import com.rometools.modules.base.types.ShippingType; +import com.rometools.modules.base.types.YearType; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for vehicles. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface Vehicle extends GlobalInterface { + /** + * Color of an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
color
Details Color of an item.
Example <g:color>Black</g:color>
+ * + * Attribute of Products, Vehicles
Content type string
+ * + * @param color Color of an item. + */ + public void setColors(String[] color); + + /** + * Color of an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
color
Details Color of an item.
Example <g:color>Black</g:color>
+ * + * Attribute of Products, Vehicles
Content type string
+ * + * @return Color of an item. + */ + public String[] getColors(); + + /** + * Condition of the item. For example: new, used, or refurbished. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
condition
DetailsCondition of the item. For example: new, used, or refurbished.
Example + * <g:condition>refurbished</g:condition>
Attribute ofProducts, Vehicles
Content typestring
+ * + * @param condition Condition of the item. For example: new, used, or refurbished. + */ + public void setCondition(String condition); + + /** + * Condition of the item. For example: new, used, or refurbished. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
condition
DetailsCondition of the item. For example: new, used, or refurbished.
Example + * <g:condition>refurbished</g:condition>
Attribute ofProducts, Vehicles
Content typestring
+ * + * @return Condition of the item. For example: new, used, or refurbished. + */ + public String getCondition(); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @param value Currency of the price amount for an item. + */ + public void setCurrency(CurrencyEnumeration value); + + /** + * Currency of the price amount for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
currency
DetailsCurrency of the price amount for an item. Values must be in ISO 4217 + * currency code format.
ExampleAcceptable:
+ * <g:currency>USD</g:currency>
+ * + * Not acceptable:
+ * <g:currency>US Dollars</g:currency>
Attribute ofEvents, Housing, Products, Services, Travel, Vehicles
Content typecurrencyEnumeration
+ * + * @return Currency of the price amount for an item. + */ + public CurrencyEnumeration getCurrency(); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @param deliveryNotes Additional instructions to explain the item’s delivery process. + */ + public void setDeliveryNotes(String deliveryNotes); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @return Additional instructions to explain the item’s delivery process. + */ + public String getDeliveryNotes(); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @param deliveryRadius The maximum distance you will deliver an item in any direction. + */ + public void setDeliveryRadius(FloatUnit deliveryRadius); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @return The maximum distance you will deliver an item in any direction. + */ + public FloatUnit getDeliveryRadius(); + + /** + * Location of a property. Should include street, city, state, postal code, and country, in that + * order. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @param location Location of a property. Should include street, city, state, postal code, and + * country, in that order. + */ + public void setLocation(String location); + + /** + * Location of a property. Should include street, city, state, postal code, and country, in that + * order. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @return Location of a property. Should include street, city, state, postal code, and country, + * in that order. + */ + public String getLocation(); + + /** + * The vehicle manufacturer. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
make
+ * + * Details + * + * The vehicle manufacturer.
Example <g:make>Honda</g:make>
Attribute of + * + * Vehicles
Content type string
+ * + * @param make The vehicle manufacturer. + */ + public void setMake(String make); + + /** + * The vehicle manufacturer. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
make
+ * + * Details + * + * The vehicle manufacturer.
Example <g:make>Honda</g:make>
Attribute of + * + * Vehicles
Content type string
+ * + * @return The vehicle manufacturer. + */ + public String getMake(); + + /** + * Current mileage of the vehicle. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
mileage + *
Details Current mileage of the vehicle.
+ * + * Example <g:mileage>1700</g:mileage>
+ *
+ * <g:mileage>1,700 miles</g:mileage>
Attribute of Vehicles
Content type intUnit
+ * + * @param mileage Current mileage of the vehicle. + */ + public void setMileage(Integer mileage); + + /** + * Current mileage of the vehicle. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
mileage + *
Details Current mileage of the vehicle.
+ * + * Example <g:mileage>1700</g:mileage>
+ *
+ * <g:mileage>1,700 miles</g:mileage>
Attribute of Vehicles
Content type intUnit
+ * + * @return Current mileage of the vehicle. + */ + public Integer getMileage(); + + /** + * The vehicle model. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
model
DetailsThe vehicle model.
Example <g:model>Camry</g:model>
Attribute of Vehicles
Content typestring
+ * + * @param model The vehicle model. + */ + public void setModel(String model); + + /** + * The vehicle model. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
model
DetailsThe vehicle model.
Example <g:model>Camry</g:model>
Attribute of Vehicles
Content typestring
+ * + * @return The vehicle model. + */ + public String getModel(); + + /** + * Payment Methods acceptable for the service. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * "Cash," "Check," "Traveler’s Check," "Visa," "MasterCard," + * + * "American Express," "Discover," "Wire transfer" or "Paypal." If you accept more than one + * method, include multiple instances of the <payment_accepted> attribute for each + * acceptable method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * + * <g:payment_accepted>Paypal</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check Paypal</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type paymentMethodEnumeration
+ * + * @param paymentAccepted Payment Methods acceptable for the service. + */ + public void setPaymentAccepted(PaymentTypeEnumeration[] paymentAccepted); + + /** + * Payment Methods acceptable for the service. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_accepted
Details Acceptable payment methods for item purchases. Acceptable values are + * "Cash," "Check," "Traveler’s Check," "Visa," "MasterCard," + * + * "American Express," "Discover," "Wire transfer" or "Paypal." If you accept more than one + * method, include multiple instances of the <payment_accepted> attribute for each + * acceptable method.
Example Acceptable:
+ * <g:payment_accepted>Cash</g:payment_accepted>
+ * + * <g:payment_accepted>Check</g:payment_accepted>
+ * + * <g:payment_accepted>Paypal</g:payment_accepted>
+ * Not acceptable:
+ * <g:payment_accepted>Cash Check Paypal</g:payment_accepted>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type paymentMethodEnumeration
+ * + * @return Payment Methods acceptable for the service. + */ + public PaymentTypeEnumeration[] getPaymentAccepted(); + + /** + * Additional payment information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
Content type string
+ * + * @param paymentNotes Additional payment information. + */ + public void setPaymentNotes(String paymentNotes); + + /** + * Additional payment information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
payment_notes
Details Additional instructions to explain a payment policy.
Example <g:payment_notes>Cash only for local + * orders.</g:payment_notes>
Attribute of + * + * Events, Housing, Products, Services, Travel, Vehicles
Content type string
+ * + * @return Additional payment information. + */ + public String getPaymentNotes(); + + /** + * Price for the service.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * <g:price>5,95</g:price>
+ * <g:price>5.00 � 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @param price Price for the service. + */ + public void setPrice(FloatUnit price); + + /** + * Price for the service.
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price
Details Prices can be a single price, 0 (free), or blank if not applicable. + * Numerice values only. When used as a sub-attribute of <shipping>, the value included + * reflects the price of shipping.
Example Acceptable:
+ * <g:price>5.95</g:price>
+ * + * <g:price>0</g:price>
+ * Not acceptable:
+ * <g:price>5,95</g:price>
+ * <g:price>5.00 � 10.00</g:price>
+ * + * <g:price>100 or best offer</g:price>
+ * <g:price>free</g:price>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content typefloatUnit
+ * + * @return Price for the service. + */ + public FloatUnit getPrice(); + + /** + * Price type information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are �negotiable,� or + * �starting.� The default is �starting�
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @param priceType Price type information. + */ + public void setPriceType(PriceTypeEnumeration priceType); + + /** + * Price type information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
price_type
DetailsThe type of pricing for the item. Acceptable values are �negotiable,� or + * �starting.� The default is �starting�
ExampleAcceptable:
+ * <g:price_type>starting</g:price_type>
+ * Not acceptable:
+ * <g:price_type>100 OBO</g:price_type>
Attribute of Events, Housing, Products, Services, Travel, Vehicles
Content type priceTypeEnumeration
+ * + * @return Price type information. + */ + public PriceTypeEnumeration getPriceType(); + + /** + * Quantity available. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
quantity
Details The number of units available for purchase. This attribute can be left + * blank if you have a large quantity or if it is not applicable.
Example Acceptable:
+ * <g:quantity>18</g:quantity>
+ * + * <g:quantity>0</g:quantity>
+ * + * Not acceptable:
+ * <g:quantity>out of stock</g:quantity>
+ * + * Attribute of Events, Products, Services, Travel, Vehicles
Content type + * + * integer
+ * + * @param quantity Quantity available. + */ + public void setQuantity(Integer quantity); + + /** + * Quantity available. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
quantity
Details The number of units available for purchase. This attribute can be left + * blank if you have a large quantity or if it is not applicable.
Example Acceptable:
+ * <g:quantity>18</g:quantity>
+ * + * <g:quantity>0</g:quantity>
+ * + * Not acceptable:
+ * <g:quantity>out of stock</g:quantity>
+ * + * Attribute of Events, Products, Services, Travel, Vehicles
Content type + * + * integer
+ * + * @return Quantity available. + */ + public Integer getQuantity(); + + /** + * Shipping options available for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * shipping
Details Shipping options available for an item. Up to 10 shipping options can be + * included for each item. Three sub-attributes are included in the shipping attribute: + *
    + * + *
  • service = The type of service used to ship an item. Acceptable values are 'FedEx', 'UPS', + * 'DHL', 'Mail', and 'Other'
  • + *
  • country = The country an item will ship to. Only acceptable values are ISO 3166 + * country codes.
  • + *
  • price = the price of shipping.
  • + *
+ *
+ * + * Example <g:shipping>
+ * <g:country>US</g:country>
+ * + * <g:service>UPS</g:shipping>
+ * + * <g:price>35.95</g:price>
+ * </g:shipping>
Attribute of Products
+ * + * Content type shippingType
+ * + * @param shipping Shipping options available for an item. + */ + public void setShipping(ShippingType[] shipping); + + /** + * Shipping options available for an item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * shipping
Details Shipping options available for an item. Up to 10 shipping options can be + * included for each item. Three sub-attributes are included in the shipping attribute: + *
    + * + *
  • service = The type of service used to ship an item. Acceptable values are 'FedEx', 'UPS', + * 'DHL', 'Mail', and 'Other'
  • + *
  • country = The country an item will ship to. Only acceptable values are ISO 3166 + * country codes.
  • + *
  • price = the price of shipping.
  • + *
+ *
+ * + * Example <g:shipping>
+ * <g:country>US</g:country>
+ * + * <g:service>UPS</g:shipping>
+ * + * <g:price>35.95</g:price>
+ * </g:shipping>
Attribute of Products
+ * + * Content type shippingType
+ * + * @return Shipping options available for an item. + */ + public ShippingType[] getShipping(); + + /** + * Tax rate associated with the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @param taxPercent Tax rate associated with the event. + */ + public void setTaxPercent(Float taxPercent); + + /** + * Tax rate associated with the item. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
tax_percent
+ * + * Details Tax rate as a percentage.
Example <g:tax_percent>8.2<g:/tax_percent>
+ * + * Attribute of + * + * Products, Events
Content type percentType
+ * + * @return Tax rate associated with the event. + */ + public Float getTaxPercent(); + + /** + * Region where tax applies. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @param taxRegion Region where tax applies. + */ + public void setTaxRegion(String taxRegion); + + /** + * Region where tax applies. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * tax_region
Details Geographical region a tax rate applies to.
+ * + * Example <g:tax_region>California</g:tax_region>
Attribute of Product, Events,
Content typestring
+ * + * @return Region where tax applies. + */ + public String getTaxRegion(); + + /** + * The type of vehicle: Car, motorcycle, scooter, etc. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * vehicle_type
Details The type of vehicle: Car, motorcycle, scooter, etc.
+ * + * Example <g:vehicle_type>truck</g:vehicle_type>
Attribute of Products
+ * + * Content type + * + * string
+ * + * @param vehicleType The type of vehicle: Car, motorcycle, scooter, etc. + */ + public void setVehicleType(String vehicleType); + + /** + * The type of vehicle: Car, motorcycle, scooter, etc. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + * vehicle_type
Details The type of vehicle: Car, motorcycle, scooter, etc.
+ * + * Example <g:vehicle_type>truck</g:vehicle_type>
Attribute of Products
+ * + * Content type + * + * string
+ * + * @return The type of vehicle: Car, motorcycle, scooter, etc. + */ + public String getVehicleType(); + + /** + * Vehicle Identification Number. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
vin
Details Vehicle Identification Number.
Example <g:vin>1M8GDM9AXKP042788</g:vin>
Attribute of Vehicles
+ * + * Content type string
+ * + * @param vin Vehicle Identification Number. + */ + public void setVin(String vin); + + /** + * Vehicle Identification Number. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
vin
Details Vehicle Identification Number.
Example <g:vin>1M8GDM9AXKP042788</g:vin>
Attribute of Vehicles
+ * + * Content type string
+ * + * @return Vehicle Identification Number. + */ + public String getVin(); + + /** + * The four digit model year or year built. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
year
Details The four digit model year or year built. Format YYYY
+ * + * Example Acceptable:
+ * + * <g:year>2005</g:year>
+ * Not acceptable:
+ * <g:year>79</g:year>
+ * + * <g:year>26</g:year>
Attribute of Housing, Vehicles
+ * + * Content type year
+ * + * @param year The four digit model year or year built. + */ + public void setYear(YearType year); + + /** + * The four digit model year or year built. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
year
Details The four digit model year or year built. Format YYYY
+ * + * Example Acceptable:
+ * + * <g:year>2005</g:year>
+ * Not acceptable:
+ * <g:year>79</g:year>
+ * + * <g:year>26</g:year>
Attribute of Housing, Vehicles
+ * + * Content type year
+ * + * @return The four digit model year or year built. + */ + public YearType getYear(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/Wanted.java b/rome-modules/src/main/java/com/rometools/modules/base/Wanted.java new file mode 100644 index 0000000..7b7bdeb --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/Wanted.java @@ -0,0 +1,309 @@ +/* + * Wanted.java + * + * Created on November 16, 2005, 3:32 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base; + +import com.rometools.modules.base.types.FloatUnit; + +/** + * This is an interface for the GoogleBase plug in that exposes methods used for wanted ads. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface Wanted extends GlobalInterface { + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @param deliveryNotes Additional instructions to explain the item’s delivery process. + */ + public void setDeliveryNotes(String deliveryNotes); + + /** + * Additional instructions to explain the item’s delivery process. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_notes
DetailsAdditional instructions to explain the item’s delivery process.
Example + * <g:delivery_notes>Items usually shipped within 24 + * hours.<g:/delivery_notes>
+ * + *
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typestring
+ * + * @return Additional instructions to explain the item’s delivery process. + */ + public String getDeliveryNotes(); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @param deliveryRadius The maximum distance you will deliver an item in any direction. + */ + public void setDeliveryRadius(FloatUnit deliveryRadius); + + /** + * The maximum distance you will deliver an item in any direction. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
delivery_radius
DetailsThe maximum distance you will deliver an item in any direction.
Example + * <g:delivery_radius>10<g:/delivery_radius>
+ * <g:delivery_radius>10km</g:delivery_radius>
Attribute of + * Events, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content typefloatUnit
+ * + * @return The maximum distance you will deliver an item in any direction. + */ + public FloatUnit getDeliveryRadius(); + + /** + * Location of the property. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @param location Location of the property. + */ + public void setLocation(String location); + + /** + * Location of the property. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
location
Details Location of a property. Should include street, city, state, postal code, + * and country, in that order.
Example Acceptable:
+ * <g:location>123 Main St, Anytown, + * CA, 12345, + * USA</g:location>
+ * + * Not acceptable:
+ * <g:location>123 Main St,, CA, + * 12345, + * USA</g:location>
+ * <g:location> Anytown, CA, + * 12345, + * USA</g:location>
Attribute of Reference Items, Events, Housing, Jobs, News and Articles, People + * profiles, Products, Reviews, Services, Travel, Vehicles, Wanted Ads.
Content type locationType
+ * + * @return Location of the property. + */ + public String getLocation(); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/io/CustomTagGenerator.java b/rome-modules/src/main/java/com/rometools/modules/base/io/CustomTagGenerator.java new file mode 100644 index 0000000..bc2474a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/io/CustomTagGenerator.java @@ -0,0 +1,157 @@ +/* + * CustomTagGenerator.java + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.io; + +import java.net.URL; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.base.CustomTag; +import com.rometools.modules.base.CustomTagImpl; +import com.rometools.modules.base.CustomTags; +import com.rometools.modules.base.types.DateTimeRange; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.IntUnit; +import com.rometools.modules.base.types.ShortDate; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public class CustomTagGenerator implements ModuleGenerator { + + static final HashSet NAMESPACES = new HashSet(); + + static { + NAMESPACES.add(CustomTagParser.NS); + } + + /** Creates a new instance of CustomTagGenerator */ + public CustomTagGenerator() { + } + + @Override + public String getNamespaceUri() { + return CustomTags.URI; + } + + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + @Override + public void generate(final Module module, final Element element) { + if (!(module instanceof CustomTags)) { + return; + } + + final List tags = ((CustomTags) module).getValues(); + final Iterator it = tags.iterator(); + + while (it.hasNext()) { + final CustomTag tag = it.next(); + + if (tag.getValue() instanceof DateTimeRange) { + final DateTimeRange dtr = (DateTimeRange) tag.getValue(); + final Element newTag = new Element(tag.getName(), CustomTagParser.NS); + newTag.setAttribute("type", "dateTimeRange"); + newTag.addContent(generateSimpleElement("start", GoogleBaseParser.LONG_DT_FMT.format(dtr.getStart()))); + newTag.addContent(generateSimpleElement("end", GoogleBaseParser.LONG_DT_FMT.format(dtr.getEnd()))); + element.addContent(newTag); + } else if (tag.getValue() instanceof ShortDate) { + final ShortDate sd = (ShortDate) tag.getValue(); + final Element newTag = generateSimpleElement(tag.getName(), GoogleBaseParser.SHORT_DT_FMT.format(sd)); + newTag.setAttribute("type", "date"); + element.addContent(newTag); + } else if (tag.getValue() instanceof Date) { + final Date d = (Date) tag.getValue(); + final Element newTag = generateSimpleElement(tag.getName(), GoogleBaseParser.SHORT_DT_FMT.format(d)); + newTag.setAttribute("type", "dateTime"); + element.addContent(newTag); + } else if (tag.getValue() instanceof Integer) { + final Element newTag = generateSimpleElement(tag.getName(), tag.getValue().toString()); + newTag.setAttribute("type", "int"); + element.addContent(newTag); + } else if (tag.getValue() instanceof IntUnit) { + final Element newTag = generateSimpleElement(tag.getName(), tag.getValue().toString()); + newTag.setAttribute("type", "intUnit"); + element.addContent(newTag); + } else if (tag.getValue() instanceof Float) { + final Element newTag = generateSimpleElement(tag.getName(), tag.getValue().toString()); + newTag.setAttribute("type", "float"); + element.addContent(newTag); + } else if (tag.getValue() instanceof FloatUnit) { + final Element newTag = generateSimpleElement(tag.getName(), tag.getValue().toString()); + newTag.setAttribute("type", "floatUnit"); + element.addContent(newTag); + } else if (tag.getValue() instanceof String) { + final Element newTag = generateSimpleElement(tag.getName(), tag.getValue().toString()); + newTag.setAttribute("type", "string"); + element.addContent(newTag); + } else if (tag.getValue() instanceof URL) { + final Element newTag = generateSimpleElement(tag.getName(), tag.getValue().toString()); + newTag.setAttribute("type", "url"); + element.addContent(newTag); + } else if (tag.getValue() instanceof Boolean) { + final Element newTag = generateSimpleElement(tag.getName(), tag.getValue().toString()); + newTag.setAttribute("type", "boolean"); + element.addContent(newTag); + } else if (tag.getValue() instanceof CustomTagImpl.Location) { + final Element newTag = generateSimpleElement(tag.getName(), tag.getValue().toString()); + newTag.setAttribute("type", "location"); + element.addContent(newTag); + } + } + } + + protected Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, CustomTagParser.NS); + element.addContent(value); + + return element; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/io/CustomTagParser.java b/rome-modules/src/main/java/com/rometools/modules/base/io/CustomTagParser.java new file mode 100644 index 0000000..15c72bd --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/io/CustomTagParser.java @@ -0,0 +1,148 @@ +/* + * CustomTagParser.java + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.io; + +import java.net.MalformedURLException; +import java.net.URL; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.base.CustomTag; +import com.rometools.modules.base.CustomTagImpl; +import com.rometools.modules.base.CustomTags; +import com.rometools.modules.base.CustomTagsImpl; +import com.rometools.modules.base.types.DateTimeRange; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.IntUnit; +import com.rometools.modules.base.types.ShortDate; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; + +/** + * @version $Revision: 1.4 $ + * @author Robert "kebernet" Cooper + */ +public class CustomTagParser implements ModuleParser { + + private static final Logger LOG = LoggerFactory.getLogger(CustomTagParser.class); + + static final Namespace NS = Namespace.getNamespace("g-custom", CustomTags.URI); + + /** Creates a new instance of CustomTagParser */ + public CustomTagParser() { + } + + @Override + public Module parse(final Element element, final Locale locale) { + final CustomTags module = new CustomTagsImpl(); + final ArrayList tags = new ArrayList(); + final List elements = element.getChildren(); + final Iterator it = elements.iterator(); + while (it.hasNext()) { + final Element child = it.next(); + if (child.getNamespace().equals(NS)) { + final String type = child.getAttributeValue("type"); + try { + if (type == null) { + continue; + } else if (type.equals("string")) { + tags.add(new CustomTagImpl(child.getName(), child.getText())); + } else if (type.equals("int")) { + tags.add(new CustomTagImpl(child.getName(), new Integer(child.getTextTrim()))); + } else if (type.equals("float")) { + tags.add(new CustomTagImpl(child.getName(), new Float(child.getTextTrim()))); + } else if (type.equals("intUnit")) { + tags.add(new CustomTagImpl(child.getName(), new IntUnit(child.getTextTrim()))); + } else if (type.equals("floatUnit")) { + tags.add(new CustomTagImpl(child.getName(), new FloatUnit(child.getTextTrim()))); + } else if (type.equals("date")) { + try { + tags.add(new CustomTagImpl(child.getName(), new ShortDate(GoogleBaseParser.SHORT_DT_FMT.parse(child.getTextTrim())))); + } catch (final ParseException e) { + LOG.warn("Unable to parse date type on " + child.getName(), e); + } + } else if (type.equals("dateTime")) { + try { + tags.add(new CustomTagImpl(child.getName(), GoogleBaseParser.LONG_DT_FMT.parse(child.getTextTrim()))); + } catch (final ParseException e) { + LOG.warn("Unable to parse date type on " + child.getName(), e); + } + } else if (type.equals("dateTimeRange")) { + try { + tags.add(new CustomTagImpl(child.getName(), new DateTimeRange(GoogleBaseParser.LONG_DT_FMT.parse(child + .getChild("start", CustomTagParser.NS).getText().trim()), GoogleBaseParser.LONG_DT_FMT.parse(child + .getChild("end", CustomTagParser.NS).getText().trim())))); + } catch (final Exception e) { + LOG.warn("Unable to parse date type on " + child.getName(), e); + } + } else if (type.equals("url")) { + try { + tags.add(new CustomTagImpl(child.getName(), new URL(child.getTextTrim()))); + } catch (final MalformedURLException e) { + LOG.warn("Unable to parse URL type on " + child.getName(), e); + } + } else if (type.equals("boolean")) { + tags.add(new CustomTagImpl(child.getName(), new Boolean(child.getTextTrim().toLowerCase()))); + } else if (type.equals("location")) { + tags.add(new CustomTagImpl(child.getName(), new CustomTagImpl.Location(child.getText()))); + } else { + throw new Exception("Unknown type: " + type); + } + } catch (final Exception e) { + LOG.warn("Unable to parse type on " + child.getName(), e); + } + } + } + module.setValues(tags); + return module; + } + + @Override + public String getNamespaceUri() { + return CustomTags.URI; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/io/GoogleBaseGenerator.java b/rome-modules/src/main/java/com/rometools/modules/base/io/GoogleBaseGenerator.java new file mode 100644 index 0000000..36ed091 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/io/GoogleBaseGenerator.java @@ -0,0 +1,163 @@ +/* + * GoogleBaseGenerator.java + * + * Created on November 17, 2005, 2:46 PM + * + * This library is provided under dual licenses. You may choose the terms of the Lesser General + * Public License or the Apache License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; either version + * 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * + * 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.rometools.modules.base.io; + +import java.beans.PropertyDescriptor; +import java.net.URL; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.base.GoogleBase; +import com.rometools.modules.base.GoogleBaseImpl; +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.DateTimeRange; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.GenderEnumeration; +import com.rometools.modules.base.types.IntUnit; +import com.rometools.modules.base.types.PaymentTypeEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; +import com.rometools.modules.base.types.ShippingType; +import com.rometools.modules.base.types.ShortDate; +import com.rometools.modules.base.types.Size; +import com.rometools.modules.base.types.YearType; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public class GoogleBaseGenerator implements ModuleGenerator { + private static final Namespace NS = Namespace.getNamespace("g-core", GoogleBase.URI); + + private static final Logger LOG = LoggerFactory.getLogger(GoogleBaseGenerator.class); + + /** Creates a new instance of GoogleBaseGenerator */ + public GoogleBaseGenerator() { + super(); + } + + @Override + public String getNamespaceUri() { + return GoogleBase.URI; + } + + @Override + public Set getNamespaces() { + final HashSet set = new HashSet(); + set.add(GoogleBaseGenerator.NS); + return set; + } + + @Override + public void generate(final Module module, final Element element) { + final GoogleBaseImpl mod = (GoogleBaseImpl) module; + final HashMap props2tags = new HashMap(GoogleBaseParser.PROPS2TAGS); + final PropertyDescriptor[] pds = GoogleBaseParser.pds; + + for (final PropertyDescriptor pd : pds) { + final String tagName = (String) props2tags.get(pd.getName()); + + if (tagName == null) { + continue; + } + + Object[] values = null; + + try { + if (pd.getPropertyType().isArray()) { + values = (Object[]) pd.getReadMethod().invoke(mod, (Object[]) null); + } else { + values = new Object[] {pd.getReadMethod().invoke(mod, (Object[]) null)}; + } + + for (int j = 0; values != null && j < values.length; j++) { + if (values[j] != null) { + element.addContent(generateTag(values[j], tagName)); + } + } + } catch (final Exception e) { + LOG.error("Error", e); + } + } + } + + public Element generateTag(final Object o, final String tagName) { + if (o instanceof URL || o instanceof Float || o instanceof Boolean || o instanceof Integer || o instanceof String || o instanceof FloatUnit + || o instanceof IntUnit || o instanceof GenderEnumeration || o instanceof PaymentTypeEnumeration || o instanceof PriceTypeEnumeration + || o instanceof CurrencyEnumeration || o instanceof Size || o instanceof YearType) { + return generateSimpleElement(tagName, o.toString()); + } else if (o instanceof ShortDate) { + return generateSimpleElement(tagName, GoogleBaseParser.SHORT_DT_FMT.format(o)); + } else if (o instanceof Date) { + return generateSimpleElement(tagName, GoogleBaseParser.LONG_DT_FMT.format(o)); + } else if (o instanceof ShippingType) { + final ShippingType st = (ShippingType) o; + final Element element = new Element(tagName, GoogleBaseGenerator.NS); + + element.addContent(generateSimpleElement("country", st.getCountry())); + + element.addContent(generateSimpleElement("service", st.getService().toString())); + + element.addContent(generateSimpleElement("price", st.getPrice().toString())); + + return element; + } else if (o instanceof DateTimeRange) { + final DateTimeRange dtr = (DateTimeRange) o; + final Element element = new Element(tagName, GoogleBaseGenerator.NS); + element.addContent(generateSimpleElement("start", GoogleBaseParser.LONG_DT_FMT.format(dtr.getStart()))); + element.addContent(generateSimpleElement("end", GoogleBaseParser.LONG_DT_FMT.format(dtr.getEnd()))); + + return element; + } + + throw new RuntimeException("Unknown class type to handle: " + o.getClass().getName()); + } + + protected Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, GoogleBaseGenerator.NS); + element.addContent(value); + + return element; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/io/GoogleBaseParser.java b/rome-modules/src/main/java/com/rometools/modules/base/io/GoogleBaseParser.java new file mode 100644 index 0000000..86a8cbe --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/io/GoogleBaseParser.java @@ -0,0 +1,238 @@ +/* + * GoogleBaseParser.java + * + * Created on November 17, 2005, 11:31 AM + * + * This library is provided under dual licenses. You may choose the terms of the Lesser General + * Public License or the Apache License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; either version + * 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * + * 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.rometools.modules.base.io; + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.IOException; +import java.lang.reflect.Array; +import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Properties; + +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.base.GoogleBase; +import com.rometools.modules.base.GoogleBaseImpl; +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.DateTimeRange; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.GenderEnumeration; +import com.rometools.modules.base.types.IntUnit; +import com.rometools.modules.base.types.PaymentTypeEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; +import com.rometools.modules.base.types.ShippingType; +import com.rometools.modules.base.types.Size; +import com.rometools.modules.base.types.YearType; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; + +/** + * DOCUMENT ME! + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.3 $ + */ +public class GoogleBaseParser implements ModuleParser { + + private static final Logger LOG = LoggerFactory.getLogger(GoogleBaseParser.class); + + public static final char[] INTEGER_CHARS = "-1234567890".toCharArray(); + public static final char[] FLOAT_CHARS = "-1234567890.".toCharArray(); + public static final SimpleDateFormat SHORT_DT_FMT = new SimpleDateFormat("yyyy-MM-dd"); + public static final SimpleDateFormat LONG_DT_FMT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + static final Namespace NS = Namespace.getNamespace(GoogleBase.URI); + static final Properties PROPS2TAGS = new Properties(); + static PropertyDescriptor[] pds = null; + + static { + try { + pds = Introspector.getBeanInfo(GoogleBaseImpl.class).getPropertyDescriptors(); + PROPS2TAGS.load(GoogleBaseParser.class.getResourceAsStream("/com/rometools/modules/base/io/tags.properties")); + } catch (final IOException e) { + LOG.error("Unable to read properties file for Google Base tags!", e); + } catch (final IntrospectionException e) { + LOG.error("Unable to get property descriptors for GoogleBaseImpl!", e); + } + } + + /** + * Creates a new instance of GoogleBaseParser + */ + public GoogleBaseParser() { + super(); + } + + @Override + public Module parse(final Element element, final Locale locale) { + final HashMap tag2pd = new HashMap(); + final GoogleBaseImpl module = new GoogleBaseImpl(); + + try { + for (final PropertyDescriptor pd : pds) { + final String tagName = GoogleBaseParser.PROPS2TAGS.getProperty(pd.getName()); + + if (tagName == null) { + LOG.debug("Property: {} doesn't have a tag mapping.", pd.getName()); + } else { + tag2pd.put(tagName, pd); + } + } + } catch (final Exception e) { + throw new RuntimeException("Exception building tag to property mapping. ", e); + } + + final List children = element.getChildren(); + final Iterator it = children.iterator(); + + while (it.hasNext()) { + final Element child = it.next(); + + if (child.getNamespace().equals(GoogleBaseParser.NS)) { + final PropertyDescriptor pd = tag2pd.get(child.getName()); + + if (pd != null) { + try { + handleTag(child, pd, module); + } catch (final Exception e) { + LOG.warn("Unable to handle tag: " + child.getName(), e); + } + } + } + } + + return module; + } + + public static String stripNonValidCharacters(final char[] validCharacters, final String input) { + final StringBuffer newString = new StringBuffer(); + + for (int i = 0; i < input.length(); i++) { + for (final char validCharacter : validCharacters) { + if (input.charAt(i) == validCharacter) { + newString.append(validCharacter); + } + } + } + + return newString.toString(); + } + + @Override + public String getNamespaceUri() { + return GoogleBase.URI; + } + + private void handleTag(final Element tag, final PropertyDescriptor pd, final GoogleBase module) throws Exception { + Object tagValue = null; + + if (pd.getPropertyType() == Integer.class || pd.getPropertyType().getComponentType() == Integer.class) { + tagValue = new Integer(GoogleBaseParser.stripNonValidCharacters(GoogleBaseParser.INTEGER_CHARS, tag.getText())); + } else if (pd.getPropertyType() == Float.class || pd.getPropertyType().getComponentType() == Float.class) { + tagValue = new Float(GoogleBaseParser.stripNonValidCharacters(GoogleBaseParser.FLOAT_CHARS, tag.getText())); + } else if (pd.getPropertyType() == String.class || pd.getPropertyType().getComponentType() == String.class) { + tagValue = tag.getText(); + } else if (pd.getPropertyType() == URL.class || pd.getPropertyType().getComponentType() == URL.class) { + tagValue = new URL(tag.getText().trim()); + } else if (pd.getPropertyType() == Boolean.class || pd.getPropertyType().getComponentType() == Boolean.class) { + tagValue = new Boolean(tag.getText().trim()); + } else if (pd.getPropertyType() == Date.class || pd.getPropertyType().getComponentType() == Date.class) { + final String text = tag.getText().trim(); + + if (text.length() > 10) { + tagValue = GoogleBaseParser.LONG_DT_FMT.parse(text); + } else { + tagValue = GoogleBaseParser.SHORT_DT_FMT.parse(text); + } + } else if (pd.getPropertyType() == IntUnit.class || pd.getPropertyType().getComponentType() == IntUnit.class) { + tagValue = new IntUnit(tag.getText()); + } else if (pd.getPropertyType() == FloatUnit.class || pd.getPropertyType().getComponentType() == FloatUnit.class) { + tagValue = new FloatUnit(tag.getText()); + } else if (pd.getPropertyType() == DateTimeRange.class || pd.getPropertyType().getComponentType() == DateTimeRange.class) { + tagValue = + new DateTimeRange(LONG_DT_FMT.parse(tag.getChild("start", GoogleBaseParser.NS).getText().trim()), LONG_DT_FMT.parse(tag + .getChild("end", GoogleBaseParser.NS).getText().trim())); + } else if (pd.getPropertyType() == ShippingType.class || pd.getPropertyType().getComponentType() == ShippingType.class) { + final FloatUnit price = new FloatUnit(tag.getChild("price", GoogleBaseParser.NS).getText().trim()); + ShippingType.ServiceEnumeration service = + ShippingType.ServiceEnumeration.findByValue(tag.getChild("service", GoogleBaseParser.NS).getText().trim()); + + if (service == null) { + service = ShippingType.ServiceEnumeration.STANDARD; + } + + final String country = tag.getChild("country", GoogleBaseParser.NS).getText().trim(); + tagValue = new ShippingType(price, service, country); + } else if (pd.getPropertyType() == PaymentTypeEnumeration.class || pd.getPropertyType().getComponentType() == PaymentTypeEnumeration.class) { + tagValue = PaymentTypeEnumeration.findByValue(tag.getText().trim()); + } else if (pd.getPropertyType() == PriceTypeEnumeration.class || pd.getPropertyType().getComponentType() == PriceTypeEnumeration.class) { + tagValue = PriceTypeEnumeration.findByValue(tag.getText().trim()); + } else if (pd.getPropertyType() == CurrencyEnumeration.class || pd.getPropertyType().getComponentType() == CurrencyEnumeration.class) { + tagValue = CurrencyEnumeration.findByValue(tag.getText().trim()); + } else if (pd.getPropertyType() == GenderEnumeration.class || pd.getPropertyType().getComponentType() == GenderEnumeration.class) { + tagValue = GenderEnumeration.findByValue(tag.getText().trim()); + } else if (pd.getPropertyType() == YearType.class || pd.getPropertyType().getComponentType() == YearType.class) { + tagValue = new YearType(tag.getText().trim()); + } else if (pd.getPropertyType() == Size.class || pd.getPropertyType().getComponentType() == Size.class) { + tagValue = new Size(tag.getText().trim()); + } + + if (!pd.getPropertyType().isArray()) { + pd.getWriteMethod().invoke(module, new Object[] {tagValue}); + } else { + final Object[] current = (Object[]) pd.getReadMethod().invoke(module, (Object[]) null); + final int newSize = current == null ? 1 : current.length + 1; + final Object setValue = Array.newInstance(pd.getPropertyType().getComponentType(), newSize); + + int i = 0; + + for (; current != null && i < current.length; i++) { + Array.set(setValue, i, current[i]); + } + + Array.set(setValue, i, tagValue); + pd.getWriteMethod().invoke(module, new Object[] {setValue}); + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/package.html b/rome-modules/src/main/java/com/rometools/modules/base/package.html new file mode 100644 index 0000000..49cd810 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/package.html @@ -0,0 +1,72 @@ + + + + + + + + This is the base package for the Google Base ROME module. +

This package contains the core module interface GoogleBase, + as well as the implementation class GoogleBaseImpl. If you want + to work with a specific type of Google Base entry, you can cast it to a + specific item type interface, such as Vehicle.

+

Sample Useage: +

+        
+        SyndEntry entry = new SyndEntryImpl();
+        // set up the entry...
+        Vehicle vehicle = new GoogleBaseImpl();
+        vehicle.setMake("Honda");
+        vehicle.setModel("Insight");
+        vehicle.setYear( new Year("2000"));
+        List modules = new ArrayList();
+        modules.add( vehicle );
+        entry.setModules( modules );
+        
+        //Optionally, to get Google Base information from a Feed:
+        Article article = entry.getModule( "http://base.google.com/ns/1.0" );
+        System.out.println( article.getPages() );        
+        
+    
+

+

Google Base is a trademark of Google, Inc. The authors of this software + are not affiliated with Google, Inc. and Google does not endorse, support, + blah blah blah. +

+
+ * This library is provided under dual licenses. 
+ * You may choose the terms of the Lesser General Public License or the Apache
+ * License at your discretion.
+ *
+ *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * 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/rome-modules/src/main/java/com/rometools/modules/base/types/CloneableType.java b/rome-modules/src/main/java/com/rometools/modules/base/types/CloneableType.java new file mode 100644 index 0000000..0f3ba6a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/CloneableType.java @@ -0,0 +1,50 @@ +/* + * CloneableType.java + * + * Created on November 18, 2005, 10:42 AM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +/** + * This is just a holder interface for cloneable elements. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public interface CloneableType extends Cloneable { + public Object clone(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/CurrencyEnumeration.java b/rome-modules/src/main/java/com/rometools/modules/base/types/CurrencyEnumeration.java new file mode 100644 index 0000000..6d4cdc6 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/CurrencyEnumeration.java @@ -0,0 +1,601 @@ +/* + * CurrencyEnumeration.java + * + * Created on November 18, 2005, 11:33 AM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +import java.util.HashMap; + +/** + * An Enumeration of valid currency types. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public class CurrencyEnumeration { + + private static final HashMap lookup = new HashMap(); + + // + // + public static final CurrencyEnumeration AED = new CurrencyEnumeration("AED"); + + // + public static final CurrencyEnumeration AFA = new CurrencyEnumeration("AFA"); + + // + public static final CurrencyEnumeration ALL = new CurrencyEnumeration("ALL"); + + // + public static final CurrencyEnumeration AMD = new CurrencyEnumeration("AMD"); + + // + public static final CurrencyEnumeration ANG = new CurrencyEnumeration("ANG"); + + // + public static final CurrencyEnumeration AOA = new CurrencyEnumeration("AOA"); + + // + public static final CurrencyEnumeration ARS = new CurrencyEnumeration("ARS"); + + // + public static final CurrencyEnumeration AUD = new CurrencyEnumeration("AUD"); + + // + public static final CurrencyEnumeration AWG = new CurrencyEnumeration("AWG"); + + // + public static final CurrencyEnumeration AZM = new CurrencyEnumeration("AZM"); + + // + public static final CurrencyEnumeration BAM = new CurrencyEnumeration("BAM"); + + // + public static final CurrencyEnumeration BBD = new CurrencyEnumeration("BBD"); + + // + public static final CurrencyEnumeration BDT = new CurrencyEnumeration("BDT"); + + // + public static final CurrencyEnumeration BGN = new CurrencyEnumeration("BGN"); + + // + public static final CurrencyEnumeration BHD = new CurrencyEnumeration("BHD"); + + // + public static final CurrencyEnumeration BIF = new CurrencyEnumeration("BIF"); + + // + public static final CurrencyEnumeration BMD = new CurrencyEnumeration("BMD"); + + // + public static final CurrencyEnumeration BND = new CurrencyEnumeration("BND"); + + // + public static final CurrencyEnumeration BOB = new CurrencyEnumeration("BOB"); + + // + public static final CurrencyEnumeration BRL = new CurrencyEnumeration("BRL"); + + // + public static final CurrencyEnumeration BSD = new CurrencyEnumeration("BSD"); + + // + public static final CurrencyEnumeration BTN = new CurrencyEnumeration("BTN"); + + // + public static final CurrencyEnumeration BWP = new CurrencyEnumeration("BWP"); + + // + public static final CurrencyEnumeration BYR = new CurrencyEnumeration("BYR"); + + // + public static final CurrencyEnumeration BZD = new CurrencyEnumeration("BZD"); + + // + public static final CurrencyEnumeration CAD = new CurrencyEnumeration("CAD"); + + // + public static final CurrencyEnumeration CDF = new CurrencyEnumeration("CDF"); + + // + public static final CurrencyEnumeration CHF = new CurrencyEnumeration("CHF"); + + // + public static final CurrencyEnumeration CLP = new CurrencyEnumeration("CLP"); + + // + public static final CurrencyEnumeration CNY = new CurrencyEnumeration("CNY"); + + // + public static final CurrencyEnumeration CRC = new CurrencyEnumeration("CRC"); + + // + public static final CurrencyEnumeration CSD = new CurrencyEnumeration("CSD"); + + // + public static final CurrencyEnumeration CUP = new CurrencyEnumeration("CUP"); + + // + public static final CurrencyEnumeration CVE = new CurrencyEnumeration("CVE"); + + // + public static final CurrencyEnumeration CYP = new CurrencyEnumeration("CYP"); + + // + public static final CurrencyEnumeration CZK = new CurrencyEnumeration("CZK"); + + // + public static final CurrencyEnumeration DJF = new CurrencyEnumeration("DJF"); + + // + public static final CurrencyEnumeration DKK = new CurrencyEnumeration("DKK"); + + // + public static final CurrencyEnumeration DOP = new CurrencyEnumeration("DOP"); + + // + public static final CurrencyEnumeration DZD = new CurrencyEnumeration("DZD"); + + // + public static final CurrencyEnumeration EEK = new CurrencyEnumeration("EEK"); + + // + public static final CurrencyEnumeration EGP = new CurrencyEnumeration("EGP"); + + // + public static final CurrencyEnumeration ERN = new CurrencyEnumeration("ERN"); + + // + public static final CurrencyEnumeration ETB = new CurrencyEnumeration("ETB"); + + // + public static final CurrencyEnumeration EUR = new CurrencyEnumeration("EUR"); + + // + public static final CurrencyEnumeration FJD = new CurrencyEnumeration("FJD"); + + // + public static final CurrencyEnumeration FKP = new CurrencyEnumeration("FKP"); + + // + public static final CurrencyEnumeration GBP = new CurrencyEnumeration("GBP"); + + // + public static final CurrencyEnumeration GEL = new CurrencyEnumeration("GEL"); + + // + public static final CurrencyEnumeration GGP = new CurrencyEnumeration("GGP"); + + // + public static final CurrencyEnumeration GHC = new CurrencyEnumeration("GHC"); + + // + public static final CurrencyEnumeration GIP = new CurrencyEnumeration("GIP"); + + // + public static final CurrencyEnumeration GMD = new CurrencyEnumeration("GMD"); + + // + public static final CurrencyEnumeration GNF = new CurrencyEnumeration("GNF"); + + // + public static final CurrencyEnumeration GTQ = new CurrencyEnumeration("GTQ"); + + // + public static final CurrencyEnumeration GYD = new CurrencyEnumeration("GYD"); + + // + public static final CurrencyEnumeration HKD = new CurrencyEnumeration("HKD"); + + // + public static final CurrencyEnumeration HNL = new CurrencyEnumeration("HNL"); + + // + public static final CurrencyEnumeration HRK = new CurrencyEnumeration("HRK"); + + // + public static final CurrencyEnumeration HTG = new CurrencyEnumeration("HTG"); + + // + public static final CurrencyEnumeration HUF = new CurrencyEnumeration("HUF"); + + // + public static final CurrencyEnumeration IDR = new CurrencyEnumeration("IDR"); + + // + public static final CurrencyEnumeration ILS = new CurrencyEnumeration("ILS"); + + // + public static final CurrencyEnumeration IMP = new CurrencyEnumeration("IMP"); + + // + public static final CurrencyEnumeration INR = new CurrencyEnumeration("INR"); + + // + public static final CurrencyEnumeration IQD = new CurrencyEnumeration("IQD"); + + // + public static final CurrencyEnumeration IRR = new CurrencyEnumeration("IRR"); + + // + public static final CurrencyEnumeration ISK = new CurrencyEnumeration("ISK"); + + // + public static final CurrencyEnumeration JEP = new CurrencyEnumeration("JEP"); + + // + public static final CurrencyEnumeration JMD = new CurrencyEnumeration("JMD"); + + // + public static final CurrencyEnumeration JOD = new CurrencyEnumeration("JOD"); + + // + public static final CurrencyEnumeration JPY = new CurrencyEnumeration("JPY"); + + // + public static final CurrencyEnumeration KES = new CurrencyEnumeration("KES"); + + // + public static final CurrencyEnumeration KGS = new CurrencyEnumeration("KGS"); + + // + public static final CurrencyEnumeration KHR = new CurrencyEnumeration("KHR"); + + // + public static final CurrencyEnumeration KMF = new CurrencyEnumeration("KMF"); + + // + public static final CurrencyEnumeration KPW = new CurrencyEnumeration("KPW"); + + // + public static final CurrencyEnumeration KRW = new CurrencyEnumeration("KRW"); + + // + public static final CurrencyEnumeration KWD = new CurrencyEnumeration("KWD"); + + // + public static final CurrencyEnumeration KYD = new CurrencyEnumeration("KYD"); + + // + public static final CurrencyEnumeration KZT = new CurrencyEnumeration("KZT"); + + // + public static final CurrencyEnumeration LAK = new CurrencyEnumeration("LAK"); + + // + public static final CurrencyEnumeration LBP = new CurrencyEnumeration("LBP"); + + // + public static final CurrencyEnumeration LKR = new CurrencyEnumeration("LKR"); + + // + public static final CurrencyEnumeration LRD = new CurrencyEnumeration("LRD"); + + // + public static final CurrencyEnumeration LSL = new CurrencyEnumeration("LSL"); + + // + public static final CurrencyEnumeration LTL = new CurrencyEnumeration("LTL"); + + // + public static final CurrencyEnumeration LVL = new CurrencyEnumeration("LVL"); + + // + public static final CurrencyEnumeration LYD = new CurrencyEnumeration("LYD"); + + // + public static final CurrencyEnumeration MAD = new CurrencyEnumeration("MAD"); + + // + public static final CurrencyEnumeration MDL = new CurrencyEnumeration("MDL"); + + // + public static final CurrencyEnumeration MGA = new CurrencyEnumeration("MGA"); + + // + public static final CurrencyEnumeration MKD = new CurrencyEnumeration("MKD"); + + // + public static final CurrencyEnumeration MMK = new CurrencyEnumeration("MMK"); + + // + public static final CurrencyEnumeration MNT = new CurrencyEnumeration("MNT"); + + // + public static final CurrencyEnumeration MOP = new CurrencyEnumeration("MOP"); + + // + public static final CurrencyEnumeration MRO = new CurrencyEnumeration("MRO"); + + // + public static final CurrencyEnumeration MTL = new CurrencyEnumeration("MTL"); + + // + public static final CurrencyEnumeration MUR = new CurrencyEnumeration("MUR"); + + // + public static final CurrencyEnumeration MVR = new CurrencyEnumeration("MVR"); + + // + public static final CurrencyEnumeration MWK = new CurrencyEnumeration("MWK"); + + // + public static final CurrencyEnumeration MXN = new CurrencyEnumeration("MXN"); + + // + public static final CurrencyEnumeration MYR = new CurrencyEnumeration("MYR"); + + // + public static final CurrencyEnumeration MZM = new CurrencyEnumeration("MZM"); + + // + public static final CurrencyEnumeration NAD = new CurrencyEnumeration("NAD"); + + // + public static final CurrencyEnumeration NGN = new CurrencyEnumeration("NGN"); + + // + public static final CurrencyEnumeration NIO = new CurrencyEnumeration("NIO"); + + // + public static final CurrencyEnumeration NOK = new CurrencyEnumeration("NOK"); + + // + public static final CurrencyEnumeration NPR = new CurrencyEnumeration("NPR"); + + // + public static final CurrencyEnumeration NZD = new CurrencyEnumeration("NZD"); + + // + public static final CurrencyEnumeration OMR = new CurrencyEnumeration("OMR"); + + // + public static final CurrencyEnumeration PAB = new CurrencyEnumeration("PAB"); + + // + public static final CurrencyEnumeration PEN = new CurrencyEnumeration("PEN"); + + // + public static final CurrencyEnumeration PGK = new CurrencyEnumeration("PGK"); + + // + public static final CurrencyEnumeration PHP = new CurrencyEnumeration("PHP"); + + // + public static final CurrencyEnumeration PKR = new CurrencyEnumeration("PKR"); + + // + public static final CurrencyEnumeration PLN = new CurrencyEnumeration("PLN"); + + // + public static final CurrencyEnumeration PYG = new CurrencyEnumeration("PYG"); + + // + public static final CurrencyEnumeration QAR = new CurrencyEnumeration("QAR"); + + // + public static final CurrencyEnumeration RON = new CurrencyEnumeration("RON"); + + // + public static final CurrencyEnumeration RUB = new CurrencyEnumeration("RUB"); + + // + public static final CurrencyEnumeration RWF = new CurrencyEnumeration("MOP"); + + // + public static final CurrencyEnumeration SAR = new CurrencyEnumeration("SAR"); + + // + public static final CurrencyEnumeration SBD = new CurrencyEnumeration("SBD"); + + // + public static final CurrencyEnumeration SCR = new CurrencyEnumeration("SCR"); + + // + public static final CurrencyEnumeration SDD = new CurrencyEnumeration("SDD"); + + // + public static final CurrencyEnumeration SEK = new CurrencyEnumeration("SEK"); + + // + public static final CurrencyEnumeration SGD = new CurrencyEnumeration("SGD"); + + // + public static final CurrencyEnumeration SHP = new CurrencyEnumeration("SHP"); + + // + public static final CurrencyEnumeration SIT = new CurrencyEnumeration("SIT"); + + // + public static final CurrencyEnumeration SKK = new CurrencyEnumeration("SKK"); + + // + public static final CurrencyEnumeration SLL = new CurrencyEnumeration("SLL"); + + // + public static final CurrencyEnumeration SOS = new CurrencyEnumeration("SOS"); + + // + public static final CurrencyEnumeration SPL = new CurrencyEnumeration("SPL"); + + // + public static final CurrencyEnumeration SRD = new CurrencyEnumeration("SRD"); + + // + public static final CurrencyEnumeration STD = new CurrencyEnumeration("STD"); + + // + public static final CurrencyEnumeration SVC = new CurrencyEnumeration("SVC"); + + // + public static final CurrencyEnumeration SYP = new CurrencyEnumeration("SYP"); + + // + public static final CurrencyEnumeration SZL = new CurrencyEnumeration("SZL"); + + // + public static final CurrencyEnumeration THB = new CurrencyEnumeration("THB"); + + // + public static final CurrencyEnumeration TJS = new CurrencyEnumeration("TJS"); + + // + public static final CurrencyEnumeration TMM = new CurrencyEnumeration("TMM"); + + // + public static final CurrencyEnumeration TND = new CurrencyEnumeration("TND"); + + // + public static final CurrencyEnumeration TOP = new CurrencyEnumeration("TOP"); + + // + public static final CurrencyEnumeration TRL = new CurrencyEnumeration("TRL"); + + // + public static final CurrencyEnumeration TRY = new CurrencyEnumeration("TRY"); + + // + public static final CurrencyEnumeration TTD = new CurrencyEnumeration("TTD"); + + // + public static final CurrencyEnumeration TVD = new CurrencyEnumeration("TVD"); + + // + public static final CurrencyEnumeration TWD = new CurrencyEnumeration("TWD"); + + // + public static final CurrencyEnumeration TZS = new CurrencyEnumeration("TZS"); + + // + public static final CurrencyEnumeration UAH = new CurrencyEnumeration("UAH"); + + // + public static final CurrencyEnumeration UGX = new CurrencyEnumeration("UGX"); + + // + public static final CurrencyEnumeration USD = new CurrencyEnumeration("USD"); + + // + public static final CurrencyEnumeration UYU = new CurrencyEnumeration("UYU"); + + // + public static final CurrencyEnumeration UZS = new CurrencyEnumeration("UZS"); + + // + public static final CurrencyEnumeration VEB = new CurrencyEnumeration("VEB"); + + // + public static final CurrencyEnumeration VND = new CurrencyEnumeration("VND"); + + // + public static final CurrencyEnumeration VUV = new CurrencyEnumeration("VUV"); + + // + public static final CurrencyEnumeration WST = new CurrencyEnumeration("WST"); + + // + public static final CurrencyEnumeration XAF = new CurrencyEnumeration("XAF"); + + // + public static final CurrencyEnumeration XAG = new CurrencyEnumeration("XAG"); + + // + public static final CurrencyEnumeration XAU = new CurrencyEnumeration("XAU"); + + // + public static final CurrencyEnumeration XCD = new CurrencyEnumeration("XCD"); + + // + public static final CurrencyEnumeration XDR = new CurrencyEnumeration("XDR"); + + // + public static final CurrencyEnumeration XOF = new CurrencyEnumeration("XOF"); + + // + public static final CurrencyEnumeration XPD = new CurrencyEnumeration("XPD"); + + // + public static final CurrencyEnumeration XPF = new CurrencyEnumeration("XPF"); + + // + public static final CurrencyEnumeration XPT = new CurrencyEnumeration("XPT"); + + // + public static final CurrencyEnumeration YER = new CurrencyEnumeration("YER"); + + // + public static final CurrencyEnumeration ZAR = new CurrencyEnumeration("ZAR"); + + // + public static final CurrencyEnumeration ZMK = new CurrencyEnumeration("ZMK"); + + // + public static final CurrencyEnumeration ZWD = new CurrencyEnumeration("ZWD"); + + // + private final String value; + + /** + * Creates a new instance of CurrencyEnumeration + * + * @param value DOCUMENT ME! + */ + private CurrencyEnumeration(final String value) { + this.value = value; + lookup.put(value, this); + } + + public String getValue() { + return value; + } + + @Override + public Object clone() { + return this; + } + + public static CurrencyEnumeration findByValue(final String value) { + return lookup.get(value.trim().toUpperCase()); + } + + @Override + public String toString() { + return value; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/DateTimeRange.java b/rome-modules/src/main/java/com/rometools/modules/base/types/DateTimeRange.java new file mode 100644 index 0000000..6de93ca --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/DateTimeRange.java @@ -0,0 +1,136 @@ +/* + * DateTimeRange.java + * + * Created on November 16, 2005, 11:14 AM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +import java.util.Date; + +/** + * Represents a time range. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public class DateTimeRange implements CloneableType { + /** + * end time + */ + private Date end; + /** + * start time + */ + private Date start; + + /** + * Creates a new instance of DateTimeRange + * + * @param start Beginning of the timeframe. + * @param end End of the Timeframe. + */ + public DateTimeRange(final Date start, final Date end) { + this.start = start; + this.end = end; + } + + /** + * The end of the timeframe. + * + * @return The end of the timeframe. + */ + public Date getEnd() { + return end; + } + + /** + * The beginning of the timeframe. + * + * @return The beginning of the timeframe. + */ + public Date getStart() { + return start; + } + + /** + * Clones the object + * + * @return Duplicate of this object. + */ + @Override + public Object clone() { + final DateTimeRange retValue = new DateTimeRange(null, null); + + if (getStart() != null) { + retValue.start = (Date) getStart().clone(); + } + + if (getEnd() != null) { + retValue.end = (Date) getEnd().clone(); + } + + return retValue; + } + + /** + * String representation of the object. + * + * @return String representation of the object. + */ + @Override + public String toString() { + return "Start: " + start + " End: " + end; + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof DateTimeRange) || o == null) { + return false; + } + final DateTimeRange d = (DateTimeRange) o; + if (start == d.getStart() && end == d.getEnd()) { + return true; + } + if (start != null && !start.equals(d.getStart())) { + return false; + } + if (end != null && !end.equals(d.getEnd())) { + return false; + } + return true; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/FloatUnit.java b/rome-modules/src/main/java/com/rometools/modules/base/types/FloatUnit.java new file mode 100644 index 0000000..6f36442 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/FloatUnit.java @@ -0,0 +1,169 @@ +/* + * FloatUnit.java + * + * Created on November 16, 2005, 11:43 AM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +import com.rometools.modules.base.io.GoogleBaseParser; + +/** + * This class represents a quantity consisting of a float value and an optional units specification. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public class FloatUnit implements CloneableType { + /** + * Units + */ + private String units; + /** + * Float value + */ + private final float value; + + /** + * Looks for a char in an array + * + * @param find char to search for + * @param array array to search + * @return boolean indicating presence. + */ + private boolean inCharArray(final char find, final char[] array) { + for (final char element : array) { + if (find == element) { + return true; + } + } + return false; + } + + /** + * Creates a new float unit by parsing a String value + * + * @param source String value to parse + */ + public FloatUnit(final String source) { + final String parse = source.trim(); + int space = -1; + for (int i = 0; i < parse.length(); i++) { + if (!inCharArray(parse.charAt(i), GoogleBaseParser.FLOAT_CHARS)) { + space = i; + break; + } + } + + if (space == -1) { + space = parse.length(); + } + + value = Float.parseFloat(GoogleBaseParser.stripNonValidCharacters(GoogleBaseParser.FLOAT_CHARS, parse.substring(0, space))); + + if (space != parse.length()) { + units = parse.substring(space, parse.length()).trim(); + } + } + + /** + * Creates a new instance of FloatUnit + * + * @param value float value + * @param units Units represented, or null. + */ + public FloatUnit(final float value, final String units) { + this.value = value; + this.units = units; + } + + /** + * Returns the units. + * + * @return Returns the units. + */ + public String getUnits() { + return units; + } + + /** + * Returns the float value. + * + * @return Returns the float value. + */ + public float getValue() { + return value; + } + + /** + * Duplicates the object. + * + * @return Duplicate FloatUnit + */ + @Override + public Object clone() { + return new FloatUnit(0 + value, units); + } + + /** + * Returns a String representation of the object. + * + * @return Returns a String representation of the object. + */ + @Override + public String toString() { + if (units != null && units.trim().length() > 0) { + return value + " " + units; + } else { + return Float.toString(value); + } + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof FloatUnit)) { + return false; + } + final FloatUnit f = (FloatUnit) o; + if (f.getValue() != value) { + return false; + } + if (units == f.getUnits() || units != null && units.equals(f.getUnits())) { + return true; + } + return false; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/GenderEnumeration.java b/rome-modules/src/main/java/com/rometools/modules/base/types/GenderEnumeration.java new file mode 100644 index 0000000..a47bd8d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/GenderEnumeration.java @@ -0,0 +1,91 @@ +/* + * GenderEnumeration.java + * + * Created on November 16, 2005, 2:35 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +/** + * Simple enumeration for Genders. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public class GenderEnumeration implements CloneableType { + /** Men */ + public static final GenderEnumeration MALE = new GenderEnumeration("Male"); + /** Women */ + public static final GenderEnumeration FEMALE = new GenderEnumeration("Female"); + private final String value; + + private GenderEnumeration(final String value) { + this.value = value; + } + + /** Returns the proper instance based on the string value */ + public static GenderEnumeration findByValue(final String value) { + if (value == null) { + return null; + } + + final String gender = value.toUpperCase(); + + if (gender.charAt(0) == 'M') { + return GenderEnumeration.MALE; + } else if (gender.charAt(0) == 'F') { + return GenderEnumeration.FEMALE; + } else { + return null; + } + } + + /** Returns the value of the instance */ + public String getValue() { + return value; + } + + /** Returns a reference to the same object. :P */ + @Override + public Object clone() { + return this; + } + + @Override + public String toString() { + return value; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/IntUnit.java b/rome-modules/src/main/java/com/rometools/modules/base/types/IntUnit.java new file mode 100644 index 0000000..eb00e10 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/IntUnit.java @@ -0,0 +1,124 @@ +/* + * IntUnit.java + * + * Created on November 16, 2005, 12:49 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +import com.rometools.modules.base.io.GoogleBaseParser; + +/** + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public class IntUnit implements CloneableType { + private String units; + private final int value; + + private boolean inCharArray(final char find, final char[] array) { + for (final char element : array) { + if (find == element) { + return true; + } + } + return false; + } + + public IntUnit(final String source) { + final String parse = source.trim(); + int space = -1; + for (int i = 0; i < parse.length(); i++) { + if (!inCharArray(parse.charAt(i), GoogleBaseParser.INTEGER_CHARS)) { + space = i; + break; + } + } + if (space == -1) { + space = parse.length(); + } + + value = Integer.parseInt(GoogleBaseParser.stripNonValidCharacters(GoogleBaseParser.INTEGER_CHARS, parse.substring(0, space))); + + if (space != parse.length()) { + units = parse.substring(space, parse.length()).trim(); + } + } + + /** Creates a new instance of IntUnit */ + public IntUnit(final int value, final String units) { + this.value = value; + this.units = units; + } + + public String getUnits() { + return units; + } + + public int getValue() { + return value; + } + + @Override + public Object clone() { + return new IntUnit(value, units); + } + + @Override + public String toString() { + if (units != null && units.trim().length() > 0) { + return value + " " + units; + } else { + return Integer.toString(value); + } + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof IntUnit)) { + return false; + } + final IntUnit f = (IntUnit) o; + if (f.getValue() != value) { + return false; + } + if (units == f.getUnits() || units != null && units.equals(f.getUnits())) { + return true; + } + return false; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/PaymentTypeEnumeration.java b/rome-modules/src/main/java/com/rometools/modules/base/types/PaymentTypeEnumeration.java new file mode 100644 index 0000000..f367e0f --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/PaymentTypeEnumeration.java @@ -0,0 +1,87 @@ +/* + * PaymentTypeEnumeration.java + * + * Created on November 16, 2005, 11:49 AM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +import java.util.HashMap; + +/** + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public class PaymentTypeEnumeration { + + private static final HashMap lookup = new HashMap(); + + public static final PaymentTypeEnumeration CASH = new PaymentTypeEnumeration("Cash"); + public static final PaymentTypeEnumeration CHECK = new PaymentTypeEnumeration("Check"); + public static final PaymentTypeEnumeration TRAVELERS_CHECK = new PaymentTypeEnumeration("Traveler�s Check"); + public static final PaymentTypeEnumeration VISA = new PaymentTypeEnumeration("Visa"); + public static final PaymentTypeEnumeration MASTERCARD = new PaymentTypeEnumeration("MasterCard"); + public static final PaymentTypeEnumeration AMERICAN_EXPRESS = new PaymentTypeEnumeration("American Express"); + public static final PaymentTypeEnumeration DISCOVER = new PaymentTypeEnumeration("Discover"); + public static final PaymentTypeEnumeration WIRE_TRANSFER = new PaymentTypeEnumeration("Wire transfer"); + public static final PaymentTypeEnumeration PAYPAL = new PaymentTypeEnumeration("Paypal"); + private final String value; + + /** Creates a new instance of PaymentTypeEnumeration */ + private PaymentTypeEnumeration(final String value) { + this.value = value; + lookup.put(this.value.toUpperCase(), this); + } + + public String getValue() { + return value; + } + + public static PaymentTypeEnumeration findByValue(final String value) { + return lookup.get(value.toUpperCase()); + } + + @Override + public Object clone() { + return this; + } + + @Override + public String toString() { + return value; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/PriceTypeEnumeration.java b/rome-modules/src/main/java/com/rometools/modules/base/types/PriceTypeEnumeration.java new file mode 100644 index 0000000..c06c4a5 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/PriceTypeEnumeration.java @@ -0,0 +1,113 @@ +/* + * PriceTypeEnumeration.java + * + * Created on November 16, 2005, 11:45 AM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +/** + * Enumeration of values suitable for "price_type" or "salary_type". + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public class PriceTypeEnumeration implements CloneableType { + /** + * Indicates the value is a starting value. + */ + public static final PriceTypeEnumeration STARTING = new PriceTypeEnumeration("starting"); + /** + * Indicates the value is negotiable + */ + public static final PriceTypeEnumeration NEGOTIABLE = new PriceTypeEnumeration("negotiable"); + /** + * String value encapsulated + */ + private final String value; + + /** + * Creates a new instance of PriceTypeEnumeration + * + * @param value Value to encapsulate + */ + private PriceTypeEnumeration(final String value) { + this.value = value; + } + + /** + * Returns the string value of this instance. + * + * @return Returns the string value of this instance. + */ + public String getValue() { + return value; + } + + /** + * Returns a PriceTypeEnumeration based on the String value or null. + * + * @param value Value to search for. + * @return PriceTypeEnumeration or null. + */ + public static PriceTypeEnumeration findByValue(final String value) { + if (value.equalsIgnoreCase("negotiable")) { + return PriceTypeEnumeration.NEGOTIABLE; + } else { + return PriceTypeEnumeration.STARTING; + } + } + + /** + * Returns a duplicate of this instance + * + * @return The same instance. + */ + @Override + public Object clone() { + return this; + } + + /** + * Returns the string value of this instance. + * + * @return Returns the string value of this instance. + */ + @Override + public String toString() { + return value; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/ShippingType.java b/rome-modules/src/main/java/com/rometools/modules/base/types/ShippingType.java new file mode 100644 index 0000000..daae24d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/ShippingType.java @@ -0,0 +1,200 @@ +/* + * ShippingType.java + * + * Created on November 16, 2005, 12:05 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +import java.util.HashMap; + +/** + * This class represents a specific shipping option for an item. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public class ShippingType implements CloneableType { + /** + * price of the shipping. + */ + private final FloatUnit price; + /** + * Service used. + */ + private final ServiceEnumeration service; + /** + * Country to ship to + */ + private final String country; + + /** + * Creates a new instance of ShippingType + * + * @param price The price of the shipping option + * @param service Shipping service used. + * @param country Country shipped to. + */ + public ShippingType(final FloatUnit price, final ServiceEnumeration service, final String country) { + this.price = price; + this.service = service; + this.country = country; + } + + /** + * Returns the destination country. + * + * @return Returns the destination country. + */ + public String getCountry() { + return country; + } + + /** + * Returns the price of this shipping option. + * + * @return Returns the price of this shipping option. + */ + public FloatUnit getPrice() { + return price; + } + + /** + * Returns the ServiceEnumeration instance for the shipping service used. + * + * @return Returns the ServiceEnumeration instance for the shipping service used. + */ + public ServiceEnumeration getService() { + return service; + } + + /** + * Clones this object. + * + * @return Duplicate ShippingType object. + */ + @Override + public Object clone() { + return new ShippingType(price, service, country); + } + + /** + * Returns a String representation of this object. + * + * @return String representation of this object. + */ + @Override + public String toString() { + return country + " " + price + " " + service; + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof ShippingType)) { + return false; + } + if (toString().equals(o.toString())) { + return true; + } + return false; + } + + /** + * Enumeration class of valid options for ServiceType. + */ + public static class ServiceEnumeration { + /** + * Looks up a ServiceEnumeration based on the string value. + */ + private static final HashMap lookup = new HashMap(); + /** + * Standard + */ + public static final ServiceEnumeration STANDARD = new ServiceEnumeration("Standard"); + /** + * Freight + */ + public static final ServiceEnumeration FREIGHT = new ServiceEnumeration("Freight"); + /** + * Overnight + */ + public static final ServiceEnumeration OVERNIGHT = new ServiceEnumeration("Overnight"); + + /** + * String value + */ + private final String value; + + /** + * Creates a new instance of ServiceEnumeration. + * + * @param value String value to encapsulate. + */ + private ServiceEnumeration(final String value) { + this.value = value; + lookup.put(this.value.toUpperCase(), this); + } + + /** + * String value of this Service. + * + * @return String value of this Service. + */ + public String getValue() { + return value; + } + + /** + * Looks up a ServiceEnumeration based on the string value. + * + * @param value String value to search for. + * @return ServiceEnumeration or null. + */ + public static ServiceEnumeration findByValue(final String value) { + return lookup.get(value.toUpperCase()); + } + + /** + * String value of this Service. + * + * @return String value of this Service. + */ + @Override + public String toString() { + return value; + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/ShortDate.java b/rome-modules/src/main/java/com/rometools/modules/base/types/ShortDate.java new file mode 100644 index 0000000..952ee67 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/ShortDate.java @@ -0,0 +1,91 @@ +/* + * ShortDate.java + * + * Created on November 17, 2005, 1:04 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +import java.util.Date; + +/** + * This is a simple wrapper for java.util.Date that indicates it should be formatted without time of + * day for Google Base. It should be transparent to module developers. + * + * Move along. Nothing to see here. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public class ShortDate extends Date implements CloneableType { + /** + * + */ + private static final long serialVersionUID = 1L; + + /** Creates a new instance of ShortDate */ + public ShortDate() { + super(); + } + + /** + * Creates a new Short Date based on a Date value. + * + * @param date Date value to read from. + */ + public ShortDate(final Date date) { + super(date.getTime()); + } + + /** + * Creates a new ShortDate based on a millisecond time. + * + * @param time Millisecond time to start with. + */ + public ShortDate(final long time) { + super(time); + } + + /** + * Returns a duplicate of this object. + * + * @return Duplicate of the object. + */ + @Override + public Object clone() { + return new ShortDate(getTime()); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/Size.java b/rome-modules/src/main/java/com/rometools/modules/base/types/Size.java new file mode 100644 index 0000000..a913368 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/Size.java @@ -0,0 +1,168 @@ +/* + * Size.java + * + * Created on November 16, 2005, 1:51 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +import java.util.StringTokenizer; + +/** + * Represents the size on an item in 2 or 3 dimensions. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public class Size implements CloneableType { + /** + * height + */ + private FloatUnit height; + /** + * length + */ + private final FloatUnit length; + /** + * width + */ + private final FloatUnit width; + + /** + * Creates a new Size object parsing a string value. + * + * @param source String value to parse + */ + public Size(final String source) { + final StringTokenizer tok = new StringTokenizer(source, "Xx"); + length = new FloatUnit(tok.nextToken()); + width = new FloatUnit(tok.nextToken()); + + if (tok.hasMoreTokens()) { + height = new FloatUnit(tok.nextToken()); + } + } + + /** + * Creates a new instance of Size + * + * @param length lenght value + * @param width width value + */ + public Size(final FloatUnit length, final FloatUnit width) { + this.length = length; + this.width = width; + } + + /** + * Creates a new instance of Size. + * + * @param length Length value. + * @param width Width value. + * @param height Height value. + */ + public Size(final FloatUnit length, final FloatUnit width, final FloatUnit height) { + this.length = length; + this.width = width; + this.height = height; + } + + /** + * Height value. + * + * @return Height value. + */ + public FloatUnit getHeight() { + return height; + } + + /** + * Length value. + * + * @return Length value. + */ + public FloatUnit getLength() { + return length; + } + + /** + * Width value. + * + * @return Width value. + */ + public FloatUnit getWidth() { + return width; + } + + /** + * Duplicates this object. + * + * @return A duplicate Size object. + */ + @Override + public Object clone() { + if (height != null) { + return new Size(length, width, height); + } else { + return new Size(length, width); + } + } + + /** + * Returns a string representation of this object. + * + * @return A string representation of this object. + */ + @Override + public String toString() { + if (height != null) { + return length + "x" + width + "x" + height; + } else { + return length + "x" + width; + } + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof Size)) { + return false; + } + if (toString().equals(o.toString())) { + return true; + } + return false; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/YearType.java b/rome-modules/src/main/java/com/rometools/modules/base/types/YearType.java new file mode 100644 index 0000000..e4887b7 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/YearType.java @@ -0,0 +1,107 @@ +/* + * YearType.java + * + * Created on November 17, 2005, 11:42 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.types; + +import java.util.Calendar; +import java.util.Date; + +/** + * This class represents a simple 4 digit year. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.1 $ + */ +public class YearType implements CloneableType { + /** + * year value + */ + int year; + + /** + * Creates a new year from a string value. + * + * @param year String to parse. + */ + public YearType(final String year) { + this.year = Integer.parseInt(year.trim()); + } + + /** + * Creates a new instance of YearType + * + * @param date Date to get the year from. + */ + public YearType(final Date date) { + final Calendar cal = Calendar.getInstance(); + cal.setTime(date); + year = cal.get(Calendar.YEAR); + } + + /** + * Duplicates this object. + * + * @return Cloned Year. + */ + @Override + public Object clone() { + return new YearType(Integer.toString(year)); + } + + /** + * Returns a String representation of this object. + * + * @return Returns a String representation of this object. + */ + @Override + public String toString() { + return Integer.toString(year); + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof YearType)) { + return false; + } + if (toString().equals(o.toString())) { + return true; + } + return false; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/base/types/package.html b/rome-modules/src/main/java/com/rometools/modules/base/types/package.html new file mode 100644 index 0000000..618ff0c --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/base/types/package.html @@ -0,0 +1,45 @@ + + + + + + + + This package contains complex and utility datatypes for use with Google Base. +
+ * This library is provided under dual licenses. 
+ * You may choose the terms of the Lesser General Public License or the Apache
+ * License at your discretion.
+ *
+ *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * 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/rome-modules/src/main/java/com/rometools/modules/cc/CreativeCommons.java b/rome-modules/src/main/java/com/rometools/modules/cc/CreativeCommons.java new file mode 100644 index 0000000..24d3345 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/cc/CreativeCommons.java @@ -0,0 +1,61 @@ +/* + * CreativeCommons.java + * + * Created on November 20, 2005, 5:05 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.cc; + +import com.rometools.modules.cc.types.License; +import com.rometools.rome.feed.module.Module; + +/** + * + * @author Robert "kebernet" Cooper + */ +public interface CreativeCommons extends Module { + + public static final String URI = "rome:CreativeCommons"; + + public License[] getAllLicenses(); + + public void setAllLicenses(License[] licenses); + + public License[] getLicenses(); + + public void setLicenses(License[] license); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/cc/CreativeCommonsImpl.java b/rome-modules/src/main/java/com/rometools/modules/cc/CreativeCommonsImpl.java new file mode 100644 index 0000000..1ea754a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/cc/CreativeCommonsImpl.java @@ -0,0 +1,136 @@ +/* + * AbstractCreativeCommons.java + * + * Created on November 20, 2005, 5:12 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.cc; + +import java.lang.reflect.Array; + +import com.rometools.modules.cc.types.License; +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public class CreativeCommonsImpl implements CreativeCommons { + + private static final long serialVersionUID = 1L; + + public static final String RDF_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + public static final String RSS2_URI = "http://backend.userland.com/creativeCommonsRssModule"; + public static final String RSS1_URI = "http://web.resource.org/cc/"; + + private License[] allLicenses; + private License[] licenses; + + protected Object arrayCopy(final Object[] source) { + if (source == null) { + return null; + } + + final Object[] array = (Object[]) Array.newInstance(source.getClass().getComponentType(), source.length); + + for (int i = 0; i < source.length; i++) { + array[i] = source[i]; + } + + return array; + } + + @Override + public License[] getAllLicenses() { + return allLicenses; + } + + @Override + public void setAllLicenses(final License[] allLicenses) { + this.allLicenses = allLicenses; + } + + @Override + public Class getInterface() { + return CreativeCommons.class; + } + + @Override + public String getUri() { + return CreativeCommons.URI; + } + + @Override + public Object clone() { + final CreativeCommonsImpl clone = new CreativeCommonsImpl(); + clone.copyFrom(this); + return clone; + } + + @Override + public void copyFrom(final CopyFrom object) { + final CreativeCommons source = (CreativeCommons) object; + setAllLicenses((License[]) arrayCopy(source.getAllLicenses())); + setLicenses(source.getLicenses()); + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public License[] getLicenses() { + return licenses; + } + + @Override + public void setLicenses(final License[] licenses) { + this.licenses = licenses; + } + + @Override + public String toString() { + final ToStringBean tsb = new ToStringBean(CreativeCommonsImpl.class, this); + return tsb.toString(); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/cc/io/CCModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/cc/io/CCModuleGenerator.java new file mode 100644 index 0000000..de0e065 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/cc/io/CCModuleGenerator.java @@ -0,0 +1,151 @@ +/* + * CCModuleGenerator.java + * + * Created on November 20, 2005, 5:23 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.cc.io; + +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.cc.CreativeCommons; +import com.rometools.modules.cc.CreativeCommonsImpl; +import com.rometools.modules.cc.types.License; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public class CCModuleGenerator implements ModuleGenerator { + + private static final Logger LOG = LoggerFactory.getLogger(CCModuleGenerator.class); + + private static final Namespace RSS1 = Namespace.getNamespace("cc", CreativeCommonsImpl.RSS1_URI); + private static final Namespace RSS2 = Namespace.getNamespace("creativeCommons", CreativeCommonsImpl.RSS2_URI); + private static final Namespace RSS = Namespace.getNamespace("http://purl.org/rss/1.0/"); + private static final Namespace RDF = Namespace.getNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + private static final HashSet NAMESPACES = new HashSet(); + static { + NAMESPACES.add(RSS1); + NAMESPACES.add(RSS2); + NAMESPACES.add(RDF); + } + + /** + * Creates a new instance of CCModuleGenerator + */ + public CCModuleGenerator() { + super(); + } + + @Override + public void generate(final Module module, final Element element) { + Element root = element; + while (root.getParentElement() != null) { + root = root.getParentElement(); + } + if (root.getNamespace().equals(RDF) || root.getNamespace().equals(RSS)) { + generateRSS1((CreativeCommons) module, element); + } else { + generateRSS2((CreativeCommons) module, element); + } + } + + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + @Override + public String getNamespaceUri() { + return CreativeCommons.URI; + } + + private void generateRSS1(final CreativeCommons module, final Element element) { + // throw new RuntimeException( "Generating RSS1 Feeds not currently Supported."); + + LOG.debug(element.getName()); + if (element.getName().equals("channel")) { + // Do all licenses list. + final License[] all = module.getAllLicenses(); + for (final License element2 : all) { + final Element license = new Element("License", RSS1); + license.setAttribute("about", element2.getValue(), RDF); + final License.Behaviour[] permits = element2.getPermits(); + for (int j = 0; permits != null && j < permits.length; j++) { + final Element permit = new Element("permits", RSS1); + permit.setAttribute("resource", permits[j].toString(), RDF); + license.addContent(permit); + } + final License.Behaviour[] requires = element2.getPermits(); + for (int j = 0; requires != null && j < requires.length; j++) { + final Element permit = new Element("requires", RSS1); + permit.setAttribute("resource", permits[j].toString(), RDF); + license.addContent(permit); + } + LOG.debug("Is Root? {}", element.getParentElement()); + element.getParentElement().addContent(license); + } + } + + // Do local licenses + final License[] licenses = module.getLicenses(); + for (final License license2 : licenses) { + final Element license = new Element("license", RSS1); + license.setAttribute("resource", license2.getValue(), RDF); + element.addContent(license); + } + + } + + private void generateRSS2(final CreativeCommons module, final Element element) { + final License[] licenses = module.getLicenses(); + for (int i = 0; licenses != null && i < licenses.length; i++) { + final Element license = new Element("license", RSS2); + license.setText(licenses[i].getValue()); + element.addContent(license); + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/cc/io/ModuleParserRSS1.java b/rome-modules/src/main/java/com/rometools/modules/cc/io/ModuleParserRSS1.java new file mode 100644 index 0000000..04ba046 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/cc/io/ModuleParserRSS1.java @@ -0,0 +1,139 @@ +/* + * CCModuleParser.java + * + * Created on November 20, 2005, 5:23 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.cc.io; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.cc.CreativeCommonsImpl; +import com.rometools.modules.cc.types.License; +import com.rometools.modules.cc.types.License.Behaviour; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; + +/** + * @version $Revision: 1.3 $ + * @author Robert "kebernet" Cooper + */ +public class ModuleParserRSS1 implements ModuleParser { + + private static final Namespace NS = Namespace.getNamespace(CreativeCommonsImpl.RSS1_URI); + static final Namespace RDF = Namespace.getNamespace(CreativeCommonsImpl.RDF_URI); + + /** + * Creates a new instance of ModuleParserRSS1 + */ + public ModuleParserRSS1() { + } + + @Override + public Module parse(final Element element, final Locale locale) { + final CreativeCommonsImpl module = new CreativeCommonsImpl(); + { + // Parsing Channel level. + Element root = element; + while (root.getParentElement() != null) { + root = root.getParentElement(); + } + final List licenseList = root.getChildren("License", NS); + final ArrayList licenses = new ArrayList(); + final Iterator it = licenseList.iterator(); + while (it.hasNext()) { + final Element licenseTag = it.next(); + final String licenseURI = licenseTag.getAttributeValue("about", RDF); + if (licenseURI == null) { + continue; + } + License license = License.findByValue(licenseURI); + { + final ArrayList permitsValues = new ArrayList(); + final ArrayList requiresValues = new ArrayList(); + final List permitsTags = licenseTag.getChildren("permits", NS); + Iterator sit = permitsTags.iterator(); + while (sit.hasNext()) { + final Element permitTag = sit.next(); + permitsValues.add(License.Behaviour.findByValue(permitTag.getAttributeValue("resource", RDF))); + } + final List requiresTags = licenseTag.getChildren("requires", NS); + sit = requiresTags.iterator(); + while (sit.hasNext()) { + final Element requireTag = sit.next(); + requiresValues.add(License.Behaviour.findByValue(requireTag.getAttributeValue("resource", RDF))); + } + license = new License(licenseURI, requiresValues.toArray(new License.Behaviour[requiresValues.size()]), + permitsValues.toArray(new License.Behaviour[permitsValues.size()])); + + } + + licenses.add(license); + } + module.setAllLicenses(licenses.toArray(new License[0])); + } + final ArrayList licenses = new ArrayList(); + final List licenseTags = element.getChildren("license", NS); + final Iterator lit = licenseTags.iterator(); + while (lit.hasNext()) { + final Element licenseTag = lit.next(); + licenses.add(License.findByValue(licenseTag.getAttributeValue("resource", RDF))); + } + + if (!licenses.isEmpty()) { + module.setLicenses(licenses.toArray(new License[licenses.size()])); + } + + if (module.getLicenses() != null || module.getAllLicenses() != null) { + return module; + } else { + return null; + } + } + + @Override + public String getNamespaceUri() { + return CreativeCommonsImpl.RSS1_URI; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/cc/io/ModuleParserRSS2.java b/rome-modules/src/main/java/com/rometools/modules/cc/io/ModuleParserRSS2.java new file mode 100644 index 0000000..8030c68 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/cc/io/ModuleParserRSS2.java @@ -0,0 +1,127 @@ +/* + * ModuleParserRSS2.java + * + * Created on November 20, 2005, 6:15 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.cc.io; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.cc.CreativeCommonsImpl; +import com.rometools.modules.cc.types.License; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; + +/** + * + * @version $Revision: 1.3 $ + * @author Robert "kebernet" Cooper + */ +public class ModuleParserRSS2 implements ModuleParser { + + private static final Namespace NS = Namespace.getNamespace(CreativeCommonsImpl.RSS2_URI); + + /** Creates a new instance of ModuleParserRSS2 */ + public ModuleParserRSS2() { + } + + @Override + public Module parse(final Element element, final Locale locale) { + final CreativeCommonsImpl module = new CreativeCommonsImpl(); + // Do channel global + { + Element root = element; + while (!root.getName().equals("channel") && !root.getName().equals("feed")) { + root = root.getParentElement(); + } + final ArrayList licenses = new ArrayList(); + List items = null; + if (root.getName().equals("channel")) { + items = root.getChildren("item"); + } else { + items = root.getChildren("entry"); + } + + final Iterator iit = items.iterator(); + while (iit.hasNext()) { + final Element item = iit.next(); + final List licenseTags = item.getChildren("license", NS); + final Iterator lit = licenseTags.iterator(); + while (lit.hasNext()) { + final Element licenseTag = lit.next(); + final License license = License.findByValue(licenseTag.getTextTrim()); + if (!licenses.contains(license)) { + ; + } + licenses.add(license); + } + } + if (!licenses.isEmpty()) { + module.setAllLicenses(licenses.toArray(new License[0])); + } + } + // do element local + final ArrayList licenses = new ArrayList(); + final List licenseTags = element.getChildren("license", NS); + final Iterator it = licenseTags.iterator(); + while (it.hasNext()) { + final Element licenseTag = it.next(); + licenses.add(License.findByValue(licenseTag.getTextTrim())); + } + if (!licenses.isEmpty()) { + module.setLicenses(licenses.toArray(new License[0])); + } + + if (module.getLicenses() != null && module.getAllLicenses() != null) { + return module; + } else { + return null; + } + } + + @Override + public String getNamespaceUri() { + return CreativeCommonsImpl.RSS2_URI; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/cc/package.html b/rome-modules/src/main/java/com/rometools/modules/cc/package.html new file mode 100644 index 0000000..0a0fbb7 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/cc/package.html @@ -0,0 +1,80 @@ + + + + + + + + This is a module for ROME that supports both the + "CC" RSS1 module and the + RSS 2 (and Atom) + module in a unified manner. + +

It does this by superimposing the "rome:creativecommon" namespace over both of them + for the purposes of the module, and synchronizes them into a unified structure. For RSS2 + it attempts to correlate the license into a code-capable fashion. If the license link + goes to one of the standard licenses at creativecommons.org, it will populate the permissions + based on it's know set (See License.Behaviour).

+ +

The module has 2 fields on it. One is "allLicenses". This is simply an array of all licenses + in a feed. The second one "licenses" contains licenses that apply to a specific element (feed or + entry). Licenses then contain "permits" and "requires" behaviours. If a license is used that + the system can't determine anything about, these will be null. Zero-lenght means "known and + empty."

+ +

At this time, because of a ROME limitation, writing RSS1 feeds is not possible. However, + if you read an RSS1 feed, you can convert it to an RSS2 feed properly.

+ +

Sample Usage: +

+        
+        CreativeCommons commons = new CreativeCommonsImpl();
+        commons.setLicense( new License[]{ License.NONCOMMERCIAL } );
+        // Note, you do not have to setAllLicenses right now. When the RSS1 functionality is
+        // added, this will be required at the Feed level only.
+        ArrayList modules = new ArrayList()
+        modules.add( commons );
+        syndEntry.setModules( commons );
+        
+        //Alternately, to get the module:
+        CreativeCommons commons = (CreativeCommons) syndFeed.getModule( CreativeCommons.URI );
+        
+    
+

+
+ * This library is provided under dual licenses. 
+ * You may choose the terms of the Lesser General Public License or the Apache
+ * License at your discretion.
+ *
+ *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * 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/rome-modules/src/main/java/com/rometools/modules/cc/types/License.java b/rome-modules/src/main/java/com/rometools/modules/cc/types/License.java new file mode 100644 index 0000000..29ec5eb --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/cc/types/License.java @@ -0,0 +1,197 @@ +/* + * LicenseEnumeration.java + * + * Created on November 20, 2005, 3:20 PM + * + * This library is provided under dual licenses. You may choose the terms of the Lesser General + * Public License or the Apache License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; either version + * 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * + * 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.rometools.modules.cc.types; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public class License { + + private static final String CC_START = "http://creativecommons.org/licenses/"; + private static final Map lookupLicense = new ConcurrentHashMap(); + private static final Logger LOG = LoggerFactory.getLogger(License.class); + public static final License NO_DERIVS = new License("http://creativecommons.org/licenses/nd/1.0/", new Behaviour[0], new Behaviour[] { + Behaviour.DISTRIBUTION, Behaviour.REPRODUCTION}); + public static final License NO_DERIVS_NONCOMMERCIAL = new License("http://creativecommons.org/licenses/nd-nc/1.0/", + new Behaviour[] {Behaviour.NONCOMMERCIAL}, new Behaviour[] {Behaviour.DISTRIBUTION, Behaviour.REPRODUCTION}); + public static final License NONCOMMERCIAL = new License("http://creativecommons.org/licenses/nc/1.0/", new Behaviour[] {Behaviour.NONCOMMERCIAL}, + new Behaviour[] {Behaviour.DERIVATIVE, Behaviour.DISTRIBUTION, Behaviour.REPRODUCTION}); + public static final License SHARE_ALIKE = new License("http://creativecommons.org/licenses/sa/1.0/", new Behaviour[] {Behaviour.COPYLEFT}, new Behaviour[] { + Behaviour.DERIVATIVE, Behaviour.DISTRIBUTION, Behaviour.REPRODUCTION}); + public static final License SHARE_ALIKE_NONCOMMERCIAL = new License("http://creativecommons.org/licenses/nc-sa/1.0/", new Behaviour[] {Behaviour.COPYLEFT, + Behaviour.NONCOMMERCIAL}, new Behaviour[] {Behaviour.DERIVATIVE, Behaviour.DISTRIBUTION, Behaviour.REPRODUCTION}); + public static final License SHARE_ALIKE_ATTRIBUTION = new License("http://creativecommons.org/licenses/by-sa/2.5/", new Behaviour[] {Behaviour.COPYLEFT, + Behaviour.ATTRIBUTION}, new Behaviour[] {Behaviour.DERIVATIVE, Behaviour.DISTRIBUTION, Behaviour.REPRODUCTION}); + public static final License SHARE_ALIKE_NONCOMMERCIAL_ATTRIBUTION = new License("http://creativecommons.org/licenses/by-nc-sa/2.5/", new Behaviour[] { + Behaviour.COPYLEFT, Behaviour.ATTRIBUTION, Behaviour.NONCOMMERCIAL}, new Behaviour[] {Behaviour.DERIVATIVE, Behaviour.DISTRIBUTION, + Behaviour.REPRODUCTION}); + public static final License NONCOMMERCIAL_ATTRIBUTION = new License("http://creativecommons.org/licenses/by-nc/2.5/", new Behaviour[] { + Behaviour.ATTRIBUTION, Behaviour.NONCOMMERCIAL}, new Behaviour[] {Behaviour.DERIVATIVE, Behaviour.DISTRIBUTION, Behaviour.REPRODUCTION}); + public static final License NONCOMMERCIAL_ATTRIBUTION_NO_DERIVS = new License("http://creativecommons.org/licenses/by-nc-nd/2.5/", new Behaviour[] { + Behaviour.ATTRIBUTION, Behaviour.NONCOMMERCIAL}, new Behaviour[] {Behaviour.DISTRIBUTION, Behaviour.REPRODUCTION}); + public static final License ATTRIBUTION_NO_DERIVS = new License("http://creativecommons.org/licenses/by-nd/2.5/", new Behaviour[] {Behaviour.ATTRIBUTION}, + new Behaviour[] {Behaviour.DISTRIBUTION, Behaviour.REPRODUCTION}); + public static final License ATTRIBUTION = new License("http://creativecommons.org/licenses/by/2.5/", new Behaviour[] {Behaviour.ATTRIBUTION}, + new Behaviour[] {Behaviour.DERIVATIVE, Behaviour.DISTRIBUTION, Behaviour.REPRODUCTION}); + private final String uri; + private final Behaviour[] permits; + private final Behaviour[] requires; + + /** + * Creates a new instance of License + */ + public License(final String uri, final Behaviour[] requires, final Behaviour[] permits) { + this.requires = requires; + this.permits = permits; + this.uri = uri; + License.lookupLicense.put(uri, this); + + if (this.uri.endsWith("/")) { + // LOG.debug(uri.substring(0,this.uri.lastIndexOf("/"))); + License.lookupLicense.put(uri.substring(0, this.uri.lastIndexOf("/")), this); + } + } + + public static License findByValue(final String uri) { + License found = License.lookupLicense.get(uri); + + // No I am going to try an guess about unknown licenses + // This is try and match known CC licenses of other versions or various URLs to + // current licenses, then make a new one with the same permissions. + if (found == null && uri.startsWith("http://") && uri.toLowerCase().indexOf("creativecommons.org") != -1) { + final Iterator it = License.lookupLicense.keySet().iterator(); + while (it.hasNext() && found == null) { + final String key = it.next(); + try { + if (key.startsWith(CC_START)) { + final String licensePath = key.substring(CC_START.length(), key.length()); + final StringTokenizer tok = new StringTokenizer(licensePath, "/"); + final String license = tok.nextToken(); + // final String version = tok.nextToken(); + if (uri.toLowerCase().indexOf("creativecommons.org/licenses/" + license) != -1) { + final License current = lookupLicense.get(key); + found = new License(uri, current.getRequires(), current.getPermits()); + } + } + } catch (final Exception e) { + LOG.error("Error", e); + } + } + } + // OK, we got here. If we haven't found a match, return a new License with unknown + // permissions. + if (found == null) { + found = new License(uri, null, null); + } + return found; + } + + /** + * This is just useful for testing to allow clearing of the looked up licenses. + */ + static void clear() { + lookupLicense.clear(); + } + + public Behaviour[] getPermits() { + return permits; + } + + public Behaviour[] getRequires() { + return requires; + } + + @Override + public String toString() { + + final ToStringBean tsb = new ToStringBean(License.class, this); + return tsb.toString(); + } + + public String getValue() { + return uri; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(License.class, this); + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(License.class, this); + return equals.beanHashCode(); + } + + public static class Behaviour { + private static final Map lookup = new HashMap(); + public static final Behaviour REPRODUCTION = new Behaviour("http://web.resource.org/cc/Reproduction"); + public static final Behaviour DISTRIBUTION = new Behaviour("http://web.resource.org/cc/Distribution"); + public static final Behaviour DERIVATIVE = new Behaviour("http://web.resource.org/cc/DerivativeWorks"); + public static final Behaviour NOTICE = new Behaviour("http://web.resource.org/cc/Notice"); + public static final Behaviour ATTRIBUTION = new Behaviour("http://web.resource.org/cc/Attribution"); + public static final Behaviour COPYLEFT = new Behaviour("http://web.resource.org/cc/Copyleft"); + public static final Behaviour NONCOMMERCIAL = new Behaviour("http://web.resource.org/cc/Noncommercial"); + private final String uri; + + private Behaviour(final String uri) { + this.uri = uri; + Behaviour.lookup.put(uri, this); + } + + public static Behaviour findByValue(final String uri) { + return Behaviour.lookup.get(uri); + } + + @Override + public String toString() { + return uri; + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/cc/types/package.html b/rome-modules/src/main/java/com/rometools/modules/cc/types/package.html new file mode 100644 index 0000000..d1ef41e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/cc/types/package.html @@ -0,0 +1,45 @@ + + + + + + + +This package contains datatypes for use with the plug in. +
+ * This library is provided under dual licenses. 
+ * You may choose the terms of the Lesser General Public License or the Apache
+ * License at your discretion.
+ *
+ *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * 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/rome-modules/src/main/java/com/rometools/modules/content/ContentItem.java b/rome-modules/src/main/java/com/rometools/modules/content/ContentItem.java new file mode 100644 index 0000000..34f95e3 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/content/ContentItem.java @@ -0,0 +1,211 @@ +/* + * ContentItem.java + * + * Created on January 12, 2005, 8:52 AM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.content; + +import java.util.List; + +import org.jdom2.Content; +import org.jdom2.Namespace; + +/** + * This class represents a content item per the "Original Syntax". + * http://purl.org/rss/1.0/modules/content/ + * + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public class ContentItem implements Cloneable { + + private String contentFormat; + private String contentEncoding; + private String contentValue; + private List contentValueDOM; + private String contentAbout; + private String contentValueParseType; + private List contentValueNamespace; + private String contentResource; + + /** Creates a new instance of ContentItem */ + public ContentItem() { + } + + public String getContentFormat() { + return contentFormat; + } + + public void setContentFormat(final String contentFormat) { + this.contentFormat = contentFormat; + } + + public String getContentEncoding() { + return contentEncoding; + } + + public void setContentEncoding(final String contentEncoding) { + this.contentEncoding = contentEncoding; + } + + public String getContentValue() { + return contentValue; + } + + public void setContentValue(final String contentValue) { + this.contentValue = contentValue; + } + + public List getContentValueDOM() { + return contentValueDOM; + } + + public void setContentValueDOM(final List contentValueDOM) { + this.contentValueDOM = contentValueDOM; + } + + public String getContentAbout() { + return contentAbout; + } + + public void setContentAbout(final String contentAbout) { + this.contentAbout = contentAbout; + } + + public String getContentValueParseType() { + return contentValueParseType; + } + + public void setContentValueParseType(final String contentValueParseType) { + this.contentValueParseType = contentValueParseType; + } + + public List getContentValueNamespaces() { + return contentValueNamespace; + } + + public void setContentValueNamespaces(final List contentValueNamespace) { + this.contentValueNamespace = contentValueNamespace; + } + + public String getContentResource() { + return contentResource; + } + + public void setContentResource(final String contentResource) { + this.contentResource = contentResource; + } + + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ContentItem other = (ContentItem) obj; + if (contentFormat == null ? other.contentFormat != null : !contentFormat.equals(other.contentFormat)) { + // LOG.debug("format"); + return false; + } + if (contentEncoding == null ? other.contentEncoding != null : !contentEncoding.equals(other.contentEncoding)) { + // LOG.debug("enc"); + return false; + } + final String thisCV = contentValue.replaceAll(" xmlns=\"http://www.w3.org/1999/xhtml\"", "").trim(); + ; + final String thatCV = other.contentValue.replaceAll(" xmlns=\"http://www.w3.org/1999/xhtml\"", "").trim(); + if (contentValue == null ? other.contentValue != null : !thisCV.equals(thatCV)) { + + return false; + } + if (contentValueDOM != other.contentValueDOM && (contentValueDOM == null || !contentValueDOM.equals(other.contentValueDOM))) { + // LOG.debug("vd"); + return false; + } + if (contentAbout == null ? other.contentAbout != null : !contentAbout.equals(other.contentAbout)) { + // LOG.debug("abt"); + return false; + } + if (contentValueParseType == null ? other.contentValueParseType != null : !contentValueParseType.equals(other.contentValueParseType)) { + // LOG.debug("pt"); + return false; + } + if (contentValueNamespace != other.contentValueNamespace + && (contentValueNamespace == null || !contentValueNamespace.equals(other.contentValueNamespace))) { + // LOG.debug("ns"); + return false; + } + if (contentResource == null ? other.contentResource != null : !contentResource.equals(other.contentResource)) { + // LOG.debug("res"); + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + (contentFormat != null ? contentFormat.hashCode() : 0); + hash = 97 * hash + (contentEncoding != null ? contentEncoding.hashCode() : 0); + hash = 97 * hash + (contentValue != null ? contentValue.hashCode() : 0); + hash = 97 * hash + (contentValueDOM != null ? contentValueDOM.hashCode() : 0); + hash = 97 * hash + (contentAbout != null ? contentAbout.hashCode() : 0); + hash = 97 * hash + (contentValueParseType != null ? contentValueParseType.hashCode() : 0); + hash = 97 * hash + (contentValueNamespace != null ? contentValueNamespace.hashCode() : 0); + hash = 97 * hash + (contentResource != null ? contentResource.hashCode() : 0); + return hash; + } + + @Override + public Object clone() { + final ContentItem o = new ContentItem(); + o.contentAbout = contentAbout; + o.contentEncoding = contentEncoding; + o.contentFormat = contentFormat; + o.contentResource = contentResource; + o.contentValue = contentValue; + o.contentValueDOM = contentValueDOM; + o.contentValueNamespace = contentValueNamespace; + o.contentValueParseType = contentValueParseType; + + return o; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/content/ContentModule.java b/rome-modules/src/main/java/com/rometools/modules/content/ContentModule.java new file mode 100644 index 0000000..342701d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/content/ContentModule.java @@ -0,0 +1,106 @@ +/* + * ContentModule.java + * + * Created on January 11, 2005, 1:02 PM + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.content; + +import java.util.List; + +import com.rometools.rome.feed.module.Module; + +/** + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public interface ContentModule extends Module { + + public static final String URI = "http://purl.org/rss/1.0/modules/content/"; + public static final String RDF_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + + /** + * Returns a List of Strings containing the New Syntax Encoded values are in the element. + * + * @return List of content Strings + */ + public List getEncodeds(); + + /** + * Sets a List of Strings containing the New Syntax Encoded values are in the element. + * + * @return List of content Strings + */ + public void setEncodeds(List encodeds); + + @Override + public String getUri(); + + public String toString(String str); + + /** + * Contains a list of ContentItems that represent the "Original Syntax" set. + * + * @see com.totsp.xml.syndication.content.ContentItem + * @return List of ContentItems. + */ + public List getContentItems(); + + /** + * Contains a list of ContentItems that represent the "Original Syntax" set. + * + * @see com.totsp.xml.syndication.content.ContentItem + * @param List of ContentItems. + */ + public void setContentItems(List list); + + /** + * Returns a List of Strings containing whatever new or original syntax items are in the + * element. + * + * @return List of content Strings + */ + public List getContents(); + + /** + * Sets a List of Strings containing whatever new or original syntax items are in the element. + * + * @return List of content Strings + */ + public void setContents(List contents); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/content/ContentModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/content/ContentModuleImpl.java new file mode 100644 index 0000000..e0e345d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/content/ContentModuleImpl.java @@ -0,0 +1,122 @@ +/* + * ContentModuleImpl.java + * + * Created on January 11, 2005, 1:07 PM + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.content; + +import java.util.ArrayList; +import java.util.List; + +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.module.ModuleImpl; + +/** + * @version $Revision: 1.4 $ + * @author Robert "kebernet" Cooper + */ +public class ContentModuleImpl extends ModuleImpl implements ContentModule { + + private static final long serialVersionUID = 1L; + + private List encodeds; + private List contents; + private List contentItems; + + public ContentModuleImpl() { + super(ContentModuleImpl.class, URI); + } + + protected ContentModuleImpl(final Class beanClass, final java.lang.String uri) { + super(beanClass, uri); + } + + @Override + public List getEncodeds() { + encodeds = encodeds == null ? new ArrayList() : encodeds; + return encodeds; + } + + @Override + public void setEncodeds(final List encodeds) { + this.encodeds = encodeds; + } + + @Override + public void copyFrom(final CopyFrom obj) { + final ContentModule cm = (ContentModule) obj; + setEncodeds(cm.getEncodeds()); + setContentItems(cm.getContentItems()); + setContents(cm.getContents()); + } + + @Override + public Class getInterface() { + return ContentModule.class; + } + + @Override + public List getContentItems() { + contentItems = contentItems == null ? new ArrayList() : contentItems; + return contentItems; + } + + @Override + public void setContentItems(final List list) { + contentItems = list; + } + + @Override + public List getContents() { + contents = contents == null ? new ArrayList() : contents; + return contents; + } + + @Override + public void setContents(final List contents) { + this.contents = contents; + } + + @Override + public String toString(final String str) { + return contentItems.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/content/io/ContentModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/content/io/ContentModuleGenerator.java new file mode 100644 index 0000000..3c9126c --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/content/io/ContentModuleGenerator.java @@ -0,0 +1,201 @@ +/* + * ContentModuleGenerator.java + * + * Created on January 11, 2005, 1:41 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.content.io; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jdom2.Attribute; +import org.jdom2.CDATA; +import org.jdom2.Content; +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.content.ContentItem; +import com.rometools.modules.content.ContentModule; + +/** + * @version $Revision: 1.2 $ + * @author Robert "kebernet" Cooper + */ +public class ContentModuleGenerator implements com.rometools.rome.io.ModuleGenerator { + + private static final Logger LOG = LoggerFactory.getLogger(ContentModuleGenerator.class); + + private static final Namespace CONTENT_NS = Namespace.getNamespace("content", ContentModule.URI); + private static final Namespace RDF_NS = Namespace.getNamespace("rdf", ContentModule.RDF_URI); + private static final Set NAMESPACES; + + static { + final Set nss = new HashSet(); + nss.add(CONTENT_NS); + NAMESPACES = Collections.unmodifiableSet(nss); + } + + /** Creates a new instance of ContentModuleGenerator */ + public ContentModuleGenerator() { + } + + @Override + public void generate(final com.rometools.rome.feed.module.Module module, final org.jdom2.Element element) { + // this is not necessary, it is done to avoid the namespace definition in every item. + Element root = element; + + while (root.getParent() != null && root.getParent() instanceof Element) { + root = (Element) root.getParent(); + } + + root.addNamespaceDeclaration(CONTENT_NS); + + if (!(module instanceof ContentModule)) { + return; + } + + final ContentModule cm = (ContentModule) module; + + final List encodeds = cm.getEncodeds(); + + if (encodeds != null) { + LOG.debug("{}", cm.getEncodeds().size()); + for (int i = 0; i < encodeds.size(); i++) { + element.addContent(generateCDATAElement("encoded", encodeds.get(i).toString())); + } + } + + final List contentItems = cm.getContentItems(); + + if (contentItems != null && !contentItems.isEmpty()) { + final Element items = new Element("items", CONTENT_NS); + final Element bag = new Element("Bag", RDF_NS); + items.addContent(bag); + + for (int i = 0; i < contentItems.size(); i++) { + final ContentItem contentItem = contentItems.get(i); + final Element li = new Element("li", RDF_NS); + final Element item = new Element("item", CONTENT_NS); + + if (contentItem.getContentAbout() != null) { + final Attribute about = new Attribute("about", contentItem.getContentAbout(), RDF_NS); + item.setAttribute(about); + } + + if (contentItem.getContentFormat() != null) { + // LOG.debug( "Format"); + final Element format = new Element("format", CONTENT_NS); + final Attribute formatResource = new Attribute("resource", contentItem.getContentFormat(), RDF_NS); + format.setAttribute(formatResource); + + item.addContent(format); + } + + if (contentItem.getContentEncoding() != null) { + // LOG.debug( "Encoding"); + final Element encoding = new Element("encoding", CONTENT_NS); + final Attribute encodingResource = new Attribute("resource", contentItem.getContentEncoding(), RDF_NS); + encoding.setAttribute(encodingResource); + item.addContent(encoding); + } + + if (contentItem.getContentValue() != null) { + final Element value = new Element("value", RDF_NS); + + if (contentItem.getContentValueParseType() != null) { + final Attribute parseType = new Attribute("parseType", contentItem.getContentValueParseType(), RDF_NS); + value.setAttribute(parseType); + } + + if (contentItem.getContentValueNamespaces() != null) { + final List namespaces = contentItem.getContentValueNamespaces(); + + for (int ni = 0; ni < namespaces.size(); ni++) { + value.addNamespaceDeclaration(namespaces.get(ni)); + } + } + + final List detached = new ArrayList(); + + for (int c = 0; c < contentItem.getContentValueDOM().size(); c++) { + detached.add(contentItem.getContentValueDOM().get(c).clone().detach()); + } + + value.setContent(detached); + item.addContent(value); + } // end value + + li.addContent(item); + bag.addContent(li); + } // end contentItems loop + + element.addContent(items); + } + } + + protected Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, CONTENT_NS); + element.addContent(value); + + return element; + } + + protected Element generateCDATAElement(final String name, final String value) { + final Element element = new Element(name, CONTENT_NS); + final CDATA cdata = new CDATA(value); + element.addContent(cdata); + + return element; + } + + @Override + public String getNamespaceUri() { + return ContentModule.URI; + } + + @Override + public Set getNamespaces() { + return NAMESPACES; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/content/io/ContentModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/content/io/ContentModuleParser.java new file mode 100644 index 0000000..61e4c92 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/content/io/ContentModuleParser.java @@ -0,0 +1,163 @@ +/* + * ContentModuleParser.java + * + * Created on January 11, 2005, 1:23 PM + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.content.io; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Attribute; +import org.jdom2.Content; +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.jdom2.output.XMLOutputter; + +import com.rometools.modules.content.ContentItem; +import com.rometools.modules.content.ContentModule; +import com.rometools.modules.content.ContentModuleImpl; + +/** + * @version $Revision: 1.3 $ + * @author Robert "kebernet" Cooper + */ +public class ContentModuleParser implements com.rometools.rome.io.ModuleParser { + private static final Namespace CONTENT_NS = Namespace.getNamespace("content", ContentModule.URI); + private static final Namespace RDF_NS = Namespace.getNamespace("rdf", ContentModule.RDF_URI); + + /** Creates a new instance of ContentModuleParser */ + public ContentModuleParser() { + } + + @Override + public String getNamespaceUri() { + return ContentModule.URI; + } + + @Override + public com.rometools.rome.feed.module.Module parse(final Element element, final Locale locale) { + boolean foundSomething = false; + final ContentModule cm = new ContentModuleImpl(); + final List encodeds = element.getChildren("encoded", CONTENT_NS); + final ArrayList contentStrings = new ArrayList(); + final ArrayList encodedStrings = new ArrayList(); + + if (!encodeds.isEmpty()) { + foundSomething = true; + + for (int i = 0; i < encodeds.size(); i++) { + final Element encodedElement = encodeds.get(i); + encodedStrings.add(encodedElement.getText()); + contentStrings.add(encodedElement.getText()); + } + } + + final ArrayList contentItems = new ArrayList(); + final List items = element.getChildren("items", CONTENT_NS); + + for (int i = 0; i < items.size(); i++) { + foundSomething = true; + + final List lis = items.get(i).getChild("Bag", RDF_NS).getChildren("li", RDF_NS); + + for (int j = 0; j < lis.size(); j++) { + final ContentItem ci = new ContentItem(); + final Element li = lis.get(j); + final Element item = li.getChild("item", CONTENT_NS); + final Element format = item.getChild("format", CONTENT_NS); + final Element encoding = item.getChild("encoding", CONTENT_NS); + final Element value = item.getChild("value", RDF_NS); + + if (value != null) { + if (value.getAttributeValue("parseType", RDF_NS) != null) { + ci.setContentValueParseType(value.getAttributeValue("parseType", RDF_NS)); + } + + if (ci.getContentValueParseType() != null && ci.getContentValueParseType().equals("Literal")) { + ci.setContentValue(getXmlInnerText(value)); + contentStrings.add(getXmlInnerText(value)); + ci.setContentValueNamespaces(value.getAdditionalNamespaces()); + } else { + ci.setContentValue(value.getText()); + contentStrings.add(value.getText()); + } + + ci.setContentValueDOM(value.clone().getContent()); + } + + if (format != null) { + ci.setContentFormat(format.getAttribute("resource", RDF_NS).getValue()); + } + + if (encoding != null) { + ci.setContentEncoding(encoding.getAttribute("resource", RDF_NS).getValue()); + } + + if (item != null) { + final Attribute about = item.getAttribute("about", RDF_NS); + + if (about != null) { + ci.setContentAbout(about.getValue()); + } + } + + contentItems.add(ci); + } + } + + cm.setEncodeds(encodedStrings); + cm.setContentItems(contentItems); + cm.setContents(contentStrings); + + return foundSomething ? cm : null; + } + + protected String getXmlInnerText(final Element e) { + final StringBuffer sb = new StringBuffer(); + final XMLOutputter xo = new XMLOutputter(); + final List children = e.getContent(); + sb.append(xo.outputString(children)); + + return sb.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/content/package.html b/rome-modules/src/main/java/com/rometools/modules/content/package.html new file mode 100644 index 0000000..3d84caf --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/content/package.html @@ -0,0 +1,66 @@ + + + + + + + + + This is a ROME plug in that implements the Content RSS extension. + http://purl.org/rss/1.0/modules/content/ + + Note, this supports both the "Original" syntax via the ContentItem object + and the "New" Syntax via the ".getEncodeds()" method on the ContentModule. + +

Sample Usage:

+
+        SyndFeedInput input = new SyndFeedInput();
+        SyndFeed syndfeed = input.build(new XmlReader(feed.toURL()));
+
+        Module module = syndfeed.getModule("http://purl.org/rss/1.0/modules/content/");
+        ContentModule content = (ContentModule) module;
+        
+        Iterator it = content.getEncodeds().iterator();
+        System.out.println( it.next() );
+    
+ + + + +
+ * This library is provided under dual licenses.
+ * You may choose the terms of the Lesser General Public License or the Apache
+ * License at your discretion.
+ *
+ *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * 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/rome-modules/src/main/java/com/rometools/modules/feedburner/FeedBurner.java b/rome-modules/src/main/java/com/rometools/modules/feedburner/FeedBurner.java new file mode 100644 index 0000000..d1619a4 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/feedburner/FeedBurner.java @@ -0,0 +1,47 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.feedburner; + +import java.io.Serializable; + +import com.rometools.rome.feed.module.Module; + +/** + * Interface for the FeedBurner RSS extension. + * + * @version 1.0 + * @author Georg Schmidl + * + */ +public interface FeedBurner extends Module, Serializable, Cloneable { + + public static final String URI = "http://rssnamespace.org/feedburner/ext/1.0"; + + public String getAwareness(); + + public void setAwareness(String awareness); + + public String getOrigLink(); + + public void setOrigLink(String origLink); + + public String getOrigEnclosureLink(); + + public void setOrigEnclosureLink(String origEnclosureLink); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/feedburner/FeedBurnerImpl.java b/rome-modules/src/main/java/com/rometools/modules/feedburner/FeedBurnerImpl.java new file mode 100644 index 0000000..cf74014 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/feedburner/FeedBurnerImpl.java @@ -0,0 +1,91 @@ +/* + * Copyright 2010 Scandio GmbH. + * + * 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.rometools.modules.feedburner; + +import com.rometools.rome.feed.CopyFrom; + +/** + * Implementation of the FeedBurner RSS extension. + * + * @version 1.0 + * @author Georg Schmidl + * + */ +public class FeedBurnerImpl implements FeedBurner { + + private static final long serialVersionUID = 1L; + + private String awareness; + private String origLink; + private String origEnclosureLink; + + @Override + public String getAwareness() { + return awareness; + } + + @Override + public void setAwareness(final String awareness) { + this.awareness = awareness; + } + + @Override + public String getOrigLink() { + return origLink; + } + + @Override + public void setOrigLink(final String origLink) { + this.origLink = origLink; + } + + @Override + public String getOrigEnclosureLink() { + return origEnclosureLink; + } + + @Override + public void setOrigEnclosureLink(final String origEnclosureLink) { + this.origEnclosureLink = origEnclosureLink; + } + + @Override + public String getUri() { + return FeedBurner.URI; + } + + @Override + public void copyFrom(final CopyFrom object) { + final FeedBurner source = (FeedBurner) object; + setAwareness(source.getAwareness()); + setOrigLink(source.getOrigLink()); + setOrigEnclosureLink(source.getOrigEnclosureLink()); + } + + @Override + public Class getInterface() { + return FeedBurner.class; + } + + @Override + public Object clone() { + final FeedBurnerImpl fbi = new FeedBurnerImpl(); + fbi.copyFrom(this); + return fbi; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/feedburner/io/FeedBurnerModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/feedburner/io/FeedBurnerModuleGenerator.java new file mode 100644 index 0000000..9406f04 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/feedburner/io/FeedBurnerModuleGenerator.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 Scandio GmbH. + * + * 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.rometools.modules.feedburner.io; + +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.feedburner.FeedBurner; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * ModuleGenerator implementation for the FeedBurner RSS extension. + * + * @version 1.0 + * @author Georg Schmidl + * + */ +public class FeedBurnerModuleGenerator implements ModuleGenerator { + private static final Namespace NS = Namespace.getNamespace("feedburner", FeedBurner.URI); + + @Override + public String getNamespaceUri() { + return FeedBurner.URI; + } + + @Override + public Set getNamespaces() { + final HashSet set = new HashSet(); + set.add(FeedBurnerModuleGenerator.NS); + return set; + } + + @Override + public void generate(final Module module, final Element element) { + if (!(module instanceof FeedBurner)) { + return; + } + + final FeedBurner feedBurner = (FeedBurner) module; + + if (feedBurner.getAwareness() != null) { + element.addContent(generateSimpleElement("awareness", feedBurner.getAwareness())); + } + + if (feedBurner.getOrigLink() != null) { + element.addContent(generateSimpleElement("origLink", feedBurner.getOrigLink())); + } + + if (feedBurner.getOrigEnclosureLink() != null) { + element.addContent(generateSimpleElement("origEnclosureLink", feedBurner.getOrigEnclosureLink())); + } + } + + protected Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, FeedBurnerModuleGenerator.NS); + element.addContent(value); + + return element; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/feedburner/io/FeedBurnerModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/feedburner/io/FeedBurnerModuleParser.java new file mode 100644 index 0000000..ad124ff --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/feedburner/io/FeedBurnerModuleParser.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 Scandio GmbH. + * + * 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.rometools.modules.feedburner.io; + +import java.util.Locale; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.feedburner.FeedBurner; +import com.rometools.modules.feedburner.FeedBurnerImpl; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; + +/** + * ModuleParser implementation for the FeedBurner RSS extension. + * + * @version 1.0 + * @author Georg Schmidl + * + */ +public class FeedBurnerModuleParser implements ModuleParser { + private static final Namespace NS = Namespace.getNamespace(FeedBurner.URI); + + @Override + public String getNamespaceUri() { + return FeedBurner.URI; + } + + @Override + public Module parse(final Element element, final Locale locale) { + final FeedBurnerImpl fbi = new FeedBurnerImpl(); + boolean returnObj = false; + Element tag = element.getChild("awareness", FeedBurnerModuleParser.NS); + + if (tag != null) { + fbi.setAwareness(tag.getText().trim()); + returnObj = true; + } + + tag = element.getChild("origLink", FeedBurnerModuleParser.NS); + + if (tag != null) { + fbi.setOrigLink(tag.getText().trim()); + returnObj = true; + } + + tag = element.getChild("origEnclosureLink", FeedBurnerModuleParser.NS); + + if (tag != null) { + fbi.setOrigEnclosureLink(tag.getText().trim()); + returnObj = true; + } + + if (returnObj) { + return fbi; + } + + return null; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/feedburner/package.html b/rome-modules/src/main/java/com/rometools/modules/feedburner/package.html new file mode 100644 index 0000000..6591aaf --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/feedburner/package.html @@ -0,0 +1,30 @@ + + + + + + + + + +
+ * This library is provided under dual licenses.
+ * You may choose the terms of the Lesser General Public License or the Apache
+ * License at your discretion.
+ *
+ *  Copyright (C) 2011 The ROME Team
+ *
+ * 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.
+    
+ + \ No newline at end of file diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/GMLGenerator.java b/rome-modules/src/main/java/com/rometools/modules/georss/GMLGenerator.java new file mode 100644 index 0000000..b83a0f7 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/GMLGenerator.java @@ -0,0 +1,173 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.georss.geometries.AbstractGeometry; +import com.rometools.modules.georss.geometries.AbstractRing; +import com.rometools.modules.georss.geometries.Envelope; +import com.rometools.modules.georss.geometries.LineString; +import com.rometools.modules.georss.geometries.LinearRing; +import com.rometools.modules.georss.geometries.Point; +import com.rometools.modules.georss.geometries.Polygon; +import com.rometools.modules.georss.geometries.Position; +import com.rometools.modules.georss.geometries.PositionList; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * GMLGenerator produces georss elements in georss GML format. + * + * @author Marc Wick + * @version $Id: GMLGenerator.java,v 1.1 2007/04/18 09:59:29 marcwick Exp $ + * + */ +public class GMLGenerator implements ModuleGenerator { + + private static final Set NAMESPACES; + + static { + final Set nss = new HashSet(); + nss.add(GeoRSSModule.GML_NS); + NAMESPACES = Collections.unmodifiableSet(nss); + } + + private Element createPosListElement(final PositionList posList) { + final Element posElement = new Element("posList", GeoRSSModule.GML_NS); + final StringBuffer sb = new StringBuffer(); + for (int i = 0; i < posList.size(); ++i) { + sb.append(posList.getLatitude(i)).append(" ").append(posList.getLongitude(i)).append(" "); + } + + posElement.addContent(sb.toString()); + return posElement; + } + + /* + * (non-Javadoc) + * @see com.rometools.rome.io.ModuleGenerator#getNamespaceUri() + */ + @Override + public String getNamespaceUri() { + return GeoRSSModule.GEORSS_GML_URI; + } + + /* + * (non-Javadoc) + * @see com.rometools.rome.io.ModuleGenerator#getNamespaces() + */ + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + /* + * (non-Javadoc) + * @see com.rometools.rome.io.ModuleGenerator#generate(com.rometools.rome.feed.module.Module, + * org.jdom2.Element) + */ + @Override + public void generate(final Module module, final Element element) { + // this is not necessary, it is done to avoid the namespace definition + // in every item. + Element root = element; + while (root.getParent() != null && root.getParent() instanceof Element) { + root = (Element) element.getParent(); + } + root.addNamespaceDeclaration(GeoRSSModule.SIMPLE_NS); + root.addNamespaceDeclaration(GeoRSSModule.GML_NS); + + final Element whereElement = new Element("where", GeoRSSModule.SIMPLE_NS); + element.addContent(whereElement); + + final GeoRSSModule geoRSSModule = (GeoRSSModule) module; + final AbstractGeometry geometry = geoRSSModule.getGeometry(); + + if (geometry instanceof Point) { + final Position pos = ((Point) geometry).getPosition(); + + final Element pointElement = new Element("Point", GeoRSSModule.GML_NS); + whereElement.addContent(pointElement); + + final Element posElement = new Element("pos", GeoRSSModule.GML_NS); + posElement.addContent(String.valueOf(pos.getLatitude()) + " " + String.valueOf(pos.getLongitude())); + pointElement.addContent(posElement); + } + + else if (geometry instanceof LineString) { + final PositionList posList = ((LineString) geometry).getPositionList(); + + final Element lineElement = new Element("LineString", GeoRSSModule.GML_NS); + lineElement.addContent(createPosListElement(posList)); + whereElement.addContent(lineElement); + } else if (geometry instanceof Polygon) { + final Element polygonElement = new Element("Polygon", GeoRSSModule.GML_NS); + { + final AbstractRing ring = ((Polygon) geometry).getExterior(); + if (ring instanceof LinearRing) { + final Element exteriorElement = new Element("exterior", GeoRSSModule.GML_NS); + polygonElement.addContent(exteriorElement); + final Element ringElement = new Element("LinearRing", GeoRSSModule.GML_NS); + exteriorElement.addContent(ringElement); + ringElement.addContent(createPosListElement(((LinearRing) ring).getPositionList())); + + } else { + System.err.println("GeoRSS GML format can't handle rings of type: " + ring.getClass().getName()); + } + } + final List interiorList = ((Polygon) geometry).getInterior(); + final Iterator it = interiorList.iterator(); + while (it.hasNext()) { + final AbstractRing ring = it.next(); + if (ring instanceof LinearRing) { + final Element interiorElement = new Element("interior", GeoRSSModule.GML_NS); + polygonElement.addContent(interiorElement); + final Element ringElement = new Element("LinearRing", GeoRSSModule.GML_NS); + interiorElement.addContent(ringElement); + ringElement.addContent(createPosListElement(((LinearRing) ring).getPositionList())); + + } else { + System.err.println("GeoRSS GML format can't handle rings of type: " + ring.getClass().getName()); + } + } + whereElement.addContent(polygonElement); + } else if (geometry instanceof Envelope) { + final Envelope envelope = (Envelope) geometry; + final Element envelopeElement = new Element("Envelope", GeoRSSModule.GML_NS); + whereElement.addContent(envelopeElement); + + final Element lowerElement = new Element("lowerCorner", GeoRSSModule.GML_NS); + lowerElement.addContent(String.valueOf(envelope.getMinLatitude()) + " " + String.valueOf(envelope.getMinLongitude())); + envelopeElement.addContent(lowerElement); + + final Element upperElement = new Element("upperCorner", GeoRSSModule.GML_NS); + upperElement.addContent(String.valueOf(envelope.getMaxLatitude()) + " " + String.valueOf(envelope.getMaxLongitude())); + envelopeElement.addContent(upperElement); + + } else { + System.err.println("GeoRSS GML format can't handle geometries of type: " + geometry.getClass().getName()); + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/GMLModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/georss/GMLModuleImpl.java new file mode 100644 index 0000000..03c944d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/GMLModuleImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +/** + * GMLModuleImpl is the implementation of the {@link GeoRSSModule} Interface for the gml GeoRSS + * format. + * + * @author Marc Wick + * @version $Id: GMLModuleImpl.java,v 1.1 2007/04/18 09:59:29 marcwick Exp $ + * + */ +public class GMLModuleImpl extends GeoRSSModule { + + private static final long serialVersionUID = 1L; + + public GMLModuleImpl() { + super(GeoRSSModule.class, GeoRSSModule.GEORSS_GML_URI); + } + + @Override + public Class getInterface() { + return GeoRSSModule.class; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/GMLParser.java b/rome-modules/src/main/java/com/rometools/modules/georss/GMLParser.java new file mode 100644 index 0000000..7312418 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/GMLParser.java @@ -0,0 +1,148 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Element; + +import com.rometools.modules.georss.geometries.Envelope; +import com.rometools.modules.georss.geometries.LineString; +import com.rometools.modules.georss.geometries.LinearRing; +import com.rometools.modules.georss.geometries.Point; +import com.rometools.modules.georss.geometries.Polygon; +import com.rometools.modules.georss.geometries.Position; +import com.rometools.modules.georss.geometries.PositionList; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; +import com.rometools.utils.Strings; + +/** + * GMLParser is a parser for the GML georss format. + * + * @author Marc Wick + * @version $Id: GMLParser.java,v 1.2 2007/06/05 20:44:53 marcwick Exp $ + * + */ +public class GMLParser implements ModuleParser { + + @Override + public String getNamespaceUri() { + return GeoRSSModule.GEORSS_GEORSS_URI; + } + + @Override + public Module parse(final Element element, final Locale locale) { + final Module geoRssModule = parseGML(element); + return geoRssModule; + } + + private static PositionList parsePosList(final Element element) { + final String coordinates = element.getText(); + final String[] coord = Strings.trimToEmpty(coordinates).split(" "); + final PositionList posList = new PositionList(); + for (int i = 0; i < coord.length; i += 2) { + posList.add(Double.parseDouble(coord[i]), Double.parseDouble(coord[i + 1])); + } + return posList; + } + + static Module parseGML(final Element element) { + GeoRSSModule geoRSSModule = null; + + final Element pointElement = element.getChild("Point", GeoRSSModule.GML_NS); + final Element lineStringElement = element.getChild("LineString", GeoRSSModule.GML_NS); + final Element polygonElement = element.getChild("Polygon", GeoRSSModule.GML_NS); + final Element envelopeElement = element.getChild("Envelope", GeoRSSModule.GML_NS); + if (pointElement != null) { + final Element posElement = pointElement.getChild("pos", GeoRSSModule.GML_NS); + if (posElement != null) { + geoRSSModule = new GMLModuleImpl(); + final String coordinates = posElement.getText(); + final String[] coord = Strings.trimToEmpty(coordinates).split(" "); + final Position pos = new Position(Double.parseDouble(coord[0]), Double.parseDouble(coord[1])); + geoRSSModule.setGeometry(new Point(pos)); + } + } else if (lineStringElement != null) { + final Element posListElement = lineStringElement.getChild("posList", GeoRSSModule.GML_NS); + if (posListElement != null) { + geoRSSModule = new GMLModuleImpl(); + geoRSSModule.setGeometry(new LineString(parsePosList(posListElement))); + } + } else if (polygonElement != null) { + Polygon poly = null; + + // The external ring + final Element exteriorElement = polygonElement.getChild("exterior", GeoRSSModule.GML_NS); + if (exteriorElement != null) { + final Element linearRingElement = exteriorElement.getChild("LinearRing", GeoRSSModule.GML_NS); + if (linearRingElement != null) { + final Element posListElement = linearRingElement.getChild("posList", GeoRSSModule.GML_NS); + if (posListElement != null) { + if (poly == null) { + poly = new Polygon(); + } + poly.setExterior(new LinearRing(parsePosList(posListElement))); + } + } + } + + // The internal rings (holes) + final List interiorElementList = polygonElement.getChildren("interior", GeoRSSModule.GML_NS); + final Iterator it = interiorElementList.iterator(); + while (it.hasNext()) { + final Element interiorElement = it.next(); + if (interiorElement != null) { + final Element linearRingElement = interiorElement.getChild("LinearRing", GeoRSSModule.GML_NS); + if (linearRingElement != null) { + final Element posListElement = linearRingElement.getChild("posList", GeoRSSModule.GML_NS); + if (posListElement != null) { + if (poly == null) { + poly = new Polygon(); + } + poly.getInterior().add(new LinearRing(parsePosList(posListElement))); + } + } + } + + } + + if (poly != null) { + geoRSSModule = new GMLModuleImpl(); + geoRSSModule.setGeometry(poly); + } + } else if (envelopeElement != null) { + final Element lowerElement = envelopeElement.getChild("lowerCorner", GeoRSSModule.GML_NS); + final Element upperElement = envelopeElement.getChild("upperCorner", GeoRSSModule.GML_NS); + if (lowerElement != null && upperElement != null) { + geoRSSModule = new GMLModuleImpl(); + final String lowerCoordinates = lowerElement.getText(); + final String[] lowerCoord = Strings.trimToEmpty(lowerCoordinates).split(" "); + final String upperCoordinates = upperElement.getText(); + final String[] upperCoord = Strings.trimToEmpty(upperCoordinates).split(" "); + final Envelope envelope = new Envelope(Double.parseDouble(lowerCoord[0]), Double.parseDouble(lowerCoord[1]), Double.parseDouble(upperCoord[0]), + Double.parseDouble(upperCoord[1])); + geoRSSModule.setGeometry(envelope); + } + } + + return geoRSSModule; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/GeoRSSModule.java b/rome-modules/src/main/java/com/rometools/modules/georss/GeoRSSModule.java new file mode 100644 index 0000000..2895c02 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/GeoRSSModule.java @@ -0,0 +1,150 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.georss.geometries.AbstractGeometry; +import com.rometools.modules.georss.geometries.Point; +import com.rometools.modules.georss.geometries.Position; +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.module.ModuleImpl; + +/** + * GeoRSSModule is the main georss interface defining the methods to produce and consume georss + * elements. + * + * @author Marc Wick + * @version $Id: GeoRSSModule.java,v 1.8 2007/06/06 09:47:32 marcwick Exp $ + */ +public abstract class GeoRSSModule extends ModuleImpl implements Cloneable { + + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(GeoRSSModule.class); + + protected AbstractGeometry geometry; + + public static final String version = "0.9.8"; + + /** + * namespace URI for georss simple: "http://www.georss.org/georss" + */ + public static final String GEORSS_GEORSS_URI = "http://www.georss.org/georss"; + + /** + * namespace URI for w3c georss : "http://www.w3.org/2003/01/geo/wgs84_pos#" + */ + public static final String GEORSS_W3CGEO_URI = "http://www.w3.org/2003/01/geo/wgs84_pos#"; + + /** + * namespace URI for GML georss : "http://www.opengis.net/gml" + */ + public static final String GEORSS_GML_URI = "http://www.opengis.net/gml"; + + /** + * Namespace for georss simple : xmlns:georss="http://www.georss.org/georss" + */ + public static final Namespace SIMPLE_NS = Namespace.getNamespace("georss", GeoRSSModule.GEORSS_GEORSS_URI); + + /** + * + * Namespace for w3c georss : xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" + */ + public static final Namespace W3CGEO_NS = Namespace.getNamespace("geo", GeoRSSModule.GEORSS_W3CGEO_URI); + + /** + * + * Namespace for gml georss : xmlns:gml="http://www.opengis.net/gml" + */ + public static final Namespace GML_NS = Namespace.getNamespace("gml", GeoRSSModule.GEORSS_GML_URI); + + protected GeoRSSModule(final Class beanClass, final java.lang.String uri) { + super(beanClass, uri); + } + + /** + * Set geometry of georss element + * + * @param geometry geometry + */ + public void setGeometry(final AbstractGeometry geometry) { + this.geometry = geometry; + } + + /** + * returns the geometry + * + * @return geometry + */ + public AbstractGeometry getGeometry() { + return geometry; + } + + /** + * Convenience method to return point geometry. Returns null if the geometry is non-point. + * + * @return geometry + */ + public Position getPosition() { + if (geometry instanceof Point) { + return ((Point) geometry).getPosition(); + } + return null; + } + + /** + * Convenience method to set point geometry. + * + * @return geometry + */ + public void setPosition(final Position pos) { + if (pos != null) { + geometry = new Point(pos); + } + } + + /* + * (non-Javadoc) + * + * @see com.rometools.rome.feed.CopyFrom#copyFrom(java.lang.Object) + */ + @Override + public void copyFrom(final CopyFrom obj) { + final GeoRSSModule geoRSSModule = (GeoRSSModule) obj; + geometry = geoRSSModule.getGeometry(); + try { + geometry = (AbstractGeometry) geometry.clone(); + } catch (final CloneNotSupportedException ex) { + LOG.error("Error", ex); + } + } + + @Override + public Object clone() throws CloneNotSupportedException { + try { + final GeoRSSModule retval = (GeoRSSModule) super.clone(); + if (geometry != null) { + retval.geometry = (AbstractGeometry) geometry.clone(); + } + return retval; + } catch (final Exception ex) { + LOG.error("Error", ex); + } + throw new CloneNotSupportedException(); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/GeoRSSPoint.java b/rome-modules/src/main/java/com/rometools/modules/georss/GeoRSSPoint.java new file mode 100644 index 0000000..ef7f1f6 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/GeoRSSPoint.java @@ -0,0 +1,61 @@ +/* + * Copyright 2007 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +/** + * @author marc + * + */ +public class GeoRSSPoint implements Cloneable { + private double latitude; + + private double longitude; + + /** + * @return the latitude + */ + public double getLatitude() { + return latitude; + } + + /** + * @param latitude the latitude to set + */ + public void setLatitude(final double latitude) { + this.latitude = latitude; + } + + /** + * @return the longitude + */ + public double getLongitude() { + return longitude; + } + + /** + * @param longitude the longitude to set + */ + public void setLongitude(final double longitude) { + this.longitude = longitude; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/GeoRSSUtils.java b/rome-modules/src/main/java/com/rometools/modules/georss/GeoRSSUtils.java new file mode 100644 index 0000000..56c82cf --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/GeoRSSUtils.java @@ -0,0 +1,93 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; + +/** + * static utility methods for georss. + * + * @author Marc Wick + * @version $Id: GeoRSSUtils.java,v 1.4 2007/04/18 09:59:29 marcwick Exp $ + * + */ +public class GeoRSSUtils { + + /** + * This convenience method checks whether there is any geoRss Element and will return it (georss + * simple or W3GGeo). + * + * @param entry the element in the feed which might have a georss element + * @return a georssmodule or null if none is present + */ + public static GeoRSSModule getGeoRSS(final SyndEntry entry) { + final GeoRSSModule simple = (GeoRSSModule) entry.getModule(GeoRSSModule.GEORSS_GEORSS_URI); + final GeoRSSModule w3cGeo = (GeoRSSModule) entry.getModule(GeoRSSModule.GEORSS_W3CGEO_URI); + final GeoRSSModule gml = (GeoRSSModule) entry.getModule(GeoRSSModule.GEORSS_GML_URI); + if (gml != null) { + return gml; + } + if (simple != null) { + return simple; + } + if (w3cGeo != null) { + return w3cGeo; + } + + return null; + /* + * if (geoRSSModule == null && w3cGeo != null) { geoRSSModule = w3cGeo; } else if + * (geoRSSModule == null && gml != null) { geoRSSModule = gml; } else if (geoRSSModule != + * null && w3cGeo != null) { // sanity check if + * (!geoRSSModule.getGeometry().equals(w3cGeo.getGeometry())) { throw new + * Error("geometry of simple and w3c do not match"); } } return geoRSSModule; + */ + } + + /** + * This convenience method checks whether there is any geoRss Element and will return it (georss + * simple or W3GGeo). + * + * @param feed the element in the feed which might have a georss element + * @return a georssmodule or null if none is present + */ + public static GeoRSSModule getGeoRSS(final SyndFeed feed) { + final GeoRSSModule simple = (GeoRSSModule) feed.getModule(GeoRSSModule.GEORSS_GEORSS_URI); + final GeoRSSModule w3cGeo = (GeoRSSModule) feed.getModule(GeoRSSModule.GEORSS_W3CGEO_URI); + final GeoRSSModule gml = (GeoRSSModule) feed.getModule(GeoRSSModule.GEORSS_GML_URI); + + if (gml != null) { + return gml; + } + if (simple != null) { + return simple; + } + if (w3cGeo != null) { + return w3cGeo; + } + + return null; + /* + * if (geoRSSModule == null && w3cGeo != null) { geoRSSModule = w3cGeo; } else if + * (geoRSSModule == null && gml != null) { geoRSSModule = gml; } else if (geoRSSModule != + * null && w3cGeo != null) { // sanity check if + * (!geoRSSModule.getGeometry().equals(w3cGeo.getGeometry())) { throw new + * Error("geometry of simple and w3c do not match"); } } return geoRSSModule; + */ + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/SimpleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/georss/SimpleGenerator.java new file mode 100644 index 0000000..f30e11e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/SimpleGenerator.java @@ -0,0 +1,143 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.georss.geometries.AbstractGeometry; +import com.rometools.modules.georss.geometries.AbstractRing; +import com.rometools.modules.georss.geometries.Envelope; +import com.rometools.modules.georss.geometries.LineString; +import com.rometools.modules.georss.geometries.LinearRing; +import com.rometools.modules.georss.geometries.Point; +import com.rometools.modules.georss.geometries.Polygon; +import com.rometools.modules.georss.geometries.Position; +import com.rometools.modules.georss.geometries.PositionList; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * SimpleGenerator produces georss elements in georss simple format. + * + * @author Marc Wick + * @version $Id: SimpleGenerator.java,v 1.4 2007/04/18 09:59:29 marcwick Exp $ + * + */ +public class SimpleGenerator implements ModuleGenerator { + private static final Logger LOG = LoggerFactory.getLogger(SimpleGenerator.class); + + private static final Set NAMESPACES; + static { + final Set nss = new HashSet(); + nss.add(GeoRSSModule.SIMPLE_NS); + NAMESPACES = Collections.unmodifiableSet(nss); + } + + /** + * @param posList PositionList to convert + * @return String representation + */ + private String posListToString(final PositionList posList) { + final StringBuffer sb = new StringBuffer(); + for (int i = 0; i < posList.size(); ++i) { + sb.append(posList.getLatitude(i)).append(" ").append(posList.getLongitude(i)).append(" "); + } + return sb.toString(); + } + + /* + * (non-Javadoc) + * @see com.rometools.rome.io.ModuleGenerator#getNamespaceUri() + */ + @Override + public String getNamespaceUri() { + return GeoRSSModule.GEORSS_GEORSS_URI; + } + + /* + * (non-Javadoc) + * @see com.rometools.rome.io.ModuleGenerator#getNamespaces() + */ + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + /* + * (non-Javadoc) + * @see com.rometools.rome.io.ModuleGenerator#generate(com.rometools.rome.feed.module.Module, + * org.jdom2.Element) + */ + @Override + public void generate(final Module module, final Element element) { + // this is not necessary, it is done to avoid the namespace definition + // in every item. + Element root = element; + while (root.getParent() != null && root.getParent() instanceof Element) { + root = (Element) element.getParent(); + } + root.addNamespaceDeclaration(GeoRSSModule.SIMPLE_NS); + + final GeoRSSModule geoRSSModule = (GeoRSSModule) module; + + final AbstractGeometry geometry = geoRSSModule.getGeometry(); + if (geometry instanceof Point) { + final Position pos = ((Point) geometry).getPosition(); + + final Element pointElement = new Element("point", GeoRSSModule.SIMPLE_NS); + pointElement.addContent(pos.getLatitude() + " " + pos.getLongitude()); + element.addContent(pointElement); + } else if (geometry instanceof LineString) { + final PositionList posList = ((LineString) geometry).getPositionList(); + + final Element lineElement = new Element("line", GeoRSSModule.SIMPLE_NS); + + lineElement.addContent(posListToString(posList)); + element.addContent(lineElement); + } else if (geometry instanceof Polygon) { + final AbstractRing ring = ((Polygon) geometry).getExterior(); + if (ring instanceof LinearRing) { + final PositionList posList = ((LinearRing) ring).getPositionList(); + final Element polygonElement = new Element("polygon", GeoRSSModule.SIMPLE_NS); + + polygonElement.addContent(posListToString(posList)); + element.addContent(polygonElement); + } else { + LOG.error("GeoRSS simple format can't handle rings of type: " + ring.getClass().getName()); + } + if (((Polygon) geometry).getInterior() != null && !((Polygon) geometry).getInterior().isEmpty()) { + LOG.error("GeoRSS simple format can't handle interior rings (ignored)"); + } + } else if (geometry instanceof Envelope) { + final Envelope envelope = (Envelope) geometry; + final Element boxElement = new Element("box", GeoRSSModule.SIMPLE_NS); + boxElement.addContent(envelope.getMinLatitude() + " " + envelope.getMinLongitude() + " " + envelope.getMaxLatitude() + " " + + envelope.getMaxLongitude()); + element.addContent(boxElement); + } else { + LOG.error("GeoRSS simple format can't handle geometries of type: " + geometry.getClass().getName()); + } + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/SimpleModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/georss/SimpleModuleImpl.java new file mode 100644 index 0000000..1e96d78 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/SimpleModuleImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +/** + * SimpleModuleImpl is the implementation of the {@link GeoRSSModule} Interface for the GeoRSS + * Simple format. + * + * @author Marc Wick + * @version $Id: SimpleModuleImpl.java,v 1.4 2007/04/18 09:59:29 marcwick Exp $ + * + */ +public class SimpleModuleImpl extends GeoRSSModule { + + private static final long serialVersionUID = 1L; + + public SimpleModuleImpl() { + super(GeoRSSModule.class, GeoRSSModule.GEORSS_GEORSS_URI); + } + + @Override + public Class getInterface() { + return GeoRSSModule.class; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/SimpleParser.java b/rome-modules/src/main/java/com/rometools/modules/georss/SimpleParser.java new file mode 100644 index 0000000..d407f47 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/SimpleParser.java @@ -0,0 +1,166 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +import java.util.Locale; + +import org.jdom2.Element; + +import com.rometools.modules.georss.geometries.Envelope; +import com.rometools.modules.georss.geometries.LineString; +import com.rometools.modules.georss.geometries.LinearRing; +import com.rometools.modules.georss.geometries.Point; +import com.rometools.modules.georss.geometries.Polygon; +import com.rometools.modules.georss.geometries.Position; +import com.rometools.modules.georss.geometries.PositionList; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; +import com.rometools.utils.Doubles; +import com.rometools.utils.Strings; + +/** + * SimpleParser is a parser for the GeoRSS Simple format. + * + * @author Marc Wick + * @version $Id: SimpleParser.java,v 1.4 2007/04/18 09:59:29 marcwick Exp $ + * + */ +public class SimpleParser implements ModuleParser { + + @Override + public String getNamespaceUri() { + return GeoRSSModule.GEORSS_GEORSS_URI; + } + + private static PositionList parsePosList(final Element element) { + + PositionList posList = null; + + final String coordinates = Strings.trimToNull(element.getText()); + if (coordinates != null) { + + posList = new PositionList(); + final String[] coord = coordinates.split(" "); + for (int i = 0; i < coord.length; i += 2) { + final double latitude = Double.parseDouble(coord[i]); + final double longitude = Double.parseDouble(coord[i + 1]); + posList.add(latitude, longitude); + } + + } + + return posList; + + } + + @Override + public Module parse(final Element element, final Locale locale) { + return parseSimple(element); + } + + static Module parseSimple(final Element element) { + + final Element pointElement = element.getChild("point", GeoRSSModule.SIMPLE_NS); + final Element lineElement = element.getChild("line", GeoRSSModule.SIMPLE_NS); + final Element polygonElement = element.getChild("polygon", GeoRSSModule.SIMPLE_NS); + final Element boxElement = element.getChild("box", GeoRSSModule.SIMPLE_NS); + final Element whereElement = element.getChild("where", GeoRSSModule.SIMPLE_NS); + + GeoRSSModule geoRSSModule = null; + + if (pointElement != null) { + + final String coordinates = Strings.trimToNull(pointElement.getText()); + if (coordinates != null) { + + final String[] coord = coordinates.split(" "); + + if (coord.length == 2) { + + final Double latitude = Doubles.parse(coord[0]); + final Double longitude = Doubles.parse(coord[1]); + + if (latitude != null && longitude != null) { + + final Position pos = new Position(latitude, longitude); + + final Point point = new Point(pos); + + geoRSSModule = new SimpleModuleImpl(); + geoRSSModule.setGeometry(point); + + } + + } + + } + + } else if (lineElement != null) { + + final PositionList posList = parsePosList(lineElement); + + if (posList != null) { + + final LineString lineString = new LineString(posList); + + geoRSSModule = new SimpleModuleImpl(); + geoRSSModule.setGeometry(lineString); + + } + + } else if (polygonElement != null) { + + final PositionList posList = parsePosList(polygonElement); + if (posList != null) { + + final LinearRing linearRing = new LinearRing(posList); + + final Polygon poly = new Polygon(); + poly.setExterior(linearRing); + + geoRSSModule = new SimpleModuleImpl(); + geoRSSModule.setGeometry(poly); + + } + + } else if (boxElement != null) { + + final String coordinates = Strings.trimToNull(boxElement.getText()); + if (coordinates != null) { + + final String[] coord = coordinates.split(" "); + final double bottom = Double.parseDouble(coord[0]); + final double left = Double.parseDouble(coord[1]); + final double top = Double.parseDouble(coord[2]); + final double right = Double.parseDouble(coord[3]); + + final Envelope envelope = new Envelope(bottom, left, top, right); + + geoRSSModule = new SimpleModuleImpl(); + geoRSSModule.setGeometry(envelope); + } + + } else if (whereElement != null) { + + geoRSSModule = (GeoRSSModule) GMLParser.parseGML(whereElement); + + } + + return geoRSSModule; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/W3CGeoGenerator.java b/rome-modules/src/main/java/com/rometools/modules/georss/W3CGeoGenerator.java new file mode 100644 index 0000000..06185ad --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/W3CGeoGenerator.java @@ -0,0 +1,110 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.georss.geometries.AbstractGeometry; +import com.rometools.modules.georss.geometries.Point; +import com.rometools.modules.georss.geometries.Position; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * W3CGeoGenerator produces georss elements in georss W3C geo format. + * + * @author Marc Wick + * @version $Id: W3CGeoGenerator.java,v 1.3 2007/04/18 09:59:30 marcwick Exp $ + * + */ +public class W3CGeoGenerator implements ModuleGenerator { + + private static boolean isShort = true; + + private static final Set NAMESPACES; + + static { + final Set nss = new HashSet(); + nss.add(GeoRSSModule.W3CGEO_NS); + NAMESPACES = Collections.unmodifiableSet(nss); + } + + public static void enableDefaultPointElement() { + isShort = false; + } + + /* + * (non-Javadoc) + * @see com.rometools.rome.io.ModuleGenerator#getNamespaceUri() + */ + @Override + public String getNamespaceUri() { + return GeoRSSModule.GEORSS_W3CGEO_URI; + } + + /* + * (non-Javadoc) + * @see com.rometools.rome.io.ModuleGenerator#getNamespaces() + */ + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + /* + * (non-Javadoc) + * @see com.rometools.rome.io.ModuleGenerator#generate(com.rometools.rome.feed.module.Module, + * org.jdom2.Element) + */ + @Override + public void generate(final Module module, final Element element) { + // this is not necessary, it is done to avoid the namespace definition + // in every item. + Element root = element; + while (root.getParent() != null && root.getParent() instanceof Element) { + root = (Element) element.getParent(); + } + root.addNamespaceDeclaration(GeoRSSModule.W3CGEO_NS); + + Element pointElement = element; + if (!isShort) { + pointElement = new Element("Point", GeoRSSModule.W3CGEO_NS); + element.addContent(pointElement); + } + + final GeoRSSModule geoRSSModule = (GeoRSSModule) module; + final AbstractGeometry geometry = geoRSSModule.getGeometry(); + + if (geometry instanceof Point) { + final Position pos = ((Point) geometry).getPosition(); + + final Element latElement = new Element("lat", GeoRSSModule.W3CGEO_NS); + latElement.addContent(String.valueOf(pos.getLatitude())); + pointElement.addContent(latElement); + final Element lngElement = new Element("long", GeoRSSModule.W3CGEO_NS); + lngElement.addContent(String.valueOf(pos.getLongitude())); + pointElement.addContent(lngElement); + } else { + System.err.println("W3C Geo format can't handle geometries of type: " + geometry.getClass().getName()); + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/W3CGeoModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/georss/W3CGeoModuleImpl.java new file mode 100644 index 0000000..a4ff886 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/W3CGeoModuleImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +/** + * W3CGeoModuleImpl is the implementation of the {@link GeoRSSModule} Interface for the W3C geo + * format. + * + * @author Marc Wick + * @version $Id: W3CGeoModuleImpl.java,v 1.2 2007/04/18 09:59:29 marcwick Exp $ + * + */ +public class W3CGeoModuleImpl extends GeoRSSModule { + + private static final long serialVersionUID = 1L; + + public W3CGeoModuleImpl() { + super(GeoRSSModule.class, GeoRSSModule.GEORSS_W3CGEO_URI); + } + + @Override + public Class getInterface() { + return GeoRSSModule.class; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/W3CGeoParser.java b/rome-modules/src/main/java/com/rometools/modules/georss/W3CGeoParser.java new file mode 100644 index 0000000..c887fbf --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/W3CGeoParser.java @@ -0,0 +1,90 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +import java.util.Locale; + +import org.jdom2.Element; + +import com.rometools.modules.georss.geometries.Point; +import com.rometools.modules.georss.geometries.Position; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; +import com.rometools.utils.Strings; + +/** + * W3CGeoParser is a parser for the W3C geo format. + * + * @author Marc Wick + * @version $Id: W3CGeoParser.java,v 1.4 2007/04/18 09:59:29 marcwick Exp $ + * + */ +public class W3CGeoParser implements ModuleParser { + + @Override + public String getNamespaceUri() { + return GeoRSSModule.GEORSS_W3CGEO_URI; + } + + static Module parseW3C(final Element element) { + + GeoRSSModule geoRSSModule = null; + + // do we have an optional "Point" element ? + Element pointElement = element.getChild("Point", GeoRSSModule.W3CGEO_NS); + + // we don't have an optional "Point" element + if (pointElement == null) { + pointElement = element; + } + + final Element lat = pointElement.getChild("lat", GeoRSSModule.W3CGEO_NS); + Element lng = pointElement.getChild("long", GeoRSSModule.W3CGEO_NS); + if (lng == null) { + lng = pointElement.getChild("lon", GeoRSSModule.W3CGEO_NS); + } + + if (lat != null && lng != null) { + + geoRSSModule = new W3CGeoModuleImpl(); + + final String latTxt = Strings.trimToNull(lat.getText()); + final String lngTxt = Strings.trimToNull(lng.getText()); + + if (latTxt != null && lngTxt != null) { + + final double latitude = Double.parseDouble(lat.getText()); + final double longitude = Double.parseDouble(lng.getText()); + + final Position position = new Position(latitude, longitude); + + final Point point = new Point(position); + + geoRSSModule.setGeometry(point); + } + + } + + return geoRSSModule; + } + + @Override + public Module parse(final Element element, final Locale locale) { + return parseW3C(element); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractCurve.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractCurve.java new file mode 100644 index 0000000..12c8324 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractCurve.java @@ -0,0 +1,33 @@ +/* + * 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.rometools.modules.georss.geometries; + +/** + * Abstract base class for Curves (linear objects) + * + * @author runaas + */ +public abstract class AbstractCurve extends AbstractGeometricPrimitive { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** Creates a new instance of Curve */ + public AbstractCurve() { + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractGeometricPrimitive.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractGeometricPrimitive.java new file mode 100644 index 0000000..7d4d431 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractGeometricPrimitive.java @@ -0,0 +1,35 @@ +/* + * 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.rometools.modules.georss.geometries; + +/** + * Abstract base class for geometric primitives (non-composite geometric objects) + * + * @author runaas + */ +public abstract class AbstractGeometricPrimitive extends AbstractGeometry { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** Creates a new instance of GeometricPrimitive */ + public AbstractGeometricPrimitive() { + + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractGeometry.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractGeometry.java new file mode 100644 index 0000000..40775fe --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractGeometry.java @@ -0,0 +1,50 @@ +/* + * 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.rometools.modules.georss.geometries; + +import java.io.Serializable; + +/** + * Abstract base class for geometries. + * + * @author runaas + */ +public abstract class AbstractGeometry implements Cloneable, Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** Creates a new instance of Geometry */ + public AbstractGeometry() { + } + + /** + * Make a deep copy of the geometric object + * + * @return A copy of the object + */ + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + @Override + public boolean equals(final Object obj) { + return obj != null && obj.getClass() == getClass(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractRing.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractRing.java new file mode 100644 index 0000000..610a2fa --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractRing.java @@ -0,0 +1,40 @@ +/* + * 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.rometools.modules.georss.geometries; + +import java.io.Serializable; + +/** + * Abstract base class for rings (closed linear objects used for polygon borders) + * + * @author runaas + */ +public abstract class AbstractRing implements Cloneable, Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** Creates a new instance of AbstractRing */ + public AbstractRing() { + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractSurface.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractSurface.java new file mode 100644 index 0000000..3776530 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/AbstractSurface.java @@ -0,0 +1,34 @@ +/* + * 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.rometools.modules.georss.geometries; + +/** + * Abstract base class for surface (area) objects + * + * @author runaas + */ +public abstract class AbstractSurface extends AbstractGeometricPrimitive { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** Creates a new instance of Surface */ + public AbstractSurface() { + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Envelope.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Envelope.java new file mode 100644 index 0000000..a80e6b8 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Envelope.java @@ -0,0 +1,107 @@ +/* + * 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.rometools.modules.georss.geometries; + +/** + * Envelope, a bounding box spanned by an upper right and lower left corner point. Note that if the + * box spans the -180 180 degree meridian the numerical value of the minLongitude may be greater + * than the maxLongitude. + * + * @author runaas + */ +public class Envelope extends AbstractGeometry { + /** + * + */ + private static final long serialVersionUID = 1L; + protected double minLatitude, minLongitude, maxLatitude, maxLongitude; + + /** Creates a new instance of Envelope */ + public Envelope() { + minLatitude = minLongitude = maxLatitude = maxLongitude = Double.NaN; + } + + /** + * Construct object from coordinate values + * + * @param minLatitude + * @param minLongitude + * @param maxLatitude + * @param maxLongitude + */ + public Envelope(final double minLatitude, final double minLongitude, final double maxLatitude, final double maxLongitude) { + this.minLatitude = minLatitude; + this.minLongitude = minLongitude; + this.maxLatitude = maxLatitude; + this.maxLongitude = maxLongitude; + } + + /** + * @return the minimum longitude + */ + public double getMinLongitude() { + return minLongitude; + } + + /** + * @return the minimum latitude + */ + public double getMinLatitude() { + return minLatitude; + } + + /** + * @return the maximum longitude + */ + public double getMaxLongitude() { + return maxLongitude; + } + + /** + * @return the maximum latitude + */ + public double getMaxLatitude() { + return maxLatitude; + } + + /** + * @param v minimum longitude + */ + public void setMinLongitude(final double v) { + minLongitude = v; + } + + /** + * @param v minimum latitude + */ + public void setMinLatitude(final double v) { + minLatitude = v; + } + + /** + * @param v maximum longitude + */ + public void setMaxLongitude(final double v) { + maxLongitude = v; + } + + /** + * @param v maximum latitude + */ + public void setMaxLatitude(final double v) { + maxLatitude = v; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/LineString.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/LineString.java new file mode 100644 index 0000000..0f31d6a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/LineString.java @@ -0,0 +1,82 @@ +/* + * 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.rometools.modules.georss.geometries; + +/** + * Linear object constructed by linear interpolation between points + * + * @author runaas + */ +public final class LineString extends AbstractCurve { + /** + * + */ + private static final long serialVersionUID = 1L; + private PositionList posList; + + /** Creates a new instance of LineString */ + public LineString() { + + } + + /** + * Construct object from a position list + */ + public LineString(final PositionList posList) { + this.posList = posList; + } + + @Override + public Object clone() throws CloneNotSupportedException { + final LineString retval = (LineString) super.clone(); + if (posList != null) { + retval.posList = (PositionList) posList.clone(); + } + return retval; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + return getPositionList().equals(((LineString) obj).getPositionList()); + } + + /** + * Get the position list + * + * @return the positionlist + */ + public PositionList getPositionList() { + if (posList == null) { + posList = new PositionList(); + } + return posList; + } + + /** + * Set the position list + * + * @param posList the new position list + */ + public void setPositionList(final PositionList posList) { + this.posList = posList; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/LinearRing.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/LinearRing.java new file mode 100644 index 0000000..fe3ec59 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/LinearRing.java @@ -0,0 +1,79 @@ +/* + * 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.rometools.modules.georss.geometries; + +/** + * Linear boundary object constructed by linear interpolation between points. Start and end point + * should be identical. + * + * @author runaas + */ +public final class LinearRing extends AbstractRing { + /** + * + */ + private static final long serialVersionUID = 1L; + private PositionList posList; + + /** Creates a new instance of LinearLing */ + public LinearRing() { + } + + public LinearRing(final PositionList posList) { + this.posList = posList; + } + + @Override + public Object clone() throws CloneNotSupportedException { + final LinearRing retval = (LinearRing) super.clone(); + if (posList != null) { + retval.posList = (PositionList) posList.clone(); + } + return retval; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + return getPositionList().equals(((LinearRing) obj).getPositionList()); + } + + /** + * Get the position list + * + * @return the positionlist + */ + public PositionList getPositionList() { + if (posList == null) { + posList = new PositionList(); + } + return posList; + } + + /** + * Set the position list + * + * @param posList the new position list + */ + public void setPositionList(final PositionList posList) { + this.posList = posList; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Point.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Point.java new file mode 100644 index 0000000..8df1f99 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Point.java @@ -0,0 +1,79 @@ +/* + * 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.rometools.modules.georss.geometries; + +/** + * Point object, contains a position + * + * @author runaas + */ +public final class Point extends AbstractGeometricPrimitive { + /** + * + */ + private static final long serialVersionUID = 1L; + private Position pos; + + /** Creates a new instance of Point */ + public Point() { + + } + + public Point(final Position pos) { + this.pos = pos; + } + + @Override + public Object clone() throws CloneNotSupportedException { + final Point retval = (Point) super.clone(); + if (pos != null) { + retval.pos = (Position) pos.clone(); + } + return retval; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + return getPosition().equals(((Point) obj).getPosition()); + } + + /** + * Get the position + * + * @return the position + */ + public Position getPosition() { + if (pos == null) { + pos = new Position(); + } + return pos; + } + + /** + * Set the position + * + * @param pos the new position + */ + public void setPosition(final Position pos) { + this.pos = pos; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Polygon.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Polygon.java new file mode 100644 index 0000000..35db7c5 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Polygon.java @@ -0,0 +1,128 @@ +/* + * 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.rometools.modules.georss.geometries; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Polygon, a surface object bounded by one external ring and zero or more internal rings + * + * @author runaas + */ +public final class Polygon extends AbstractSurface implements Cloneable { + /** + * + */ + private static final long serialVersionUID = 1L; + private AbstractRing exterior; + private List interior; + + /** Creates a new instance of Polygon */ + public Polygon() { + + } + + @Override + public Object clone() throws CloneNotSupportedException { + final Polygon retval = (Polygon) super.clone(); + if (exterior != null) { + retval.exterior = (AbstractRing) exterior.clone(); + } + if (interior != null) { + retval.interior = new ArrayList(); + final Iterator it = interior.iterator(); + while (it.hasNext()) { + final AbstractRing r = it.next(); + retval.interior.add((AbstractRing) r.clone()); + } + } + return retval; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + final Polygon pol = (Polygon) obj; + if (exterior == null && pol.exterior == null) { + ; + } else if (exterior == null || pol.exterior == null) { + return false; + } else if (!exterior.equals(pol.exterior)) { + return false; + } + + // Not efficient.... (but the number of internal ringr is usually small). + Iterator it = interior.iterator(); + while (it.hasNext()) { + if (!pol.interior.contains(it.next())) { + return false; + } + } + it = pol.interior.iterator(); + while (it.hasNext()) { + if (!interior.contains(it.next())) { + return false; + } + } + return true; + } + + /** + * Retrieve the outer border + * + * @return the border ring + */ + public AbstractRing getExterior() { + return exterior; + } + + /** + * Retrieve the inner border + * + * @return the list of border rings + */ + public List getInterior() { + if (interior == null) { + interior = new ArrayList(); + } + return interior; + } + + /** + * Set the outer border + * + * @param exterior the outer ring + */ + public void setExterior(final AbstractRing exterior) { + this.exterior = exterior; + } + + /** + * Set the list of inner borders (holes) + * + * @param interior the list of inner rings + */ + public void setInterior(final List interior) { + this.interior = interior; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Position.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Position.java new file mode 100644 index 0000000..7d4904b --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/Position.java @@ -0,0 +1,99 @@ +/* + * 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.rometools.modules.georss.geometries; + +import java.io.Serializable; + +/** + * A two dimensional position represented by latitude and longitude decimal degrees in WGS84 + * + * @author runaas + */ +public class Position implements Cloneable, Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + private double latitude; + private double longitude; + + /** Creates a new instance of Position */ + public Position() { + latitude = Double.NaN; + longitude = Double.NaN; + } + + /** + * Create Position from a pair of coordinate values + * + * @param latitude + * @param longitude + */ + public Position(final double latitude, final double longitude) { + this.latitude = latitude; + this.longitude = longitude; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + + final Position p = (Position) obj; + return p.latitude == latitude && p.longitude == longitude; + } + + /** + * @return latitude + */ + public double getLatitude() { + return latitude; + } + + /** + * Set the latitude + * + * @param latitude the new latitude + */ + public void setLatitude(final double latitude) { + this.latitude = latitude; + } + + /** + * @return longitude + */ + public double getLongitude() { + return longitude; + } + + /** + * Set the longitude + * + * @param longitude the new longitude + */ + public void setLongitude(final double longitude) { + this.longitude = longitude; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/PositionList.java b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/PositionList.java new file mode 100644 index 0000000..509008d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/PositionList.java @@ -0,0 +1,169 @@ +/* + * 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.rometools.modules.georss.geometries; + +import java.io.Serializable; + +/** + * A list of geographic positions, latitude, longitude decimal degrees WGS84 + * + * @author runaas + */ +public class PositionList implements Cloneable, Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + private double[] latitude; + private double[] longitude; + private int size; + + /** Creates a new empty instance of PositionList */ + public PositionList() { + size = 0; + } + + @Override + public Object clone() throws CloneNotSupportedException { + final PositionList retval = (PositionList) super.clone(); + if (latitude != null) { + retval.latitude = latitude.clone(); + } + if (longitude != null) { + retval.longitude = longitude.clone(); + } + retval.size = size; + return retval; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + + final PositionList p = (PositionList) obj; + if (p.size != size) { + return false; + } + for (int i = 0; i < size; ++i) { + if (p.latitude[i] != latitude[i] || p.longitude[i] != longitude[i]) { + return false; + } + } + return true; + } + + private void ensureCapacity(int new_size) { + if (longitude != null && longitude.length >= new_size) { + return; + } + if (new_size < 4) { + new_size = 4; + } else { + new_size = (int) Math.ceil(Math.pow(2, Math.ceil(Math.log(new_size) / Math.log(2)))); + } + double[] tmp = new double[new_size]; + if (longitude != null) { + System.arraycopy(longitude, 0, tmp, 0, size); + } + longitude = tmp; + tmp = new double[new_size]; + if (latitude != null) { + System.arraycopy(latitude, 0, tmp, 0, size); + } + latitude = tmp; + } + + /** + * @return the number of positions in the list + */ + public int size() { + return size; + } + + /** + * @param pos position index + * @return longitude for position + */ + public double getLongitude(final int pos) { + return longitude[pos]; + } + + /** + * @param pos position index + * @return latitude for position + */ + public double getLatitude(final int pos) { + return latitude[pos]; + } + + /** + * Add a position at the end of the list + * + * @param latitude + * @param longitude + */ + public void add(final double latitude, final double longitude) { + ensureCapacity(size + 1); + this.longitude[size] = longitude; + this.latitude[size] = latitude; + ++size; + } + + /** + * Add a position at a given index in the list. The rest of the list is shifted one place to the + * "right" + * + * @param pos position index + * @param latitude + * @param longitude + */ + public void insert(final int pos, final double latitude, final double longitude) { + ensureCapacity(size + 1); + System.arraycopy(this.longitude, pos, this.longitude, pos + 1, size - pos); + System.arraycopy(this.latitude, pos, this.latitude, pos + 1, size - pos); + this.longitude[pos] = longitude; + this.latitude[pos] = latitude; + ++size; + } + + /** + * Replace the position at the index with new values + * + * @param pos position index + * @param latitude + * @param longitude + */ + public void replace(final int pos, final double latitude, final double longitude) { + this.longitude[pos] = longitude; + this.latitude[pos] = latitude; + } + + /** + * Remove the position at the index, the rest of the list is shifted one place to the "left" + * + * @param pos position index + */ + public void remove(final int pos) { + System.arraycopy(longitude, pos + 1, longitude, pos, size - pos - 1); + System.arraycopy(latitude, pos + 1, latitude, pos, size - pos - 1); + --size; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/geometries/package.html b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/package.html new file mode 100644 index 0000000..2d7654a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/geometries/package.html @@ -0,0 +1,14 @@ + + + + + Geometry package documetation + + + This package contains classes for handling of geometric objects in a + geographical context, mainly for + use with the GeoRSS library. The geometry objects closely mimics the model + used for the geometry part of GML + 3.1.1 "simple features", and supports the whole GeoRSS GML profile. + + diff --git a/rome-modules/src/main/java/com/rometools/modules/georss/package.html b/rome-modules/src/main/java/com/rometools/modules/georss/package.html new file mode 100644 index 0000000..bf84f47 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/georss/package.html @@ -0,0 +1,46 @@ + + + + + GeoRSS package documentation + + + + + +This package contains classes to enable the rome rss library with georss support. +GeoRSS describes a number of ways to encoding location in RSS feeds + + +

Code Examples

+ +

GeoRSS Consumer

+ +
   SyndFeedInput input = new SyndFeedInput();
+       SyndFeed feed = input.build(new XmlReader(new URL(
+             "http://www.geonames.org/recent-changes.xml")));
+
+       List<syndentry> entries = feed.getEntries();
+       for (SyndEntry entry : entries) {
+            GeoRSSModule geoRSSModule = GeoRSSUtils.getGeoRSS(entry);
+            System.out.println(entry.getTitle() + " : lat="
+                  + geoRSSModule.getPosition().getLatitude() + ",lng="
+                  + geoRSSModule.getPosition().getLongitude() + ", desc="
+                  + entry.getDescription().getValue() + "; time="
+                  + entry.getPublishedDate());
+       }
+   
+ + + + +

GeoRSS Producer

+ +
    GeoRSSModule geoRSSModule = new W3CGeoModuleImpl();
+        //GeoRSSModule geoRSSModule = new SimpleModuleImpl();
+        geoRSSModule.setPosition(new Position(47.0, 9.0));
+        entry.getModules().add(geoRSSModule);
+    
+ + + diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/AbstractITunesObject.java b/rome-modules/src/main/java/com/rometools/modules/itunes/AbstractITunesObject.java new file mode 100644 index 0000000..948d47e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/AbstractITunesObject.java @@ -0,0 +1,273 @@ +/* + * AbstractITunesObject.java + * + * Created on August 1, 2005, 7:37 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes; + +import java.net.URL; + +/** + * This is an abstract object that implements the attributes common across Feeds or Items in an + * iTunes compatible RSS feed. + * + * @version $Revision: 1.4 $ + * @author Robert "kebernet" Cooper + */ +public abstract class AbstractITunesObject implements ITunes, java.lang.Cloneable { + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * The URI that iTunes used for its custom tags. + *

+ * What is up with using a versioned DTD anyway? + *

+ * \ + */ + public static final String URI = "http://www.itunes.com/dtds/podcast-1.0.dtd"; + + /** + * The RDF namespace URI. + */ + public static final String RDF_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + + /** + * A default prefix to use for itunes tags. + */ + public static final String PREFIX = "itunes"; + private String author; + private boolean block; + private boolean explicit; + private URL image; + private String[] keywords; + private String subtitle; + private String summary; + + /** + * Defined by the ROME API + * + * @return Class of the Interface for this module. + */ + @Override + public Class getInterface() { + return getClass(); + } + + /** + * The URI this module implements + * + * @return "http://www.itunes.com/dtds/podcast-1.0.dtd" + */ + @Override + public String getUri() { + return AbstractITunesObject.URI; + } + + /** + * Required by the ROME API + * + * @return A clone of this module object + */ + @Override + public abstract Object clone(); + + /** + * Returns the author string for this feed or entry + * + * @return Returns the author string for this feed or entry + */ + @Override + public String getAuthor() { + return author; + } + + /** + * Sets the author string for this feed or entry + * + * @param author Sets the author string for this feed or entry + */ + @Override + public void setAuthor(final String author) { + this.author = author; + } + + /** + * Boolean as to whether to block this feed or entry + * + * @return Boolean as to whether to block this feed or entry + */ + @Override + public boolean getBlock() { + return block; + } + + /** + * Boolean as to whether to block this feed or entry + * + * @param block Boolean as to whether to block this feed or entry + */ + @Override + public void setBlock(final boolean block) { + this.block = block; + } + + /** + * Boolean as to whether this feed or entry contains adult content + * + * @return Boolean as to whether this feed or entry contains adult content + */ + @Override + public boolean getExplicit() { + return explicit; + } + + /** + * Boolean as to whether this feed or entry contains adult content + * + * @param explicit Boolean as to whether this feed or entry contains adult content + */ + @Override + public void setExplicit(final boolean explicit) { + this.explicit = explicit; + } + + @Override + public URL getImage() { + return image; + } + + @Override + public void setImage(final URL image) { + this.image = image; + } + + /** + * A list of keywords for this feed or entry + * + * Must not contain spaces + * + * @return A list of keywords for this feed or entry + */ + @Override + public String[] getKeywords() { + return keywords == null ? new String[0] : keywords; + } + + /** + * A list of keywords for this feed or entry + * + * Must not contain spaces + * + * @param keywords A list of keywords for this feed or enty + */ + @Override + public void setKeywords(final String[] keywords) { + this.keywords = keywords; + } + + /** + * A subtitle for this feed or entry + * + * @return A subtitle for this feed or entry + */ + @Override + public String getSubtitle() { + return subtitle; + } + + /** + * A subtitle for this feed or entry + * + * @param subtitle A subtitle for this feed or entry + */ + @Override + public void setSubtitle(final String subtitle) { + this.subtitle = subtitle; + } + + /** + * A subtitle for this feed or entry + * + * @return A subtitle for this feed or entry + */ + @Override + public String getSummary() { + return summary; + } + + /** + * A subtitle for this feed or entry + * + * @param summary A subtitle for this feed or entry + */ + @Override + public void setSummary(final String summary) { + this.summary = summary; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("["); + sb.append(" Author: "); + sb.append(getAuthor()); + sb.append(" Block: "); + sb.append(getBlock()); + sb.append(" Explicit: "); + sb.append(getExplicit()); + sb.append(" Image: "); + sb.append(getImage()); + sb.append(" Keywords: "); + + if (getKeywords() != null) { + for (int i = 0; i < keywords.length; i++) { + sb.append("'" + getKeywords()[i] + "'"); + } + } + + sb.append(" Subtitle: "); + sb.append(getSubtitle()); + sb.append(" Summary: "); + sb.append(getSummary()); + sb.append("]"); + + return sb.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformation.java b/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformation.java new file mode 100644 index 0000000..4710a1e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformation.java @@ -0,0 +1,76 @@ +/* + * EntryInformation.java + * + * Created on November 19, 2005, 10:56 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes; + +import com.rometools.modules.itunes.types.Duration; + +/** + * This class contains information for iTunes podcast feeds that exist at the Item level. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + * + */ +public interface EntryInformation extends ITunes { + + /** + * Returns the Duration object for this Item + * + * @return Returns the Duration object for this Item + */ + public Duration getDuration(); + + /** + * Sets the Duration object for this Item + * + * @param duration Sets the Duration object for this Item + */ + public void setDuration(Duration duration); + + public boolean getClosedCaptioned(); + + public void setClosedCaptioned(boolean closedCaptioned); + + public Integer getOrder(); + + public void setOrder(Integer order); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformationImpl.java b/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformationImpl.java new file mode 100644 index 0000000..b85449b --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformationImpl.java @@ -0,0 +1,178 @@ +/* + * EntryInformation.java + * + * Created on August 1, 2005, 7:37 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes; + +import com.rometools.modules.itunes.types.Duration; +import com.rometools.rome.feed.CopyFrom; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * This class contains information for iTunes podcast feeds that exist at the Item level. + * + * @version $Revision: 1.2 $ + * @author Robert "kebernet" Cooper + */ +public class EntryInformationImpl extends AbstractITunesObject implements EntryInformation { + /** + * + */ + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(EntryInformationImpl.class); + + private Duration duration; + private boolean closedCaptioned; + private Integer order; + + /** + * Creates a new instance of EntryInformationImpl + */ + public EntryInformationImpl() { + } + + /** + * Returns the Duration object for this Item + * + * @return Returns the Duration object for this Item + */ + @Override + public Duration getDuration() { + return duration; + } + + /** + * Sets the Duration object for this Item + * + * @param duration Sets the Duration object for this Item + */ + @Override + public void setDuration(final Duration duration) { + this.duration = duration; + } + + @Override + public boolean getClosedCaptioned() { + return closedCaptioned; + } + + @Override + public void setClosedCaptioned(boolean closedCaptioned) { + this.closedCaptioned = closedCaptioned; + } + + @Override + public Integer getOrder() { + return order; + } + + @Override + public void setOrder(Integer order) { + this.order = order; + } + + /** + * Defined by the ROME module API + * + * @param obj Object to copy from + */ + @Override + public void copyFrom(final CopyFrom obj) { + final EntryInformationImpl info = (EntryInformationImpl) obj; + setAuthor(info.getAuthor()); + setBlock(info.getBlock()); + + if (info.getDuration() != null) { + setDuration(new Duration(info.getDuration().getMilliseconds())); + } + + setExplicit(info.getExplicit()); + + try { + if (info.getImage() != null) { + setImage(new URL(info.getImage().toExternalForm())); + } + } catch (final MalformedURLException e) { + LOG.debug("Error copying URL:" + info.getImage(), e); + } + + if (info.getKeywords() != null) { + setKeywords(info.getKeywords().clone()); + } + + setSubtitle(info.getSubtitle()); + setSummary(info.getSummary()); + setClosedCaptioned(info.getClosedCaptioned()); + setOrder(info.getOrder()); + } + + /** + * Required by the ROME API + * + * @return A clone of this module object + */ + @Override + public Object clone() { + final EntryInformationImpl info = new EntryInformationImpl(); + info.copyFrom(this); + + return info; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("["); + sb.append(" duration: "); + sb.append(getDuration()); + sb.append(" closedCaptioned: "); + sb.append(getClosedCaptioned()); + sb.append(" order: "); + sb.append(getOrder()); + sb.append("]"); + sb.append(super.toString()); + + return sb.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformation.java b/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformation.java new file mode 100644 index 0000000..9f2965d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformation.java @@ -0,0 +1,105 @@ +/* + * FeedInformation.java + * + * Created on November 19, 2005, 10:57 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes; + +import java.net.URL; +import java.util.List; + +import com.rometools.modules.itunes.types.Category; + +/** + * This class contains information for iTunes podcast feeds that exist at the Channel level. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public interface FeedInformation extends ITunes { + + /** + * The parent categories for this feed + * + * @return The parent categories for this feed + */ + public List getCategories(); + + /** + * The parent categories for this feed + * + * @param categories The parent categories for this feed + */ + public void setCategories(List categories); + + public boolean getComplete(); + + public void setComplete(boolean complete); + + public String getNewFeedUrl(); + + public void setNewFeedUrl(String newFeedUrl); + + /** + * Sets the owner email address for the feed. + * + * @param ownerEmailAddress Sets the owner email address for the feed. + */ + public void setOwnerEmailAddress(String ownerEmailAddress); + + /** + * Returns the owner email address for the feed. + * + * @return Returns the owner email address for the feed. + */ + public String getOwnerEmailAddress(); + + /** + * Sets the owner name for the feed + * + * @param ownerName Sets the owner name for the feed + */ + public void setOwnerName(String ownerName); + + /** + * Returns the owner name for the feed + * + * @return Returns the owner name for the feed + */ + public String getOwnerName(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformationImpl.java b/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformationImpl.java new file mode 100644 index 0000000..07f584f --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformationImpl.java @@ -0,0 +1,228 @@ +/* + * FeedInformation.java + * + * Created on August 1, 2005, 7:11 PM + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.itunes.types.Category; +import com.rometools.rome.feed.CopyFrom; + +/** + * This class contains information for iTunes podcast feeds that exist at the Channel level. + * + * @version $Revision: 1.2 $ + * @author Robert "kebernet" Cooper + */ +public class FeedInformationImpl extends AbstractITunesObject implements FeedInformation { + + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(FeedInformationImpl.class); + + private String ownerName; + private String ownerEmailAddress; + private List categories; + private boolean complete; + private String newFeedUrl; + + /** + * Creates a new instance of FeedInformationImpl + */ + public FeedInformationImpl() { + } + + /** + * The parent categories for this feed + * + * @return The parent categories for this feed + */ + @Override + public List getCategories() { + return categories == null ? (categories = new ArrayList()) : categories; + } + + /** + * The parent categories for this feed + * + * @param categories The parent categories for this feed + */ + @Override + public void setCategories(final List categories) { + this.categories = categories; + } + + @Override + public boolean getComplete() { + return complete; + } + + @Override + public void setComplete(boolean complete) { + this.complete = complete; + } + + @Override + public String getNewFeedUrl() { + return newFeedUrl; + } + + @Override + public void setNewFeedUrl(String newFeedUrl) { + this.newFeedUrl = newFeedUrl; + } + + /** + * Returns the owner name for the feed + * + * @return Returns the owner name for the feed + */ + @Override + public String getOwnerName() { + return ownerName; + } + + /** + * Sets the owner name for the feed + * + * @param ownerName Sets the owner name for the feed + */ + @Override + public void setOwnerName(final String ownerName) { + this.ownerName = ownerName; + } + + /** + * Returns the owner email address for the feed. + * + * @return Returns the owner email address for the feed. + */ + @Override + public String getOwnerEmailAddress() { + return ownerEmailAddress; + } + + /** + * Sets the owner email address for the feed. + * + * @param ownerEmailAddress Sets the owner email address for the feed. + */ + @Override + public void setOwnerEmailAddress(final String ownerEmailAddress) { + this.ownerEmailAddress = ownerEmailAddress; + } + + /** + * Required by the ROME API + * + * @param obj object to copy property values from + */ + @Override + public void copyFrom(final CopyFrom obj) { + final FeedInformationImpl info = (FeedInformationImpl) obj; + setAuthor(info.getAuthor()); + setBlock(info.getBlock()); + + getCategories().clear(); + if (info.getCategories() != null) { + getCategories().addAll(info.getCategories()); + } + + setComplete(info.getComplete()); + setNewFeedUrl(info.getNewFeedUrl()); + setExplicit(info.getExplicit()); + + try { + if (info.getImage() != null) { + setImage(new URL(info.getImage().toExternalForm())); + } + } catch (final MalformedURLException e) { + LOG.debug("Error copying URL:" + info.getImage(), e); + } + + if (info.getKeywords() != null) { + setKeywords(info.getKeywords().clone()); + } + + setOwnerEmailAddress(info.getOwnerEmailAddress()); + setOwnerName(info.getOwnerName()); + setSubtitle(info.getSubtitle()); + setSummary(info.getSummary()); + } + + /** + * Returns a copy of this FeedInformationImpl object + * + * @return Returns a copy of this FeedInformationImpl object + */ + @Override + public Object clone() { + final FeedInformationImpl info = new FeedInformationImpl(); + info.copyFrom(this); + + return info; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("["); + sb.append(" email: "); + sb.append(getOwnerEmailAddress()); + sb.append(" name: "); + sb.append(getOwnerName()); + sb.append(" categories: "); + sb.append(getCategories()); + sb.append(" complete: "); + sb.append(getComplete()); + sb.append(" newFeedUrl: "); + sb.append(getNewFeedUrl()); + sb.append("]"); + sb.append(super.toString()); + + return sb.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/ITunes.java b/rome-modules/src/main/java/com/rometools/modules/itunes/ITunes.java new file mode 100644 index 0000000..1451f95 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/ITunes.java @@ -0,0 +1,149 @@ +/* + * ITunes.java + * + * Created on November 19, 2005, 10:58 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes; + +import com.rometools.rome.feed.module.Module; + +import java.net.URL; + +/** + * This interface contains the methods common to all iTunes module points. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.3 $ + */ +public interface ITunes extends Module { + + public static final String URI = AbstractITunesObject.URI; + + /** + * Returns the author string for this feed or entry + * + * @return Returns the author string for this feed or entry + */ + public String getAuthor(); + + /** + * Sets the author string for this feed or entry + * + * @param author Sets the author string for this feed or entry + */ + public void setAuthor(String author); + + /** + * Boolean as to whether to block this feed or entry + * + * @return Boolean as to whether to block this feed or entry + */ + public boolean getBlock(); + + /** + * Boolean as to whether to block this feed or entry + * + * @param block Boolean as to whether to block this feed or entry + */ + public void setBlock(boolean block); + + /** + * Boolean as to whether this feed or entry contains adult content + * + * @return Boolean as to whether this feed or entry contains adult content + */ + public boolean getExplicit(); + + /** + * Boolean as to whether this feed or entry contains adult content + * + * @param explicit Boolean as to whether this feed or entry contains adult content + */ + public void setExplicit(boolean explicit); + + public URL getImage(); + + public void setImage(URL image); + + /** + * A list of keywords for this feed or entry + * + * Must not contain spaces + * + * @return A list of keywords for this feed or entry + */ + public String[] getKeywords(); + + /** + * A list of keywords for this feed or entry + * + * Must not contain spaces + * + * @param keywords A list of keywords for this feed or enty + */ + public void setKeywords(String[] keywords); + + /** + * A subtitle for this feed or entry + * + * @return A subtitle for this feed or entry + */ + public String getSubtitle(); + + /** + * A subtitle for this feed or entry + * + * @param subtitle A subtitle for this feed or entry + */ + public void setSubtitle(String subtitle); + + /** + * A subtitle for this feed or entry + * + * @return A subtitle for this feed or entry + */ + public String getSummary(); + + /** + * A subtitle for this feed or entry + * + * @param summary A subtitle for this feed or entry + */ + public void setSummary(String summary); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesGenerator.java b/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesGenerator.java new file mode 100644 index 0000000..e4fc68a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesGenerator.java @@ -0,0 +1,207 @@ +/* + * ITunesGenerator.java + * + * Created on August 1, 2005, 10:44 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes.io; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.itunes.AbstractITunesObject; +import com.rometools.modules.itunes.EntryInformationImpl; +import com.rometools.modules.itunes.FeedInformationImpl; +import com.rometools.modules.itunes.types.Category; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * @version $Revision: 1.3 $ + * @author Robert "kebernet" Cooper + */ +public class ITunesGenerator implements ModuleGenerator { + + private static final HashSet NAMESPACES = new HashSet(); + private static final Namespace NAMESPACE = Namespace.getNamespace(AbstractITunesObject.PREFIX, AbstractITunesObject.URI); + + static { + NAMESPACES.add(NAMESPACE); + } + + /** Creates a new instance of ITunesGenerator */ + public ITunesGenerator() { + } + + @Override + public void generate(final Module module, final Element element) { + Element root = element; + + while (root.getParent() != null && root.getParent() instanceof Element) { + root = (Element) root.getParent(); + } + + root.addNamespaceDeclaration(NAMESPACE); + + if (!(module instanceof AbstractITunesObject)) { + return; + } + + final AbstractITunesObject itunes = (AbstractITunesObject) module; + + if (itunes instanceof FeedInformationImpl) { + // Do Channel Specific Stuff. + final FeedInformationImpl info = (FeedInformationImpl) itunes; + final Element owner = generateSimpleElement("owner", ""); + final Element email = generateSimpleElement("email", info.getOwnerEmailAddress()); + owner.addContent(email); + + final Element name = generateSimpleElement("name", info.getOwnerName()); + owner.addContent(name); + element.addContent(owner); + + final List categories = info.getCategories(); + for (final Category cat : categories) { + + final Element category = generateSimpleElement("category", ""); + category.setAttribute("text", cat.getName()); + + if (cat.getSubcategory() != null) { + final Element subcat = generateSimpleElement("category", ""); + subcat.setAttribute("text", cat.getSubcategory().getName()); + category.addContent(subcat); + } + + element.addContent(category); + } + + if (info.getComplete()) { + element.addContent(generateSimpleElement("complete", "yes")); + } + + if (info.getNewFeedUrl() != null) { + element.addContent(generateSimpleElement("new-feed-url", info.getNewFeedUrl())); + } + + } else if (itunes instanceof EntryInformationImpl) { + final EntryInformationImpl info = (EntryInformationImpl) itunes; + + if (info.getDuration() != null) { + element.addContent(generateSimpleElement("duration", info.getDuration().toString())); + } + if (info.getClosedCaptioned()) { + element.addContent(generateSimpleElement("isClosedCaptioned", "yes")); + } + if (info.getOrder() != null) { + element.addContent(generateSimpleElement("order", info.getOrder().toString())); + } + } + + if (itunes.getAuthor() != null) { + element.addContent(generateSimpleElement("author", itunes.getAuthor())); + } + + if (itunes.getBlock()) { + element.addContent(generateSimpleElement("block", "")); + } + + if (itunes.getExplicit()) { + element.addContent(generateSimpleElement("explicit", "yes")); + } else { + element.addContent(generateSimpleElement("explicit", "no")); + } + + if (itunes.getImage() != null) { + final Element image = generateSimpleElement("image", ""); + image.setAttribute("href", itunes.getImage().toExternalForm()); + element.addContent(image); + } + + if (itunes.getKeywords() != null) { + final StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < itunes.getKeywords().length; i++) { + if (i != 0) { + sb.append(", "); + } + + sb.append(itunes.getKeywords()[i]); + } + + element.addContent(generateSimpleElement("keywords", sb.toString())); + } + + if (itunes.getSubtitle() != null) { + element.addContent(generateSimpleElement("subtitle", itunes.getSubtitle())); + } + + if (itunes.getSummary() != null) { + element.addContent(generateSimpleElement("summary", itunes.getSummary())); + } + } + + /** + * Returns the list of namespaces this module uses. + * + * @return set of Namespace objects. + */ + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + /** + * Returns the namespace URI this module handles. + * + * @return Returns the namespace URI this module handles. + */ + @Override + public String getNamespaceUri() { + return AbstractITunesObject.URI; + } + + protected Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, NAMESPACE); + element.addContent(value); + + return element; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesParser.java b/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesParser.java new file mode 100644 index 0000000..1986df7 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesParser.java @@ -0,0 +1,234 @@ +/* + * ITunesParser.java + * + * Created on August 1, 2005, 8:29 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes.io; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Locale; +import java.util.StringTokenizer; + +import org.jdom2.Content; +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.jdom2.output.XMLOutputter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.itunes.AbstractITunesObject; +import com.rometools.modules.itunes.EntryInformationImpl; +import com.rometools.modules.itunes.FeedInformationImpl; +import com.rometools.modules.itunes.types.Category; +import com.rometools.modules.itunes.types.Duration; +import com.rometools.modules.itunes.types.Subcategory; +import com.rometools.rome.io.ModuleParser; +import com.rometools.rome.io.WireFeedParser; + +/** + * @version $Revision: 1.10 $ + * @author Robert "kebernet" Cooper + */ +public class ITunesParser implements ModuleParser { + + private static final Logger LOG = LoggerFactory.getLogger(ITunesParser.class); + + Namespace ns = Namespace.getNamespace(AbstractITunesObject.URI); + + /** Creates a new instance of ITunesParser */ + public ITunesParser() { + } + + public void setParser(final WireFeedParser feedParser) { + } + + @Override + public String getNamespaceUri() { + return AbstractITunesObject.URI; + } + + @Override + public com.rometools.rome.feed.module.Module parse(final Element element, final Locale locale) { + AbstractITunesObject module = null; + + if (element.getName().equals("channel")) { + final FeedInformationImpl feedInfo = new FeedInformationImpl(); + module = feedInfo; + + // Now I am going to get the channel specific tags + final Element owner = element.getChild("owner", ns); + + if (owner != null) { + final Element name = owner.getChild("name", ns); + + if (name != null) { + feedInfo.setOwnerName(name.getValue().trim()); + } + + final Element email = owner.getChild("email", ns); + + if (email != null) { + feedInfo.setOwnerEmailAddress(email.getValue().trim()); + } + } + + final List categories = element.getChildren("category", ns); + for (final Element element2 : categories) { + final Element category = element2; + if (category != null && category.getAttribute("text") != null) { + final Category cat = new Category(); + cat.setName(category.getAttribute("text").getValue().trim()); + + final Element subcategory = category.getChild("category", ns); + + if (subcategory != null && subcategory.getAttribute("text") != null) { + final Subcategory subcat = new Subcategory(); + subcat.setName(subcategory.getAttribute("text").getValue().trim()); + cat.setSubcategory(subcat); + } + + feedInfo.getCategories().add(cat); + } + } + + final Element complete = element.getChild("complete", ns); + if (complete != null) { + feedInfo.setComplete("yes".equals(complete.getTextTrim().toLowerCase())); + } + + final Element newFeedUrl = element.getChild("new-feed-url", ns); + if (newFeedUrl != null) { + feedInfo.setNewFeedUrl(newFeedUrl.getTextTrim()); + } + + } else if (element.getName().equals("item")) { + final EntryInformationImpl entryInfo = new EntryInformationImpl(); + module = entryInfo; + + // Now I am going to get the item specific tags + + final Element duration = element.getChild("duration", ns); + + if (duration != null && duration.getValue() != null) { + final Duration dur = new Duration(duration.getValue().trim()); + entryInfo.setDuration(dur); + } + + final Element closedCaptioned = element.getChild("isClosedCaptioned", ns); + + if (closedCaptioned != null && closedCaptioned.getValue() != null && closedCaptioned.getValue().trim().equalsIgnoreCase("yes")) { + entryInfo.setClosedCaptioned(true); + } + + final Element order = element.getChild("order", ns); + + if (order != null && order.getValue() != null) { + final Integer o = Integer.valueOf(order.getValue().trim()); + entryInfo.setOrder(o); + } + } + if (module != null) { + // All these are common to both Channel and Item + final Element author = element.getChild("author", ns); + + if (author != null && author.getText() != null) { + module.setAuthor(author.getText()); + } + + final Element block = element.getChild("block", ns); + + if (block != null) { + module.setBlock(true); + } + + final Element explicit = element.getChild("explicit", ns); + + if (explicit != null && explicit.getValue() != null && explicit.getValue().trim().equalsIgnoreCase("yes")) { + module.setExplicit(true); + } + + final Element keywords = element.getChild("keywords", ns); + + if (keywords != null) { + final StringTokenizer tok = new StringTokenizer(getXmlInnerText(keywords).trim(), ","); + final String[] keywordsArray = new String[tok.countTokens()]; + + for (int i = 0; tok.hasMoreTokens(); i++) { + keywordsArray[i] = tok.nextToken(); + } + + module.setKeywords(keywordsArray); + } + + final Element subtitle = element.getChild("subtitle", ns); + + if (subtitle != null) { + module.setSubtitle(subtitle.getTextTrim()); + } + + final Element summary = element.getChild("summary", ns); + + if (summary != null) { + module.setSummary(summary.getTextTrim()); + } + + final Element image = element.getChild("image", ns); + + if (image != null && image.getAttributeValue("href") != null) { + try { + final URL imageURL = new URL(image.getAttributeValue("href").trim()); + module.setImage(imageURL); + } catch (final MalformedURLException e) { + LOG.debug("Malformed URL Exception reading itunes:image tag: {}", image.getAttributeValue("href")); + } + } + } + + return module; + } + + protected String getXmlInnerText(final Element e) { + final StringBuffer sb = new StringBuffer(); + final XMLOutputter xo = new XMLOutputter(); + final List children = e.getContent(); + sb.append(xo.outputString(children)); + return sb.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesParserOldNamespace.java b/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesParserOldNamespace.java new file mode 100644 index 0000000..ac05a7b --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesParserOldNamespace.java @@ -0,0 +1,62 @@ +/* + * ITunesParserOldNamespace.java + * + * Created on April 23, 2006, 2:09 AM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes.io; + +import org.jdom2.Namespace; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class ITunesParserOldNamespace extends ITunesParser { + String URI = "http://www.itunes.com/DTDs/Podcast-1.0.dtd"; + + /** Creates a new instance of ITunesParserOldNamespace */ + public ITunesParserOldNamespace() { + super(); + super.ns = Namespace.getNamespace(URI); + } + + @Override + public String getNamespaceUri() { + return URI; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/package.html b/rome-modules/src/main/java/com/rometools/modules/itunes/package.html new file mode 100644 index 0000000..a618e26 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/package.html @@ -0,0 +1,74 @@ + + + + + + + + + This is a ROME plug in that implements the iTunes RSS extensions as defined + by Apple in their + documentation. BTW, an anti-shoutout to Apple for moving the original + PDF spec + . Thanks for making it harder than it needed to be. + +

Sample Usage:

+
+        SyndFeedInput input = new SyndFeedInput();
+        SyndFeed syndfeed = input.build(new XmlReader(feed.toURL()));
+
+        Module module = syndfeed.getModule("http://www.itunes.com/DTDs/Podcast-1.0.dtd");
+        FeedInformation feedInfo = (FeedInformation) module;
+        
+        System.out.println( feedInfo.getImage() );
+        System.out.println( feedInfo.getCategory() );
+        
+        // Or to create a feed..
+        
+        ArrayList modules = new ArrayList();
+        EntryInformation e = new EntryInformationImpl();
+        e.setDuration( new Duration( 10000 ) );
+        modules.add( e );
+        syndEntry.setModules( modules );
+    
+ + Similarly you can get an EntryInformation object off SyndEntries or Items. + + +
+ * This library is provided under dual licenses.
+ * You may choose the terms of the Lesser General Public License or the Apache
+ * License at your discretion.
+ *
+ *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * 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/rome-modules/src/main/java/com/rometools/modules/itunes/types/Category.java b/rome-modules/src/main/java/com/rometools/modules/itunes/types/Category.java new file mode 100644 index 0000000..50e6eaf --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/types/Category.java @@ -0,0 +1,136 @@ +/* + * Category.java + * + * Created on August 1, 2005, 7:24 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes.types; + +import java.io.Serializable; + +/** + * This Category information. Basically a name and an optional Subcategory. Categories are defined + * by Apple. See ITMS for a view. + * + * @version $Revision: 1.2 $ + * @author Robert "kebernet" Cooper + */ +public class Category implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + private String name; + private Subcategory subcategory; + + /** Creates a new instance of Category */ + public Category() { + } + + /** + * Creates a new instance of Category with a given name. + * + * @param name Name of the category. + */ + public Category(final String name) { + setName(name); + } + + /** + * Returns the name of the category + * + * @return Returns the name of the category + */ + public String getName() { + return name; + } + + /** + * Sets the name of the category + * + * @param name Sets the name of the category + */ + public void setName(final String name) { + this.name = name; + } + + /** + * Returns the Subcategory object for this category + * + * @return Returns the Subcategory object for this category + */ + public Subcategory getSubcategory() { + return subcategory; + } + + /** + * Sets the Subcategory object for this category + * + * @param subcategory Sets the Subcategory object for this category + */ + public void setSubcategory(final Subcategory subcategory) { + this.subcategory = subcategory; + } + + /** + * Returns a copy of this category. + * + * @return Returns a copy of this category. + */ + @Override + public Object clone() { + final Category c = new Category(); + c.setName(getName()); + + if (getSubcategory() != null) { + c.setSubcategory((Subcategory) getSubcategory().clone()); + } + + return c; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer(getName()); + + if (getSubcategory() != null) { + sb.append(" -> " + getSubcategory().toString()); + } + + return sb.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/types/Duration.java b/rome-modules/src/main/java/com/rometools/modules/itunes/types/Duration.java new file mode 100644 index 0000000..7d04273 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/types/Duration.java @@ -0,0 +1,166 @@ +/* + * Duration.java + * + * Created on August 1, 2005, 7:45 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes.types; + +import java.io.Serializable; +import java.text.NumberFormat; +import java.util.StringTokenizer; + +import com.rometools.rome.io.impl.NumberParser; + +/** + * An encapsulation of the duration of a podcast. This will serialize (via .toString()) to HH:MM:SS + * format, and can parse [H]*H:[M]*M:[S]*S or [M]*M:[S]*S. + * + * @version $Revision: 1.7 $ + * @author Robert "kebernet" Cooper + */ +public class Duration implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + static final long SECOND = 1000; + static final long MINUTE = SECOND * 60; + static final long HOUR = MINUTE * 60; + static final NumberFormat NUM_FORMAT = NumberFormat.getNumberInstance(); + static { + NUM_FORMAT.setMinimumFractionDigits(0); + NUM_FORMAT.setMaximumFractionDigits(0); + NUM_FORMAT.setMinimumIntegerDigits(2); + NUM_FORMAT.setGroupingUsed(false); + } + private long milliseconds; + + /** + * Creates a new Duration object with 0 length. + */ + public Duration() { + super(); + } + + /** + * Creates a new instance of Duration specifying a length in milliseconds + * + * @param milliseconds Creates a new instance of Duration specifying a length in milliseconds + */ + public Duration(final long milliseconds) { + setMilliseconds(milliseconds); + } + + /** + * Creates a new duration object with the given hours, minutes and seconds + * + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + */ + public Duration(final int hours, final int minutes, final float seconds) { + setMilliseconds(hours * HOUR + minutes * MINUTE + (long) (seconds * SECOND)); + } + + /** + * Creates a new Duration parsing the String value. + * + * @param duration A String to parse + */ + public Duration(final String duration) { + final StringTokenizer tok = new StringTokenizer(duration, ":"); + switch (tok.countTokens()) { + case 1: + setMilliseconds((long) (NumberParser.parseFloat(tok.nextToken(), 0f) * SECOND)); + break; + case 2: + setMilliseconds(NumberParser.parseLong(tok.nextToken(), 0l) * MINUTE + (long) (NumberParser.parseFloat(tok.nextToken(), 0f) * SECOND)); + break; + case 3: + setMilliseconds(NumberParser.parseLong(tok.nextToken(), 0l) * HOUR + NumberParser.parseLong(tok.nextToken(), 0l) * MINUTE + + (long) (NumberParser.parseFloat(tok.nextToken(), 0f) * SECOND)); + break; + default: + throw new RuntimeException("Illegal time value: " + duration); + } + } + + /** + * Returns a String representation in the formation HH:MM:SS + * + * @return Returns a String representation in the formation HH:MM:SS + */ + @Override + public String toString() { + final Time time = new Time(); + + return NUM_FORMAT.format(time.hours) + ":" + NUM_FORMAT.format(time.minutes) + ":" + NUM_FORMAT.format(Math.round(time.seconds)); + } + + /** + * Returns the millisecond length + * + * @return the millisecond length + */ + public long getMilliseconds() { + return milliseconds; + } + + /** + * Sets the millisecond length + * + * @param milliseconds the millisecond length + */ + public void setMilliseconds(final long milliseconds) { + this.milliseconds = milliseconds; + } + + private class Time { + int hours; + int minutes; + float seconds; + + public Time() { + long time = getMilliseconds(); + hours = (int) (time / HOUR); + time = time - hours * HOUR; + minutes = (int) (time / MINUTE); + time = time - minutes * MINUTE; + seconds = (float) time / (float) SECOND; + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/types/Subcategory.java b/rome-modules/src/main/java/com/rometools/modules/itunes/types/Subcategory.java new file mode 100644 index 0000000..0c68b92 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/types/Subcategory.java @@ -0,0 +1,111 @@ +/* + * SubCategory.java + * + * Created on August 1, 2005, 7:24 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.itunes.types; + +import java.io.Serializable; + +/** + * This class represents a Subcategor of a Category. + * + * @author Robert "kebernet" Cooper + * @version $Revision: 1.2 $ + */ +public class Subcategory implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + private String name; + + /** Creates a new instance of SubCategory */ + public Subcategory() { + } + + /** + * Creates a new instance of Category with a given name. + * + * @param name Name of the category. + */ + public Subcategory(final String name) { + setName(name); + } + + /** + * Returns the name of the subcategory. + * + * @return Returns the name of the subcategory. + */ + public String getName() { + return name; + } + + /** + * Set the name of the subcategory. + * + * @param name Set the name of the subcategory. + */ + public void setName(final String name) { + this.name = name; + } + + /** + * Clones the object. + * + * @return Clone of the object. + */ + @Override + public Object clone() { + final Subcategory sc = new Subcategory(); + sc.setName(getName()); + + return sc; + } + + /** + * String representation of the object. + * + * @return String representation of the object. + */ + @Override + public String toString() { + return new StringBuffer(getName()).toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/types/package.html b/rome-modules/src/main/java/com/rometools/modules/itunes/types/package.html new file mode 100644 index 0000000..98e5105 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/types/package.html @@ -0,0 +1,47 @@ + + + + + + + + This package contains data types for use wit the iTunes plug in. + +
+ * This library is provided under dual licenses.
+ * You may choose the terms of the Lesser General Public License or the Apache
+ * License at your discretion.
+ *
+ *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * 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/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaEntryModule.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaEntryModule.java new file mode 100644 index 0000000..1b3b8b8 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaEntryModule.java @@ -0,0 +1,47 @@ +/* + * MediaEntryModule.java + * + * Created on April 19, 2006, 1:15 AM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss; + +import com.rometools.modules.mediarss.types.MediaContent; +import com.rometools.modules.mediarss.types.MediaGroup; + +/** + * Represents entry/item level information. + * + * @author cooper + */ +public interface MediaEntryModule extends MediaModule { + /** + * Returns the MediaContent items for the entry. + * + * @return Returns the MediaContent items for the entry. + */ + public MediaContent[] getMediaContents(); + + /** + * Returns the media groups for the entry. + * + * @return Returns the media groups for the entry. + */ + public MediaGroup[] getMediaGroups(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaEntryModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaEntryModuleImpl.java new file mode 100644 index 0000000..ecf6871 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaEntryModuleImpl.java @@ -0,0 +1,134 @@ +/* + * Copyright 2006 Nathanial X. Freitas, openvision.tv + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss; + +import java.io.Serializable; + +import com.rometools.modules.mediarss.types.MediaContent; +import com.rometools.modules.mediarss.types.MediaGroup; +import com.rometools.modules.mediarss.types.Metadata; +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * Represents information for an Entry/Item level. + * + * @author Nathanial X. Freitas + */ +public class MediaEntryModuleImpl extends MediaModuleImpl implements MediaEntryModule, Cloneable, Serializable { + private static final long serialVersionUID = 1L; + + /* + * the variables in the MediaModule are set when they apply to all MediaContent instances in the + * set + */ + private MediaContent[] mediaContents = new MediaContent[0]; + private MediaGroup[] mediaGroups = new MediaGroup[0]; + + /** + * Creates a new instance. + */ + public MediaEntryModuleImpl() { + super(MediaEntryModule.class, MediaModule.URI); + } + + /** + * MediaContent items for the entry + * + * @param mediaContents MediaContent items for the entry + */ + public void setMediaContents(final MediaContent[] mediaContents) { + this.mediaContents = mediaContents == null ? new MediaContent[0] : mediaContents; + } + + /** + * MediaContent items for the entry + * + * @return MediaContent items for the entry + */ + @Override + public MediaContent[] getMediaContents() { + return mediaContents; + } + + /** + * MediaGroups for the entry + * + * @param mediaGroups MediaGroups for the entry + */ + public void setMediaGroups(final MediaGroup[] mediaGroups) { + this.mediaGroups = mediaGroups == null ? new MediaGroup[0] : mediaGroups; + } + + /** + * MediaGroups for the entry + * + * @return MediaGroups for the entry + */ + @Override + public MediaGroup[] getMediaGroups() { + return mediaGroups; + } + + @Override + public Object clone() { + final MediaEntryModuleImpl m = new MediaEntryModuleImpl(); + m.setMediaContents(mediaContents.clone()); + m.setMediaGroups(mediaGroups.clone()); + m.setMetadata(getMetadata() == null ? null : (Metadata) getMetadata().clone()); + m.setPlayer(getPlayer()); + + return m; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(MediaEntryModuleImpl.class, this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(MediaEntryModuleImpl.class, this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(MediaEntryModuleImpl.class, this); + + return tsBean.toString(); + } + + @Override + public void copyFrom(final CopyFrom obj) { + MediaEntryModuleImpl other = (MediaEntryModuleImpl) obj; + other = (MediaEntryModuleImpl) other.clone(); + setMediaContents(other.getMediaContents()); + setMediaGroups(other.getMediaGroups()); + setMetadata(other.getMetadata()); + setPlayer(other.getPlayer()); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaModule.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaModule.java new file mode 100644 index 0000000..9e1c56d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaModule.java @@ -0,0 +1,54 @@ +/* + * Copyright 2006 Nathanial X. Freitas, openvision.tv + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss; + +import com.rometools.modules.mediarss.types.Metadata; +import com.rometools.modules.mediarss.types.PlayerReference; +import com.rometools.rome.feed.module.Module; + +/** + * This is the base module for MediaRSS. + *

+ * It represents information that can be stored at the feed level, as well is a base for entry level + * information, as the same information can apply. + *

+ * + * @author Nathanial X. Freitas + */ +public interface MediaModule extends Module { + // the URI of the MediaRSS specification as hosted by yahoo + public final static String URI = "http://search.yahoo.com/mrss/"; + + /** + * Returns Metadata associated with the feed. + * + * @return Returns Metadata associated with the feed. + */ + public Metadata getMetadata(); + + /** + * Returns a player reference associated with the feed. + * + * @return Returns a player reference associated with the feed. + */ + public PlayerReference getPlayer(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaModuleImpl.java new file mode 100644 index 0000000..fbb0cc0 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/MediaModuleImpl.java @@ -0,0 +1,122 @@ +/* + * MediaModuleImpl.java + * + * Created on April 19, 2006, 1:17 AM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss; + +import java.io.Serializable; + +import com.rometools.modules.mediarss.types.Metadata; +import com.rometools.modules.mediarss.types.PlayerReference; +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.module.ModuleImpl; + +/** + * + * This class represents feed/channel level elements for MediaRSS + * + * @author cooper + */ +public class MediaModuleImpl extends ModuleImpl implements MediaModule, Serializable { + private static final long serialVersionUID = 1L; + + private Metadata metadata; + private PlayerReference player; + + /** Creates a new instance of MediaModuleImpl */ + public MediaModuleImpl() { + this(MediaModule.class, MediaModule.URI); + } + + /** + * constructor that passes values up to ModuleImpl. + * + * @param clazz + * @param uri + */ + public MediaModuleImpl(final Class clazz, final String uri) { + super(clazz, uri); + } + + @Override + public Class getInterface() { + return MediaModule.class; + } + + /** + * Metadata for a feed. + * + * @param metadata Metadata for a feed. + */ + public void setMetadata(final Metadata metadata) { + this.metadata = metadata; + } + + /** + * Metadata for a feed. + * + * @return Metadata for a feed. + */ + @Override + public Metadata getMetadata() { + return metadata; + } + + /** + * Player for a feed. + * + * @param player Player for a feed. + */ + public void setPlayer(final PlayerReference player) { + this.player = player; + } + + /** + * Player for a feed. + * + * @return Player for a feed. + */ + @Override + public PlayerReference getPlayer() { + return player; + } + + @Override + public String getUri() { + return MediaModule.URI; + } + + @Override + public Object clone() { + final MediaModuleImpl m = new MediaModuleImpl(); + m.setMetadata((Metadata) metadata.clone()); + m.setPlayer(player); + + return m; + } + + @Override + public void copyFrom(final CopyFrom obj) { + final MediaModule m = (MediaModule) obj; + metadata = (Metadata) m.getMetadata().clone(); + player = m.getPlayer(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/io/AlternateMediaModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/AlternateMediaModuleParser.java new file mode 100644 index 0000000..1f5883d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/AlternateMediaModuleParser.java @@ -0,0 +1,43 @@ +/* + * 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.rometools.modules.mediarss.io; + +import org.jdom2.Namespace; + +/** + * + * @author cooper + */ +public class AlternateMediaModuleParser extends MediaModuleParser { + + private static final Namespace NS = Namespace.getNamespace("http://search.yahoo.com/mrss"); + + /** Creates a new instance of AlternateMediaModuleParser */ + public AlternateMediaModuleParser() { + super(); + } + + @Override + public String getNamespaceUri() { + return "http://search.yahoo.com/mrss"; + } + + @Override + public Namespace getNS() { + return AlternateMediaModuleParser.NS; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleGenerator.java new file mode 100644 index 0000000..6d2ca05 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleGenerator.java @@ -0,0 +1,260 @@ +/* + * Copyright 2006 Nathanial X. Freitas, openvision.tv + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.io; + +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.mediarss.MediaEntryModule; +import com.rometools.modules.mediarss.MediaModule; +import com.rometools.modules.mediarss.types.Category; +import com.rometools.modules.mediarss.types.Credit; +import com.rometools.modules.mediarss.types.MediaContent; +import com.rometools.modules.mediarss.types.MediaGroup; +import com.rometools.modules.mediarss.types.Metadata; +import com.rometools.modules.mediarss.types.PlayerReference; +import com.rometools.modules.mediarss.types.Rating; +import com.rometools.modules.mediarss.types.Restriction; +import com.rometools.modules.mediarss.types.Text; +import com.rometools.modules.mediarss.types.Thumbnail; +import com.rometools.modules.mediarss.types.UrlReference; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +//this class TBI +public class MediaModuleGenerator implements ModuleGenerator { + + private static final Namespace NS = Namespace.getNamespace("media", MediaModule.URI); + private static final Set NAMESPACES = new HashSet(); + + static { + NAMESPACES.add(NS); + } + + @Override + public String getNamespaceUri() { + return MediaModule.URI; + } + + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + @Override + public void generate(final Module module, final Element element) { + if (module instanceof MediaModule) { + final MediaModule m = (MediaModule) module; + generateMetadata(m.getMetadata(), element); + generatePlayer(m.getPlayer(), element); + } + + if (module instanceof MediaEntryModule) { + final MediaEntryModule m = (MediaEntryModule) module; + final MediaGroup[] g = m.getMediaGroups(); + + for (final MediaGroup element2 : g) { + generateGroup(element2, element); + } + + final MediaContent[] c = m.getMediaContents(); + + for (final MediaContent element2 : c) { + generateContent(element2, element); + } + } + } + + public void generateContent(final MediaContent c, final Element e) { + final Element mc = new Element("content", NS); + addNotNullAttribute(mc, "medium", c.getMedium()); + addNotNullAttribute(mc, "channels", c.getAudioChannels()); + addNotNullAttribute(mc, "bitrate", c.getBitrate()); + addNotNullAttribute(mc, "duration", c.getDuration()); + addNotNullAttribute(mc, "expression", c.getExpression()); + addNotNullAttribute(mc, "fileSize", c.getFileSize()); + addNotNullAttribute(mc, "framerate", c.getFramerate()); + addNotNullAttribute(mc, "height", c.getHeight()); + addNotNullAttribute(mc, "lang", c.getLanguage()); + addNotNullAttribute(mc, "samplingrate", c.getSamplingrate()); + addNotNullAttribute(mc, "type", c.getType()); + addNotNullAttribute(mc, "width", c.getWidth()); + + if (c.isDefaultContent()) { + addNotNullAttribute(mc, "isDefault", "true"); + } + + if (c.getReference() instanceof UrlReference) { + addNotNullAttribute(mc, "url", c.getReference()); + generatePlayer(c.getPlayer(), mc); + } else { + generatePlayer(c.getPlayer(), mc); + } + + generateMetadata(c.getMetadata(), mc); + e.addContent(mc); + } + + public void generateGroup(final MediaGroup g, final Element e) { + final Element t = new Element("group", NS); + final MediaContent[] c = g.getContents(); + + for (final MediaContent element : c) { + generateContent(element, t); + } + + generateMetadata(g.getMetadata(), t); + e.addContent(t); + } + + public void generateMetadata(final Metadata m, final Element e) { + if (m == null) { + return; + } + + final Category[] cats = m.getCategories(); + + for (final Category cat : cats) { + final Element c = generateSimpleElement("category", cat.getValue()); + addNotNullAttribute(c, "scheme", cat.getScheme()); + addNotNullAttribute(c, "label", cat.getLabel()); + e.addContent(c); + } + + final Element copyright = addNotNullElement(e, "copyright", m.getCopyright()); + addNotNullAttribute(copyright, "url", m.getCopyrightUrl()); + + final Credit[] creds = m.getCredits(); + + for (final Credit cred : creds) { + final Element c = generateSimpleElement("credit", cred.getName()); + addNotNullAttribute(c, "role", cred.getRole()); + addNotNullAttribute(c, "scheme", cred.getScheme()); + e.addContent(c); + } + + final Element desc = addNotNullElement(e, "description", m.getDescription()); + addNotNullAttribute(desc, "type", m.getDescriptionType()); + + if (m.getHash() != null) { + final Element hash = addNotNullElement(e, "hash", m.getHash().getValue()); + addNotNullAttribute(hash, "algo", m.getHash().getAlgorithm()); + } + + final String[] keywords = m.getKeywords(); + + if (keywords.length > 0) { + String keyword = keywords[0]; + + for (int i = 1; i < keywords.length; i++) { + keyword += ", " + keywords[i]; + } + + addNotNullElement(e, "keywords", keyword); + } + + final Rating[] rats = m.getRatings(); + + for (final Rating rat2 : rats) { + final Element rat = addNotNullElement(e, "rating", rat2.getValue()); + addNotNullAttribute(rat, "scheme", rat2.getScheme()); + + if (rat2.equals(Rating.ADULT)) { + addNotNullElement(e, "adult", "true"); + } else if (rat2.equals(Rating.NONADULT)) { + addNotNullElement(e, "adult", "false"); + } + } + + final Text[] text = m.getText(); + + for (final Text element : text) { + final Element t = addNotNullElement(e, "text", element.getValue()); + addNotNullAttribute(t, "type", element.getType()); + addNotNullAttribute(t, "start", element.getStart()); + addNotNullAttribute(t, "end", element.getEnd()); + } + + final Thumbnail[] thumbs = m.getThumbnail(); + + for (final Thumbnail thumb : thumbs) { + final Element t = new Element("thumbnail", NS); + addNotNullAttribute(t, "url", thumb.getUrl()); + addNotNullAttribute(t, "width", thumb.getWidth()); + addNotNullAttribute(t, "height", thumb.getHeight()); + addNotNullAttribute(t, "time", thumb.getTime()); + e.addContent(t); + } + + final Element title = addNotNullElement(e, "title", m.getTitle()); + addNotNullAttribute(title, "type", m.getTitleType()); + + final Restriction[] r = m.getRestrictions(); + + for (final Restriction element : r) { + final Element res = addNotNullElement(e, "restriction", element.getValue()); + addNotNullAttribute(res, "type", element.getType()); + addNotNullAttribute(res, "relationship", element.getRelationship()); + } + } + + public void generatePlayer(final PlayerReference p, final Element e) { + if (p == null) { + return; + } + + final Element t = new Element("player", NS); + addNotNullAttribute(t, "url", p.getUrl()); + addNotNullAttribute(t, "width", p.getWidth()); + addNotNullAttribute(t, "height", p.getHeight()); + e.addContent(t); + } + + protected void addNotNullAttribute(final Element target, final String name, final Object value) { + if (target == null || value == null) { + return; + } else { + target.setAttribute(name, value.toString()); + } + } + + protected Element addNotNullElement(final Element target, final String name, final Object value) { + if (value == null) { + return null; + } else { + final Element e = generateSimpleElement(name, value.toString()); + target.addContent(e); + + return e; + } + } + + protected Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, NS); + element.addContent(value); + + return element; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleParser.java new file mode 100644 index 0000000..2cfa573 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleParser.java @@ -0,0 +1,468 @@ +/* + * Copyright 2006 Nathanial X. Freitas, openvision.tv + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.io; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.StringTokenizer; + +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.mediarss.MediaEntryModuleImpl; +import com.rometools.modules.mediarss.MediaModule; +import com.rometools.modules.mediarss.MediaModuleImpl; +import com.rometools.modules.mediarss.types.Category; +import com.rometools.modules.mediarss.types.Credit; +import com.rometools.modules.mediarss.types.Expression; +import com.rometools.modules.mediarss.types.Hash; +import com.rometools.modules.mediarss.types.MediaContent; +import com.rometools.modules.mediarss.types.MediaGroup; +import com.rometools.modules.mediarss.types.Metadata; +import com.rometools.modules.mediarss.types.PlayerReference; +import com.rometools.modules.mediarss.types.Rating; +import com.rometools.modules.mediarss.types.Restriction; +import com.rometools.modules.mediarss.types.Text; +import com.rometools.modules.mediarss.types.Thumbnail; +import com.rometools.modules.mediarss.types.Time; +import com.rometools.modules.mediarss.types.UrlReference; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; +import com.rometools.utils.Integers; +import com.rometools.utils.Longs; +import com.rometools.utils.Strings; + +/** + * @author Nathanial X. Freitas + * + */ +public class MediaModuleParser implements ModuleParser { + + private static final Logger LOG = LoggerFactory.getLogger(MediaModuleParser.class); + + private static final Namespace NS = Namespace.getNamespace(MediaModule.URI); + + @Override + public String getNamespaceUri() { + return MediaModule.URI; + } + + @Override + public Module parse(final Element mmRoot, final Locale locale) { + MediaModuleImpl mod = null; + + if (mmRoot.getName().equals("channel") || mmRoot.getName().equals("feed")) { + mod = new MediaModuleImpl(); + } else { + mod = new MediaEntryModuleImpl(); + } + + mod.setMetadata(parseMetadata(mmRoot)); + mod.setPlayer(parsePlayer(mmRoot)); + + if (mod instanceof MediaEntryModuleImpl) { + final MediaEntryModuleImpl m = (MediaEntryModuleImpl) mod; + m.setMediaContents(parseContent(mmRoot)); + m.setMediaGroups(parseGroup(mmRoot)); + } + + return mod; + } + + private MediaContent[] parseContent(final Element e) { + + final List contents = e.getChildren("content", getNS()); + final ArrayList values = new ArrayList(); + + try { + for (int i = 0; contents != null && i < contents.size(); i++) { + final Element content = contents.get(i); + MediaContent mc = null; + + if (content.getAttributeValue("url") != null) { + try { + mc = new MediaContent(new UrlReference(new URI(content.getAttributeValue("url").replace(' ', '+')))); + mc.setPlayer(parsePlayer(content)); + } catch (final Exception ex) { + LOG.warn("Exception parsing content tag.", ex); + } + } else { + mc = new MediaContent(parsePlayer(content)); + } + if (mc != null) { + values.add(mc); + try { + if (content.getAttributeValue("channels") != null) { + mc.setAudioChannels(Integer.valueOf(content.getAttributeValue("channels"))); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing content tag.", ex); + } + try { + if (content.getAttributeValue("bitrate") != null) { + mc.setBitrate(Float.valueOf(content.getAttributeValue("bitrate"))); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing content tag.", ex); + } + try { + if (content.getAttributeValue("duration") != null) { + mc.setDuration(Longs.parseDecimal(content.getAttributeValue("duration"))); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing content tag.", ex); + } + + mc.setMedium(content.getAttributeValue("medium")); + + final String expression = content.getAttributeValue("expression"); + + if (expression != null) { + if (expression.equalsIgnoreCase("full")) { + mc.setExpression(Expression.FULL); + } else if (expression.equalsIgnoreCase("sample")) { + mc.setExpression(Expression.SAMPLE); + } else if (expression.equalsIgnoreCase("nonstop")) { + mc.setExpression(Expression.NONSTOP); + } + } + + try { + if (content.getAttributeValue("fileSize") != null) { + mc.setFileSize(Long.valueOf(content.getAttributeValue("fileSize"))); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing content tag.", ex); + } + try { + if (content.getAttributeValue("framerate") != null) { + mc.setFramerate(Float.valueOf(content.getAttributeValue("framerate"))); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing content tag.", ex); + } + try { + if (content.getAttributeValue("height") != null) { + mc.setHeight(Integer.valueOf(content.getAttributeValue("height"))); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing content tag.", ex); + } + + mc.setLanguage(content.getAttributeValue("lang")); + mc.setMetadata(parseMetadata(content)); + try { + if (content.getAttributeValue("samplingrate") != null) { + mc.setSamplingrate(Float.valueOf(content.getAttributeValue("samplingrate"))); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing content tag.", ex); + } + + mc.setType(content.getAttributeValue("type")); + try { + if (content.getAttributeValue("width") != null) { + mc.setWidth(Integer.valueOf(content.getAttributeValue("width"))); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing content tag.", ex); + } + + if (content.getAttributeValue("isDefault") != null) { + mc.setDefaultContent(Boolean.valueOf(content.getAttributeValue("isDefault"))); + } + } else { + LOG.warn("Could not find MediaContent."); + } + + } + } catch (final Exception ex) { + LOG.warn("Exception parsing content tag.", ex); + } + + return values.toArray(new MediaContent[values.size()]); + } + + private MediaGroup[] parseGroup(final Element e) { + final List groups = e.getChildren("group", getNS()); + final ArrayList values = new ArrayList(); + + for (int i = 0; groups != null && i < groups.size(); i++) { + final Element group = groups.get(i); + final MediaGroup g = new MediaGroup(parseContent(group)); + + for (int j = 0; j < g.getContents().length; j++) { + if (g.getContents()[j].isDefaultContent()) { + g.setDefaultContentIndex(new Integer(j)); + + break; + } + } + + g.setMetadata(parseMetadata(group)); + values.add(g); + } + + return values.toArray(new MediaGroup[values.size()]); + } + + private Metadata parseMetadata(final Element e) { + final Metadata md = new Metadata(); + // categories + { + final List categories = e.getChildren("category", getNS()); + final ArrayList values = new ArrayList(); + + for (int i = 0; categories != null && i < categories.size(); i++) { + try { + final Element cat = categories.get(i); + values.add(new Category(cat.getAttributeValue("scheme"), cat.getAttributeValue("label"), cat.getText())); + } catch (final Exception ex) { + LOG.warn("Exception parsing category tag.", ex); + } + } + + md.setCategories(values.toArray(new Category[values.size()])); + } + + // copyright + try { + final Element copy = e.getChild("copyright", getNS()); + + if (copy != null) { + md.setCopyright(copy.getText()); + md.setCopyrightUrl(copy.getAttributeValue("url") != null ? new URI(copy.getAttributeValue("url")) : null); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing copyright tag.", ex); + } + // credits + { + final List credits = e.getChildren("credit", getNS()); + final ArrayList values = new ArrayList(); + + for (int i = 0; credits != null && i < credits.size(); i++) { + try { + final Element cred = credits.get(i); + values.add(new Credit(cred.getAttributeValue("scheme"), cred.getAttributeValue("role"), cred.getText())); + md.setCredits(values.toArray(new Credit[values.size()])); + } catch (final Exception ex) { + LOG.warn("Exception parsing credit tag.", ex); + } + } + } + + // description + try { + final Element description = e.getChild("description", getNS()); + + if (description != null) { + md.setDescription(description.getText()); + md.setDescriptionType(description.getAttributeValue("type")); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing description tag.", ex); + } + + // hash + try { + final Element hash = e.getChild("hash", getNS()); + + if (hash != null) { + md.setHash(new Hash(hash.getAttributeValue("algo"), hash.getText())); + } + } catch (final Exception ex) { + LOG.warn("Exception parsing hash tag.", ex); + } + // keywords + { + final Element keywords = e.getChild("keywords", getNS()); + + if (keywords != null) { + final StringTokenizer tok = new StringTokenizer(keywords.getText(), ","); + final String[] value = new String[tok.countTokens()]; + + for (int i = 0; tok.hasMoreTokens(); i++) { + value[i] = tok.nextToken().trim(); + } + + md.setKeywords(value); + } + } + // ratings + { + final ArrayList values = new ArrayList(); + + final List ratings = e.getChildren("rating", getNS()); + for (final Element ratingElement : ratings) { + try { + final String ratingText = ratingElement.getText(); + String ratingScheme = Strings.trimToNull(ratingElement.getAttributeValue("scheme")); + if (ratingScheme == null) { + ratingScheme = "urn:simple"; + } + final Rating rating = new Rating(ratingScheme, ratingText); + values.add(rating); + } catch (final Exception ex) { + LOG.warn("Exception parsing rating tag.", ex); + } + } + + md.setRatings(values.toArray(new Rating[values.size()])); + + } + // text + { + final List texts = e.getChildren("text", getNS()); + final ArrayList values = new ArrayList(); + + for (int i = 0; texts != null && i < texts.size(); i++) { + try { + final Element text = texts.get(i); + final Time start = text.getAttributeValue("start") == null ? null : new Time(text.getAttributeValue("start")); + final Time end = text.getAttributeValue("end") == null ? null : new Time(text.getAttributeValue("end")); + values.add(new Text(text.getAttributeValue("type"), text.getTextTrim(), start, end)); + } catch (final Exception ex) { + LOG.warn("Exception parsing text tag.", ex); + } + } + + md.setText(values.toArray(new Text[values.size()])); + } + // thumbnails + { + final ArrayList values = new ArrayList(); + + final List thumbnails = e.getChildren("thumbnail", getNS()); + for (final Element thumb : thumbnails) { + try { + + final String timeAttr = Strings.trimToNull(thumb.getAttributeValue("time")); + Time time = null; + if (timeAttr != null) { + time = new Time(timeAttr); + } + + final String widthAttr = thumb.getAttributeValue("width"); + final Integer width = Integers.parse(widthAttr); + + final String heightAttr = thumb.getAttributeValue("height"); + final Integer height = Integers.parse(heightAttr); + + final String url = thumb.getAttributeValue("url"); + final URI uri = new URI(url); + final Thumbnail thumbnail = new Thumbnail(uri, width, height, time); + + values.add(thumbnail); + + } catch (final Exception ex) { + LOG.warn("Exception parsing thumbnail tag.", ex); + } + } + + md.setThumbnail(values.toArray(new Thumbnail[values.size()])); + } + // title + { + final Element title = e.getChild("title", getNS()); + + if (title != null) { + md.setTitle(title.getText()); + md.setTitleType(title.getAttributeValue("type")); + } + } + // restrictions + { + final List restrictions = e.getChildren("restriction", getNS()); + final ArrayList values = new ArrayList(); + + for (int i = 0; i < restrictions.size(); i++) { + final Element r = restrictions.get(i); + Restriction.Type type = null; + + if (r.getAttributeValue("type").equalsIgnoreCase("uri")) { + type = Restriction.Type.URI; + } else if (r.getAttributeValue("type").equalsIgnoreCase("country")) { + type = Restriction.Type.COUNTRY; + } + + Restriction.Relationship relationship = null; + + if (r.getAttributeValue("relationship").equalsIgnoreCase("allow")) { + relationship = Restriction.Relationship.ALLOW; + } else if (r.getAttributeValue("relationship").equalsIgnoreCase("deny")) { + relationship = Restriction.Relationship.DENY; + } + + final Restriction value = new Restriction(relationship, type, r.getTextTrim()); + values.add(value); + } + + md.setRestrictions(values.toArray(new Restriction[values.size()])); + } + // handle adult + { + final Element adult = e.getChild("adult", getNS()); + + if (adult != null && md.getRatings().length == 0) { + final Rating[] r = new Rating[1]; + + if (adult.getTextTrim().equals("true")) { + r[0] = new Rating("urn:simple", "adult"); + } else { + r[0] = new Rating("urn:simple", "nonadult"); + } + + md.setRatings(r); + } + } + + return md; + } + + private PlayerReference parsePlayer(final Element e) { + final Element player = e.getChild("player", getNS()); + PlayerReference p = null; + + if (player != null) { + final Integer width = player.getAttributeValue("width") == null ? null : new Integer(player.getAttributeValue("width")); + final Integer height = player.getAttributeValue("height") == null ? null : new Integer(player.getAttributeValue("height")); + + try { + p = new PlayerReference(new URI(player.getAttributeValue("url")), width, height); + } catch (final Exception ex) { + LOG.warn("Exception parsing player tag.", ex); + } + } + + return p; + } + + public Namespace getNS() { + return NS; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/io/RSS20YahooParser.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/RSS20YahooParser.java new file mode 100644 index 0000000..3eadf25 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/RSS20YahooParser.java @@ -0,0 +1,95 @@ +/* + * Copyright 2006 Nathanial X. Freitas, openvision.tv + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.io; + +import java.util.Locale; + +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.io.impl.RSS20Parser; + +/** + * @author Nathanial X. Freitas + * + * + */ +public class RSS20YahooParser extends RSS20Parser { + // the Yahoo Namespace URI they sometimes use in the returns for video.search.yahoo.com RSS feed + private static final String RSS_URI = "urn:yahoo:yn"; + + // + public RSS20YahooParser() { + this("rss_2.0yahoo"); + } + + protected RSS20YahooParser(final String type) { + super(type); + } + + /** + * Indicates if a JDom document is an RSS instance that can be parsed with the parser. + *

+ * It checks for RDF ("http://www.w3.org/1999/02/22-rdf-syntax-ns#") and RSS + * ("http://purl.org/rss/1.0/") namespaces being defined in the root element. + * + * @param document document to check if it can be parsed with this parser implementation. + * @return true if the document is RSS1., false otherwise. + */ + @Override + public boolean isMyType(final Document document) { + boolean ok = false; + + final Element rssRoot = document.getRootElement(); + final Namespace defaultNS = rssRoot.getNamespace(); + + ok = defaultNS != null && defaultNS.equals(getRSSNamespace()); + + return ok; + } + + /** + * Returns the namespace used by RSS elements in document of the RSS 1.0 + *

+ * + * @return returns "http://purl.org/rss/1.0/". + */ + @Override + protected Namespace getRSSNamespace() { + return Namespace.getNamespace(RSS_URI); + } + + /** + * After we parse the feed we put "rss_2.0" in it (so converters and generators work) this + * parser is a phantom. + * + */ + @Override + protected WireFeed parseChannel(final Element rssRoot, final Locale locale) { + final WireFeed wFeed = super.parseChannel(rssRoot, locale); + wFeed.setFeedType("rss_2.0"); + + return wFeed; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/io/package.html b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/package.html new file mode 100644 index 0000000..328588a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/package.html @@ -0,0 +1,11 @@ + + + + + + + + This package contains parsers and generators for the module as well as a specia feed + parser for Yahoo's custom RSS2 namespace. + + diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/package.html b/rome-modules/src/main/java/com/rometools/modules/mediarss/package.html new file mode 100644 index 0000000..ae93e29 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/package.html @@ -0,0 +1,54 @@ + + + + + + + + This module supports Yahoo! MediaRSS elements for ROME feeds. + + Sample usage: +

+            SyndFeed feed =  input.build( myRSSFile );
+            List entries = feed.getEntries();
+            for( int i = 0; i < entries.size(); i++ ){
+                System.out.println( ((SyndEntry) entries.get(i)).getModule( MediaModule.URI ) );
+            }
+  
+ Alternatively, to add a media item to an entry: +
+      MediaContent[] contents = new MediaContent[1];
+      MediaContent myItem = new MediaContent( new UrlReference("http://me.com/movie.mpg") );
+      contents[0] = myItem();
+      Metadata md = new Metadata();
+      Thumbnail[] thumbs = new Thumbnail[2];
+      thumbs[0] = new Thumbnail( new URL("http://me.com/movie1.jpg") );
+      thumbs[1] = new Thumbnail( new URL("http://me.com/movie2.jpg") );
+      md.setThumbnail( thumbs );
+      myItem.setMetadata( md );
+      MediaEntryModuleImpl module = new MediaEntryModuleImpl();
+      module.setContents( contents );
+      mySyndEntry.getModules().add( module );
+      
+  
+ +
+ * This code is currently released under the Mozilla Public License.
+ * http://www.mozilla.org/MPL/
+ *
+ * Alternately you may apply the terms of the Apache Software License
+ *
+ * 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/rome-modules/src/main/java/com/rometools/modules/mediarss/types/AbstractSchemeValue.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/AbstractSchemeValue.java new file mode 100644 index 0000000..9b6faa1 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/AbstractSchemeValue.java @@ -0,0 +1,54 @@ +/* + * AbstractSchemeValue.java + * + * Created on April 18, 2006, 8:03 PM + * + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; + +/** + * Simple data bean parent for scheme-value type entities. + * + * @author cooper + */ +public abstract class AbstractSchemeValue implements Serializable { + private static final long serialVersionUID = 1L; + private final String scheme; + private final String value; + + public AbstractSchemeValue(final String scheme, final String value) { + if (scheme == null || value == null) { + throw new NullPointerException("Scheme and value cannot be null."); + } + + this.scheme = scheme; + this.value = value; + } + + public String getScheme() { + return scheme; + } + + public String getValue() { + return value; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Category.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Category.java new file mode 100644 index 0000000..60012c1 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Category.java @@ -0,0 +1,148 @@ +/* + * Category.java + * + * Created on April 18, 2006, 8:04 PM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * + * <media:category>

+ *

+ * Allows a taxonomy to be set that gives an indication of the type of media content, and its + * particular contents. It has 2 optional attributes. + *

+ * + *
+ * <media:category scheme="http://search.yahoo.com/mrss/category_
+ *        schema">music/artist/album/song</media:category>
+ * 
+ *        <media:category scheme="http://dmoz.org" label="Ace Ventura - Pet
+ *        Detective">Arts/Movies/Titles/A/Ace_Ventura_Series/Ace_Ventura_
+ *        -_Pet_Detective</media:category>
+ * 
+ *        <media:category scheme="urn:flickr:tags">ycantpark
+ *        mobile</media:category>
+ * 
+ * + *

+ * scheme is the URI that identifies the categorization scheme. It is an optional + * attribute. If this attribute is not included, the default scheme is + * 'http://search.yahoo.com/mrss/category_schema'. + *

+ * + *

+ * label is the human readable label that can be displayed in end user applications. It is + * an optional attribute. + *

+ * + * @author cooper + */ +public class Category implements Serializable { + private static final long serialVersionUID = 1L; + /** + * Schem for FLICKR tags + */ + public static final String SCHEME_FLICKR_TAGS = "urn:flickr:tags"; + private String label; + private String scheme; + private final String value; + + /** + * Creates a new instance of Category + * + * @param scheme scheme used + * @param label label for the category + * @param value value of the category item + */ + public Category(final String scheme, final String label, final String value) { + this.scheme = scheme; + this.value = value; + this.label = label; + } + + /** + * Creates a new Category. + * + * @param value value of the category. + */ + public Category(final String value) { + this.value = value; + } + + /** + * label is the human readable label that can be displayed in end user applications. It is an + * optional attribute. + * + * @return label is the human readable label that can be displayed in end user applications. It + * is an optional attribute. + */ + public String getLabel() { + return label; + } + + /** + * scheme is the URI that identifies the categorization scheme. It is an optional attribute. If + * this attribute is not included, the default scheme is + * 'http://search.yahoo.com/mrss/category_schema'. + * + * @return scheme is the URI that identifies the categorization scheme. It is an optional + * attribute. If this attribute is not included, the default scheme is + * 'http://search.yahoo.com/mrss/category_schema'. + */ + public String getScheme() { + return scheme; + } + + /** + * value of the category + * + * @return value of the category + */ + public String getValue() { + return value; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(this.getClass(), this); + + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Credit.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Credit.java new file mode 100644 index 0000000..0411560 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Credit.java @@ -0,0 +1,163 @@ +/* + * Credit.java + * + * Created on April 18, 2006, 7:34 PM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * + * <media:credit>

+ * + *

+ * Notable entity and the contribution to the creation of the media object. Current entities can + * include people, companies, locations, etc. Specific entities can have multiple roles, and several + * entities can have the same role. These should appear as distinct <media:credit> elements. + * It has 2 optional attributes. + *

+ * + *
+ * <media:credit role="producer" scheme="urn:ebu">entity name</media:credit>
+ * 
+ *

+ * role specifies the role the entity played. Must be lowercase. It is an optional attribute. + *

+ * + *

+ * scheme is the URI that identifies the role scheme. It is an optional attribute. If this + * attribute is not included, the default scheme is 'urn:ebu'. See: European Broadcasting Union Role + * Codes. + *

+ * + * + *

+ * Example roles: + *

+ * + *
+ * actor
+ *        anchor person
+ *        author
+ *        choreographer
+ *        composer
+ *        conductor
+ *        director
+ *        editor
+ *        graphic designer
+ *        grip
+ *        illustrator
+ *        lyricist
+ *        music arranger
+ *        music group
+ *        musician
+ *        orchestra
+ *        performer
+ *        photographer
+ *        producer
+ *        reporter
+ *        vocalist
+ * 
+ *

+ * Additional roles: European + * Broadcasting Union Role Codes + * + * @author cooper + */ +public class Credit implements Serializable { + private static final long serialVersionUID = 1L; + /** + * Scheme value for the EBU credits. + */ + public static final String SCHEME_EBU = "urn:ebu"; + private final String name; + private final String role; + private final String scheme; + + /** + * Creates a new instance of Credit + * + * @param scheme schem used + * @param role role name + * @param name persons name + */ + public Credit(final String scheme, final String role, final String name) { + if (name == null) { + throw new NullPointerException("A credit name cannot be null."); + } + + this.scheme = scheme == null ? SCHEME_EBU : scheme; + this.role = role == null ? null : role.toLowerCase(); + this.name = name; + } + + /** + * Person/organizations name + * + * @return Person/organizations name + */ + public String getName() { + return name; + } + + /** + * Role name + * + * @return Role name + */ + public String getRole() { + return role; + } + + /** + * Scheme used. + * + * @return Scheme used. + */ + public String getScheme() { + return scheme; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(this.getClass(), this); + + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Expression.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Expression.java new file mode 100644 index 0000000..f632432 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Expression.java @@ -0,0 +1,54 @@ +/* This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; + +/** + * expression determines if the object is a sample or the full version of the object, or even if it + * is a continuous stream (sample | full | nonstop). Default value is 'full'. It is an optional + * attribute. + */ +public class Expression implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * Represents a complete media object. + */ + public static final Expression FULL = new Expression("full"); + + /** + * Represents a sample media object. + */ + public static final Expression SAMPLE = new Expression("sample"); + + /** + * represents a streaming media object. + */ + public static final Expression NONSTOP = new Expression("nonstop"); + private final String value; + + private Expression(final String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Hash.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Hash.java new file mode 100644 index 0000000..c385dd6 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Hash.java @@ -0,0 +1,102 @@ +/* + * Hash.java + * + * Created on April 18, 2006, 8:06 PM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * + * <media:hash>

+ * + *

+ * This is the hash of the binary media file. It can appear multiple times as long as each instance + * is a different algo. It has 1 optional attribute. + *

+ *

+ *

+ * + *
+ * <media:hash algo="md5">dfdec888b72151965a34b4b59031290a</media:hash>
+ * 
+ * + *

+ * algo indicates the algorithm used to create the hash. Possible values are 'md5' and + * 'sha-1'. Default value is 'md5'. It is an optional attribute. + * + * @author cooper + */ +public class Hash extends AbstractSchemeValue implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * Creates a new instance of Hash + * + * @param algorithm algoright used + * @param value value of the hash + */ + public Hash(final String algorithm, final String value) { + super(algorithm == null ? "MD5" : algorithm, value); + } + + /** + * Creates a new instance of Hash assuming the default algorithm of MD5 + * + * @param algorithm algoright used + */ + public Hash(final String value) { + this(null, value); + } + + /** + * Alsorithm used for the hash + * + * @return Alsorithm used for the hash + */ + public String getAlgorithm() { + return super.getScheme(); + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(this.getClass(), this); + + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/MediaContent.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/MediaContent.java new file mode 100644 index 0000000..850f422 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/MediaContent.java @@ -0,0 +1,608 @@ +/* + * Copyright 2006 Nathanial X. Freitas, openvision.tv + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * <media:content>

+ *

+ * <media:content> is a sub-element of either <item> or <media:group>. Media + * objects that are not the same content should not be included in the same <media:group> + * element. The sequence of these items implies the order of presentation. While many of the + * attributes appear to be audio/video specific, this element can be used to publish any type of + * media. It contains 14 attributes, most of which are optional. + *

+ * + *
+ *        <media:content
+ *               url="http://www.foo.com/movie.mov"
+ *               fileSize="12216320"
+ *               type="video/quicktime"
+ *               medium="video"
+ *               isDefault="true"
+ *               expression="full"
+ *               bitrate="128"
+ *               framerate="25"
+ *               samplingrate="44.1"
+ *               channels="2"
+ *               duration="185"
+ *               height="200"
+ *               width="300"
+ *               lang="en" />
+ * 
+ * + *

+ * url should specify the direct url to the media object. If not included, a + * <media:player> element must be specified. + *

+ *

+ * fileSize is the number of bytes of the media object. It is an optional attribute. + *

+ *

+ * type is the standard MIME type of the object. It is an optional attribute. + *

+ * + *

+ * medium is the type of object (image | audio | video | document | executable). While this + * attribute can at times seem redundant if type is supplied, it is included because it + * simplifies decision making on the reader side, as well as flushes out any ambiguities between + * MIME type and object type. It is an optional attribute. + *

+ * + * + *

+ * isDefault determines if this is the default object that should be used for the + * <media:group>. There should only be one default object per <media:group>. It is an + * optional attribute. + *

+ * + *

+ * expression determines if the object is a sample or the full version of the object, or + * even if it is a continuous stream (sample | full | nonstop). Default value is 'full'. It is an + * optional attribute. + *

+ * + *

+ * bitrate is the kilobits per second rate of media. It is an optional attribute. + *

+ *

+ * framerate is the number of frames per second for the media object. It is an optional + * attribute. + *

+ *

+ * samplingrate is the number of samples per second taken to create the media object. It is + * expressed in thousands of samples per second (kHz). It is an optional attribute. + *

+ *

+ * channels is number of audio channels in the media object. It is an optional attribute. + *

+ *

+ * duration is the number of seconds the media object plays. It is an optional attribute. + *

+ * + * + * + * + * + *

+ * height is the height of the media object. It is an optional attribute. + *

+ *

+ * width is the width of the media object. It is an optional attribute. + *

+ * + *

+ * lang is the primary language encapsulated in the media object. Language codes possible + * are detailed in RFC 3066. This attribute is used similar to the xml:lang attribute + * detailed in the XML 1.0 Specification (Third Edition). It is an optional attribute. + *

+ * + * + *

+ * These optional attributes, along with the optional elements below, contain the primary metadata + * entries needed to index and organize media content. Additional supported attributes for + * describing images, audio, and video may be added in future revisions of this document. + *

+ * + * @author Nathanial X. Freitas + * + * MediaContent corresponds to the element defined within the MediaRSS + * specification. There may be one or more instances within each instance of + * an within an RSS 2.0 document. + */ +public class MediaContent implements Serializable { + private static final long serialVersionUID = 1L; + private Expression expression; + private Float bitrate = null; + private Float framerate = null; + private Float samplingrate = null; + + /* + * private variable for storing instances of Thumbnail class each MediaContent can have zero to + * many thumbnails + */ + private Integer audioChannels = null; + + /* the height in pixels of the resource */ + private Integer height = null; + + /* the width in pixels of the resource */ + private Integer width = null; + + /* the duration in seconds of the resource */ + private Long duration = null; + + /* the file size in bytes of the resouce */ + private Long fileSize = null; + private Metadata metadata; + private PlayerReference player; + private Reference reference; + private String language; + private String medium; + + /* the MIME type of the resource */ + private String type = null; + private boolean defaultContent; + + /* + * MediaContent constructor + */ + + /** + * Creates a new MediaContent + * + * @param reference UrlReference or Player reference for the item. + */ + public MediaContent(final Reference reference) { + super(); + + if (reference == null) { + throw new NullPointerException("You must provide either a PlayerReference or URL reference."); + } + + setReference(reference); + } + + /** + * channels is number of audio channels in the media object. It is an optional attribute. + * + * @param audioChannels channels is number of audio channels in the media object. It is an + * optional attribute. + */ + public void setAudioChannels(final Integer audioChannels) { + this.audioChannels = audioChannels; + } + + /** + * channels is number of audio channels in the media object. It is an optional attribute. + * + * @return channels is number of audio channels in the media object. It is an optional + * attribute. + */ + public Integer getAudioChannels() { + return audioChannels; + } + + /** + * bitrate is the kilobits per second rate of media. It is an optional attribute. + * + * @param bitrate bitrate is the kilobits per second rate of media. It is an optional attribute. + */ + public void setBitrate(final Float bitrate) { + this.bitrate = bitrate; + } + + /** + * bitrate is the kilobits per second rate of media. It is an optional attribute. + * + * @return bitrate is the kilobits per second rate of media. It is an optional attribute. + */ + public Float getBitrate() { + return bitrate; + } + + /** + * isDefault determines if this is the default object that should be used for the . + * There should only be one default object per . It is an optional attribute. + * + * @param defaultContent isDefault determines if this is the default object that should be used + * for the . There should only be one default object per . + * It is an optional attribute. + */ + public void setDefaultContent(final boolean defaultContent) { + this.defaultContent = defaultContent; + } + + /** + * isDefault determines if this is the default object that should be used for the . + * There should only be one default object per . It is an optional attribute. + * + * @return isDefault determines if this is the default object that should be used for the + * . There should only be one default object per . It is an + * optional attribute. + */ + public boolean isDefaultContent() { + return defaultContent; + } + + /** + * duration is the number of seconds the media object plays. It is an optional attribute. + * + * @param duration duration is the number of seconds the media object plays. It is an optional + * attribute. + */ + public void setDuration(final Long duration) { + this.duration = duration; + } + + /** + * duration is the number of seconds the media object plays. It is an optional attribute. + * + * @return duration is the number of seconds the media object plays. It is an optional + * attribute. + */ + public Long getDuration() { + return duration; + } + + /** + * expression determines if the object is a sample or the full version of the object, or even if + * it is a continuous stream (sample | full | nonstop). Default value is 'full'. It is an + * optional attribute. + * + * @param expression expression determines if the object is a sample or the full version of the + * object, or even if it is a continuous stream (sample | full | nonstop). Default + * value is 'full'. It is an optional attribute. + */ + public void setExpression(final Expression expression) { + this.expression = expression; + } + + /** + * expression determines if the object is a sample or the full version of the object, or even if + * it is a continuous stream (sample | full | nonstop). Default value is 'full'. It is an + * optional attribute. + * + * @return expression determines if the object is a sample or the full version of the object, or + * even if it is a continuous stream (sample | full | nonstop). Default value is 'full'. + * It is an optional attribute. + */ + public Expression getExpression() { + return expression; + } + + /** + * + * fileSize is the number of bytes of the media object. It is an optional attribute. + * + * @param fileSize The fileSize to set. + */ + public void setFileSize(final Long fileSize) { + this.fileSize = fileSize; + } + + /** + * fileSize is the number of bytes of the media object. It is an optional attribute. + * + * @return Returns the fileSize. + */ + public Long getFileSize() { + return fileSize; + } + + /** + * framerate is the number of frames per second for the media object. It is an optional + * attribute. + * + * @param framerate framerate is the number of frames per second for the media object. It is an + * optional attribute. + */ + public void setFramerate(final Float framerate) { + this.framerate = framerate; + } + + /** + * framerate is the number of frames per second for the media object. It is an optional + * attribute. + * + * @return framerate is the number of frames per second for the media object. It is an optional + * attribute. + */ + public Float getFramerate() { + return framerate; + } + + /** + * height is the height of the media object. It is an optional attribute. + * + * @param height height is the height of the media object. It is an optional attribute. + */ + public void setHeight(final Integer height) { + this.height = height; + } + + /** + * height is the height of the media object. It is an optional attribute. + * + * @return height is the height of the media object. It is an optional attribute. + */ + public Integer getHeight() { + return height; + } + + /** + * lang is the primary language encapsulated in the media object. Language codes possible are + * detailed in RFC 3066. This attribute is used similar to the xml:lang attribute detailed in + * the XML 1.0 Specification (Third Edition). It is an optional attribute. + * + * @param language lang is the primary language encapsulated in the media object. Language codes + * possible are detailed in RFC 3066. This attribute is used similar to the xml:lang + * attribute detailed in the XML 1.0 Specification (Third Edition). It is an optional + * attribute. + */ + public void setLanguage(final String language) { + this.language = language; + } + + /** + * lang is the primary language encapsulated in the media object. Language codes possible are + * detailed in RFC 3066. This attribute is used similar to the xml:lang attribute detailed in + * the XML 1.0 Specification (Third Edition). It is an optional attribute. + * + * @return lang is the primary language encapsulated in the media object. Language codes + * possible are detailed in RFC 3066. This attribute is used similar to the xml:lang + * attribute detailed in the XML 1.0 Specification (Third Edition). It is an optional + * attribute. + */ + public String getLanguage() { + return language; + } + + /** + * Set the value of medium + * + * @param newmedium new value of medium + */ + public void setMedium(final String newmedium) { + medium = newmedium; + } + + /** + * Get the value of medium + * + * @return the value of medium + */ + public String getMedium() { + return medium; + } + + /** + * The metadata for the item + * + * @param metadata The metadata for the item + */ + public void setMetadata(final Metadata metadata) { + this.metadata = metadata; + } + + /** + * The metadata for the item + * + * @return The metadata for the item + */ + public Metadata getMetadata() { + return metadata; + } + + /** + * <media:player>

+ *

+ * Allows the media object to be accessed through a web browser media player console. This + * element is required only if a direct media url attribute is not specified in the + * <media:content> element. It has 1 required attribute, and 2 optional attributes. + *

+ * + *
+     * <media:player url="http://www.foo.com/player?id=1111" height="200" width="400" />
+     * 
+ *

+ * url is the url of the player console that plays the media. It is a required + * attribute. + *

+ * + *

+ * height is the height of the browser window that the url should be opened + * in. It is an optional attribute. + *

+ *

+ * width is the width of the browser window that the url should be opened in. + * It is an optional attribute. + *

+ * + *

+ * + * @param player PlayerReference for the item. + */ + public void setPlayer(final PlayerReference player) { + this.player = player; + } + + /** + * <media:player>

+ *

+ * Allows the media object to be accessed through a web browser media player console. This + * element is required only if a direct media url attribute is not specified in the + * <media:content> element. It has 1 required attribute, and 2 optional attributes. + *

+ * + *
+     * <media:player url="http://www.foo.com/player?id=1111" height="200" width="400" />
+     * 
+ *

+ * url is the url of the player console that plays the media. It is a required + * attribute. + *

+ * + *

+ * height is the height of the browser window that the url should be opened + * in. It is an optional attribute. + *

+ *

+ * width is the width of the browser window that the url should be opened in. + * It is an optional attribute. + *

+ * + * @return PlayerReference for the item. + */ + public PlayerReference getPlayer() { + return player; + } + + /** + * The player or URL reference for the item + * + * @param reference The player or URL reference for the item + */ + public void setReference(final Reference reference) { + this.reference = reference; + + if (reference instanceof PlayerReference) { + setPlayer((PlayerReference) reference); + } + } + + /** + * The player or URL reference for the item + * + * @return The player or URL reference for the item + */ + public Reference getReference() { + return reference; + } + + /** + * samplingrate is the number of samples per second taken to create the media object. It is + * expressed in thousands of samples per second (kHz). It is an optional attribute. + * + * @param samplingrate samplingrate is the number of samples per second taken to create the + * media object. It is expressed in thousands of samples per second (kHz). It is an + * optional attribute. + */ + public void setSamplingrate(final Float samplingrate) { + this.samplingrate = samplingrate; + } + + /** + * samplingrate is the number of samples per second taken to create the media object. It is + * expressed in thousands of samples per second (kHz). It is an optional attribute. + * + * @return samplingrate is the number of samples per second taken to create the media object. It + * is expressed in thousands of samples per second (kHz). It is an optional attribute. + */ + public Float getSamplingrate() { + return samplingrate; + } + + /** + * + * type is the standard MIME type of the object. It is an optional attribute. + * + * @param type The type to set. + */ + public void setType(final String type) { + this.type = type; + } + + /** + * + * type is the standard MIME type of the object. It is an optional attribute. + * + * @return Returns the type. + */ + public String getType() { + return type; + } + + /** + * width is the width of the media object. It is an optional attribute. + * + * @param width width is the width of the media object. It is an optional attribute. + */ + public void setWidth(final Integer width) { + this.width = width; + } + + /** + * width is the width of the media object. It is an optional attribute. + * + * @return width is the width of the media object. It is an optional attribute. + */ + public Integer getWidth() { + return width; + } + + @Override + public Object clone() { + final MediaContent c = new MediaContent(getReference()); + c.setAudioChannels(getAudioChannels()); + c.setBitrate(getBitrate()); + c.setDefaultContent(isDefaultContent()); + c.setDuration(getDuration()); + c.setExpression(getExpression()); + c.setFileSize(getFileSize()); + c.setFramerate(getFramerate()); + c.setHeight(getHeight()); + c.setLanguage(getLanguage()); + c.setMetadata(getMetadata() == null ? null : (Metadata) getMetadata().clone()); + c.setPlayer(getPlayer()); + c.setSamplingrate(getSamplingrate()); + c.setType(getType()); + c.setWidth(getWidth()); + + return c; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(MediaContent.class, this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(MediaContent.class, this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(MediaContent.class, this); + + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/MediaGroup.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/MediaGroup.java new file mode 100644 index 0000000..2e5e5cd --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/MediaGroup.java @@ -0,0 +1,169 @@ +/* + * MediaGroup.java + * + * Created on April 19, 2006, 12:34 AM + * + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * <media:group>

+ *

+ * <media:group> is a sub-element of <item>. It allows grouping of <media:content> + * elements that are effectively the same content, yet different representations. For instance: + * the same song recorded in both the WAV and MP3 format. It's an optional element that must only be + * used for this purpose. + *

+ * + * @author cooper + */ +public class MediaGroup implements Cloneable, Serializable { + private static final long serialVersionUID = 1L; + + private Integer defaultContentIndex; + private Metadata metadata; + private MediaContent[] contents = new MediaContent[0]; + + /** + * Creates a new instance of MediaGroup + * + * @param contents Contents of the group. + */ + public MediaGroup(final MediaContent[] contents) { + setContents(contents); + } + + /** + * Creates a new instance of MediaGroup + * + * @param contents contents of the group + * @param defaultContentIndex index of the default content value. + */ + public MediaGroup(final MediaContent[] contents, final Integer defaultContentIndex) { + setContents(contents); + setDefaultContentIndex(defaultContentIndex); + } + + /** + * Creates a new instance of MediaGroup + * + * @param contents contents of the group + * @param defaultContentIndex index of the default content item. + * @param metadata metadata for the group. + */ + public MediaGroup(final MediaContent[] contents, final Integer defaultContentIndex, final Metadata metadata) { + setContents(contents); + setDefaultContentIndex(defaultContentIndex); + setMetadata(metadata); + } + + /** + * MediaContents for the group + * + * @param contents MediaContents for the group + */ + public void setContents(final MediaContent[] contents) { + this.contents = contents == null ? new MediaContent[0] : contents; + } + + /** + * MediaContents for the group + * + * @return MediaContents for the group + */ + public MediaContent[] getContents() { + return contents; + } + + /** + * Default content index MediaContent. + * + * @param defaultContentIndex Default content index MediaContent. + */ + public void setDefaultContentIndex(final Integer defaultContentIndex) { + for (int i = 0; i < getContents().length; i++) { + if (i == defaultContentIndex.intValue()) { + getContents()[i].setDefaultContent(true); + } else { + getContents()[i].setDefaultContent(false); + } + } + + this.defaultContentIndex = defaultContentIndex; + } + + /** + * Default content index MediaContent. + * + * @return Default content index MediaContent. + */ + public Integer getDefaultContentIndex() { + return defaultContentIndex; + } + + /** + * Metadata for the group + * + * @param metadata Metadata for the group + */ + public void setMetadata(final Metadata metadata) { + this.metadata = metadata; + } + + /** + * Metadata for the group + * + * @return Metadata for the group + */ + public Metadata getMetadata() { + return metadata; + } + + @Override + public Object clone() { + return new MediaGroup(getContents(), getDefaultContentIndex(), getMetadata()); + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(this.getClass(), this); + + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Metadata.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Metadata.java new file mode 100644 index 0000000..8f4b5c0 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Metadata.java @@ -0,0 +1,990 @@ +/* + * Metadata.java + * + * Created on April 18, 2006, 7:57 PM + * + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.net.URI; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * + * + * + * Optional Elements + *

+ * The following elements are optional and may appear as sub-elements of <channel>, + * <item>, <media:content> and/or <media:group>. + * + * + *

+ *

+ * + * When an element appears at a shallow level, such as <channel> or <item>, it means + * that the element should be applied to every media object within its scope. + *

+ * + * + *

+ * Duplicated elements appearing at deeper levels of the document tree have higher priority over + * other levels. + * + * For example, <media:content> level elements are favored over <item> level elements. + * The priority level is listed from strongest to weakest: <media:content>, + * <media:group>, <item>, <channel>. + *

+ * + * @author cooper + */ +public class Metadata implements Cloneable, Serializable { + private static final long serialVersionUID = 1L; + + private Hash hash; + private String copyright; + private String description; + private String descriptionType; + private String title; + private String titleType; + private URI copyrightUrl; + private Category[] categories = new Category[0]; + private Credit[] credits = new Credit[0]; + private String[] keywords = new String[0]; + private Rating[] ratings = new Rating[0]; + private Restriction[] restrictions = new Restriction[0]; + private Text[] text = new Text[0]; + private Thumbnail[] thumbnail = new Thumbnail[0]; + + /** Creates a new instance of Metadata */ + public Metadata() { + super(); + } + + /** + * <media:category>

+ *

+ * Allows a taxonomy to be set that gives an indication of the type of media content, and its + * particular contents. It has 2 optional attributes. + *

+ * + *
+     * <media:category scheme="http://search.yahoo.com/mrss/category_
+     *        schema">music/artist/album/song</media:category>
+     * 
+     *        <media:category scheme="http://dmoz.org" label="Ace Ventura - Pet
+     *        Detective">Arts/Movies/Titles/A/Ace_Ventura_Series/Ace_Ventura_
+     *        -_Pet_Detective</media:category>
+     * 
+     *        <media:category scheme="urn:flickr:tags">ycantpark
+     *        mobile</media:category>
+     * 
+ * + *

+ * scheme is the URI that identifies the categorization scheme. It is an optional + * attribute. If this attribute is not included, the default scheme is + * 'http://search.yahoo.com/mrss/category_schema'. + *

+ * + *

+ * label is the human readable label that can be displayed in end user applications. It + * is an optional attribute. + *

+ * + * @param categories categories for the item + */ + public void setCategories(final Category[] categories) { + this.categories = categories == null ? new Category[0] : categories; + } + + /** + * <media:category>

+ *

+ * Allows a taxonomy to be set that gives an indication of the type of media content, and its + * particular contents. It has 2 optional attributes. + *

+ * + *
+     * <media:category scheme="http://search.yahoo.com/mrss/category_
+     *        schema">music/artist/album/song</media:category>
+     * 
+     *        <media:category scheme="http://dmoz.org" label="Ace Ventura - Pet
+     *        Detective">Arts/Movies/Titles/A/Ace_Ventura_Series/Ace_Ventura_
+     *        -_Pet_Detective</media:category>
+     * 
+     *        <media:category scheme="urn:flickr:tags">ycantpark
+     *        mobile</media:category>
+     * 
+ * + *

+ * scheme is the URI that identifies the categorization scheme. It is an optional + * attribute. If this attribute is not included, the default scheme is + * 'http://search.yahoo.com/mrss/category_schema'. + *

+ * + *

+ * label is the human readable label that can be displayed in end user applications. It + * is an optional attribute. + *

+ * + * @return categories for the item. + */ + public Category[] getCategories() { + return categories; + } + + /** + * <media:copyright>

+ *

+ * Copyright information for media object. It has 1 optional attribute. + *

+ * + *
+     * <media:copyright url="http://blah.com/additional-info.html">2005 FooBar Media</media:copyright>
+     * 
+ *

+ * url is the url for a terms of use page or additional copyright information. If the + * media is operating under a Creative Commons license, the Creative Commons module should be + * used instead. It is an optional attribute. + *

+ * + * @param copyright copyright text + */ + public void setCopyright(final String copyright) { + this.copyright = copyright; + } + + /** + * <media:copyright>

+ *

+ * Copyright information for media object. It has 1 optional attribute. + *

+ * + *
+     * <media:copyright url="http://blah.com/additional-info.html">2005 FooBar Media</media:copyright>
+     * 
+ *

+ * url is the url for a terms of use page or additional copyright information. If the + * media is operating under a Creative Commons license, the Creative Commons module should be + * used instead. It is an optional attribute. + *

+ * + * @return Copyright text + */ + public String getCopyright() { + return copyright; + } + + /** + * <media:copyright>

+ *

+ * Copyright information for media object. It has 1 optional attribute. + *

+ * + *
+     * <media:copyright url="http://blah.com/additional-info.html">2005 FooBar Media</media:copyright>
+     * 
+ *

+ * url is the url for a terms of use page or additional copyright information. If the + * media is operating under a Creative Commons license, the Creative Commons module should be + * used instead. It is an optional attribute. + *

+ * + * @param copyrightUrl link to more copyright information. + */ + public void setCopyrightUrl(final URI copyrightUrl) { + this.copyrightUrl = copyrightUrl; + } + + /** + * <media:copyright>

+ *

+ * Copyright information for media object. It has 1 optional attribute. + *

+ * + *
+     * <media:copyright url="http://blah.com/additional-info.html">2005 FooBar Media</media:copyright>
+     * 
+ *

+ * url is the url for a terms of use page or additional copyright information. If the + * media is operating under a Creative Commons license, the Creative Commons module should be + * used instead. It is an optional attribute. + *

+ * + * @return Link to more copyright information. + */ + public URI getCopyrightUrl() { + return copyrightUrl; + } + + /** + * <media:credit>

+ * + *

+ * Notable entity and the contribution to the creation of the media object. Current entities can + * include people, companies, locations, etc. Specific entities can have multiple roles, and + * several entities can have the same role. These should appear as distinct <media:credit> + * elements. It has 2 optional attributes. + *

+ * + *
+     * <media:credit role="producer" scheme="urn:ebu">entity name</media:credit>
+     * 
+ *

+ * role specifies the role the entity played. Must be lowercase. It is an optional attribute. + *

+ * + *

+ * scheme is the URI that identifies the role scheme. It is an optional attribute. If + * this attribute is not included, the default scheme is 'urn:ebu'. See: European Broadcasting + * Union Role Codes. + *

+ * + * + *

+ * Example roles: + *

+ * + *
+     * actor
+     *        anchor person
+     *        author
+     *        choreographer
+     *        composer
+     *        conductor
+     *        director
+     *        editor
+     *        graphic designer
+     *        grip
+     *        illustrator
+     *        lyricist
+     *        music arranger
+     *        music group
+     *        musician
+     *        orchestra
+     *        performer
+     *        photographer
+     *        producer
+     *        reporter
+     *        vocalist
+     * 
+ *

+ * Additional roles: European + * Broadcasting Union Role Codes + * + * @param credits credits for the item. + */ + public void setCredits(final Credit[] credits) { + this.credits = credits == null ? new Credit[0] : credits; + } + + /** + * <media:credit>

+ * + *

+ * Notable entity and the contribution to the creation of the media object. Current entities can + * include people, companies, locations, etc. Specific entities can have multiple roles, and + * several entities can have the same role. These should appear as distinct <media:credit> + * elements. It has 2 optional attributes. + *

+ * + *
+     * <media:credit role="producer" scheme="urn:ebu">entity name</media:credit>
+     * 
+ *

+ * role specifies the role the entity played. Must be lowercase. It is an optional attribute. + *

+ * + *

+ * scheme is the URI that identifies the role scheme. It is an optional attribute. If + * this attribute is not included, the default scheme is 'urn:ebu'. See: European Broadcasting + * Union Role Codes. + *

+ * + * + *

+ * Example roles: + *

+ * + *
+     * actor
+     *        anchor person
+     *        author
+     *        choreographer
+     *        composer
+     *        conductor
+     *        director
+     *        editor
+     *        graphic designer
+     *        grip
+     *        illustrator
+     *        lyricist
+     *        music arranger
+     *        music group
+     *        musician
+     *        orchestra
+     *        performer
+     *        photographer
+     *        producer
+     *        reporter
+     *        vocalist
+     * 
+ *

+ * Additional roles: European + * Broadcasting Union Role Codes + * + * @return credits for the time. + */ + public Credit[] getCredits() { + return credits; + } + + /** + * <media:description>

+ *

+ * Short description describing the media object typically a sentence in length. It has 1 + * optional attribute. + *

+ * + *
+     * <media:description type="plain">This was some really bizarre band I listened to as a young lad.</media:description>
+     * 
+ *

+ * type specifies the type of text embedded. Possible values are either 'plain' or + * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional + * attribute. + *

+ * + * @param description value of the description + */ + public void setDescription(final String description) { + this.description = description; + } + + /** + * <media:description>

+ *

+ * Short description describing the media object typically a sentence in length. It has 1 + * optional attribute. + *

+ * + *
+     * <media:description type="plain">This was some really bizarre band I listened to as a young lad.</media:description>
+     * 
+ *

+ * type specifies the type of text embedded. Possible values are either 'plain' or + * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional + * attribute. + *

+ * + * @return value of the description + */ + public String getDescription() { + return description; + } + + /** + * <media:description>

+ *

+ * Short description describing the media object typically a sentence in length. It has 1 + * optional attribute. + *

+ * + *
+     * <media:description type="plain">This was some really bizarre band I listened to as a young lad.</media:description>
+     * 
+ *

+ * type specifies the type of text embedded. Possible values are either 'plain' or + * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional + * attribute. + *

+ * + * @param descriptionType type of the description. + */ + public void setDescriptionType(final String descriptionType) { + this.descriptionType = descriptionType; + } + + /** + * <media:description>

+ *

+ * Short description describing the media object typically a sentence in length. It has 1 + * optional attribute. + *

+ * + *
+     * <media:description type="plain">This was some really bizarre band I listened to as a young lad.</media:description>
+     * 
+ *

+ * type specifies the type of text embedded. Possible values are either 'plain' or + * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional + * attribute. + *

+ * + * @return type of the description + */ + public String getDescriptionType() { + return descriptionType; + } + + /** + * <media:hash>

+ * + *

+ * This is the hash of the binary media file. It can appear multiple times as long as each + * instance is a different algo. It has 1 optional attribute. + *

+ *

+ *

+ * + *
+     * <media:hash algo="md5">dfdec888b72151965a34b4b59031290a</media:hash>
+     * 
+ * + *

+ * algo indicates the algorithm used to create the hash. Possible values are 'md5' and + * 'sha-1'. Default value is 'md5'. It is an optional attribute. + * + * @param hash sets the hash for the item. + */ + public void setHash(final Hash hash) { + this.hash = hash; + } + + /** + * <media:hash>

+ * + *

+ * This is the hash of the binary media file. It can appear multiple times as long as each + * instance is a different algo. It has 1 optional attribute. + *

+ *

+ *

+ * + *
+     * <media:hash algo="md5">dfdec888b72151965a34b4b59031290a</media:hash>
+     * 
+ * + *

+ * algo indicates the algorithm used to create the hash. Possible values are 'md5' and + * 'sha-1'. Default value is 'md5'. It is an optional attribute. + * + * @return returns a Hash object for the item. + */ + public Hash getHash() { + return hash; + } + + /** + * <media:keywords>

+ *

+ * Highly relevant keywords describing the media object with typically a maximum of ten words. + * The keywords and phrases should be comma delimited. + *

+ * + *
+     * <media:keywords>kitty, cat, big dog, yarn, fluffy</media:keywords>
+     * 
+ * + * @param keywords Array of keywords + */ + public void setKeywords(final String[] keywords) { + this.keywords = keywords == null ? new String[0] : keywords; + } + + /** + * <media:keywords>

+ *

+ * Highly relevant keywords describing the media object with typically a maximum of ten words. + * The keywords and phrases should be comma delimited. + *

+ * + *
+     * <media:keywords>kitty, cat, big dog, yarn, fluffy</media:keywords>
+     * 
+ * + * @return Array of keywords + */ + public String[] getKeywords() { + return keywords; + } + + /** + * <media:rating>

+ * + * + *

+ * This allows the permissible audience to be declared. If this element is not included, it + * assumes that no restrictions are necessary. It has one optional attribute. + *

+ * + *
+     * <media:rating scheme="urn:simple">adult</media:rating>
+     *               <media:rating scheme="urn:icra">r (cz 1 lz 1 nz 1 oz 1 vz 1)</media:rating>
+     *               <media:rating scheme="urn:mpaa">pg</media:rating>
+     * 
+     *               <media:rating scheme="urn:v-chip">tv-y7-fv</media:rating>
+     * 
+ * + * + *

+ * scheme is the URI that identifies the rating scheme. It is an optional attribute. If + * this attribute is not included, the default scheme is urn:simple (adult | nonadult). + *

+ * + *

+ * + * @param ratings Ratings objects + */ + public void setRatings(final Rating[] ratings) { + this.ratings = ratings == null ? new Rating[0] : ratings; + } + + /** + * <media:rating>

+ * + * + *

+ * This allows the permissible audience to be declared. If this element is not included, it + * assumes that no restrictions are necessary. It has one optional attribute. + *

+ * + *
+     * <media:rating scheme="urn:simple">adult</media:rating>
+     *               <media:rating scheme="urn:icra">r (cz 1 lz 1 nz 1 oz 1 vz 1)</media:rating>
+     *               <media:rating scheme="urn:mpaa">pg</media:rating>
+     * 
+     *               <media:rating scheme="urn:v-chip">tv-y7-fv</media:rating>
+     * 
+ * + * + *

+ * scheme is the URI that identifies the rating scheme. It is an optional attribute. If + * this attribute is not included, the default scheme is urn:simple (adult | nonadult). + *

+ * + *

+ * + * @return Ratings objects + */ + public Rating[] getRatings() { + return ratings; + } + + /** + * <media:restriction>

+ * + *

+ * Allows restrictions to be placed on the aggregator rendering the media in the feed. + * Currently, restrictions are based on distributor (uri) and country codes. This element is + * purely informational and no obligation can be assumed or implied. Only one + * <media:restriction> element of the same type can be applied to a media object + * - all others will be ignored. Entities in this element should be space separated. To + * allow the producer to explicitly declare his/her intentions, two literals are reserved: + * 'all', 'none'. These literals can only be used once. This element has 1 required attribute, + * and 1 optional attribute (with strict requirements for its exclusion). + *

+ * + *
+     * <media:restriction relationship="allow" type="country">au us</media:restriction>
+     * 
+ * + *

+ * relationship indicates the type of relationship that the restriction represents + * (allow | deny). In the example above, the media object should only be syndicated in Australia + * and the United States. It is a required attribute. + *

+ * + * @param restrictions restrictions for the item. + */ + public void setRestrictions(final Restriction[] restrictions) { + this.restrictions = restrictions == null ? new Restriction[0] : restrictions; + } + + /** + * <media:restriction>

+ * + *

+ * Allows restrictions to be placed on the aggregator rendering the media in the feed. + * Currently, restrictions are based on distributor (uri) and country codes. This element is + * purely informational and no obligation can be assumed or implied. Only one + * <media:restriction> element of the same type can be applied to a media object + * - all others will be ignored. Entities in this element should be space separated. To + * allow the producer to explicitly declare his/her intentions, two literals are reserved: + * 'all', 'none'. These literals can only be used once. This element has 1 required attribute, + * and 1 optional attribute (with strict requirements for its exclusion). + *

+ * + *
+     * <media:restriction relationship="allow" type="country">au us</media:restriction>
+     * 
+ * + *

+ * relationship indicates the type of relationship that the restriction represents + * (allow | deny). In the example above, the media object should only be syndicated in Australia + * and the United States. It is a required attribute. + *

+ * + * @return restrictions for the item. + */ + public Restriction[] getRestrictions() { + return restrictions; + } + + /** + * <media:text>

+ *

+ * Allows the inclusion of a text transcript, closed captioning, or lyrics of the media content. + * Many of these elements are permitted to provide a time series of text. In such cases, it is + * encouraged, but not required, that the elements be grouped by language and appear in time + * sequence order based on the start time. Elements can have overlapping start + * and end times. It has 4 optional attributes. + *

+ * + *
+     * <media:text type="plain" lang="en" start="00:00:03.000"
+     *        end="00:00:10.000"> Oh, say, can you see</media:text>
+     * 
+     *        <media:text type="plain" lang="en" start="00:00:10.000"
+     *        end="00:00:17.000">By the dawn's early light</media:text>
+     * 
+ *

+ * type specifies the type of text embedded. Possible values are either 'plain' or + * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional + * attribute. + *

+ * + * + * + * + * + * + *

+ * lang is the primary language encapsulated in the media object. Language codes + * possible are detailed in RFC 3066. This attribute is used similar to the xml:lang attribute + * detailed in the XML 1.0 Specification (Third Edition). It is an optional attribute. + *

+ * + *

+ * start specifies the start time offset that the text starts being relevant to the + * media object. An example of this would be for closed captioning. It uses the NTP time code + * format (see: the time attribute used in <media:thumbnail>). It is an optional + * attribute. + *

+ * + *

+ * end specifies the end time that the text is relevant. If this attribute is not + * provided, and a start time is used, it is expected that the end time is either the + * end of the clip or the start of the next <media:text> element. + * + * @param text text objects for the item. + */ + public void setText(final Text[] text) { + this.text = text == null ? new Text[0] : text; + } + + /** + * <media:text>

+ *

+ * Allows the inclusion of a text transcript, closed captioning, or lyrics of the media content. + * Many of these elements are permitted to provide a time series of text. In such cases, it is + * encouraged, but not required, that the elements be grouped by language and appear in time + * sequence order based on the start time. Elements can have overlapping start + * and end times. It has 4 optional attributes. + *

+ * + *
+     * <media:text type="plain" lang="en" start="00:00:03.000"
+     *        end="00:00:10.000"> Oh, say, can you see</media:text>
+     * 
+     *        <media:text type="plain" lang="en" start="00:00:10.000"
+     *        end="00:00:17.000">By the dawn's early light</media:text>
+     * 
+ *

+ * type specifies the type of text embedded. Possible values are either 'plain' or + * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional + * attribute. + *

+ * + * + * + * + * + * + *

+ * lang is the primary language encapsulated in the media object. Language codes + * possible are detailed in RFC 3066. This attribute is used similar to the xml:lang attribute + * detailed in the XML 1.0 Specification (Third Edition). It is an optional attribute. + *

+ * + *

+ * start specifies the start time offset that the text starts being relevant to the + * media object. An example of this would be for closed captioning. It uses the NTP time code + * format (see: the time attribute used in <media:thumbnail>). It is an optional + * attribute. + *

+ * + *

+ * end specifies the end time that the text is relevant. If this attribute is not + * provided, and a start time is used, it is expected that the end time is either the + * end of the clip or the start of the next <media:text> element. + * + * @return Text objects for the item. + */ + public Text[] getText() { + return text; + } + + /** + * <media:thumbnail>

+ * + * + *

+ * Allows particular images to be used as representative images for the media object. If + * multiple thumbnails are included, and time coding is not at play, it is assumed that the + * images are in order of importance. It has 1 required attribute and 3 optional attributes. + *

+ * + * + * + * + * + *
+     * <media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123" />
+     * 
+ *

+ * url specifies the url of the thumbnail. It is a required attribute. + *

+ *

+ * height specifies the height of the thumbnail. It is an optional attribute. + *

+ *

+ * width specifies the width of the thumbnail. It is an optional attribute. + *

+ * + * + *

+ * time specifies the time offset in relation to the media object. Typically this is + * used when creating multiple keyframes within a single video. The format for this attribute + * should be in the DSM-CC's Normal Play Time (NTP) as used in RTSP [RFC 2326 3.6 Normal Play Time]. It is an + * optional attribute. + *

+ * + * @param thumbnail thumbnails for the image + */ + public void setThumbnail(final Thumbnail[] thumbnail) { + this.thumbnail = thumbnail == null ? new Thumbnail[0] : thumbnail; + } + + /** + * <media:thumbnail>

+ * + * + *

+ * Allows particular images to be used as representative images for the media object. If + * multiple thumbnails are included, and time coding is not at play, it is assumed that the + * images are in order of importance. It has 1 required attribute and 3 optional attributes. + *

+ * + * + * + * + * + *
+     * <media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123" />
+     * 
+ *

+ * url specifies the url of the thumbnail. It is a required attribute. + *

+ *

+ * height specifies the height of the thumbnail. It is an optional attribute. + *

+ *

+ * width specifies the width of the thumbnail. It is an optional attribute. + *

+ * + * + *

+ * time specifies the time offset in relation to the media object. Typically this is + * used when creating multiple keyframes within a single video. The format for this attribute + * should be in the DSM-CC's Normal Play Time (NTP) as used in RTSP [RFC 2326 3.6 Normal Play Time]. It is an + * optional attribute. + *

+ * + * @return Thumbnails for the image + */ + public Thumbnail[] getThumbnail() { + return thumbnail; + } + + /** + * <media:title>

+ *

+ * The title of the particular media object. It has 1 optional attribute. + *

+ * + *
+     * <media:title type="plain">The Judy's - The Moo Song</media:title>
+     * 
+ * + *

+ * type specifies the type of text embedded. Possible values are either 'plain' or + * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional + * attribute. + *

+ * + * @param title Value of the title + */ + public void setTitle(final String title) { + this.title = title; + } + + /** + * <media:title>

+ *

+ * The title of the particular media object. It has 1 optional attribute. + *

+ * + *
+     * <media:title type="plain">The Judy's - The Moo Song</media:title>
+     * 
+ * + *

+ * type specifies the type of text embedded. Possible values are either 'plain' or + * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional + * attribute. + *

+ * + * @return value of the title. + */ + public String getTitle() { + return title; + } + + /** + * <media:title>

+ *

+ * The title of the particular media object. It has 1 optional attribute. + *

+ * + *
+     * <media:title type="plain">The Judy's - The Moo Song</media:title>
+     * 
+ * + *

+ * type specifies the type of text embedded. Possible values are either 'plain' or + * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional + * attribute. + *

+ * + * @param titleType type of the title. + */ + public void setTitleType(final String titleType) { + this.titleType = titleType; + } + + /** + * <media:title>

+ *

+ * The title of the particular media object. It has 1 optional attribute. + *

+ * + *
+     * <media:title type="plain">The Judy's - The Moo Song</media:title>
+     * 
+ * + *

+ * type specifies the type of text embedded. Possible values are either 'plain' or + * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional + * attribute. + *

+ * + * @return type of the title + */ + public String getTitleType() { + return titleType; + } + + /** + * <media:copyright>

+ *

+ * Copyright information for media object. It has 1 optional attribute. + *

+ * + *
+     * <media:copyright url="http://blah.com/additional-info.html">2005 FooBar Media</media:copyright>
+     * 
+ *

+ * url is the url for a terms of use page or additional copyright information. If the + * media is operating under a Creative Commons license, the Creative Commons module should be + * used instead. It is an optional attribute. + *

+ * + * @return Link to more copyright information. + */ + @Override + public Object clone() { + final Metadata md = new Metadata(); + md.setCategories(getCategories()); + md.setCopyright(getCopyright()); + md.setCopyrightUrl(getCopyrightUrl()); + md.setCredits(getCredits()); + md.setDescription(getDescription()); + md.setDescriptionType(getDescriptionType()); + md.setHash(getHash()); + md.setKeywords(getKeywords()); + md.setRatings(getRatings()); + md.setText(getText()); + md.setThumbnail(getThumbnail()); + md.setTitle(getTitle()); + md.setTitleType(getTitleType()); + md.setRestrictions(getRestrictions()); + + return md; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(Metadata.class, this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(Metadata.class, this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(Metadata.class, this); + + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/PlayerReference.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/PlayerReference.java new file mode 100644 index 0000000..d8969be --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/PlayerReference.java @@ -0,0 +1,140 @@ +/* + * PlayerReference.java + * + * Created on April 18, 2006, 7:18 PM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.net.URI; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * + * <media:player>

+ *

+ * Allows the media object to be accessed through a web browser media player console. This element + * is required only if a direct media url attribute is not specified in the + * <media:content> element. It has 1 required attribute, and 2 optional attributes. + *

+ * + *
+ * <media:player url="http://www.foo.com/player?id=1111" height="200" width="400" />
+ * 
+ *

+ * url is the url of the player console that plays the media. It is a required attribute. + *

+ * + *

+ * height is the height of the browser window that the url should be opened in. It + * is an optional attribute. + *

+ *

+ * width is the width of the browser window that the url should be opened in. It + * is an optional attribute. + *

+ * + * @author cooper + */ +public class PlayerReference implements Reference, Serializable { + private static final long serialVersionUID = 1L; + + private final Integer height; + private final Integer width; + private final URI url; + + /** + * Creates a new instance of PlayerReference + * + * @param url url of the player + * @param width width of the player + * @param height height of the player + */ + public PlayerReference(final URI url, final Integer width, final Integer height) { + super(); + + if (url == null) { + throw new NullPointerException("url cannot be null."); + } + + this.url = url; + this.height = height; + this.width = width; + } + + /** + * Constructs a new PlayerReference + * + * @param url URL of the player + */ + public PlayerReference(final URI url) { + this(url, null, null); + } + + /** + * Height of the player + * + * @return Height of the player + */ + public Integer getHeight() { + return height; + } + + /** + * URL of the player + * + * @return URL of the player + */ + public URI getUrl() { + return url; + } + + /** + * Width of the player + * + * @return Width of the player + */ + public Integer getWidth() { + return width; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(this.getClass(), this); + + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Rating.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Rating.java new file mode 100644 index 0000000..8e2011c --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Rating.java @@ -0,0 +1,111 @@ +/* + * Rating.java + * + * Created on April 18, 2006, 7:58 PM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * <media:rating>

+ * + * + *

+ * This allows the permissible audience to be declared. If this element is not included, it assumes + * that no restrictions are necessary. It has one optional attribute. + *

+ * + *
+ * <media:rating scheme="urn:simple">adult</media:rating>
+ *               <media:rating scheme="urn:icra">r (cz 1 lz 1 nz 1 oz 1 vz 1)</media:rating>
+ *               <media:rating scheme="urn:mpaa">pg</media:rating>
+ * 
+ *               <media:rating scheme="urn:v-chip">tv-y7-fv</media:rating>
+ * 
+ * + * + *

+ * scheme is the URI that identifies the rating scheme. It is an optional attribute. If + * this attribute is not included, the default scheme is urn:simple (adult | nonadult). + *

+ * + * For compatibility, a medai:adult tag will appear in the ratings as a urn:simple equiv. + * + * @author cooper + */ +public class Rating extends AbstractSchemeValue { + private static final long serialVersionUID = 1L; + + /** + * urn:simple adult. This will be populated on the deprecated media:adult tag as well, + */ + public static final Rating ADULT = new Rating("urn:simple", "adult"); + + /** + * urn:simple nonadult. This will be populated on the deprecated media:adult tag as well, + */ + public static final Rating NONADULT = new Rating("urn:simple", "nonadult"); + + /** + * Constructs a new Rating object. + * + * @param scheme scheme used for the rating + * @param value value of the rating. + */ + public Rating(final String scheme, final String value) { + super(scheme, value); + } + + /** + * + * @param obj + * @return + */ + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + /** + * + * @return + */ + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + /** + * + * @return + */ + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(this.getClass(), this); + + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Reference.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Reference.java new file mode 100644 index 0000000..e1819c4 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Reference.java @@ -0,0 +1,32 @@ +/* + * Reference.java + * + * Created on April 18, 2006, 7:18 PM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +/** + * This class is an idenfier for UrlReference and PlayerReference and is required for constructing a + * MediaContent object. + * + * @author cooper + */ +public interface Reference { +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Restriction.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Restriction.java new file mode 100644 index 0000000..1c518e1 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Restriction.java @@ -0,0 +1,192 @@ +/* + * Restriction.java + * + * Created on April 19, 2006, 12:17 AM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * <media:restriction>

+ * + *

+ * Allows restrictions to be placed on the aggregator rendering the media in the feed. Currently, + * restrictions are based on distributor (uri) and country codes. This element is purely + * informational and no obligation can be assumed or implied. Only one <media:restriction> + * element of the same type can be applied to a media object - all others will be + * ignored. Entities in this element should be space separated. To allow the producer to + * explicitly declare his/her intentions, two literals are reserved: 'all', 'none'. These literals + * can only be used once. This element has 1 required attribute, and 1 optional attribute (with + * strict requirements for its exclusion). + *

+ * + *
+ * <media:restriction relationship="allow" type="country">au us</media:restriction>
+ * 
+ * + *

+ * relationship indicates the type of relationship that the restriction represents (allow | + * deny). In the example above, the media object should only be syndicated in Australia and the + * United States. It is a required attribute. + *

+ * + *

+ * Note: If the "allow" element is empty and the type is relationship is "allow", + * it is assumed that the empty list means "allow nobody" and the media should not be syndicated. + *

+ *

+ * A more explicit method would be: + *

+ * + *
+ * <media:restriction relationship="allow" type="country">au us</media:restriction>
+ * 
+ * + *

+ * type specifies the type of restriction (country | uri) that the media can be syndicated. + * It is an optional attribute; however can only be excluded when using one of the literal values + * "all" or "none". + *

+ * + *

+ * "country" allows restrictions to be placed based on country code. [ISO 3166] + *

+ *

+ * "uri" allows restrictions based on URI. Examples: urn:apple, http://images.google.com, urn:yahoo, + * etc. + * + * @author cooper + */ +public class Restriction implements Serializable { + private static final long serialVersionUID = 1L; + + private final Relationship relationship; + private final String value; + private final Type type; + + /** + * Creates a new instance of Restriction + * + * @param relationship a Restriction.Relationship object + * @param type A Restriction.Type object + * @param value a value for the restriction. + */ + public Restriction(final Relationship relationship, final Type type, final String value) { + if (value == null || relationship == null) { + throw new NullPointerException("Value and Relationship cannot be null."); + } + + if (type == null && !(value.equals("all") || value.equals("none"))) { + throw new NullPointerException("Type is required if the value is other than 'all' or 'none'."); + } + + this.relationship = relationship; + this.type = type; + this.value = value; + } + + public Relationship getRelationship() { + return relationship; + } + + public Type getType() { + return type; + } + + public String getValue() { + return value; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(this.getClass(), this); + + return tsBean.toString(); + } + + /** + * Indicates the action of the relationship + */ + public static class Relationship { + /** + * An Allow relationship + */ + public static final Relationship ALLOW = new Relationship("allow"); + + /** + * A deny relationship. + */ + public static final Relationship DENY = new Relationship("deny"); + private final String value; + + private Relationship(final String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + /** + * Indicated the type of the relationship + */ + public static class Type { + /** + * Indicates a Country type. + */ + public static final Type COUNTRY = new Type("country"); + + /** + * Indicates a URI for a special restriction type. + */ + public static final Type URI = new Type("uri"); + private final String value; + + private Type(final String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Text.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Text.java new file mode 100644 index 0000000..495dae5 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Text.java @@ -0,0 +1,174 @@ +/* + * Text.java + * + * Created on April 18, 2006, 10:25 PM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * <media:text>

+ *

+ * Allows the inclusion of a text transcript, closed captioning, or lyrics of the media content. + * Many of these elements are permitted to provide a time series of text. In such cases, it is + * encouraged, but not required, that the elements be grouped by language and appear in time + * sequence order based on the start time. Elements can have overlapping start and + * end times. It has 4 optional attributes. + *

+ * + *
+ * <media:text type="plain" lang="en" start="00:00:03.000"
+ *        end="00:00:10.000"> Oh, say, can you see</media:text>
+ * 
+ *        <media:text type="plain" lang="en" start="00:00:10.000"
+ *        end="00:00:17.000">By the dawn's early light</media:text>
+ * 
+ *

+ * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. + * Default value is 'plain'. All html must be entity-encoded. It is an optional attribute. + *

+ * + * + * + * + * + * + *

+ * lang is the primary language encapsulated in the media object. Language codes possible + * are detailed in RFC 3066. This attribute is used similar to the xml:lang attribute detailed in + * the XML 1.0 Specification (Third Edition). It is an optional attribute. + *

+ * + *

+ * start specifies the start time offset that the text starts being relevant to the media + * object. An example of this would be for closed captioning. It uses the NTP time code format (see: + * the time attribute used in <media:thumbnail>). It is an optional attribute. + *

+ * + *

+ * end specifies the end time that the text is relevant. If this attribute is not provided, + * and a start time is used, it is expected that the end time is either the end of the clip + * or the start of the next <media:text> element. + *

+ * + * @author cooper + */ +public class Text implements Serializable { + private static final long serialVersionUID = 1L; + private String type; + private final String value; + private Time end; + private Time start; + + /** + * Creates a text object. + * + * @param value value of the text + */ + public Text(final String value) { + this.value = value; + } + + /** + * Creates a new instance of Text + * + * @param type type of text + * @param value value of text + */ + public Text(final String type, final String value) { + this.type = type; + this.value = value; + } + + /** + * Creates a text object with start and end times + * + * @param type type of text + * @param value value of text + * @param start start time + * @param end end time + */ + public Text(final String type, final String value, final Time start, final Time end) { + this(type, value); + this.start = start; + this.end = end; + } + + /** + * End time of the text + * + * @return End time of the text + */ + public Time getEnd() { + return end; + } + + /** + * Start time of the text + * + * @return Start time of the text + */ + public Time getStart() { + return start; + } + + /** + * type of the text + * + * @return type of the text + */ + public String getType() { + return type; + } + + /** + * Value of the text + * + * @return type of the text + */ + public String getValue() { + return value; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(this.getClass(), this); + + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Thumbnail.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Thumbnail.java new file mode 100644 index 0000000..1aa9e1a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Thumbnail.java @@ -0,0 +1,173 @@ +/* + * Copyright 2006 Nathanial X. Freitas, openvision.tv + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.net.URI; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * <media:thumbnail>

+ * + * + *

+ * Allows particular images to be used as representative images for the media object. If multiple + * thumbnails are included, and time coding is not at play, it is assumed that the images are in + * order of importance. It has 1 required attribute and 3 optional attributes. + *

+ * + * + * + * + * + *
+ * <media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123" />
+ * 
+ *

+ * url specifies the url of the thumbnail. It is a required attribute. + *

+ *

+ * height specifies the height of the thumbnail. It is an optional attribute. + *

+ *

+ * width specifies the width of the thumbnail. It is an optional attribute. + *

+ * + * + *

+ * time specifies the time offset in relation to the media object. Typically this is used + * when creating multiple keyframes within a single video. The format for this attribute should be + * in the DSM-CC's Normal Play Time (NTP) as used in RTSP [RFC 2326 3.6 Normal Play Time]. It is an optional + * attribute. + *

+ */ +public class Thumbnail implements Cloneable, Serializable { + private static final long serialVersionUID = 1L; + + private Integer thumbHeight = null; + private Integer thumbWidth = null; + private final Time time; + private URI thumbUrl = null; + + /** + * Creates a new thumbnail + * + * @param url URL to thumbnail + * @param width width in pixels + * @param height height in pixels + * @param time Timecode representing the thumbnails position in a source. + */ + public Thumbnail(final URI url, final Integer width, final Integer height, final Time time) { + thumbUrl = url; + thumbHeight = height; + thumbWidth = width; + this.time = time; + } + + /** + * Creates a new thumbnail + * + * @param url URL + * @param width width + * @param height height + */ + public Thumbnail(final URI url, final Integer width, final Integer height) { + this(url, width, height, null); + } + + /** + * Creates a new thumbnail + * + * @param url URL + */ + public Thumbnail(final URI url) { + this(url, null, null, null); + } + + /** + * + * Returns the thumbHeight. + * + * @return Returns the thumbHeight. + */ + public Integer getHeight() { + return thumbHeight; + } + + /** + * returns the time that the thumbnail was captured from its source + * + * @return returns the time that the thumbnail was captured from its source + */ + public Time getTime() { + return time; + } + + /** + * + * Retursn the URL + * + * @return Returns the thumbUrl. + */ + public URI getUrl() { + return thumbUrl; + } + + /** + * + * Returns width. + * + * @return Returns the thumbWidth. + */ + public Integer getWidth() { + return thumbWidth; + } + + @Override + public Object clone() { + return new Thumbnail(thumbUrl, thumbWidth, thumbHeight); + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(this.getClass(), this); + + return tsBean.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Time.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Time.java new file mode 100644 index 0000000..8bf9354 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Time.java @@ -0,0 +1,112 @@ +/* + * Time.java + * + * Created on April 18, 2006, 9:48 PM + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.text.NumberFormat; + +import com.rometools.rome.feed.impl.EqualsBean; + +/** + * Represents a RFC 2326 3.6 Normal Play Time + * timestamp. + * + * @author cooper + */ +public class Time implements Serializable { + private static final long serialVersionUID = 1L; + + private static final long SECOND = 1000; + private static final long MINUTE = 60 * SECOND; + private static final long HOUR = 60 * MINUTE * SECOND; + private static final NumberFormat nf = NumberFormat.getInstance(); + + static { + nf.setMinimumIntegerDigits(2); + } + + private long milliseconds = 0; + + /** + * Creates a new instance of Time + * + * @param milliseconds milliseconds in length or offset. + */ + public Time(final long milliseconds) { + this.milliseconds = milliseconds; + } + + /** + * Creates a new instance of Time + * + * @param value RFC 2326 3.6 Normal Play Time + * value + */ + public Time(final String value) { + final String[] values = value.split(":"); + int count = values.length - 1; + milliseconds = (long) (Double.parseDouble(values[count]) * SECOND); + count--; + + if (count >= 0) { + milliseconds += Long.parseLong(values[count]) * MINUTE; + count--; + } + + if (count >= 0) { + milliseconds += Long.parseLong(values[count]) * HOUR; + } + } + + public long getValue() { + return milliseconds; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + long value = milliseconds; + final long hours = value / HOUR; + value -= hours * HOUR; + + final long minutes = value / MINUTE; + value -= minutes * MINUTE; + + final double seconds = (double) value / (double) SECOND; + + return nf.format(hours) + ":" + nf.format(minutes) + ":" + seconds; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/UrlReference.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/UrlReference.java new file mode 100644 index 0000000..4c7b710 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/UrlReference.java @@ -0,0 +1,98 @@ +/* + * UrlReference.java + * + * Created on April 18, 2006, 7:18 PM + * + * + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * 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.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.net.URI; +import java.net.URISyntaxException; + +import com.rometools.rome.feed.impl.EqualsBean; + +/** + * Used to indicate a URL primary reference for a MediaContent object. + * + * @author cooper + */ +public class UrlReference implements Reference, Serializable { + private static final long serialVersionUID = 1L; + + private final URI url; + + /** + * Creates a new UrlReference. + * + * @param url URL to the media source + */ + public UrlReference(final URI url) { + if (url == null) { + throw new NullPointerException("url cannot be null."); + } + + this.url = url; + } + + /** + * Creates a new instance of UrlReference + * + * @param url String value of a URL + * @throws java.net.MalformedURLException thrown on bad URLs + */ + public UrlReference(final String url) throws URISyntaxException { + super(); + + if (url == null) { + throw new NullPointerException("url cannot be null."); + } + + this.url = new URI(url); + } + + /** + * Returns the URL value + * + * @return Returns the URL value + */ + public URI getUrl() { + return url; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(this.getClass(), this); + + return equals.beanHashCode(); + } + + @Override + public String toString() { + return url.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/package.html b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/package.html new file mode 100644 index 0000000..3ac4ff7 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/package.html @@ -0,0 +1,10 @@ + + + + + + + + This package contains datatypes for working with MediaRSS. + + diff --git a/rome-modules/src/main/java/com/rometools/modules/opensearch/OpenSearchModule.java b/rome-modules/src/main/java/com/rometools/modules/opensearch/OpenSearchModule.java new file mode 100644 index 0000000..a1269aa --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/opensearch/OpenSearchModule.java @@ -0,0 +1,29 @@ +/* + * 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.rometools.modules.opensearch; + +import com.rometools.rome.feed.module.Module; + +/** + * Provides access to A9 Open Search information. + * + * @author Michael W. Nassif (enrouteinc@gmail.com) + */ +public interface OpenSearchModule extends Module, OpenSearchResponse { + + public final static String URI = "http://a9.com/-/spec/opensearch/1.1/"; + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/opensearch/OpenSearchResponse.java b/rome-modules/src/main/java/com/rometools/modules/opensearch/OpenSearchResponse.java new file mode 100644 index 0000000..bc9a45e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/opensearch/OpenSearchResponse.java @@ -0,0 +1,144 @@ +/* + * 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.rometools.modules.opensearch; + +import java.util.List; + +import com.rometools.modules.opensearch.entity.OSQuery; +import com.rometools.rome.feed.atom.Link; + +/** + * Provides access to A9 Open Search information. + * + * @author Michael W. Nassif (enrouteinc@gmail.com) + */ +public interface OpenSearchResponse { + + /** + * # totalResults – the maximum number of results available for these search terms + * + * * Restrictions: An integer greater than or equal to 0. * Default: The number of items that + * were returned in this set of results. * Requirements: May appear zero or one time. + * + * @param totalResults A positive integer value. + */ + public void setTotalResults(int totalResults); + + /** + * # totalResults – the maximum number of results available for these search terms + * + * * Restrictions: An integer greater than or equal to 0. * Default: The number of items that + * were returned in this set of results. * Requirements: May appear zero or one time. + * + * @return a positive integer value. + */ + public int getTotalResults(); + + /** + * # startIndex – the index of the first item returned in the result. + * + * * Restrictions: An integer greater than or equal to 1. * Note: The first result is 1. * + * Default: 1 * Requirements: May appear zero or one time. + * + * @param startIndex int value >= 1. + */ + public void setStartIndex(int startIndex); + + /** + * # startIndex – the index of the first item returned in the result. + * + * * Restrictions: An integer greater than or equal to 1. * Note: The first result is 1. * + * Default: 1 * Requirements: May appear zero or one time. + * + * @return int value >= 1. + */ + public int getStartIndex(); + + /** + * # itemsPerPage – the maximum number of items that can appear in one page of results. + * + * * Restrictions: An integer greater than or equal to 1. * Default: The number of items that + * were returned in this set of results. * Requirements: May appear zero or one time. + * + * @param itemsPerPage int value >= 1. + */ + public void setItemsPerPage(int itemsPerPage); + + /** + * # itemsPerPage – the maximum number of items that can appear in one page of results. + * + * * Restrictions: An integer greater than or equal to 1. * Default: The number of items that + * were returned in this set of results. * Requirements: May appear zero or one time. + * + * @return int value >= 1 + */ + public int getItemsPerPage(); + + /** + * # link – a reference back to the OpenSearch Description file + * + * * Attributes: This is a clone of the link element in Atom, including href, hreflang, rel, and + * type attributes. * Restrictions: The rel attribute must equal search. * Note: New in version + * 1.1. * Requirements: May appear zero or one time. + * + * @param link link to the open search spec. + */ + public void setLink(Link link); + + /** + * # link – a reference back to the OpenSearch Description file + * + * * Attributes: This is a clone of the link element in Atom, including href, hreflang, rel, and + * type attributes. * Restrictions: The rel attribute must equal search. * Note: New in version + * 1.1. * Requirements: May appear zero or one time. + * + * @return link to the opensearch spec. + */ + public Link getLink(); + + // list of OSResponseQuery interfaces + /** + * Query – in an OpenSearch Response, can be used both to echo back the original + * query and to suggest new searches. Please see the OpenSearch Query + * specification for more information. + *
    + *
  • Note: New in version 1.1.
  • + *
  • Requirements: May appear zero or more times. Note that the “Q” is capitalized.
  • + * + * @param query List of OSQuery objects. + */ + public void setQueries(List query); + + /** + * Query – in an OpenSearch Response, can be used both to echo back the original + * query and to suggest new searches. Please see the OpenSearch Query + * specification for more information. + *
      + *
    • Note: New in version 1.1.
    • + *
    • Requirements: May appear zero or more times. Note that the “Q” is capitalized.
    • + * + * @return A list of OSQuery objects. + */ + public List getQueries(); + + // convenience method + /** + * Adds a query to the module. + * + * @param query OSQuery object to add. + */ + public void addQuery(OSQuery query); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/opensearch/RequiredAttributeMissingException.java b/rome-modules/src/main/java/com/rometools/modules/opensearch/RequiredAttributeMissingException.java new file mode 100644 index 0000000..ddb53ce --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/opensearch/RequiredAttributeMissingException.java @@ -0,0 +1,36 @@ +/* + * 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.rometools.modules.opensearch; + +/** + * @author Michael W. Nassif (enrouteinc@gmail.com) + */ +public class RequiredAttributeMissingException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public RequiredAttributeMissingException(final String arg0, final Throwable arg1) { + super(arg0, arg1); + } + + public RequiredAttributeMissingException(final String arg0) { + super(arg0); + } + + public RequiredAttributeMissingException(final Throwable arg0) { + super(arg0); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/opensearch/entity/OSQuery.java b/rome-modules/src/main/java/com/rometools/modules/opensearch/entity/OSQuery.java new file mode 100644 index 0000000..ee8b011 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/opensearch/entity/OSQuery.java @@ -0,0 +1,186 @@ +/* + * 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.rometools.modules.opensearch.entity; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.ObjectBean; + +/** + * @author Michael W. Nassif (enrouteinc@gmail.com) Class representation of the Query object + * (Response portion so far) + */ +public class OSQuery implements Cloneable, Serializable { + private static final long serialVersionUID = 1L; + + ObjectBean _objBean = null; + + // role is required + private String role; + private int startPage = -1; + private int totalResults = -1; + private String osd; + private String title; + private String searchTerms; + + /** + * Default constructor. All properties are set to null. + *

      + */ + public OSQuery() { + _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. + * + */ + @Override + 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. + * + */ + @Override + public boolean equals(final 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. + * + */ + @Override + public int hashCode() { + return _objBean.hashCode(); + } + + /** + * Returns the String representation for the object. + *

      + * + * @return String representation for the object. + * + */ + @Override + public String toString() { + return _objBean.toString(); + } + + /** + * @return Returns the osd. + */ + public String getOsd() { + return osd; + } + + /** + * Typically represents a url link to the os description file + * + * @param osd The osd to set. + */ + public void setOsd(final String osd) { + this.osd = osd; + } + + /** + * @return Returns the role. + */ + public String getRole() { + return role; + } + + /** + * @param role The role to set. + */ + public void setRole(final String role) { + this.role = role; + } + + /** + * @return Returns the searchTerms. + */ + public String getSearchTerms() { + return searchTerms; + } + + /** + * @param searchTerms The searchTerms to set. + */ + public void setSearchTerms(final String searchTerms) { + this.searchTerms = searchTerms; + } + + /** + * @return Returns the startPage. + */ + public int getStartPage() { + return startPage; + } + + /** + * @param startPage The startPage to set. + */ + public void setStartPage(final int startPage) { + this.startPage = startPage; + } + + /** + * @return Returns the title. + */ + public String getTitle() { + return title; + } + + /** + * @param title The title to set. + */ + public void setTitle(final String title) { + this.title = title; + } + + /** + * @return Returns the totalResults. + */ + public int getTotalResults() { + return totalResults; + } + + /** + * @param totalResults The totalResults to set. + */ + public void setTotalResults(final int totalResults) { + this.totalResults = totalResults; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/opensearch/impl/OpenSearchModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/opensearch/impl/OpenSearchModuleGenerator.java new file mode 100644 index 0000000..529e0f6 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/opensearch/impl/OpenSearchModuleGenerator.java @@ -0,0 +1,171 @@ +/* + * 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.rometools.modules.opensearch.impl; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jdom2.Attribute; +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.opensearch.OpenSearchModule; +import com.rometools.modules.opensearch.RequiredAttributeMissingException; +import com.rometools.modules.opensearch.entity.OSQuery; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * @author Michael W. Nassif (enrouteinc@gmail.com) OpenSearch implementation of ModuleGenerator + */ +public class OpenSearchModuleGenerator implements ModuleGenerator { + + private static final Namespace OS_NS = Namespace.getNamespace("opensearch", OpenSearchModule.URI); + + @Override + public String getNamespaceUri() { + return OpenSearchModule.URI; + } + + private static final Set NAMESPACES; + + static { + final Set nss = new HashSet(); + nss.add(OS_NS); + NAMESPACES = Collections.unmodifiableSet(nss); + } + + /** + * Returns a set with all the URIs (JDOM Namespace elements) this module generator uses. + *

      + * It is used by the the feed generators to add their namespace definition in the root element + * of the generated document (forward-missing of Java 5.0 Generics). + *

      + * + * @return a set with all the URIs (JDOM Namespace elements) this module generator uses. + */ + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + @Override + public void generate(final Module module, final Element element) { + + final OpenSearchModule osm = (OpenSearchModule) module; + + if (osm.getItemsPerPage() > -1) { + element.addContent(generateSimpleElement("itemsPerPage", Integer.toString(osm.getItemsPerPage()))); + } + + if (osm.getTotalResults() > -1) { + element.addContent(generateSimpleElement("totalResults", Integer.toString(osm.getTotalResults()))); + } + + final int startIndex = osm.getStartIndex() > 0 ? osm.getStartIndex() : 1; + element.addContent(generateSimpleElement("startIndex", Integer.toString(startIndex))); + + if (osm.getQueries() != null) { + + final List queries = osm.getQueries(); + + for (final OSQuery query : queries) { + if (query != null) { + element.addContent(generateQueryElement(query)); + } + } + } + + if (osm.getLink() != null) { + element.addContent(generateLinkElement(osm.getLink())); + } + } + + protected Element generateQueryElement(final OSQuery query) { + + final Element qElement = new Element("Query", OS_NS); + + if (query.getRole() != null) { + final Attribute roleAttribute = new Attribute("role", query.getRole()); + qElement.setAttribute(roleAttribute); + } else { + throw new RequiredAttributeMissingException("If declaring a Query element, the field 'role' must be be specified"); + } + + if (query.getOsd() != null) { + final Attribute osd = new Attribute("osd", query.getOsd()); + qElement.setAttribute(osd); + } + + if (query.getSearchTerms() != null) { + final Attribute searchTerms = new Attribute("searchTerms", query.getSearchTerms()); + qElement.setAttribute(searchTerms); + } + + if (query.getStartPage() > -1) { + final int startPage = query.getStartPage() != 0 ? query.getStartPage() : 1; + final Attribute sp = new Attribute("startPage", Integer.toString(startPage)); + qElement.setAttribute(sp); + } + + if (query.getTitle() != null) { + qElement.setAttribute(new Attribute("title", query.getTitle())); + } + + if (query.getTotalResults() > -1) { + qElement.setAttribute(new Attribute("totalResults", Integer.toString(query.getTotalResults()))); + } + + return qElement; + } + + protected Element generateLinkElement(final Link link) { + final Element linkElement = new Element("link", OS_NS); + + if (link.getRel() != null) { + final Attribute relAttribute = new Attribute("rel", "search"); + linkElement.setAttribute(relAttribute); + } + + if (link.getType() != null) { + final Attribute typeAttribute = new Attribute("type", link.getType()); + linkElement.setAttribute(typeAttribute); + } + + if (link.getHref() != null) { + final Attribute hrefAttribute = new Attribute("href", link.getHref()); + linkElement.setAttribute(hrefAttribute); + } + + if (link.getHreflang() != null) { + final Attribute hreflangAttribute = new Attribute("hreflang", link.getHreflang()); + linkElement.setAttribute(hreflangAttribute); + } + return linkElement; + } + + protected Element generateSimpleElement(final String name, final String value) { + + final Element element = new Element(name, OS_NS); + element.addContent(value); + + return element; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/opensearch/impl/OpenSearchModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/opensearch/impl/OpenSearchModuleImpl.java new file mode 100644 index 0000000..a0a0f03 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/opensearch/impl/OpenSearchModuleImpl.java @@ -0,0 +1,161 @@ +/* + * 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.rometools.modules.opensearch.impl; + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.opensearch.OpenSearchModule; +import com.rometools.modules.opensearch.entity.OSQuery; +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.module.ModuleImpl; + +/** + * @author Michael W. Nassif (enrouteinc@gmail.com) OpenSearch Module implementation + */ +public class OpenSearchModuleImpl extends ModuleImpl implements OpenSearchModule, Serializable { + private static final long serialVersionUID = 1L; + private static final Logger LOG = LoggerFactory.getLogger(OpenSearchModuleImpl.class); + private int totalResults = -1; + private int startIndex = 1; + private int itemsPerPage = -1; + private Link link; + private List queries; + + public OpenSearchModuleImpl() { + super(OpenSearchModuleImpl.class, OpenSearchModule.URI); + } + + /** + * @return Returns the itemsPerPage. + */ + @Override + public int getItemsPerPage() { + return itemsPerPage; + } + + /** + * @param itemsPerPage The itemsPerPage to set. + */ + @Override + public void setItemsPerPage(final int itemsPerPage) { + this.itemsPerPage = itemsPerPage; + } + + /** + * @return Returns the link. + */ + @Override + public Link getLink() { + return link; + } + + /** + * @param link The link to set. + */ + @Override + public void setLink(final Link link) { + this.link = link; + } + + /** + * @return Returns the queries. + */ + @Override + public List getQueries() { + if (queries == null) { + queries = new LinkedList(); + } + return queries; + } + + /** + * @param queries The queries to set. + */ + @Override + public void setQueries(final List queries) { + this.queries = queries; + } + + @Override + public void addQuery(final OSQuery query) { + getQueries().add(query); + } + + /** + * @return Returns the startIndex. + */ + @Override + public int getStartIndex() { + return startIndex; + } + + /** + * @param startIndex The startIndex to set. + */ + @Override + public void setStartIndex(final int startIndex) { + this.startIndex = startIndex; + } + + /** + * @return Returns the totalResults. + */ + @Override + public int getTotalResults() { + return totalResults; + } + + /** + * @param totalResults The totalResults to set. + */ + @Override + public void setTotalResults(final int totalResults) { + this.totalResults = totalResults; + } + + /* + * (non-Javadoc) + * + * @see com.rometools.rome.feed.CopyFrom#copyFrom(java.lang.Object) + */ + @Override + public void copyFrom(final CopyFrom obj) { + final OpenSearchModule osm = (OpenSearchModule) obj; + setTotalResults(osm.getTotalResults()); + setItemsPerPage(osm.getItemsPerPage()); + setStartIndex(osm.getStartIndex()); + setLink(osm.getLink()); + for (final OSQuery q : osm.getQueries()) { + try { + getQueries().add((OSQuery) q.clone()); + } catch (final CloneNotSupportedException e) { + LOG.error("Error", e); + } + } + } + + /* + * (non-Javadoc) + * + * @see com.rometools.rome.feed.CopyFrom#getInterface() + */ + @Override + public Class getInterface() { + return OpenSearchModule.class; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/opensearch/impl/OpenSearchModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/opensearch/impl/OpenSearchModuleParser.java new file mode 100644 index 0000000..1332b3d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/opensearch/impl/OpenSearchModuleParser.java @@ -0,0 +1,251 @@ +/* + * 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.rometools.modules.opensearch.impl; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Attribute; +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.jdom2.Parent; + +import com.rometools.modules.opensearch.OpenSearchModule; +import com.rometools.modules.opensearch.entity.OSQuery; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; + +/** + * @author Michael W. Nassif (enrouteinc@gmail.com) OpenSearch implementation of the ModuleParser + * class + */ +public class OpenSearchModuleParser implements ModuleParser { + + private static final Namespace OS_NS = Namespace.getNamespace("opensearch", OpenSearchModule.URI); + + @Override + public String getNamespaceUri() { + return OpenSearchModule.URI; + } + + @Override + public Module parse(final Element dcRoot, final Locale locale) { + + final URL baseURI = findBaseURI(dcRoot); + + boolean foundSomething = false; + final OpenSearchModule osm = new OpenSearchModuleImpl(); + + Element e = dcRoot.getChild("totalResults", OS_NS); + + if (e != null) { + try { + osm.setTotalResults(Integer.parseInt(e.getText())); + foundSomething = true; + } catch (final NumberFormatException ex) { + // Ignore setting the field and post a warning + System.err.println("Warning: The element totalResults must be an integer value: " + ex.getMessage()); + } + } + + e = dcRoot.getChild("itemsPerPage", OS_NS); + if (e != null) { + try { + osm.setItemsPerPage(Integer.parseInt(e.getText())); + foundSomething = true; + } catch (final NumberFormatException ex) { + // Ignore setting the field and post a warning + System.err.println("Warning: The element itemsPerPage must be an integer value: " + ex.getMessage()); + } + } + + e = dcRoot.getChild("startIndex", OS_NS); + if (e != null) { + try { + osm.setStartIndex(Integer.parseInt(e.getText())); + foundSomething = true; + } catch (final NumberFormatException ex) { + // Ignore setting the field and post a warning + System.err.println("Warning: The element startIndex must be an integer value: " + ex.getMessage()); + } + } + + final List queries = dcRoot.getChildren("Query", OS_NS); + + if (queries != null && !queries.isEmpty()) { + + // Create the OSQuery list + final List osqList = new LinkedList(); + + for (final Iterator iter = queries.iterator(); iter.hasNext();) { + e = iter.next(); + osqList.add(parseQuery(e)); + } + + osm.setQueries(osqList); + } + + e = dcRoot.getChild("link", OS_NS); + + if (e != null) { + osm.setLink(parseLink(e, baseURI)); + } + + return foundSomething ? osm : null; + } + + private static OSQuery parseQuery(final Element e) { + + final OSQuery query = new OSQuery(); + + String att = e.getAttributeValue("role"); + query.setRole(att); + + att = e.getAttributeValue("osd"); + query.setOsd(att); + + att = e.getAttributeValue("searchTerms"); + query.setSearchTerms(att); + + att = e.getAttributeValue("title"); + query.setTitle(att); + + try { + + // someones mistake should not cause the parser to fail, since these + // are only optional attributes + + att = e.getAttributeValue("totalResults"); + if (att != null) { + query.setTotalResults(Integer.parseInt(att)); + } + + att = e.getAttributeValue("startPage"); + if (att != null) { + query.setStartPage(Integer.parseInt(att)); + } + + } catch (final NumberFormatException ex) { + System.err.println("Warning: Exception caught while trying to parse a non-numeric Query attribute " + ex.getMessage()); + } + + return query; + } + + private static Link parseLink(final Element e, final URL baseURI) { + + final Link link = new Link(); + + String att = e.getAttributeValue("rel");// getAtomNamespace()); DONT + // KNOW WHY DOESN'T WORK + + if (att != null) { + link.setRel(att); + } + + att = e.getAttributeValue("type");// getAtomNamespace()); DONT KNOW WHY + // DOESN'T WORK + + if (att != null) { + link.setType(att); + } + + att = e.getAttributeValue("href");// getAtomNamespace()); DONT KNOW WHY + // DOESN'T WORK + + if (att != null) { + + if (isRelativeURI(att)) { // + link.setHref(resolveURI(baseURI, e, "")); + } else { + link.setHref(att); + } + } + + att = e.getAttributeValue("hreflang");// getAtomNamespace()); DONT KNOW + // WHY DOESN'T WORK + + if (att != null) { + link.setHreflang(att); + } + + att = e.getAttributeValue("length");// getAtomNamespace()); DONT KNOW + // WHY DOESN'T WORK + + return link; + } + + private static boolean isRelativeURI(final String uri) { + if (uri.startsWith("http://") || uri.startsWith("https://") || uri.startsWith("/")) { + return false; + } + return true; + } + + /** + * Use xml:base attributes at feed and entry level to resolve relative links + */ + private static String resolveURI(final URL baseURI, final Parent parent, String url) { + url = url.equals(".") || url.equals("./") ? "" : url; + if (isRelativeURI(url) && parent != null && parent instanceof Element) { + final Attribute baseAtt = ((Element) parent).getAttribute("base", Namespace.XML_NAMESPACE); + String xmlBase = baseAtt == null ? "" : baseAtt.getValue(); + if (!isRelativeURI(xmlBase) && !xmlBase.endsWith("/")) { + xmlBase = xmlBase.substring(0, xmlBase.lastIndexOf("/") + 1); + } + return resolveURI(baseURI, parent.getParent(), xmlBase + url); + } else if (isRelativeURI(url) && parent == null) { + return baseURI + url; + } else if (baseURI != null && url.startsWith("/")) { + String hostURI = baseURI.getProtocol() + "://" + baseURI.getHost(); + if (baseURI.getPort() != baseURI.getDefaultPort()) { + hostURI = hostURI + ":" + baseURI.getPort(); + } + return hostURI + url; + } + return url; + } + + /** Use feed links and/or xml:base attribute to determine baseURI of feed */ + private static URL findBaseURI(final Element root) { + URL baseURI = null; + final List linksList = root.getChildren("link", OS_NS); + if (linksList != null) { + for (final Element element : linksList) { + final Element link = element; + if (!root.equals(link.getParent())) { + break; + } + String href = link.getAttribute("href").getValue(); + if (link.getAttribute("rel", OS_NS) == null || link.getAttribute("rel", OS_NS).getValue().equals("alternate")) { + href = resolveURI(null, link, href); + try { + baseURI = new URL(href); + break; + } catch (final MalformedURLException e) { + System.err.println("Base URI is malformed: " + href); + } + } + } + } + return baseURI; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/photocast/PhotocastModule.java b/rome-modules/src/main/java/com/rometools/modules/photocast/PhotocastModule.java new file mode 100644 index 0000000..7d219b5 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/photocast/PhotocastModule.java @@ -0,0 +1,131 @@ +/* + * PhotocastModule.java + * + * Created on March 30, 2006, 6:27 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.photocast; + +import java.net.URL; +import java.util.Date; + +import com.rometools.modules.photocast.types.Metadata; +import com.rometools.rome.feed.module.Module; + +/** + * This is a ROME module that provides support for the "http://www.apple.com/ilife/wallpapers" + * namespace. + * + * See the package information for example usage. + * + * @author Robert "kebernet" Cooper + */ +public interface PhotocastModule extends Module { + /** + * The URI of the namespace. ("http://www.apple.com/ilife/wallpapers") + */ + public static final String URI = "http://www.apple.com/ilife/wallpapers"; + + /** + * Returns the Item level photoDate value. + * + * @return Returns the Item level photoDate value. + */ + public Date getPhotoDate(); + + /** + * Set the Item level photoDate value. + * + * @param photoDate Item level photoDate value + */ + public void setPhotoDate(Date photoDate); + + /** + * Returns the cropDate value from the item level. + * + * @return Item level cropDate value + */ + public Date getCropDate(); + + /** + * Sets the cropDate value for the item level. + * + * @param cropDate cropDate value for the item level + */ + public void setCropDate(Date cropDate); + + /** + * The URL of the image. + * + * @return The URL of the image. + */ + public URL getImageUrl(); + + /** + * The URL of the image. + * + * @param imageUrl The URL of the image. + */ + public void setImageUrl(URL imageUrl); + + /** + * The URL of the image thumbnail. + * + * @return The URL of the image thumbnail. + */ + public URL getThumbnailUrl(); + + /** + * The URL of the image thumbnail. + * + * @param thumbnailUrl The URL of the image thumbnail. + */ + public void setThumbnailUrl(URL thumbnailUrl); + + /** + * The iPhoto metadata for the image. + * + * @return The iPhoto metadata for the image. + */ + public Metadata getMetadata(); + + /** + * The iPhoto metadata for the image. + * + * @param metadata The iPhoto metadata for the image. + */ + public void setMetadata(Metadata metadata); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/photocast/PhotocastModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/photocast/PhotocastModuleImpl.java new file mode 100644 index 0000000..8f239de --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/photocast/PhotocastModuleImpl.java @@ -0,0 +1,173 @@ +/* + * PhotocastModuleImpl.java + * + * Created on March 30, 2006, 6:23 PM + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.photocast; + +import java.net.URL; +import java.util.Date; + +import com.rometools.modules.photocast.types.Metadata; +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class PhotocastModuleImpl implements PhotocastModule { + /** + * + */ + private static final long serialVersionUID = 1L; + private Date photoDate; + private Date cropDate; + private URL imageUrl; + private URL thumbnailUrl; + private Metadata metadata; + + /** Creates a new instance of PhotocastModuleImpl */ + public PhotocastModuleImpl() { + } + + @Override + public Date getPhotoDate() { + return photoDate; + } + + @Override + public void setPhotoDate(final Date photoDate) { + this.photoDate = photoDate; + } + + @Override + public Date getCropDate() { + return cropDate; + } + + @Override + public void setCropDate(final Date cropDate) { + this.cropDate = cropDate; + } + + @Override + public URL getImageUrl() { + return imageUrl; + } + + @Override + public void setImageUrl(final URL imageUrl) { + this.imageUrl = imageUrl; + } + + @Override + public URL getThumbnailUrl() { + return thumbnailUrl; + } + + @Override + public void setThumbnailUrl(final URL thumbnailUrl) { + this.thumbnailUrl = thumbnailUrl; + } + + @Override + public Metadata getMetadata() { + return metadata; + } + + @Override + public void setMetadata(final Metadata metadata) { + this.metadata = metadata; + } + + @Override + public void copyFrom(final CopyFrom obj) { + final PhotocastModule pm = (PhotocastModule) obj; + setPhotoDate(pm.getPhotoDate() == null ? null : (Date) pm.getPhotoDate().clone()); + setCropDate(pm.getCropDate() == null ? null : (Date) pm.getCropDate().clone()); + setImageUrl(pm.getImageUrl()); + setThumbnailUrl(pm.getThumbnailUrl()); + setMetadata(pm.getMetadata()); + } + + @Override + public Object clone() { + final PhotocastModuleImpl pm = new PhotocastModuleImpl(); + pm.setPhotoDate(getPhotoDate() == null ? null : (Date) getPhotoDate().clone()); + pm.setCropDate(getCropDate() == null ? null : (Date) getCropDate().clone()); + pm.setImageUrl(getThumbnailUrl()); + pm.setThumbnailUrl(getThumbnailUrl()); + pm.setMetadata(getMetadata()); + + return pm; + } + + @Override + public String getUri() { + return PhotocastModule.URI; + } + + @Override + public Class getInterface() { + return PhotocastModule.class; + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(PhotocastModuleImpl.class, this); + + return tsBean.toString(); + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(PhotocastModuleImpl.class, this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(PhotocastModuleImpl.class, this); + + return equals.beanHashCode(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/photocast/io/Generator.java b/rome-modules/src/main/java/com/rometools/modules/photocast/io/Generator.java new file mode 100644 index 0000000..64780f4 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/photocast/io/Generator.java @@ -0,0 +1,113 @@ +/* + * Generator.java + * + * Created on March 30, 2006, 6:43 PM + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.photocast.io; + +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.photocast.PhotocastModule; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class Generator implements ModuleGenerator { + + private static final Namespace NS = Namespace.getNamespace("apple-wallpapers", PhotocastModule.URI); + private static final HashSet NAMESPACES = new HashSet(); + private static final String FEED_VERSION = "0.9"; + static { + NAMESPACES.add(NS); + } + + /** Creates a new instance of Generator */ + public Generator() { + super(); + } + + @Override + public void generate(final Module module, final Element element) { + if (!(module instanceof PhotocastModule)) { + return; + } + final PhotocastModule pm = (PhotocastModule) module; + if (element.getName().equals("channel") || element.getName().equals("feed")) { + element.addContent(generateSimpleElement("feedVersion", FEED_VERSION)); + return; + } + element.addContent(generateSimpleElement("photoDate", Parser.PHOTO_DATE_FORMAT.format(pm.getPhotoDate()))); + element.addContent(generateSimpleElement("cropDate", Parser.CROP_DATE_FORMAT.format(pm.getCropDate()))); + element.addContent(generateSimpleElement("thumbnail", pm.getThumbnailUrl().toString())); + element.addContent(generateSimpleElement("image", pm.getImageUrl().toString())); + final Element e = new Element("metadata", NS); + final Element pd = new Element("PhotoDate", ""); + pd.addContent(pm.getMetadata().getPhotoDate().toString()); + e.addContent(pd); + final Element com = new Element("Comments", ""); + com.addContent(pm.getMetadata().getComments()); + e.addContent(com); + element.addContent(e); + } + + @Override + public Set getNamespaces() { + return Generator.NAMESPACES; + } + + @Override + public String getNamespaceUri() { + return PhotocastModule.URI; + } + + protected Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, NS); + element.addContent(value); + + return element; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/photocast/io/Parser.java b/rome-modules/src/main/java/com/rometools/modules/photocast/io/Parser.java new file mode 100644 index 0000000..354400d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/photocast/io/Parser.java @@ -0,0 +1,144 @@ +/* + * Parser.java + * + * Created on March 30, 2006, 6:43 PM + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.photocast.io; + +import java.net.URL; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.photocast.PhotocastModule; +import com.rometools.modules.photocast.PhotocastModuleImpl; +import com.rometools.modules.photocast.types.Metadata; +import com.rometools.modules.photocast.types.PhotoDate; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class Parser implements ModuleParser { + + private static final Logger LOG = LoggerFactory.getLogger(Parser.class); + + private static final Namespace NS = Namespace.getNamespace(PhotocastModule.URI); + // 2005-11-29T04:36:06 + static final DateFormat PHOTO_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + // 2006-01-11 16:42:26 -0800 + static final DateFormat CROP_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); + + /** Creates a new instance of Parser */ + public Parser() { + } + + @Override + public Module parse(final Element element, final Locale locale) { + if (element.getName().equals("channel") || element.getName().equals("feed")) { + return new PhotocastModuleImpl(); + } else if (element.getChild("metadata", Parser.NS) == null && element.getChild("image", Parser.NS) == null) { + return null; + } + final PhotocastModule pm = new PhotocastModuleImpl(); + final List children = element.getChildren(); + final Iterator it = children.iterator(); + while (it.hasNext()) { + final Element e = it.next(); + if (!e.getNamespace().equals(Parser.NS)) { + continue; + } + if (e.getName().equals("photoDate")) { + try { + pm.setPhotoDate(Parser.PHOTO_DATE_FORMAT.parse(e.getText())); + } catch (final Exception ex) { + LOG.warn("Unable to parse photoDate: " + e.getText(), ex); + } + } else if (e.getName().equals("cropDate")) { + try { + pm.setCropDate(Parser.CROP_DATE_FORMAT.parse(e.getText())); + } catch (final Exception ex) { + LOG.warn("Unable to parse cropDate: " + e.getText(), ex); + } + } else if (e.getName().equals("thumbnail")) { + try { + pm.setThumbnailUrl(new URL(e.getText())); + } catch (final Exception ex) { + LOG.warn("Unable to parse thumnail: " + e.getText(), ex); + } + } else if (e.getName().equals("image")) { + try { + pm.setImageUrl(new URL(e.getText())); + } catch (final Exception ex) { + LOG.warn("Unable to parse image: " + e.getText(), ex); + } + } else if (e.getName().equals("metadata")) { + String comments = ""; + PhotoDate photoDate = null; + if (e.getChildText("PhotoDate") != null) { + try { + photoDate = new PhotoDate(Double.parseDouble(e.getChildText("PhotoDate"))); + } catch (final Exception ex) { + LOG.warn("Unable to parse PhotoDate: " + e.getText(), ex); + } + } + if (e.getChildText("Comments") != null) { + comments = e.getChildText("Comments"); + } + pm.setMetadata(new Metadata(photoDate, comments)); + } + } + return pm; + } + + @Override + public String getNamespaceUri() { + return PhotocastModule.URI; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/photocast/io/package.html b/rome-modules/src/main/java/com/rometools/modules/photocast/io/package.html new file mode 100644 index 0000000..c6cdda4 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/photocast/io/package.html @@ -0,0 +1,10 @@ + + + + + + + + This package contains the parser and generator implementations for ROME. + + diff --git a/rome-modules/src/main/java/com/rometools/modules/photocast/package.html b/rome-modules/src/main/java/com/rometools/modules/photocast/package.html new file mode 100644 index 0000000..d619ccc --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/photocast/package.html @@ -0,0 +1,69 @@ + + + + + + + + This package represents the Apple iPhoto Photocasting 0.9 namespace support. + Sample Usage: +

      + SyndFeed feed = input.build( new File( "/foo.rss" ) ) ); + List entries = feed.getEntries(); + for( int i =0; i < entries.size() ; i++ ){ + System.out.println( ((SyndEntry)entries.get(i)).getModule( PhotocastModule.URI ) ); + } + + // or to create a photocast module: + + SyndFeed myFeed = new SyndFeedImpl(); + myFeed.getModules().add( new PhotocastModuleImpl() ); + // you need this as a placeholder so the version gets in the feed. + + SyndEntry myEntry = new SyndEntryImpl(); + PhotocastModule pm = new PhotocastModuleImpl(); + pm.setUrl( new URL("http://foo.com/img.jpg" ) ); + pm.setThumnail( new URL("http://foo.com/img-small.jpg" ) ); + pm.setCropDate( new Date() ); + pm.setPhotoDate( new Date() ); + pm.setMetaData( new PhotoDate(), "Some comments that I think always get ignored." ); + myEntry.getModules().add( pm ); + +
      + * This library is provided under dual licenses.
      + * You may choose the terms of the Lesser General Public License or the Apache
      + * License at your discretion.
      + *
      + *  Copyright (C) 2006  Robert Cooper, Temple of the Screaming Penguin
      + *
      + *
      + * This library is free software; you can redistribute it and/or
      + * modify it under the terms of the GNU Lesser General Public
      + * License as published by the Free Software Foundation; either
      + * version 2.1 of the License, or (at your option) any later version.
      + *
      + * This library is distributed in the hope that it will be useful,
      + * but WITHOUT ANY WARRANTY; without even the implied warranty of
      + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      + * Lesser General Public License for more details.
      + *
      + * You should have received a copy of the GNU Lesser General Public
      + * License along with this library; if not, write to the Free Software
      + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      + *
      + *
      + * 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/rome-modules/src/main/java/com/rometools/modules/photocast/types/Metadata.java b/rome-modules/src/main/java/com/rometools/modules/photocast/types/Metadata.java new file mode 100644 index 0000000..02fe47f --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/photocast/types/Metadata.java @@ -0,0 +1,112 @@ +/* + * Metadata.java + * + * Created on March 30, 2006, 6:16 PM + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.photocast.types; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * This is an immutable class representing the apple-wallpapers:metadata tag in the photocast + * module. + * + * @author Robert "kebernet" Cooper + */ +public class Metadata { + + private final PhotoDate photoDate; + private final String comments; + + /** + * Creates a new instance of Metadata with a set photoDate and comments value. + * + * @param photoDate PhotoDate value to use + * @param comments comments about this photo. + */ + public Metadata(final PhotoDate photoDate, final String comments) { + this.photoDate = photoDate == null ? new PhotoDate() : photoDate; + this.comments = comments == null ? "" : comments; + } + + /** + * Returns the PhotoDate value. + * + * @return Returns the PhotoDate value. + */ + public PhotoDate getPhotoDate() { + return photoDate; + } + + /** + * Returns comments about the photo. + * + * @return Returns comments about the photo. + */ + public String getComments() { + return comments; + } + + /** + * Returns a String representation of the metadata object. + * + * @return Returns a String representation of the metadata object. + */ + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(Metadata.class, this); + + return tsBean.toString(); + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(Metadata.class, this); + + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(Metadata.class, this); + + return equals.beanHashCode(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/photocast/types/PhotoDate.java b/rome-modules/src/main/java/com/rometools/modules/photocast/types/PhotoDate.java new file mode 100644 index 0000000..89a7f7e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/photocast/types/PhotoDate.java @@ -0,0 +1,113 @@ +/* + * PhotoDate.java + * + * Created on March 30, 2006, 5:53 PM + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.photocast.types; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * This is a specialized Date class for working with the apple PhotoDate format. It provides a + * constructor taking a dobule value representing the fractional number of days since 00:00:00 + * 01/01/00. + * + * @author Robert "kebernet" Cooper + */ +public class PhotoDate extends Date { + + /** + * + */ + private static final long serialVersionUID = 1L; + private static final long Y2K = 946616400531l; + private static final double DAY = 24 * 60 * 60 * 1000; + + /** Creates a new instance of PhotoDate */ + public PhotoDate() { + super(); + } + + /** + * Creates a new instance of PhotoDate with the timestamp provided. + * + * @param time milliseconds time + */ + public PhotoDate(final long time) { + super(time); + } + + /** + * Creates a new instance of PhotoDate with the fractional number of days since 00:00:00 + * 01/01/00. + * + * @param photoDateValue fractional number of days since 00:00:00 01/01/00 + */ + public PhotoDate(final double photoDateValue) { + BigDecimal d = new BigDecimal(photoDateValue); + d = d.multiply(new BigDecimal(DAY)); + d = d.add(new BigDecimal(Y2K)); + setTime(d.longValue()); + } + + /** + * Returns a string representing the fractional number of days since 00:00:00 01/01/00. + * + * @return Returns a string representing the fractional number of days since 00:00:00 01/01/00. + */ + @Override + public String toString() { + BigDecimal d = new BigDecimal(getTime()); + d = d.subtract(new BigDecimal(Y2K)); + d = d.multiply(new BigDecimal(1000000)); + d = d.divide(new BigDecimal(DAY), BigDecimal.ROUND_HALF_UP); + return d.divide(new BigDecimal(1000000), 7, BigDecimal.ROUND_HALF_UP).toString(); + } + + @Override + public boolean equals(final Object o) { + if (o instanceof Date || ((Date) o).getTime() / 1000 == getTime() / 1000) { + return true; + } else { + return false; + } + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/photocast/types/package.html b/rome-modules/src/main/java/com/rometools/modules/photocast/types/package.html new file mode 100644 index 0000000..25f3091 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/photocast/types/package.html @@ -0,0 +1,10 @@ + + + + + + + + This package contains datatypes for use with the photocast module. + + diff --git a/rome-modules/src/main/java/com/rometools/modules/portablecontacts/ContactModule.java b/rome-modules/src/main/java/com/rometools/modules/portablecontacts/ContactModule.java new file mode 100644 index 0000000..db32b49 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/portablecontacts/ContactModule.java @@ -0,0 +1,26 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.portablecontacts; + +/** + * + * @author robert.cooper + */ +public interface ContactModule { + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/portablecontacts/types/Address.java b/rome-modules/src/main/java/com/rometools/modules/portablecontacts/types/Address.java new file mode 100644 index 0000000..9794765 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/portablecontacts/types/Address.java @@ -0,0 +1,26 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.portablecontacts.types; + +/** + * + * @author robert.cooper + */ +public class Address { + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/slash/Slash.java b/rome-modules/src/main/java/com/rometools/modules/slash/Slash.java new file mode 100644 index 0000000..0cf59fa --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/slash/Slash.java @@ -0,0 +1,73 @@ +/* + * Slash.java + * + * Created on November 19, 2005, 8:48 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.slash; + +import java.io.Serializable; + +import com.rometools.rome.feed.module.Module; + +/** + * This interface represents the Slash RSS extension. + * + * @version $Revision: 1.2 $ + * @author Robert "kebernet" Cooper + */ +public interface Slash extends Module, Serializable { + + public static final String URI = "http://purl.org/rss/1.0/modules/slash/"; + + public String getSection(); + + public void setSection(String section); + + public String getDepartment(); + + public void setDepartment(String department); + + public Integer getComments(); + + public void setComments(Integer comments); + + public Integer[] getHitParade(); + + public void setHitParade(Integer[] hitParade); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/slash/SlashImpl.java b/rome-modules/src/main/java/com/rometools/modules/slash/SlashImpl.java new file mode 100644 index 0000000..de6248f --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/slash/SlashImpl.java @@ -0,0 +1,145 @@ +/* + * SlashImpl.java + * + * Created on November 19, 2005, 8:53 PM + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.slash; + +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.impl.EqualsBean; + +/** + * @version $Revision: 1.2 $ + * @author Robert "kebernet" Cooper + */ +public class SlashImpl implements Slash { + + private static final long serialVersionUID = 1L; + + private String section; + private String department; + private Integer comments; + private Integer[] hitParade; + + @Override + public String getSection() { + return section; + } + + @Override + public void setSection(final String section) { + this.section = section; + } + + @Override + public String getDepartment() { + return department; + } + + @Override + public void setDepartment(final String department) { + this.department = department; + } + + @Override + public Integer getComments() { + return comments; + } + + @Override + public void setComments(final Integer comments) { + this.comments = comments; + } + + @Override + public Integer[] getHitParade() { + return hitParade == null ? new Integer[0] : hitParade; + } + + @Override + public void setHitParade(final Integer[] hitParade) { + this.hitParade = hitParade; + } + + @Override + public void copyFrom(final CopyFrom object) { + final Slash source = (Slash) object; + setHitParade(arrayCopy(source.getHitParade())); + setComments(source.getComments()); + setDepartment(source.getDepartment()); + setSection(source.getSection()); + } + + @Override + public Object clone() { + final SlashImpl si = new SlashImpl(); + si.copyFrom(this); + return si; + } + + @Override + public String getUri() { + return Slash.URI; + } + + private Integer[] arrayCopy(final Integer[] source) { + if (source == null) { + return null; + } + + final Integer[] array = new Integer[source.length]; + for (int i = 0; i < source.length; i++) { + array[i] = source[i]; + } + + return array; + } + + @Override + public Class getInterface() { + return Slash.class; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(this.getClass(), this); + return eBean.beanEquals(obj); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/slash/io/SlashModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/slash/io/SlashModuleGenerator.java new file mode 100644 index 0000000..ce94b98 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/slash/io/SlashModuleGenerator.java @@ -0,0 +1,114 @@ +/* + * SlashModuleGenerator.java + * + * Created on November 19, 2005, 9:07 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.slash.io; + +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.slash.Slash; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * The ModuleGenerator implementation for the Slash plug in. + * + * @version $Revision: 1.1 $ + * @author Robert "kebernet" Cooper + */ +public class SlashModuleGenerator implements ModuleGenerator { + + private static final Namespace NAMESPACE = Namespace.getNamespace("slash", Slash.URI); + + /** Creates a new instance of SlashModuleGenerator */ + public SlashModuleGenerator() { + } + + @Override + public void generate(final Module module, final Element element) { + if (!(module instanceof Slash)) { + return; + } + final Slash slash = (Slash) module; + if (slash.getComments() != null) { + element.addContent(generateSimpleElement("comments", slash.getComments().toString())); + } + if (slash.getDepartment() != null) { + element.addContent(generateSimpleElement("department", slash.getDepartment())); + } + if (slash.getSection() != null) { + element.addContent(generateSimpleElement("section", slash.getSection())); + } + if (slash.getHitParade() != null && slash.getHitParade().length > 0) { + final StringBuffer buff = new StringBuffer(); + final Integer[] p = slash.getHitParade(); + for (int i = 0; i < p.length; i++) { + if (i != 0) { + buff.append(","); + } + buff.append(p[i]); + } + element.addContent(generateSimpleElement("hit_parade", buff.toString())); + } + + } + + protected Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, SlashModuleGenerator.NAMESPACE); + element.addContent(value); + return element; + } + + @Override + public Set getNamespaces() { + final HashSet set = new HashSet(); + set.add(SlashModuleGenerator.NAMESPACE); + return set; + } + + @Override + public String getNamespaceUri() { + return Slash.URI; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/slash/io/SlashModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/slash/io/SlashModuleParser.java new file mode 100644 index 0000000..8ca6d28 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/slash/io/SlashModuleParser.java @@ -0,0 +1,107 @@ +/* + * SlashModuleParser.java + * + * Created on November 19, 2005, 9:19 PM + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2005 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.slash.io; + +import java.util.Locale; +import java.util.StringTokenizer; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.slash.Slash; +import com.rometools.modules.slash.SlashImpl; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; + +/** + * ModuleParser implementation for Slash RSS. + * + * @version $Revision: 1.3 $ + * @author Robert "kebernet" Cooper + */ +public class SlashModuleParser implements ModuleParser { + + private static final Namespace NS = Namespace.getNamespace(Slash.URI); + + /** Creates a new instance of SlashModuleParser */ + public SlashModuleParser() { + super(); + } + + @Override + public String getNamespaceUri() { + return Slash.URI; + } + + @Override + public Module parse(final Element element, final Locale locale) { + final SlashImpl si = new SlashImpl(); + Element tag = element.getChild("hit_parade", SlashModuleParser.NS); + if (tag != null) { + final StringTokenizer tok = new StringTokenizer(tag.getText(), ","); + final Integer[] hp = new Integer[tok.countTokens()]; + for (int i = 0; tok.hasMoreTokens(); i++) { + hp[i] = new Integer(tok.nextToken()); + } + si.setHitParade(hp); + } + tag = null; + tag = element.getChild("comments", SlashModuleParser.NS); + if (tag != null) { + si.setComments(new Integer(tag.getText())); + } + tag = null; + tag = element.getChild("department", SlashModuleParser.NS); + if (tag != null) { + si.setDepartment(tag.getText().trim()); + } + tag = null; + tag = element.getChild("section", SlashModuleParser.NS); + if (tag != null) { + si.setSection(tag.getText().trim()); + } + if (si.getHitParade() != null || si.getComments() != null || si.getDepartment() != null || si.getSection() != null) { + return si; + } + return null; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/slash/io/package.html b/rome-modules/src/main/java/com/rometools/modules/slash/io/package.html new file mode 100644 index 0000000..4790779 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/slash/io/package.html @@ -0,0 +1,45 @@ + + + + + + + + This package contains the parser and generator for ROME. +
      + * This library is provided under dual licenses.
      + * You may choose the terms of the Lesser General Public License or the Apache
      + * License at your discretion.
      + *
      + *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
      + *
      + *
      + * This library is free software; you can redistribute it and/or
      + * modify it under the terms of the GNU Lesser General Public
      + * License as published by the Free Software Foundation; either
      + * version 2.1 of the License, or (at your option) any later version.
      + *
      + * This library is distributed in the hope that it will be useful,
      + * but WITHOUT ANY WARRANTY; without even the implied warranty of
      + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      + * Lesser General Public License for more details.
      + *
      + * You should have received a copy of the GNU Lesser General Public
      + * License along with this library; if not, write to the Free Software
      + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      + *
      + *
      + * 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/rome-modules/src/main/java/com/rometools/modules/slash/package.html b/rome-modules/src/main/java/com/rometools/modules/slash/package.html new file mode 100644 index 0000000..3ab4aad --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/slash/package.html @@ -0,0 +1,68 @@ + + + + + + + + This package contains the core classes for the Slash plug in for ROME. + +

      This package contains the core module interface Slash, + as well as the implementation class SlashImpl.

      +

      Sample Useage: +

      +        
      +        SyndEntry entry = new SyndEntryImpl();
      +        // set up the entry...
      +        Slash slash = new SlashImpl();
      +        slash.setComments( new Integer( 12 ) );
      +        slash.setDepartment( "look-another-rome-plugin" );
      +        slash.setSection("code");
      +        slash.setHitParade( new Integer[] { new Integer(12), new Integer(0) } );
      +        List modules = new ArrayList();
      +        modules.add( slash );
      +        entry.setModules( modules );
      +        
      +        //Optionally, to get Slash information from a Feed:
      +        Slash slash = entry.getModule( "http://purl.org/rss/1.0/modules/slash/" );
      +        System.out.println( slash.getComments() );        
      +        
      +    
      +

      +
      +* This library is provided under dual licenses.
      + * You may choose the terms of the Lesser General Public License or the Apache
      + * License at your discretion.
      + *
      + *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
      + *
      + *
      + * This library is free software; you can redistribute it and/or
      + * modify it under the terms of the GNU Lesser General Public
      + * License as published by the Free Software Foundation; either
      + * version 2.1 of the License, or (at your option) any later version.
      + *
      + * This library is distributed in the hope that it will be useful,
      + * but WITHOUT ANY WARRANTY; without even the implied warranty of
      + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      + * Lesser General Public License for more details.
      + *
      + * You should have received a copy of the GNU Lesser General Public
      + * License along with this library; if not, write to the Free Software
      + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      + *
      + *
      + * 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/rome-modules/src/main/java/com/rometools/modules/sle/GroupStrategy.java b/rome-modules/src/main/java/com/rometools/modules/sle/GroupStrategy.java new file mode 100644 index 0000000..fdeb50d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/GroupStrategy.java @@ -0,0 +1,36 @@ +/* + * 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.rometools.modules.sle; + +import com.rometools.modules.sle.io.ModuleParser; +import com.rometools.modules.sle.types.EntryValue; +import com.rometools.modules.sle.types.Group; +import com.rometools.rome.feed.module.Extendable; + +class GroupStrategy implements ValueStrategy { + + @Override + public EntryValue getValue(final Extendable extendable, final Object value) { + try { + final String uri = ModuleParser.TEMP.getURI(); + final SleEntry entry = (SleEntry) extendable.getModule(uri); + final Group group = (Group) value; + return entry.getGroupByElement(group); + } catch (final NullPointerException npe) { + return null; + } + } + +} \ No newline at end of file diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/SimpleListExtension.java b/rome-modules/src/main/java/com/rometools/modules/sle/SimpleListExtension.java new file mode 100644 index 0000000..1ffbaba --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/SimpleListExtension.java @@ -0,0 +1,89 @@ +/* + * SimpleListExtension.java + * + * Created on April 27, 2006, 6:45 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle; + +import com.rometools.modules.sle.types.Group; +import com.rometools.modules.sle.types.Sort; +import com.rometools.rome.feed.module.Module; + +/** + * This is the primary module interface for the MS + * Simple List Extensions. + * + * @author Robert "kebernet" Cooper + */ +public interface SimpleListExtension extends Module { + /** + * "http://www.microsoft.com/schemas/rss/core/2005" + */ + public static final String URI = "http://www.microsoft.com/schemas/rss/core/2005"; + + /** + * The cf:group element is intended to inform the client that the property to which it refers is + * one that is “groupable” – that is, that the client should provide a user interface that + * allows the user to group or filter on the values of that property. Groupable properties + * should contain a small set of discrete values (e.g. book genres are perfect for groups). + * + * @param groupFields Array of types.Group objects. + */ + public void setGroupFields(Group[] groupFields); + + /** + * The cf:group element is intended to inform the client that the property to which it refers is + * one that is “groupable” – that is, that the client should provide a user interface that + * allows the user to group or filter on the values of that property. Groupable properties + * should contain a small set of discrete values (e.g. book genres are perfect for groups). + * + * @return Array of types.Group objects. + */ + public Group[] getGroupFields(); + + /** + * The cf:sort element is intended to inform the client that the property to which it refers is + * one that is “sortable” – that is, that the client should provide a user interface that allows + * the user to sort on that property. + * + * @param sortFields Array of types.Sort objects + */ + public void setSortFields(Sort[] sortFields); + + /** + * The cf:sort element is intended to inform the client that the property to which it refers is + * one that is “sortable” – that is, that the client should provide a user interface that allows + * the user to sort on that property. + * + * @return Array of types.Sort objects + */ + public Sort[] getSortFields(); + + /** + * This XML element allows the publisher of a feed document to indicate to the consumers of the + * feed that the feed is intended to be consumed as a list. (defaults to "list" ) + * + * @param value treatAs value + */ + public void setTreatAs(String value); + + /** + * This XML element allows the publisher of a feed document to indicate to the consumers of the + * feed that the feed is intended to be consumed as a list. + * + * @return treatAs value. + */ + public String getTreatAs(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/SimpleListExtensionImpl.java b/rome-modules/src/main/java/com/rometools/modules/sle/SimpleListExtensionImpl.java new file mode 100644 index 0000000..e896a97 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/SimpleListExtensionImpl.java @@ -0,0 +1,116 @@ +/* + * SimpleListExtensionImpl.java + * + * Created on April 27, 2006, 10:41 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle; + +import com.rometools.modules.sle.types.Group; +import com.rometools.modules.sle.types.Sort; +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.module.ModuleImpl; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class SimpleListExtensionImpl extends ModuleImpl implements SimpleListExtension { + + private static final long serialVersionUID = 1L; + + private String treatAs = "list"; + private Group[] groupFields; + private Sort[] sortFields; + + /** Creates a new instance of SimpleListExtensionImpl */ + public SimpleListExtensionImpl() { + super(SimpleListExtensionImpl.class, SimpleListExtension.URI); + } + + @Override + public void setGroupFields(final Group[] groupFields) { + this.groupFields = groupFields; + } + + @Override + public Group[] getGroupFields() { + return groupFields; + } + + /** + * Returns the interface the copyFrom works on. + *

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

      + * + * @return the interface the copyFrom works on. + */ + @Override + public Class getInterface() { + return SimpleListExtension.class; + } + + @Override + public void setSortFields(final Sort[] sortFields) { + this.sortFields = sortFields; + } + + @Override + public Sort[] getSortFields() { + return sortFields; + } + + @Override + public void setTreatAs(final String treatAs) { + this.treatAs = treatAs; + } + + @Override + public String getTreatAs() { + return treatAs; + } + + /** + * Returns the URI of the module. + *

      + * + * @return URI of the module. + */ + @Override + public String getUri() { + return SimpleListExtension.URI; + } + + /** + * 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. + */ + @Override + public void copyFrom(final CopyFrom obj) { + final SimpleListExtension sle = (SimpleListExtension) obj; + setGroupFields(sle.getGroupFields().clone()); + setSortFields(sle.getSortFields().clone()); + setTreatAs(sle.getTreatAs()); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/SleEntry.java b/rome-modules/src/main/java/com/rometools/modules/sle/SleEntry.java new file mode 100644 index 0000000..2527303 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/SleEntry.java @@ -0,0 +1,73 @@ +/* + * EntrySle.java + * + * Created on April 27, 2006, 7:13 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle; + +import com.rometools.modules.sle.io.ModuleParser; +import com.rometools.modules.sle.types.EntryValue; +import com.rometools.modules.sle.types.Group; +import com.rometools.modules.sle.types.Sort; +import com.rometools.rome.feed.module.Module; + +/** + * This is a parse only module that holds the values of enternal fields declared in the SLE + * module. These will not be persisted on an output() call, nor will changing a value + * here change a value in another module or a foreign markup tag. + * + * @author Robert "kebernet" Cooper + */ +public interface SleEntry extends Module { + /** + * A bogus namespace used for temporarily storing values during parsing. + */ + public static final String URI = ModuleParser.TEMP.getURI(); + + /** + * Returns an EntryValue for the given element name. + * + * @param element element name to look for + * @return Returns an EntryValue for the given element name. + */ + public EntryValue getGroupByElement(Group element); + + /** + * An array of EntryValue objects that correspond to the grouping for the feed. + * + * @return An array of EntryValue objects that correspond to the grouping for the feed. + */ + public EntryValue[] getGroupValues(); + + /** + * Returns an EntryValue for the given element name. + * + * @param element element name + * @return Returns an EntryValue for the given element name. + */ + public EntryValue getSortByElement(Sort element); + + /** + * Returns an array of EntryValues for the fields declared in the heading. + * + * NB:
      + * Right now the parser will take any default=true field and change it to an integer value + * representing the default order in the field. You should not rely on these values data display + * to a user! + * + * @return Array of EntryValue implementations from this entry. + */ + public EntryValue[] getSortValues(); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/SleEntryImpl.java b/rome-modules/src/main/java/com/rometools/modules/sle/SleEntryImpl.java new file mode 100644 index 0000000..247277f --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/SleEntryImpl.java @@ -0,0 +1,164 @@ +/* + * SleEntryImpl.java + * + * Created on April 29, 2006, 5:05 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.sle.io.LabelNamespaceElement; +import com.rometools.modules.sle.io.ModuleParser; +import com.rometools.modules.sle.types.EntryValue; +import com.rometools.modules.sle.types.Group; +import com.rometools.modules.sle.types.Sort; +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.impl.ObjectBean; + +/** + * This is a parse only module that holds the values of enternal fields declared in the SLE + * module. These will not be persisted on an output() call, nor will changing a value + * here change a value in another module or a foreign markup tag. + * + * @author Robert "kebernet" Cooper + */ +public class SleEntryImpl implements SleEntry { + + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(SleEntryImpl.class); + + private static final EntryValue[] EMPTY_VALUES = new EntryValue[0]; + private final ObjectBean obj = new ObjectBean(SleEntryImpl.class, this); + private EntryValue[] groupValues = EMPTY_VALUES; + private EntryValue[] sortValues = EMPTY_VALUES; + + /** Creates a new instance of SleEntryImpl */ + public SleEntryImpl() { + super(); + } + + @Override + public EntryValue getGroupByElement(final Group element) { + final EntryValue[] values = getGroupValues(); + final LabelNamespaceElement compare = new LabelNamespaceElement(element.getLabel(), element.getNamespace(), element.getElement()); + for (final EntryValue value : values) { + if (compare.equals(new LabelNamespaceElement(value.getLabel(), value.getNamespace(), value.getElement()))) { + return value; + } + } + + return null; + } + + public void setGroupValues(final EntryValue[] groupValues) { + this.groupValues = groupValues == null ? EMPTY_VALUES : groupValues; + } + + @Override + public EntryValue[] getGroupValues() { + return groupValues; + } + + /** + * Returns the interface the copyFrom works on. + *

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

      + * + * @return the interface the copyFrom works on. + */ + @Override + public Class getInterface() { + return SleEntry.class; + } + + @Override + public EntryValue getSortByElement(final Sort element) { + LOG.debug("Looking for value for {} from {}", element.getLabel(), sortValues.length); + final EntryValue[] values = getSortValues(); + final LabelNamespaceElement compare = new LabelNamespaceElement(element.getLabel(), element.getNamespace(), element.getElement()); + for (final EntryValue value : values) { + LOG.debug("Compare to value {}", value.getLabel()); + if (compare.equals(new LabelNamespaceElement(value.getLabel(), value.getNamespace(), value.getElement()))) { + LOG.debug("Match."); + return value; + } + } + + return null; + } + + public void setSortValues(final EntryValue[] sortValues) { + this.sortValues = sortValues; + } + + @Override + public EntryValue[] getSortValues() { + return sortValues; + } + + /** + * Returns the URI of the module. + *

      + * + * @return URI of the module. + */ + @Override + public String getUri() { + return ModuleParser.TEMP.getURI(); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return obj.clone(); + } + + /** + * 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. + */ + @Override + public void copyFrom(final CopyFrom obj) { + final SleEntry entry = (SleEntry) obj; + setGroupValues(entry.getGroupValues().clone()); + setSortValues(entry.getSortValues().clone()); + } + + @Override + public boolean equals(final Object o) { + return obj.equals(o); + } + + @Override + public int hashCode() { + return obj.hashCode(); + } + + @Override + public String toString() { + return obj.toString(); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/SleUtility.java b/rome-modules/src/main/java/com/rometools/modules/sle/SleUtility.java new file mode 100644 index 0000000..d1fa52e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/SleUtility.java @@ -0,0 +1,123 @@ +/* + * GroupAndSort.java + * + * Created on April 29, 2006, 5:56 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle; + +import java.util.List; + +import org.jdom2.Document; + +import com.rometools.modules.sle.types.Group; +import com.rometools.modules.sle.types.Sort; +import com.rometools.rome.feed.module.Extendable; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; + +/** + * This is a utiltiy class for grouping and sorting lists of entries based on the SLE. + * + *

      + * Note, this class can ONLY be used on parsed feeds, unless you manually add the appropriate + * SleEntry objects on the items. + *

      + * + * @author Robert "kebernet" Cooper + * @see SleEntry + */ +public final class SleUtility { + + // private static final String ITEM_MODULE_GENERATORS_POSFIX_KEY = + // ".item.ModuleGenerator.classes"; + + /** Private constructor for utility class */ + private SleUtility() { + } + + /** + * Groups values by the groups from the SLE. + * + * @param values List of Extendable implementations to group. + * @param groups Group fields (from the SimpleListExtension module) + * @return Grouped list of entries. + */ + public static List group(final List values, final Group[] groups) { + final SortableList list = getSortableList(values); + final GroupStrategy strategy = new GroupStrategy(); + for (int i = groups.length - 1; i >= 0; i--) { + list.sortOnProperty(groups[i], true, strategy); + } + return list; + } + + /** + * Sorts a list of values based on a given sort field using a selection sort. + * + * @param values List of values (implements Extendable) to sort. + * @param sort The sort field to sort on. + * @param ascending Sort ascending/descending. + * @return Sorted list of values + */ + public static List sort(final List values, final Sort sort, final boolean ascending) { + final SortableList list = getSortableList(values); + list.sortOnProperty(sort, ascending, new SortStrategy()); + return list; + } + + /** + * Sorts and groups a set of entries. + * + * @param values List of Extendable implementations. + * @param groups Group items to group by. + * @param sort Field to sort on. + * @param ascending Sort ascending/descending + * @return Grouped and sorted list of entries. + */ + public static List sortAndGroup(final List values, final Group[] groups, final Sort sort, final boolean ascending) { + List list = sort(values, sort, ascending); + list = group(list, groups); + return list; + } + + /** + * This method will take a SyndFeed object with a SimpleListExtension on it and populate the + * entries with current SleEntry values for sorting and grouping. NB: This basically does + * this by re-generating the XML for all the entries then re-parsing them into the SLE data + * structures. It is a very heavy operation and should not be called frequently! + */ + public static void initializeForSorting(final SyndFeed feed) throws FeedException { + // TODO: the null parameter below will break delegating parsers and generators + // final ModuleGenerators g = new ModuleGenerators(feed.getFeedType() + + // ITEM_MODULE_GENERATORS_POSFIX_KEY, null); + final SyndFeedOutput output = new SyndFeedOutput(); + final Document document = output.outputJDom(feed); + final SyndFeed copy = new SyndFeedInput().build(document); + feed.copyFrom(copy); + } + + private static SortableList getSortableList(final List list) { + SortableList sortableList; + if (list instanceof SortableList) { + sortableList = (SortableList) list; + } else { + sortableList = new SortableList(list); + } + return sortableList; + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/SortStrategy.java b/rome-modules/src/main/java/com/rometools/modules/sle/SortStrategy.java new file mode 100644 index 0000000..98d2f35 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/SortStrategy.java @@ -0,0 +1,36 @@ +/* + * 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.rometools.modules.sle; + +import com.rometools.modules.sle.io.ModuleParser; +import com.rometools.modules.sle.types.EntryValue; +import com.rometools.modules.sle.types.Sort; +import com.rometools.rome.feed.module.Extendable; + +class SortStrategy implements ValueStrategy { + + @Override + public EntryValue getValue(final Extendable extendable, final Object value) { + try { + final String uri = ModuleParser.TEMP.getURI(); + final SleEntry entry = (SleEntry) extendable.getModule(uri); + final Sort sort = (Sort) value; + return entry.getSortByElement(sort); + } catch (final NullPointerException npe) { + return null; + } + } + +} \ No newline at end of file diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/SortableList.java b/rome-modules/src/main/java/com/rometools/modules/sle/SortableList.java new file mode 100644 index 0000000..4a12101 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/SortableList.java @@ -0,0 +1,70 @@ +/* + * 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.rometools.modules.sle; + +import java.util.ArrayList; +import java.util.Collection; + +import com.rometools.modules.sle.types.EntryValue; +import com.rometools.rome.feed.module.Extendable; + +class SortableList extends ArrayList { + + private static final long serialVersionUID = 1L; + + public SortableList(final Collection c) { + super(c); + } + + /** + * performs a selection sort on all the beans in the List + */ + public synchronized void sortOnProperty(final Object value, final boolean ascending, final ValueStrategy strategy) { + + final int elementCount = size(); + + for (int i = 0; i < elementCount - 1; i++) { + + for (int j = i + 1; j < elementCount; j++) { + + final T entry1 = get(i); + final T entry2 = get(j); + + final EntryValue oc1 = strategy.getValue(entry1, value); + final EntryValue oc2 = strategy.getValue(entry2, value); + + if (oc1 != oc2) { + final boolean bothNotNull = oc1 != null && oc2 != null; + if (ascending) { + if (oc2 == null || bothNotNull && oc2.compareTo(oc1) < 0) { + // swap entries + set(i, entry2); + set(j, entry1); + } + } else { + if (oc1 == null || bothNotNull && oc1.compareTo(oc2) < 0) { + // swap entries + set(i, entry2); + set(j, entry1); + } + } + } + } + + } + + } + +} \ No newline at end of file diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/ValueStrategy.java b/rome-modules/src/main/java/com/rometools/modules/sle/ValueStrategy.java new file mode 100644 index 0000000..a7c84d0 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/ValueStrategy.java @@ -0,0 +1,24 @@ +/* + * 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.rometools.modules.sle; + +import com.rometools.modules.sle.types.EntryValue; +import com.rometools.rome.feed.module.Extendable; + +interface ValueStrategy { + + public EntryValue getValue(Extendable extendable, Object value); + +} \ No newline at end of file diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/io/ItemParser.java b/rome-modules/src/main/java/com/rometools/modules/sle/io/ItemParser.java new file mode 100644 index 0000000..c083c9b --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/io/ItemParser.java @@ -0,0 +1,157 @@ +/* + * ItemParser.java + * + * Created on April 29, 2006, 4:27 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle.io; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.sle.SleEntryImpl; +import com.rometools.modules.sle.types.DateValue; +import com.rometools.modules.sle.types.EntryValue; +import com.rometools.modules.sle.types.NumberValue; +import com.rometools.modules.sle.types.Sort; +import com.rometools.modules.sle.types.StringValue; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.impl.DateParser; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class ItemParser implements com.rometools.rome.io.ModuleParser { + /** Creates a new instance of ItemParser */ + public ItemParser() { + super(); + } + + /** + * Returns the namespace URI this parser handles. + *

      + * + * @return the namespace URI. + */ + @Override + public String getNamespaceUri() { + return ModuleParser.TEMP.getURI(); + } + + /** + * 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. + */ + @Override + public Module parse(final Element element, final Locale locale) { + final SleEntryImpl sle = new SleEntryImpl(); + ArrayList values = new ArrayList(); + final List groups = element.getChildren("group", ModuleParser.TEMP); + + for (final Element group : groups) { + final StringValue value = new StringValue(); + value.setElement(group.getAttributeValue("element")); + value.setLabel(group.getAttributeValue("label")); + value.setValue(group.getAttributeValue("value")); + if (group.getAttributeValue("ns") != null) { + value.setNamespace(Namespace.getNamespace(group.getAttributeValue("ns"))); + } else { + value.setNamespace(element.getDocument().getRootElement().getNamespace()); + } + values.add(value); + element.removeContent(group); + } + + sle.setGroupValues(values.toArray(new EntryValue[values.size()])); + values = values.size() == 0 ? values : new ArrayList(); + + final List sorts = new ArrayList(element.getChildren("sort", ModuleParser.TEMP)); + // LOG.debug("]]] sorts on element"+sorts.size()); + for (final Element sort : sorts) { + final String dataType = sort.getAttributeValue("data-type"); + // LOG.debug("Doing datatype "+dataType +" :: "+sorts.size()); + if (dataType == null || dataType.equals(Sort.TEXT_TYPE)) { + final StringValue value = new StringValue(); + value.setElement(sort.getAttributeValue("element")); + value.setLabel(sort.getAttributeValue("label")); + value.setValue(sort.getAttributeValue("value")); + if (sort.getAttributeValue("ns") != null) { + value.setNamespace(Namespace.getNamespace(sort.getAttributeValue("ns"))); + } else { + value.setNamespace(element.getDocument().getRootElement().getNamespace()); + } + values.add(value); + + element.removeContent(sort); + + } else if (dataType.equals(Sort.DATE_TYPE)) { + final DateValue value = new DateValue(); + value.setElement(sort.getAttributeValue("element")); + value.setLabel(sort.getAttributeValue("label")); + if (sort.getAttributeValue("ns") != null) { + value.setNamespace(Namespace.getNamespace(sort.getAttributeValue("ns"))); + } else { + value.setNamespace(element.getDocument().getRootElement().getNamespace()); + } + Date dateValue = null; + + try { + dateValue = DateParser.parseRFC822(sort.getAttributeValue("value"), locale); + if (dateValue == null) { + dateValue = DateParser.parseW3CDateTime(sort.getAttributeValue("value"), locale); + } + } catch (final Exception e) { + ; // ignore parse exceptions + } + + value.setValue(dateValue); + values.add(value); + element.removeContent(sort); + } else if (dataType.equals(Sort.NUMBER_TYPE)) { + final NumberValue value = new NumberValue(); + value.setElement(sort.getAttributeValue("element")); + value.setLabel(sort.getAttributeValue("label")); + if (sort.getAttributeValue("ns") != null) { + value.setNamespace(Namespace.getNamespace(sort.getAttributeValue("ns"))); + } else { + value.setNamespace(element.getDocument().getRootElement().getNamespace()); + } + + try { + value.setValue(new BigDecimal(sort.getAttributeValue("value"))); + } catch (final NumberFormatException nfe) { + ; // ignore + values.add(value); + element.removeContent(sort); + } + } else { + throw new RuntimeException("Unknown datatype"); + } + } + // LOG.debug("Values created "+values.size()+" from sorts" +sorts.size()); + sle.setSortValues(values.toArray(new EntryValue[values.size()])); + + return sle; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/io/LabelNamespaceElement.java b/rome-modules/src/main/java/com/rometools/modules/sle/io/LabelNamespaceElement.java new file mode 100644 index 0000000..41863e9 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/io/LabelNamespaceElement.java @@ -0,0 +1,93 @@ +/* + * 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.rometools.modules.sle.io; + +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LabelNamespaceElement { + + private static final Logger LOG = LoggerFactory.getLogger(LabelNamespaceElement.class); + + private String element; + private String label; + private Namespace namespace; + + public LabelNamespaceElement(final String label, final Namespace namespace, final String element) { + this.element = element; + this.label = label; + this.namespace = namespace; + } + + public String getElement() { + return element; + } + + public void setElement(final String element) { + this.element = element; + } + + public String getLabel() { + return label; + } + + public void setLabel(final String label) { + this.label = label; + } + + public Namespace getNamespace() { + return namespace; + } + + public void setNamespace(final Namespace namespace) { + this.namespace = namespace; + } + + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final LabelNamespaceElement other = (LabelNamespaceElement) obj; + if (element == null ? other.element != null : !element.equals(other.element)) { + LOG.debug("E {} != {}", element, other.element); + return false; + } + if (label == null ? other.label != null : !label.equals(other.label)) { + LOG.debug("L"); + return false; + } + if (namespace != other.namespace && (namespace == null || !namespace.equals(other.namespace))) { + LOG.debug("N"); + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 61 * hash + (element != null ? element.hashCode() : 0); + hash = 61 * hash + (label != null ? label.hashCode() : 0); + hash = 61 * hash + (namespace != null ? namespace.hashCode() : 0); + return hash; + } + +} \ No newline at end of file diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/io/ModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/sle/io/ModuleGenerator.java new file mode 100644 index 0000000..914ae20 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/io/ModuleGenerator.java @@ -0,0 +1,152 @@ +/* + * 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.rometools.modules.sle.io; + +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.sle.SimpleListExtension; +import com.rometools.modules.sle.types.Group; +import com.rometools.modules.sle.types.Sort; +import com.rometools.rome.feed.module.Module; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class ModuleGenerator implements com.rometools.rome.io.ModuleGenerator { + + private static final Set NAMESPACES = new HashSet(); + + static { + NAMESPACES.add(ModuleParser.NS); + } + + /** Creates a new instance of ModuleGenerator */ + public ModuleGenerator() { + super(); + } + + /** + * Returns the namespace URI this generator handles. + *

      + * + * @return the namespace URI. + */ + @Override + public String getNamespaceUri() { + return SimpleListExtension.URI; + } + + /** + * Returns a set with all the URIs (JDOM Namespace elements) this module generator uses. + *

      + * It is used by the the feed generators to add their namespace definition in the root element + * of the generated document (forward-missing of Java 5.0 Generics). + *

      + * + * @return a set with all the URIs (JDOM Namespace elements) this module generator uses. + */ + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + /** + * Generates and injectts module metadata in a XML node (JDOM element). + *

      + * + * @param module the module to inject into the XML node (JDOM element). + * @param element the XML node to inject the module metadata to. + */ + @Override + public void generate(final Module module, final Element element) { + if (!(module instanceof SimpleListExtension)) { + return; + } + + final SimpleListExtension sle = (SimpleListExtension) module; + addNotNullElement(element, "treatAs", sle.getTreatAs()); + + final Group[] groups = sle.getGroupFields(); + final Element listInfo = new Element("listinfo", ModuleParser.NS); + + for (int i = 0; groups != null && i < groups.length; i++) { + final Element group = new Element("group", ModuleParser.NS); + + if (groups[i].getNamespace() != Namespace.NO_NAMESPACE) { + addNotNullAttribute(group, "ns", groups[i].getNamespace().getURI()); + } + + addNotNullAttribute(group, "element", groups[i].getElement()); + addNotNullAttribute(group, "label", groups[i].getLabel()); + listInfo.addContent(group); + } + + final Sort[] sorts = sle.getSortFields(); + + for (int i = 0; sorts != null && i < sorts.length; i++) { + final Element sort = new Element("sort", ModuleParser.NS); + + if (sorts[i].getNamespace() != Namespace.NO_NAMESPACE) { + addNotNullAttribute(sort, "ns", sorts[i].getNamespace().getURI()); + } + + addNotNullAttribute(sort, "element", sorts[i].getElement()); + addNotNullAttribute(sort, "label", sorts[i].getLabel()); + addNotNullAttribute(sort, "data-type", sorts[i].getDataType()); + + if (sorts[i].getDefaultOrder()) { + addNotNullAttribute(sort, "default", "true"); + } + + listInfo.addContent(sort); + } + + if (!listInfo.getChildren().isEmpty()) { + element.addContent(listInfo); + } + } + + protected void addNotNullAttribute(final Element target, final String name, final Object value) { + if (target == null || value == null) { + return; + } else { + target.setAttribute(name, value.toString()); + } + } + + protected Element addNotNullElement(final Element target, final String name, final Object value) { + if (value == null) { + return null; + } else { + final Element e = generateSimpleElement(name, value.toString()); + target.addContent(e); + + return e; + } + } + + protected Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, ModuleParser.NS); + element.addContent(value); + + return element; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/io/ModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/sle/io/ModuleParser.java new file mode 100644 index 0000000..79e807a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/io/ModuleParser.java @@ -0,0 +1,177 @@ +/* + * ModuleParser.java + * + * Created on April 27, 2006, 10:37 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle.io; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.sle.SimpleListExtension; +import com.rometools.modules.sle.SimpleListExtensionImpl; +import com.rometools.modules.sle.types.Group; +import com.rometools.modules.sle.types.Sort; +import com.rometools.rome.feed.module.Module; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class ModuleParser implements com.rometools.rome.io.ModuleParser { + + private static final Logger LOG = LoggerFactory.getLogger(ModuleParser.class); + + static final Namespace NS = Namespace.getNamespace("cf", SimpleListExtension.URI); + public static final Namespace TEMP = Namespace.getNamespace("rome-sle", "urn:rome:sle"); + + /** Creates a new instance of ModuleParser */ + public ModuleParser() { + super(); + } + + /** + * Returns the namespace URI this parser handles. + *

      + * + * @return the namespace URI. + */ + @Override + public String getNamespaceUri() { + return SimpleListExtension.URI; + } + + /** + * 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. + */ + @Override + public Module parse(final Element element, final Locale locale) { + if (element.getChild("treatAs", NS) == null) { + return null; + } + + final SimpleListExtension sle = new SimpleListExtensionImpl(); + sle.setTreatAs(element.getChildText("treatAs", NS)); + + final Element listInfo = element.getChild("listinfo", NS); + ArrayList values = new ArrayList(); + for (final Element ge : listInfo.getChildren("group", NS)) { + final Namespace ns = ge.getAttribute("ns") == null ? element.getNamespace() : Namespace.getNamespace(ge.getAttributeValue("ns")); + final String elementName = ge.getAttributeValue("element"); + final String label = ge.getAttributeValue("label"); + values.add(new Group(ns, elementName, label)); + } + + sle.setGroupFields(values.toArray(new Group[values.size()])); + values = values.size() == 0 ? values : new ArrayList(); + + for (final Element se : listInfo.getChildren("sort", NS)) { + LOG.debug("Parse cf:sort {}{}", se.getAttributeValue("element"), se.getAttributeValue("data-type")); + final Namespace ns = se.getAttributeValue("ns") == null ? element.getNamespace() : Namespace.getNamespace(se.getAttributeValue("ns")); + final String elementName = se.getAttributeValue("element"); + final String label = se.getAttributeValue("label"); + final String dataType = se.getAttributeValue("data-type"); + final boolean defaultOrder = se.getAttributeValue("default") == null ? false : new Boolean(se.getAttributeValue("default")).booleanValue(); + values.add(new Sort(ns, elementName, dataType, label, defaultOrder)); + } + + sle.setSortFields(values.toArray(new Sort[values.size()])); + insertValues(sle, element.getChildren()); + + return sle; + } + + protected void addNotNullAttribute(final Element target, final String name, final Object value) { + if (target == null || value == null) { + return; + } else { + target.setAttribute(name, value.toString()); + } + } + + public void insertValues(final SimpleListExtension sle, final List elements) { + for (int i = 0; elements != null && i < elements.size(); i++) { + final Element e = elements.get(i); + final Group[] groups = sle.getGroupFields(); + + for (final Group group2 : groups) { + final Element value = e.getChild(group2.getElement(), group2.getNamespace()); + + if (value == null) { + continue; + } + + final Element group = new Element("group", TEMP); + addNotNullAttribute(group, "element", group2.getElement()); + addNotNullAttribute(group, "label", group2.getLabel()); + addNotNullAttribute(group, "value", value.getText()); + addNotNullAttribute(group, "ns", group2.getNamespace().getURI()); + + e.addContent(group); + } + + final Sort[] sorts = sle.getSortFields(); + + for (final Sort sort2 : sorts) { + LOG.debug("Inserting for {} {}", sort2.getElement(), sort2.getDataType()); + final Element sort = new Element("sort", TEMP); + // this is the default sort order, so I am just going to ignore + // the actual values and add a number type. It really shouldn't + // work this way. I should be checking to see if any of the elements + // defined have a value then use that value. This will preserve the + // sort order, however, if anyone is using the SleEntry to display + // the value of the field, it will not give the correct value. + // This, however, would require knowledge in the item parser that I don't + // have right now. + if (sort2.getDefaultOrder()) { + sort.setAttribute("label", sort2.getLabel()); + sort.setAttribute("value", Integer.toString(i)); + sort.setAttribute("data-type", Sort.NUMBER_TYPE); + e.addContent(sort); + + continue; + } + // LOG.debug(e.getName()); + final Element value = e.getChild(sort2.getElement(), sort2.getNamespace()); + if (value == null) { + LOG.debug("No value for {} : {}", sort2.getElement(), sort2.getNamespace()); + } else { + LOG.debug("{} value: {}", sort2.getElement(), value.getText()); + } + if (value == null) { + continue; + } + + addNotNullAttribute(sort, "label", sort2.getLabel()); + addNotNullAttribute(sort, "element", sort2.getElement()); + addNotNullAttribute(sort, "value", value.getText()); + addNotNullAttribute(sort, "data-type", sort2.getDataType()); + addNotNullAttribute(sort, "ns", sort2.getNamespace().getURI()); + e.addContent(sort); + LOG.debug("Added {} {} = {}", sort, sort2.getLabel(), value.getText()); + } + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/io/package.html b/rome-modules/src/main/java/com/rometools/modules/sle/io/package.html new file mode 100644 index 0000000..02a9f12 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/io/package.html @@ -0,0 +1,10 @@ + + + + + + + + Contains the IO related classes for the SLE module. + + diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/package.html b/rome-modules/src/main/java/com/rometools/modules/sle/package.html new file mode 100644 index 0000000..d299c1f --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/package.html @@ -0,0 +1,53 @@ + + + + + + + + This is a module that supports the Microsoft Simple List Extensions. +

      + This is a feed-level module. However, for the purposes of sorting and goupding + it provides the SleEntry module, which is dynamically generated with values for + sorting and grouping. + + Sample Usage: +

      + SimpleListExtension sle = (SimpleListExtension) feed.getModule( SimpleListExtension.URI ); + System.out.println( sle ); + Group[] groups = sle.getGroupFields(); + System.out.println( groups[0].getLabel() ); + + //You can use the SleUtility class to do sorting and grouping: + + + List sortedEntries = SleUtility.sort( feed.getEntries(), sle.getSortFields()[1], true ); + SyndEntry entry = (SyndEntry) sortedEntries.get( 0 ); + + //You can also Group or Sort and Group + + List sortedAndGroupedEntries = SleUtility.sortAndGroup( feed.getEntries, sle.getGroupFields(), sle.getSortFields()[0], false ); + + // If you change, for instance, module values on a feed and want to reinitialize it for + // grouping and sorting... + + SleUtility.initializeForSorting( feed ); + + // Be aware, this is a VERY heavy operation and should not be used frequently. + + +
      + * 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/rome-modules/src/main/java/com/rometools/modules/sle/types/DateValue.java b/rome-modules/src/main/java/com/rometools/modules/sle/types/DateValue.java new file mode 100644 index 0000000..5430d7a --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/types/DateValue.java @@ -0,0 +1,113 @@ +/* + * DateValue.java + * + * Created on April 29, 2006, 5:29 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle.types; + +import java.util.Date; + +import org.jdom2.Namespace; + +import com.rometools.rome.feed.impl.ObjectBean; + +/** + * An EntryValue implementation representing a "date" data-type. + * + * @author Robert "kebernet" Cooper + */ +public class DateValue implements EntryValue { + + private static final long serialVersionUID = 1L; + + private final ObjectBean obj = new ObjectBean(DateValue.class, this); + + private String element; + private String label; + private Date value; + private Namespace namespace = Namespace.XML_NAMESPACE; + + public void setElement(final String element) { + this.element = element; + } + + @Override + public String getElement() { + return element; + } + + public void setLabel(final String label) { + this.label = label; + } + + @Override + public String getLabel() { + return label; + } + + public void setValue(final Date value) { + this.value = value; + } + + @Override + public Date getValue() { + return value; + } + + @Override + public Namespace getNamespace() { + return namespace; + } + + public void setNamespace(final Namespace namespace) { + this.namespace = namespace == null ? Namespace.XML_NAMESPACE : namespace; + } + + @Override + public Object clone() { + final DateValue clone = new DateValue(); + clone.setElement(getElement()); + clone.setLabel(getLabel()); + clone.setValue(value); + clone.setNamespace(namespace); + return clone; + } + + @Override + public boolean equals(final Object o) { + return obj.equals(o); + } + + @Override + public int hashCode() { + return obj.hashCode(); + } + + @Override + public String toString() { + return "[Namespace: " + namespace + " Element:" + element + " Label:" + label + " Value:" + value + "]"; + } + + @Override + public int compareTo(final EntryValue other) { + final Comparable otherValue = other.getValue(); + if (otherValue instanceof Date) { + return value.compareTo((Date) otherValue); + } else { + throw new RuntimeException("Can't compare different EntryValue types"); + } + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/types/EntryValue.java b/rome-modules/src/main/java/com/rometools/modules/sle/types/EntryValue.java new file mode 100644 index 0000000..767ab5f --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/types/EntryValue.java @@ -0,0 +1,58 @@ +/* + * EntryValue.java + * + * Created on April 29, 2006, 4:58 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle.types; + +import java.io.Serializable; + +import org.jdom2.Namespace; + +/** + * An interface that parents data types for sorting and grouping. + * + * @author Robert "kebernet" Cooper + */ +public interface EntryValue extends Serializable, Cloneable, Comparable { + /** + * Returns the name of the element. + * + * @return Returns the name of the element. + */ + public String getElement(); + + /** + * Returns a label for the element. + * + * @return Returns a label for the element. + */ + public String getLabel(); + + /** + * Returns the value of the element. + * + * @return Returns the value of the element. + */ + public Comparable getValue(); + + /** + * Returns the namespace of the element. + * + * @return Returns the namespace of the element. + */ + public Namespace getNamespace(); + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/types/Group.java b/rome-modules/src/main/java/com/rometools/modules/sle/types/Group.java new file mode 100644 index 0000000..fcbf7ec --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/types/Group.java @@ -0,0 +1,126 @@ +/* + * Group.java + * + * Created on April 27, 2006, 6:53 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle.types; + +import java.io.Serializable; + +import org.jdom2.Namespace; + +import com.rometools.rome.feed.impl.ObjectBean; + +/** + * The cf:group element is intended to inform the client that the property to + * which it + * + * refers is one that is “groupable” – that is, that the client should provide a user interface that + * + * allows the user to group or filter on the values of that property. Groupable properties + * should contain + * + * a small set of discrete values (e.g. book genres are perfect for groups).

      + * + *

      + * The cf:group element contains the following attributes: + *

      + * + *
        + *
      • ns - this attribute is the full namespace used in the property element. If the + * attribute value is an empty string, it is assumed that the property does not live in a + * namespace. If the ns attribute is omitted, the default value is the empty string. In the example + * above, the ns attribute would contain "http://www.example.com/book". It would not contain + * the namespace prefix.
      • + *
      • element - this attribute is the name of the property (without any namespace). In the + * example above, the element attribute would contain "firstedition" If this attribute is omitted, + * it is assumed that the label attribute is included and that this cf:group element + * refers to the default sort order.
      • + * + *
      • label - this attribute contains a human-readable name for the property to which this + * cf:group element refers. If it is omitted, the client should use the value of the + * "element" attribute as the human-readable name. The "label" attribute is required if the + * "element" attribute is omitted.  
      • + *
      + * + * @author Robert "kebernet" Cooper + */ +public class Group implements Serializable, Cloneable { + private static final long serialVersionUID = 1L; + private Namespace namespace = Namespace.XML_NAMESPACE; + private final ObjectBean obj = new ObjectBean(Group.class, this); + private final String element; + private final String label; + + /** + * Creates a new instance of Group + * + * @param namespace Namespace of the element + * @param element Name of the element + * @param label Label for the grouping. + */ + public Group(final Namespace namespace, final String element, final String label) { + this.namespace = namespace == null ? Namespace.XML_NAMESPACE : namespace; + this.element = element; + this.label = label; + } + + /** + * Returns the name of the element. + * + * @return Returns the name of the element. + */ + public String getElement() { + return element; + } + + /** + * Returns the label of the element. + * + * @return Returns the label of the element. + */ + public String getLabel() { + return label; + } + + /** + * Returns the namespace of the element. + * + * @return Returns the namespace of the element. + */ + public Namespace getNamespace() { + return namespace; + } + + @Override + public Object clone() { + return new Group(namespace, element, label); + } + + @Override + public boolean equals(final Object o) { + return obj.equals(o); + } + + @Override + public int hashCode() { + return obj.hashCode(); + } + + @Override + public String toString() { + return obj.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/types/NumberValue.java b/rome-modules/src/main/java/com/rometools/modules/sle/types/NumberValue.java new file mode 100644 index 0000000..2dce7c0 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/types/NumberValue.java @@ -0,0 +1,113 @@ +/* + * NumberValue.java + * + * Created on April 29, 2006, 5:00 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle.types; + +import java.math.BigDecimal; + +import org.jdom2.Namespace; + +import com.rometools.rome.feed.impl.ObjectBean; + +/** + * An EntryValue implementation for "number" data-type values. + * + * @author Robert "kebernet" Cooper + */ +public class NumberValue implements EntryValue { + + private static final long serialVersionUID = 1L; + + private final ObjectBean obj = new ObjectBean(NumberValue.class, this); + + private String element; + private String label; + private BigDecimal value; + private Namespace namespace = Namespace.XML_NAMESPACE; + + public void setElement(final String element) { + this.element = element; + } + + @Override + public String getElement() { + return element; + } + + public void setLabel(final String label) { + this.label = label; + } + + @Override + public String getLabel() { + return label; + } + + public void setValue(final BigDecimal value) { + this.value = value; + } + + @Override + public BigDecimal getValue() { + return value; + } + + @Override + public Namespace getNamespace() { + return namespace; + } + + public void setNamespace(final Namespace namespace) { + this.namespace = namespace == null ? Namespace.XML_NAMESPACE : namespace; + } + + @Override + public Object clone() { + final NumberValue clone = new NumberValue(); + clone.setElement(getElement()); + clone.setLabel(getLabel()); + clone.setValue(value); + clone.setNamespace(namespace); + return clone; + } + + @Override + public boolean equals(final Object o) { + return obj.equals(o); + } + + @Override + public int hashCode() { + return obj.hashCode(); + } + + @Override + public String toString() { + return "[Element:" + element + " Label:" + label + " Value:" + value + "]"; + } + + @Override + public int compareTo(final EntryValue other) { + final Comparable otherValue = other.getValue(); + if (otherValue instanceof BigDecimal) { + return value.compareTo((BigDecimal) otherValue); + } else { + throw new RuntimeException("Can't compare different EntryValue types"); + } + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/types/Sort.java b/rome-modules/src/main/java/com/rometools/modules/sle/types/Sort.java new file mode 100644 index 0000000..c8f1d53 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/types/Sort.java @@ -0,0 +1,180 @@ +/* + * Sort.java + * + * Created on April 27, 2006, 6:50 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle.types; + +import java.io.Serializable; + +import org.jdom2.Namespace; + +import com.rometools.rome.feed.impl.ObjectBean; + +/** + *

      + * The cf:sort element is intended to inform the client that the property to which it + * refers + * + * is one that is “sortable” – that is, that the client should provide a user interface that allows + * the + * + * user to sort on that property. + *

      + * + *

      + * The cf:sort element can also be used to provide a label for the default sort that + * appears + * + * in the list (in this case, only the label attribute should be included). + *

      + * + *

      + * The cf:sort element contains the following attributes: + *

      + * + *
        + *
      • ns - this attribute is the full namespace used in the property element. If the + * attribute value is an empty string, it is assumed that the property does not live in a + * namespace. If the ns attribute is omitted, the default value is the empty string. In the example + * above, the ns attribute would contain "http://www.example.com/book". It would not contain + * the namespace prefix.
      • + *
      • element - this attribute is the name of the property (without any namespace). In the + * example above, the element attribute would contain "firstedition" If this attribute is omitted, + * it is assumed that the label attribute is included and that this cf:sort element + * refers to the default sort order.
      • + * + *
      • label - this attribute contains a human-readable name for the property to which this + * cf:sort element refers. If it is omitted, the client should use the value of the + * "element" attribute as the human-readable name. The "label" attribute is required if the + * "element" attribute is omitted.
      • + *
      • data-type - this attribute informs the client about the data-type of the property to + * which this cf:sort element refers.. It contains one of the following values: date, + * number, text. If it is omitted, the default value is text.
      • + *
      • default - this attribute indicates whether the property to which this + * cf:sort element refers is the default sort order in the list. The allowed values are + * "true" and "false". If omitted, the default value is "false". The items in the list must + * be already be sorted by the element – this is, the client should not expect to have to resort by + * this field if it displaying content directly from the list. The client should respect only the + * first instance of default="true" that it encounters.
      • + * + *
      + * + * @author Robert "kebernet" Cooper + */ +public class Sort implements Serializable, Cloneable { + private static final long serialVersionUID = 1L; + /** + * dataType value for Date information. + */ + public static final String DATE_TYPE = "date"; + /** + * dataType value for Text information + */ + public static final String TEXT_TYPE = "text"; + /** + * DataType value for Number information. + */ + public static final String NUMBER_TYPE = "number"; + private Namespace namespace = Namespace.XML_NAMESPACE; + private final ObjectBean obj = new ObjectBean(Sort.class, this); + private final String dataType; + private final String element; + private final String label; + private final boolean defaultOrder; + + /** + * Creates a new instance of Sort + * + * @param namespace Namespace of the element + * @param element Name of the element + * @param dataType data-type of the element + * @param label Label for the sort + * @param defaultOrder indicates if this is the defaul order of the feed. + */ + public Sort(final Namespace namespace, final String element, final String dataType, final String label, final boolean defaultOrder) { + super(); + this.namespace = namespace == null ? Namespace.XML_NAMESPACE : namespace; + this.element = element; + this.dataType = dataType; + this.label = label; + this.defaultOrder = defaultOrder; + } + + /** + * Returns the dataType of the sort + * + * @return Returns the dataType of the sort + */ + public String getDataType() { + return dataType; + } + + /** + * Indicates this is the natural order of the feed. + * + * @return Indicates this is the natural order of the feed. + */ + public boolean getDefaultOrder() { + return defaultOrder; + } + + /** + * Name of the element. + * + * @return Name of the element. + */ + public String getElement() { + return element; + } + + /** + * User label for sorting. + * + * @return User label for sorting. + */ + public String getLabel() { + return label; + } + + /** + * Namespace of the element + * + * @return Namespace of the element + */ + public Namespace getNamespace() { + return namespace; + } + + @Override + public Object clone() { + return new Sort(namespace, element, dataType, label, defaultOrder); + } + + @Override + public boolean equals(final Object o) { + return obj.equals(o); + } + + @Override + public int hashCode() { + return obj.hashCode(); + } + + @Override + public String toString() { + return obj.toString(); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/types/StringValue.java b/rome-modules/src/main/java/com/rometools/modules/sle/types/StringValue.java new file mode 100644 index 0000000..744a144 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/types/StringValue.java @@ -0,0 +1,111 @@ +/* + * StringValue.java + * + * Created on April 29, 2006, 4:59 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.modules.sle.types; + +import org.jdom2.Namespace; + +import com.rometools.rome.feed.impl.ObjectBean; + +/** + * An EntryValue implementation for "text" data-types. + * + * @author Robert "kebernet" Cooper + */ +public class StringValue implements EntryValue { + + private static final long serialVersionUID = 1L; + + private final ObjectBean obj = new ObjectBean(StringValue.class, this); + + private String element; + private String label; + private String value; + private Namespace namespace = Namespace.XML_NAMESPACE; + + public void setValue(final String value) { + this.value = value; + } + + @Override + public String getElement() { + return element; + } + + public void setLabel(final String label) { + this.label = label; + } + + @Override + public String getLabel() { + return label; + } + + @Override + public String getValue() { + return value; + } + + public void setElement(final String element) { + this.element = element; + } + + @Override + public Namespace getNamespace() { + return namespace; + } + + public void setNamespace(final Namespace namespace) { + this.namespace = namespace == null ? Namespace.XML_NAMESPACE : namespace; + } + + @Override + public Object clone() { + final StringValue clone = new StringValue(); + clone.setElement(getElement()); + clone.setLabel(getLabel()); + clone.setValue(value); + clone.setNamespace(namespace); + return clone; + } + + @Override + public boolean equals(final Object o) { + return obj.equals(o); + } + + @Override + public int hashCode() { + return obj.hashCode(); + } + + @Override + public String toString() { + return "[Namespace: " + namespace + " Element:" + element + " Label:" + label + " Value:" + value + "]"; + } + + @Override + public int compareTo(final EntryValue other) { + final Comparable otherValue = other.getValue(); + if (otherValue instanceof String) { + return value.compareTo((String) otherValue); + } else { + throw new RuntimeException("Can't compare different EntryValue types"); + } + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sle/types/package.html b/rome-modules/src/main/java/com/rometools/modules/sle/types/package.html new file mode 100644 index 0000000..8ecdedf --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sle/types/package.html @@ -0,0 +1,11 @@ + + + + + + + + This package contains classes used with the SimpleListExtension module and the SLEEntry. + Pay closest attention to the Group and Sort classes if you want to generate feeds. + + diff --git a/rome-modules/src/main/java/com/rometools/modules/sse/SSE091Generator.java b/rome-modules/src/main/java/com/rometools/modules/sse/SSE091Generator.java new file mode 100644 index 0000000..56e7f4e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sse/SSE091Generator.java @@ -0,0 +1,200 @@ +/* + * 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.rometools.modules.sse; + +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.sse.modules.Conflict; +import com.rometools.modules.sse.modules.Conflicts; +import com.rometools.modules.sse.modules.History; +import com.rometools.modules.sse.modules.Related; +import com.rometools.modules.sse.modules.SSEModule; +import com.rometools.modules.sse.modules.Sharing; +import com.rometools.modules.sse.modules.Sync; +import com.rometools.modules.sse.modules.Update; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.feed.rss.Item; +import com.rometools.rome.io.DelegatingModuleGenerator; +import com.rometools.rome.io.WireFeedGenerator; +import com.rometools.rome.io.impl.DateParser; +import com.rometools.rome.io.impl.RSS20Generator; + +/** + * Generator for the SSE Module. + *

      + * + * @author Laird Dornin + */ +public class SSE091Generator implements DelegatingModuleGenerator { + private RSS20Generator parentGenerator; + + public SSE091Generator() { + } + + @Override + public void setFeedGenerator(final WireFeedGenerator feedGenerator) { + parentGenerator = (RSS20Generator) feedGenerator; + } + + @Override + public String getNamespaceUri() { + return SSEModule.SSE_SCHEMA_URI; + } + + /** + * Returns a set with all the URIs (JDOM Namespace elements) this module generator uses. + *

      + * It is used by the the feed generators to add their namespace definition in the root element + * of the generated document (forward-missing of Java 5.0 Generics). + *

      + * + * @return a set with all the URIs (JDOM Namespace elements) this module generator uses. + */ + @Override + public Set getNamespaces() { + return SSEModule.NAMESPACES; + } + + @Override + public void generate(final Module module, final Element element) { + if (!(module instanceof SSEModule)) { + return; + } + + final SSEModule sseModule = (SSEModule) module; + + if (sseModule instanceof Sharing) { + final Sharing sharing = (Sharing) sseModule; + // add sse namespace + Element root = element; + while (root.getParent() != null && root.getParent() instanceof Element) { + root = (Element) root.getParent(); + } + root.addNamespaceDeclaration(SSEModule.SSE_NS); + + generateSharing(sharing, root); + } else if (sseModule instanceof Sync) { + generateSync((Sync) sseModule, element); + } + } + + private void generateSharing(final Sharing sharing, final Element parent) { + // inject sse sharingModule element + final Element sharingElement = new Element(Sharing.NAME, SSEModule.SSE_NS); + generateAttribute(sharingElement, Sharing.UNTIL_ATTRIBUTE, sharing.getUntil()); + generateAttribute(sharingElement, Sharing.SINCE_ATTRIBUTE, sharing.getSince()); + generateAttribute(sharingElement, Sharing.ORDERED_ATTRIBUTE, sharing.getOrdered()); + generateAttribute(sharingElement, Sharing.WINDOW_ATTRIBUTE, sharing.getWindow()); + generateAttribute(sharingElement, Sharing.VERSION_ATTRIBUTE, sharing.getVersion()); + + // add sharing as the first element of the rss root + parent.addContent(0, sharingElement); + + final Related related = sharing.getRelated(); + if (related != null) { + generateRelated(related); + } + } + + private void generateRelated(final Related related) { + final Element relatedElement = new Element(Related.NAME, SSEModule.SSE_NS); + generateAttribute(relatedElement, Related.SINCE_ATTRIBUTE, related.getSince()); + generateAttribute(relatedElement, Related.UNTIL_ATTRIBUTE, related.getUntil()); + generateAttribute(relatedElement, Related.LINK_ATTRIBUTE, related.getLink()); + generateAttribute(relatedElement, Related.TITLE_ATTRIBUTE, related.getTitle()); + generateAttribute(relatedElement, Related.TYPE_ATTRIBUTE, related.getType()); + } + + protected void generateSync(final Sync sync, final Element parent) { + final Element syncElement = new Element(Sync.NAME, SSEModule.SSE_NS); + generateAttribute(syncElement, Sync.DELETED_ATTRIBUTE, sync.isDeleted()); + generateAttribute(syncElement, Sync.VERSION_ATTRIBUTE, sync.getVersion()); + generateAttribute(syncElement, Sync.ID_ATTRIBUTE, sync.getId()); + generateAttribute(syncElement, Sync.CONFLICT_ATTRIBUTE, sync.isConflict()); + generateHistory(syncElement, sync.getHistory()); + generateConflicts(syncElement, sync.getConflicts()); + parent.addContent(syncElement); + } + + private void generateConflicts(final Element syncElement, final List conflicts) { + if (conflicts != null) { + final Element conflictsElement = new Element(Conflicts.NAME, SSEModule.SSE_NS); + for (final Conflict conflict2 : conflicts) { + final Element conflictElement = new Element(Conflict.NAME, SSEModule.SSE_NS); + final Conflict conflict = conflict2; + generateAttribute(conflictElement, Conflict.BY_ATTRIBUTE, conflict.getBy()); + generateAttribute(conflictElement, Conflict.VERSION_ATTRIBUTE, conflict.getVersion()); + generateAttribute(conflictElement, Conflict.WHEN_ATTRIBUTE, conflict.getWhen()); + generateItem(conflictElement, conflict.getItem()); + conflictsElement.addContent(conflictElement); + } + syncElement.addContent(conflictsElement); + } + } + + private void generateItem(final Element conflictElement, final Item item) { + if (item != null) { + final Element itemElement = new Element("item"); + parentGenerator.populateItem(item, itemElement, 0); + parentGenerator.generateItemModules(item.getModules(), itemElement); + conflictElement.addContent(itemElement); + } + } + + private void generateHistory(final Element syncElement, final History history) { + if (history != null) { + final Element historyElement = new Element(History.NAME, SSEModule.SSE_NS); + generateAttribute(historyElement, History.BY_ATTRIBUTE, history.getBy()); + generateAttribute(historyElement, History.WHEN_ATTRIBUTE, history.getWhen()); + generateUpdates(historyElement, history.getUpdates()); + syncElement.addContent(historyElement); + } + } + + private void generateUpdates(final Element historyElement, final List updates) { + if (updates != null) { + for (final Update update : updates) { + final Element updateElement = new Element(Update.NAME, SSEModule.SSE_NS); + generateAttribute(updateElement, Update.BY_ATTRIBUTE, update.getBy()); + generateAttribute(updateElement, Update.WHEN_ATTRIBUTE, update.getWhen()); + historyElement.addContent(updateElement); + } + } + } + + private void generateAttribute(final Element syncElement, final String attrName, final Object attribute) { + if (attribute != null) { + syncElement.setAttribute(attrName, toString(attribute)); + } + } + + private String toString(final Object o) { + if (o != null) { + if (o instanceof Date) { + return DateParser.formatRFC822((Date) o, Locale.US); + } else { + return o.toString(); + } + } + return ""; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sse/SSE091Parser.java b/rome-modules/src/main/java/com/rometools/modules/sse/SSE091Parser.java new file mode 100644 index 0000000..f05a168 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sse/SSE091Parser.java @@ -0,0 +1,268 @@ +/* + * 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.rometools.modules.sse; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Attribute; +import org.jdom2.DataConversionException; +import org.jdom2.Element; +import org.jdom2.filter.AbstractFilter; + +import com.rometools.modules.sse.modules.Conflict; +import com.rometools.modules.sse.modules.Conflicts; +import com.rometools.modules.sse.modules.History; +import com.rometools.modules.sse.modules.Related; +import com.rometools.modules.sse.modules.SSEModule; +import com.rometools.modules.sse.modules.Sharing; +import com.rometools.modules.sse.modules.Sync; +import com.rometools.modules.sse.modules.Update; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.feed.rss.Item; +import com.rometools.rome.io.DelegatingModuleParser; +import com.rometools.rome.io.WireFeedParser; +import com.rometools.rome.io.impl.DateParser; +import com.rometools.rome.io.impl.RSS20Parser; + +/** + * Parses embedded SSE content from RSS channel and item content. + * + * @author ldornin + */ +public class SSE091Parser implements DelegatingModuleParser { + + // root of the sharing element + private RSS20Parser rssParser; + + /** Creates a new instance of SSE091Parser */ + public SSE091Parser() { + } + + @Override + public void setFeedParser(final WireFeedParser feedParser) { + rssParser = (RSS20Parser) feedParser; + } + + @Override + public String getNamespaceUri() { + return SSEModule.SSE_SCHEMA_URI; + } + + @Override + public Module parse(final Element element, final Locale locale) { + SSEModule sseModule = null; + final String name = element.getName(); + + if (name.equals("rss")) { + sseModule = parseSharing(element, locale); + } else if (name.equals("item")) { + sseModule = parseSync(element, locale); + } + return sseModule; + } + + private Sharing parseSharing(final Element element, final Locale locale) { + final Element root = getRoot(element); + + Sharing sharing = null; + final Element sharingChild = root.getChild(Sharing.NAME, SSEModule.SSE_NS); + if (sharingChild != null) { + sharing = new Sharing(); + sharing.setOrdered(parseBooleanAttr(sharingChild, Sharing.ORDERED_ATTRIBUTE)); + sharing.setSince(parseDateAttribute(sharingChild, Sharing.SINCE_ATTRIBUTE, locale)); + sharing.setUntil(parseDateAttribute(sharingChild, Sharing.UNTIL_ATTRIBUTE, locale)); + sharing.setWindow(parseIntegerAttribute(sharingChild, Sharing.WINDOW_ATTRIBUTE)); + sharing.setVersion(parseStringAttribute(sharingChild, Sharing.VERSION_ATTRIBUTE)); + parseRelated(root, sharing, locale); + } + + return sharing; + } + + private void parseRelated(final Element root, final Sharing sharing, final Locale locale) { + Related related; + final Element relatedChild = root.getChild(Related.NAME, SSEModule.SSE_NS); + if (relatedChild != null) { + related = new Related(); + // TODO; is this an attribute? + related.setLink(parseStringAttribute(relatedChild, Related.LINK_ATTRIBUTE)); + related.setSince(parseDateAttribute(relatedChild, Related.SINCE_ATTRIBUTE, locale)); + related.setTitle(parseStringAttribute(relatedChild, Related.TITLE_ATTRIBUTE)); + related.setType(parseIntegerAttribute(relatedChild, Related.TYPE_ATTRIBUTE)); + related.setUntil(parseDateAttribute(relatedChild, Related.UNTIL_ATTRIBUTE, locale)); + sharing.setRelated(related); + } + } + + private Sync parseSync(final Element element, final Locale locale) { + // Now I am going to get the item specific tags + final Element syncChild = element.getChild(Sync.NAME, SSEModule.SSE_NS); + Sync sync = null; + + if (syncChild != null) { + sync = new Sync(); + sync.setId(parseStringAttribute(syncChild, Sync.ID_ATTRIBUTE)); + sync.setVersion(parseIntegerAttribute(syncChild, Sync.VERSION_ATTRIBUTE)); + sync.setDeleted(parseBooleanAttr(syncChild, Sync.DELETED_ATTRIBUTE)); + sync.setConflict(parseBooleanAttr(syncChild, Sync.CONFLICT_ATTRIBUTE)); + sync.setHistory(parseHistory(syncChild, locale)); + sync.setConflicts(parseConflicts(syncChild, locale)); + } + return sync; + } + + private List parseConflicts(final Element syncElement, final Locale locale) { + List conflicts = null; + + final List conflictsContent = syncElement.getContent(new ContentFilter(Conflicts.NAME)); + for (final Element conflictsElement : conflictsContent) { + final List conflictContent = conflictsElement.getContent(new ContentFilter(Conflict.NAME)); + for (final Element element : conflictContent) { + final Element conflictElement = element; + + final Conflict conflict = new Conflict(); + conflict.setBy(parseStringAttribute(conflictElement, Conflict.BY_ATTRIBUTE)); + conflict.setWhen(parseDateAttribute(conflictElement, Conflict.WHEN_ATTRIBUTE, locale)); + conflict.setVersion(parseIntegerAttribute(conflictElement, Conflict.VERSION_ATTRIBUTE)); + + final List conflictItemContent = conflictElement.getContent(new ContentFilter("item")); + for (final Element element2 : conflictItemContent) { + final Element conflictItemElement = element2; + final Element root = getRoot(conflictItemElement); + final Item conflictItem = rssParser.parseItem(root, conflictItemElement, locale); + conflict.setItem(conflictItem); + + if (conflicts == null) { + conflicts = new ArrayList(); + } + conflicts.add(conflict); + } + } + } + + return conflicts; + } + + private Element getRoot(final Element start) { + // reach up to grab the sharing element out of the root + Element root = start; + + while (root.getParent() != null && root.getParent() instanceof Element) { + root = (Element) root.getParent(); + } + return root; + } + + private History parseHistory(final Element historyElement, final Locale locale) { + final Element historyContent = getFirstContent(historyElement, History.NAME); + + History history = null; + if (historyContent != null) { + history = new History(); + history.setBy(parseStringAttribute(historyContent, History.BY_ATTRIBUTE)); + history.setWhen(parseDateAttribute(historyContent, History.WHEN_ATTRIBUTE, locale)); + parseUpdates(historyContent, history, locale); + } + return history; + } + + private Element getFirstContent(final Element element, final String name) { + final List filterList = element.getContent(new ContentFilter(name)); + Element firstContent = null; + if (filterList != null && !filterList.isEmpty()) { + firstContent = filterList.get(0); + } + return firstContent; + } + + private void parseUpdates(final Element historyChild, final History history, final Locale locale) { + final List updatedChildren = historyChild.getContent(new ContentFilter(Update.NAME)); + for (final Element updateChild : updatedChildren) { + final Update update = new Update(); + update.setBy(parseStringAttribute(updateChild, Update.BY_ATTRIBUTE)); + update.setWhen(parseDateAttribute(updateChild, Update.WHEN_ATTRIBUTE, locale)); + history.addUpdate(update); + } + } + + private String parseStringAttribute(final Element syncChild, final String attrName) { + final Attribute idAttribute = syncChild.getAttribute(attrName); + return idAttribute != null ? idAttribute.getValue().trim() : null; + } + + private Integer parseIntegerAttribute(final Element sharingChild, final String attrName) { + final Attribute integerAttribute = sharingChild.getAttribute(attrName); + Integer integerAttr = null; + if (integerAttribute != null) { + try { + integerAttr = new Integer(integerAttribute.getIntValue()); + } catch (final DataConversionException e) { + // dont use the data + } + } + return integerAttr; + } + + private Boolean parseBooleanAttr(final Element sharingChild, final String attrName) { + final Attribute attribute = sharingChild.getAttribute(attrName); + Boolean attrValue = null; + if (attribute != null) { + try { + attrValue = Boolean.valueOf(attribute.getBooleanValue()); + } catch (final DataConversionException e) { + // dont use the data + } + } + return attrValue; + } + + private Date parseDateAttribute(final Element childElement, final String attrName, final Locale locale) { + final Attribute dateAttribute = childElement.getAttribute(attrName); + final Date date = null; + if (dateAttribute != null) { + // SSE spec requires the timezone to be 'GMT' + // admittedly, this is a bit heavy-handed + final String dateAttr = dateAttribute.getValue().trim(); + return DateParser.parseRFC822(dateAttr, locale); + } + return date; + } + + private static class ContentFilter extends AbstractFilter { + private static final long serialVersionUID = 1L; + private final String name; + + private ContentFilter(final String name) { + this.name = name; + } + + @Override + public Element filter(final Object content) { + final Element returnValue; + if (content instanceof Element && name.equals(((Element) content).getName())) { + returnValue = (Element) content; + } else { + returnValue = null; + } + return returnValue; + } + + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sse/modules/Conflict.java b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Conflict.java new file mode 100644 index 0000000..3f4fb46 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Conflict.java @@ -0,0 +1,109 @@ +/* + * 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.rometools.modules.sse.modules; + +import java.util.Date; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.rss.Item; + +/** + * element within + */ +public class Conflict extends SSEModule { + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(Conflict.class); + + public static final String CONFLICTS_NAME = "conflicts"; + + public static final String NAME = "conflict"; + + /** + * An optional, string attribute. This text attribute identifies the endpoint that made the + * conflicting modification. It is used and compared programmatically. See sx:update for format + * guidance. + *

      + * Note: Either or both of the when or by attributes MUST be present; it is invalid to have + * neither. + */ + public static final String BY_ATTRIBUTE = "by"; + + /** + * A required, integer attribute. This is the version number of the conflicting modification. + */ + public static final String VERSION_ATTRIBUTE = "version"; + + /** + * An optional, date-time attribute. This is the date-time when the conflicting modification + * took place. See sx:update for format guidance. + *

      + * Note: Either or both of the when or by attributes MUST be present; it is invalid to have + * neither. + */ + public static final String WHEN_ATTRIBUTE = "when"; + + private Integer version; + private Date when; + private String by; + private Item conflictItem; + + @Override + public void copyFrom(final CopyFrom obj) { + final Conflict conflict = (Conflict) obj; + conflict.when = when == null ? null : (Date) when.clone(); + conflict.by = by; + conflict.version = version; + try { + conflict.conflictItem = (Item) conflictItem.clone(); + } catch (final CloneNotSupportedException e) { + // should not happen + LOG.error("Error", e); + } + } + + public String getBy() { + return by; + } + + public void setBy(final String by) { + this.by = by; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(final Integer version) { + this.version = version; + } + + public Date getWhen() { + return when; + } + + public void setWhen(final Date when) { + this.when = when; + } + + public void setItem(final Item conflictItem) { + this.conflictItem = conflictItem; + } + + public Item getItem() { + return conflictItem; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sse/modules/Conflicts.java b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Conflicts.java new file mode 100644 index 0000000..2a7892e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Conflicts.java @@ -0,0 +1,32 @@ +/* + * 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.rometools.modules.sse.modules; + +import com.rometools.rome.feed.CopyFrom; + +/** + * element within + *

      + * The sx:conflicts element MUST contain one or more sx:conflict sub-elements. + */ +public class Conflicts extends SSEModule { + private static final long serialVersionUID = 1L; + public static final String NAME = "conflicts"; + + @Override + public void copyFrom(final CopyFrom obj) { + // nothing to copy, just a place-holder + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sse/modules/History.java b/rome-modules/src/main/java/com/rometools/modules/sse/modules/History.java new file mode 100644 index 0000000..f76cbcc --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sse/modules/History.java @@ -0,0 +1,141 @@ +/* + * 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.rometools.modules.sse.modules; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.rometools.rome.feed.CopyFrom; + +/** + *

      + * 
      + * 
      + * + * Element within + * + *
      + * 
      + * 
      + * + * . + */ +public class History extends SSEModule { + private static final long serialVersionUID = 1L; + + // A date-time attribute. + private Date when; + + // A string attribute. + private String by; + + public static final String NAME = "history"; + + public static final String WHEN_ATTRIBUTE = "when"; + public static final String BY_ATTRIBUTE = "by"; + + private List updates; + + public History() { + } + + @Override + public void copyFrom(final CopyFrom other) { + final History otherHistory = (History) other; + when = otherHistory.when == null ? null : (Date) otherHistory.when.clone(); + // dont copy immutable + by = otherHistory.by; + + if (otherHistory.updates != null) { + updates = new ArrayList(); + updates.addAll(otherHistory.updates); + } + } + + /** + * Get the date-time when the most recent modification took place. + *

      + * This is the date-time when the most recent modification took place. If this attribute is + * omitted the value defaults to the earliest time representable in RFC 822. + * + * @return the date-time when the most recent modification took place. + */ + public Date getWhen() { + // TODO: convert to the earliest time in RFC 822 (which is what?) + return when; + } + + /** + * Set the date-time when the most recent modification took place. + *

      + * Either or both of the when or by attributes MUST be present; it is invalid to have neither. + * + * @param when the date-time when the most recent modification took place. + */ + public void setWhen(final Date when) { + this.when = when; + } + + /** + * Provides access to a text attribute identifying the unique endpoint that made the most recent + * modification. This SHOULD be some combination of user and device (so that a given user can + * edit a feed on multiple devices). This attribute is used programmatically to break ties in + * case two changes happened at the same time (within the same second). + *

      + * Either or both of the when or by must be present; it is invalid to have neither. + *

      + * If this attribute is omitted the value defaults to the empty string (which must be less than + * all other values for purposes of collation). + * + * @return A text attribute identifying the unique endpoint that made the most recent + * modification. + */ + public String getBy() { + return by; + } + + /** + * Sets the endpoint that made the most recent modification. + *

      + * Either or both of the when or by attributes MUST be present; it is invalid to have neither. + * + * @param by the endpoint that made the most recent modification. + */ + public void setBy(final String by) { + this.by = by; + } + + /** + * Add an update to this history + * + * @param update an update to add to the list of updates for this history. + */ + public void addUpdate(final Update update) { + if (updates == null) { + updates = new ArrayList(); + } + updates.add(update); + } + + /** + * Return the list of updates for this history. + * + * @return the list of updates for this history. + */ + public List getUpdates() { + return updates; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sse/modules/Related.java b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Related.java new file mode 100644 index 0000000..4214eeb --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Related.java @@ -0,0 +1,175 @@ +/* + * 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.rometools.modules.sse.modules; + +import java.util.Date; + +import com.rometools.rome.feed.CopyFrom; + +/** + *

      + * 
      + * 
      + * + * Element within + * + *
      + * 
      + * 
      + * + * . + */ +public class Related extends SSEModule { + private static final long serialVersionUID = 1L; + + public static final String NAME = "related"; + + /** + * Indicates whether the link points to a file containing the complete collection of items for + * this feed. + */ + public static final int COMPLETE = 0; + + /** + * Indicates whether the link points to a feed whose contents are being incorporated into this + * feed by the publisher. + */ + public static final int AGGREGATED = 1; + + // url for related feeds + private String link; + // name or description of the related feed + private String title; + // the type of the relation "complete" or "aggregated" + private Integer type; + // starting point of the related feed + private Date since; + // ending point of a feed + private Date until; + + public static final String LINK_ATTRIBUTE = "link"; + public static final String SINCE_ATTRIBUTE = "since"; + public static final String TITLE_ATTRIBUTE = "title"; + public static final String TYPE_ATTRIBUTE = "type"; + public static final String UNTIL_ATTRIBUTE = "until"; + + @Override + public void copyFrom(final CopyFrom obj) { + final Related related = (Related) obj; + related.link = link; + related.since = since == null ? null : (Date) since.clone(); + related.title = title; + related.type = type; + related.until = until == null ? null : (Date) until.clone(); + } + + /** + * link A required, URL attribute. The URL for related feeds. + * + * @return the URL for related feeds + */ + // TODO: use a java.net.URL? + public String getLink() { + return link; + } + + /** + * Set the URL for related feeds. + * + * @param link the URL for related feeds. + */ + public void setLink(final String link) { + this.link = link; + } + + /** + * title An optional, string attribute. The name or description of the related feed. + * + * @return The name or description of the related feed. + */ + public String getTitle() { + return title; + } + + /** + * Set the name or description of the related feed. + * + * @param title the name or description of the related feed. + */ + public void setTitle(final String title) { + this.title = title; + } + + /** + * type A required, string attribute. This attribute can have one of the following values: + *

      + * "complete" if the link points to file containing the complete collection of items for this + * feed. + *

      + * "aggregated" if the link points to a feed whose contents are being incorporated into this + * feed by the publisher. + * + * @return the type of the releated feed. + */ + public Integer getType() { + return type; + } + + /** + * Set the type of relationship, complete or aggregated. + * + * @param type the type of relationship, complete or aggregated. + */ + public void setType(final Integer type) { + this.type = type; + } + + /** + * An optional, date-time attribute. This is the starting point of the related feed. If this + * attribute is omitted or blank, it is assumed that this is a complete feed. + * + * @return the starting point of the related feed. + */ + public Date getSince() { + return since; + } + + /** + * Set the starting point of the related feed. + * + * @param since the starting point of the related feed. + */ + public void setSince(final Date since) { + this.since = since; + } + + /** + * An optional, date-time attribute. This is the ending point of a feed. + * + * @return the ending point of the feed, until. + */ + public Date getUntil() { + return until; + } + + /** + * Set the ending point of the feed, until. An optional, date-time attribute. + * + * @param until the ending point of the feed. + */ + public void setUntil(final Date until) { + this.until = until; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sse/modules/SSEModule.java b/rome-modules/src/main/java/com/rometools/modules/sse/modules/SSEModule.java new file mode 100644 index 0000000..ad5c7db --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sse/modules/SSEModule.java @@ -0,0 +1,74 @@ +/* + * 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.rometools.modules.sse.modules; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.module.Module; + +/** + * The base module for SSE data synchronization. Defines a namespace, uri, and basic copying + * operations. + */ +public abstract class SSEModule implements Module { + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(SSEModule.class); + + public static final String SSE_SCHEMA_URI = "http://www.microsoft.com/schemas/rss/sse"; + + // a default prefix to use for sse tags + public static final String PREFIX = "sx"; + public static final Namespace SSE_NS = Namespace.getNamespace(PREFIX, SSE_SCHEMA_URI); + + public static final Set NAMESPACES; + + static { + final Set nss = new HashSet(); + nss.add(SSEModule.SSE_NS); + NAMESPACES = Collections.unmodifiableSet(nss); + } + + @Override + public String getUri() { + return SSE_SCHEMA_URI; + } + + @Override + public Class getInterface() { + return getClass(); + } + + @Override + public Object clone() { + SSEModule clone = null; + try { + clone = this.getClass().newInstance(); + clone.copyFrom(this); + } catch (final InstantiationException e) { + LOG.error("Error", e); + } catch (final IllegalAccessException e) { + LOG.error("Error", e); + } + return clone; + } + + @Override + public abstract void copyFrom(CopyFrom obj); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sse/modules/Sharing.java b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Sharing.java new file mode 100644 index 0000000..3edd03e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Sharing.java @@ -0,0 +1,176 @@ +/* + * 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.rometools.modules.sse.modules; + +import java.util.Date; + +import com.rometools.rome.feed.CopyFrom; + +/** + *

      + * 
      + * 
      + * + * Element within RSS + * + *
      + * 
      + * 
      + * + * or OPML + * + *
      + * 
      + * 
      + * + * . + */ +public class Sharing extends SSEModule { + private static final long serialVersionUID = 1L; + + public static final String NAME = "sharing"; + + public static final String UNTIL_ATTRIBUTE = "until"; + public static final String SINCE_ATTRIBUTE = "since"; + public static final String ORDERED_ATTRIBUTE = "ordered"; + public static final String WINDOW_ATTRIBUTE = "window"; + public static final String VERSION_ATTRIBUTE = "version"; + + public static final String VERSION = "0.91"; + + // whether subscribers MUST treat the item list as an ordered set + private Boolean ordered; + // expresses size of the window of change history kept by the published. + private Integer window; + // date after which updated items are included in the feed. + private Date since; + // date after which updated items are not included in the feed. + + // version of the sse in shared channel + private String version; + + private Date until; + private Related related; + + @Override + public void copyFrom(final CopyFrom obj) { + final Sharing sharing = (Sharing) obj; + ordered = sharing.ordered; + since = sharing.since == null ? null : (Date) sharing.since.clone(); + window = sharing.window; + until = sharing.until == null ? null : (Date) sharing.until.clone(); + version = sharing.version; + } + + /** + * ordered An optional, Boolean attribute. If present and its value is "true" (lower-case), + * subscribers MUST treat the item list as an ordered set (see section 3.2). If this attribute + * is omitted or blank, it is assumed that this is an unordered feed. + * + * @return a Boolean indicating if subscribers must treat the item list as an ordered set. + */ + public Boolean getOrdered() { + return ordered; + } + + /** + * Set whether subscribers MUST tread the item list as an ordered set. + * + * @param ordered whether subscribers MUST tread the item list as an ordered set. + */ + public void setOrdered(final Boolean ordered) { + this.ordered = ordered; + } + + /** + * Provides an Integer that expresses the size of the window of change history kept by the + * publisher. Subscribers MAY use this value to determine the frequency with which they must + * read a feed. + * + * @return an Integer that expresses the size of the window of change history kept by the + * publisher. + */ + public Integer getWindow() { + return window; + } + + /** + * Set an Integer that expresses the size of the window of change history kept by the publisher. + * + * @param window an Integer that expresses the size of the window of change history kept by the + * publisher. + */ + public void setWindow(final Integer window) { + this.window = window; + } + + /** + * since An optional date-time attribute. All items updated on or after this date-time are + * included in the feed. If not present or null, the "beginning of time" is assumed and the feed + * contains the node's complete item set as of the until date-time. + * + * @return An optional date-time attribute. + */ + public Date getSince() { + return since; + } + + /** + * Sets the optional date-time attribute where all items updated on or after this date-time are + * included in the feed. + * + * @param since An optional date-time attribute. + */ + public void setSince(final Date since) { + this.since = since; + } + + /** + * until An optional date-time attribute. Items updated after this date are not included in the + * feed. The publisher must guarantee that the value of until will increase if any items in the + * feed are updated. If this attribute is omitted or blank, the subscriber cannot make + * assumptions about when the feed was updated. + * + * @return the date where items updated after this date are not included in the feed. + */ + public Date getUntil() { + return until; + } + + /** + * Set the date where items updated after this date are not included in the feed. + * + * @param until the date where items updated after this date are not included in the feed. + */ + public void setUntil(final Date until) { + this.until = until; + } + + public void setRelated(final Related related) { + this.related = related; + } + + public Related getRelated() { + return related; + } + + public void setVersion(final String version) { + this.version = version; + } + + public Object getVersion() { + return version; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sse/modules/Sync.java b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Sync.java new file mode 100644 index 0000000..9ff18fe --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Sync.java @@ -0,0 +1,182 @@ +package com.rometools.modules.sse.modules; + +import java.util.ArrayList; +import java.util.List; + +import com.rometools.rome.feed.CopyFrom; + +/** + *
      + * 
      + * 
      + * + * Element within RSS + * + *
      + * 
      + * 
      + * + * or OPML + * + *
      + * 
      + * 
      + * + * . + */ +public class Sync extends SSEModule { + private static final long serialVersionUID = 1L; + + public static final String NAME = "sync"; + + public static final String ID_ATTRIBUTE = "id"; + public static final String VERSION_ATTRIBUTE = "version"; + public static final String CONFLICT_ATTRIBUTE = "conflict"; + public static final String DELETED_ATTRIBUTE = "deleted"; + + // item identifier + private String id; + // item sequence modification number + private Integer version; + // indication of whether the item is deleted and is a tombstone + private Boolean deleted; + // an indication of whether there was an update conflict + private Boolean conflict; + + private History history; + private List conflicts; + + @Override + public void copyFrom(final CopyFrom obj) { + final Sync sync = (Sync) obj; + deleted = sync.deleted; + version = sync.version; + conflict = sync.conflict; + id = sync.id; + history = sync.history == null ? null : (History) sync.history.clone(); + if (sync.conflicts != null) { + conflicts = new ArrayList(); + conflicts.addAll(sync.conflicts); + } + } + + /** + * Provides access to the sync id, a required, string attribute. This is the identifier for the + * item. + *

      + * The ID is assigned by the creator of the item, and MUST NOT be changed by subsequent + * publishers. Applications will collate and compare these identifiers, therefore they MUST + * conform to the syntax for Namespace Specific Strings (the NSS portion of a URN) in RFC 2141. + */ + public String getId() { + return id; + } + + /** + * Set the identifier for the item. The ID MUST be globally unique within the feed and it MUST + * be identical across feeds if an item is being shared or replicated as part of multiple + * distinct independent feeds. + * + * @param id the identifier for the item. + */ + public void setId(final String id) { + this.id = id; + } + + /** + * Provides access to a required, integer attribute. This is the modification sequence number of + * the item, starting at 1 and incrementing by 1 indefinitely for each subsequent modification. + */ + public Integer getVersion() { + return version; + } + + /** + * Set the modification sequence number of the item. + * + * @param version the modification sequence number of the item. + */ + public void setVersion(final Integer version) { + this.version = version; + } + + /** + * Provide access to an optional, Boolean attribute. If present and its value is "true" + * (lower-case), it indicates that the item has been deleted and this is a tombstone. If not + * present, or if present with value of "false" or "", then the item is not deleted. All other + * values are invalid. + */ + public Boolean isDeleted() { + return deleted; + } + + /** + * Set an indication of whether this item has been deleted and is a tombstone. + * + * @param deleted an indication of whether this item has been deleted and is a tombstone. + */ + public void setDeleted(final Boolean deleted) { + this.deleted = deleted; + } + + /** + * Provides access to an optional, Boolean conflict attribute. If present and its value is + * "true" (lower-case), it indicates there was an update conflict detected when processing an + * update of this item, and it should potentially be examined by the user. If not present, or + * present with value of "false" or "", Then no conflict has been detected. All other values are + * invalid. + * + * @return indicates there was an update conflict detected when processing an update of this + * item. + */ + public Boolean isConflict() { + return conflict; + } + + /** + * Set an indication of whether there was an update conflict detected when processing an update + * of this item. + * + * @param conflict an indication of whether there was an update conflict detected when + * processing an update of this item. + */ + public void setConflict(final Boolean conflict) { + this.conflict = conflict; + } + + // TODO: does it make sense for the sync element to have a history? + // TODO: should the history be a module? + + /** + * The history history for this sync object + * + * @param history the history for this sync object. + */ + public void setHistory(final History history) { + this.history = history; + } + + /** + * Get the history for this sync object + * + * @return get the history for this sync object. + */ + public History getHistory() { + return history; + } + + public void addConflict(final Conflict conflict) { + if (conflicts == null) { + conflicts = new ArrayList(); + } + conflicts.add(conflict); + } + + public List getConflicts() { + return conflicts; + } + + public void setConflicts(final List conflicts) { + this.conflicts = conflicts; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/sse/modules/Update.java b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Update.java new file mode 100644 index 0000000..9ca22e2 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/sse/modules/Update.java @@ -0,0 +1,90 @@ +/* + * 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.rometools.modules.sse.modules; + +import java.util.Date; + +import com.rometools.rome.feed.CopyFrom; + +/** + *

      + * 
      + * 
      + * + * Element within + * + *
      + * 
      + * 
      + * + * . + */ +public class Update extends SSEModule { + private static final long serialVersionUID = 1L; + public static final String NAME = "update"; + public static final String BY_ATTRIBUTE = "by"; + public static final String WHEN_ATTRIBUTE = "when"; + + private Date when; + private String by; + + @Override + public void copyFrom(final CopyFrom other) { + final Update otherUpdate = (Update) other; + otherUpdate.when = when == null ? null : (Date) when.clone(); + // dont copy immutable + otherUpdate.by = by; + } + + /** + * Provides access to the date-time when the modification took place. If this attribute is + * omitted the value defaults to the earliest time representable in RFC 822. Either or both of + * the when or by attributes MUST be present; it is invalid to have neither. + */ + public Date getWhen() { + return when; + } + + /** + * Set the date-time when the modification took place. + * + * @param when the date-time when the modification took place. + */ + public void setWhen(final Date when) { + this.when = when; + } + + /** + * Provides access to a text attribute identifying the unique endpoint that made a modification. + * This SHOULD be some combination of user and device (so that a given user can edit a feed on + * multiple devices). This attribute is used programmatically to break ties in case two changes + * happened at the same time (within the same second). Either or both of the when or by must be + * present; it is invalid to have neither. + * + * @return access to a text attribute identifying the unique endpoint that made a modification. + */ + public String getBy() { + return by; + } + + /** + * Sets a text attribute identifying the unique endpoint that made a modification. + * + * @param by a text attribute identifying the unique endpoint that made a modification. + */ + public void setBy(final String by) { + this.by = by; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/thr/ThreadingModule.java b/rome-modules/src/main/java/com/rometools/modules/thr/ThreadingModule.java new file mode 100644 index 0000000..98f19b9 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/thr/ThreadingModule.java @@ -0,0 +1,29 @@ +package com.rometools.modules.thr; + +import com.rometools.rome.feed.module.Module; + +/** + * Currently no support for thr:count, thr:updated, thr:total link attributes. + * + * @author Andreas Feldschmid + */ +public interface ThreadingModule extends Module { + + public static final String URI = "http://purl.org/syndication/thread/1.0"; + + public String getRef(); + + public void setRef(String ref); + + public String getType(); + + public void setType(String type); + + public String getHref(); + + public void setHref(String href); + + public String getSource(); + + public void setSource(String source); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/thr/ThreadingModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/thr/ThreadingModuleImpl.java new file mode 100644 index 0000000..e0a44c3 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/thr/ThreadingModuleImpl.java @@ -0,0 +1,110 @@ +package com.rometools.modules.thr; + +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; +import com.rometools.rome.feed.module.ModuleImpl; + +/** + * Currently no support for thr:count, thr:updated, thr:total link attributes. + * + * @author Andreas Feldschmid + */ +public class ThreadingModuleImpl extends ModuleImpl implements ThreadingModule { + + private static final long serialVersionUID = 1L; + + private String ref; + private String href; + private String type; + private String source; + + public ThreadingModuleImpl() { + super(ThreadingModule.class, ThreadingModule.URI); + } + + @Override + public Class getInterface() { + return ThreadingModule.class; + } + + @Override + public void copyFrom(CopyFrom copyFrom) { + if (copyFrom instanceof ThreadingModule) { + ThreadingModule module = (ThreadingModule) copyFrom; + setHref(module.getHref()); + setRef(module.getRef()); + setType(module.getType()); + setSource(module.getSource()); + } + } + + @Override + public String getRef() { + return ref; + } + + @Override + public void setRef(String ref) { + this.ref = ref; + } + + @Override + public String getType() { + return type; + } + + @Override + public void setType(String type) { + this.type = type; + } + + @Override + public String getHref() { + return href; + } + + @Override + public void setHref(String href) { + this.href = href; + } + + @Override + public String getSource() { + return source; + } + + @Override + public void setSource(String source) { + this.source = source; + } + + @Override + public Object clone() { + final ThreadingModule m = new ThreadingModuleImpl(); + m.setHref(href); + m.setRef(ref); + m.setSource(source); + m.setType(type); + return m; + } + + @Override + public boolean equals(final Object obj) { + final EqualsBean eBean = new EqualsBean(ThreadingModuleImpl.class, this); + return eBean.beanEquals(obj); + } + + @Override + public int hashCode() { + final EqualsBean equals = new EqualsBean(ThreadingModuleImpl.class, this); + return equals.beanHashCode(); + } + + @Override + public String toString() { + final ToStringBean tsBean = new ToStringBean(ThreadingModuleImpl.class, this); + return tsBean.toString(); + } + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/thr/io/ThreadingModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/thr/io/ThreadingModuleGenerator.java new file mode 100644 index 0000000..af51f83 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/thr/io/ThreadingModuleGenerator.java @@ -0,0 +1,62 @@ +package com.rometools.modules.thr.io; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.thr.ThreadingModule; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * Currently no support for thr:count, thr:updated, thr:total link attributes. + * + * @author Andreas Feldschmid + */ +public class ThreadingModuleGenerator implements ModuleGenerator { + + private static final Namespace NAMESPACE = Namespace.getNamespace("thr", ThreadingModule.URI); + private static final Set NAMESPACES; + + static { + Set namespaces = new HashSet(); + namespaces.add(NAMESPACE); + NAMESPACES = Collections.unmodifiableSet(namespaces); + } + + @Override + public String getNamespaceUri() { + return ThreadingModule.URI; + } + + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + @Override + public void generate(Module module, Element element) { + if (module != null && module instanceof ThreadingModule) { + ThreadingModule threadedModule = (ThreadingModule) module; + Element inReplyTo = new Element("in-reply-to", NAMESPACE); + + if (threadedModule.getHref() != null) { + inReplyTo.setAttribute("href", threadedModule.getHref()); + } + if (threadedModule.getRef() != null) { + inReplyTo.setAttribute("ref", threadedModule.getRef()); + } + if (threadedModule.getType() != null) { + inReplyTo.setAttribute("type", threadedModule.getType()); + } + if (threadedModule.getSource() != null) { + inReplyTo.setAttribute("source", threadedModule.getSource()); + } + + element.addContent(inReplyTo); + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/thr/io/ThreadingModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/thr/io/ThreadingModuleParser.java new file mode 100644 index 0000000..ecba871 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/thr/io/ThreadingModuleParser.java @@ -0,0 +1,42 @@ +package com.rometools.modules.thr.io; + +import java.util.Locale; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.thr.ThreadingModule; +import com.rometools.modules.thr.ThreadingModuleImpl; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; + +/** + * Currently no support for thr:count, thr:updated, thr:total link attributes. + * + * @author Andreas Feldschmid + */ +public class ThreadingModuleParser implements ModuleParser { + + private static final Namespace NS = Namespace.getNamespace(ThreadingModule.URI); + + @Override + public String getNamespaceUri() { + return ThreadingModule.URI; + } + + @Override + public Module parse(final Element element, final Locale locale) { + final ThreadingModule tm = new ThreadingModuleImpl(); + Element inReplyTo = element.getChild("in-reply-to", ThreadingModuleParser.NS); + + if (inReplyTo != null) { + tm.setHref(inReplyTo.getAttributeValue("href")); + tm.setRef(inReplyTo.getAttributeValue("ref")); + tm.setSource(inReplyTo.getAttributeValue("source")); + tm.setType(inReplyTo.getAttributeValue("type")); + return tm; + } + + return null; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherEntryModule.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherEntryModule.java new file mode 100644 index 0000000..4be4f22 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherEntryModule.java @@ -0,0 +1,76 @@ +/* + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather; + +import com.rometools.modules.yahooweather.types.Condition; +import com.rometools.modules.yahooweather.types.Forecast; + +/** + * An interface describing the entry/item level data for Yahoo Weather. + * + * @version $Id: YWeatherEntryModule.java,v 1.2 2008/01/22 14:50:06 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public interface YWeatherEntryModule extends YWeatherModule { + /** + * The current conditions. + * + * @return The current conditions. + */ + Condition getCondition(); + + /** + * The current conditions. + * + * @param condition The current conditions. + */ + void setCondition(Condition condition); + + /** + * Forecasts for this location. + * + * @return Forecasts for this location. + */ + Forecast[] getForecasts(); + + /** + * Forecasts for this location. + * + * @param forecasts Forecasts for this location. + */ + void setForecasts(Forecast[] forecasts); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherFeedModule.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherFeedModule.java new file mode 100644 index 0000000..c678ada --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherFeedModule.java @@ -0,0 +1,120 @@ +/* + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather; + +import com.rometools.modules.yahooweather.types.Astronomy; +import com.rometools.modules.yahooweather.types.Atmosphere; +import com.rometools.modules.yahooweather.types.Location; +import com.rometools.modules.yahooweather.types.Units; +import com.rometools.modules.yahooweather.types.Wind; + +/** + * An interface describing feed/channel level data for Yahoo Weather. + * + * @version $Id: YWeatherFeedModule.java,v 1.3 2008/03/29 16:19:12 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public interface YWeatherFeedModule extends YWeatherModule { + /** + * The location the feed is for. + * + * @return The location the feed is for. + */ + Location getLocation(); + + /** + * The location the feed is for. + * + * @param location The location the feed is for. + */ + void setLocation(Location location); + + /** + * Astronomical information for the location. + * + * @return Astronomical information for the location. + */ + Astronomy getAstronomy(); + + /** + * Astronomical information for the location. + * + * @param astronomy Astronomical information for the location. + */ + void setAstronomy(Astronomy astronomy); + + /** + * Units that data in the feed is provided in. + * + * @return Units that data in the feed is provided in. + */ + Units getUnits(); + + /** + * Units that data in the feed is provided in. + * + * @param units Units that data in the feed is provided in. + */ + void setUnits(Units units); + + /** + * Current wind conditions at the location. + * + * @return Current wind conditions at the location. + */ + Wind getWind(); + + /** + * Current wind conditions at the location. + * + * @param wind Current wind conditions at the location. + */ + void setWind(Wind wind); + + /** + * The current atmospheric conditions. + * + * @return Atmosphere object. + */ + Atmosphere getAtmosphere(); + + /** + * Sets the current atmopheric condictions. + * + * @param value Atmosphere object. + */ + void setAtmosphere(Atmosphere value); +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherModule.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherModule.java new file mode 100644 index 0000000..25ec3e3 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherModule.java @@ -0,0 +1,51 @@ +/* + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather; + +import com.rometools.rome.feed.module.Module; + +/** + * A simple parent interface that defines the feed URI. + * + * @version $Id: YWeatherModule.java,v 1.2 2008/01/22 14:50:06 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public interface YWeatherModule extends Module { + /** + * "http://xml.weather.yahoo.com/ns/rss/1.0". + */ + String URI = "http://xml.weather.yahoo.com/ns/rss/1.0"; +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherModuleImpl.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherModuleImpl.java new file mode 100644 index 0000000..69bbdf2 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/YWeatherModuleImpl.java @@ -0,0 +1,173 @@ +/* + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather; + +import com.rometools.modules.yahooweather.types.Astronomy; +import com.rometools.modules.yahooweather.types.Atmosphere; +import com.rometools.modules.yahooweather.types.Condition; +import com.rometools.modules.yahooweather.types.Forecast; +import com.rometools.modules.yahooweather.types.Location; +import com.rometools.modules.yahooweather.types.Units; +import com.rometools.modules.yahooweather.types.Wind; +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.feed.module.ModuleImpl; + +/** + * A Module implementation for entry or feed level information. + * + * @version $Id: YWeatherModuleImpl.java,v 1.2 2008/01/22 14:50:06 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public class YWeatherModuleImpl extends ModuleImpl implements YWeatherEntryModule, YWeatherFeedModule { + private static final long serialVersionUID = 1L; + private Location location; + private Astronomy astronomy; + private Atmosphere atmosphere; + private Units units; + private Condition condition; + private Wind wind; + private Forecast[] forecasts; + + /** + */ + public YWeatherModuleImpl() { + super(YWeatherModuleImpl.class, YWeatherModule.URI); + } + + @Override + public Class getInterface() { + return CopyFromInterface.class; + } + + @Override + public void copyFrom(final CopyFrom o) { + final YWeatherModuleImpl from = (YWeatherModuleImpl) o; + setAstronomy(from.getAstronomy() != null ? (Astronomy) from.getAstronomy().clone() : null); + setCondition(from.getCondition() != null ? (Condition) from.getCondition().clone() : null); + setLocation(from.getLocation() != null ? (Location) from.getLocation().clone() : null); + setUnits(from.getUnits() != null ? (Units) from.getUnits().clone() : null); + setWind(from.getWind() != null ? (Wind) from.getWind().clone() : null); + + setAtmosphere(from.getAtmosphere() != null ? (Atmosphere) from.getAtmosphere().clone() : null); + + if (from.getForecasts() != null) { + forecasts = new Forecast[from.forecasts.length]; + + for (int i = 0; i < from.forecasts.length; i++) { + forecasts[i] = from.forecasts[i] != null ? (Forecast) from.forecasts[i].clone() : null; + } + } else { + forecasts = null; + } + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public void setLocation(final Location location) { + this.location = location; + } + + @Override + public Astronomy getAstronomy() { + return astronomy; + } + + @Override + public void setAstronomy(final Astronomy astronomy) { + this.astronomy = astronomy; + } + + @Override + public Units getUnits() { + return units; + } + + @Override + public void setUnits(final Units units) { + this.units = units; + } + + @Override + public Condition getCondition() { + return condition; + } + + @Override + public void setCondition(final Condition condition) { + this.condition = condition; + } + + @Override + public Forecast[] getForecasts() { + return forecasts; + } + + @Override + public void setForecasts(final Forecast[] forecasts) { + this.forecasts = forecasts; + } + + @Override + public Wind getWind() { + return wind; + } + + @Override + public void setWind(final Wind wind) { + this.wind = wind; + } + + @Override + public Atmosphere getAtmosphere() { + return atmosphere; + } + + @Override + public void setAtmosphere(final Atmosphere atmosphere) { + this.atmosphere = atmosphere; + } + + /** + * Inteface combining feed and entry module. + */ + public interface CopyFromInterface extends YWeatherFeedModule, YWeatherEntryModule { + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/io/WeatherModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/io/WeatherModuleGenerator.java new file mode 100644 index 0000000..088c819 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/io/WeatherModuleGenerator.java @@ -0,0 +1,218 @@ +/* + * WeatherModuleGenerator.java + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather.io; + +import java.text.SimpleDateFormat; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.modules.yahooweather.YWeatherModule; +import com.rometools.modules.yahooweather.YWeatherModuleImpl; +import com.rometools.modules.yahooweather.types.Forecast; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * The ModuleGenerator implementation for the Yahoo Weather plug in. + * + * @version $Revision: 1.3 $ + * @author Robert "kebernet" Cooper + */ +public class WeatherModuleGenerator implements ModuleGenerator { + private static final Namespace NS = Namespace.getNamespace("yweather", YWeatherModule.URI); + private static final SimpleDateFormat TIME_ONLY = new SimpleDateFormat("h:mm a", Locale.US); + private static final SimpleDateFormat LONG_DATE = new SimpleDateFormat("EEE, d MMM yyyy h:mm a zzz", Locale.US); + private static final SimpleDateFormat SHORT_DATE = new SimpleDateFormat("d MMM yyyy", Locale.US); + + /** Creates a new instance of SlashModuleGenerator. */ + public WeatherModuleGenerator() { + } + + @Override + public void generate(final Module module, final Element element) { + if (!(module instanceof YWeatherModuleImpl)) { + return; + } + + final YWeatherModuleImpl weather = (YWeatherModuleImpl) module; + + if (weather.getAstronomy() != null) { + final Element astro = new Element("astronomy", WeatherModuleGenerator.NS); + + if (weather.getAstronomy().getSunrise() != null) { + astro.setAttribute("sunrise", TIME_ONLY.format(weather.getAstronomy().getSunrise()).toLowerCase()); + } + + if (weather.getAstronomy().getSunrise() != null) { + astro.setAttribute("sunset", TIME_ONLY.format(weather.getAstronomy().getSunset()).toLowerCase()); + } + + element.addContent(astro); + } + + if (weather.getAtmosphere() != null) { + final Element atmos = new Element("atmosphere", WeatherModuleGenerator.NS); + atmos.setAttribute("humidity", Integer.toString(weather.getAtmosphere().getHumidity())); + atmos.setAttribute("visibility", Integer.toString((int) (weather.getAtmosphere().getVisibility() * 100d))); + atmos.setAttribute("pressure", Double.toString(weather.getAtmosphere().getPressure())); + + if (weather.getAtmosphere().getChange() != null) { + atmos.setAttribute("rising", Integer.toString(weather.getAtmosphere().getChange().getCode())); + } + + element.addContent(atmos); + } + + if (weather.getCondition() != null) { + final Element condition = new Element("condition", WeatherModuleGenerator.NS); + + if (weather.getCondition().getText() != null) { + condition.setAttribute("text", weather.getCondition().getText()); + } + + if (weather.getCondition().getCode() != null) { + condition.setAttribute("code", Integer.toString(weather.getCondition().getCode().getCode())); + } + + if (weather.getCondition().getDate() != null) { + condition.setAttribute("date", LONG_DATE.format(weather.getCondition().getDate()).replaceAll("AM", "am").replaceAll("PM", "pm")); + } + + condition.setAttribute("temp", Integer.toString(weather.getCondition().getTemperature())); + element.addContent(condition); + } + + if (weather.getLocation() != null) { + final Element location = new Element("location", WeatherModuleGenerator.NS); + + if (weather.getLocation().getCity() != null) { + location.setAttribute("city", weather.getLocation().getCity()); + } + + if (weather.getLocation().getRegion() != null) { + location.setAttribute("region", weather.getLocation().getRegion()); + } + + if (weather.getLocation().getCountry() != null) { + location.setAttribute("country", weather.getLocation().getCountry()); + } + + element.addContent(location); + } + + if (weather.getUnits() != null) { + final Element units = new Element("units", WeatherModuleGenerator.NS); + + if (weather.getUnits().getDistance() != null) { + units.setAttribute("distance", weather.getUnits().getDistance()); + } + + if (weather.getUnits().getPressure() != null) { + units.setAttribute("pressure", weather.getUnits().getPressure()); + } + + if (weather.getUnits().getSpeed() != null) { + units.setAttribute("speed", weather.getUnits().getSpeed()); + } + + if (weather.getUnits().getTemperature() != null) { + units.setAttribute("temperature", weather.getUnits().getTemperature()); + } + + element.addContent(units); + } + + if (weather.getWind() != null) { + final Element wind = new Element("wind", WeatherModuleGenerator.NS); + wind.setAttribute("chill", Integer.toString(weather.getWind().getChill())); + wind.setAttribute("direction", Integer.toString(weather.getWind().getDirection())); + wind.setAttribute("speed", Integer.toString(weather.getWind().getSpeed())); + element.addContent(wind); + } + + if (weather.getForecasts() != null) { + for (int i = 0; i < weather.getForecasts().length; i++) { + final Element forecast = new Element("forecast", WeatherModuleGenerator.NS); + final Forecast f = weather.getForecasts()[i]; + + if (f.getCode() != null) { + forecast.setAttribute("code", Integer.toString(f.getCode().getCode())); + } + + if (f.getDate() != null) { + forecast.setAttribute("date", SHORT_DATE.format(f.getDate())); + } + + if (f.getDay() != null) { + forecast.setAttribute("day", f.getDay()); + } + + if (f.getText() != null) { + forecast.setAttribute("text", f.getText()); + } + + forecast.setAttribute("high", Integer.toString(f.getHigh())); + forecast.setAttribute("low", Integer.toString(f.getLow())); + element.addContent(forecast); + } + } + } + + protected Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, WeatherModuleGenerator.NS); + element.addContent(value); + + return element; + } + + @Override + public Set getNamespaces() { + final Set set = new HashSet(); + set.add(WeatherModuleGenerator.NS); + return set; + } + + @Override + public String getNamespaceUri() { + return YWeatherModule.URI; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/io/WeatherModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/io/WeatherModuleParser.java new file mode 100644 index 0000000..cad9ee3 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/io/WeatherModuleParser.java @@ -0,0 +1,178 @@ +/* + * WeatherModuleParser.java + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather.io; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.yahooweather.YWeatherModule; +import com.rometools.modules.yahooweather.YWeatherModuleImpl; +import com.rometools.modules.yahooweather.types.Astronomy; +import com.rometools.modules.yahooweather.types.Atmosphere; +import com.rometools.modules.yahooweather.types.Condition; +import com.rometools.modules.yahooweather.types.ConditionCode; +import com.rometools.modules.yahooweather.types.Forecast; +import com.rometools.modules.yahooweather.types.Location; +import com.rometools.modules.yahooweather.types.Units; +import com.rometools.modules.yahooweather.types.Wind; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; + +/** + * ModuleParser implementation for Slash RSS. + * + * @version $Revision: 1.2 $ + * @author Robert "kebernet" Cooper + */ +public class WeatherModuleParser implements ModuleParser { + private static final Logger LOG = LoggerFactory.getLogger(WeatherModuleParser.class); + private static final Namespace NS = Namespace.getNamespace(YWeatherModule.URI); + + @Override + public String getNamespaceUri() { + return YWeatherModule.URI; + } + + @Override + public Module parse(final Element element, final Locale locale) { + final YWeatherModuleImpl module = new YWeatherModuleImpl(); + final Element location = element.getChild("location", WeatherModuleParser.NS); + + if (location != null) { + final Location l = new Location(location.getAttributeValue("city"), location.getAttributeValue("region"), location.getAttributeValue("country")); + module.setLocation(l); + } + + final Element units = element.getChild("units", WeatherModuleParser.NS); + + if (units != null) { + final Units u = new Units(units.getAttributeValue("temperature"), units.getAttributeValue("distance"), units.getAttributeValue("pressure"), + units.getAttributeValue("speed")); + module.setUnits(u); + } + + final Element wind = element.getChild("wind", WeatherModuleParser.NS); + + if (wind != null) { + try { + final Wind w = new Wind(Integer.parseInt(wind.getAttributeValue("chill")), Integer.parseInt(wind.getAttributeValue("direction")), + Integer.parseInt(wind.getAttributeValue("speed"))); + module.setWind(w); + } catch (final NumberFormatException nfe) { + LOG.warn("NumberFormatException processing tag.", nfe); + } + } + + final Element atmosphere = element.getChild("atmosphere", WeatherModuleParser.NS); + + if (atmosphere != null) { + try { + final Atmosphere a = new Atmosphere(Integer.parseInt(atmosphere.getAttributeValue("humidity")), Double.parseDouble(atmosphere + .getAttributeValue("visibility")) / 100, Double.parseDouble(atmosphere.getAttributeValue("pressure")), + Atmosphere.PressureChange.fromCode(Integer.parseInt(atmosphere.getAttributeValue("rising")))); + module.setAtmosphere(a); + } catch (final NumberFormatException nfe) { + LOG.warn("NumberFormatException processing tag.", nfe); + } + } + + final Element astronomy = element.getChild("astronomy", WeatherModuleParser.NS); + + if (astronomy != null) { + try { + final SimpleDateFormat timeFormat = new SimpleDateFormat("h:mm a", locale); + final Astronomy a = new Astronomy(timeFormat.parse(astronomy.getAttributeValue("sunrise").replaceAll("am", "AM").replaceAll("pm", "PM")), + timeFormat.parse(astronomy.getAttributeValue("sunset").replaceAll("am", "AM").replaceAll("pm", "PM"))); + module.setAstronomy(a); + } catch (final ParseException pe) { + LOG.warn("ParseException processing tag.", pe); + } + } + + final Element condition = element.getChild("condition", WeatherModuleParser.NS); + + if (condition != null) { + try { + final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, d MMM yyyy h:mm a zzz", locale); + final Condition c = new Condition(condition.getAttributeValue("text"), ConditionCode.fromCode(Integer.parseInt(condition + .getAttributeValue("code"))), Integer.parseInt(condition.getAttributeValue("temp")), dateFormat.parse(condition + .getAttributeValue("date").replaceAll("pm", "PM").replaceAll("am", "AM"))); + module.setCondition(c); + } catch (final NumberFormatException nfe) { + LOG.warn("NumberFormatException processing tag.", nfe); + } catch (final ParseException pe) { + LOG.warn("ParseException processing tag.", pe); + } + } + + final List forecasts = element.getChildren("forecast", WeatherModuleParser.NS); + + if (forecasts != null) { + final Forecast[] f = new Forecast[forecasts.size()]; + int i = 0; + + final SimpleDateFormat dateFormat = new SimpleDateFormat("d MMM yyyy", locale); + for (final Iterator it = forecasts.iterator(); it.hasNext(); i++) { + final Element forecast = it.next(); + + try { + f[i] = new Forecast(forecast.getAttributeValue("day"), dateFormat.parse(forecast.getAttributeValue("date")), Integer.parseInt(forecast + .getAttributeValue("low")), Integer.parseInt(forecast.getAttributeValue("high")), forecast.getAttributeValue("text"), + ConditionCode.fromCode(Integer.parseInt(forecast.getAttributeValue("code")))); + } catch (final NumberFormatException nfe) { + LOG.warn("NumberFormatException processing tag.", nfe); + } catch (final ParseException pe) { + LOG.warn("ParseException processing tag.", pe); + } + } + + module.setForecasts(f); + } + + return module; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/io/package.html b/rome-modules/src/main/java/com/rometools/modules/yahooweather/io/package.html new file mode 100644 index 0000000..4790779 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/io/package.html @@ -0,0 +1,45 @@ + + + + + + + + This package contains the parser and generator for ROME. +
      + * This library is provided under dual licenses.
      + * You may choose the terms of the Lesser General Public License or the Apache
      + * License at your discretion.
      + *
      + *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
      + *
      + *
      + * This library is free software; you can redistribute it and/or
      + * modify it under the terms of the GNU Lesser General Public
      + * License as published by the Free Software Foundation; either
      + * version 2.1 of the License, or (at your option) any later version.
      + *
      + * This library is distributed in the hope that it will be useful,
      + * but WITHOUT ANY WARRANTY; without even the implied warranty of
      + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      + * Lesser General Public License for more details.
      + *
      + * You should have received a copy of the GNU Lesser General Public
      + * License along with this library; if not, write to the Free Software
      + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      + *
      + *
      + * 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/rome-modules/src/main/java/com/rometools/modules/yahooweather/package.html b/rome-modules/src/main/java/com/rometools/modules/yahooweather/package.html new file mode 100644 index 0000000..d815c8e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/package.html @@ -0,0 +1,64 @@ + + + + + + This package contains Modules for working with + Yahoo! Weather. + +

      Example usage:

      +

      Retrieving information from a feed: +

      +          SyndFeed feed = input.build( ... );
      +          YWeatherFeedModule yfeed = (YWeatherFeedModule) feed.getModule( YWeatherFeedModule.URI );
      +          System.out.println( yfeed.getLocation().getCity() );
      +          SyndEntry entry = (SyndEntry) feed.getEntries().get(0);
      +          YWeatherEntryModule yentry = (YWeatherEntryModule) entry.getModule( YWeatherEntryModule.URI );
      +          System.out.println( yentry.getForecasts()[0].getHigh();
      +      
      +

      +

      To add information to a feed, construct a YWeatherModuleImpl and cast it to + the appropriate interface: +

      +          SyndEntry entry = new SyndEntryImpl();
      +          YWeatherEntryModule yentry = new YWeatherModuleImpl();
      +          yentry.setCondition( Condition("Partly Cloudy", ConditionCode.PARTLY_CLOUDY, 65, new Date() ) );
      +          entry.getModules.add(yentry);
      +        
      +
      + * This library is provided under dual licenses.
      + * You may choose the terms of the Lesser General Public License or the Apache
      + * License at your discretion.
      + *
      + *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
      + *
      + *
      + * This library is free software; you can redistribute it and/or
      + * modify it under the terms of the GNU Lesser General Public
      + * License as published by the Free Software Foundation; either
      + * version 2.1 of the License, or (at your option) any later version.
      + *
      + * This library is distributed in the hope that it will be useful,
      + * but WITHOUT ANY WARRANTY; without even the implied warranty of
      + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      + * Lesser General Public License for more details.
      + *
      + * You should have received a copy of the GNU Lesser General Public
      + * License along with this library; if not, write to the Free Software
      + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      + *
      + *
      + * 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.
      +  
      + + \ No newline at end of file diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Astronomy.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Astronomy.java new file mode 100644 index 0000000..30f4399 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Astronomy.java @@ -0,0 +1,141 @@ +/* + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather.types; + +import java.io.Serializable; +import java.util.Date; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * Forecast information about current astronomical conditions. Attributes: + *
        + *
      • sunrise: today's sunrise time. The time is a string in a local time format of "h:mm am/pm", + * for example "7:02 am" (string)
      • + *
      • sunset today's sunset time. The time is a string in a local time format of "h:mm am/pm", for + * example "4:51 pm" (string)
      • + *
      + * + * @version $Id: Astronomy.java,v 1.2 2008/01/22 14:50:05 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public class Astronomy implements Serializable, Cloneable { + /** + * + */ + private static final long serialVersionUID = 1L; + private final EqualsBean equals = new EqualsBean(Astronomy.class, this); + private final ToStringBean toString = new ToStringBean(Astronomy.class, this); + private Date sunrise; + private Date sunset; + + /** + * Simple constructor. + */ + public Astronomy() { + super(); + } + + /** + * Constructs a new Astronomy object + * + * @param sunrise time of sunrise (from 0ms) + * @param sunset time of sunset (from 0ms) + */ + public Astronomy(final Date sunrise, final Date sunset) { + this.sunrise = sunrise; + this.sunset = sunset; + } + + @Override + public Object clone() { + return new Astronomy(getSunrise() != null ? new Date(getSunrise().getTime()) : null, getSunset() != null ? new Date(getSunset().getTime()) : null); + } + + @Override + public boolean equals(final Object o) { + return equals.equals(o); + } + + @Override + public int hashCode() { + return equals.hashCode(); + } + + @Override + public String toString() { + return toString.toString(); + } + + /** + * Time of sunrise + * + * @return ime of sunrise (from 0ms) + */ + public Date getSunrise() { + return sunrise; + } + + /** + * Time of sunrise + * + * @param sunrise ime of sunrise (from 0ms) + */ + public void setSunrise(final Date sunrise) { + this.sunrise = sunrise; + } + + /** + * Time of sunset + * + * @return time of sunset (from 0ms) + */ + public Date getSunset() { + return sunset; + } + + /** + * Time of sunset + * + * @param sunset time of sunset (from 0ms) + */ + public void setSunset(final Date sunset) { + this.sunset = sunset; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Atmosphere.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Atmosphere.java new file mode 100644 index 0000000..9ff349e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Atmosphere.java @@ -0,0 +1,242 @@ +/* + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * Forecast information about current atmospheric pressure, humidity, and visibility. Attributes: + *
        + *
      • humidity: humidity, in percent (integer)
      • + *
      • visibility, in the units specified by the distance attribute of the yweather:units element + * (mi or km). Note that the visibility is specified as the actual value * 100. For example, a + * visibility of 16.5 miles will be specified as 1650. A visibility of 14 kilometers will appear as + * 1400. (integer) [ A double here, and adjusted accordingly]
      • + *
      • pressure: barometric pressure, in the units specified by the pressure attribute of the + * yweather:units element (in or mb). (float).
      • + *
      • rising: state of the barometric pressure: steady (0), rising (1), or falling (2). (integer: + * 0, 1, 2)
      • + *
      + * + * @version $Id: Atmosphere.java,v 1.2 2008/01/22 14:50:05 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public class Atmosphere implements Serializable, Cloneable { + /** + * + */ + private static final long serialVersionUID = 1L; + private final EqualsBean equals = new EqualsBean(Atmosphere.class, this); + private final ToStringBean toString = new ToStringBean(Atmosphere.class, this); + private int humidity; + private double visibility; + private double pressure; + private PressureChange change; + + /** + * Simple constructor. + */ + public Atmosphere() { + super(); + } + + /** + * Constructs a new Atmosphere object + * + * @param humidity humidity, in percent + * @param visibility visibility distance (value beyond 1/100ths of a unit will be truncated) + * @param pressure barometric pressure + * @param change state of the barometric pressure + */ + public Atmosphere(final int humidity, final double visibility, final double pressure, final PressureChange change) { + super(); + this.humidity = humidity; + this.visibility = visibility; + this.pressure = pressure; + this.change = change; + } + + @Override + public boolean equals(final Object o) { + return equals.equals(o); + } + + @Override + public int hashCode() { + return equals.hashCode(); + } + + @Override + public String toString() { + return toString.toString(); + } + + /** + * Relative humidity + * + * @return humidity, in percent + */ + public int getHumidity() { + return humidity; + } + + /** + * Relative humidity + * + * @param humidity humidity, in percent + */ + public void setHumidity(final int humidity) { + this.humidity = humidity; + } + + /** + * Visibility distance + * + * @return distance + */ + public double getVisibility() { + return visibility; + } + + /** + * Visibility distance + * + * @param visibility distance (value beyond 1/100ths of a unit will be truncated) + */ + public void setVisibility(final double visibility) { + this.visibility = visibility; + } + + /** + * Barometric pressure + * + * @return pressure + */ + public double getPressure() { + return pressure; + } + + /** + * Barometric pressure + * + * @param pressure pressure + */ + public void setPressure(final double pressure) { + this.pressure = pressure; + } + + /** + * Change in pressure + * + * @return Atmosphere.PressureChange object + */ + public PressureChange getChange() { + return change; + } + + /** + * Change in pressure + * + * @param change PressureChange object + */ + public void setChange(final PressureChange change) { + this.change = change; + } + + @Override + public Object clone() { + return new Atmosphere(humidity, visibility, pressure, change); + } + + public static class PressureChange implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + public static final PressureChange RISING = new PressureChange(1, "rising"); + public static final PressureChange STEADY = new PressureChange(0, "steady"); + public static final PressureChange FALLING = new PressureChange(2, "falling"); + private final int code; + private final String text; + + private PressureChange(final int code, final String text) { + this.code = code; + this.text = text; + } + + @Override + public String toString() { + return "[ code: " + code + " (" + text + ")]"; + } + + /** + * The integer code for this chage state + * + * @return int code + */ + public int getCode() { + return code; + } + + /** + * Gets a PressureChange instance for this int code. + * + * @param code int code value + * @return PressureChange instance + * @throws RuntimeException if no 0, 1, or 2. + */ + public static PressureChange fromCode(final int code) { + switch (code) { + case 0: + return STEADY; + + case 1: + return RISING; + + case 2: + return FALLING; + + default: + throw new RuntimeException("Invalid pressure change code."); + } + } + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Condition.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Condition.java new file mode 100644 index 0000000..09eaf1e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Condition.java @@ -0,0 +1,192 @@ +/* + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather.types; + +import java.io.Serializable; +import java.util.Date; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * The current weather conditions. Attributes: + *
        + *
      • text: a textual description of conditions, for example, "Partly Cloudy" (string)
      • + *
      • code: the condition code for this forecast. You could use this code to choose a text + * description or image for the forecast. The possible values for this element are described in Condition Codes (integer)
      • + *
      • temp: the current temperature, in the units specified by the yweather:units element (integer) + *
      • + *
      • date: the current date and time for which this forecast applies. [ + * I believe this should be the time this condition information was captured] The date is + * in RFC822 Section 5 format, for example + * "Wed, 30 Nov 2005 1:56 pm PST" (string)
      • + *
      + * + * @version $Id: Condition.java,v 1.2 2008/01/22 14:50:05 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public class Condition implements Serializable, Cloneable { + /** + * + */ + private static final long serialVersionUID = 1L; + private final EqualsBean equals = new EqualsBean(Condition.class, this); + private final ToStringBean toString = new ToStringBean(Condition.class, this); + private String text; + private ConditionCode code; + private int temperature; + private Date date; + + /** + * Simple constructor + */ + public Condition() { + super(); + } + + /** + * Constructs a new Condition. + * + * @param text a textual description of conditions, for example, "Partly Cloudy" + * @param code the condition code for this forecast. + * @param temperature the current temperature + * @param date the current date and time + */ + public Condition(final String text, final ConditionCode code, final int temperature, final Date date) { + super(); + this.text = text; + this.code = code; + this.temperature = temperature; + this.date = date; + } + + /** + * Description of condition + * + * @return a textual description of conditions, for example, "Partly Cloudy" + */ + public String getText() { + return text; + } + + /** + * Description of condition + * + * @param text a textual description of conditions, for example, "Partly Cloudy" + */ + public void setText(final String text) { + this.text = text; + } + + /** + * Condition code + * + * @return condition code + */ + public ConditionCode getCode() { + return code; + } + + /** + * Condition code + * + * @param code Condition code + */ + public void setCode(final ConditionCode code) { + this.code = code; + } + + /** + * Current Temperature + * + * @return the current temperature + * @see Units + */ + public int getTemperature() { + return temperature; + } + + /** + * Current Temperature + * + * @param temperature the current temperature + * @see Units + */ + public void setTemperature(final int temperature) { + this.temperature = temperature; + } + + /** + * Date recorded + * + * @return the current date and time + */ + public Date getDate() { + return date; + } + + /** + * Date recorded + * + * @param date the current date and time + */ + public void setDate(final Date date) { + this.date = date; + } + + @Override + public boolean equals(final Object o) { + return equals.equals(o); + } + + @Override + public int hashCode() { + return equals.hashCode(); + } + + @Override + public String toString() { + return toString.toString(); + } + + @Override + public Object clone() { + return new Condition(text, code, temperature, date != null ? new Date(date.getTime()) : null); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/ConditionCode.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/ConditionCode.java new file mode 100644 index 0000000..4323ed5 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/ConditionCode.java @@ -0,0 +1,399 @@ +/* + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather.types; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import com.rometools.rome.feed.impl.EqualsBean; + +/** + *

      Condition Codes

      + * + *

      + * Condition codes are used in the yweather:forecast element to describe the current conditions. + *

      + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      CodeDescription
      0tornado
      1tropical storm
      2hurricane
      3severe thunderstorms
      4thunderstorms
      5mixed rain and snow
      6mixed rain and sleet
      7mixed snow and sleet
      8freezing drizzle
      9drizzle
      10freezing rain
      11showers
      12showers
      13snow flurries
      14light snow showers
      15blowing snow
      16snow
      17hail
      18sleet
      19dust
      20foggy
      21haze
      22smoky
      23blustery
      24windy
      25cold
      26cloudy
      27mostly cloudy (night)
      28mostly cloudy (day)
      29partly cloudy (night)
      30partly cloudy (day)
      31clear (night)
      32sunny
      33fair (night)
      34fair (day)
      35mixed rain and hail
      36hot
      37isolated thunderstorms
      38scattered thunderstorms
      39scattered thunderstorms
      40scattered showers
      41heavy snow
      42scattered snow showers
      43heavy snow
      44partly cloudy
      45thundershowers
      46snow showers
      47isolated thundershowers
      3200not available
      + * + * @version $Id: ConditionCode.java,v 1.2 2008/01/22 14:50:05 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public class ConditionCode implements Serializable { + + private static final long serialVersionUID = 1L; + + private transient static Map LOOKUP = new HashMap(); + public static final ConditionCode TORNADO = new ConditionCode(0, "tornado"); + public static final ConditionCode TROPICAL_STORM = new ConditionCode(1, "tropical storm"); + public static final ConditionCode HURRICANE = new ConditionCode(2, "hurricane"); + public static final ConditionCode SEVERE_THUNDERSTORMS = new ConditionCode(3, "severe thunderstorms"); + public static final ConditionCode THUNDERSTORMS = new ConditionCode(4, "thunderstorms"); + public static final ConditionCode MIXED_RAIN_AND_SNOW = new ConditionCode(5, "mixed rain and snow"); + public static final ConditionCode MIXED_RAIN_AND_SLEET = new ConditionCode(6, "mixed rain and sleet"); + public static final ConditionCode MIXED_SNOW_AND_SLEET = new ConditionCode(7, "mixed snow and sleet"); + public static final ConditionCode FREEZING_DRIZZLE = new ConditionCode(8, "freezing drizzle"); + public static final ConditionCode DRIZZLE = new ConditionCode(9, "drizzle"); + public static final ConditionCode FREEZING_RAIN = new ConditionCode(10, "freezing rain"); + public static final ConditionCode SHOWERS_LIGHT = new ConditionCode(11, "showers"); + public static final ConditionCode SHOWERS_HEAVY = new ConditionCode(12, "showers"); + public static final ConditionCode FLURRIES = new ConditionCode(13, "snow flurries"); + public static final ConditionCode LIGHT_SNOW_SHOWERS = new ConditionCode(14, "light snow showers"); + public static final ConditionCode BLOWING_SNOW = new ConditionCode(15, "blowing snow"); + public static final ConditionCode SNOW = new ConditionCode(16, "snow"); + public static final ConditionCode HAIL = new ConditionCode(17, "hail"); + public static final ConditionCode SLEET = new ConditionCode(18, "sleet"); + public static final ConditionCode DUST = new ConditionCode(19, "dust"); + public static final ConditionCode FOGGY = new ConditionCode(20, "foggy"); + public static final ConditionCode HAZE = new ConditionCode(21, "haze"); + public static final ConditionCode SMOKY = new ConditionCode(22, "smoky"); + public static final ConditionCode BLUSTERY = new ConditionCode(23, "blustery"); + public static final ConditionCode WINDY = new ConditionCode(24, "windy"); + public static final ConditionCode COLD = new ConditionCode(25, "cold"); + public static final ConditionCode CLOUDY = new ConditionCode(26, "cloudy"); + public static final ConditionCode MOSTLY_CLOUDY_NIGHT = new ConditionCode(27, "mostly cloudy (night)"); + public static final ConditionCode MOSTLY_CLOUDY_DAY = new ConditionCode(28, "mostly cloudy (day)"); + public static final ConditionCode PARTLY_CLOUDY_NIGHT = new ConditionCode(29, "partly cloudy (night)"); + public static final ConditionCode PARTLY_CLOUDY_DAY = new ConditionCode(30, "partly couldy (day)"); + public static final ConditionCode CLEAR_NIGHT = new ConditionCode(31, "clear (night)"); + public static final ConditionCode SUNNY = new ConditionCode(32, "sunny"); + public static final ConditionCode FAIR_NIGHT = new ConditionCode(33, "fair (night)"); + public static final ConditionCode FAIR_DAY = new ConditionCode(34, "fair (day)"); + public static final ConditionCode MIXED_RAIN_AND_HAIL = new ConditionCode(35, "mixed rain and hail"); + public static final ConditionCode HOT = new ConditionCode(36, "hot"); + public static final ConditionCode ISOLATED_THUNDERSTORMS = new ConditionCode(37, "isolated thunderstorms"); + public static final ConditionCode SCATTERED_THUNDERSTORMS_HEAVY = new ConditionCode(38, "scattered thunderstorms"); + public static final ConditionCode SCATTERED_THUNDERSTORMS_LIGHT = new ConditionCode(39, "scattered thunderstorms"); + public static final ConditionCode SCATTERED_SHOWERS = new ConditionCode(40, "scattered showers"); + public static final ConditionCode HEAVY_SNOW = new ConditionCode(41, "heavy snow"); + public static final ConditionCode SCATTERED_SNOW_SHOWERS = new ConditionCode(42, "scattered snow showers"); + public static final ConditionCode HEAVY_SNOW_WINDY = new ConditionCode(43, "heavy snow"); + public static final ConditionCode PARTLY_CLOUDY = new ConditionCode(44, "partly cloudy"); + public static final ConditionCode THUNDERSHOWERS = new ConditionCode(45, "thundershowers"); + public static final ConditionCode SHOW_SHOWERS = new ConditionCode(46, "snow showers"); + public static final ConditionCode ISLOATED_THUNDERSHOWERS = new ConditionCode(47, "isolated thundershowers"); + public static final ConditionCode NOT_AVAILABLE = new ConditionCode(3200, "not available"); + private final int code; + private final String description; + private transient EqualsBean equals = new EqualsBean(ConditionCode.class, this); + + private ConditionCode(final int code, final String description) { + this.code = code; + this.description = description; + + final Object old = ConditionCode.LOOKUP.put(new Integer(code), this); + + if (old != null) { + throw new RuntimeException("Duplicate condition code!"); + } + } + + /** + * The integer code for this condition + * + * @return int code value + */ + public int getCode() { + return code; + } + + /** + * Text description of condition (from the table at top of class) + * + * @return + */ + public String getDescription() { + return description; + } + + /** + * Returns a condition code instance for a given integer + * + * @param code integer code to search for + * @return a ConditionCode instance or null + */ + public static ConditionCode fromCode(final int code) { + return ConditionCode.LOOKUP.get(new Integer(code)); + } + + @Override + public boolean equals(final Object o) { + return equals.equals(o); + } + + @Override + public int hashCode() { + return equals.hashCode(); + } + + @Override + public String toString() { + return "[Condition code:" + code + " description:" + description + "]"; + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Forecast.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Forecast.java new file mode 100644 index 0000000..a219fb6 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Forecast.java @@ -0,0 +1,244 @@ +/* + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather.types; + +import java.io.Serializable; +import java.util.Date; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * The weather forecast for a specific day. The item element contains multiple forecast elements for + * today and tomorrow. Attributes: + *
        + *
      • day: day of the week to which this forecast applies. Possible values are Mon Tue Wed Thu Fri + * Sat Sun (string)
      • + *
      • date: the date to which this forecast applies. The date is in "dd Mmm yyyy" format, for + * example "30 Nov 2005" (string)
      • + *
      • low: the forecasted low temperature for this day, in the units specified by the + * yweather:units element (integer)
      • + *
      • high: the forecasted high temperature for this day, in the units specified by the + * yweather:units element (integer)
      • + *
      • text: a textual description of conditions, for example, "Partly Cloudy" (string)
      • + * + *
      • code: the condition code for this forecast. You could use this code to choose a text + * description or image for the forecast. The possible values for this element are described in + * Condition Codes (integer)
      • + *
      + * + * @see ConditionCode + * @version $Id: Forecast.java,v 1.2 2008/01/22 14:50:05 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public class Forecast implements Serializable, Cloneable { + /** + * + */ + private static final long serialVersionUID = 1L; + private transient ToStringBean toString = new ToStringBean(Forecast.class, this); + private transient EqualsBean equals = new EqualsBean(Forecast.class, this); + private String day; + private Date date; + private int low; + private int high; + private String text; + private ConditionCode code; + + /** + * Simple constructor. + */ + public Forecast() { + super(); + } + + /** + * Constructs a new Forecast object. + * + * @param day day of the week to which this forecast applies. Possible values are Mon Tue Wed + * Thu Fri Sat Sun (string) + * @param date the date to which this forecast applies + * @param low the forecasted low temperature for this day + * @param high the forecasted high temperature for this day + * @param text a textual description of conditions, for example, "Partly Cloudy" + * @param code ConditionCode instance for this forcast. + */ + public Forecast(final String day, final Date date, final int low, final int high, final String text, final ConditionCode code) { + super(); + this.day = day; + this.date = date; + this.low = low; + this.high = high; + this.text = text; + this.code = code; + } + + /** + * Day of week + * + * @return day of the week to which this forecast applies. Possible values are Mon Tue Wed Thu + * Fri Sat Sun (string) + */ + public String getDay() { + return day; + } + + /** + * Day of week + * + * @param day day of the week to which this forecast applies. Possible values are Mon Tue Wed + * Thu Fri Sat Sun (string) + */ + public void setDay(final String day) { + this.day = day; + } + + /** + * For date. + * + * @return the date to which this forecast applies + */ + public Date getDate() { + return date; + } + + /** + * For date. + * + * @param date the date to which this forecast applies + */ + public void setDate(final Date date) { + this.date = date; + } + + /** + * Low temperature. + * + * @return the forecasted low temperature for this day + * @see Units + */ + public int getLow() { + return low; + } + + /** + * Low temperature + * + * @param low the forecasted low temperature for this day + * @see Units + */ + public void setLow(final int low) { + this.low = low; + } + + /** + * High temperature + * + * @return the forecasted high temperature for this day + * @see Units + */ + public int getHigh() { + return high; + } + + /** + * High temperature + * + * @param high the forecasted high temperature for this day + * @see Units + */ + public void setHigh(final int high) { + this.high = high; + } + + /** + * Text summary + * + * @return a textual description of conditions, for example, "Partly Cloudy" + */ + public String getText() { + return text; + } + + /** + * Text summary + * + * @param text a textual description of conditions, for example, "Partly Cloudy" + */ + public void setText(final String text) { + this.text = text; + } + + /** + * Condition code + * + * @return the condition code for this forecast + */ + public ConditionCode getCode() { + return code; + } + + /** + * Condition code + * + * @param code the condition code for this forecast + */ + public void setCode(final ConditionCode code) { + this.code = code; + } + + @Override + public boolean equals(final Object o) { + return equals.equals(o); + } + + @Override + public int hashCode() { + return equals.hashCode(); + } + + @Override + public String toString() { + return toString.toString(); + } + + @Override + public Object clone() { + return new Forecast(day, date != null ? new Date(date.getTime()) : null, low, high, text, code); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Location.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Location.java new file mode 100644 index 0000000..257fb78 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Location.java @@ -0,0 +1,161 @@ +/* + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * The location of this forecast. Attributes: + *
        + *
      • city: city name (string)
      • + *
      • region: state, territory, or region, if given (string)
      • + *
      • country: two-character country code. (string)
      • + *
      + * + * @version $Id: Location.java,v 1.2 2008/01/22 14:50:05 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public class Location implements Serializable, Cloneable { + /** + * + */ + private static final long serialVersionUID = 1L; + private transient ToStringBean toString = new ToStringBean(Location.class, this); + private transient EqualsBean equals = new EqualsBean(Location.class, this); + private String city; + private String region; + private String country; + + /** + * Simple constructor + */ + public Location() { + super(); + } + + /** + * Constructs a new Location object. + * + * @param city city name + * @param region state, territory, or region, if given + * @param country two-character country code. + */ + public Location(final String city, final String region, final String country) { + super(); + this.city = city; + this.region = region; + this.country = country; + } + + /** + * City name + * + * @return city name. + */ + public String getCity() { + return city; + } + + /** + * City name + * + * @param city city name + */ + public void setCity(final String city) { + this.city = city; + } + + /** + * state, territory, or region, if given + * + * @return state, territory, or region, if given + */ + public String getRegion() { + return region; + } + + /** + * state, territory, or region, if given + * + * @param region state, territory, or region, if given + */ + public void setRegion(final String region) { + this.region = region; + } + + /** + * country two-character country code. + * + * @return country two-character country code. + */ + public String getCountry() { + return country; + } + + /** + * country two-character country code. + * + * @param country country two-character country code. + */ + public void setCountry(final String country) { + this.country = country; + } + + @Override + public boolean equals(final Object o) { + return equals.equals(o); + } + + @Override + public int hashCode() { + return equals.hashCode(); + } + + @Override + public String toString() { + return toString.toString(); + } + + @Override + public Object clone() { + return new Location(city, region, country); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Units.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Units.java new file mode 100644 index 0000000..6552a01 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Units.java @@ -0,0 +1,189 @@ +/* + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * Units for various aspects of the forecast. Attributes: + *
        + *
      • temperature: degree units, f for Fahrenheit or c for Celsius (character)
      • + *
      • distance: units for distance, mi for miles or km for kilometers (string)
      • + *
      • pressure: units of barometric pressure, in for pounds per square inch or mb for millibars + * (string) [I am pretty sure this is wrong. + * I believe this number of be inches of Mercury, not PSI.]
      • + *
      • speed: units of speed, mph for miles per hour or kph for kilometers per hour (string)
      • + *
      + * Note that the default RSS feed uses Fahrenheit degree units and English units for all other + * attributes (miles, pounds per square inch, miles per hour). If Celsius has been specified as the + * degree units for the feed (using the u request parameter), all the units are in metric format + * (Celsius, kilometers, millibars, kilometers per hour). + * + * @version $Id: Units.java,v 1.2 2008/01/22 14:50:05 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public class Units implements Serializable, Cloneable { + /** + * + */ + private static final long serialVersionUID = 1L; + private transient ToStringBean toString = new ToStringBean(Units.class, this); + private transient EqualsBean equals = new EqualsBean(Units.class, this); + private String temperature; + private String distance; + private String pressure; + private String speed; + + /** + * Simple constructor. + */ + public Units() { + super(); + } + + /** + * Constructs a new Units object + * + * @param temperature units of temp ("f" or "c"); + * @param distance units of distance ("mi" or "km") + * @param pressure units of pressure ("in" or "mb") + * @param speed units of speed ("mph" or "kph") + */ + public Units(final String temperature, final String distance, final String pressure, final String speed) { + super(); + this.temperature = temperature; + this.distance = distance; + this.pressure = pressure; + this.speed = speed; + } + + /** + * Units of Temperature. + * + * @return temperature units of temp ("f" or "c"); + */ + public String getTemperature() { + return temperature; + } + + /** + * Units of Temperature. + * + * @param temperature units of temp ("f" or "c"); + */ + public void setTemperature(final String temperature) { + this.temperature = temperature; + } + + /** + * Units of distance + * + * @return distance units of distance ("mi" or "km") + */ + public String getDistance() { + return distance; + } + + /** + * Units of distance + * + * @param distance units of distance ("mi" or "km") + */ + public void setDistance(final String distance) { + this.distance = distance; + } + + /** + * Units of pressure + * + * @return units of pressure ("in" or "mb") + */ + public String getPressure() { + return pressure; + } + + /** + * Units of pressure + * + * @param pressure units of pressure ("in" or "mb") + */ + public void setPressure(final String pressure) { + this.pressure = pressure; + } + + /** + * Units of speed + * + * @return units of speed ("mph" or "kph") + */ + public String getSpeed() { + return speed; + } + + /** + * Units of speed + * + * @param speed units of speed ("mph" or "kph") + */ + public void setSpeed(final String speed) { + this.speed = speed; + } + + @Override + public boolean equals(final Object o) { + return equals.equals(o); + } + + @Override + public int hashCode() { + return equals.hashCode(); + } + + @Override + public String toString() { + return toString.toString(); + } + + @Override + public Object clone() { + return new Units(temperature, distance, pressure, speed); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Wind.java b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Wind.java new file mode 100644 index 0000000..04235cf --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/Wind.java @@ -0,0 +1,171 @@ +/* + * + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2008 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.yahooweather.types; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * Units for various aspects of the forecast. Attributes: + *
        + *
      • temperature: degree units, f for Fahrenheit or c for Celsius (character)
      • + *
      • distance: units for distance, mi for miles or km for kilometers (string)
      • + *
      • pressure: units of barometric pressure, in for pounds per square inch or mb for millibars + * (string)
      • + *
      • speed: units of speed, mph for miles per hour or kph for kilometers per hour (string)
      • + *
      + * Note that the default RSS feed uses Fahrenheit degree units and English units for all other + * attributes (miles, pounds per square inch, miles per hour). If Celsius has been specified as the + * degree units for the feed (using the u request parameter), all the units are in metric format + * (Celsius, kilometers, millibars, kilometers per hour). + * + * @version $Id: Wind.java,v 1.2 2008/01/22 14:50:05 kebernet Exp $ + * @author Robert "kebernet" Cooper + */ +public class Wind implements Serializable, Cloneable { + /** + * + */ + private static final long serialVersionUID = 1L; + private transient ToStringBean toString = new ToStringBean(Wind.class, this); + private transient EqualsBean equals = new EqualsBean(Wind.class, this); + private int chill; + private int direction; + private int speed; + + /** + * Simple Constructor + */ + public Wind() { + super(); + } + + /** + * Constructs a new Wind object + * + * @param chill wind chill adjusted temperature + * @param direction direction of wind in degrees + * @param speed speed of wind + */ + public Wind(final int chill, final int direction, final int speed) { + super(); + this.chill = chill; + this.direction = direction; + this.speed = speed; + } + + @Override + public boolean equals(final Object o) { + return equals.equals(o); + } + + @Override + public int hashCode() { + return equals.hashCode(); + } + + @Override + public String toString() { + return toString.toString(); + } + + /** + * Wind chill adjusted temperature. + * + * @return int temperature value + * @see Units + */ + public int getChill() { + return chill; + } + + /** + * Wind chill adjusted temperature. + * + * @param chill int temperature value + * @see Units + */ + public void setChill(final int chill) { + this.chill = chill; + } + + /** + * Direction of wind in degrees + * + * @return int direction of wind. + */ + public int getDirection() { + return direction; + } + + /** + * Direction of wind in degrees + * + * @param direction int direction of wind. + */ + public void setDirection(final int direction) { + this.direction = direction; + } + + /** + * Speed of wind + * + * @return int speed of wind + * @see Units + */ + public int getSpeed() { + return speed; + } + + /** + * Speed of wind + * + * @param speed int speed of wind + * @see Units + */ + public void setSpeed(final int speed) { + this.speed = speed; + } + + @Override + public Object clone() { + return new Wind(chill, direction, speed); + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/package.html b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/package.html new file mode 100644 index 0000000..6f5939f --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/yahooweather/types/package.html @@ -0,0 +1,43 @@ + + + + + + This package contains data types use with the YWeatherModules. +
      + * This library is provided under dual licenses.
      + * You may choose the terms of the Lesser General Public License or the Apache
      + * License at your discretion.
      + *
      + *  Copyright (C) 2005  Robert Cooper, Temple of the Screaming Penguin
      + *
      + *
      + * This library is free software; you can redistribute it and/or
      + * modify it under the terms of the GNU Lesser General Public
      + * License as published by the Free Software Foundation; either
      + * version 2.1 of the License, or (at your option) any later version.
      + *
      + * This library is distributed in the hope that it will be useful,
      + * but WITHOUT ANY WARRANTY; without even the implied warranty of
      + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      + * Lesser General Public License for more details.
      + *
      + * You should have received a copy of the GNU Lesser General Public
      + * License along with this library; if not, write to the Free Software
      + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      + *
      + *
      + * 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.
      +  
      + + \ No newline at end of file diff --git a/rome-modules/src/main/resources/com/rometools/modules/base/io/tags.properties b/rome-modules/src/main/resources/com/rometools/modules/base/io/tags.properties new file mode 100644 index 0000000..1004239 --- /dev/null +++ b/rome-modules/src/main/resources/com/rometools/modules/base/io/tags.properties @@ -0,0 +1,91 @@ +# properties to tagnames +pickup=pickup +expirationDate=expiration_date +publishDate=publish_date +year=year +courseDateRange=course_date_range +eventDateRange=event_date_range +travelDateRange=travel_date_range +propertyTypes=property_type +bathrooms=bathrooms +hoaDues=hoa_dues +rating=rating +salary=salary +taxPercent=taxPercent +deliveryRadius=delivery_radius +megapixels=megapixels +memory=memory +price=price +processorSpeed=processor_speed +gender=gender +area=area +age=age +bedrooms=bedrooms +pages=pages +quantity=quantity +toLocation=to_location +fromLocation=from_location +priceType=price_type +salaryType=salary_type +size=size +sexualOrientation=sexual_orientation +apparelType=apparel_type +brand=brand +condition=condition +courseNumber=course_number +courseTimes=course_times +currency=currency +deliveryNotes=delivery_notes +education=education +employer=employer +id=id +immigrationStatus=immigration_status +isbn=isbn +make=make +manufacturer=manufacturer +manufacturerId=manufacturer_id +maritalStatus=marital_status +model=model +nameOfItemBeingReviewed=name_of_item_being_reviewed +newsSource=news_source +occupation=occupation +publicationName=publication_name +publicationVolume=publication_volume +reviewType=review_type +reviewerType=reviewer_type +schoolDistrict=school_district +serviceType=service_type +taxRegion=tax_region +taxPercent=tax_percent +upc=upc +vehicleType=vehicle_type +urlOfItemBeingReviewed=url_of_item_being_reviewed +actors=actor +agents=agent +artists=artist +authors=author +colors=color +ethnicities=ethnicity +imageLinks=image_link +interestedIn=interested_in +jobFunctions=job_function +jobIndustries=job_industry +jobTypes=job_type +labels=label +location=location +listingType=listing_type +paymentAccepted=payment_accepted +paymentNotes=payment_notes +productTypes=product_type +programmingLanguages=programming_language +relatedLinks=related_link +shipping=shipping +squareFootages=square_footage +subjectAreas=subject_area +subjects=subject +university=university +operatingSystems=operating_systems +weight=weight +modelNumber=model_number +mileage=mileage +vin=vin diff --git a/rome-modules/src/main/resources/rome.properties b/rome-modules/src/main/resources/rome.properties new file mode 100644 index 0000000..513157d --- /dev/null +++ b/rome-modules/src/main/resources/rome.properties @@ -0,0 +1,157 @@ +WireFeedParser.classes=com.rometools.modules.mediarss.io.RSS20YahooParser + +rss_2.0.feed.ModuleParser.classes=com.rometools.modules.cc.io.ModuleParserRSS2 \ + com.rometools.modules.content.io.ContentModuleParser \ + com.rometools.modules.itunes.io.ITunesParser \ + com.rometools.modules.mediarss.io.MediaModuleParser \ + com.rometools.modules.opensearch.impl.OpenSearchModuleParser \ + com.rometools.modules.georss.SimpleParser \ + com.rometools.modules.georss.W3CGeoParser \ + com.rometools.modules.photocast.io.Parser \ + com.rometools.modules.mediarss.io.MediaModuleParser \ + com.rometools.modules.atom.io.AtomModuleParser \ + com.rometools.modules.itunes.io.ITunesParserOldNamespace \ + com.rometools.modules.mediarss.io.AlternateMediaModuleParser \ + com.rometools.modules.sle.io.ModuleParser \ + com.rometools.modules.yahooweather.io.WeatherModuleParser + +rss_1.0.feed.ModuleParser.classes=com.rometools.modules.cc.io.ModuleParserRSS1 \ + com.rometools.modules.content.io.ContentModuleParser + +atom_0.3.feed.ModuleParser.classes=com.rometools.modules.cc.io.ModuleParserRSS2 \ + com.rometools.modules.opensearch.impl.OpenSearchModuleParser \ + com.rometools.modules.georss.SimpleParser \ + com.rometools.modules.georss.W3CGeoParser \ + com.rometools.modules.photocast.io.Parser \ + com.rometools.modules.mediarss.io.MediaModuleParser \ + com.rometools.modules.mediarss.io.AlternateMediaModuleParser + +atom_1.0.feed.ModuleParser.classes=com.rometools.modules.cc.io.ModuleParserRSS2 \ + com.rometools.modules.opensearch.impl.OpenSearchModuleParser \ + com.rometools.modules.georss.SimpleParser \ + com.rometools.modules.georss.W3CGeoParser \ + com.rometools.modules.photocast.io.Parser \ + com.rometools.modules.mediarss.io.MediaModuleParser \ + com.rometools.modules.mediarss.io.AlternateMediaModuleParser + +rss_2.0.item.ModuleParser.classes=com.rometools.modules.cc.io.ModuleParserRSS2 \ + com.rometools.modules.base.io.GoogleBaseParser \ + com.rometools.modules.content.io.ContentModuleParser \ + com.rometools.modules.slash.io.SlashModuleParser \ + com.rometools.modules.itunes.io.ITunesParser \ + com.rometools.modules.mediarss.io.MediaModuleParser \ + com.rometools.modules.atom.io.AtomModuleParser \ + com.rometools.modules.opensearch.impl.OpenSearchModuleParser \ + com.rometools.modules.georss.SimpleParser \ + com.rometools.modules.georss.W3CGeoParser \ + com.rometools.modules.photocast.io.Parser \ + com.rometools.modules.itunes.io.ITunesParserOldNamespace \ + com.rometools.modules.mediarss.io.AlternateMediaModuleParser \ + com.rometools.modules.sle.io.ItemParser \ + com.rometools.modules.yahooweather.io.WeatherModuleParser + +rss_1.0.item.ModuleParser.classes=com.rometools.modules.cc.io.ModuleParserRSS1 \ + com.rometools.modules.base.io.GoogleBaseParser \ + com.rometools.modules.base.io.CustomTagParser \ + com.rometools.modules.content.io.ContentModuleParser \ + com.rometools.modules.slash.io.SlashModuleParser + +atom_0.3.item.ModuleParser.classes=com.rometools.modules.cc.io.ModuleParserRSS2 \ + com.rometools.modules.base.io.GoogleBaseParser \ + com.rometools.modules.base.io.CustomTagParser \ + com.rometools.modules.slash.io.SlashModuleParser \ + com.rometools.modules.opensearch.impl.OpenSearchModuleParser \ + com.rometools.modules.georss.SimpleParser \ + com.rometools.modules.georss.W3CGeoParser \ + com.rometools.modules.photocast.io.Parser \ + com.rometools.modules.mediarss.io.MediaModuleParser \ + com.rometools.modules.mediarss.io.AlternateMediaModuleParser + +atom_1.0.item.ModuleParser.classes=com.rometools.modules.cc.io.ModuleParserRSS2 \ + com.rometools.modules.base.io.GoogleBaseParser \ + com.rometools.modules.base.io.CustomTagParser \ + com.rometools.modules.slash.io.SlashModuleParser \ + com.rometools.modules.opensearch.impl.OpenSearchModuleParser \ + com.rometools.modules.georss.SimpleParser \ + com.rometools.modules.georss.W3CGeoParser \ + com.rometools.modules.photocast.io.Parser \ + com.rometools.modules.mediarss.io.MediaModuleParser \ + com.rometools.modules.mediarss.io.AlternateMediaModuleParser \ + com.rometools.modules.thr.io.ThreadingModuleParser + +rss_2.0.feed.ModuleGenerator.classes=com.rometools.modules.cc.io.CCModuleGenerator \ + com.rometools.modules.content.io.ContentModuleGenerator \ + com.rometools.modules.itunes.io.ITunesGenerator \ + com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator \ + com.rometools.modules.georss.SimpleGenerator \ + com.rometools.modules.georss.W3CGeoGenerator \ + com.rometools.modules.photocast.io.Generator \ + com.rometools.modules.mediarss.io.MediaModuleGenerator \ + com.rometools.modules.atom.io.AtomModuleGenerator \ + com.rometools.modules.sle.io.ModuleGenerator \ + com.rometools.modules.yahooweather.io.WeatherModuleGenerator + +rss_1.0.feed.ModuleGenerator.classes=com.rometools.modules.content.io.ContentModuleGenerator + +atom_0.3.feed.ModuleGenerator.classes=com.rometools.modules.cc.io.CCModuleGenerator \ + com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator \ + com.rometools.modules.georss.SimpleGenerator \ + com.rometools.modules.georss.W3CGeoGenerator \ + com.rometools.modules.photocast.io.Generator \ + com.rometools.modules.mediarss.io.MediaModuleGenerator + +atom_1.0.feed.ModuleGenerator.classes=com.rometools.modules.cc.io.CCModuleGenerator \ + com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator \ + com.rometools.modules.georss.SimpleGenerator \ + com.rometools.modules.georss.W3CGeoGenerator \ + com.rometools.modules.photocast.io.Generator \ + com.rometools.modules.mediarss.io.MediaModuleGenerator + +rss_2.0.item.ModuleGenerator.classes=com.rometools.modules.cc.io.CCModuleGenerator \ + com.rometools.modules.base.io.GoogleBaseGenerator \ + com.rometools.modules.base.io.CustomTagGenerator \ + com.rometools.modules.content.io.ContentModuleGenerator \ + com.rometools.modules.slash.io.SlashModuleGenerator \ + com.rometools.modules.itunes.io.ITunesGenerator \ + com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator \ + com.rometools.modules.georss.SimpleGenerator \ + com.rometools.modules.georss.W3CGeoGenerator \ + com.rometools.modules.photocast.io.Generator \ + com.rometools.modules.mediarss.io.MediaModuleGenerator \ + com.rometools.modules.atom.io.AtomModuleGenerator \ + com.rometools.modules.yahooweather.io.WeatherModuleGenerator + +rss_1.0.item.ModuleGenerator.classes=com.rometools.modules.base.io.GoogleBaseGenerator \ + com.rometools.modules.content.io.ContentModuleGenerator \ + com.rometools.modules.slash.io.SlashModuleGenerator + +atom_0.3.item.ModuleGenerator.classes=com.rometools.modules.cc.io.CCModuleGenerator \ + com.rometools.modules.base.io.GoogleBaseGenerator \ + com.rometools.modules.base.io.CustomTagGenerator \ + com.rometools.modules.slash.io.SlashModuleGenerator \ + com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator \ + com.rometools.modules.georss.SimpleGenerator \ + com.rometools.modules.georss.W3CGeoGenerator \ + com.rometools.modules.photocast.io.Generator \ + com.rometools.modules.mediarss.io.MediaModuleGenerator + +atom_1.0.item.ModuleGenerator.classes=com.rometools.modules.cc.io.CCModuleGenerator \ + com.rometools.modules.base.io.CustomTagGenerator \ + com.rometools.modules.slash.io.SlashModuleGenerator \ + com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator \ + com.rometools.modules.georss.SimpleGenerator \ + com.rometools.modules.georss.W3CGeoGenerator \ + com.rometools.modules.photocast.io.Generator \ + com.rometools.modules.mediarss.io.MediaModuleGenerator \ + com.rometools.modules.thr.io.ThreadingModuleGenerator + +rss_2.0wNS.feed.ModuleParser.classes=com.rometools.modules.mediarss.io.MediaModuleParser +rss_2.0wNS.item.ModuleParser.classes=com.rometools.modules.mediarss.io.MediaModuleParser +rss_2.0yahoo.feed.ModuleParser.classes=com.rometools.modules.mediarss.io.MediaModuleParser +rss_2.0yahoo.item.ModuleParser.classes=com.rometools.modules.mediarss.io.MediaModuleParser + +rss_2.0wNS.feed.ModuleGenerator.classes=com.rometools.modules.mediarss.io.MediaModuleGenerator +rss_2.0wNS.item.ModuleGenerator.classes=com.rometools.modules.mediarss.io.MediaModuleGenerator +rss_2.0yahoo.feed.ModuleGenerator.classes=com.rometools.modules.mediarss.io.MediaModuleGenerator +rss_2.0yahoo.item.ModuleGenerator.classes=com.rometools.modules.mediarss.io.MediaModuleGenerator + diff --git a/rome-modules/src/site/apt/A9OpenSearch.apt b/rome-modules/src/site/apt/A9OpenSearch.apt new file mode 100644 index 0000000..e29999a --- /dev/null +++ b/rome-modules/src/site/apt/A9OpenSearch.apt @@ -0,0 +1,52 @@ + ----- + A9 OpenSearch + ----- + mkurz + ----- + 2011-08-16 05:25:45.000 + ----- + +A9 OpenSearch + + This plug in is for use with {{{http://www.opensearch.org/}OpenSearch.org}} results. + + The latest version is 0.1 available. + +*Sample Usage + ++------+ +SyndFeed feed = new SyndFeedImpl(); +feed.setFeedType(feedType); + +// Add the opensearch module, you would get information like totalResults from the +// return results of your search +List mods = feed.getModules(); +OpenSearchModule osm = new OpenSearchModuleImpl(); +osm.setItemsPerPage(1); +osm.setStartIndex(1); +osm.setTotalResults(1024); +osm.setItemsPerPage(50); + +OSQuery query = new OSQuery(); +query.setRole("superset"); +query.setSearchTerms("Java Syndication"); +query.setStartPage(1); +osm.addQuery(query); + +Link link = new Link(); +link.setHref("http://www.bargainstriker.com/opensearch-description.xml"); +link.setType("application/opensearchdescription+xml"); +osm.setLink(link); + +mods.add(osm); + +feed.setModules(mods); +// end add module ++------+ + +*Changes + +**0.1 + + Initial move to the ROME project. + diff --git a/rome-modules/src/site/apt/Content.apt b/rome-modules/src/site/apt/Content.apt new file mode 100644 index 0000000..d3b0a77 --- /dev/null +++ b/rome-modules/src/site/apt/Content.apt @@ -0,0 +1,32 @@ + ----- + Content + ----- + mkurz + ----- + 2011-08-16 05:18:31.894 + ----- + +Content + + This plug in is for use content:encoded in feeds. + + The latest version is 0.4 available. + +*Sample Usage + ++------+ +SyndFeedInput input = new SyndFeedInput(); +SyndFeed syndfeed = input.build(new XmlReader(feed.toURL())); + +Module module = syndfeed.getModule("http://purl.org/rss/1.0/modules/content/"); +ContentModule content = (ContentModule) module; + +Iterator it = content.getEncodeds().iterator(); +System.out.println( it.next() ); ++------+ + +*Changes + +**0.4 + + Initial move to the ROME project. diff --git a/rome-modules/src/site/apt/CreativeCommons.apt b/rome-modules/src/site/apt/CreativeCommons.apt new file mode 100644 index 0000000..b090dfc --- /dev/null +++ b/rome-modules/src/site/apt/CreativeCommons.apt @@ -0,0 +1,36 @@ + ----- + Creative Commons + ----- + mkurz + ----- + 2011-08-16 05:19:51.376 + ----- + +Creative Commons + + This plug in is for use with feeds from Creative Commons license. + + This module provides a unified rights and license system for both the RSS2/Atom and RSS/RDF namespace. However, if you wish to <> RDF/RSS feeds, you need to use a CVS build of ROME (or a version higher than 0.8). + + The latest version is 0.2 available. + +*Sample Usage + ++------+ +CreativeCommons commons = new CreativeCommonsImpl(); +commons.setLicense( new License[]{ License.NONCOMMERCIAL } ); +// Note, you do not have to setAllLicenses right now. When the RSS1 functionality is +// added, this will be required at the Feed level only. +ArrayList modules = new ArrayList() +modules.add( commons ); +syndEntry.setModules( commons ); + +//Alternately, to get the module: +CreativeCommons commons = (CreativeCommons) syndFeed.getModule( CreativeCommons.URI ); ++------+ + +*Changes + +**0.2 + + Initial release from ROME. diff --git a/rome-modules/src/site/apt/GeoRSS.apt b/rome-modules/src/site/apt/GeoRSS.apt new file mode 100644 index 0000000..5b1e4bd --- /dev/null +++ b/rome-modules/src/site/apt/GeoRSS.apt @@ -0,0 +1,46 @@ + ----- + GeoRSS + ----- + mkurz + ----- + 2011-08-16 05:15:01.880 + ----- + +GeoRSS + + This Rome plugin is for adding location information to RSS/Atom. + + The latest version is 0.1 available. + +*Sample Usage + ++------+ +SyndFeedInput input = new SyndFeedInput(); +SyndFeed feed = input.build(new XmlReader(new URL("http://www.geonames.org/recent-changes.xml"))); + +List; entries = feed.getEntries(); +for (SyndEntry entry : entries) { + GeoRSSModule geoRSSModule = GeoRSSUtils.getGeoRSS(entry); + System.out.println(entry.getTitle() + " : lat=" + + geoRSSModule.getLatitude() + ",lng=" + + geoRSSModule.getLongitude() + ", desc=" + + entry.getDescription().getValue() + "; time=" + + entry.getPublishedDate()); + } + +//to generate a GeoRSS item + +GeoRSSModule geoRSSModule = new W3CGeoModuleImpl(); +//GeoRSSModule geoRSSModule = new SimpleModuleImpl(); +geoRSSModule.setLatitude(47.0); +geoRSSModule.setLongitude(9.0); +entry.getModules().add(geoRSSModule); ++------+ + + More information here: {{{http://georss.geonames.org/}http://georss.geonames.org/}} + +*Changes + +**0.1 + + Initial Releas from ROME diff --git a/rome-modules/src/site/apt/GoogleBase.apt b/rome-modules/src/site/apt/GoogleBase.apt new file mode 100644 index 0000000..0703428 --- /dev/null +++ b/rome-modules/src/site/apt/GoogleBase.apt @@ -0,0 +1,37 @@ + ----- + Google Base + ----- + mkurz + ----- + 2011-08-16 05:17:31.435 + ----- + +Google Base + + This plug in is for use with Google Base RSS/Atom Extensions + + The latest version is 0.2 available. + +*Sample Usage + ++------+ +SyndEntry entry = new SyndEntryImpl(); +// set up the entry... +Vehicle vehicle = new GoogleBaseImpl(); +vehicle.setMake("Honda"); +vehicle.setModel("Insight"); +vehicle.setYear( new Year("2000")); +List modules = new ArrayList(); +modules.add( vehicle ); +entry.setModules( modules ); + +//Optionally, to get Google Base information from a Feed: +Article article = entry.getModule( "http://base.google.com/ns/1.0" ); +System.out.println( article.getPages() ); ++------+ + +*Changes + +**0.2 + + Initial release from ROME project. diff --git a/rome-modules/src/site/apt/IPhotoPhotocasting.apt b/rome-modules/src/site/apt/IPhotoPhotocasting.apt new file mode 100644 index 0000000..003a21b --- /dev/null +++ b/rome-modules/src/site/apt/IPhotoPhotocasting.apt @@ -0,0 +1,46 @@ + ----- + iPhoto Photocasting + ----- + mkurz + ----- + 2011-08-16 05:24:08.864 + ----- + +iPhoto Photocasting + + This plug in is for use with iPhoto Photocast listings. + + This module will read and write photocast feeds "properly". Be advised, however, that an iPhoto photocast feed will not pass a FeedValidator test as they are not properly namespaced. If you are wanting to publish, rather than read, consider using the {{{./MediaRSS.html}MediaRSS (modules)}} plug in instead. iPhoto will also read {{{./MediaRSS.html}MediaRSS (modules)}} (Flickr Photostream) feeds as well. + + The latest version is 0.2 available. + +*Sample Usage + ++------+ +SyndFeed feed = input.build( new File( "/foo.rss" ) ) ); +List entries = feed.getEntries(); +for( int i =0; i < entries.size() ; i++ ){ + System.out.println( ((SyndEntry)entries.get(i)).getModule( PhotocastModule.URI ) ); +} + +// or to create a photocast module: + +SyndFeed myFeed = new SyndFeedImpl(); +myFeed.getModules().add( new PhotocastModuleImpl() ); +// you need this as a placeholder so the version gets in the feed. + +SyndEntry myEntry = new SyndEntryImpl(); +PhotocastModule pm = new PhotocastModuleImpl(); +pm.setUrl( new URL("http://foo.com/img.jpg" ) ); +pm.setThumnail( new URL("http://foo.com/img-small.jpg" ) ); +pm.setCropDate( new Date() ); +pm.setPhotoDate( new Date() ); +pm.setMetaData( new PhotoDate(), "Some comments that I think always get ignored." ); +myEntry.getModules().add( pm ); ++------+ + +*Changes: + +**0.2 + + Initial move to the ROME project. diff --git a/rome-modules/src/site/apt/ITunesPodcasting.apt b/rome-modules/src/site/apt/ITunesPodcasting.apt new file mode 100644 index 0000000..2ad4dd4 --- /dev/null +++ b/rome-modules/src/site/apt/ITunesPodcasting.apt @@ -0,0 +1,49 @@ + ----- + iTunes Podcasting + ----- + mkurz + ----- + 2011-08-16 05:12:32.907 + ----- + +iTunes Podcasting + + This plug in is for use with iTunes Music Service podcast listings. + + The latest version is 0.4 available. + +*Sample Usage + ++------+ +SyndFeedInput input = new SyndFeedInput(); +SyndFeed syndfeed = input.build(new XmlReader(feed.toURL())); + +Module module = syndfeed.getModule("http://www.itunes.com/dtds/podcast-1.0.dtd"); +FeedInformation feedInfo = (FeedInformation) module; + +System.out.println( feedInfo.getImage() ); +System.out.println( feedInfo.getCategory() ); + +// Or to create a feed.. + +ArrayList modules = new ArrayList(); +EntryInformation e = new EntryInformationImpl(); +e.setDuration( new Duration( 10000 ) ); +modules.add( e ); +syndEntry.setModules( modules ); ++------+ + +*Changes + +**0.4 + + * Corrected some Feed vs Item attribute issue. + + * Keywords now comma separated instead of space. + + [] + +**0.3 + + * Added support for the "other" case of podcasts. It will now correctly parse all lowercase URIs as wells as the original mixed case URIs All generated feeds + use the lowercase URI. Fixed some entity problems related to the apple summary tag. diff --git a/rome-modules/src/site/apt/MediaRSS.apt b/rome-modules/src/site/apt/MediaRSS.apt new file mode 100644 index 0000000..638fd3a --- /dev/null +++ b/rome-modules/src/site/apt/MediaRSS.apt @@ -0,0 +1,48 @@ + ----- + MediaRSS + ----- + mkurz + ----- + 2011-10-18 05:47:39.741 + ----- + +MediaRSS + + This plugin is for use with Yahoo! MediaRSS/Flickr Photostreams + + The latest version is 0.1 available. + +*Sample Usage + ++------+ +SyndFeed feed = input.build( myRSSFile ); +List entries = feed.getEntries(); +for( int i = 0; i < entries.size(); i++ ){ + System.out.println( ((SyndEntry) entries.get(i)).getModule( MediaModule.URI ) ); +} + +//Alternatively, to add a media item to an entry: + +MediaContent[] contents = new MediaContent[1]; +MediaContent myItem = new MediaContent( new UrlReference("http://me.com/movie.mpg") ); +contents[0] = myItem(); +Metadata md = new Metadata(); +Thumbnail[] thumbs = new Thumbnail[2]; +thumbs[0] = new Thumbnail( new URL("http://me.com/movie1.jpg") ); +thumbs[1] = new Thumbnail( new URL("http://me.com/movie2.jpg") ); +md.setThumbnail( thumbs ); +myItem.setMetadata( md ); +MediaEntryModuleImpl module = new MediaEntryModuleImpl(); +module.setMediaContents( contents ); +mySyndEntry.getModules().add( module ); ++------+ + +*Changes + +**0.2.1 + + Bugfix for metadata on MediaGroups. + +**0.1 + + Initial release from ROME. diff --git a/rome-modules/src/site/apt/MicrosoftSimpleListExtensions.apt b/rome-modules/src/site/apt/MicrosoftSimpleListExtensions.apt new file mode 100644 index 0000000..a15db75 --- /dev/null +++ b/rome-modules/src/site/apt/MicrosoftSimpleListExtensions.apt @@ -0,0 +1,47 @@ + ----- + Microsoft Simple List Extensions + ----- + mkurz + ----- + 2011-08-16 05:27:04.351 + ----- + +Microsoft Simple List Extensions + + This plug in is for use with feeds ith Microsoft Simple List Extensions. + + Note you need to use the current CVS version of ROME or 0.9 when available. + + The latest version is 0.1 available. + +*Sample Usage + ++------+ +SimpleListExtension sle = (SimpleListExtension) feed.getModule( SimpleListExtension.URI ); +System.out.println( sle ); +Group[] groups = sle.getGroupFields(); +System.out.println( groups[0].getLabel() ); + +//You can use the SleUtility class to do sorting and grouping: + +List sortedEntries = SleUtility.sort( feed.getEntries(), sle.getSortFields()[1], true ); +SyndEntry entry = (SyndEntry) sortedEntries.get( 0 ); + +//You can also Group or Sort and Group + +List sortedAndGroupedEntries = SleUtility.sortAndGroup( feed.getEntries, sle.getGroupFields(), sle.getSortFields()[0], false ); + +// If you change, for instance, module values on a feed and want to reinitialize it for +// grouping and sorting... + +SleUtility.initializeForSorting( feed ); + +// Be aware, this is a VERY heavy operation and should not be used frequently. ++------+ + +*Changes + +**0.1 + + Initial release from ROME. + diff --git a/rome-modules/src/site/apt/MicrosoftSimpleSharingExtensions.apt b/rome-modules/src/site/apt/MicrosoftSimpleSharingExtensions.apt new file mode 100644 index 0000000..3db19cf --- /dev/null +++ b/rome-modules/src/site/apt/MicrosoftSimpleSharingExtensions.apt @@ -0,0 +1,37 @@ + ----- + Microsoft Simple Sharing Extensions + ----- + mkurz + ----- + 2011-08-16 05:28:45.289 + ----- + +Microsoft Simple Sharing Extensions + + This ROME module supports Microsoft Simple Sharing Extensions, an RSS and {{{../opml/index.html}OPML}} extension designed to support data synchronization between bi\-directional feeds. + + The latest version is 0.1 available. + +*Sample Usage + ++------+ +SyndFeedInput input = new SyndFeedInput(); +SyndFeed syndfeed = input.build(new XmlReader(feed.toURL())); + +List entries = syndfeed.getEntries(); +Iterator it = entries.iterator(); + +for (int id = 101; it.hasNext() && id <= 113; id++) { + SyndEntry entry = (SyndEntry) it.next(); + Sync sync = (Sync) entry.getModule(SSEModule.SSE_SCHEMA_URI); + assertEquals(String.valueOf(id), sync.getId()); + + History history = sync.getHistory(); + assertNotNull(history); + + Date when = history.getWhen(); + assertNotNull(when); + Date testDate = DateParser.parseRFC822("Fri, 6 Jan 2006 19:24:09 GMT"); + assertEquals(testDate, when); +} ++------+ diff --git a/rome-modules/src/site/apt/Slash.apt b/rome-modules/src/site/apt/Slash.apt new file mode 100644 index 0000000..4fc124a --- /dev/null +++ b/rome-modules/src/site/apt/Slash.apt @@ -0,0 +1,38 @@ + ----- + Slash + ----- + mkurz + ----- + 2011-08-16 05:16:18.857 + ----- + +Slash + + This plug in is for use with feeds from Slash\-based weblogs. + + The latest version is 0.2 available. + +*Sample Usage + ++------+ +SyndEntry entry = new SyndEntryImpl(); +// set up the entry... +Slash slash = new SlashImpl(); +slash.setComments( new Integer( 12 ) ); +slash.setDepartment( "look-another-rome-plugin" ); +slash.setSection("code"); +slash.setHitParade( new Integer[] { new Integer(12), new Integer(0) } ); +List modules = new ArrayList(); +modules.add( slash ); +entry.setModules( modules ); + +//Optionally, to get Slash information from a Feed: +Slash slash = entry.getModule( Slash.URI ); +System.out.println( slash.getComments() ); ++------+ + +*Changes + +**0.2 + + Initial release from ROME. diff --git a/rome-modules/src/site/apt/Weather.apt b/rome-modules/src/site/apt/Weather.apt new file mode 100644 index 0000000..cbb7d42 --- /dev/null +++ b/rome-modules/src/site/apt/Weather.apt @@ -0,0 +1,36 @@ + ----- + Weather + ----- + mkurz + ----- + 2011-08-16 05:30:00.759 + ----- + +Weather + + This plug in is for use the {{{http://developer.yahoo.com/weather/}Yahoo! Weather service}}. + + The latest version is 0.1 available. + +*Sample Usage + ++------+ +SyndFeed feed = input.build( ... ); +YWeatherFeedModule yfeed = (YWeatherFeedModule) feed.getModule( YWeatherFeedModule.URI ); +System.out.println( yfeed.getLocation().getCity() ); +SyndEntry entry = (SyndEntry) feed.getEntries().get(0); +YWeatherEntryModule yentry = (YWeatherEntryModule) entry.getModule( YWeatherEntryModule.URI ); +System.out.println( yentry.getForecasts()[0].getHigh() ); + +//Optionally, to add Weather information to a feed: +SyndEntry entry = new SyndEntryImpl(); +YWeatherEntryModule yentry = new YWeatherModuleImpl(); +yentry.setCondition( Condition("Partly Cloudy", ConditionCode.PARTLY_CLOUDY, 65, new Date() ) ); +entry.getModules.add(yentry); ++------+ + +*Changes + +**0.1 + + Initial release from ROME. diff --git a/rome-modules/src/site/apt/index.apt b/rome-modules/src/site/apt/index.apt new file mode 100644 index 0000000..f0c8eaf --- /dev/null +++ b/rome-modules/src/site/apt/index.apt @@ -0,0 +1,101 @@ + ----- + Home + ----- + mkurz + ----- + 2011-08-16 05:35:31.783 + ----- + +The ROME Modules Subproject. + + The ROME Modules project is an effort to roll up contributed module support into a single distribution for users. + +*Current modules in the subproject include: + + * {{{./ITunesPodcasting.html}iTunes Podcasting (modules)}} – Apples extensions for listing in the iTunes podcast directory. + + * {{{./GeoRSS.html}GeoRSS (modules)}} – For adding location information to RSS/Atom. + + * {{{./Slash.html}Slash (modules)}} – Used by Slash\-based blogs. + + * {{{./GoogleBase.html}Google Base (modules)}} – For working with the Google Base types and custom tagsets. + + * {{{./Content.html}Content (modules)}} – For using content:encoded tags. + + * {{{./CreativeCommons.html}Creative Commons (modules)}} – A unified module for working with the RDF and RSS/Atom Creative Commons License information. + + * {{{./MediaRSS.html}Yahoo! MediaRSS}} – For working with Yahoo! MediaRSS feeds (and Flickr Photostreams) + + * {{{./IPhotoPhotocasting.html}iPhoto Photocasting (modules)}} – For working with Apple iPhoto Photocasts + + * {{{./A9OpenSearch.html}A9 OpenSearch (modules)}} – For working with Amazon/OpenSearch.org results. + + * {{{./MicrosoftSimpleListExtensions.html}Microsoft Simple List Extensions (modules)}} – for sorting and grouping entries. + + * {{{./MicrosoftSimpleSharingExtensions.html}Microsoft Simple Sharing Extensions (modules)}} – for synchronizing across bi\-directional RSS and {{{./index.html}OPML}} feeds. + + * {{{./Weather.html}Yahoo! Weather}} – For use with the Yahoo Weather API + + [] + +*Get it. + + The 0.3.2 release of modules.jar (which contains all the above modules) is available. + +*Downloads + + * {{{./rome\-modules\-1.0.jar}rome\-modules\-1.0.jar}} + + * {{{./modules\-0.3.2\-javadoc.jar}modules\-0.3.2\-javadoc.jar}} + + * {{{./modules\-0.3.2.jar}modules\-0.3.2.jar}} + + * {{{./modules\-0.3.1.jar}modules\-0.3.1.jar}} + + * {{{./modules\-0.3.1\-javadoc.jar}modules\-0.3.1\-javadoc.jar}} + + * {{{./modules\-0.3.1\-sources.jar}modules\-0.3.1\-sources.jar}} + + * {{{./modules\-0.3\-sources.jar}modules\-0.3\-sources.jar}} + + * {{{./modules\-0.3.2\-sources.jar}modules\-0.3.2\-sources.jar}} + + * {{{./modules\-0.3.jar}modules\-0.3.jar}} + + * {{{./modules\-0.3\-javadoc.jar}modules\-0.3\-javadoc.jar}} + + [] + + Please don't use modules\-0.3.jar. It had errors in the packaging which have been fixed in modules\-0.3.1.jar and subsequent releases + + See individual module sites for information. + +*Changes + +**1.0 \- released 24 February 2011 + + Finalized 1.0 release. + +**0.3.2 \- released 30 Jan 2009 + + * {{{http://java.net/jira/browse/ROME\-122}http://java.net/jira/browse/ROME\-122}} + + [] + +*General Guidelines for modules: + + This is intended to serve as a guide for contributions as well as a hint for users working with the modules. + + * Modules are packaged in com.rometools.rome.feed.module.\[Module Name\]. + + * Modules contain a com.rometools.rome.feed.module.\[Module Name\].Module.URI reference for retrieval from ROME Synd\* classes. + + * Modules contain a com.rometools.rome.feed.module.\[Module Name\].ModuleImpl that is a concrete implementation. + + * Modules contain a com.rometools.rome.feed.module.\[Module Name\].types package that holds any other datatypes needed for the module. + Many of these are simple immutable types to simplify clone() and copyFrom() + + * Modules contain a com.rometools.rome.feed.module.\[Module Name\].io package with parsers and generators. + + [] + \ No newline at end of file diff --git a/rome-modules/src/site/resources/.nojekyll b/rome-modules/src/site/resources/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/rome-modules/src/site/resources/css/site.css b/rome-modules/src/site/resources/css/site.css new file mode 100644 index 0000000..43c3cd8 --- /dev/null +++ b/rome-modules/src/site/resources/css/site.css @@ -0,0 +1,8 @@ +h1 { + padding: 4px 4px 4px 6px; + border: 1px solid #999; + color: #900; + background-color: #ddd; + font-weight:900; + font-size: x-large; +} \ No newline at end of file diff --git a/rome-modules/src/site/resources/images/romelogo.png b/rome-modules/src/site/resources/images/romelogo.png new file mode 100644 index 0000000..2c90608 Binary files /dev/null and b/rome-modules/src/site/resources/images/romelogo.png differ diff --git a/rome-modules/src/site/resources/modules-0.3-javadoc.jar b/rome-modules/src/site/resources/modules-0.3-javadoc.jar new file mode 100644 index 0000000..4ee214f Binary files /dev/null and b/rome-modules/src/site/resources/modules-0.3-javadoc.jar differ diff --git a/rome-modules/src/site/resources/modules-0.3-sources.jar b/rome-modules/src/site/resources/modules-0.3-sources.jar new file mode 100644 index 0000000..76a6925 Binary files /dev/null and b/rome-modules/src/site/resources/modules-0.3-sources.jar differ diff --git a/rome-modules/src/site/resources/modules-0.3.1-javadoc.jar b/rome-modules/src/site/resources/modules-0.3.1-javadoc.jar new file mode 100644 index 0000000..8be8227 Binary files /dev/null and b/rome-modules/src/site/resources/modules-0.3.1-javadoc.jar differ diff --git a/rome-modules/src/site/resources/modules-0.3.1-sources.jar b/rome-modules/src/site/resources/modules-0.3.1-sources.jar new file mode 100644 index 0000000..6296f00 Binary files /dev/null and b/rome-modules/src/site/resources/modules-0.3.1-sources.jar differ diff --git a/rome-modules/src/site/resources/modules-0.3.1.jar b/rome-modules/src/site/resources/modules-0.3.1.jar new file mode 100644 index 0000000..4ae93dc Binary files /dev/null and b/rome-modules/src/site/resources/modules-0.3.1.jar differ diff --git a/rome-modules/src/site/resources/modules-0.3.2-javadoc.jar b/rome-modules/src/site/resources/modules-0.3.2-javadoc.jar new file mode 100644 index 0000000..6e16bcd Binary files /dev/null and b/rome-modules/src/site/resources/modules-0.3.2-javadoc.jar differ diff --git a/rome-modules/src/site/resources/modules-0.3.2-sources.jar b/rome-modules/src/site/resources/modules-0.3.2-sources.jar new file mode 100644 index 0000000..b54a9ce Binary files /dev/null and b/rome-modules/src/site/resources/modules-0.3.2-sources.jar differ diff --git a/rome-modules/src/site/resources/modules-0.3.2.jar b/rome-modules/src/site/resources/modules-0.3.2.jar new file mode 100644 index 0000000..abfaad4 Binary files /dev/null and b/rome-modules/src/site/resources/modules-0.3.2.jar differ diff --git a/rome-modules/src/site/resources/modules-0.3.jar b/rome-modules/src/site/resources/modules-0.3.jar new file mode 100644 index 0000000..2f3b07d Binary files /dev/null and b/rome-modules/src/site/resources/modules-0.3.jar differ diff --git a/rome-modules/src/site/resources/rome-modules-1.0.jar b/rome-modules/src/site/resources/rome-modules-1.0.jar new file mode 100644 index 0000000..4839dab Binary files /dev/null and b/rome-modules/src/site/resources/rome-modules-1.0.jar differ diff --git a/rome-modules/src/site/site.xml b/rome-modules/src/site/site.xml new file mode 100644 index 0000000..a516bce --- /dev/null +++ b/rome-modules/src/site/site.xml @@ -0,0 +1,42 @@ + + + + + org.apache.maven.skins + maven-fluido-skin + 1.3.0 + + + + ROME + images/romelogo.png + http://github.com/rometools/ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rome-modules/src/test/java/com/rometools/modules/AbstractTestCase.java b/rome-modules/src/test/java/com/rometools/modules/AbstractTestCase.java new file mode 100644 index 0000000..3f72773 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/AbstractTestCase.java @@ -0,0 +1,121 @@ +package com.rometools.modules; + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.net.URISyntaxException; + +import junit.framework.TestCase; + +/** + * Abstract base class for test cases. + * + * @author Jason van Zyl + */ +public abstract class AbstractTestCase extends TestCase { + /** + * Basedir for all file I/O. Important when running tests from the reactor. + */ + public String basedir = System.getProperty("basedir") + "/src/test/resources"; + + /** + * Constructor. + */ + public AbstractTestCase(final String testName) { + super(testName); + } + + /** + * Get test input file. + * + * @param path Path to test input file. + */ + public String getTestFile(final String path) { + try { + return new File(this.getClass().getResource("/" + path).toURI()).getAbsolutePath(); + } catch (final URISyntaxException e) { + throw new RuntimeException(e); + } + } + + /** + * This method takes a JavaBean and generates a standard toString() type result for it. + * + * @param o JavaBean object to stringinate + * @return STRINGIATION! Stringingating the countryside. Stringinating all the peasants. + */ + public static String beanToString(final Object o, final boolean showNulls) { + final StringBuffer result = new StringBuffer(); + + if (o == null) { + return "--- null"; + } + + result.append("--- begin"); + result.append(o.getClass().getName()); + result.append(" hash: "); + result.append(o.hashCode()); + result.append("\r\n"); + + try { + final PropertyDescriptor[] pds = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors(); + + for (final PropertyDescriptor pd : pds) { + String out = ""; + + try { + final Object value = pd.getReadMethod().invoke(o, (Object[]) null); + + if (value != null && value.getClass().isArray()) { + final Object[] values = (Object[]) value; + + for (final Object value2 : values) { + out += value2 + " "; + } + } else { + out += value; + } + + if (!out.equals("null") || showNulls) { + result.append("Property: " + pd.getName() + " Value: " + out); + } + } catch (final IllegalAccessException iae) { + result.append("Property: " + pd.getName() + " (Illegal Access to Value) "); + } catch (final InvocationTargetException iae) { + result.append("Property: " + pd.getName() + " (InvocationTargetException) " + iae.toString()); + } catch (final Exception e) { + result.append("Property: " + pd.getName() + " (Other Exception )" + e.toString()); + } + + if (!out.equals("null") || showNulls) { + result.append("\r\n"); + } + } + } catch (final IntrospectionException ie) { + result.append("Introspection Exception: " + ie.toString()); + result.append("\r\n"); + } + + result.append("--- end "); + result.append(o.getClass().getName()); + result.append(" hash: "); + result.append(o.hashCode()); + result.append("\n"); + + return result.toString(); + } + + public boolean assertEquals(final String message, final Object[] control, final Object[] test) { + if (control == null && test == null) { + return true; + } + assertTrue(message + " Nulls", control != null && test != null); + assertEquals(message + " [size]", control.length, test.length); + for (int i = 0; i < control.length; i++) { + assertEquals(message + "[" + i + "]", control[i], test[i]); + } + return true; + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/ITunesGeneratorTest.java b/rome-modules/src/test/java/com/rometools/modules/ITunesGeneratorTest.java new file mode 100644 index 0000000..61d01e9 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/ITunesGeneratorTest.java @@ -0,0 +1,78 @@ +/* + * ITunesGeneratorTest.java + * JUnit based test + * + * Created on August 2, 2005, 2:31 PM + */ +package com.rometools.modules; + +import java.io.File; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.itunes.AbstractITunesObject; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; +import com.rometools.rome.io.XmlReader; + +/** + * + * @author cooper + */ +public class ITunesGeneratorTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ITunesGeneratorTest.class); + + public ITunesGeneratorTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(ITunesGeneratorTest.class); + + return suite; + } + + /** + * Test of generate method, of class com.totsp.xml.syndication.itunes.ITunesGenerator. + */ + public void testEndToEnd() throws Exception { + LOG.debug("testEndToEnd"); + testFile("xml/leshow.xml"); + + // testFile( "/test/xml/apple.xml" ); + // testFile( "/test/xml/lr.xml" ); + } + + private void testFile(final String filename) throws Exception { + final File feed = new File(getTestFile(filename)); + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed syndfeed = input.build(new XmlReader(feed.toURI().toURL())); + + final SyndFeedOutput output = new SyndFeedOutput(); + final File outfeed = new File("target/" + feed.getName()); + output.output(syndfeed, outfeed); + + final SyndFeed syndCheck = input.build(new XmlReader(outfeed.toURI().toURL())); + LOG.debug(syndCheck.getModule(AbstractITunesObject.URI).toString()); + assertEquals("Feed Level: ", syndfeed.getModule(AbstractITunesObject.URI).toString(), syndCheck.getModule(AbstractITunesObject.URI).toString()); + + final List syndEntries = syndfeed.getEntries(); + final List syndChecks = syndCheck.getEntries(); + + for (int i = 0; i < syndEntries.size(); i++) { + final SyndEntry entry = syndEntries.get(i); + final SyndEntry check = syndChecks.get(i); + LOG.debug("Original: {}", entry.getModule(AbstractITunesObject.URI)); + LOG.debug("Check: {}", check.getModule(AbstractITunesObject.URI)); + assertEquals("Entry Level: ", entry.getModule(AbstractITunesObject.URI).toString(), check.getModule(AbstractITunesObject.URI).toString()); + } + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/activitystreams/types/VerbTest.java b/rome-modules/src/test/java/com/rometools/modules/activitystreams/types/VerbTest.java new file mode 100644 index 0000000..7736d1c --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/activitystreams/types/VerbTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2011 robert.cooper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ + +package com.rometools.modules.activitystreams.types; + +import junit.framework.TestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.activitystreams.types.Verb; + +/** + * + * @author robert.cooper + */ +public class VerbTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(VerbTest.class); + + public VerbTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Test of valueOf method, of class Verb. + */ + public void testValueOf() { + LOG.debug("valueOf"); + final String fav = Verb.MARK_AS_FAVORITE.toString(); + assertEquals("http://activitystrea.ms/schema/1.0/favorite", fav); + assertEquals(Verb.MARK_AS_FAVORITE, Verb.fromIRI(fav)); + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/atom/AtomLinkTest.java b/rome-modules/src/test/java/com/rometools/modules/atom/AtomLinkTest.java new file mode 100644 index 0000000..508646e --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/atom/AtomLinkTest.java @@ -0,0 +1,82 @@ +/* + * SSEParserTest.java + * JUnit based test + * + * Created on August 2, 2005, 1:30 PM + */ +package com.rometools.modules.atom; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.atom.io.AtomModuleGenerator; +import com.rometools.modules.atom.modules.AtomLinkModule; +import com.rometools.modules.sle.SimpleListExtension; +import com.rometools.modules.sse.SSE091Generator; +import com.rometools.modules.sse.modules.Conflict; +import com.rometools.modules.sse.modules.History; +import com.rometools.modules.sse.modules.SSEModule; +import com.rometools.modules.sse.modules.Sync; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.rss.Item; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; +import com.rometools.rome.io.XmlReader; +import com.rometools.rome.io.impl.DateParser; +import junit.framework.Test; +import junit.framework.TestSuite; +import org.jdom2.Attribute; +import org.jdom2.Content; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.input.SAXBuilder; + +import java.io.File; +import java.net.URL; +import java.util.*; + +/** + * Test to verify correctness of SSE subproject. + */ +public class AtomLinkTest extends AbstractTestCase { + public static final String href = "http://test.com"; + public static final String type = "application/rss+xml"; + public static final String rel = "self"; + + public AtomLinkTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + public static Test suite() { + return new TestSuite(AtomLinkTest.class); + } + + /** + * Test of getNamespaceUri method, of class com.rometools.rome.feed.module.sse.SSE091 + */ + public void testGetNamespaceUri() { + assertEquals("Namespace", AtomLinkModule.URI, new AtomModuleGenerator().getNamespaceUri()); + } + + public void test() throws Exception { + + final File testdata = new File(super.getTestFile("atom/atom.xml")); + final SyndFeed feed = new SyndFeedInput().build(testdata); + + final AtomLinkModule atomLinkModule = (AtomLinkModule) feed.getModule(AtomLinkModule.URI); + Link link = atomLinkModule.getLink(); + + assertEquals(href, link.getHref()); + assertEquals(rel, link.getRel()); + assertEquals(type, link.getType()); + + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/base/io/CustomTagGeneratorTest.java b/rome-modules/src/test/java/com/rometools/modules/base/io/CustomTagGeneratorTest.java new file mode 100644 index 0000000..6936910 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/base/io/CustomTagGeneratorTest.java @@ -0,0 +1,106 @@ +/* + * CustomTagGeneratorTest.java + * JUnit based test + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.io; + +import java.io.File; +import java.util.Iterator; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.base.CustomTag; +import com.rometools.modules.base.CustomTags; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class CustomTagGeneratorTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(CustomTagGeneratorTest.class); + + public CustomTagGeneratorTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(CustomTagGeneratorTest.class); + + return suite; + } + + public void testGenerate() throws Exception { + final SyndFeedInput input = new SyndFeedInput(); + + final SyndFeed feed = input.build(new File(super.getTestFile("xml/custom-tags-example.xml"))); + final SyndFeedOutput output = new SyndFeedOutput(); + output.output(feed, new File("target/custom-tags-example.xml")); + final SyndFeed feed2 = input.build(new File("target/custom-tags-example.xml")); + + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final CustomTags customTags = (CustomTags) entry.getModule(CustomTags.URI); + + final List entries2 = feed2.getEntries(); + final SyndEntry entry2 = entries2.get(0); + final CustomTags customTags2 = (CustomTags) entry2.getModule(CustomTags.URI); + + final Iterator it = customTags.getValues().iterator(); + final Iterator it2 = customTags2.getValues().iterator(); + while (it.hasNext()) { + final CustomTag tag = it.next(); + final CustomTag tag2 = it2.next(); + LOG.debug("tag1: {}", tag); + LOG.debug("tag2: {}", tag2); + Assert.assertEquals(tag, tag2); + } + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/base/io/CustomTagParserTest.java b/rome-modules/src/test/java/com/rometools/modules/base/io/CustomTagParserTest.java new file mode 100644 index 0000000..6b516ca --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/base/io/CustomTagParserTest.java @@ -0,0 +1,128 @@ +/* + * CustomTagParserTest.java + * JUnit based test + * + * This library is provided under dual licenses. + * You may choose the terms of the Lesser General Public License or the Apache + * License at your discretion. + * + * Copyright (C) 2006 Robert Cooper, Temple of the Screaming Penguin + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 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.rometools.modules.base.io; + +import java.io.File; +import java.net.URL; +import java.util.Calendar; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.base.CustomTag; +import com.rometools.modules.base.CustomTagImpl; +import com.rometools.modules.base.CustomTags; +import com.rometools.modules.base.types.DateTimeRange; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.IntUnit; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class CustomTagParserTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(CustomTagParserTest.class); + + public CustomTagParserTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(CustomTagParserTest.class); + + return suite; + } + + public void testParse() throws Exception { + final SyndFeedInput input = new SyndFeedInput(); + + final SyndFeed feed = input.build(new File(super.getTestFile("xml/custom-tags-example.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final CustomTags customTags = (CustomTags) entry.getModule(CustomTags.URI); + final Iterator it = customTags.getValues().iterator(); + while (it.hasNext()) { + final CustomTag tag = it.next(); + LOG.debug("{}", tag); + if (tag.getName().equals("language_skills")) { + Assert.assertEquals("Fluent in English and German", tag.getValue()); + } + if (tag.getName().equals("prior_experience_years")) { + Assert.assertEquals(new Integer(5), tag.getValue()); + } else if (tag.getName().equals("start_date")) { + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + cal.set(2005, 10, 15, 0, 0, 0); + Assert.assertEquals(cal.getTime(), tag.getValue()); + } else if (tag.getName().equals("test_url")) { + Assert.assertEquals(new URL("http://www.screaming-penguin.com"), tag.getValue()); + } else if (tag.getName().equals("test_boolean")) { + Assert.assertEquals(new Boolean(true), tag.getValue()); + } else if (tag.getName().equals("test_intUnit")) { + Assert.assertEquals(new IntUnit(25, "horses"), tag.getValue()); + } else if (tag.getName().equals("test_floatUnit")) { + Assert.assertEquals(new FloatUnit((float) 2.5, "cows"), tag.getValue()); + } else if (tag.getName().equals("test_location")) { + Assert.assertEquals(new CustomTagImpl.Location("125 Main St, Sometown, GA"), tag.getValue()); + } else if (tag.getName().equals("test_dateRange")) { + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + cal.set(2005, 06, 04, 20, 0, 0); + final Date start = cal.getTime(); + cal.set(2005, 06, 04, 23, 0, 0); + final DateTimeRange dtr = new DateTimeRange(start, cal.getTime()); + Assert.assertEquals(dtr, tag.getValue()); + } + } + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/base/io/GoogleBaseGeneratorTest.java b/rome-modules/src/test/java/com/rometools/modules/base/io/GoogleBaseGeneratorTest.java new file mode 100644 index 0000000..2711361 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/base/io/GoogleBaseGeneratorTest.java @@ -0,0 +1,119 @@ +/* + * GoogleBaseGeneratorTest.java + * JUnit based test + * + * Created on November 17, 2005, 3:40 PM + */ +package com.rometools.modules.base.io; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.base.GoogleBase; +import com.rometools.modules.base.GoogleBaseImpl; +import com.rometools.modules.base.Product; +import com.rometools.modules.base.Vehicle; +import com.rometools.rome.feed.synd.SyndContent; +import com.rometools.rome.feed.synd.SyndContentImpl; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndEntryImpl; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndFeedImpl; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; + +/** + * + * @author rcooper + */ +public class GoogleBaseGeneratorTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(GoogleBaseGeneratorTest.class); + + public GoogleBaseGeneratorTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(GoogleBaseGeneratorTest.class); + + return suite; + } + + /** + * Test of generate method, of class com.totsp.xml.syndication.base.io.GoogleBaseGenerator. + */ + public void testGenerate() throws Exception { + LOG.debug("testGenerate"); + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeedOutput output = new SyndFeedOutput(); + final File testDir = new File(super.getTestFile("xml")); + final File[] testFiles = testDir.listFiles(); + for (int h = 0; h < testFiles.length; h++) { + if (!testFiles[h].getName().endsWith(".xml")) { + continue; + } + LOG.debug(testFiles[h].getName()); + final SyndFeed feed = input.build(testFiles[h]); + try { + output.output(feed, new File("target/" + testFiles[h].getName())); + } catch (final Exception e) { + throw new RuntimeException(testFiles[h].getAbsolutePath(), e); + } + final SyndFeed feed2 = input.build(new File("target/" + testFiles[h].getName())); + for (int i = 0; i < feed.getEntries().size(); i++) { + final SyndEntry entry = feed.getEntries().get(i); + final SyndEntry entry2 = feed2.getEntries().get(i); + final GoogleBase base = (GoogleBase) entry.getModule(GoogleBase.URI); + final GoogleBase base2 = (GoogleBase) entry2.getModule(GoogleBase.URI); + Assert.assertEquals(testFiles[h].getName(), base, base2); + } + } + + } + + public void testMehta() throws Exception { + final SyndFeed feed = new SyndFeedImpl(); + feed.setFeedType("atom_1.0"); + + feed.setTitle("Sample Feed (created with Rome)"); + feed.setLink("http://rome.dev.java.net"); + feed.setDescription("This feed has been created using Rome (Java syndication utilities"); + + final List entries = new ArrayList(); + SyndEntry entry; + SyndContent description; + + entry = new SyndEntryImpl(); + entry.setTitle("Rome v1.0"); + entry.setLink("http://wiki.java.net/bin/view/Javawsxml/Rome01 "); + description = new SyndContentImpl(); + description.setType("text/plain"); + description.setValue("Initial release of Rome"); + entry.setDescription(description); + final Vehicle vehicle = new GoogleBaseImpl(); + vehicle.setMake("Honda"); + vehicle.setModel("Insight"); + + final Product product = new GoogleBaseImpl(); + product.setCondition("New"); + product.setDeliveryNotes("Insight"); + + entries.add(entry); + + feed.setEntries(entries); + + final SyndFeedOutput output = new SyndFeedOutput(); + LOG.debug(output.outputString(feed)); + + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/base/io/GoogleBaseParserTest.java b/rome-modules/src/test/java/com/rometools/modules/base/io/GoogleBaseParserTest.java new file mode 100644 index 0000000..eac4179 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/base/io/GoogleBaseParserTest.java @@ -0,0 +1,584 @@ +/* + * GoogleBaseParserTest.java + * JUnit based test + * + * Created on November 17, 2005, 4:49 PM + */ +package com.rometools.modules.base.io; + +import java.io.File; +import java.net.URL; +import java.util.Calendar; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.base.Article; +import com.rometools.modules.base.Course; +import com.rometools.modules.base.Event; +import com.rometools.modules.base.GoogleBase; +import com.rometools.modules.base.Housing; +import com.rometools.modules.base.Job; +import com.rometools.modules.base.Person; +import com.rometools.modules.base.Product; +import com.rometools.modules.base.Review; +import com.rometools.modules.base.ScholarlyArticle; +import com.rometools.modules.base.Service; +import com.rometools.modules.base.Travel; +import com.rometools.modules.base.Vehicle; +import com.rometools.modules.base.Wanted; +import com.rometools.modules.base.io.GoogleBaseParser; +import com.rometools.modules.base.types.CurrencyEnumeration; +import com.rometools.modules.base.types.FloatUnit; +import com.rometools.modules.base.types.GenderEnumeration; +import com.rometools.modules.base.types.PaymentTypeEnumeration; +import com.rometools.modules.base.types.PriceTypeEnumeration; +import com.rometools.modules.base.types.ShippingType; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; + +/** + * + * @author rcooper + */ +public class GoogleBaseParserTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(GoogleBaseParserTest.class); + + public GoogleBaseParserTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(GoogleBaseParserTest.class); + + return suite; + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testQuickParse() throws Exception { + try { + LOG.debug("testParse"); + final SyndFeedInput input = new SyndFeedInput(); + final File testDir = new File(super.getTestFile("xml")); + final File[] testFiles = testDir.listFiles(); + for (int h = 0; h < testFiles.length; h++) { + if (!testFiles[h].getName().endsWith(".xml")) { + continue; + } + SyndFeed feed = null; + try { + feed = input.build(testFiles[h]); + } catch (final Exception e) { + throw new RuntimeException(testFiles[h].getAbsolutePath(), e); + } + final List entries = feed.getEntries(); + for (int i = 0; i < entries.size(); i++) { + final SyndEntry entry = entries.get(i); + LOG.debug("{}", entry.getModules().size()); + for (int j = 0; j < entry.getModules().size(); j++) { + LOG.debug("{}", entry.getModules().get(j).getClass()); + if (entry.getModules().get(j) instanceof GoogleBase) { + final GoogleBase base = (GoogleBase) entry.getModules().get(j); + LOG.debug(testFiles[h].getName()); + LOG.debug(super.beanToString(base, false)); + } + } + } + } + } catch (final Exception e) { + e.printStackTrace(); + throw e; + } + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testCourse2Parse() throws Exception { + LOG.debug("testCourse2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + + final SyndFeed feed = input.build(new File(super.getTestFile("xml/courses2.xml"))); + final List entries = feed.getEntries(); + SyndEntry entry = entries.get(0); + Course course = (Course) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", course.getImageLinks()[0].toString()); + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + cal.set(2005, 10, 30, 0, 0, 0); + Assert.assertEquals("Course Date", cal.getTime(), course.getExpirationDate()); + String[] labels = new String[] { "robots", "society", "computers" }; + this.assertEquals("Labels", labels, course.getLabels()); + cal.set(2005, 7, 19, 8, 30, 00); + Assert.assertEquals("Start Time", cal.getTime(), course.getCourseDateRange().getStart()); + cal.set(2005, 11, 20, 9, 45, 00); + Assert.assertEquals("End Time", cal.getTime(), course.getCourseDateRange().getEnd()); + Assert.assertEquals("Course Number", "CS 230", course.getCourseNumber()); + Assert.assertEquals("Coutse Times", "MWF 08:30-09:00", course.getCourseTimes()); + this.assertEquals("Subject", new String[] { "computer science" }, course.getSubjects()); + Assert.assertEquals("University", "Johnson State", course.getUniversity()); + + entry = entries.get(1); + course = (Course) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", course.getImageLinks()[0].toString()); + cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + cal.set(2005, 10, 30, 0, 0, 0); + Assert.assertEquals("Course Date", cal.getTime(), course.getExpirationDate()); + labels = new String[] { "film", "video", "documentary" }; + this.assertEquals("Labels", labels, course.getLabels()); + cal.set(2005, 7, 19, 8, 30, 00); + Assert.assertEquals("Start Time", cal.getTime(), course.getCourseDateRange().getStart()); + cal.set(2005, 11, 20, 9, 45, 00); + Assert.assertEquals("End Time", cal.getTime(), course.getCourseDateRange().getEnd()); + Assert.assertEquals("Course Number", "FS 192", course.getCourseNumber()); + Assert.assertEquals("Coutse Times", "TTh 14:00-16:00", course.getCourseTimes()); + Assert.assertEquals("Subject", "film", course.getSubjects()[0]); + Assert.assertEquals("University", "Johnson State", course.getUniversity()); + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testEvent2Parse() throws Exception { + LOG.debug("testEvent2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + + final SyndFeed feed = input.build(new File(super.getTestFile("xml/events2.xml"))); + final List entries = feed.getEntries(); + SyndEntry entry = entries.get(0); + Event event = (Event) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", event.getImageLinks()[0].toString()); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), event.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Festival", "Halloween", "Party", "Costumes" }, event.getLabels()); + Assert.assertEquals("Currency", CurrencyEnumeration.USD, event.getCurrency()); + Assert.assertEquals("Price", 10, event.getPrice().getValue(), 0); + Assert.assertEquals("PriceUnit", null, event.getPrice().getUnits()); + Assert.assertEquals("PriceType", PriceTypeEnumeration.STARTING, event.getPriceType()); + this.assertEquals("Payment Accepted", new PaymentTypeEnumeration[] { PaymentTypeEnumeration.CASH, PaymentTypeEnumeration.CHECK, + PaymentTypeEnumeration.VISA }, event.getPaymentAccepted()); + Assert.assertEquals("Payment Notes", "Cash only for local orders", event.getPaymentNotes()); + /* + * 2005-07-04T20:00:00 + * 2005-07-04T23:00:00 + */ + cal.set(2005, 06, 04, 20, 00, 00); + Assert.assertEquals("Start Time", cal.getTime(), event.getEventDateRange().getStart()); + cal.set(2005, 06, 04, 23, 00, 00); + Assert.assertEquals("End Time", cal.getTime(), event.getEventDateRange().getEnd()); + Assert.assertEquals("Location", "1600 Amphitheatre Parkway, Mountain View, CA, 94043", event.getLocation()); + Assert.assertEquals("Shipping Price", (float) 32.95, event.getShipping()[0].getPrice().getValue(), 0); + // TODO: Determine what to do about the bogus services. + Assert.assertEquals("Shipping Country", "US", event.getShipping()[0].getCountry()); + Assert.assertEquals("Tax Region", "California", event.getTaxRegion()); + Assert.assertEquals("Tax Percentage", new Float(8.25), event.getTaxPercent()); + + entry = entries.get(1); + event = (Event) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image2.jpg", event.getImageLinks()[0].toString()); + cal.setTimeInMillis(0); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), event.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Concert", "festival", "music" }, event.getLabels()); + Assert.assertEquals("Currency", CurrencyEnumeration.USD, event.getCurrency()); + Assert.assertEquals("Price", 50, event.getPrice().getValue(), 0); + Assert.assertEquals("PriceUnit", null, event.getPrice().getUnits()); + Assert.assertEquals("PriceType", PriceTypeEnumeration.STARTING, event.getPriceType()); + this.assertEquals("Payment Accepted", new PaymentTypeEnumeration[] { PaymentTypeEnumeration.CASH, PaymentTypeEnumeration.CHECK, + PaymentTypeEnumeration.VISA }, event.getPaymentAccepted()); + Assert.assertEquals("Payment Notes", "Cash only for local orders", event.getPaymentNotes()); + /* + * 2005-08-23T20:00:00 + * 2005-08-23T23:00:00 + */ + cal.set(2005, 07, 23, 20, 00, 00); + Assert.assertEquals("Start Time", cal.getTime(), event.getEventDateRange().getStart()); + cal.set(2005, 07, 23, 23, 00, 00); + Assert.assertEquals("End Time", cal.getTime(), event.getEventDateRange().getEnd()); + Assert.assertEquals("Location", "123 Main St, Anytown, CA, 12345, USA", event.getLocation()); + Assert.assertEquals("Shipping Price", (float) 32.95, event.getShipping()[0].getPrice().getValue(), 0); + // TODO: Determine what to do about the bogus services. + Assert.assertEquals("Shipping Country", "US", event.getShipping()[0].getCountry()); + Assert.assertEquals("Tax Region", "California", event.getTaxRegion()); + Assert.assertEquals("Tax Percentage", new Float(8.25), event.getTaxPercent()); + + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testHousing2Parse() throws Exception { + LOG.debug("testHousing2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/housing2.xml"))); + final List entries = feed.getEntries(); + SyndEntry entry = entries.get(0); + Housing module = (Housing) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", module.getImageLinks()[0].toString()); + cal.set(2007, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Housing", "New House", "Sale" }, module.getLabels()); + Assert.assertEquals("Currency", CurrencyEnumeration.USD, module.getCurrency()); + Assert.assertEquals("Price", 350000, module.getPrice().getValue(), 0); + Assert.assertEquals("PriceUnit", null, module.getPrice().getUnits()); + Assert.assertEquals("PriceType", PriceTypeEnumeration.STARTING, module.getPriceType()); + this.assertEquals("Payment Accepted", new PaymentTypeEnumeration[] { PaymentTypeEnumeration.CASH, PaymentTypeEnumeration.CHECK, + PaymentTypeEnumeration.VISA }, module.getPaymentAccepted()); + Assert.assertEquals("Payment Notes", "1000 deposit", module.getPaymentNotes()); + Assert.assertEquals("Listing Type", new Boolean(true), module.getListingType()); + this.assertEquals("PropertyTypes", new String[] { "Townhouse" }, module.getPropertyTypes()); + Assert.assertEquals("Location", "123 Main St, Anytown, CA, 12345, USA", module.getLocation()); + Assert.assertEquals("Bedrooms", new Integer(3), module.getBedrooms()); + Assert.assertEquals("Bathrooms", new Float(3), module.getBathrooms()); + Assert.assertEquals("Area", 1300, module.getArea().getValue()); + Assert.assertEquals("Area Units", null, module.getArea().getUnits()); + Assert.assertEquals("School District", "Union School District", module.getSchoolDistrict()); + Assert.assertEquals("HOA Dues", new Float(120), module.getHoaDues()); + Assert.assertEquals("Year", "2005", module.getYear().toString()); + this.assertEquals("Agents", new String[] { "Sue Smith" }, module.getAgents()); + Assert.assertEquals("Tax Region", "California", module.getTaxRegion()); + Assert.assertEquals("Tax Percentage", new Float(8.25), module.getTaxPercent()); + + entry = entries.get(1); + module = (Housing) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image2.jpg", module.getImageLinks()[0].toString()); + cal.set(2008, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Housing", "rent", "lease" }, module.getLabels()); + Assert.assertEquals("Currency", CurrencyEnumeration.USD, module.getCurrency()); + Assert.assertEquals("Price", 1400, module.getPrice().getValue(), 0); + Assert.assertEquals("PriceUnit", null, module.getPrice().getUnits()); + Assert.assertEquals("PriceType", PriceTypeEnumeration.STARTING, module.getPriceType()); + this.assertEquals("Payment Accepted", new PaymentTypeEnumeration[] { PaymentTypeEnumeration.CHECK }, module.getPaymentAccepted()); + Assert.assertEquals("Payment Notes", "1000 deposit", module.getPaymentNotes()); + Assert.assertEquals("Listing Type", new Boolean(false), module.getListingType()); + this.assertEquals("PropertyTypes", new String[] { "apartment" }, module.getPropertyTypes()); + Assert.assertEquals("Location", "123 Main St, Anytown, CA, 12345, USA", module.getLocation()); + Assert.assertEquals("Bedrooms", new Integer(2), module.getBedrooms()); + Assert.assertEquals("Bathrooms", new Float(2), module.getBathrooms()); + Assert.assertEquals("Area", 1100, module.getArea().getValue()); + Assert.assertEquals("Area Units", null, module.getArea().getUnits()); + Assert.assertEquals("School District", "Union School District", module.getSchoolDistrict()); + Assert.assertEquals("HOA Dues", null, module.getHoaDues()); + Assert.assertEquals("Year", "2004", module.getYear().toString()); + this.assertEquals("Agents", new String[] { "Sue Smith" }, module.getAgents()); + Assert.assertEquals("Tax Region", null, module.getTaxRegion()); + Assert.assertEquals("Tax Percentage", null, module.getTaxPercent()); + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testJobs2Parse() throws Exception { + LOG.debug("testJobs2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/jobs2.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final Job module = (Job) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", module.getImageLinks()[0].toString()); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Coordinator", "Google", "Online Support" }, module.getLabels()); + this.assertEquals("Industriy", new String[] { "Internet" }, module.getJobIndustries()); + Assert.assertEquals("Employer", "Google, Inc", module.getEmployer()); + this.assertEquals("Job Function", new String[] { "Google Coordinator" }, module.getJobFunctions()); + LOG.debug("{}", new Object[] { module.getJobTypes() }); + this.assertEquals("Job Type", new String[] { "full-time" }, module.getJobTypes()); + Assert.assertEquals("Currency", CurrencyEnumeration.USD, module.getCurrency()); + Assert.assertEquals("Salary", new Float(40000), module.getSalary()); + Assert.assertEquals("Salary Type", PriceTypeEnumeration.STARTING, module.getSalaryType()); + Assert.assertEquals("Education", "BS", module.getEducation()); + Assert.assertEquals("Immigration", "Permanent Resident", module.getImmigrationStatus()); + Assert.assertEquals("Location", "1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA", module.getLocation()); + + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testNews2Parse() throws Exception { + LOG.debug("testNews2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/news2.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final Article module = (Article) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", module.getImageLinks()[0].toString()); + cal.set(2007, 2, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "news", "old" }, module.getLabels()); + Assert.assertEquals("Source", "Journal", module.getNewsSource()); + cal.set(1961, 3, 12, 0, 0, 0); + Assert.assertEquals("Pub Date", cal.getTime(), module.getPublishDate()); + this.assertEquals("Authors", new String[] { "James Smith" }, module.getAuthors()); + Assert.assertEquals("Pages", new Integer(1), module.getPages()); + + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testTravel2Parse() throws Exception { + LOG.debug("testTravel2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/travel2.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final Travel module = (Travel) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", module.getImageLinks()[0].toString()); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Vacation", "Train" }, module.getLabels()); + Assert.assertEquals("Currency", CurrencyEnumeration.USD, module.getCurrency()); + Assert.assertEquals("Price", 250, module.getPrice().getValue(), 0); + Assert.assertEquals("PriceUnit", null, module.getPrice().getUnits()); + Assert.assertEquals("PriceType", PriceTypeEnumeration.STARTING, module.getPriceType()); + this.assertEquals("Payment Accepted", new PaymentTypeEnumeration[] { PaymentTypeEnumeration.CHECK, PaymentTypeEnumeration.VISA }, + module.getPaymentAccepted()); + Assert.assertEquals("Payment notes", "minimum payment on credit cards:45", module.getPaymentNotes()); + Assert.assertEquals("Quantity", new Integer(204), module.getQuantity()); + Assert.assertEquals("From", "Mytown, USA", module.getFromLocation()); + Assert.assertEquals("To", "Anytown, USA", module.getToLocation()); + cal.set(2005, 11, 20, 18, 0, 0); + Assert.assertEquals("Start Date", cal.getTime(), module.getTravelDateRange().getStart()); + cal.set(2005, 11, 22, 18, 0, 0); + Assert.assertEquals("End Date", cal.getTime(), module.getTravelDateRange().getEnd()); + Assert.assertEquals("Location", "123 Main St, Mytown, CA, 12345, USA", module.getLocation()); + this.assertEquals("Shipping", new ShippingType[] { new ShippingType(new FloatUnit("32.95"), ShippingType.ServiceEnumeration.OVERNIGHT, "US") }, + module.getShipping()); + Assert.assertEquals("Tax Region", "California", module.getTaxRegion()); + Assert.assertEquals("Tax Percentage", new Float(8.25), module.getTaxPercent()); + + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testPersona2Parse() throws Exception { + LOG.debug("testPerson2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/personals2.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final Person module = (Person) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", module.getImageLinks()[0].toString()); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Personals", "m4w" }, module.getLabels()); + this.assertEquals("Ethnicity", new String[] { "South Asian" }, module.getEthnicities()); + Assert.assertEquals("Gender", GenderEnumeration.MALE, module.getGender()); + Assert.assertEquals("Sexual Orientation", "straight", module.getSexualOrientation()); + this.assertEquals("Interested In", new String[] { "Single Women" }, module.getInterestedIn()); + Assert.assertEquals("Marital Status", "single", module.getMaritalStatus()); + Assert.assertEquals("Occupation", "Sales", module.getOccupation()); + Assert.assertEquals("Employer", "Google, Inc.", module.getEmployer()); + Assert.assertEquals("Age", new Integer(23), module.getAge()); + Assert.assertEquals("Location", "Anytown, 12345, USA", module.getLocation()); + + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testProduct2Parse() throws Exception { + LOG.debug("testProduct2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/products2.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final Product module = (Product) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.googlestore.com/appliance/images/products/GO0144E.jpg", module.getImageLinks()[0].toString()); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "web search", "appliance" }, module.getLabels()); + Assert.assertEquals("Currency", CurrencyEnumeration.USD, module.getCurrency()); + Assert.assertEquals("Price", 2995, module.getPrice().getValue(), 0); + Assert.assertEquals("PriceType", PriceTypeEnumeration.STARTING, module.getPriceType()); + this.assertEquals("Payment Accepted", new PaymentTypeEnumeration[] { PaymentTypeEnumeration.CHECK, PaymentTypeEnumeration.MASTERCARD }, + module.getPaymentAccepted()); + Assert.assertEquals("Payment Notes", "financing available", module.getPaymentNotes()); + Assert.assertEquals("Brand", "Google", module.getBrand()); + Assert.assertEquals("UPC", "12348573", module.getUpc()); + Assert.assertEquals("Manufacturer", "Google", module.getManufacturer()); + Assert.assertEquals("ManufacturerId", "2325", module.getManufacturerId()); + Assert.assertEquals("Model number", "234", module.getModelNumber()); + LOG.debug("{}", module.getSize()); + Assert.assertEquals("Size", 10, module.getSize().getLength().getValue(), 0); + Assert.assertEquals("Size", 50, module.getSize().getWidth().getValue(), 0); + Assert.assertEquals("Size", 20, module.getSize().getHeight().getValue(), 0); + Assert.assertEquals("Weight", 2, module.getWeight().getValue(), 0); + Assert.assertEquals("Quantity", new Integer(300), module.getQuantity()); + Assert.assertEquals("Condition", "new", module.getCondition()); + this.assertEquals("Colors", new String[] { "blue" }, module.getColors()); + Assert.assertEquals("Location", "1600 Amphitheatre Pkwy Mountain View, CA 94043-1351, US", module.getLocation()); + + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testResearch2Parse() throws Exception { + LOG.debug("testResearch2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/research2.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final ScholarlyArticle module = (ScholarlyArticle) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", module.getImageLinks()[0].toString()); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Economy", "Tsunami" }, module.getLabels()); + cal.set(2005, 1, 25); + Assert.assertEquals("PubDate", cal.getTime(), module.getPublishDate()); + this.assertEquals("Authors", new String[] { "James Smith" }, module.getAuthors()); + Assert.assertEquals("Pub Name", "Tsunami and the Economy", module.getPublicationName()); + Assert.assertEquals("Pub Vol", "III", module.getPublicationVolume()); + Assert.assertEquals("Pages", new Integer(5), module.getPages()); + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testReview2Parse() throws Exception { + LOG.debug("testReview2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/reviews2.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final Review module = (Review) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", module.getImageLinks()[0].toString()); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Review", "Earth", "Google" }, module.getLabels()); + cal.set(2005, 2, 24); + Assert.assertEquals("PubDate", cal.getTime(), module.getPublishDate()); + this.assertEquals("Authors", new String[] { "Jimmy Smith" }, module.getAuthors()); + Assert.assertEquals("Name of Item Rev", "Google Earth", module.getNameOfItemBeingReviewed()); + Assert.assertEquals("Type", "Product", module.getReviewType()); + Assert.assertEquals("Rever Type", "editorial", module.getReviewerType()); + Assert.assertEquals("Rating", new Float(5), module.getRating()); + Assert.assertEquals("URL of Item", new URL("http://earth.google.com/"), module.getUrlOfItemBeingReviewed()); + + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testService2Parse() throws Exception { + LOG.debug("testService2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/services2.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final Service module = (Service) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", module.getImageLinks()[0].toString()); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Food delivery" }, module.getLabels()); + cal.set(2005, 2, 24); + Assert.assertEquals("Currency", CurrencyEnumeration.USD, module.getCurrency()); + Assert.assertEquals("Price", 15, module.getPrice().getValue(), 0); + Assert.assertEquals("PriceType", PriceTypeEnumeration.STARTING, module.getPriceType()); + this.assertEquals("Payment Accepted", new PaymentTypeEnumeration[] { PaymentTypeEnumeration.VISA, PaymentTypeEnumeration.MASTERCARD }, + module.getPaymentAccepted()); + Assert.assertEquals("Payment Notes", "minimum payment on credit cards:45", module.getPaymentNotes()); + Assert.assertEquals("Service Type", "delivery", module.getServiceType()); + Assert.assertEquals("Location", "Anytown, CA, USA", module.getLocation()); + Assert.assertEquals("DeliveryRad", 20, module.getDeliveryRadius().getValue(), 0); + Assert.assertEquals("Delivery Notes", "will deliver between 9am -5pm", module.getDeliveryNotes()); + + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testVehicle2Parse() throws Exception { + LOG.debug("testVehicle2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/vehicles2.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final Vehicle module = (Vehicle) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", module.getImageLinks()[0].toString()); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "car", "mini" }, module.getLabels()); + cal.set(2005, 2, 24); + Assert.assertEquals("Currency", CurrencyEnumeration.USD, module.getCurrency()); + Assert.assertEquals("Price", 24000, module.getPrice().getValue(), 0); + Assert.assertEquals("PriceType", PriceTypeEnumeration.STARTING, module.getPriceType()); + this.assertEquals("Payment Accepted", new PaymentTypeEnumeration[] { PaymentTypeEnumeration.CHECK, PaymentTypeEnumeration.VISA, + PaymentTypeEnumeration.MASTERCARD }, module.getPaymentAccepted()); + Assert.assertEquals("Payment Notes", "financing available", module.getPaymentNotes()); + Assert.assertEquals("Vehicle Type", "car", module.getVehicleType()); + Assert.assertEquals("Make", "Mini", module.getMake()); + Assert.assertEquals("Model", "Cooper S", module.getModel()); + Assert.assertEquals("Year", "2006", module.getYear().toString()); + Assert.assertEquals("Mileage", new Integer(0), module.getMileage()); + this.assertEquals("Colors", new String[] { "red" }, module.getColors()); + Assert.assertEquals("Vin", "1M8GDM9AXKP042788", module.getVin()); + Assert.assertEquals("Location", "123 Main Street, Anytown, CA, 12345, USA", module.getLocation()); + + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testWanted2Parse() throws Exception { + LOG.debug("testVehicle2Parse"); + final SyndFeedInput input = new SyndFeedInput(); + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(0); + final SyndFeed feed = input.build(new File(super.getTestFile("xml/wanted2.xml"))); + final List entries = feed.getEntries(); + final SyndEntry entry = entries.get(0); + final Wanted module = (Wanted) entry.getModule(GoogleBase.URI); + Assert.assertEquals("Image Link", "http://www.providers-website.com/image1.jpg", module.getImageLinks()[0].toString()); + cal.set(2005, 11, 20, 0, 0, 0); + Assert.assertEquals("Expiration Date", cal.getTime(), module.getExpirationDate()); + this.assertEquals("Labels", new String[] { "Wanted", "Truck" }, module.getLabels()); + Assert.assertEquals("Location", "123 Main Street, Anytown, CA, 12345, USA", module.getLocation()); + } + + /** + * Test of getNamespaceUri method, of class com.totsp.xml.syndication.base.io.GoogleBaseParser. + */ + public void testGetNamespaceUri() { + LOG.debug("testGetNamespaceUri"); + LOG.debug(new GoogleBaseParser().getNamespaceUri()); + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/base/types/FloatUnitTest.java b/rome-modules/src/test/java/com/rometools/modules/base/types/FloatUnitTest.java new file mode 100644 index 0000000..1ca3f4f --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/base/types/FloatUnitTest.java @@ -0,0 +1,54 @@ +/* + * FloatUnitTest.java + * JUnit based test + * + * Created on November 18, 2005, 5:16 PM + */ + +package com.rometools.modules.base.types; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.base.types.FloatUnit; + +/** + * + * @author rcooper + */ +public class FloatUnitTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(FloatUnitTest.class); + + public FloatUnitTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(FloatUnitTest.class); + + return suite; + } + + /** + * Test of getUnits method, of class com.totsp.xml.syndication.base.types.FloatUnit. + */ + public void testFloatUnit() { + LOG.debug("testFloatUnit"); + FloatUnit fu = new FloatUnit("1.22km"); + + assertEquals((float) 1.22, fu.getValue(), 0); + assertEquals("km", fu.getUnits()); + fu = new FloatUnit("1 gb"); + assertEquals(1, fu.getValue(), 0); + assertEquals("gb", fu.getUnits()); + fu = new FloatUnit("-3.1"); + assertEquals((float) -3.1, fu.getValue(), 0); + assertEquals(null, fu.getUnits()); + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/base/types/IntUnitTest.java b/rome-modules/src/test/java/com/rometools/modules/base/types/IntUnitTest.java new file mode 100644 index 0000000..1ed68d2 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/base/types/IntUnitTest.java @@ -0,0 +1,55 @@ +/* + * IntUnitTest.java + * JUnit based test + * + * Created on November 18, 2005, 5:16 PM + */ + +package com.rometools.modules.base.types; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.base.types.IntUnit; +import com.rometools.modules.cc.io.CCModuleGenerator; + +/** + * + * @author rcooper + */ +public class IntUnitTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(CCModuleGenerator.class); + + public IntUnitTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(IntUnitTest.class); + + return suite; + } + + /** + * Test of getUnits method, of class com.totsp.xml.syndication.base.types.IntUnit. + */ + public void testIntUnit() { + LOG.debug("testIntUnit"); + IntUnit fu = new IntUnit("1km"); + + assertEquals(1, fu.getValue()); + assertEquals("km", fu.getUnits()); + fu = new IntUnit("1 gb"); + assertEquals(1, fu.getValue()); + assertEquals("gb", fu.getUnits()); + fu = new IntUnit("-3"); + assertEquals(-3, fu.getValue()); + assertEquals(null, fu.getUnits()); + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/cc/io/CCModuleGeneratorTest.java b/rome-modules/src/test/java/com/rometools/modules/cc/io/CCModuleGeneratorTest.java new file mode 100644 index 0000000..6bb4b78 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/cc/io/CCModuleGeneratorTest.java @@ -0,0 +1,82 @@ +/* + * CCModuleGeneratorTest.java + * JUnit based test + * + * Created on November 20, 2005, 9:48 PM + */ + +package com.rometools.modules.cc.io; + +import java.io.File; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.cc.CreativeCommons; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class CCModuleGeneratorTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(CCModuleGeneratorTest.class); + + public CCModuleGeneratorTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(CCModuleGeneratorTest.class); + + return suite; + } + + public void testGenerate() throws Exception { + LOG.debug("testGenerate"); + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeedOutput output = new SyndFeedOutput(); + final File testDir = new File(super.getTestFile("xml")); + final File[] testFiles = testDir.listFiles(); + for (int h = 0; h < testFiles.length; h++) { + if (!testFiles[h].getName().endsWith(".xml")) { + continue; + } + LOG.debug(testFiles[h].getName()); + final SyndFeed feed = input.build(testFiles[h]); + // if( !feed.getFeedType().equals("rss_1.0")) + { + feed.setFeedType("rss_2.0"); + if (feed.getDescription() == null) { + feed.setDescription("test file"); + } + output.output(feed, new File("target/" + testFiles[h].getName())); + final SyndFeed feed2 = input.build(new File("target/" + testFiles[h].getName())); + for (int i = 0; i < feed.getEntries().size(); i++) { + // FIXME + // final SyndEntry entry = feed.getEntries().get(i); + final SyndEntry entry2 = feed2.getEntries().get(i); + // / FIXME + // final CreativeCommons base = (CreativeCommons) + // entry.getModule(CreativeCommons.URI); + final CreativeCommons base2 = (CreativeCommons) entry2.getModule(CreativeCommons.URI); + LOG.debug("{}", base2); + // FIXME + // if( base != null) + // this.assertEquals( testFiles[h].getName(), base.getLicenses(), + // base2.getLicenses() ); + } + } + } + + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/cc/io/ModuleParserTest.java b/rome-modules/src/test/java/com/rometools/modules/cc/io/ModuleParserTest.java new file mode 100644 index 0000000..4fcaa59 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/cc/io/ModuleParserTest.java @@ -0,0 +1,70 @@ +/* + * ModuleParserRSS1Test.java + * JUnit based test + * + * Created on November 20, 2005, 7:05 PM + */ + +package com.rometools.modules.cc.io; + +import java.io.File; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.cc.CreativeCommons; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class ModuleParserTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ModuleParserTest.class); + + public ModuleParserTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(ModuleParserTest.class); + + return suite; + } + + public void testNull() { + return; + } + + public void atestParse() throws Exception { + + final SyndFeedInput input = new SyndFeedInput(); + final File testDir = new File(super.getTestFile("test/xml")); + final File[] testFiles = testDir.listFiles(); + for (int h = 0; h < testFiles.length; h++) { + if (!testFiles[h].getName().endsWith(".xml")) { + continue; + } + LOG.debug(testFiles[h].getName()); + final SyndFeed feed = input.build(testFiles[h]); + final List entries = feed.getEntries(); + final CreativeCommons fMod = (CreativeCommons) feed.getModule(CreativeCommons.URI); + LOG.debug("{}", fMod); + for (int i = 0; i < entries.size(); i++) { + final SyndEntry entry = entries.get(i); + final CreativeCommons eMod = (CreativeCommons) entry.getModule(CreativeCommons.URI); + LOG.debug("\nEntry:"); + LOG.debug("{}", eMod); + } + } + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/cc/types/LicenseTest.java b/rome-modules/src/test/java/com/rometools/modules/cc/types/LicenseTest.java new file mode 100644 index 0000000..2f0a6aa --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/cc/types/LicenseTest.java @@ -0,0 +1,83 @@ +package com.rometools.modules.cc.types; + +import static org.junit.Assert.assertFalse; + +import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.Before; +import org.junit.Test; + +import com.rometools.modules.cc.types.License; + +/** + * @author Matthew Buckett + */ +public class LicenseTest { + + @Before + public void setUp() { + // As the looked up licenses are held statically we need to clear this between tests. + License.clear(); + } + + @Test(timeout = 1000) + public void testConcurrent() throws InterruptedException { + final AtomicBoolean run = new AtomicBoolean(true); + final AtomicLong type = new AtomicLong(0); + // Tracking any problems. + final AtomicBoolean hadProblem = new AtomicBoolean(false); + final AtomicBoolean hadException = new AtomicBoolean(false); + + // This thread keeps on adding new licenses (not very realistic but shows the bug) + final Thread addNew = new Thread() { + @Override + public void run() { + try { + while (run.get()) { + final License license = License.findByValue("http://creativecommons.org/licenses/" + type.incrementAndGet() + "/1"); + if (license == null) { + hadProblem.set(true); + } + } + } catch (final Exception e) { + hadException.set(true); + } + } + }; + + // This thread attempts to get ones we know have already been put in. + final Thread getExisting = new Thread() { + @Override + public void run() { + final Random rnd = new Random(); + try { + while (run.get()) { + final License license = License.findByValue("http://creativecommons.org/licenses/" + rnd.nextInt(type.intValue()) + "/1"); + if (license == null) { + hadProblem.set(true); + } + } + } catch (final Exception e) { + hadException.set(true); + } + } + }; + + addNew.start(); + getExisting.start(); + // Let them do some stuff. + Thread.sleep(400); + // Get them to both stop. + run.set(false); + // Allow them a little time to stop. + addNew.join(50); + getExisting.join(50); + // Check we didn't have any problems and they have both stopped. + assertFalse(hadProblem.get()); + assertFalse(hadException.get()); + assertFalse(addNew.isAlive()); + assertFalse(getExisting.isAlive()); + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/content/ContentItemTest.java b/rome-modules/src/test/java/com/rometools/modules/content/ContentItemTest.java new file mode 100644 index 0000000..0df4790 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/content/ContentItemTest.java @@ -0,0 +1,144 @@ +/* + * ContentItemTest.java + * JUnit based test + * + * Created on February 2, 2005, 2:50 PM + */ + +package com.rometools.modules.content; + +import junit.framework.TestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.content.ContentItem; + +/** + * This is all standard property storage testing. + * + * @author Robert Cooper + */ +public class ContentItemTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ContentItemTest.class); + + private final ContentItem item = new ContentItem(); + + public ContentItemTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws java.lang.Exception { + } + + @Override + protected void tearDown() throws java.lang.Exception { + } + + public static junit.framework.Test suite() { + final junit.framework.TestSuite suite = new junit.framework.TestSuite(ContentItemTest.class); + + return suite; + } + + /** + * Test of ContentFormat method, of class com.totsp.xml.syndication.content.ContentItem. + */ + public void testContentFormat() { + LOG.debug("testContentFormat"); + final String test = "application/xhtml"; + item.setContentFormat(test); + assertTrue(item.getContentFormat().equals(test)); + } + + /** + * Test of ContentEncoding method, of class com.totsp.xml.syndication.content.ContentItem. + */ + public void testContentEncoding() { + LOG.debug("testContentEncoding"); + final String test = "http://www.w3.org/TR/REC-xml#dt-wellformed"; + + item.setContentFormat(test); + assertTrue(item.getContentFormat().equals(test)); + } + + /** + * Test of ContentValue method, of class com.totsp.xml.syndication.content.ContentItem. + */ + public void testContentValue() { + LOG.debug("testContentValue"); + final String test = "This isvery cool."; + + item.setContentFormat(test); + assertTrue(item.getContentFormat().equals(test)); + } + + /** + * Test of ContentAbout method, of class com.totsp.xml.syndication.content.ContentItem. + */ + public void testContentAbout() { + LOG.debug("testContentAbout"); + final String test = "http://example.org/item/content.svg"; + + item.setContentFormat(test); + assertTrue(item.getContentFormat().equals(test)); + } + + /** + * Test of ContentValueParseType method, of class com.totsp.xml.syndication.content.ContentItem. + */ + public void testContentValueParseType() { + LOG.debug("testContentValueParseType"); + final String test = "Literal"; + + item.setContentFormat(test); + assertTrue(item.getContentFormat().equals(test)); + } + + /** + * Test of ContentValueNamespace method, of class com.totsp.xml.syndication.content.ContentItem. + */ + public void testContentValueNamespace() { + LOG.debug("testContentValueNamespace"); + final String test = "http://www.w3.org/1999/xhtml"; + + item.setContentFormat(test); + assertTrue(item.getContentFormat().equals(test)); + } + + /** + * Test of ContentResource method, of class com.totsp.xml.syndication.content.ContentItem. + */ + public void testContentResource() { + LOG.debug("testContentResource"); + final String test = "http://www.w3.org/2000/svg"; + + item.setContentResource(test); + assertTrue(item.getContentResource().equals(test)); + } + + /** + * this is a stupid test. + * + * @todo make better Test of ContentResource method, of class + * com.totsp.xml.syndication.content.ContentItem. + */ + public void testEquals() { + LOG.debug("testEquals"); + final String test = "http://www.w3.org/2000/svg"; + + assertTrue(test.equals(test)); + final ContentItem test2 = ContentModuleImplTest.contentItems.get(0); + assertTrue(!test.equals(test2)); + final ContentItem test3 = new ContentItem(); + test3.setContentFormat(new String("http://www.w3.org/1999/xhtml")); + test3.setContentEncoding(new String("http://www.w3.org/TR/REC-xml#dt-wellformed")); + test3.setContentEncoding(new String("Literal")); + // test3.setContentValueNamespace(new String("http://www.w3.org/1999/xhtml")); + test3.setContentValue(new String("This is very cool.")); + // assertEquals( test2, test3 ); + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/content/ContentModuleGeneratorTest.java b/rome-modules/src/test/java/com/rometools/modules/content/ContentModuleGeneratorTest.java new file mode 100644 index 0000000..3e5a7fd --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/content/ContentModuleGeneratorTest.java @@ -0,0 +1,67 @@ +/* + * ContentModuleGeneratorTest.java + * JUnit based test + * + * Created on February 2, 2005, 4:15 PM + */ +package com.rometools.modules.content; + +import java.io.File; +import java.io.StringWriter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.content.ContentModule; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; +import com.rometools.rome.io.XmlReader; + +/** + * + * @author Robert Cooper + */ +public class ContentModuleGeneratorTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ContentModuleGeneratorTest.class); + + public ContentModuleGeneratorTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws java.lang.Exception { + } + + @Override + protected void tearDown() throws java.lang.Exception { + } + + public static junit.framework.Test suite() { + final junit.framework.TestSuite suite = new junit.framework.TestSuite(ContentModuleGeneratorTest.class); + + return suite; + } + + /** + * Test of generate method, of class com.totsp.xml.syndication.content.ContentModuleGenerator. + */ + public void testGenerate() throws Exception { + + LOG.debug("testGenerate"); + + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed feed = input.build(new XmlReader(new File(getTestFile("xml/test-rdf.xml")).toURI().toURL())); + final SyndEntry entry = feed.getEntries().get(0); + entry.getModule(ContentModule.URI); + final SyndFeedOutput output = new SyndFeedOutput(); + final StringWriter writer = new StringWriter(); + output.output(feed, writer); + + LOG.debug("{}", writer); + + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/content/ContentModuleImplTest.java b/rome-modules/src/test/java/com/rometools/modules/content/ContentModuleImplTest.java new file mode 100644 index 0000000..1679dc5 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/content/ContentModuleImplTest.java @@ -0,0 +1,138 @@ +/* + * ContentModuleImplTest.java + * JUnit based test + * + * Created on February 2, 2005, 2:58 PM + */ + +package com.rometools.modules.content; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.content.ContentItem; +import com.rometools.modules.content.ContentModule; +import com.rometools.modules.content.ContentModuleImpl; + +/** + * + * @author Robert Cooper + */ +public class ContentModuleImplTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ContentModuleImplTest.class); + + private final ContentModuleImpl module = new ContentModuleImpl(); + public static ArrayList contentItems = new ArrayList(); + + static { + ContentItem item = new ContentItem(); + item.setContentFormat("http://www.w3.org/1999/xhtml"); + item.setContentEncoding("http://www.w3.org/TR/REC-xml#dt-wellformed"); + // item.setContentValueNamespaces("http://www.w3.org/1999/xhtml"); + item.setContentValue("This is very cool."); + item.setContentValueParseType("Literal"); + + contentItems.add(item); + + item = new ContentItem(); + item.setContentFormat("http://www.w3.org/TR/html4/"); + item.setContentValue("This isvery cool."); + + contentItems.add(item); + + item = new ContentItem(); + item.setContentAbout("http://example.org/item/content-here.txt"); + item.setContentFormat("http://www.isi.edu/in-notes/iana/assignments/media-types/text/plain"); + item.setContentValue("This is >very cool<."); + + contentItems.add(item); + + item = new ContentItem(); + item.setContentAbout("http://example.org/item/content.svg"); + item.setContentResource("http://www.w3.org/2000/svg"); + + contentItems.add(item); + } + + public ContentModuleImplTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws java.lang.Exception { + + } + + @Override + protected void tearDown() throws java.lang.Exception { + } + + public static junit.framework.Test suite() { + final junit.framework.TestSuite suite = new junit.framework.TestSuite(ContentModuleImplTest.class); + + return suite; + } + + /** + * Test of getEncodeds method, of class com.totsp.xml.syndication.content.ContentModuleImpl. + */ + public void testEncodeds() { + final ArrayList encodeds = new ArrayList(); + encodeds.add("Foo"); + encodeds.add("Bar"); + encodeds.add("Baz"); + module.setEncodeds(encodeds); + final List check = module.getEncodeds(); + assertTrue(check.equals(encodeds)); + + } + + /** + * Test of getInterface method, of class com.totsp.xml.syndication.content.ContentModuleImpl. + */ + public void testInterface() { + LOG.debug("testInterface"); + assertTrue(module.getInterface().equals(ContentModule.class)); + } + + /** + * Test of getContentItems method, of class com.totsp.xml.syndication.content.ContentModuleImpl. + */ + public void testContentItems() { + LOG.debug("testContentItems"); + module.setContentItems(contentItems); + assertTrue(module.getContentItems().equals(contentItems)); + } + + /** + * Test of getContents method, of class com.totsp.xml.syndication.content.ContentModuleImpl. + */ + public void testContents() { + LOG.debug("testContents"); + final ArrayList contents = new ArrayList(); + contents.add("Foo"); + contents.add("Bar"); + contents.add("Baz"); + module.setContents(contents); + final List check = module.getContents(); + assertTrue(check.equals(contents)); + } + + /** + * Test of copyFrom method, of class com.totsp.xml.syndication.content.ContentModuleImpl. + */ + public void testCopyFrom() { + LOG.debug("testCopyFrom"); + final ContentModule test = new ContentModuleImpl(); + test.copyFrom(module); + assertTrue(test.getContentItems().equals(module.getContentItems()) & test.getContents().equals(module.getContents()) + & test.getEncodeds().equals(module.getEncodeds())); + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/content/ContentModuleParserTest.java b/rome-modules/src/test/java/com/rometools/modules/content/ContentModuleParserTest.java new file mode 100644 index 0000000..fb3bc57 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/content/ContentModuleParserTest.java @@ -0,0 +1,63 @@ +/* + * ContentModuleParserTest.java + * JUnit based test + * + * Created on February 2, 2005, 3:35 PM + */ +package com.rometools.modules.content; + +import java.io.File; +import java.util.List; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.content.ContentItem; +import com.rometools.modules.content.ContentModule; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.XmlReader; + +/** + * + * @author Robert Cooper + */ +public class ContentModuleParserTest extends AbstractTestCase { + public ContentModuleParserTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws java.lang.Exception { + } + + @Override + protected void tearDown() throws java.lang.Exception { + } + + public static junit.framework.Test suite() { + final junit.framework.TestSuite suite = new junit.framework.TestSuite(ContentModuleParserTest.class); + + return suite; + } + + /** + * Test of parse method, of class com.rometools.rome.feed.module.content.ContentModuleParser. + * It will test through the whole ROME framework. + */ + public void testParse() throws Exception { + + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed feed = input.build(new XmlReader(new File(getTestFile("xml/test-rdf.xml")).toURI().toURL())); + final SyndEntry entry = feed.getEntries().get(0); + final ContentModule module = (ContentModule) entry.getModule(ContentModule.URI); + final List items = module.getContentItems(); + + for (int i = 0; i < items.size(); i++) { + // FIXME + // final ContentItem item = ContentModuleImplTest.contentItems.get(i); + // assertEquals (item , items.get(i)); + } + + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/georss/GeoRSSModuleTest.java b/rome-modules/src/test/java/com/rometools/modules/georss/GeoRSSModuleTest.java new file mode 100644 index 0000000..3da4517 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/georss/GeoRSSModuleTest.java @@ -0,0 +1,288 @@ +/* + * Copyright 2006 Marc Wick, geonames.org + * + * 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.rometools.modules.georss; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.georss.GMLModuleImpl; +import com.rometools.modules.georss.GeoRSSModule; +import com.rometools.modules.georss.GeoRSSUtils; +import com.rometools.modules.georss.SimpleModuleImpl; +import com.rometools.modules.georss.geometries.LineString; +import com.rometools.modules.georss.geometries.Position; +import com.rometools.modules.georss.geometries.PositionList; +import com.rometools.rome.feed.synd.SyndContent; +import com.rometools.rome.feed.synd.SyndContentImpl; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndEntryImpl; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndFeedImpl; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; +import com.rometools.rome.io.XmlReader; + +/** + * tests for geo-rss module. + * + */ +public class GeoRSSModuleTest extends AbstractTestCase { + + public GeoRSSModuleTest(final String testName) { + super(testName); + } + + private static final double DELTA = 0.00001; + + /** + * compares expected lat/lng values with acutal values read from feed. + * + * @param fileName a file in the src/data directory + * @param expectedLat array of expected latitude values + * @param expectedLng array of expected longitude values + * @throws Exception if file not found or not accessible + */ + private void assertTestFile(final String fileName, final Double[] expectedLat, final Double[] expectedLng) throws Exception { + assertTestInputStream(new FileInputStream(new File("src/test/resources/data/", fileName)), expectedLat, expectedLng); + } + + /** + * test expected latitude and longitude values in items of test file. + * + * @param in testfeed + * @param expectedLat expected latitude values + * @param expectedLng expected longitude values + * @throws Exception if file not found or not accessible + */ + private void assertTestInputStream(final InputStream in, final Double[] expectedLat, final Double[] expectedLng) throws Exception { + final SyndFeedInput input = new SyndFeedInput(); + + final SyndFeed feed = input.build(new XmlReader(in)); + + final List entries = feed.getEntries(); + for (int i = 0; i < entries.size(); i++) { + final SyndEntry entry = entries.get(i); + final GeoRSSModule geoRSSModule = GeoRSSUtils.getGeoRSS(entry); + final Position position = geoRSSModule.getPosition(); + if (expectedLat[i] == null || expectedLng[i] == null) { + assertNull("position " + i, position); + } else { + assertEquals("lat " + i, expectedLat[i], position.getLatitude(), DELTA); + assertEquals("lng " + i, expectedLng[i], position.getLongitude(), DELTA); + } + } + } + + /** + * @return implementation of SyndFeed with basic setup + */ + private SyndFeed createFeed() { + final SyndFeed feed = new SyndFeedImpl(); + feed.setFeedType("rss_2.0"); + + feed.setTitle("Sample Feed (created with ROME)"); + feed.setLink("http://rome.dev.java.net"); + feed.setDescription("This feed has been created using ROME (Java syndication utilities"); + + final List entries = new ArrayList(); + SyndEntry entry; + SyndContent description; + + entry = new SyndEntryImpl(); + entry.setTitle("ROME v1.0"); + entry.setLink("http://wiki.java.net/bin/view/Javawsxml/Rome01"); + entry.setPublishedDate(new Date()); + description = new SyndContentImpl(); + description.setType("text/plain"); + description.setValue("Initial release of ROME"); + entry.setDescription(description); + entries.add(entry); + + feed.setEntries(entries); + return feed; + } + + /** + * @throws Exception if file not found or not accessible + */ + public void testReadRss2Simple() throws Exception { + final Double[] lat = { 31.7666667, 31.7666667, 31.7666667 }; + final Double[] lng = { 35.2333333, 35.2333333, 35.2333333 }; + assertTestFile("rss2.0-simple.xml", lat, lng); + } + + /** + * @throws Exception if file not found or not accessible + */ + public void testReadRss2W3CGeo() throws Exception { + final Double[] lat = { 42.986284, 41.492491, 39.901893, 40.750598 }; + final Double[] lng = { -71.45156, -72.095783, -75.171998, -73.993392 }; + assertTestFile("rss2.0-w3cgeo.xml", lat, lng); + } + + /** + * @throws Exception if file not found or not accessible + */ + public void xtestReadRss1W3CGeo() throws Exception { + final Double[] lat = { 45.9774, 45.9707, 46.0087 }; + final Double[] lng = { 8.9781, 8.97055, 8.98579 }; + assertTestFile("rss1.0-w3cgeo.xml", lat, lng); + } + + /** + * @throws Exception if file not found or not accessible + */ + public void testReadGML() throws Exception { + final Double[] lat = { 45.256, 45.256, 45.256, 45.256 }; + final Double[] lng = { -71.92, -71.92, -71.92, -71.92 }; + assertTestFile("rss2.0-gml.xml", lat, lng); + } + + /** + * @throws Exception if file not found or not accessible + */ + public void testNpeOnEmptyPoint() throws Exception { + final Double[] lat = { null, 0.0, 0.0, 0.0, 43.653226, 0.0, 0.0, 0.0, 0.0, 0.0 }; + final Double[] lng = { null, 0.0, 0.0, 0.0, -79.383184, 0.0, 0.0, 0.0, 0.0, 0.0 }; + assertTestFile("geo-rss-issue-27.rss", lat, lng); + } + + /** + * @throws Exception if file not found or not accessible + */ + public void xtestProduceAndReadGML() throws Exception { + final SyndFeed feed = createFeed(); + final GeoRSSModule geoRSSModule = new GMLModuleImpl(); + final double latitude = 47.0; + final double longitude = 9.0; + final Position position = new Position(); + position.setLatitude(latitude); + position.setLongitude(longitude); + geoRSSModule.setPosition(position); + + final SyndEntry entry = feed.getEntries().get(0); + entry.getModules().add(geoRSSModule); + + final SyndFeedOutput output = new SyndFeedOutput(); + + final StringWriter stringWriter = new StringWriter(); + output.output(feed, stringWriter); + + final InputStream in = new ByteArrayInputStream(stringWriter.toString().getBytes("UTF8")); + final Double[] lat = { latitude }; + final Double[] lng = { longitude }; + assertTestInputStream(in, lat, lng); + } + + /** + * @throws Exception if file not found or not accessible + */ + public void testProduceAndReadSimple() throws Exception { + final SyndFeed feed = createFeed(); + final GeoRSSModule geoRSSModule = new SimpleModuleImpl(); + final double latitude = 47.0; + final double longitude = 9.0; + final Position position = new Position(); + position.setLatitude(latitude); + position.setLongitude(longitude); + geoRSSModule.setPosition(position); + + final SyndEntry entry = feed.getEntries().get(0); + entry.getModules().add(geoRSSModule); + + final SyndFeedOutput output = new SyndFeedOutput(); + + final StringWriter stringWriter = new StringWriter(); + output.output(feed, stringWriter); + + final InputStream in = new ByteArrayInputStream(stringWriter.toString().getBytes("UTF8")); + final Double[] lat = { latitude }; + final Double[] lng = { longitude }; + assertTestInputStream(in, lat, lng); + } + + /** + * @throws Exception if file not found or not accessible + */ + public void testProduceAndReadSimpleLine() throws Exception { + SyndFeed feed = createFeed(); + + final double[] latitudes = new double[] { 45.256, 46.46, 43.84 }; + final double[] longitudes = new double[] { -110.45, -109.48, -109.86 }; + // 45.256 -110.45 46.46 -109.48 43.84 -109.86 + PositionList positionList = new PositionList(); + positionList.add(latitudes[0], longitudes[0]); + positionList.add(latitudes[1], longitudes[1]); + positionList.add(latitudes[2], longitudes[2]); + + SimpleModuleImpl geoRSSModule = new SimpleModuleImpl(); + geoRSSModule.setGeometry(new LineString(positionList)); + + SyndEntry entry = feed.getEntries().get(0); + entry.getModules().add(geoRSSModule); + + final SyndFeedOutput output = new SyndFeedOutput(); + + final StringWriter stringWriter = new StringWriter(); + output.output(feed, stringWriter); + + final InputStream in = new ByteArrayInputStream(stringWriter.toString().getBytes("UTF8")); + final SyndFeedInput input = new SyndFeedInput(); + + feed = input.build(new XmlReader(in)); + + final List entries = feed.getEntries(); + for (int i = 0; i < entries.size(); i++) { + entry = entries.get(i); + geoRSSModule = (SimpleModuleImpl) GeoRSSUtils.getGeoRSS(entry); + final LineString lineString = (LineString) geoRSSModule.getGeometry(); + positionList = lineString.getPositionList(); + + assertEquals(latitudes[i], positionList.getLatitude(i), DELTA); + assertEquals(longitudes[i], positionList.getLongitude(i), DELTA); + } + } + + /** + * Tests whether a feed with invalid point values can be parsed + * (https://github.com/rometools/rome-modules/issues/02). + * + * @throws IOException if file not found or not accessible + * @throws FeedException when the feed can't be parsed + * + */ + public void testParseInvalidPointValue() throws IOException, FeedException { + // only tests whether file can be parsed (there should be no exception) + getSyndFeed("org/rometools/feed/module/georss/issue-02.xml"); + } + + private SyndFeed getSyndFeed(final String filePath) throws IOException, FeedException { + final String fullPath = getTestFile(filePath); + final File file = new File(fullPath); + return new SyndFeedInput().build(file); + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/itunes/ITunesGeneratorTest.java b/rome-modules/src/test/java/com/rometools/modules/itunes/ITunesGeneratorTest.java new file mode 100644 index 0000000..d57859c --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/itunes/ITunesGeneratorTest.java @@ -0,0 +1,109 @@ +/* + * ITunesGeneratorTest.java + * JUnit based test + * + * Created on August 2, 2005, 2:31 PM + */ +package com.rometools.modules.itunes; + +import java.io.File; +import java.io.StringWriter; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.itunes.AbstractITunesObject; +import com.rometools.modules.itunes.FeedInformation; +import com.rometools.modules.itunes.FeedInformationImpl; +import com.rometools.modules.itunes.types.Category; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndFeedImpl; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; +import com.rometools.rome.io.XmlReader; + +/** + * + * @author cooper + */ +public class ITunesGeneratorTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ITunesGeneratorTest.class); + + static final String URI = AbstractITunesObject.URI; + + public ITunesGeneratorTest(final String testName) { + super(testName); + } + + public static Test suite() { + return new TestSuite(ITunesGeneratorTest.class); + } + + /** + * Test of generate method, of class com.totsp.xml.syndication.itunes.ITunesGenerator. + */ + public void testEndToEnd() throws Exception { + LOG.debug("testEndToEnd"); + testFile("xml/leshow.xml"); + // testFile( "/test/xml/apple.xml" ); + testFile("xml/lr.xml"); + } + + private void testFile(final String filename) throws Exception { + final File feed = new File(getTestFile(filename)); + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed syndfeed = input.build(new XmlReader(feed.toURI().toURL())); + + final SyndFeedOutput output = new SyndFeedOutput(); + final File outfeed = new File(feed.getAbsolutePath() + ".output"); + output.output(syndfeed, outfeed); + + final SyndFeed syndCheck = input.build(new XmlReader(outfeed.toURI().toURL())); + LOG.debug(syndCheck.getModule(AbstractITunesObject.URI).toString()); + assertEquals("Feed Level: ", syndfeed.getModule(AbstractITunesObject.URI).toString(), syndCheck.getModule(AbstractITunesObject.URI).toString()); + + final List syndEntries = syndfeed.getEntries(); + final List syndChecks = syndCheck.getEntries(); + + for (int i = 0; i < syndEntries.size(); i++) { + final SyndEntry entry = syndEntries.get(i); + final SyndEntry check = syndChecks.get(i); + LOG.debug("Original: " + entry.getModule(AbstractITunesObject.URI)); + LOG.debug("Check: " + check.getModule(AbstractITunesObject.URI)); + LOG.debug(entry.getModule(AbstractITunesObject.URI).toString()); + LOG.debug("-----------------------------------------"); + LOG.debug(check.getModule(AbstractITunesObject.URI).toString()); + assertEquals("Entry Level: ", entry.getModule(AbstractITunesObject.URI).toString(), check.getModule(AbstractITunesObject.URI).toString()); + } + } + + public void testCreate() throws Exception { + + final SyndFeed feed = new SyndFeedImpl(); + final String feedType = "rss_2.0"; + feed.setFeedType(feedType); + feed.setLanguage("en-us"); + feed.setTitle("sales.com on the Radio!"); + feed.setDescription("sales.com radio shows in MP3 format"); + feed.setLink("http://foo/rss/podcasts.rss"); + + final FeedInformation fi = new FeedInformationImpl(); + fi.setOwnerName("sales.com"); + fi.getCategories().add(new Category("Shopping")); + fi.setOwnerEmailAddress("patti@sales.com"); + feed.getModules().add(fi); + + final SyndFeedOutput output = new SyndFeedOutput(); + final StringWriter writer = new StringWriter(); + output.output(feed, writer); + LOG.debug("{}", writer); + + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/itunes/ITunesParserTest.java b/rome-modules/src/test/java/com/rometools/modules/itunes/ITunesParserTest.java new file mode 100644 index 0000000..eb8fd68 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/itunes/ITunesParserTest.java @@ -0,0 +1,123 @@ +/* + * ITunesParserTest.java + * JUnit based test + * + * Created on August 2, 2005, 1:30 PM + */ +package com.rometools.modules.itunes; + +import java.io.File; +import java.util.Iterator; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.itunes.AbstractITunesObject; +import com.rometools.modules.itunes.EntryInformationImpl; +import com.rometools.modules.itunes.FeedInformationImpl; +import com.rometools.modules.itunes.io.ITunesGenerator; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.XmlReader; + +/** + * + * @author cooper + */ +public class ITunesParserTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ITunesParserTest.class); + + public ITunesParserTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + public static Test suite() { + final TestSuite suite = new TestSuite(ITunesParserTest.class); + + return suite; + } + + /** + * Test of getNamespaceUri method, of class com.totsp.xml.syndication.itunes.ITunesParser. + */ + public void testGetNamespaceUri() { + LOG.debug("testGetNamespaceUri"); + + assertEquals("Namespace", "http://www.itunes.com/dtds/podcast-1.0.dtd", new ITunesGenerator().getNamespaceUri()); + } + + /** + * Test of parse method, of class com.totsp.xml.syndication.itunes.ITunesParser. + */ + public void testParse() throws Exception { + File feed = new File(getTestFile("xml/leshow.xml")); + final SyndFeedInput input = new SyndFeedInput(); + SyndFeed syndfeed = input.build(new XmlReader(feed.toURI().toURL())); + + final Module module = syndfeed.getModule(AbstractITunesObject.URI); + final FeedInformationImpl feedInfo = (FeedInformationImpl) module; + + assertEquals("owner", "Harry Shearer", feedInfo.getOwnerName()); + assertEquals("email", "", feedInfo.getOwnerEmailAddress()); + assertEquals("image", "http://a1.phobos.apple.com/Music/y2005/m06/d26/h21/mcdrrifv.jpg", feedInfo.getImage().toExternalForm()); + assertEquals("category", "Comedy", feedInfo.getCategories().get(0).getName()); + assertEquals( + "summary", + "A weekly, hour-long romp through the worlds of media, politics, sports and show business, leavened with an eclectic mix of mysterious music, hosted by Harry Shearer.", + feedInfo.getSummary()); + assertEquals(true, feedInfo.getComplete()); + assertEquals("http://example.org", feedInfo.getNewFeedUrl()); + + List entries = syndfeed.getEntries(); + Iterator it = entries.iterator(); + + while (it.hasNext()) { + final SyndEntry entry = it.next(); + final EntryInformationImpl entryInfo = (EntryInformationImpl) entry.getModule(AbstractITunesObject.URI); + LOG.debug("{}", entryInfo); + } + + feed = new File(getTestFile("xml/rsr.xml")); + syndfeed = input.build(new XmlReader(feed.toURI().toURL())); + entries = syndfeed.getEntries(); + it = entries.iterator(); + + while (it.hasNext()) { + final SyndEntry entry = it.next(); + final EntryInformationImpl entryInfo = (EntryInformationImpl) entry.getModule(AbstractITunesObject.URI); + LOG.debug("{}", entryInfo.getDuration()); + } + } + + /** + * Test of parse method, of class com.rometools.modules.itunes.io.ITunesParser. + */ + public void testParseItem() throws Exception { + File feed = new File(getTestFile("xml/leshow.xml")); + final SyndFeedInput input = new SyndFeedInput(); + SyndFeed syndfeed = input.build(new XmlReader(feed.toURI().toURL())); + + SyndEntry entry = syndfeed.getEntries().get(0); + + EntryInformationImpl entryInfo = (EntryInformationImpl) entry.getModule(AbstractITunesObject.URI); + assertEquals(true, entryInfo.getClosedCaptioned()); + assertEquals(Integer.valueOf(2), entryInfo.getOrder()); + assertEquals("http://example.org/image.png", entryInfo.getImage().toString()); + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/itunes/types/DurationTest.java b/rome-modules/src/test/java/com/rometools/modules/itunes/types/DurationTest.java new file mode 100644 index 0000000..cb91cd9 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/itunes/types/DurationTest.java @@ -0,0 +1,83 @@ +/* + * DurationTest.java + * JUnit based test + * + * Created on August 1, 2005, 8:02 PM + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.rometools.modules.itunes.types; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.itunes.types.Duration; + +/** + * + * @author cooper + */ +public class DurationTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(DurationTest.class); + + private final Duration duration = new Duration(2 * Duration.HOUR + 3 * Duration.MINUTE + 20 * Duration.SECOND); + private final Duration duration2 = new Duration(12000 * Duration.HOUR + 61 * Duration.MINUTE + 61 * Duration.SECOND); + private final Duration duration3 = new Duration("1:20:01"); + private final long duration3ms = Duration.HOUR * 1 + Duration.MINUTE * 20 + Duration.SECOND * 1; + + private final Duration duration4 = new Duration("1:02"); + private final long duration4ms = Duration.MINUTE * 1 + Duration.SECOND * 2; + + public DurationTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + public static Test suite() { + final TestSuite suite = new TestSuite(DurationTest.class); + + return suite; + } + + /** + * Test of toString method, of class com.totsp.xml.syndication.itunes.Duration. + */ + public void testToString() { + LOG.debug("testToString"); + LOG.debug(duration.toString()); + assertEquals("Regular time failed", "02:03:20", duration.toString()); + LOG.debug(duration2.toString()); + assertEquals("Long time failed", "12001:02:01", duration2.toString()); + } + + public void testGetMilliseconds() { + LOG.debug("testGetMilliseconds"); + assertEquals("Milliseconds from 3 string constructor", duration3ms, duration3.getMilliseconds()); + assertEquals("Milliseconds from 2 string constructor", duration4ms, duration4.getMilliseconds()); + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/mediarss/GoogleTest.java b/rome-modules/src/test/java/com/rometools/modules/mediarss/GoogleTest.java new file mode 100644 index 0000000..59f7699 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/mediarss/GoogleTest.java @@ -0,0 +1,49 @@ +/* + * MediaModuleTest.java + * JUnit based test + * + * Created on March 29, 2006, 11:49 PM + */ + +package com.rometools.modules.mediarss; + +import java.io.InputStreamReader; +import java.net.URL; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.mediarss.MediaEntryModule; +import com.rometools.modules.mediarss.MediaModule; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; + +/** + * + * @author cooper + */ +public class GoogleTest extends AbstractTestCase { + + public GoogleTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(MediaModuleTest.class); + + return suite; + } + + public static void testGoogleVideo() throws Exception { + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed feed = input.build(new InputStreamReader(new URL("http://video.google.com/videofeed?type=top100new&num=20&output=rss").openStream())); + for (final Object element : feed.getEntries()) { + final SyndEntry entry = (SyndEntry) element; + final MediaEntryModule m = (MediaEntryModule) entry.getModule(MediaModule.URI); + System.out.print(m); + } + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/mediarss/MediaModuleTest.java b/rome-modules/src/test/java/com/rometools/modules/mediarss/MediaModuleTest.java new file mode 100644 index 0000000..f53a68f --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/mediarss/MediaModuleTest.java @@ -0,0 +1,177 @@ +/* + * MediaModuleTest.java + * JUnit based test + * + * Created on March 29, 2006, 11:49 PM + */ + +package com.rometools.modules.mediarss; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.mediarss.MediaEntryModule; +import com.rometools.modules.mediarss.MediaModule; +import com.rometools.modules.mediarss.types.MediaContent; +import com.rometools.modules.mediarss.types.Rating; +import com.rometools.modules.mediarss.types.Thumbnail; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; + +/** + * + * @author cooper + */ +public class MediaModuleTest extends AbstractTestCase { + + /** + * @param testName id of test + */ + public MediaModuleTest(final String testName) { + super(testName); + } + + /** + * @return actual test suite + */ + public static Test suite() { + return new TestSuite(MediaModuleTest.class); + } + + /** + * @throws Exception if file not found or not accessible + */ + public void testGoogleVideo() throws Exception { + final SyndFeed feed = getSyndFeed(new File(getTestFile("data/YouTube-MostPopular.rss"))); + for (final Object element : feed.getEntries()) { + final SyndEntry entry = (SyndEntry) element; + final MediaEntryModule m = (MediaEntryModule) entry.getModule(MediaModule.URI); + assertNotNull(m); + } + } + + /** + * @throws Exception if file not found or not accessible + */ + public void testParse() throws Exception { + final File test = new File(super.getTestFile("xml")); + final File[] files = test.listFiles(); + for (int j = 0; j < files.length; j++) { + if (!files[j].getName().endsWith(".xml")) { + continue; + } + final SyndFeed feed = getSyndFeed(files[j]); + final List entries = feed.getEntries(); + final SyndFeedOutput output = new SyndFeedOutput(); + output.output(feed, new File("target/" + j + ".xml")); + final SyndFeed feed2 = getSyndFeed(new File("target/" + j + ".xml")); + for (int i = 0; i < entries.size(); i++) { + BufferedWriter b = new BufferedWriter(new FileWriter("target/" + j + "a.txt")); + b.write("" + entries.get(i).getModule(MediaModule.URI)); + b.close(); + b = new BufferedWriter(new FileWriter("target/" + j + "b.txt")); + b.write("" + feed2.getEntries().get(i).getModule(MediaModule.URI)); + b.close(); + assertEquals(entries.get(i).getModule(MediaModule.URI), feed2.getEntries().get(i).getModule(MediaModule.URI)); + } + } + } + + /** + * tests parsing thubnails with empty dimensions + * (https://github.com/rometools/rome-modules/issues/7). + * + * @throws IOException if file not found or not accessible + * @throws FeedException when the feed can't be parsed + * + */ + public void testParseThumbnailWithEmptyDimensions() throws FeedException, IOException { + + final SyndFeed feed = getSyndFeed("org/rometools/feed/module/mediarss/issue-07.xml"); + final SyndEntry entry = feed.getEntries().get(0); + final MediaEntryModule module = (MediaEntryModule) entry.getModule(MediaModule.URI); + final Thumbnail[] thumbnails = module.getMetadata().getThumbnail(); + + assertThat(thumbnails, is(notNullValue())); + + } + + /** + * tests parsing a decimal duration (https://github.com/rometools/rome-modules/issues/8). + * + * @throws IOException if file not found or not accessible + * @throws FeedException when the feed can't be parsed + * + */ + public void testParseDecimalDuration() throws FeedException, IOException { + + final SyndFeed feed = getSyndFeed("org/rometools/feed/module/mediarss/issue-08.xml"); + final SyndEntry entry = feed.getEntries().get(0); + final MediaEntryModule module = (MediaEntryModule) entry.getModule(MediaModule.URI); + final Thumbnail[] thumbnails = module.getMetadata().getThumbnail(); + + assertThat(thumbnails, is(notNullValue())); + + } + + /** + * tests parsing rating without scheme (https://github.com/rometools/rome-modules/issues/12). + * + * @throws IOException if file not found or not accessible + * @throws FeedException when the feed can't be parsed + * + */ + public void testParseRatingWithoutScheme() throws FeedException, IOException { + + final SyndFeed feed = getSyndFeed("org/rometools/feed/module/mediarss/issue-12.xml"); + final SyndEntry entry = feed.getEntries().get(0); + final MediaEntryModule module = (MediaEntryModule) entry.getModule(MediaModule.URI); + final Rating[] ratings = module.getMetadata().getRatings(); + + assertThat(ratings, is(notNullValue())); + + } + + /** + * test url with whitespace in media element + * (https://github.com/rometools/rome-modules/issues/20). + * + * @throws Exception if file not found or not accessible + */ + public void testParseMediaContentContainingURLWithSpaces() throws Exception { + final SyndFeed feed = getSyndFeed("org/rometools/feed/module/mediarss/issue-20.xml"); + final SyndEntry entry = feed.getEntries().get(0); + final MediaEntryModule m = (MediaEntryModule) entry.getModule(MediaModule.URI); + assertNotNull("missing media entry module", m); + final MediaContent[] mcs = m.getMediaContents(); + assertNotNull("missing media:content", mcs); + assertEquals("wrong count of media:content", 1, mcs.length); + final MediaContent mc = mcs[0]; + assertEquals("http://www.foo.com/path/containing+spaces/trailer.mov", mc.getReference().toString()); + } + + private SyndFeed getSyndFeed(final File file) throws IOException, FeedException { + return new SyndFeedInput().build(file); + } + + private SyndFeed getSyndFeed(final String filePath) throws IOException, FeedException { + final String fullPath = getTestFile(filePath); + final File file = new File(fullPath); + return new SyndFeedInput().build(file); + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/mediarss/types/TimeTest.java b/rome-modules/src/test/java/com/rometools/modules/mediarss/types/TimeTest.java new file mode 100644 index 0000000..63c1c1d --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/mediarss/types/TimeTest.java @@ -0,0 +1,50 @@ +/* + * TimeTest.java + * JUnit based test + * + * Created on April 18, 2006, 10:01 PM + */ + +package com.rometools.modules.mediarss.types; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.mediarss.types.Time; + +/** + * + * @author cooper + */ +public class TimeTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(TimeTest.class); + + public TimeTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(TimeTest.class); + + return suite; + } + + /** + * Test of toString method, of class com.rometools.rome.feed.module.mediarss.types.Time. + */ + public void testToString() { + final Time t = new Time("12:05:35.3"); + LOG.debug("{}", t); + final Time t2 = new Time(t.toString()); + Assert.assertEquals(t.toString(), t2.toString()); + LOG.debug("{}", t2); + LOG.debug(new Time("3:54.00001").toString()); + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/opensearch/OpenSearchModuleTest.java b/rome-modules/src/test/java/com/rometools/modules/opensearch/OpenSearchModuleTest.java new file mode 100644 index 0000000..78b74aa --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/opensearch/OpenSearchModuleTest.java @@ -0,0 +1,56 @@ +/* + * OpenSearchModuleTest.java + * JUnit based test + * + * Created on April 25, 2006, 8:56 PM + */ + +package com.rometools.modules.opensearch; + +import java.io.File; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.opensearch.OpenSearchModule; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; + +/** + * + * @author cooper + */ +public class OpenSearchModuleTest extends AbstractTestCase { + + public OpenSearchModuleTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(OpenSearchModuleTest.class); + + return suite; + } + + public void testEndToEnd() throws Exception { + final SyndFeedInput input = new SyndFeedInput(); + final File test = new File(super.getTestFile("os")); + final File[] files = test.listFiles(); + for (int j = 0; j < files.length; j++) { + if (!files[j].getName().endsWith(".xml")) { + continue; + } + final SyndFeed feed = input.build(files[j]); + final Module m = feed.getModule(OpenSearchModule.URI); + final SyndFeedOutput output = new SyndFeedOutput(); + final File outfile = new File("target/" + files[j].getName()); + output.output(feed, outfile); + final SyndFeed feed2 = input.build(outfile); + assertEquals(m, feed2.getModule(OpenSearchModule.URI)); + } + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/photocast/io/GeneratorTest.java b/rome-modules/src/test/java/com/rometools/modules/photocast/io/GeneratorTest.java new file mode 100644 index 0000000..c34e95a --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/photocast/io/GeneratorTest.java @@ -0,0 +1,80 @@ +/* + * GeneratorTest.java + * JUnit based test + * + * Created on April 16, 2006, 5:58 PM + */ + +package com.rometools.modules.photocast.io; + +import java.io.File; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.photocast.PhotocastModule; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; + +/** + * + * @author cooper + */ +public class GeneratorTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(GeneratorTest.class); + + public GeneratorTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(GeneratorTest.class); + + return suite; + } + + /** + * Test of generate method, of class com.rometools.rome.feed.module.photocast.io.Generator. + */ + public void testGenerate() throws Exception { + final SyndFeedInput input = new SyndFeedInput(); + + final SyndFeed feed = input.build(new File(super.getTestFile("index.rss"))); + final List entries = feed.getEntries(); + for (int i = 0; i < entries.size(); i++) { + LOG.debug("{}", entries.get(i).getModule(PhotocastModule.URI)); + } + final SyndFeedOutput output = new SyndFeedOutput(); + output.output(feed, new File("target/index.rss")); + final SyndFeed feed2 = input.build(new File("target/index.rss")); + final List entries2 = feed2.getEntries(); + for (int i = 0; i < entries.size(); i++) { + assertEquals("Module test", entries.get(i).getModule(PhotocastModule.URI), entries2.get(i).getModule(PhotocastModule.URI)); + } + } + + /** + * Test of getNamespaces method, of class + * com.rometools.rome.feed.module.photocast.io.Generator. + */ + public void testGetNamespaces() { + // TODO add your test code. + } + + /** + * Test of getNamespaceUri method, of class + * com.rometools.rome.feed.module.photocast.io.Generator. + */ + public void testGetNamespaceUri() { + // TODO add your test code. + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/sle/GroupAndSortTest.java b/rome-modules/src/test/java/com/rometools/modules/sle/GroupAndSortTest.java new file mode 100644 index 0000000..aa7795b --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/sle/GroupAndSortTest.java @@ -0,0 +1,132 @@ +package com.rometools.modules.sle; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.sle.SimpleListExtension; +import com.rometools.modules.sle.SleUtility; +import com.rometools.modules.sle.types.Sort; +import com.rometools.rome.feed.module.Extendable; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; + +/** + * + * @author cooper + */ +public class GroupAndSortTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(GroupAndSortTest.class); + + public GroupAndSortTest(final String testName) { + super(testName); + } + + public static Test suite() { + return new TestSuite(GroupAndSortTest.class); + } + + /** + * Test of sort method, of class com.rometools.rome.feed.module.sle.GroupAndSort. + */ + public void testSort() throws Exception { + + final File testdata = new File(super.getTestFile("data/bookexample.xml")); + final SyndFeed feed = new SyndFeedInput().build(testdata); + + List entries = feed.getEntries(); + + final SimpleListExtension extention = (SimpleListExtension) feed.getModule(SimpleListExtension.URI); + final Sort[] sortFields = extention.getSortFields(); + + final Sort sortByDate = sortFields[1]; + final Sort sortByTitle = sortFields[2]; + + // sort by date ascending + List sortedEntries = SleUtility.sort(entries, sortByDate, true); + SyndEntry entry = sortedEntries.get(0); + assertEquals("Great Journeys of the Past", entry.getTitle()); + + // sort by date descending + sortedEntries = SleUtility.sort(entries, sortByDate, false); + entry = sortedEntries.get(0); + assertEquals("Horror Stories, vol 16", entry.getTitle()); + + // sort by date ascending + sortedEntries = SleUtility.sort(entries, sortByDate, true); + + // update first entry and reinitialize + entry = sortedEntries.get(0); + entry.setTitle("ZZZZZ"); + SleUtility.initializeForSorting(feed); + entries = feed.getEntries(); + + // sort by title desc + sortedEntries = SleUtility.sort(entries, sortByTitle, false); + entry = sortedEntries.get(0); + assertEquals("ZZZZZ", entry.getTitle()); + + // sort by title asc + sortedEntries = SleUtility.sort(entries, sortByTitle, true); + entry = sortedEntries.get(0); + assertEquals("Horror Stories, vol 16", entry.getTitle()); + + } + + /** + * Test of sort method, of class com.rometools.rome.feed.module.sle.GroupAndSort. + */ + public void testSort2() throws Exception { + + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed feed = input.build(new File(super.getTestFile("data/YahooTopSongs.xml"))); + final SimpleListExtension sle = (SimpleListExtension) feed.getModule(SimpleListExtension.URI); + + final List entries = new ArrayList(feed.getEntries()); + final List sortedEntries = SleUtility.sort(entries, sle.getSortFields()[0], true); + for (int i = 0; i < sortedEntries.size(); i++) { + final SyndEntry entry = (SyndEntry) sortedEntries.get(i); + LOG.debug(entry.getTitle()); + } + + } + + /** + * Test of group method, of class com.rometools.rome.feed.module.sle.GroupAndSort. + */ + public void testGroup() { + // TODO add your test code. + } + + /** + * Test of sortAndGroup method, of class com.rometools.rome.feed.module.sle.GroupAndSort. + */ + public void testSortAndGroup() throws Exception { + + final File testdata = new File(super.getTestFile("data/bookexample.xml")); + final SyndFeed feed = new SyndFeedInput().build(testdata); + + final List feedEntries = feed.getEntries(); + final List entries = new ArrayList(feedEntries); + + final SimpleListExtension sle = (SimpleListExtension) feed.getModule(SimpleListExtension.URI); + final Sort[] sortFields = sle.getSortFields(); + + final Sort sortByTitle = sortFields[2]; + + final List sortedEntries = SleUtility.sortAndGroup(entries, sle.getGroupFields(), sortByTitle, true); + final SyndEntry entry = (SyndEntry) sortedEntries.get(0); + assertEquals("Horror Stories, vol 16", entry.getTitle()); + + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/sle/io/ModuleGeneratorTest.java b/rome-modules/src/test/java/com/rometools/modules/sle/io/ModuleGeneratorTest.java new file mode 100644 index 0000000..01edf27 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/sle/io/ModuleGeneratorTest.java @@ -0,0 +1,37 @@ +/* + * ModuleGeneratorTest.java + * JUnit based test + * + * Created on April 29, 2006, 9:34 PM + */ + +package com.rometools.modules.sle.io; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * + * @author cooper + */ +public class ModuleGeneratorTest extends TestCase { + + public ModuleGeneratorTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(ModuleGeneratorTest.class); + + return suite; + } + + /** + * Test of generate method, of class com.rometools.rome.feed.module.sle.io.ModuleGenerator. + */ + public void testGenerate() { + // TODO add your test code. + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/sle/io/ModuleParserTest.java b/rome-modules/src/test/java/com/rometools/modules/sle/io/ModuleParserTest.java new file mode 100644 index 0000000..44aa0d8 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/sle/io/ModuleParserTest.java @@ -0,0 +1,73 @@ +/* + * ModuleParserTest.java + * JUnit based test + * + * Created on April 29, 2006, 7:00 PM + */ + +package com.rometools.modules.sle.io; + +import java.io.File; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.jdom2.Namespace; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.sle.SimpleListExtension; +import com.rometools.modules.sle.SleEntry; +import com.rometools.modules.sle.types.Group; +import com.rometools.modules.sle.types.Sort; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; + +/** + * + * @author cooper + */ +public class ModuleParserTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ModuleParserTest.class); + + public ModuleParserTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(ModuleParserTest.class); + + return suite; + } + + /** + * Test of parse method, of class com.rometools.rome.feed.module.sle.io.ModuleParser. + */ + public void testParse() throws Exception { + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed feed = input.build(new File(super.getTestFile("data/bookexample.xml"))); + final SimpleListExtension sle = (SimpleListExtension) feed.getModule(SimpleListExtension.URI); + // LOG.debug( sle ); + assertEquals("list", sle.getTreatAs()); + final Group[] groups = sle.getGroupFields(); + assertEquals("genre", groups[0].getElement()); + assertEquals("Genre", groups[0].getLabel()); + final Sort[] sorts = sle.getSortFields(); + assertEquals("Relevance", sorts[0].getLabel()); + assertTrue(sorts[0].getDefaultOrder()); + assertEquals(sorts[1].getNamespace(), Namespace.getNamespace("http://www.example.com/book")); + assertEquals(sorts[1].getDataType(), Sort.DATE_TYPE); + assertEquals(sorts[1].getElement(), "firstedition"); + final SyndEntry entry = feed.getEntries().get(0); + final SleEntry sleEntry = (SleEntry) entry.getModule(SleEntry.URI); + LOG.debug("{}", sleEntry); + LOG.debug("getGroupByElement"); + LOG.debug("{}", sleEntry.getGroupByElement(groups[0])); + LOG.debug("getSortByElement"); + LOG.debug("{}", sleEntry.getSortByElement(sorts[0])); + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/sse/SSEParserTest.java b/rome-modules/src/test/java/com/rometools/modules/sse/SSEParserTest.java new file mode 100644 index 0000000..a1a3479 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/sse/SSEParserTest.java @@ -0,0 +1,276 @@ +/* + * SSEParserTest.java + * JUnit based test + * + * Created on August 2, 2005, 1:30 PM + */ +package com.rometools.modules.sse; + +import java.io.File; +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.jdom2.Attribute; +import org.jdom2.Content; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.input.SAXBuilder; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.sse.SSE091Generator; +import com.rometools.modules.sse.modules.Conflict; +import com.rometools.modules.sse.modules.History; +import com.rometools.modules.sse.modules.SSEModule; +import com.rometools.modules.sse.modules.Sync; +import com.rometools.rome.feed.rss.Item; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; +import com.rometools.rome.io.XmlReader; +import com.rometools.rome.io.impl.DateParser; + +/** + * Test to verify correctness of SSE subproject. + */ +public class SSEParserTest extends AbstractTestCase { + public SSEParserTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + public static Test suite() { + return new TestSuite(SSEParserTest.class); + } + + /** + * Test of getNamespaceUri method, of class com.rometools.rome.feed.module.sse.SSE091 + */ + public void testGetNamespaceUri() { + assertEquals("Namespace", SSEModule.SSE_SCHEMA_URI, new SSE091Generator().getNamespaceUri()); + } + + public void xtestParseGenerateV5() throws Exception { + final URL feedURL = new File(getTestFile("xml/v/v5.xml")).toURI().toURL(); + // parse the document for comparison + final SAXBuilder builder = new SAXBuilder(); + final Document directlyBuilt = builder.build(feedURL); + + // generate the feed back into a document + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed inputFeed = input.build(new XmlReader(feedURL)); + + final SyndFeedOutput output = new SyndFeedOutput(); + final Document parsedAndGenerated = output.outputJDom(inputFeed); + + // XMLOutputter outputter = new XMLOutputter(); + // outputter.setFormat(Format.getPrettyFormat()); + // outputter.output(directlyBuilt, new + // FileOutputStream("c:\\cygwin\\tmp\\sync-direct.xml")); + // outputter.output(parsedAndGenerated, new + // FileOutputStream("c:\\cygwin\\tmp\\sync-pg.xml")); + + assertDocumentsEqual(directlyBuilt, parsedAndGenerated); + } + + // TODO: probably should rip this out and use xunit instead + private void assertDocumentsEqual(final Document one, final Document two) { + assertEqualElements(one.getRootElement(), two.getRootElement()); + } + + private void assertEqualElements(final Element one, final Element two) { + if (one == two || bothNull(one, two)) { + return; + } + + assertNullEqual("elements not null equal", one, two); + assertEqualAttributes(one, two); + asserEqualContent(one, two); + } + + private void assertNullEqual(final String mesg, final Object one, final Object two) { + assertTrue(mesg, nullEqual(one, two)); + } + + private boolean nullEqual(final Object one, final Object two) { + return one == null && two == null || one != null && two != null; + } + + private boolean bothNull(final Object one, final Object two) { + return one == null && two == null; + } + + private void assertEqualAttributes(final Element one, final Element two) { + assertTrue(equalAttributes(one, two, true)); + } + + private boolean equalAttributes(final Element one, final Element two, final boolean doAssert) { + final List attrs1 = one.getAttributes(); + final List attrs2 = two.getAttributes(); + + boolean equal = nullEqual(attrs1, attrs2); + if (doAssert) { + assertTrue("not null equal", equal); + } + + if (bothNull(attrs1, attrs2)) { + return true; + } + + if (equal) { + for (final Object element : attrs1) { + // compare the attributes in an order insensitive way + final Attribute a1 = (Attribute) element; + final Attribute a2 = findAttribute(a1.getName(), attrs2); + + equal = a2 != null; + if (!equal) { + if (doAssert) { + assertNotNull("no matching attribute for: " + one.getName() + "." + a1.getName() + "=" + a1.getValue(), a2); + } + break; + } + + Object av1 = a1.getValue(); + Object av2 = a2.getValue(); + + equal = nullEqual(av1, av2); + if (!equal && doAssert) { + assertNullEqual("attribute values not null equal: " + av1 + " != " + av2, av1, av2); + } + + if (!bothNull(av1, av2)) { + final String a1Name = a1.getName(); + + // this test is brittle, but its comprehensive + if ("until".equals(a1Name) || "since".equals(a1Name) || "when".equals(a1Name)) { + av1 = DateParser.parseRFC822((String) av1, Locale.US); + av2 = DateParser.parseRFC822((String) av2, Locale.US); + } + + assertTrue("unequal attributes:" + one.getName() + "." + a1.getName() + ": " + av1 + " != " + av2, av1.equals(av2)); + } + } + } + return equal; + } + + private Attribute findAttribute(final String name, final List attrs) { + for (final Attribute a : attrs) { + if (a.getName().equalsIgnoreCase(name)) { + return a; + } + } + return null; + } + + private void asserEqualContent(final Element one, final Element two) { + final List oneContent = one.getContent(); + final List twoContent = two.getContent(); + if (bothNull(oneContent, twoContent)) { + return; + } + + assertNullEqual("missing compare content", oneContent, twoContent); + assertEqualAttributes(one, two); + + // scan through the content to make sure each element is equal + for (final Object content1 : oneContent) { + if (content1 instanceof Element) { + final Element e1 = (Element) content1; + + boolean foundEqual = false; + final ArrayList messages = new ArrayList(); + for (final Object o : twoContent) { + if (o instanceof Element) { + final Element e2 = (Element) o; + + try { + // have to check all elements to be order insensitive + if (e1.getName().equals(e2.getName()) && equalAttributes(e1, e2, false)) { + assertEqualElements(e1, e2); + foundEqual = true; + messages.clear(); + break; + } + } catch (final Error e) { + messages.add(e.getMessage()); + } + } + } + + // if (!foundEqual) { + // // show accumulated error messages + // for (Iterator mesgIter = messages.iterator(); mesgIter.hasNext();) { + // LOG.debug((String) mesgIter.next()); + // } + // } + + // look for the content in the other tree + assertTrue("could not find matching element for: " + one.getName(), foundEqual); + } + } + } + + /** + * Assure v5 file parsed correctly. + * + * @throws Exception + */ + public void xtestV5() throws Exception { + final File feed = new File(getTestFile("xml/v/v5.xml")); + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeed syndfeed = input.build(new XmlReader(feed.toURI().toURL())); + + final List entries = syndfeed.getEntries(); + final Iterator it = entries.iterator(); + + for (int id = 101; it.hasNext() && id <= 113; id++) { + final SyndEntry entry = it.next(); + final Sync sync = (Sync) entry.getModule(SSEModule.SSE_SCHEMA_URI); + assertEquals(String.valueOf(id), sync.getId()); + + final History history = sync.getHistory(); + assertNotNull(history); + + final Date when = history.getWhen(); + assertNotNull(when); + final Date testDate = DateParser.parseRFC822("Fri, 6 Jan 2006 19:24:09 GMT", Locale.US); + assertEquals(testDate, when); + } + + for (int ep = 1; ep <= 2; ep++) { + for (int i = 100; i < 102; i++) { + final SyndEntry entry = it.next(); + final Sync sync = (Sync) entry.getModule(SSEModule.SSE_SCHEMA_URI); + final String id = sync.getId(); + assertEquals("ep" + ep + "." + i, id); + + if (id.equals("ep1.100")) { + final List conflicts = sync.getConflicts(); + assertNotNull(conflicts); + + final Conflict conflict = conflicts.get(0); + final Item conflictItem = conflict.getItem(); + + assertEquals(conflictItem.getTitle(), "Phish - Coventry Live (the last *good* concert)"); + assertEquals(conflictItem.getDescription().getValue(), "All songs"); + } + } + } + } +} diff --git a/rome-modules/src/test/java/com/rometools/modules/thr/io/ThreadingModuleTest.java b/rome-modules/src/test/java/com/rometools/modules/thr/io/ThreadingModuleTest.java new file mode 100644 index 0000000..3c01c8d --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/thr/io/ThreadingModuleTest.java @@ -0,0 +1,111 @@ +package com.rometools.modules.thr.io; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.thr.ThreadingModule; +import com.rometools.modules.thr.ThreadingModuleImpl; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndEntryImpl; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; + +/** + * + * @author Andreas Feldschmid + */ +public class ThreadingModuleTest extends AbstractTestCase { + + public ThreadingModuleTest(String testName) { + super(testName); + } + + public void testReadMainSpec() throws IOException, FeedException { + final SyndFeed feed = getSyndFeed("thr/threading-main.xml"); + List entries = feed.getEntries(); + SyndEntry parentEntry = entries.get(0); + assertEquals("should be the parent entry", "My original entry", parentEntry.getTitle()); + assertNull(parentEntry.getModule(ThreadingModule.URI)); + + SyndEntry replyEntry = entries.get(1); + assertEquals("should be the reply entry", "A response to the original", replyEntry.getTitle()); + Module module = replyEntry.getModule(ThreadingModule.URI); + assertNotNull(module); + ThreadingModule threadingModule = (ThreadingModule) module; + assertEquals("tag:example.org,2005:1", threadingModule.getRef()); + assertEquals("application/xhtml+xml", threadingModule.getType()); + assertEquals("http://www.example.org/entries/1", threadingModule.getHref()); + assertNull(threadingModule.getSource()); + } + + public void testGenerate() throws IOException, FeedException { + final SyndFeed feed = getSyndFeed("thr/threading-main.xml"); + List entries = feed.getEntries(); + + // create a new "root" entry that the next entry will reference to + SyndEntry newRootEntry = new SyndEntryImpl(); + newRootEntry.setTitle("New, 2nd root entry"); + newRootEntry.setUri("tag:example.org,2005:2"); + newRootEntry.setLink("http://www.example.org/entries/2"); + entries.add(newRootEntry); + + // create a new reply entry that will reference the new root entry + SyndEntry newReplyEntry = new SyndEntryImpl(); + newReplyEntry.setTitle("New test reply entry"); + newReplyEntry.setUri("tag:example.org,2005:2,1"); + + ThreadingModule threadingModule = new ThreadingModuleImpl(); + threadingModule.setRef("tag:example.org,2005:2"); + threadingModule.setType("application/xhtml+xml"); + threadingModule.setHref("http://www.example.org/entries/2"); + threadingModule.setSource("http://example.org/entries/2"); + + newReplyEntry.getModules().add(threadingModule); + entries.add(newReplyEntry); + + File outputFile = new File("target/threading-testGenerate.xml"); + final SyndFeedOutput output = new SyndFeedOutput(); + output.output(feed, outputFile); + + // read back in and validate + final SyndFeed generatedFeed = getSyndFeed(outputFile); + SyndEntry generatedReplyEntry = generatedFeed.getEntries().get(3); + assertNotNull(generatedReplyEntry); + ThreadingModule generatedReplyThreadingModule = (ThreadingModule) generatedReplyEntry.getModule(ThreadingModule.URI); + assertEquals("tag:example.org,2005:2", generatedReplyThreadingModule.getRef()); + assertEquals("application/xhtml+xml", generatedReplyThreadingModule.getType()); + assertEquals("http://www.example.org/entries/2", generatedReplyThreadingModule.getHref()); + assertEquals("http://example.org/entries/2", generatedReplyThreadingModule.getSource()); + } + + public void testEnd2End() throws IOException, FeedException { + final SyndFeed feed = getSyndFeed("thr/threading-main.xml"); + final SyndFeedOutput output = new SyndFeedOutput(); + File outputFile = new File("target/threading-main-generated.xml"); + output.output(feed, outputFile); + + final SyndFeed feedOut = getSyndFeed(outputFile); + + ThreadingModule moduleSrc = (ThreadingModule) feed.getEntries().get(1).getModule(ThreadingModule.URI); + ThreadingModule moduleOut = (ThreadingModule) feedOut.getEntries().get(1).getModule(ThreadingModule.URI); + assertEquals(moduleSrc, moduleOut); + assertEquals("tag:example.org,2005:1", moduleSrc.getRef()); + assertEquals("tag:example.org,2005:1", moduleOut.getRef()); + } + + private SyndFeed getSyndFeed(final File file) throws IOException, FeedException { + return new SyndFeedInput().build(file); + } + + private SyndFeed getSyndFeed(final String filePath) throws IOException, FeedException { + final String fullPath = getTestFile(filePath); + final File file = new File(fullPath); + return new SyndFeedInput().build(file); + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/yahooweather/io/WeatherGeneratorTest.java b/rome-modules/src/test/java/com/rometools/modules/yahooweather/io/WeatherGeneratorTest.java new file mode 100644 index 0000000..dffa34b --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/yahooweather/io/WeatherGeneratorTest.java @@ -0,0 +1,81 @@ +/* + * SlashModuleGeneratorTest.java + * JUnit based test + * + * Created on November 19, 2005, 10:13 PM + */ + +package com.rometools.modules.yahooweather.io; + +import java.io.File; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.yahooweather.YWeatherModule; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.SyndFeedOutput; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class WeatherGeneratorTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(WeatherGeneratorTest.class); + + /** + * @param testName name of the test + */ + public WeatherGeneratorTest(final String testName) { + super(testName); + } + + /** + * @return test suite + */ + public static Test suite() { + return new TestSuite(WeatherGeneratorTest.class); + } + + /** + * Test of generate method, of class com.totsp.xml.syndication.base.io.SlashGenerator. + * + * @throws Exception on error + */ + public void testGenerate() throws Exception { + LOG.debug("testGenerate"); + final SyndFeedInput input = new SyndFeedInput(); + final SyndFeedOutput output = new SyndFeedOutput(); + final File testDir = new File(super.getTestFile("xml")); + final File[] testFiles = testDir.listFiles(); + for (int h = 0; h < testFiles.length; h++) { + if (!testFiles[h].getName().endsWith(".xml")) { + continue; + } + LOG.debug("processing" + testFiles[h]); + final SyndFeed feed = input.build(testFiles[h]); + output.output(feed, new File("target/" + testFiles[h].getName())); + final SyndFeed feed2 = input.build(new File("target/" + testFiles[h].getName())); + final YWeatherModule weather = (YWeatherModule) feed.getModule(YWeatherModule.URI); + final YWeatherModule weather2 = (YWeatherModule) feed2.getModule(YWeatherModule.URI); + Assert.assertEquals(testFiles[h].getName(), weather, weather2); + for (int i = 0; i < feed.getEntries().size(); i++) { + final SyndEntry entry = feed.getEntries().get(i); + final SyndEntry entry2 = feed2.getEntries().get(i); + final YWeatherModule weatherEntry = (YWeatherModule) entry.getModule(YWeatherModule.URI); + final YWeatherModule weatherEntry2 = (YWeatherModule) entry2.getModule(YWeatherModule.URI); + assertEquals(testFiles[h].getName(), weatherEntry, weatherEntry2); + } + } + + } + +} diff --git a/rome-modules/src/test/java/com/rometools/modules/yahooweather/io/WeatherModuleParserTest.java b/rome-modules/src/test/java/com/rometools/modules/yahooweather/io/WeatherModuleParserTest.java new file mode 100644 index 0000000..40816f0 --- /dev/null +++ b/rome-modules/src/test/java/com/rometools/modules/yahooweather/io/WeatherModuleParserTest.java @@ -0,0 +1,86 @@ +/* + * SlashModuleParserTest.java + * JUnit based test + * + * Created on November 19, 2005, 9:45 PM + */ + +package com.rometools.modules.yahooweather.io; + +import java.io.File; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.modules.AbstractTestCase; +import com.rometools.modules.cc.io.CCModuleGenerator; +import com.rometools.modules.yahooweather.YWeatherEntryModule; +import com.rometools.modules.yahooweather.YWeatherModule; +import com.rometools.modules.yahooweather.YWeatherModuleImpl; +import com.rometools.modules.yahooweather.io.WeatherModuleParser; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; + +/** + * + * @author Robert "kebernet" Cooper + */ +public class WeatherModuleParserTest extends AbstractTestCase { + + private static final Logger LOG = LoggerFactory.getLogger(CCModuleGenerator.class); + + public WeatherModuleParserTest(final String testName) { + super(testName); + } + + public static Test suite() { + final TestSuite suite = new TestSuite(WeatherModuleParserTest.class); + + return suite; + } + + public void testGetNamespaceUri() { + final WeatherModuleParser instance = new WeatherModuleParser(); + final String result = instance.getNamespaceUri(); + assertEquals(YWeatherModule.URI, result); + } + + public void testQuickParse() throws Exception { + LOG.debug("testParse"); + final SyndFeedInput input = new SyndFeedInput(); + final File testDir = new File(super.getTestFile("xml")); + final File[] testFiles = testDir.listFiles(); + for (int h = 0; h < testFiles.length; h++) { + if (!testFiles[h].getName().endsWith(".xml")) { + continue; + } + + final SyndFeed feed = input.build(testFiles[h]); + final List entries = feed.getEntries(); + for (int i = 0; i < entries.size(); i++) { + final SyndEntry entry = entries.get(i); + LOG.debug("{}", entry.getModules().size()); + for (int j = 0; j < entry.getModules().size(); j++) { + LOG.debug("{}", entry.getModules().get(j).getClass()); + if (entry.getModules().get(j) instanceof YWeatherModule) { + final YWeatherModule base = (YWeatherModule) entry.getModules().get(j); + assertTrue(((YWeatherEntryModule) base).getForecasts().length > 0); + LOG.debug(testFiles[h].getName()); + LOG.debug(super.beanToString(base, false)); + + final YWeatherEntryModule module2 = new YWeatherModuleImpl(); + module2.copyFrom(base); + assertEquals(((YWeatherEntryModule) base).getForecasts().length, module2.getForecasts().length); + + } + } + } + } + } + +} diff --git a/rome-modules/src/test/resources/2.rss b/rome-modules/src/test/resources/2.rss new file mode 100644 index 0000000..02f70a7 --- /dev/null +++ b/rome-modules/src/test/resources/2.rss @@ -0,0 +1,52 @@ + + + + We're Sorry + + + + + +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      We're Sorry
      The browser you are using does not support the display of Photocasts.
      +

      You can view the photos in this Photocast with Safari RSS (included with Mac OS X v10.4 Tiger or later) or other photo-compatible RSS reader for Mac, Windows, and other operating systems. Copy the link below and bookmark or subscribe to it using your RSS reader so you can return to the photos in the future.

      http://web.mac.com/stuartbainbridge/iPhoto/the-5-6-7-8's-red-cloth/index.rss

      Learn more about iPhoto 6 and viewing Photocasts.

      +
      +
      + + diff --git a/rome-modules/src/test/resources/atom/atom.xml b/rome-modules/src/test/resources/atom/atom.xml new file mode 100644 index 0000000..678d281 --- /dev/null +++ b/rome-modules/src/test/resources/atom/atom.xml @@ -0,0 +1,9 @@ + + + + Test title + http://test.com + Test description + + + diff --git a/rome-modules/src/test/resources/base/courses-atombase.xml b/rome-modules/src/test/resources/base/courses-atombase.xml new file mode 100644 index 0000000..406474f --- /dev/null +++ b/rome-modules/src/test/resources/base/courses-atombase.xml @@ -0,0 +1,69 @@ + + + + + +The name of your feed + + + +2003-12-13T18:30:02Z2003-12-13T18:30:02Z + + + The name of the author + + + + + Robots and Society + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T18:30:02Z 2003-12-13T18:30:02Z + Research and study of the integration of robots in developed economies. + + http://www.providers-website.com/image1.jpg + 2005-11-30 + robots + society + computers + + + 2005-08-19T08:30:00 + 2005-12-20T09:45:00 + + CS 230 + MWF 08:30-09:00 + computer science + Johnson State + + + + + + Documentary Filming + + tag:providers-website-item2.com,2003:3.2397 + 2003-12-13T18:30:02Z 2003-12-13T18:30:02Z + Understanding the theory behind filming documentaries. + + http://www.providers-website.com/image1.jpg + 2005-11-30 + film + video + documentary + + + 2005-08-19T08:30:00 + 2005-12-20T09:45:00 + + FS 192 + TTh 14:00-16:00 + film + Johnson State + + + diff --git a/rome-modules/src/test/resources/base/courses2base.xml b/rome-modules/src/test/resources/base/courses2base.xml new file mode 100644 index 0000000..cd80d63 --- /dev/null +++ b/rome-modules/src/test/resources/base/courses2base.xml @@ -0,0 +1,61 @@ + + + + + + + The name of your channel + A description of the channels content. + http://www.providers-website.com + + + + Robots and Society + Research and study of the integration of robots in developed economies. + http://www.example.com/courses/robots.html + http://www.providers-website.com/image1.jpg + 1 + 2005-11-30 + robots + society + computers + + + + 2005-08-19T08:30:00 + 2005-12-20T09:45:00 + + CS 230 + MWF 08:30-09:00 + computer science + Johnson State + + + + + + Documentary Filming + Understanding the theory behind filming documentaries. + http://www.example.com/courses/documentary.html + http://www.providers-website.com/image1.jpg + 2 + 2005-11-30 + film + video + documentary + + + + 2005-08-19T08:30:00 + 2005-12-20T09:45:00 + + FS 192 + TTh 14:00-16:00 + film + Johnson State + + + + diff --git a/rome-modules/src/test/resources/base/custom-tags-examplebase.xml b/rome-modules/src/test/resources/base/custom-tags-examplebase.xml new file mode 100644 index 0000000..dfe73ef --- /dev/null +++ b/rome-modules/src/test/resources/base/custom-tags-examplebase.xml @@ -0,0 +1,49 @@ + + + Google Jobs + +2005-10-11T18:30:02Z + + +Google + +tag:google.com,2005-10-15:/support/jobs + +HR Analyst - Mountain View + + +We have an immediate need for an experienced analytical HR professional. +The ideal candidate has a proven record of developing analytical frameworks to make +fact-based decisions +tag:google.com,2005-10-15:/support/jobs/hr-analyst +2005-10-13T18:30:02Z +2005-10-13T18:30:02Z + +http://www.google.com/images/google_sm.gif +2005-11-15 +Analyst +1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA +Hi-Tech +Business development +Personnel +Silicon Valley +Staffing + +Fluent in English and German +5 +2005-11-15 + +http://www.screaming-penguin.com +true +25 horses +2.5 cows +125 Main St, Sometown, GA + + 2005-07-04T20:00:00 + 2005-07-04T23:00:00 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/events-atombase.xml b/rome-modules/src/test/resources/base/events-atombase.xml new file mode 100644 index 0000000..87343a8 --- /dev/null +++ b/rome-modules/src/test/resources/base/events-atombase.xml @@ -0,0 +1,91 @@ + + + + +The name of your feed + + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Google's 2005 Halloween Fright Fest + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T18:30:02 + 2003-12-13T18:30:02 + Come face to face with your most horrific fears. This year's Halloween fest will be sure to scare your socks off, complete with a real haunted Googleplex, decomposed BBQ roadkill, and vials of beetlejuice. + + http://www.providers-website.com/image1.jpg + 2005-12-20 + Festival + Halloween + Party + Costumes + + USD + 10 + starting + Cash + Check + Visa + Cash only for local orders + + 2005-07-04T20:00:00 + 2005-07-04T23:00:00 + + 1600 Amphitheatre Parkway, Mountain View, CA, 94043 + + US + Overnight + 32.95 + + California + 8.25 + + + + + + U2 Elevation tour + + tag:providers-website-item2.com,2003:3.2397 + 2003-12-13T18:30:02 + 2003-12-13T18:30:02 + Rock Concert! + + http://www.providers-website.com/image2.jpg + 2005-12-20 + Concert + festival + music + + USD + 50 + starting + Cash + Check + Visa + Cash only for local orders + + 2005-08-02T20:30:00 + 2005-08-23T23:43:00 + + 123 Main St, Anytown, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/events2base.xml b/rome-modules/src/test/resources/base/events2base.xml new file mode 100644 index 0000000..22a98d1 --- /dev/null +++ b/rome-modules/src/test/resources/base/events2base.xml @@ -0,0 +1,80 @@ + + + + + + + The name of your channel + A description of the channels content. + http://provider-website.com/ + + + Google's 2005 Halloween Fright Fest + Come face to face with your most horrific fears. This year's Halloween fest will be sure to scare your socks off, complete with a real haunted Googleplex, decomposed BBQ roadkill, and vials of beetlejuice. + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 1028 + 2005-12-20 + Festival + Halloween + Party + Costumes + + USD + 10 + starting + Cash + Check + Visa + Cash only for local orders + + 2005-07-04T20:00:00 + 2005-07-04T23:00:00 + + 1600 Amphitheatre Parkway, Mountain View, CA, 94043 + + US + Overnight + 32.95 + + California + 8.25 + + + + + + U2 Elevation tour + Rock Concert! + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 1970 + 2005-12-20 + Concert + festival + music + + USD + 50 + starting + Cash + Check + Visa + Cash only for local orders + + 2005-08-23T20:00:00 + 2005-08-23T23:00:00 + + 123 Main St, Anytown, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/housing-atombase.xml b/rome-modules/src/test/resources/base/housing-atombase.xml new file mode 100644 index 0000000..b4a3611 --- /dev/null +++ b/rome-modules/src/test/resources/base/housing-atombase.xml @@ -0,0 +1,80 @@ + + + + +The name of your channel + +2003-12-13T18:30:02Z + + The name of the author + + + + New Townhomes + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + Housing new house! + + http://www.providers-website.com/image1.jpg + 2007-12-20 + Housing + New House + Sale + + USD + 350000 + starting + Cash + Check + Visa + 1000 deposit + true + Townhouse + 123 Main St, Anytown, CA, 12345, USA + 3 + 3 + 1300 + Union School District + 120 + 2005 + Sue Smith + California + 8.25 + + + + + + Luxury Apartments + + tag:providers-website-item2.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + Brand new Luxury apartments for lease! + + http://www.providers-website.com/image2.jpg + 2008-12-20 + Housing + rent + lease + + USD + 1400 + starting + Check + 1000 deposit + false + apartment + 123 Main St, Anytown, CA, 12345, USA + 2 + 2 + 1100 + Union School District + 2004 + Sue Smith + + + diff --git a/rome-modules/src/test/resources/base/housing2base.xml b/rome-modules/src/test/resources/base/housing2base.xml new file mode 100644 index 0000000..d1d244b --- /dev/null +++ b/rome-modules/src/test/resources/base/housing2base.xml @@ -0,0 +1,76 @@ + + + + + + + The name of your channel + A description of the channels content. + http://www.providers-website.com + + + + New Townhomes + Brand new Townhomes for sale! + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 101 + 2007-12-20 + Housing + New House + Sale + + USD + 350000 + starting + Cash + Check + Visa + 1000 deposit + true + Townhouse + 123 Main St, Anytown, CA, 12345, USA + 3 + 3 + 1300 + Union School District + 120 + 2005 + Sue Smith + California + 8.25 + + + + + + Luxury Apartments + Brand new Luxury apartments for lease! + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 102 + 2008-12-20 + Housing + rent + lease + + USD + 1400 + starting + Check + 1000 deposit + false + apartment + 123 Main St, Anytown, CA, 12345, USA + 2 + 2 + 1100 + Union School District + 2004 + Sue Smith + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/jobs-atombase.xml b/rome-modules/src/test/resources/base/jobs-atombase.xml new file mode 100644 index 0000000..ce6fd95 --- /dev/null +++ b/rome-modules/src/test/resources/base/jobs-atombase.xml @@ -0,0 +1,70 @@ + + + + +The name of your channel + + +2003-12-13T18:30:02Z + + The name of the author + + + + + + Google Coordinator - Mountain View + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + The successful candidate will be responsible for providing excellent service to our merchants, while simultaneously helping the product run smoothly behind the scenes. This person should be proactive, organized, extremely detail-oriented, and should work well within a group. + + http://www.providers-website.com/image1.jpg + 2005-12-20 + Coordinator + Google + Online Support + + Internet + Google, Inc + Google Coordinator + full-time + USD + 40000 + starting + BS + Permanent Resident + 1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA + + + + + + Google T-Shirt Distributor + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + Love T-shirts? Just can't get enough? Why not consider a career as an official Google T-shirt Distributor. You will have first dibs on all new t-shirts, and you'll get the satisfaction of giving each Googler ONE t-shirt each. + http://www.providers-website.com/image2.jpg + 2006-01-20 + Distributor + T-Shirts + Google + + Customer Service + Google, Inc. + Distributor + part-time + USD + 25000 + starting + High School + Permanent Resident + 1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA + + + + diff --git a/rome-modules/src/test/resources/base/jobs2base.xml b/rome-modules/src/test/resources/base/jobs2base.xml new file mode 100644 index 0000000..feb301d --- /dev/null +++ b/rome-modules/src/test/resources/base/jobs2base.xml @@ -0,0 +1,63 @@ + + + + + + + The name of your channel + A description of the channels content. + http://www.providers-website.com + + + + Google Coordinator - Mountain View + The successful candidate will be responsible for providing excellent service to our merchants, while simultaneously helping the product run smoothly behind the scenes. This person should be proactive, organized, extremely detail-oriented, and should work well within a group. + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 1001 + 2005-12-20 + Coordinator + Google + Online Support + + Internet + Google, Inc + Google Coordinator + full-time + USD + 40000 + starting + BS + Permanent Resident + 1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA + + + + + + Google T-Shirt Distributor + Love T-shirts? Just can't get enough? Why not consider a career as an official Google T-shirt Distributor. You will have first dibs on all new t-shirts, and you'll get the satisfaction of giving each Googler ONE t-shirt each. + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 1002 + 2006-01-20 + Distributor + T-Shirts + Google + + Customer Service + Google, Inc. + Distributor + part-time + USD + 25000 + starting + High School + Permanent Resident + 1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA + + + + diff --git a/rome-modules/src/test/resources/base/news-atom.xml b/rome-modules/src/test/resources/base/news-atom.xml new file mode 100644 index 0000000..0ae4a03 --- /dev/null +++ b/rome-modules/src/test/resources/base/news-atom.xml @@ -0,0 +1,58 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + First man in Space + Colonel Yuri A. Gagarin,1934 - 1968, 1961 + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + http://www.providers-website.com/image1.jpg + 2007-03-20 + news + old + + Journal + 1961-04-12 + James Smith + 1 + + + + + + Cloning in focus + Some of the issues in cloning. + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + http://www.providers-website.com/image2.jpg + 2010-03-20 + news + risk + flash + + Government Press release + 2007-02-13 + James Smith + 1 + + + diff --git a/rome-modules/src/test/resources/base/news2.xml b/rome-modules/src/test/resources/base/news2.xml new file mode 100644 index 0000000..574387d --- /dev/null +++ b/rome-modules/src/test/resources/base/news2.xml @@ -0,0 +1,50 @@ + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + + First man in Space + Colonel Yuri A. Gagarin,1934 - 1968, 1961 + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 192 + 2007-03-20 + news + old + + Journal + 1961-04-12 + James Smith + 1 + + + + + + Cloning in focus + Some of the issues in cloning. + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 193 + 2010-03-20 + news + risk + flash + + Government Press release + 2007-02-13 + James Smith + 1 + + + + diff --git a/rome-modules/src/test/resources/base/personals-atom.xml b/rome-modules/src/test/resources/base/personals-atom.xml new file mode 100644 index 0000000..560e8d0 --- /dev/null +++ b/rome-modules/src/test/resources/base/personals-atom.xml @@ -0,0 +1,66 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Vietnamese Asian Male + 23 year old dude looking for a girl + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + http://www.providers-website.com/image1.jpg + 2005-12-20 + Personals + m4w + + Vietnamese + M + straight + Single Women + single + Sales + Google, Inc. + 23 + Anytown, 12345, USA + + + + + + Divorced female + Looking for a partner + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + http://www.providers-website.com/image2.jpg + 2005-12-20 + Personals + w4m + + Latino + F + straight + Single/Divorced Male + divorced + Construction + Constrco, Inc. + 33 + Anytown, 12345, USA + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/personals2.xml b/rome-modules/src/test/resources/base/personals2.xml new file mode 100644 index 0000000..90d97a3 --- /dev/null +++ b/rome-modules/src/test/resources/base/personals2.xml @@ -0,0 +1,59 @@ + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + + Single South Asian Male + 23 year old man looking for a woman + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 199 + 2005-12-20 + Personals + m4w + + South Asian + M + straight + Single Women + single + Sales + Google, Inc. + 23 + Anytown, 12345, USA + + + + + + Divorced female + Looking for a partner + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 199 + 2005-12-20 + Personals + w4m + + Hispanic + F + straight + Single/Divorced Men + divorced + Construction + Constrco, Inc. + 33 + Anytown, 12345, USA + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/products-atom.xml b/rome-modules/src/test/resources/base/products-atom.xml new file mode 100644 index 0000000..b02fcbb --- /dev/null +++ b/rome-modules/src/test/resources/base/products-atom.xml @@ -0,0 +1,103 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Google Mini + Now the same reliable results you expect from Google web search can be yours on your intranet or public website with the Google Mini search appliance. This combined hardware and software solution is easy to use, simple to deploy, and can begin providing great search results in just a few short hours. The Google Mini can provide search for up to 100,000 documents, and it supports over 220 different file types. The price includes 1 year of full customer support, software updates, and replacement coverage. + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + + http://www.googlestore.com/appliance/images/products/GO0144E.jpg + 2005-12-20 + Web Search + Appliance + + USD + 2995 + starting + Check + MasterCard + financing available + Google + 12348573 + Google + 2325 + 234 + 10x50x20 + 2 + 300 + new + blue + ship + 1600 Amphitheatre Pkwy Mountain View, CA 94043-1351, US + + US + Standard + 5000 + + California + 8.25 + + + + + + Acme Laptop + Acme 2000 series laptop + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + + http://www.providers-website.com/image2.jpg + 2005-12-20 + Computer + Laptop + + USD + 1400 + starting + MasterCard + Visa + 20 + Acme + 2305934757 + Acme + 834 + 512 + 2 + 2000 + 14x14x3 + 2 + new + black + electronics + 123 Main St, Anytown, CA, 12345, USA + 50 + + US + Overnight + 32.95 + + California + 8.25 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/products2.xml b/rome-modules/src/test/resources/base/products2.xml new file mode 100644 index 0000000..83c5da1 --- /dev/null +++ b/rome-modules/src/test/resources/base/products2.xml @@ -0,0 +1,92 @@ + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + + Google Mini + Now the same reliable results you expect from Google web search can be yours on your intranet or public website with the Google Mini search appliance. This combined hardware and software solution is easy to use, simple to deploy, and can begin providing great search results in just a few short hours. The Google Mini can provide search for up to 100,000 documents, and it supports over 220 different file types. The price includes 1 year of full customer support, software updates, and replacement coverage. + http://www.googlestore.com/appliance/GO0123.asp + http://www.googlestore.com/appliance/images/products/GO0144E.jpg + 1092 + 2005-12-20 + web search + appliance + + USD + 2995 + starting + Check + MasterCard + financing available + Google + 12348573 + Google + 2325 + 234 + 10x50x20 + 2 + 300 + new + blue + 1600 Amphitheatre Pkwy Mountain View, CA 94043-1351, US + + US + Standard + 5000 + + California + 8.25 + + + + + + Acme Laptop + Acme 2000 series laptop + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 822 + 2005-12-20 + Computer + Laptop + + USD + 1400 + starting + MasterCard + Visa + 20 + Acme + 2305934757 + Acme + 834 + 512 + 2 + 2000 + 14x14x3 + 2 + new + black + electronics + 123 Main St, Anytown, CA, 12345, USA + 50 + + US + Overnight + 32.95 + + California + 8.25 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/research-atom.xml b/rome-modules/src/test/resources/base/research-atom.xml new file mode 100644 index 0000000..fcac7d3 --- /dev/null +++ b/rome-modules/src/test/resources/base/research-atom.xml @@ -0,0 +1,59 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Analysis of tsunami on the economy + Analysis of the recent tsumani on the economy + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Economy + Tsunami + + 2005-02-25 + James Smith + Tsunami and the Economy + III + 5 + + + + + + Google and the internet + Analysis of Google's impact on the internet + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Internet + Search Engine + + 2004-01-29 + Sue Smith + Google and the Internet + VI + 23 + + + diff --git a/rome-modules/src/test/resources/base/research2.xml b/rome-modules/src/test/resources/base/research2.xml new file mode 100644 index 0000000..9cca88b --- /dev/null +++ b/rome-modules/src/test/resources/base/research2.xml @@ -0,0 +1,52 @@ + + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + + Analysis of tsunami on the economy + Analysis of the recent tsumani on the economy + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 19 + 2005-12-20 + Economy + Tsunami + + 2005-02-25 + James Smith + Tsunami and the Economy + III + 5 + + + + + + Google and the internet + Analysis of Google's impact on the internet + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 29 + 2005-12-20 + Internet + Search Engine + + 2004-01-29 + Sue Smith + Google and the Internet + VI + 23 + + + + diff --git a/rome-modules/src/test/resources/base/reviews-atom.xml b/rome-modules/src/test/resources/base/reviews-atom.xml new file mode 100644 index 0000000..15bb8cb --- /dev/null +++ b/rome-modules/src/test/resources/base/reviews-atom.xml @@ -0,0 +1,64 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Google Earth - Explore the World from your PC + Read about Google Earth and its many features. + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Review + Earth + Google + + Google Earth + Product + editorial + 5 + http://earth.google.com/ + 2005-03-24 + Jimmy Smith + + + + + + Movie Review: Star Wars + Movie review for Star Wars + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Movie Review + Star Wars + + Star Wars Movie + Movies + editorial + 4 + http://www.example.com/asp/sp.asp?id=169 + 2004-04-23 + Sue Smith + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/reviews2.xml b/rome-modules/src/test/resources/base/reviews2.xml new file mode 100644 index 0000000..05b6776 --- /dev/null +++ b/rome-modules/src/test/resources/base/reviews2.xml @@ -0,0 +1,56 @@ + + + + + + + Provider's Title + A description of the channels content. + http://www.providers-website.com + + + + Google Earth - Explore the World from your PC + Read about Google Earth and its many features + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 193 + 2005-12-20 + Review + Earth + Google + + Google Earth + Product + editorial + 5 + http://earth.google.com/ + 2005-03-24 + Jimmy Smith + + + + + + Movie Review: Star Wars + Movie review for Star Wars + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 169 + 2005-12-20 + Movie Review + Star Wars + + Star Wars Movie + Movies + editorial + 4 + http://www.example.com/asp/sp.asp?id=169 + 2004-04-23 + Sue Smith + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/rss-test-1.xml b/rome-modules/src/test/resources/base/rss-test-1.xml new file mode 100644 index 0000000..8e50af9 --- /dev/null +++ b/rome-modules/src/test/resources/base/rss-test-1.xml @@ -0,0 +1,37 @@ + + + + + + + + Google Jobs +http://www.google.com/support/jobs/ +Information about job openings at Google Inc. + + +HR Analyst - Mountain View +http://www.google.com/support/jobs/bin/topic.py?dep_id=1077&loc_id=1116 + We have an immediate need for an experienced analytical HR professional. +The ideal candidate has a proven record of developing analytical frameworks to make +fact-based decisions. +2005-11-17T14:28:27-05:00 +http://www.google.com/images/google_sm.gif +2005-11-15 +Analyst +1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA +Hi-Tech +Business development +Personnel +Silicon Valley +Staffing + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/services-atom.xml b/rome-modules/src/test/resources/base/services-atom.xml new file mode 100644 index 0000000..eaf2b7f --- /dev/null +++ b/rome-modules/src/test/resources/base/services-atom.xml @@ -0,0 +1,72 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Acme food delivery + Food delivery service + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Food delivery + + USD + 15 + starting + Visa + MasterCard + minimum payment on credit cards:45 + delivery + Anytown, CA, USA + 20 + Will deliver between 9am to 6pm + + US + Standard + 20 + + California + 8.25 + + + + + Acme Pest Control + Get rid of those pesky pests + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Pest + Mouse + + USD + 20 + starting + Check + Visa + pest control + Anytown, CA, USA + 50 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/services2.xml b/rome-modules/src/test/resources/base/services2.xml new file mode 100644 index 0000000..bf96262 --- /dev/null +++ b/rome-modules/src/test/resources/base/services2.xml @@ -0,0 +1,63 @@ + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + Acme food delivery + Food delivery service + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 69 + 2005-12-20 + Food delivery + + USD + 15 + starting + Visa + MasterCard + minimum payment on credit cards:45 + delivery + Anytown, CA, USA + 20 + will deliver between 9am -5pm + + US + Standard + 20 + + California + 8.25 + + + + + Acme Pest Control + Get rid of those pesky pests + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 69 + 2005-12-20 + Pest + Mouse + + USD + 20 + starting + Check + Visa + pest control + Anytown, CA, USA + 50 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/travel-atom.xml b/rome-modules/src/test/resources/base/travel-atom.xml new file mode 100644 index 0000000..dca2b59 --- /dev/null +++ b/rome-modules/src/test/resources/base/travel-atom.xml @@ -0,0 +1,91 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Train tickets to Anytown + Luxury train tickets + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Vacation + Train + + USD + 250 + starting + Check + Visa + minimum payment on credit cards:45 + 204 + Mytown, USA + Anytown, USA + + 2005-12-20T18:00:00 + 2005-12-22T18:00:00 + + 123 Main St, Mytown, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + + + + Cruise Hawaii + 3 day Crusie, visit Hawaii + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Cruise + Hawaii + + USD + 1200 + starting + Visa + MasterCard + minimum payment on credit cards:45 + 210 + San Francisco, CA, USA + Hawaii, USA + + 2005-11-20T18:00:00 + 2005-11-26T12:00:00 + + 123 Main St., San Francisco, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/travel2.xml b/rome-modules/src/test/resources/base/travel2.xml new file mode 100644 index 0000000..d1c396d --- /dev/null +++ b/rome-modules/src/test/resources/base/travel2.xml @@ -0,0 +1,82 @@ + + + + + + + Provider's Title + A description of the channels content. + http://www.providers-website.com + + + Train tickets to Anytown + Luxury train tickets + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 199 + 2005-12-20 + Vacation + Train + + USD + 250 + starting + Check + Visa + minimum payment on credit cards:45 + 204 + Mytown, USA + Anytown, USA + + 2005-12-20T18:00:00 + 2005-12-22T18:00:00 + + 123 Main St, Mytown, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + + + + Cruise Hawaii + 3 day Crusie, visit Hawaii + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 1869 + 2005-12-20 + Cruise + Hawaii + + USD + 1200 + starting + Visa + MasterCard + minimum payment on credit cards:45 + 210 + San Francisco, CA, USA + Hawaii, USA + + 2005-11-20T18:00:00 + 2005-11-26T12:00:00 + + 123 Main St., San Francisco, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/vehicles-atom.xml b/rome-modules/src/test/resources/base/vehicles-atom.xml new file mode 100644 index 0000000..06469d3 --- /dev/null +++ b/rome-modules/src/test/resources/base/vehicles-atom.xml @@ -0,0 +1,95 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Mini Cooper S + 2006 Mini Cooper S + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + car + mini + + USD + 24000 + starting + Check + Visa + MasterCard + financing available + car + Mini + Cooper S + 2006 + 0 + new + red + 1M8GDM9AXKP042788 + 123 Main Street, Anytown, CA, 12345, USA + + US + Standard + 1000 + + California + 8.25 + + + + + + Acme Bio Truck + Acme Bio Fuel Truck + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Truck + Bio + + USD + 32000 + starting + Check + Visa + MasterCard + financing available + truck + Acme + Bio + 1999 + 20000 + used + black + 1M8GDM9AXKP034788 + 123 Main Street, Anytown, CA, 12345, USA + + US + Standard + 1000 + + California + 8.25 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/vehicles2.xml b/rome-modules/src/test/resources/base/vehicles2.xml new file mode 100644 index 0000000..34eb180 --- /dev/null +++ b/rome-modules/src/test/resources/base/vehicles2.xml @@ -0,0 +1,87 @@ + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + + Mini Cooper S + 2006 Mini Cooper S + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 39 + 2005-12-20 + car + mini + + USD + 24000 + starting + Check + Visa + MasterCard + financing available + car + Mini + Cooper S + 2006 + 0 + new + red + 1M8GDM9AXKP042788 + 123 Main Street, Anytown, CA, 12345, USA + + US + Standard + 1000 + + California + 8.25 + + + + + + Acme Bio Truck + Acme Bio Fuel Truck + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 39 + 2005-12-20 + Truck + Bio + + USD + 32000 + starting + Check + Visa + MasterCard + financing available + truck + Acme + Bio + 1999 + 20000 + used + black + 1M8GDM9AXKP034788 + 123 Main Street, Anytown, CA, 12345, USA + + US + Standard + 1000 + + California + 8.25 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/base/wanted-atom.xml b/rome-modules/src/test/resources/base/wanted-atom.xml new file mode 100644 index 0000000..4e7e80b --- /dev/null +++ b/rome-modules/src/test/resources/base/wanted-atom.xml @@ -0,0 +1,51 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Wanted: Used Acme Bio Truck + Wanted a used Acme Bio Truct + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Wanted + Truck + + 123 Main Street, Anytown, CA, 12345, USA + + + + + Wanted: Acme 2000 Camera + Wanted new or used Acme 2000 camera + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Camera + Acme + + 123 Main Street, Anytown, CA, 12345, USA + + + + diff --git a/rome-modules/src/test/resources/base/wanted2.xml b/rome-modules/src/test/resources/base/wanted2.xml new file mode 100644 index 0000000..34876f4 --- /dev/null +++ b/rome-modules/src/test/resources/base/wanted2.xml @@ -0,0 +1,41 @@ + + + + + + + The name of the channel + A description of the channels content. + http://provider-website.com/ + + + Wanted: Used Acme Bio Truck + Wanted a used Acme Bio Truct + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 69 + 2005-12-20 + Wanted + Truck + + 123 Main Street, Anytown, CA, 12345, USA + + + + + Wanted: Acme 2000 Camera + Wanted new or used Acme 2000 camera + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 19 + 2005-12-20 + Camera + Acme + + 123 Main Street, Anytown, CA, 12345, USA + + + + diff --git a/rome-modules/src/test/resources/data/YahooTopSongs.xml b/rome-modules/src/test/resources/data/YahooTopSongs.xml new file mode 100644 index 0000000..da07c95 --- /dev/null +++ b/rome-modules/src/test/resources/data/YahooTopSongs.xml @@ -0,0 +1,534 @@ + + + +list +Y! Music Unlimited Top Songs +http://music.yahoo.com +Top 10 Most Played and Downloaded Songs on Yahoo! Music Unlimited +en +Copyright (c) 2006 Yahoo! Inc. +Mon, 24 Apr 2006 22:04:33 GMT +Mon, 24 Apr 2006 22:04:33 GMT +240 + + +http://us.ent1.yimg.com/images.launch.yahoo.com/rss/ymusic_logo_stroke.jpg +http://music.yahoo.com/ +Yahoo! Music + + + + + + +#1: You're Beautiful - James Blunt +http://pa.yahoo.com/*http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37895/*http://music.yahoo.com/ymu-21642319-1-1 +(C) 2005 Atlantic Records. +Mon, 24 Apr 2006 22:04:33 GMT + + + + + + + + + + + + + + + + +You're Beautiful + +
      +James Blunt +
      +
      +
      + + (C) 2005 Atlantic Records. + + + +]]>
      + + + +James Blunt +You're Beautiful + + + +1 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/ar-8190206 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/track/21642319 + +
      + +#2: What Hurts The Most - Rascal Flatts +http://pa.yahoo.com/*http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37895/*http://music.yahoo.com/ymu-31148799-1-1 +(C) 2006 Lyric Street. +Mon, 24 Apr 2006 22:04:33 GMT + + + + + + + + + + + + + + + + +What Hurts The Most + +
      +Rascal Flatts +
      +
      +
      + + (C) 2006 Lyric Street. + + + +]]>
      + + + +Rascal Flatts +What Hurts The Most + + + +2 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/ar-297648 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/track/31148799 + +
      + +#3: Dance, Dance - Fall Out Boy +http://pa.yahoo.com/*http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37895/*http://music.yahoo.com/ymu-18692393-1-1 +(C) 2005 Island. +Mon, 24 Apr 2006 22:04:33 GMT + + + + + + + + + + + + + + + + +Dance, Dance + +
      +Fall Out Boy +
      +
      +
      + + (C) 2005 Island. + + + +]]>
      + + + +Fall Out Boy +Dance, Dance + + + +3 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/ar-303899 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/track/18692393 + +
      + +#4: Beep - Pussycat Dolls +http://pa.yahoo.com/*http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37895/*http://music.yahoo.com/ymu-23795761-1-1 +(C) 2005 A&M. +Mon, 24 Apr 2006 22:04:33 GMT + + + + + + + + + + + + + + + + +Beep + +
      +Pussycat Dolls +
      +
      +
      + + (C) 2005 A&M. + + + +]]>
      + + + +Pussycat Dolls +Beep + + + +4 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/ar-4623677 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/track/23795761 + +
      + +#5: Check On It - Beyoncé +http://pa.yahoo.com/*http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37895/*http://music.yahoo.com/ymu-24775854-1-1 +(C) 2005 Sony Urban/Columbia. +Mon, 24 Apr 2006 22:04:33 GMT + + + + + + + + + + + + + + + + +Check On It + +
      +Beyoncé +
      +
      +
      + + (C) 2005 Sony Urban/Columbia. + + + +]]>
      + + + +Beyoncé +Check On It + + + +5 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/ar-301363 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/track/24775854 + +
      + +#6: Move Along - The All-American Rejects +http://pa.yahoo.com/*http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37895/*http://music.yahoo.com/ymu-21476799-1-1 +(C) 2005 Interscope/Doghouse. +Mon, 24 Apr 2006 22:04:33 GMT + + + + + + + + + + + + + + + + +Move Along + +
      +The All-American Rejects +
      +
      +
      + + (C) 2005 Interscope/Doghouse. + + + +]]>
      + + + +The All-American Rejects +Move Along + + + +6 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/ar-295168 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/track/21476799 + +
      + +#7: I Write Sins Not Tragedies - Panic! At The Disco +http://pa.yahoo.com/*http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37895/*http://music.yahoo.com/ymu-24213842-1-1 +(C) 2005 Fueled By Ramen. +Mon, 24 Apr 2006 22:04:33 GMT + + + + + + + + + + + + + + + + +I Write Sins Not Tragedies + +
      +Panic! At The Disco +
      +
      +
      + + (C) 2005 Fueled By Ramen. + + + +]]>
      + + + +Panic! At The Disco +I Write Sins Not Tragedies + + + +7 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/ar-24210699 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/track/24213842 + +
      + +#8: Temperature - Sean Paul +http://pa.yahoo.com/*http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37895/*http://music.yahoo.com/ymu-24263368-1-1 +(C) 2005 Atlantic Records. +Mon, 24 Apr 2006 22:04:33 GMT + + + + + + + + + + + + + + + + +Temperature + +
      +Sean Paul +
      +
      +
      + + (C) 2005 Atlantic Records. + + + +]]>
      + + + +Sean Paul +Temperature + + + +8 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/ar-295912 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/track/24263368 + +
      + +#9: Bad Day (Live In Vienna For Hitradio 03) - Daniel Powter +http://pa.yahoo.com/*http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37895/*http://music.yahoo.com/ymu-25260607-1-1 +(C) 2005 Warner Bros.. +Mon, 24 Apr 2006 22:04:33 GMT + + + + + + + + + + + + + + + + +Bad Day (Live In Vienna For Hitradio 03) + +
      +Daniel Powter +
      +
      +
      + + (C) 2005 Warner Bros.. + + + +]]>
      + + + +Daniel Powter +Bad Day (Live In Vienna For Hitradio 03) + + + +9 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/ar-9028913 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/track/25260607 + +
      + +#10: Dirty Little Secret - The All-American Rejects +http://pa.yahoo.com/*http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37895/*http://music.yahoo.com/ymu-21476557-1-1 +(C) 2005 Interscope/Doghouse. +Mon, 24 Apr 2006 22:04:33 GMT + + + + + + + + + + + + + + + + +Dirty Little Secret + +
      +The All-American Rejects +
      +
      +
      + + (C) 2005 Interscope/Doghouse. + + + +]]>
      + + + +The All-American Rejects +Dirty Little Secret + + + +10 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/ar-295168 + + +http://us.rd.yahoo.com/launch/ms/RSSfeeds/ymulink/evt=37894/*http://music.yahoo.com/track/21476557 + +
      +
      +
      \ No newline at end of file diff --git a/rome-modules/src/test/resources/data/YouTube-MostPopular.rss b/rome-modules/src/test/resources/data/YouTube-MostPopular.rss new file mode 100644 index 0000000..d90c229 --- /dev/null +++ b/rome-modules/src/test/resources/data/YouTube-MostPopular.rss @@ -0,0 +1,54 @@ +http://gdata.youtube.com/feeds/api/standardfeeds/most_popular2013-10-09T17:35:53.618ZMost Popularhttp://www.gstatic.com/youtube/img/logo.pngYouTubehttp://www.youtube.com/YouTube data API9125http://gdata.youtube.com/feeds/api/videos/_OBlgSz8sSM2007-05-22T20:29:24.000Z2013-10-09T17:34:13.000ZCharlie bit my finger - again !HDCYThttps://gdata.youtube.com/feeds/api/users/HDCYTComedyhdcytT-Shirts http://charliebitme.firebrandstore.com/ +iPhone http://itunes.apple.com/gb/app/charlie-bit-me!!!/id494858348?mt=8 +Android https://play.google.com/store/apps/details?id=com.viralspiral.charlie +Even had I thought of trying to get my boys to do this I probably couldn't have. Neither were coerced into any of this and neither were hurt (for very long anyway). This was just one of those moments when I had the video camera out because the boys were being fun and they provided something really very funny. + +FAQ Harry is 8 3/4, Charlie is 6 1/2, Jasper is 4 1/4, Rupert is 1 1/2 +(November 2012) + +Harry and Charlie Blogging - Charlie Bit My Finger Again! +http://harryandcharlie.blogspot.com/ + +Twitter +http://twitter.com/harryandcharlieCharlie bit my finger - again !2007-05-22T20:29:24.000ZUCfHZCZHykS3IQDPyFfnqjWg_OBlgSz8sSM2007-03-19http://gdata.youtube.com/feeds/api/videos/dMH0bHeiRNg2006-04-06T21:30:53.000Z2013-10-09T17:22:49.000ZEvolution of Dance - By Judson LaipplyJudson Laipplyhttps://gdata.youtube.com/feeds/api/users/judsonlaipplyComedyjudsonlaipplyFor more visit http://www.mightaswelldance.comEvolution of Dance - By Judson Laipply2006-04-06T21:30:53.000ZUC5B9H4l2vtgo7cAoExcFh-wdMH0bHeiRNghttp://gdata.youtube.com/feeds/api/videos/1uwOL4rB-go2007-09-29T17:04:02.000Z2013-10-09T17:31:44.000ZJeff Dunham - Achmed the Dead TerroristKrowBatelliohttps://gdata.youtube.com/feeds/api/users/KrowBatellioEntertainmentkrowbatellioAll rights reserved to Jeff Dunham.Jeff Dunham - Achmed the Dead Terroristwidescreen2007-09-29T17:04:02.000ZUC0W_cSq4Vhidc0LsuHT27jA1uwOL4rB-gohttp://gdata.youtube.com/feeds/api/videos/7AVHXe-ol-s2006-10-11T22:20:59.000Z2013-10-09T15:20:47.000ZSyndication of this video was restricted.Cut Chemist feat. Hymnal "What's the Altitude" Music Videointernmarkethttps://gdata.youtube.com/feeds/api/users/internmarketMusicinternmarketCut Chemist Music Video "What's the Altitude" Music VideoCut Chemist feat. Hymnal "What's the Altitude" Music Video2006-10-11T22:20:59.000ZUCwd3x4lKPVvvnziwO_CcabA7AVHXe-ol-shttp://gdata.youtube.com/feeds/api/videos/ePyRrb2-fzs2007-05-22T14:42:52.000Z2013-10-09T16:35:36.000ZSyndication of this video was restricted.Timbaland - Apologize (feat. One Republic)1988bastihttps://gdata.youtube.com/feeds/api/users/1988bastiMusic1988bastiVideo made by: http://www.aaronplatt.com / http://de.youtube.com/user/plattino + +Song: Timbaland presents One Republic: Apologize + +Lyrics: + +I'm holding on your rope, +Got me ten feet off the ground +And I'm hearing what you say but I just can't make a sound +You tell me that you need me +Then you go and cut me down, but wait +You tell me that you're sorry +Didn't think I'd turn around, and say... + +That it's too late to apologize, it's too late +I said it's too late to apologize, it's too late + +I'd take another chance, take a fall +Take a shot for you +And I need you like a heart needs a beat +But it's nothing new - yeah yeah + +I loved you with the fire red +Now it's turning blue, and you say... +"Sorry" like the angel heaven let me think was you +But I'm afraid... + +It's too late to apologize, it's too late +I said it's too late to apologize, it's too late whoa..... + +It's too late to apologize, it's too late +I said it's too late to apologize, it's too late +I said it's too late to apologize, yeah +I said it's too late to apologize, yeah +I'm holding on your rope, got me ten feet off the ground...Timbaland - Apologize (feat. One Republic)widescreen2007-05-22T14:42:52.000ZUChLKT__F8P1juQWQ39whVnQePyRrb2-fzs2007-05-21http://gdata.youtube.com/feeds/api/videos/Tx1XIm6q4r42007-03-24T06:32:49.000Z2013-10-09T17:28:41.000ZSyndication of this video was restricted.Potter Puppet Pals: The Mysterious Ticking NoiseNeilCicieregahttps://gdata.youtube.com/feeds/api/users/NeilCicieregaComedyneilcicieregahttp://www.potterpuppetpals.com +Snape hears a strange ticking sound. Love ensues.Potter Puppet Pals: The Mysterious Ticking Noise2007-03-24T06:32:49.000ZUCDrJor35jYVnuC3JgRzheIwTx1XIm6q4r4http://gdata.youtube.com/feeds/api/videos/FzRH3iTQPrk2006-11-06T15:51:58.000Z2013-10-09T17:33:13.000ZThe Sneezing Baby Pandajimvwmosshttps://gdata.youtube.com/feeds/api/users/jimvwmossComedyjimvwmossA Baby Panda Sneezing + +Original footage taken and being used with kind permission of LJM Productions Pty. Ltd.,/Wild Candy Pty. Ltd. Authentic t-shirts http://www.sneezingbabypanda.com + +*The link in the video is at the request of the original owner of the footage. Do NOT ask for your link to be added as I will not respond. Thank you.The Sneezing Baby Panda2006-11-06T15:51:58.000ZUCX72ZQtKY8DUYQqYBc3zMRQFzRH3iTQPrkhttp://gdata.youtube.com/feeds/api/videos/F5VvvVxuKko2007-03-19T18:01:58.000Z2013-10-09T17:33:28.000ZVanessa Hudgens Say Ok Music Video (Official with Zac Efron)hollywoodrecordshttps://gdata.youtube.com/feeds/api/users/hollywoodrecordsMusichollywoodrecordsSay Ok is the second single from High School Musical's own Vanessa Hudgens. Her debut album V is in stores now and features the hit single "Come Back To Me".Vanessa Hudgens Say Ok Music Video (Official with Zac Efron)2007-03-19T18:01:58.000ZUCufxAtBrPqlPy5fHNIZwauAF5VvvVxuKkohttp://gdata.youtube.com/feeds/api/videos/QWNoiVrJDsE2007-06-13T18:38:37.000Z2013-10-09T17:32:06.000Z☆"Britains Got Talent or Americas Got Talent ♥ Connie Talbot WOWs Simon Cowell !"behindthesecrethttps://gdata.youtube.com/feeds/api/users/behindthesecretEntertainmentbehindthesecretYou won't believe which of your favorite celebs have had a nip and tuck! #5 is extreme! http://bit.ly/13pqycy + +Download album: http://amzn.to/SOgKb0☆"Britains Got Talent or Americas Got Talent ♥ Connie Talbot WOWs Simon Cowell !"2007-06-13T18:38:37.000ZUC_UgAFa_i_baEmeoAgsqYgwQWNoiVrJDsE \ No newline at end of file diff --git a/rome-modules/src/test/resources/data/bookexample.xml b/rome-modules/src/test/resources/data/bookexample.xml new file mode 100644 index 0000000..66cbeea --- /dev/null +++ b/rome-modules/src/test/resources/data/bookexample.xml @@ -0,0 +1,32 @@ + + + list + Books in My Collection + http://www.example.com/collectionofbooks.htm + + + + + + + + + Horror Stories, vol 16 + Steve + Our favorite horror author provides us with another great collection + Thu, 25 Aug 2005 00:00:01 GMT + Horror + + + Great Journeys of the Past + Bob + A wonderful history of great journeys + Sat, 07 Sep 2002 00:00:01 GMT + Travel + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/data/geo-rss-issue-27.rss b/rome-modules/src/test/resources/data/geo-rss-issue-27.rss new file mode 100644 index 0000000..e0ce403 --- /dev/null +++ b/rome-modules/src/test/resources/data/geo-rss-issue-27.rss @@ -0,0 +1,1401 @@ + + + + + The Torontonian + + http://thetorontonian.ca + A Lifestyle Blog + Tue, 15 Apr 2014 20:19:46 +0000 + en + hourly + 1 + http://wordpress.com/ + + + http://0.gravatar.com/blavatar/81b7bf46fd5aa138012ed7156d139088?s=96&d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png + The Torontonian + http://thetorontonian.ca + + + diff --git a/rome-modules/src/test/resources/data/rss1.0-w3cgeo.xml b/rome-modules/src/test/resources/data/rss1.0-w3cgeo.xml new file mode 100644 index 0000000..24e75da --- /dev/null +++ b/rome-modules/src/test/resources/data/rss1.0-w3cgeo.xml @@ -0,0 +1,93 @@ + + + +Tagzania - http://www.tagzania.com/tag/ticino +http://www.tagzania.com/tag/ticino + + + + + + + + + + + + +Pugerna +http://www.tagzania.com/item/10679 +45.9774 +8.9781 +tagman +2006-02-21T21:16:00Z +ticino +switzerland + + + + + + + + + + +Campione d'Italia +http://www.tagzania.com/item/10678 +45.9707 +8.97055 +tagman +2006-02-21T21:14:00Z +ticino +switzerland +enclave +italy +lugano +lake + + + + + + + + + + + + + + +Monte Brè +http://www.tagzania.com/item/10652 +46.0087 +8.98579 +tagzania +2006-02-21T10:43:00Z +switzerland +ticino +geonames + + + + + + + + + + + + + + + diff --git a/rome-modules/src/test/resources/data/rss2.0-gml.xml b/rome-modules/src/test/resources/data/rss2.0-gml.xml new file mode 100644 index 0000000..d236260 --- /dev/null +++ b/rome-modules/src/test/resources/data/rss2.0-gml.xml @@ -0,0 +1,55 @@ + + + +coldplay Tour +http://www.myconcertdates.com/event.php?name=coldplay +coldplay Tour +en-us +Copyright 2005, The Newledge Group + +04/03/2006: Manchester, NH +http://www.myconcertdates.com/event.php?name=coldplay&m=4&d=3&y=2006 +Verizon Wireless Arena New Hampshire. <br><br>Feed provided by <a href="http://www.myconcertdates.com">www.myconcertdates.com</a> + + + 45.256 -71.92 + + +Thu, 17 Nov 2005 09:20:02 GMT + + +04/04/2006: Uncasville, CT +http://www.myconcertdates.com/event.php?name=coldplay&m=4&d=4&y=2006 +Mohegan Sun Arena. <br><br>Feed provided by <a href="http://www.myconcertdates.com">www.myconcertdates.com</a> + + + 45.256 -71.92 + + +Thu, 17 Nov 2005 09:20:01 GMT + + +04/06/2006: Philadelphia, PA +http://www.myconcertdates.com/event.php?name=coldplay&m=4&d=6&y=2006 +Wachovia Center (First Union Center). <br><br>Feed provided by <a href="http://www.myconcertdates.com">www.myconcertdates.com</a> + + + 45.256 -71.92 + + +Thu, 17 Nov 2005 09:20:03 GMT + + +09/06/2006: New York, NY +http://www.myconcertdates.com/event.php?name=coldplay&m=9&d=6&y=2006 +Madison Square Garden. <br><br>Feed provided by <a href="http://www.myconcertdates.com">www.myconcertdates.com</a> + + + 45.256 -71.92 + + +Sat, 16 Jul 2005 04:03:11 GMT + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/data/rss2.0-simple.xml b/rome-modules/src/test/resources/data/rss2.0-simple.xml new file mode 100644 index 0000000..904a41e --- /dev/null +++ b/rome-modules/src/test/resources/data/rss2.0-simple.xml @@ -0,0 +1,32 @@ + + + +GeoNames.org recent changes +http://www.geonames.org/recent-changes.html +50 most recent modifications + +Jerusalem +http://www.geonames.org/maps/geonameId=281184 +http://www.geonames.org/maps/geonameId=281184&revision=80 +delete name :la,Hierusalem +Mon, 03 Apr 2006 10:35:16 +0200 +31.7666667 35.2333333 + + +Jerusalem +http://www.geonames.org/maps/geonameId=281184 +http://www.geonames.org/maps/geonameId=281184&revision=72 +add name :he,Ir Ha-Qodesh +Mon, 03 Apr 2006 10:32:24 +0200 +31.7666667 35.2333333 + + +Jerusalem +http://www.geonames.org/maps/geonameId=281184 +http://www.geonames.org/maps/geonameId=281184&revision=31 +update name :grc,Μωριας +Mon, 03 Apr 2006 10:17:41 +0200 +31.7666667 35.2333333 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/data/rss2.0-w3cgeo.xml b/rome-modules/src/test/resources/data/rss2.0-w3cgeo.xml new file mode 100644 index 0000000..cfdd709 --- /dev/null +++ b/rome-modules/src/test/resources/data/rss2.0-w3cgeo.xml @@ -0,0 +1,51 @@ + + + +coldplay Tour +http://www.myconcertdates.com/event.php?name=coldplay +coldplay Tour +en-us +Copyright 2005, The Newledge Group + +04/03/2006: Manchester, NH +http://www.myconcertdates.com/event.php?name=coldplay&m=4&d=3&y=2006 +Verizon Wireless Arena New Hampshire. <br><br>Feed provided by <a href="http://www.myconcertdates.com">www.myconcertdates.com</a> + +42.986284 +-71.45156 + +Thu, 17 Nov 2005 09:20:02 GMT + + +04/04/2006: Uncasville, CT +http://www.myconcertdates.com/event.php?name=coldplay&m=4&d=4&y=2006 +Mohegan Sun Arena. <br><br>Feed provided by <a href="http://www.myconcertdates.com">www.myconcertdates.com</a> + +41.492491 +-72.095783 + +Thu, 17 Nov 2005 09:20:01 GMT + + +04/06/2006: Philadelphia, PA +http://www.myconcertdates.com/event.php?name=coldplay&m=4&d=6&y=2006 +Wachovia Center (First Union Center). <br><br>Feed provided by <a href="http://www.myconcertdates.com">www.myconcertdates.com</a> + +39.901893 +-75.171998 + +Thu, 17 Nov 2005 09:20:03 GMT + + +09/06/2006: New York, NY +http://www.myconcertdates.com/event.php?name=coldplay&m=9&d=6&y=2006 +Madison Square Garden. <br><br>Feed provided by <a href="http://www.myconcertdates.com">www.myconcertdates.com</a> + +40.750598 +-73.993392 + +Sat, 16 Jul 2005 04:03:11 GMT + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/index.rss b/rome-modules/src/test/resources/index.rss new file mode 100644 index 0000000..90a42db --- /dev/null +++ b/rome-modules/src/test/resources/index.rss @@ -0,0 +1,90 @@ + + + + photocast_test + http://web.mac.com/mrakes/iPhoto/photocast_test/index.rss + photocast_test + 2006-01-11 16:43:22 -0800 + 2006-01-11 16:43:22 -0800 + iPhoto [iLife Publication Framework] (6.0) + 0.9 + 95148ACD-C1A3-45C3-A927-15C836892DCC + + http://web.mac.com/mrakes/iPhoto/photocast_test/1C8C5C8D-651D-4990-B6DD-DF11D515213C.jpg?transform=medium + photocast_test + http://web.mac.com/mrakes/iPhoto/photocast_test/index.rss + + + IMG_0663.JPG + http://web.mac.com/mrakes/iPhoto/photocast_test/1C8C5C8D-651D-4990-B6DD-DF11D515213C.jpg + <p><a href="http://web.mac.com/mrakes/iPhoto/photocast_test/1C8C5C8D-651D-4990-B6DD-DF11D515213C.jpg"><img src="http://web.mac.com/mrakes/iPhoto/photocast_test/1C8C5C8D-651D-4990-B6DD-DF11D515213C.jpg?transform=medium" alt="photo" title="" style="float:left; padding-right:10px; padding-bottom:10px;"/></a></p><br clear=all> + 2006-01-11 16:42:55 -0800 + Rakes + photocast_test + Mark + 1C8C5C8D-651D-4990-B6DD-DF11D515213C + 2005-11-29T04:36:06 + 2006-01-11 16:42:26 -0800 + http://web.mac.com/mrakes/iPhoto/photocast_test/1C8C5C8D-651D-4990-B6DD-DF11D515213C.jpg?transform=medium + http://web.mac.com/mrakes/iPhoto/photocast_test/1C8C5C8D-651D-4990-B6DD-DF11D515213C.jpg + + 2159.525069 + + + + + IMG_0664.JPG + http://web.mac.com/mrakes/iPhoto/photocast_test/7ED6492F-6F0E-47CA-8262-EBB4C374EAB1.jpg + <p><a href="http://web.mac.com/mrakes/iPhoto/photocast_test/7ED6492F-6F0E-47CA-8262-EBB4C374EAB1.jpg"><img src="http://web.mac.com/mrakes/iPhoto/photocast_test/7ED6492F-6F0E-47CA-8262-EBB4C374EAB1.jpg?transform=medium" alt="photo" title="" style="float:left; padding-right:10px; padding-bottom:10px;"/></a></p><br clear=all> + 2006-01-11 16:43:05 -0800 + Rakes + photocast_test + Mark + 7ED6492F-6F0E-47CA-8262-EBB4C374EAB1 + 2005-11-29T04:36:30 + 2006-01-11 16:42:26 -0800 + http://web.mac.com/mrakes/iPhoto/photocast_test/7ED6492F-6F0E-47CA-8262-EBB4C374EAB1.jpg?transform=medium + http://web.mac.com/mrakes/iPhoto/photocast_test/7ED6492F-6F0E-47CA-8262-EBB4C374EAB1.jpg + + 2159.525347 + + + + + IMG_0665.JPG + http://web.mac.com/mrakes/iPhoto/photocast_test/0FE733FE-55EB-4D83-A7B7-33878108DF0A.jpg + <p><a href="http://web.mac.com/mrakes/iPhoto/photocast_test/0FE733FE-55EB-4D83-A7B7-33878108DF0A.jpg"><img src="http://web.mac.com/mrakes/iPhoto/photocast_test/0FE733FE-55EB-4D83-A7B7-33878108DF0A.jpg?transform=medium" alt="photo" title="" style="float:left; padding-right:10px; padding-bottom:10px;"/></a></p><br clear=all> + 2006-01-11 16:42:47 -0800 + Rakes + photocast_test + Mark + 0FE733FE-55EB-4D83-A7B7-33878108DF0A + 2005-11-29T04:36:52 + 2006-01-11 16:42:26 -0800 + http://web.mac.com/mrakes/iPhoto/photocast_test/0FE733FE-55EB-4D83-A7B7-33878108DF0A.jpg?transform=medium + http://web.mac.com/mrakes/iPhoto/photocast_test/0FE733FE-55EB-4D83-A7B7-33878108DF0A.jpg + + 2159.525602 + + + + + IMG_0666.JPG + http://web.mac.com/mrakes/iPhoto/photocast_test/AE9870D4-3CA3-4BC8-B3CB-71CD9EC0CEF1.jpg + <p><a href="http://web.mac.com/mrakes/iPhoto/photocast_test/AE9870D4-3CA3-4BC8-B3CB-71CD9EC0CEF1.jpg"><img src="http://web.mac.com/mrakes/iPhoto/photocast_test/AE9870D4-3CA3-4BC8-B3CB-71CD9EC0CEF1.jpg?transform=medium" alt="photo" title="" style="float:left; padding-right:10px; padding-bottom:10px;"/></a></p><br clear=all> + 2006-01-11 16:43:21 -0800 + Rakes + photocast_test + Mark + AE9870D4-3CA3-4BC8-B3CB-71CD9EC0CEF1 + 2005-11-29T04:37:24 + 2006-01-11 16:42:26 -0800 + http://web.mac.com/mrakes/iPhoto/photocast_test/AE9870D4-3CA3-4BC8-B3CB-71CD9EC0CEF1.jpg?transform=medium + http://web.mac.com/mrakes/iPhoto/photocast_test/AE9870D4-3CA3-4BC8-B3CB-71CD9EC0CEF1.jpg + + 2159.525972 + + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/itunes/leshow.xml b/rome-modules/src/test/resources/itunes/leshow.xml new file mode 100644 index 0000000..c5044de --- /dev/null +++ b/rome-modules/src/test/resources/itunes/leshow.xml @@ -0,0 +1,184 @@ + + + + KCRW's Le Show + Harry Shearer + http://www.kcrw.com/show/ls + A weekly, hour-long romp through the worlds of media, politics, sports and show business, leavened with an eclectic mix of mysterious music, hosted by Harry Shearer. + An hour's worth of Harry Shearer + A weekly, hour-long romp through the worlds of media, politics, sports and show business, leavened with an eclectic mix of mysterious music, hosted by Harry Shearer. + en + + KCRW 2005 + + + Harry Shearer + + + + KCRW's Le Show + + + Comedy + + + + + + + + + + + + + + + + le Show + Harry Shearer + + + + + http://66.186.18.80/podcast/mp3/ls/ls050731le_Show.mp3 + + Sun, 31 Jul 2005 16:00:00 GMT + + + + Comedy + + + + + + + + + + + + + + no + + 46:34 + + + + + + + le Show + Harry Shearer + + + + + + + + http://66.186.18.80/podcast/mp3/ls/ls050724le_Show.mp3 + + Sun, 24 Jul 2005 16:00:00 GMT + + + + Comedy + + + + + + + + + + + + + + no + + 44:00 + + + + + + + le Show + Harry Shearer + + + + + + + + http://66.186.18.80/podcast/mp3/ls/ls050717le_Show.mp3 + + Sun, 17 Jul 2005 16:00:00 GMT + + + + Comedy + + + + + + + + + + + + + + no + + 48:33 + + + + + + + le Show + Harry Shearer + + + + + http://66.186.18.80/podcast/mp3/ls/ls050710le_Show.mp3 + + Sun, 10 Jul 2005 16:00:00 GMT + + + + Comedy + + + + + + + + + + + + + + no + + 45:56 + + + + + + + diff --git a/rome-modules/src/test/resources/logback-test.xml b/rome-modules/src/test/resources/logback-test.xml new file mode 100644 index 0000000..c34b099 --- /dev/null +++ b/rome-modules/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/org/rometools/feed/module/content/test-rdf.xml b/rome-modules/src/test/resources/org/rometools/feed/module/content/test-rdf.xml new file mode 100644 index 0000000..77ab7f2 --- /dev/null +++ b/rome-modules/src/test/resources/org/rometools/feed/module/content/test-rdf.xml @@ -0,0 +1,51 @@ + + + + + Example Feed + http://www.example.org + Simply for the purpose of demonstration. + + + + + + + + + + + The Example Item + http://example.org/item/ + + + + + + + Altered This is very cool. + + + + + + This isvery cool.]]> + + + + + This is >very cool<. + + + + + + + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/org/rometools/feed/module/georss/issue-02.xml b/rome-modules/src/test/resources/org/rometools/feed/module/georss/issue-02.xml new file mode 100644 index 0000000..e6bce32 --- /dev/null +++ b/rome-modules/src/test/resources/org/rometools/feed/module/georss/issue-02.xml @@ -0,0 +1,8 @@ + + + + + - + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-07.xml b/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-07.xml new file mode 100644 index 0000000..2290c89 --- /dev/null +++ b/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-07.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-08.xml b/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-08.xml new file mode 100644 index 0000000..846afea --- /dev/null +++ b/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-08.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-12.xml b/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-12.xml new file mode 100644 index 0000000..274cca5 --- /dev/null +++ b/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-12.xml @@ -0,0 +1,8 @@ + + + + + adult + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-20.xml b/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-20.xml new file mode 100644 index 0000000..0abaeb4 --- /dev/null +++ b/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-20.xml @@ -0,0 +1,13 @@ + + + + My Movie Review Site + http://www.foo.com + I review movies. + + Movie Title: Is this a good movie? + http://www.foo.com/item1.htm + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/os/sample1.xml b/rome-modules/src/test/resources/os/sample1.xml new file mode 100644 index 0000000..ed114e0 --- /dev/null +++ b/rome-modules/src/test/resources/os/sample1.xml @@ -0,0 +1,114 @@ + + + + + + + Example.com Search: New York history + http://example.com/New+York+history + Search results for "New York history" at Example.com + 4230000 + 21 + 10 + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/os/sample2.xml b/rome-modules/src/test/resources/os/sample2.xml new file mode 100644 index 0000000..40daa0d --- /dev/null +++ b/rome-modules/src/test/resources/os/sample2.xml @@ -0,0 +1,44 @@ + + + + + + Example.com Search: New York history + + 2003-12-13T18:30:02Z + + Example.com, Inc. + + urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 + 4230000 + 21 + 10 + diff --git a/rome-modules/src/test/resources/test1.xml b/rome-modules/src/test/resources/test1.xml new file mode 100644 index 0000000..eeb0d2d --- /dev/null +++ b/rome-modules/src/test/resources/test1.xml @@ -0,0 +1,3 @@ + +Yahoo! Video: surfinghttp://video.search.yahoo.com/search?p=surfing&ei=UTF-8enVideo results for the query surfingCopyright (c) 2006 Yahoo! Inc. All rights reserved.Sat, 22 Apr 2006 16:07:08 -0700http://us.i1.yimg.com/us.yimg.com/i/us/nt/b/rss/rss_search.gifYahoo! Video Searchhttp://video.search.yahoo.com14218Surfing.wmvhttp://sunnykonacondos.com/images/Surfing.wmvView Surfing Video taken from the lanai Hawaii Volcanoes National Parkhttp://sunnykonacondos.com/images/Surfing.wmvfalseBigIslandSurfing.mpghttp://tman.no-ip.com:8088/pictures/movies/BigIslandSurfing.mpgStylee II Wazzup Big Island Surfing Skate Videohttp://tman.no-ip.com:8088/pictures/movies/BigIslandSurfing.mpgfalsezambales surfinghttp://media02.grouper.com/2/tz/cd/sa2e_rz_preview.asfTuesday, March 14, 2006 Views: 9 Shared by : val surfinghttp://media02.grouper.com/2/tz/cd/sa2e_rz_preview.asffalseKite_surfing_the_movie.mpghttp://www.magnafacta.nl/ph_movies/Kite_surfing_the_movie.mpgKite surfing pictures Size: 20.7 Mbhttp://www.magnafacta.nl/ph_movies/Kite_surfing_the_movie.mpgfalsesurfing_manresa.mpghttp://www.geocities.com/bobgustaff/surfing_manresa.mpgSurfing - 9-20-04http://www.geocities.com/bobgustaff/surfing_manresa.mpgfalse20040620_surfing.wmvhttp://www.letsplay.net/videos/surfing/jo/20040620_surfing.wmv1964 Windansea 2004 John, Katie, RJ, Andy, and Kevin Bujarski Vacation in San Diegonew 2004 John Bujarski's Family Surfing 2005 Santa Barbara with Ray and Laurahttp://www.letsplay.net/videos/surfing/jo/20040620_surfing.wmvfalsegrade7band_surfing usa.wmvhttp://www.lejardinacademy.com/NewWeb/05Middle/pics/2004.05/Activities/7thband/videos/grade7band_surfing%20usa.wmv7th grade band- Surfing USAhttp://www.lejardinacademy.com/NewWeb/05Middle/pics/2004.05/Activities/7thband/videos/grade7band_surfing%20usa.wmvfalsekite_surfing.wmv Download: right-click save as kite_surfing...http://media.santoalt.com/videos/kite_surfing.wmvkite surfing Crazy Videos, Funny Videos, Flash Games, Funny Pictures :: updated daily at SantoAlt Download: right-click save as kite surfing Crazy Videos, Funny Videos, Flash Games, Funny Pictures :: updated daily at SantoAlt Download: right-click save as kite surfing Download: right-click save as Crazy Videos, Funny Videos, Flash Games, Funny Pictures :: updated daily at SantoAlthttp://media.santoalt.com/videos/kite_surfing.wmvfalseSurfing Performance.wmvhttp://www.thedatabahn.com/vid/Surfing%20&%20Performance.wmvNetwork Architecture - (Windows Media Only) Ping Test - (Windows Media Only) Surfing and Performance - (Windows Media Only) CNN News - (Windows Media Only)http://www.thedatabahn.com/vid/Surfing%20&%20Performance.wmvfalseSky-Surfing.wmv Sky-Surfing.wmvhttp://emailgifsandsounds.com/fotoalbum/data/XX_media/35/Sky-Surfing.wmvSky Surfing FunPics4u - funny flash movies, funny pictures, funplaatjes, grappige flash filmpjes Please wait while video is loading... Direct link to this file: Sky Surfing FunPics4u - funny flash movies, funny pictures, funplaatjes, grappige flash filmpjeshttp://emailgifsandsounds.com/fotoalbum/data/XX_media/35/Sky-Surfing.wmvfalse + \ No newline at end of file diff --git a/rome-modules/src/test/resources/test1media.xml b/rome-modules/src/test/resources/test1media.xml new file mode 100644 index 0000000..eeb0d2d --- /dev/null +++ b/rome-modules/src/test/resources/test1media.xml @@ -0,0 +1,3 @@ + +Yahoo! Video: surfinghttp://video.search.yahoo.com/search?p=surfing&ei=UTF-8enVideo results for the query surfingCopyright (c) 2006 Yahoo! Inc. All rights reserved.Sat, 22 Apr 2006 16:07:08 -0700http://us.i1.yimg.com/us.yimg.com/i/us/nt/b/rss/rss_search.gifYahoo! Video Searchhttp://video.search.yahoo.com14218Surfing.wmvhttp://sunnykonacondos.com/images/Surfing.wmvView Surfing Video taken from the lanai Hawaii Volcanoes National Parkhttp://sunnykonacondos.com/images/Surfing.wmvfalseBigIslandSurfing.mpghttp://tman.no-ip.com:8088/pictures/movies/BigIslandSurfing.mpgStylee II Wazzup Big Island Surfing Skate Videohttp://tman.no-ip.com:8088/pictures/movies/BigIslandSurfing.mpgfalsezambales surfinghttp://media02.grouper.com/2/tz/cd/sa2e_rz_preview.asfTuesday, March 14, 2006 Views: 9 Shared by : val surfinghttp://media02.grouper.com/2/tz/cd/sa2e_rz_preview.asffalseKite_surfing_the_movie.mpghttp://www.magnafacta.nl/ph_movies/Kite_surfing_the_movie.mpgKite surfing pictures Size: 20.7 Mbhttp://www.magnafacta.nl/ph_movies/Kite_surfing_the_movie.mpgfalsesurfing_manresa.mpghttp://www.geocities.com/bobgustaff/surfing_manresa.mpgSurfing - 9-20-04http://www.geocities.com/bobgustaff/surfing_manresa.mpgfalse20040620_surfing.wmvhttp://www.letsplay.net/videos/surfing/jo/20040620_surfing.wmv1964 Windansea 2004 John, Katie, RJ, Andy, and Kevin Bujarski Vacation in San Diegonew 2004 John Bujarski's Family Surfing 2005 Santa Barbara with Ray and Laurahttp://www.letsplay.net/videos/surfing/jo/20040620_surfing.wmvfalsegrade7band_surfing usa.wmvhttp://www.lejardinacademy.com/NewWeb/05Middle/pics/2004.05/Activities/7thband/videos/grade7band_surfing%20usa.wmv7th grade band- Surfing USAhttp://www.lejardinacademy.com/NewWeb/05Middle/pics/2004.05/Activities/7thband/videos/grade7band_surfing%20usa.wmvfalsekite_surfing.wmv Download: right-click save as kite_surfing...http://media.santoalt.com/videos/kite_surfing.wmvkite surfing Crazy Videos, Funny Videos, Flash Games, Funny Pictures :: updated daily at SantoAlt Download: right-click save as kite surfing Crazy Videos, Funny Videos, Flash Games, Funny Pictures :: updated daily at SantoAlt Download: right-click save as kite surfing Download: right-click save as Crazy Videos, Funny Videos, Flash Games, Funny Pictures :: updated daily at SantoAlthttp://media.santoalt.com/videos/kite_surfing.wmvfalseSurfing Performance.wmvhttp://www.thedatabahn.com/vid/Surfing%20&%20Performance.wmvNetwork Architecture - (Windows Media Only) Ping Test - (Windows Media Only) Surfing and Performance - (Windows Media Only) CNN News - (Windows Media Only)http://www.thedatabahn.com/vid/Surfing%20&%20Performance.wmvfalseSky-Surfing.wmv Sky-Surfing.wmvhttp://emailgifsandsounds.com/fotoalbum/data/XX_media/35/Sky-Surfing.wmvSky Surfing FunPics4u - funny flash movies, funny pictures, funplaatjes, grappige flash filmpjes Please wait while video is loading... Direct link to this file: Sky Surfing FunPics4u - funny flash movies, funny pictures, funplaatjes, grappige flash filmpjeshttp://emailgifsandsounds.com/fotoalbum/data/XX_media/35/Sky-Surfing.wmvfalse + \ No newline at end of file diff --git a/rome-modules/src/test/resources/test2.xml b/rome-modules/src/test/resources/test2.xml new file mode 100644 index 0000000..ca9a19b --- /dev/null +++ b/rome-modules/src/test/resources/test2.xml @@ -0,0 +1,240 @@ + + + + kebernet's Photos + http://www.flickr.com/photos/kebernet/ + A feed of kebernet's Photos + Mon, 6 Feb 2006 08:59:39 -0800 + Mon, 6 Feb 2006 08:59:39 -0800 + http://www.flickr.com/ + + http://static.flickr.com/4/buddyicons/48407098@N00.jpg?1107755534 + kebernet's Photos + http://www.flickr.com/photos/kebernet/ + + + + Lights in the Rain + http://www.flickr.com/photos/kebernet/96349506/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/96349506/" title="Lights in the Rain"><img src="http://static.flickr.com/22/96349506_6f022998be_m.jpg" width="240" height="180" alt="Lights in the Rain" style="border: 1px solid #ddd;" /></a></p> + + + Mon, 6 Feb 2006 08:59:39 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/96349506 + + Lights in the Rain + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/96349506/" title="Lights in the Rain"><img src="http://static.flickr.com/22/96349506_6f022998be_m.jpg" width="240" height="180" alt="Lights in the Rain" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + atlanta georgia + + + + Midtown rain + http://www.flickr.com/photos/kebernet/96349115/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/96349115/" title="Midtown rain"><img src="http://static.flickr.com/32/96349115_05201684c2_m.jpg" width="240" height="180" alt="Midtown rain" style="border: 1px solid #ddd;" /></a></p> + + + Mon, 6 Feb 2006 08:58:40 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/96349115 + + Midtown rain + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/96349115/" title="Midtown rain"><img src="http://static.flickr.com/32/96349115_05201684c2_m.jpg" width="240" height="180" alt="Midtown rain" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + atlanta georgia + + + + img_0080.jpg + http://www.flickr.com/photos/kebernet/86513598/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513598/" title="img_0080.jpg"><img src="http://static.flickr.com/9/86513598_dde1591b5f_m.jpg" width="240" height="180" alt="img_0080.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 12:00:35 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86513598 + + img_0080.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513598/" title="img_0080.jpg"><img src="http://static.flickr.com/9/86513598_dde1591b5f_m.jpg" width="240" height="180" alt="img_0080.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0079.jpg + http://www.flickr.com/photos/kebernet/86513448/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513448/" title="img_0079.jpg"><img src="http://static.flickr.com/43/86513448_274c16b705_m.jpg" width="240" height="180" alt="img_0079.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 12:00:12 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86513448 + + img_0079.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513448/" title="img_0079.jpg"><img src="http://static.flickr.com/43/86513448_274c16b705_m.jpg" width="240" height="180" alt="img_0079.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0078.jpg + http://www.flickr.com/photos/kebernet/86513332/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513332/" title="img_0078.jpg"><img src="http://static.flickr.com/36/86513332_08e0447649_m.jpg" width="240" height="180" alt="img_0078.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:59:52 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86513332 + + img_0078.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513332/" title="img_0078.jpg"><img src="http://static.flickr.com/36/86513332_08e0447649_m.jpg" width="240" height="180" alt="img_0078.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0077.jpg + http://www.flickr.com/photos/kebernet/86513201/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513201/" title="img_0077.jpg"><img src="http://static.flickr.com/38/86513201_ff82c336a1_m.jpg" width="240" height="180" alt="img_0077.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:59:32 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86513201 + + img_0077.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513201/" title="img_0077.jpg"><img src="http://static.flickr.com/38/86513201_ff82c336a1_m.jpg" width="240" height="180" alt="img_0077.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0076.jpg + http://www.flickr.com/photos/kebernet/86513082/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513082/" title="img_0076.jpg"><img src="http://static.flickr.com/42/86513082_d88d4ef28a_m.jpg" width="240" height="180" alt="img_0076.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:59:15 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86513082 + + img_0076.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513082/" title="img_0076.jpg"><img src="http://static.flickr.com/42/86513082_d88d4ef28a_m.jpg" width="240" height="180" alt="img_0076.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0075.jpg + http://www.flickr.com/photos/kebernet/86512971/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512971/" title="img_0075.jpg"><img src="http://static.flickr.com/9/86512971_18ba7a51b6_m.jpg" width="240" height="180" alt="img_0075.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:58:58 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86512971 + + img_0075.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512971/" title="img_0075.jpg"><img src="http://static.flickr.com/9/86512971_18ba7a51b6_m.jpg" width="240" height="180" alt="img_0075.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0074.jpg + http://www.flickr.com/photos/kebernet/86512857/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512857/" title="img_0074.jpg"><img src="http://static.flickr.com/6/86512857_f57b70e61c_m.jpg" width="240" height="180" alt="img_0074.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:58:41 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86512857 + + img_0074.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512857/" title="img_0074.jpg"><img src="http://static.flickr.com/6/86512857_f57b70e61c_m.jpg" width="240" height="180" alt="img_0074.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0073.jpg + http://www.flickr.com/photos/kebernet/86512732/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512732/" title="img_0073.jpg"><img src="http://static.flickr.com/37/86512732_2f67a4086b_m.jpg" width="240" height="180" alt="img_0073.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:58:24 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86512732 + + img_0073.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512732/" title="img_0073.jpg"><img src="http://static.flickr.com/37/86512732_2f67a4086b_m.jpg" width="240" height="180" alt="img_0073.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/test2media.xml b/rome-modules/src/test/resources/test2media.xml new file mode 100644 index 0000000..ca9a19b --- /dev/null +++ b/rome-modules/src/test/resources/test2media.xml @@ -0,0 +1,240 @@ + + + + kebernet's Photos + http://www.flickr.com/photos/kebernet/ + A feed of kebernet's Photos + Mon, 6 Feb 2006 08:59:39 -0800 + Mon, 6 Feb 2006 08:59:39 -0800 + http://www.flickr.com/ + + http://static.flickr.com/4/buddyicons/48407098@N00.jpg?1107755534 + kebernet's Photos + http://www.flickr.com/photos/kebernet/ + + + + Lights in the Rain + http://www.flickr.com/photos/kebernet/96349506/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/96349506/" title="Lights in the Rain"><img src="http://static.flickr.com/22/96349506_6f022998be_m.jpg" width="240" height="180" alt="Lights in the Rain" style="border: 1px solid #ddd;" /></a></p> + + + Mon, 6 Feb 2006 08:59:39 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/96349506 + + Lights in the Rain + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/96349506/" title="Lights in the Rain"><img src="http://static.flickr.com/22/96349506_6f022998be_m.jpg" width="240" height="180" alt="Lights in the Rain" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + atlanta georgia + + + + Midtown rain + http://www.flickr.com/photos/kebernet/96349115/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/96349115/" title="Midtown rain"><img src="http://static.flickr.com/32/96349115_05201684c2_m.jpg" width="240" height="180" alt="Midtown rain" style="border: 1px solid #ddd;" /></a></p> + + + Mon, 6 Feb 2006 08:58:40 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/96349115 + + Midtown rain + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/96349115/" title="Midtown rain"><img src="http://static.flickr.com/32/96349115_05201684c2_m.jpg" width="240" height="180" alt="Midtown rain" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + atlanta georgia + + + + img_0080.jpg + http://www.flickr.com/photos/kebernet/86513598/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513598/" title="img_0080.jpg"><img src="http://static.flickr.com/9/86513598_dde1591b5f_m.jpg" width="240" height="180" alt="img_0080.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 12:00:35 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86513598 + + img_0080.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513598/" title="img_0080.jpg"><img src="http://static.flickr.com/9/86513598_dde1591b5f_m.jpg" width="240" height="180" alt="img_0080.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0079.jpg + http://www.flickr.com/photos/kebernet/86513448/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513448/" title="img_0079.jpg"><img src="http://static.flickr.com/43/86513448_274c16b705_m.jpg" width="240" height="180" alt="img_0079.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 12:00:12 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86513448 + + img_0079.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513448/" title="img_0079.jpg"><img src="http://static.flickr.com/43/86513448_274c16b705_m.jpg" width="240" height="180" alt="img_0079.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0078.jpg + http://www.flickr.com/photos/kebernet/86513332/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513332/" title="img_0078.jpg"><img src="http://static.flickr.com/36/86513332_08e0447649_m.jpg" width="240" height="180" alt="img_0078.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:59:52 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86513332 + + img_0078.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513332/" title="img_0078.jpg"><img src="http://static.flickr.com/36/86513332_08e0447649_m.jpg" width="240" height="180" alt="img_0078.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0077.jpg + http://www.flickr.com/photos/kebernet/86513201/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513201/" title="img_0077.jpg"><img src="http://static.flickr.com/38/86513201_ff82c336a1_m.jpg" width="240" height="180" alt="img_0077.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:59:32 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86513201 + + img_0077.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513201/" title="img_0077.jpg"><img src="http://static.flickr.com/38/86513201_ff82c336a1_m.jpg" width="240" height="180" alt="img_0077.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0076.jpg + http://www.flickr.com/photos/kebernet/86513082/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513082/" title="img_0076.jpg"><img src="http://static.flickr.com/42/86513082_d88d4ef28a_m.jpg" width="240" height="180" alt="img_0076.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:59:15 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86513082 + + img_0076.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86513082/" title="img_0076.jpg"><img src="http://static.flickr.com/42/86513082_d88d4ef28a_m.jpg" width="240" height="180" alt="img_0076.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0075.jpg + http://www.flickr.com/photos/kebernet/86512971/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512971/" title="img_0075.jpg"><img src="http://static.flickr.com/9/86512971_18ba7a51b6_m.jpg" width="240" height="180" alt="img_0075.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:58:58 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86512971 + + img_0075.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512971/" title="img_0075.jpg"><img src="http://static.flickr.com/9/86512971_18ba7a51b6_m.jpg" width="240" height="180" alt="img_0075.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0074.jpg + http://www.flickr.com/photos/kebernet/86512857/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512857/" title="img_0074.jpg"><img src="http://static.flickr.com/6/86512857_f57b70e61c_m.jpg" width="240" height="180" alt="img_0074.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:58:41 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86512857 + + img_0074.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512857/" title="img_0074.jpg"><img src="http://static.flickr.com/6/86512857_f57b70e61c_m.jpg" width="240" height="180" alt="img_0074.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + img_0073.jpg + http://www.flickr.com/photos/kebernet/86512732/ + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512732/" title="img_0073.jpg"><img src="http://static.flickr.com/37/86512732_2f67a4086b_m.jpg" width="240" height="180" alt="img_0073.jpg" style="border: 1px solid #ddd;" /></a></p> + + + Sat, 14 Jan 2006 11:58:24 -0800 + nobody@flickr.com (kebernet) + tag:flickr.com,2004:/photo/86512732 + + img_0073.jpg + <p><a href="http://www.flickr.com/people/kebernet/">kebernet</a> posted a photo:</p> + +<p><a href="http://www.flickr.com/photos/kebernet/86512732/" title="img_0073.jpg"><img src="http://static.flickr.com/37/86512732_2f67a4086b_m.jpg" width="240" height="180" alt="img_0073.jpg" style="border: 1px solid #ddd;" /></a></p> + + + + kebernet + + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/test3.xml b/rome-modules/src/test/resources/test3.xml new file mode 100644 index 0000000..a88e771 --- /dev/null +++ b/rome-modules/src/test/resources/test3.xml @@ -0,0 +1,101 @@ + + + http://gdata.youtube.com/feeds/videos + Fri, 23 Nov 2007 14:08:44 +0000 + http://gdata.youtube.com/schemas/2007#videoYouTube Videos matching query: Ratatouille trailerhttp://www.youtube.comhttp://www.youtube.com/img/pic_youtubelogo_123x63.gifYouTube Videos matching query: Ratatouille trailerhttp://www.youtube.comYouTubeYouTube data API18915http://gdata.youtube.com/feeds/videos/OtmEBYQbTe0Tue, 03 Apr 2007 12:22:26 +00002007-11-22T16:37:23.000-08:00DeutschFilmhttp://gdata.youtube.com/schemas/2007#videoRatatouilleGermanRatatouille - Trailer<div style="color: #000000;font-family: Arial, Helvetica, sans-serif; font-size:12px; font-size: 12px; width: 555px;"> + <table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td width="140" valign="top" rowspan="2"><div style="border: 1px solid #999999; margin: 0px 10px 5px 0px;"><a href="http://www.youtube.com/watch?v=OtmEBYQbTe0"><img alt="" src="http://img.youtube.com/vi/OtmEBYQbTe0/2.jpg"></a></div></td> + <td width="256" valign="top"><div style="font-size: 12px; font-weight: bold;"><a style="font-size: 15px; font-weight: bold; font-decoration: none;" href="http://www.youtube.com/watch?v=OtmEBYQbTe0">Ratatouille - Trailer</a> + <br></div> + <div style="font-size: 12px; margin: 3px 0px;"><span>Ratatouille</span></div></td> + <td style="font-size: 11px; line-height: 1.4em; padding-left: 20px; padding-top: 1px;" width="146" valign="top"><div><span style="color: #666666; font-size: 11px;">From:</span> + <a href="http://www.youtube.com/profile?user=nextpirat">nextpirat</a></div> + <div><span style="color: #666666; font-size: 11px;">Views:</span> + 40184</div> + <div style="white-space: nowrap;text-align: left"><img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_half_11x11.gif"></div> + <div style="font-size: 11px;">45 + <span style="color: #666666; font-size: 11px;">ratings</span></div></td></tr> + <tr><td><span style="color: #666666; font-size: 11px;">Time:</span> + <span style="color: #000000; font-size: 11px; font-weight: bold;">01:36</span></td> + <td style="font-size: 11px; padding-left: 20px;"><span style="color: #666666; font-size: 11px;">More in</span> + <a href="http://www.youtube.com/categories_portal?c=1">Film &amp; Animation</a></td></tr></tbody></table></div>http://www.youtube.com/watch?v=OtmEBYQbTe0nextpiratRatatouille - TrailerRatatouilleRatatouille, Deutsch, GermanFilmhttp://gdata.youtube.com/feeds/videos/cxbruOoXfOAMon, 05 Feb 2007 02:30:19 +00002007-11-22T17:06:36.000-08:00Filmhttp://gdata.youtube.com/schemas/2007#videoRatatouilleAnimationPixarFilmTrailerRatatouille Trailer<div style="color: #000000;font-family: Arial, Helvetica, sans-serif; font-size:12px; font-size: 12px; width: 555px;"> + <table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td width="140" valign="top" rowspan="2"><div style="border: 1px solid #999999; margin: 0px 10px 5px 0px;"><a href="http://www.youtube.com/watch?v=cxbruOoXfOA"><img alt="" src="http://img.youtube.com/vi/cxbruOoXfOA/2.jpg"></a></div></td> + <td width="256" valign="top"><div style="font-size: 12px; font-weight: bold;"><a style="font-size: 15px; font-weight: bold; font-decoration: none;" href="http://www.youtube.com/watch?v=cxbruOoXfOA">Ratatouille Trailer</a> + <br></div> + <div style="font-size: 12px; margin: 3px 0px;"><span>Upcoming Pixar animation feature film!</span></div></td> + <td style="font-size: 11px; line-height: 1.4em; padding-left: 20px; padding-top: 1px;" width="146" valign="top"><div><span style="color: #666666; font-size: 11px;">From:</span> + <a href="http://www.youtube.com/profile?user=fabirebeque">fabirebeque</a></div> + <div><span style="color: #666666; font-size: 11px;">Views:</span> + 65325</div> + <div style="white-space: nowrap;text-align: left"><img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_half_11x11.gif"></div> + <div style="font-size: 11px;">64 + <span style="color: #666666; font-size: 11px;">ratings</span></div></td></tr> + <tr><td><span style="color: #666666; font-size: 11px;">Time:</span> + <span style="color: #000000; font-size: 11px; font-weight: bold;">01:47</span></td> + <td style="font-size: 11px; padding-left: 20px;"><span style="color: #666666; font-size: 11px;">More in</span> + <a href="http://www.youtube.com/categories_portal?c=1">Film &amp; Animation</a></td></tr></tbody></table></div>http://www.youtube.com/watch?v=cxbruOoXfOAfabirebequeRatatouille TrailerUpcoming Pixar animation feature film!Pixar, Animation, Ratatouille, Trailer, FilmFilmhttp://gdata.youtube.com/feeds/videos/c3sBBRxDAqkThu, 05 Apr 2007 20:21:38 +00002007-11-22T17:03:23.000-08:00GarofaloJaneanehttp://gdata.youtube.com/schemas/2007#videoGarrettOswaltAnimationDisneyMoviePattonCartoonFilmBradRatatouilleRatPixarFilmTrailerRatatouille Trailer<div style="color: #000000;font-family: Arial, Helvetica, sans-serif; font-size:12px; font-size: 12px; width: 555px;"> + <table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td width="140" valign="top" rowspan="2"><div style="border: 1px solid #999999; margin: 0px 10px 5px 0px;"><a href="http://www.youtube.com/watch?v=c3sBBRxDAqk"><img alt="" src="http://img.youtube.com/vi/c3sBBRxDAqk/2.jpg"></a></div></td> + <td width="256" valign="top"><div style="font-size: 12px; font-weight: bold;"><a style="font-size: 15px; font-weight: bold; font-decoration: none;" href="http://www.youtube.com/watch?v=c3sBBRxDAqk">Ratatouille Trailer</a> + <br></div> + <div style="font-size: 12px; margin: 3px 0px;"><span>Academy Award-winning director Brad Bird (&quot;The Incredibles&quot;) and the amazing storytellers at Pixar Animation Studios (&quot;Cars,&quot; &quot;Finding Nemo&quot;) take you into an entirely new and original world where the unthinkable combination of a rat and a 5-star gourmet restaurant come together for the ultimate fish-out-of-water tale. + + In the hilarious new animated-adventure, RATATOUILLE, a rat named Remy dreams of becoming a great chef despite his family&#39;s wishes and the obvious problem of being a rat in a decidedly rodent-phobic profession. When fate places Remy in the city of Paris, he finds himself ideally situated beneath a restaurant made famous by his culinary hero, Auguste Gusteau. Despite the apparent dangers of being an unwanted visitor in the kitchen at one of Paris&#39; most exclusive restaurants, Remy forms an unlikely partnership with Linguini, the garbage boy, who inadvertently discovers Remy&#39;s amazing talents. They strike a deal, ultimately setting into motion a hilarious and exciting chain of extraordinary events that turns the culinary world of Paris upside down. + + Remy finds himself torn between following his dreams or returning forever to his previous existence as a rat. He learns the truth about friendship, family and having no choice but to be who he really is, a rat who wants to be a chef.</span></div></td> + <td style="font-size: 11px; line-height: 1.4em; padding-left: 20px; padding-top: 1px;" width="146" valign="top"><div><span style="color: #666666; font-size: 11px;">From:</span> + <a href="http://www.youtube.com/profile?user=RatatouilleMovie">RatatouilleMovie</a></div> + <div><span style="color: #666666; font-size: 11px;">Views:</span> + 26755</div> + <div style="white-space: nowrap;text-align: left"><img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_half_11x11.gif"></div> + <div style="font-size: 11px;">58 + <span style="color: #666666; font-size: 11px;">ratings</span></div></td></tr> + <tr><td><span style="color: #666666; font-size: 11px;">Time:</span> + <span style="color: #000000; font-size: 11px; font-weight: bold;">02:29</span></td> + <td style="font-size: 11px; padding-left: 20px;"><span style="color: #666666; font-size: 11px;">More in</span> + <a href="http://www.youtube.com/categories_portal?c=1">Film &amp; Animation</a></td></tr></tbody></table></div>http://www.youtube.com/watch?v=c3sBBRxDAqkRatatouilleMovie + + Ratatouille Trailer + Academy Award-winning director Brad Bird ("The Incredibles") and the amazing storytellers at Pixar Animation Studios ("Cars," "Finding Nemo") take you into an entirely new and original world where the unthinkable combination of a rat and a 5-star gourmet restaurant come together for the ultimate fish-out-of-water tale. + + In the hilarious new animated-adventure, RATATOUILLE, a rat named Remy dreams of becoming a great chef despite his family's wishes and the obvious problem of being a rat in a decidedly rodent-phobic profession. When fate places Remy in the city of Paris, he finds himself ideally situated beneath a restaurant made famous by his culinary hero, Auguste Gusteau. Despite the apparent dangers of being an unwanted visitor in the kitchen at one of Paris' most exclusive restaurants, Remy forms an unlikely partnership with Linguini, the garbage boy, who inadvertently discovers Remy's amazing talents. They strike a deal, ultimately setting into motion a hilarious and exciting chain of extraordinary events that turns the culinary world of Paris upside down. + + Remy finds himself torn between following his dreams or returning forever to his previous existence as a rat. He learns the truth about friendship, family and having no choice but to be who he really is, a rat who wants to be a chef. + Pixar, Animation, Janeane, Garofalo, Trailer, Disney, Brad, Garrett, Oswalt, Cartoon, Rat, Movie, Patton, Ratatouille, Film + + Film + + http://gdata.youtube.com/feeds/videos/nYUjNQrokegTue, 15 Aug 2006 22:55:00 +00002007-11-22T17:02:26.000-08:00Entertainmenthttp://gdata.youtube.com/schemas/2007#videoRatatouilleRatatouille Teaser<div style="color: #000000;font-family: Arial, Helvetica, sans-serif; font-size:12px; font-size: 12px; width: 555px;"> + <table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td width="140" valign="top" rowspan="2"><div style="border: 1px solid #999999; margin: 0px 10px 5px 0px;"><a href="http://www.youtube.com/watch?v=nYUjNQrokeg"><img alt="" src="http://img.youtube.com/vi/nYUjNQrokeg/2.jpg"></a></div></td> + <td width="256" valign="top"><div style="font-size: 12px; font-weight: bold;"><a style="font-size: 15px; font-weight: bold; font-decoration: none;" href="http://www.youtube.com/watch?v=nYUjNQrokeg">Ratatouille Teaser</a> + <br></div> + <div style="font-size: 12px; margin: 3px 0px;"><span>Ratatouille Teaser</span></div></td> + <td style="font-size: 11px; line-height: 1.4em; padding-left: 20px; padding-top: 1px;" width="146" valign="top"><div><span style="color: #666666; font-size: 11px;">From:</span> + <a href="http://www.youtube.com/profile?user=avelinforl32">avelinforl32</a></div> + <div><span style="color: #666666; font-size: 11px;">Views:</span> + 448398</div> + <div style="white-space: nowrap;text-align: left"><img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_half_11x11.gif"></div> + <div style="font-size: 11px;">442 + <span style="color: #666666; font-size: 11px;">ratings</span></div></td></tr> + <tr><td><span style="color: #666666; font-size: 11px;">Time:</span> + <span style="color: #000000; font-size: 11px; font-weight: bold;">01:57</span></td> + <td style="font-size: 11px; padding-left: 20px;"><span style="color: #666666; font-size: 11px;">More in</span> + <a href="http://www.youtube.com/categories_portal?c=24">Entertainment</a></td></tr></tbody></table></div>http://www.youtube.com/watch?v=nYUjNQrokegavelinforl32Ratatouille TeaserRatatouille TeaserRatatouilleEntertainmenthttp://gdata.youtube.com/feeds/videos/4XAFYbIxkcAThu, 01 Mar 2007 18:01:11 +00002007-11-22T16:54:36.000-08:00Filmhttp://gdata.youtube.com/schemas/2007#videoRatatouillePixarDisneyPortugu√™sRatatouille Trailer ( Portugu√™s )<div style="color: #000000;font-family: Arial, Helvetica, sans-serif; font-size:12px; font-size: 12px; width: 555px;"> + <table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td width="140" valign="top" rowspan="2"><div style="border: 1px solid #999999; margin: 0px 10px 5px 0px;"><a href="http://www.youtube.com/watch?v=4XAFYbIxkcA"><img alt="" src="http://img.youtube.com/vi/4XAFYbIxkcA/2.jpg"></a></div></td> + <td width="256" valign="top"><div style="font-size: 12px; font-weight: bold;"><a style="font-size: 15px; font-weight: bold; font-decoration: none;" href="http://www.youtube.com/watch?v=4XAFYbIxkcA">Ratatouille Trailer ( Portugu√™s )</a> + <br></div> + <div style="font-size: 12px; margin: 3px 0px;"><span>Trailer de Ratatouille em portugu√™s. Novo filme da Pixar.</span></div></td> + <td style="font-size: 11px; line-height: 1.4em; padding-left: 20px; padding-top: 1px;" width="146" valign="top"><div><span style="color: #666666; font-size: 11px;">From:</span> + <a href="http://www.youtube.com/profile?user=redemisti">redemisti</a></div> + <div><span style="color: #666666; font-size: 11px;">Views:</span> + 20285</div> + <div style="white-space: nowrap;text-align: left"><img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_full_11x11.gif"> <img style="border: 0px none; margin: 0px; padding: 0px; vertical-align: middle; font-size: 11px;" align="top" alt="" src="http://gdata.youtube.com/static/images/icn_star_half_11x11.gif"></div> + <div style="font-size: 11px;">18 + <span style="color: #666666; font-size: 11px;">ratings</span></div></td></tr> + <tr><td><span style="color: #666666; font-size: 11px;">Time:</span> + <span style="color: #000000; font-size: 11px; font-weight: bold;">01:40</span></td> + <td style="font-size: 11px; padding-left: 20px;"><span style="color: #666666; font-size: 11px;">More in</span> +<a href="http://www.youtube.com/categories_portal?c=1">Film &amp; Animation</a></td></tr></tbody></table></div>http://www.youtube.com/watch?v=4XAFYbIxkcAredemistiRatatouille Trailer ( Portugu√™s )Trailer de Ratatouille em portugu√™s. Novo filme da Pixar.Portugu√™s, Ratatouille, Disney, PixarFilm \ No newline at end of file diff --git a/rome-modules/src/test/resources/thr/threading-main.xml b/rome-modules/src/test/resources/thr/threading-main.xml new file mode 100644 index 0000000..6d22220 --- /dev/null +++ b/rome-modules/src/test/resources/thr/threading-main.xml @@ -0,0 +1,25 @@ + + http://www.example.org/myfeed + My Example Feed + 2005-07-28T12:00:00Z + + + James + + + tag:example.org,2005:1 + My original entry + 2006-03-01T12:12:12Z + + This is my original entry + + + tag:example.org,2005:1,1 + A response to the original + 2006-03-01T12:12:12Z + + + This is a response to the original entry + + diff --git a/rome-modules/src/test/resources/xml/at.xml b/rome-modules/src/test/resources/xml/at.xml new file mode 100644 index 0000000..b161568 --- /dev/null +++ b/rome-modules/src/test/resources/xml/at.xml @@ -0,0 +1,215 @@ + + +KCRW's Art Talk +Edward Goldman +http://www.kcrw.com/show/at +Art reviews, news and announcements from Edward Goldman.<P>Edward Goldman is an art consultant for private and corporate collectors. Email him at <a href=mailto:edwardgoldman@earthlink.net>edwardgoldman@earthlink.net</a>. Or call him at 310-314-4660 ext 280. +Insightful commentary on LA's art scene. +Art reviews, news and announcements from Edward Goldman.<P>Edward Goldman is an art consultant for private and corporate collectors. Email him at <a href=mailto:edwardgoldman@earthlink.net>edwardgoldman@earthlink.net</a>. Or call him at 310-314-4660 ext 280. +en-us +KCRW 2005 + + KCRW Podmaster + podmaster@kcrw.org + + +Tue, 2 Aug 2005 12:09:14 -0700 +720 + + http://www.kcrw.com/images/kcrw_logo_small.gif + KCRW.com + http://www.kcrw.com/ + 59 + 144 + +Art Talk + +Arts & Entertainment + + + + + + In Memory of Kathy Reges + Edward Goldman + http://kcrw.com/cgi-bin/db/kcrw.pl?show_code=at&air_date=07/26/05&tmplt_type=Show + Los Angeles has been shaped by untold contributions of millions of people. Some sad events of recent days have made me think of those special people who left a wonderful and lasting legacy on our city of angels.<br> + + Los Angeles has been shaped by untold contributions of millions of people. Some sad events of recent days have made me think of those special people who left a wonderful and lasting legacy on our city of angels.<br> + + Los Angeles has been shaped by untold contributions of millions of people. Some sad events of recent days have made me think of those special people who left a wonderful and lasting legacy on our city of angels.<br> + + + 00:04:12 + + Tue, 26 Jul 2005 09:00:00 -0700 + + Arts & Entertainment + + + + no + + + + L.A. Embarrassment of Riches + Edward Goldman + http://kcrw.com/cgi-bin/db/kcrw.pl?show_code=at&air_date=07/19/05&tmplt_type=Show + From King Tut's archaeological artifacts and 17th century paintings by Rembrandt and Ruisdael to early 20th century photographs by Hungarian born Andr- Kert-sz and to graffiti inspired American art by Jean-Michel Basquiat -- these hot summer months, love it or hate it, Los Angeles is the place to be for those who like their art to be all over the map. + + From King Tut's archaeological artifacts and 17th century paintings by Rembrandt and Ruisdael to early 20th century photographs by Hungarian born Andr- Kert-sz and to graffiti inspired American art by Jean-Michel Basquiat -- these hot summer months, love it or hate it, Los Angeles is the place to be for those who like their art to be all over the map. + + From King Tut's archaeological artifacts and 17th century paintings by Rembrandt and Ruisdael to early 20th century photographs by Hungarian born Andr- Kert-sz and to graffiti inspired American art by Jean-Michel Basquiat -- these hot summer months, love it or hate it, Los Angeles is the place to be for those who like their art to be all over the map. + + + 00:04:13 + + Tue, 19 Jul 2005 09:00:00 -0700 + + Arts & Entertainment + + + + no + + + + The Comeuppance Smart Critic + Edward Goldman + http://kcrw.com/cgi-bin/db/kcrw.pl?show_code=at&air_date=07/12/05&tmplt_type=Show + +My late mother used to tell me affectionately, &quotEdward, you are smart,&quot but then she would say, &quotBut not enough.&quot Truth be told, there were a number of occasions of late where she proved to be right, but we're talking here about art, not my personal life---aren't we? +<br> + +My late mother used to tell me affectionately, &quotEdward, you are smart,&quot but then she would say, &quotBut not enough.&quot Truth be told, there were a number of occasions of late where she proved to be right, but we're talking here about art, not my personal life---aren't we? +<br> + +My late mother used to tell me affectionately, &quotEdward, you are smart,&quot but then she would say, &quotBut not enough.&quot Truth be told, there were a number of occasions of late where she proved to be right, but we're talking here about art, not my personal life---aren't we? +<br> + + 00:04:21 + + Tue, 12 Jul 2005 09:00:00 -0700 + + Arts & Entertainment + + + + no + + + + Does Tim Hawkinson Have Multiple Personalities? + Edward Goldman + http://kcrw.com/cgi-bin/db/kcrw.pl?show_code=at&air_date=07/05/05&tmplt_type=Show + The opening of Tim Hawkinson's exhibition at LACMA a couple of weeks ago turned into an event memorable not only as a chance to celebrate the work of one of the most inventive artists working today, but also an occasion to observe a crowd behaving in a most unusual way: with goofy smiles on their faces, adult men and women were giggling or intently staring in total disbelief. And let me admit for the record that, as for myself, I was guilty on both counts. +<br> + The opening of Tim Hawkinson's exhibition at LACMA a couple of weeks ago turned into an event memorable not only as a chance to celebrate the work of one of the most inventive artists working today, but also an occasion to observe a crowd behaving in a most unusual way: with goofy smiles on their faces, adult men and women were giggling or intently staring in total disbelief. And let me admit for the record that, as for myself, I was guilty on both counts. +<br> + The opening of Tim Hawkinson's exhibition at LACMA a couple of weeks ago turned into an event memorable not only as a chance to celebrate the work of one of the most inventive artists working today, but also an occasion to observe a crowd behaving in a most unusual way: with goofy smiles on their faces, adult men and women were giggling or intently staring in total disbelief. And let me admit for the record that, as for myself, I was guilty on both counts. +<br> + Tue, 5 Jul 2005 09:00:00 -0700 + + Arts & Entertainment + + + + no + + + + The Explosion of New Museums: Too Much of a Good Thing? + Edward Goldman + http://kcrw.com/cgi-bin/db/kcrw.pl?show_code=at&air_date=06/28/05&tmplt_type=Show + If you've lived long enough to make it around the block once or twice, then you know that it's possible to have too much of a good thing. For example, I would never complain that there are too many museums in Rome or in Paris. But I would be wary of a phenomenon of a hundred new museums springing up in a short period of time in one country... + If you've lived long enough to make it around the block once or twice, then you know that it's possible to have too much of a good thing. For example, I would never complain that there are too many museums in Rome or in Paris. But I would be wary of a phenomenon of a hundred new museums springing up in a short period of time in one country... + If you've lived long enough to make it around the block once or twice, then you know that it's possible to have too much of a good thing. For example, I would never complain that there are too many museums in Rome or in Paris. But I would be wary of a phenomenon of a hundred new museums springing up in a short period of time in one country... + Tue, 28 Jun 2005 09:00:00 -0700 + + Arts & Entertainment + + + + no + + + + King Tut: First Time's A Charm, The Second Time A Travesty + Edward Goldman + http://kcrw.com/cgi-bin/db/kcrw.pl?show_code=at&air_date=06/21/05&tmplt_type=Show + So much has been said and written about the whirlwind King Tut exhibition--launched last week here at LACMA--that I hesitated initially to talk about it. I thought, &quotWhy add to all this white noise?&quot But after the totally disagreeable experience of attending the gala opening, followed, a few days later, by walking through the exhibition with the curator, I am filled with conflicting emotions. + So much has been said and written about the whirlwind King Tut exhibition--launched last week here at LACMA--that I hesitated initially to talk about it. I thought, &quotWhy add to all this white noise?&quot But after the totally disagreeable experience of attending the gala opening, followed, a few days later, by walking through the exhibition with the curator, I am filled with conflicting emotions. + So much has been said and written about the whirlwind King Tut exhibition--launched last week here at LACMA--that I hesitated initially to talk about it. I thought, &quotWhy add to all this white noise?&quot But after the totally disagreeable experience of attending the gala opening, followed, a few days later, by walking through the exhibition with the curator, I am filled with conflicting emotions. + Tue, 21 Jun 2005 09:00:00 -0700 + + Arts & Entertainment + + + + no + + + + 16 Rembrandt Portraits Burning the Getty Walls + Edward Goldman + http://kcrw.com/cgi-bin/db/kcrw.pl?show_code=at&air_date=06/14/05&tmplt_type=Show + + + + + + + Tue, 14 Jun 2005 09:00:00 -0700 + + Arts & Entertainment + + + + no + + + + What was Jennifer Steinkamp Smoking? + Edward Goldman + http://kcrw.com/cgi-bin/db/kcrw.pl?show_code=at&air_date=06/07/05&tmplt_type=Show + + + + Tue, 7 Jun 2005 09:00:00 -0700 + + Arts & Entertainment + + + + no + + + + How to Translate L.A. Art & Culture into a Waterfall of Green Dollars + Edward Goldman + http://kcrw.com/cgi-bin/db/kcrw.pl?show_code=at&air_date=05/31/05&tmplt_type=Show + + + + + + + Tue, 31 May 2005 09:00:00 -0700 + + Arts & Entertainment + + + + no + + + + + + diff --git a/rome-modules/src/test/resources/xml/courses-atom.xml b/rome-modules/src/test/resources/xml/courses-atom.xml new file mode 100644 index 0000000..406474f --- /dev/null +++ b/rome-modules/src/test/resources/xml/courses-atom.xml @@ -0,0 +1,69 @@ + + + + + +The name of your feed + + + +2003-12-13T18:30:02Z2003-12-13T18:30:02Z + + + The name of the author + + + + + Robots and Society + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T18:30:02Z 2003-12-13T18:30:02Z + Research and study of the integration of robots in developed economies. + + http://www.providers-website.com/image1.jpg + 2005-11-30 + robots + society + computers + + + 2005-08-19T08:30:00 + 2005-12-20T09:45:00 + + CS 230 + MWF 08:30-09:00 + computer science + Johnson State + + + + + + Documentary Filming + + tag:providers-website-item2.com,2003:3.2397 + 2003-12-13T18:30:02Z 2003-12-13T18:30:02Z + Understanding the theory behind filming documentaries. + + http://www.providers-website.com/image1.jpg + 2005-11-30 + film + video + documentary + + + 2005-08-19T08:30:00 + 2005-12-20T09:45:00 + + FS 192 + TTh 14:00-16:00 + film + Johnson State + + + diff --git a/rome-modules/src/test/resources/xml/courses2.xml b/rome-modules/src/test/resources/xml/courses2.xml new file mode 100644 index 0000000..cd80d63 --- /dev/null +++ b/rome-modules/src/test/resources/xml/courses2.xml @@ -0,0 +1,61 @@ + + + + + + + The name of your channel + A description of the channels content. + http://www.providers-website.com + + + + Robots and Society + Research and study of the integration of robots in developed economies. + http://www.example.com/courses/robots.html + http://www.providers-website.com/image1.jpg + 1 + 2005-11-30 + robots + society + computers + + + + 2005-08-19T08:30:00 + 2005-12-20T09:45:00 + + CS 230 + MWF 08:30-09:00 + computer science + Johnson State + + + + + + Documentary Filming + Understanding the theory behind filming documentaries. + http://www.example.com/courses/documentary.html + http://www.providers-website.com/image1.jpg + 2 + 2005-11-30 + film + video + documentary + + + + 2005-08-19T08:30:00 + 2005-12-20T09:45:00 + + FS 192 + TTh 14:00-16:00 + film + Johnson State + + + + diff --git a/rome-modules/src/test/resources/xml/custom-tags-example.xml b/rome-modules/src/test/resources/xml/custom-tags-example.xml new file mode 100644 index 0000000..dfe73ef --- /dev/null +++ b/rome-modules/src/test/resources/xml/custom-tags-example.xml @@ -0,0 +1,49 @@ + + + Google Jobs + +2005-10-11T18:30:02Z + + +Google + +tag:google.com,2005-10-15:/support/jobs + +HR Analyst - Mountain View + + +We have an immediate need for an experienced analytical HR professional. +The ideal candidate has a proven record of developing analytical frameworks to make +fact-based decisions +tag:google.com,2005-10-15:/support/jobs/hr-analyst +2005-10-13T18:30:02Z +2005-10-13T18:30:02Z + +http://www.google.com/images/google_sm.gif +2005-11-15 +Analyst +1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA +Hi-Tech +Business development +Personnel +Silicon Valley +Staffing + +Fluent in English and German +5 +2005-11-15 + +http://www.screaming-penguin.com +true +25 horses +2.5 cows +125 Main St, Sometown, GA + + 2005-07-04T20:00:00 + 2005-07-04T23:00:00 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/ep/ep1_v1a.xml b/rome-modules/src/test/resources/xml/ep/ep1_v1a.xml new file mode 100644 index 0000000..5f64996 --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep1_v1a.xml @@ -0,0 +1,107 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + Phish + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep1_v1b.xml b/rome-modules/src/test/resources/xml/ep/ep1_v1b.xml new file mode 100644 index 0000000..fe1f43a --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep1_v1b.xml @@ -0,0 +1,114 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + Phish + All songs + + + + + + Moe + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep1_v2a.xml b/rome-modules/src/test/resources/xml/ep/ep1_v2a.xml new file mode 100644 index 0000000..6cb48e3 --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep1_v2a.xml @@ -0,0 +1,130 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + Phish - Coventry Live (the last concert) + All songs + + + + + + Moe + All songs + + + + + + Return to Forever + All songs + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep1_v3a.xml b/rome-modules/src/test/resources/xml/ep/ep1_v3a.xml new file mode 100644 index 0000000..6f946f4 --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep1_v3a.xml @@ -0,0 +1,133 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + + Phish - Coventry Live (the last *good* concert) + All songs + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep1_v4a.xml b/rome-modules/src/test/resources/xml/ep/ep1_v4a.xml new file mode 100644 index 0000000..1effd39 --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep1_v4a.xml @@ -0,0 +1,149 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + + + + + + + + + + Phish - Coventry Live (the last *good* concert) + All songs + + + + + Phish - Coventry Live (the last *simulcast* concert) + All songs + + + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep1_v5a.xml b/rome-modules/src/test/resources/xml/ep/ep1_v5a.xml new file mode 100644 index 0000000..3f07f31 --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep1_v5a.xml @@ -0,0 +1,138 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + + + Phish - Coventry Live (the last *simulcast* concert) + All songs + + + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep2_v1a.xml b/rome-modules/src/test/resources/xml/ep/ep2_v1a.xml new file mode 100644 index 0000000..275396b --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep2_v1a.xml @@ -0,0 +1,107 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + Return to Forever + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep2_v1b.xml b/rome-modules/src/test/resources/xml/ep/ep2_v1b.xml new file mode 100644 index 0000000..15f08b5 --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep2_v1b.xml @@ -0,0 +1,114 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + Return to Forever + All songs + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep2_v2a.xml b/rome-modules/src/test/resources/xml/ep/ep2_v2a.xml new file mode 100644 index 0000000..d6ee53d --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep2_v2a.xml @@ -0,0 +1,130 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + Phish + All songs + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep2_v3a.xml b/rome-modules/src/test/resources/xml/ep/ep2_v3a.xml new file mode 100644 index 0000000..61728ef --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep2_v3a.xml @@ -0,0 +1,133 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + + Phish - Coventry Live (the last *simulcast* concert) + All songs + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep2_v4a.xml b/rome-modules/src/test/resources/xml/ep/ep2_v4a.xml new file mode 100644 index 0000000..5dda4ef --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep2_v4a.xml @@ -0,0 +1,149 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + + + + + + + + + + Phish - Coventry Live (the last *good* concert) + All songs + + + + + Phish - Coventry Live (the last *simulcast* concert) + All songs + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/ep/ep2_v5a.xml b/rome-modules/src/test/resources/xml/ep/ep2_v5a.xml new file mode 100644 index 0000000..1bcf9d0 --- /dev/null +++ b/rome-modules/src/test/resources/xml/ep/ep2_v5a.xml @@ -0,0 +1,138 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + + + Phish - Coventry Live (the last *simulcast* concert) + All songs + + + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/events-atom.xml b/rome-modules/src/test/resources/xml/events-atom.xml new file mode 100644 index 0000000..87343a8 --- /dev/null +++ b/rome-modules/src/test/resources/xml/events-atom.xml @@ -0,0 +1,91 @@ + + + + +The name of your feed + + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Google's 2005 Halloween Fright Fest + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T18:30:02 + 2003-12-13T18:30:02 + Come face to face with your most horrific fears. This year's Halloween fest will be sure to scare your socks off, complete with a real haunted Googleplex, decomposed BBQ roadkill, and vials of beetlejuice. + + http://www.providers-website.com/image1.jpg + 2005-12-20 + Festival + Halloween + Party + Costumes + + USD + 10 + starting + Cash + Check + Visa + Cash only for local orders + + 2005-07-04T20:00:00 + 2005-07-04T23:00:00 + + 1600 Amphitheatre Parkway, Mountain View, CA, 94043 + + US + Overnight + 32.95 + + California + 8.25 + + + + + + U2 Elevation tour + + tag:providers-website-item2.com,2003:3.2397 + 2003-12-13T18:30:02 + 2003-12-13T18:30:02 + Rock Concert! + + http://www.providers-website.com/image2.jpg + 2005-12-20 + Concert + festival + music + + USD + 50 + starting + Cash + Check + Visa + Cash only for local orders + + 2005-08-02T20:30:00 + 2005-08-23T23:43:00 + + 123 Main St, Anytown, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/events2.xml b/rome-modules/src/test/resources/xml/events2.xml new file mode 100644 index 0000000..22a98d1 --- /dev/null +++ b/rome-modules/src/test/resources/xml/events2.xml @@ -0,0 +1,80 @@ + + + + + + + The name of your channel + A description of the channels content. + http://provider-website.com/ + + + Google's 2005 Halloween Fright Fest + Come face to face with your most horrific fears. This year's Halloween fest will be sure to scare your socks off, complete with a real haunted Googleplex, decomposed BBQ roadkill, and vials of beetlejuice. + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 1028 + 2005-12-20 + Festival + Halloween + Party + Costumes + + USD + 10 + starting + Cash + Check + Visa + Cash only for local orders + + 2005-07-04T20:00:00 + 2005-07-04T23:00:00 + + 1600 Amphitheatre Parkway, Mountain View, CA, 94043 + + US + Overnight + 32.95 + + California + 8.25 + + + + + + U2 Elevation tour + Rock Concert! + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 1970 + 2005-12-20 + Concert + festival + music + + USD + 50 + starting + Cash + Check + Visa + Cash only for local orders + + 2005-08-23T20:00:00 + 2005-08-23T23:00:00 + + 123 Main St, Anytown, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/housing-atom.xml b/rome-modules/src/test/resources/xml/housing-atom.xml new file mode 100644 index 0000000..b4a3611 --- /dev/null +++ b/rome-modules/src/test/resources/xml/housing-atom.xml @@ -0,0 +1,80 @@ + + + + +The name of your channel + +2003-12-13T18:30:02Z + + The name of the author + + + + New Townhomes + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + Housing new house! + + http://www.providers-website.com/image1.jpg + 2007-12-20 + Housing + New House + Sale + + USD + 350000 + starting + Cash + Check + Visa + 1000 deposit + true + Townhouse + 123 Main St, Anytown, CA, 12345, USA + 3 + 3 + 1300 + Union School District + 120 + 2005 + Sue Smith + California + 8.25 + + + + + + Luxury Apartments + + tag:providers-website-item2.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + Brand new Luxury apartments for lease! + + http://www.providers-website.com/image2.jpg + 2008-12-20 + Housing + rent + lease + + USD + 1400 + starting + Check + 1000 deposit + false + apartment + 123 Main St, Anytown, CA, 12345, USA + 2 + 2 + 1100 + Union School District + 2004 + Sue Smith + + + diff --git a/rome-modules/src/test/resources/xml/housing2.xml b/rome-modules/src/test/resources/xml/housing2.xml new file mode 100644 index 0000000..d1d244b --- /dev/null +++ b/rome-modules/src/test/resources/xml/housing2.xml @@ -0,0 +1,76 @@ + + + + + + + The name of your channel + A description of the channels content. + http://www.providers-website.com + + + + New Townhomes + Brand new Townhomes for sale! + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 101 + 2007-12-20 + Housing + New House + Sale + + USD + 350000 + starting + Cash + Check + Visa + 1000 deposit + true + Townhouse + 123 Main St, Anytown, CA, 12345, USA + 3 + 3 + 1300 + Union School District + 120 + 2005 + Sue Smith + California + 8.25 + + + + + + Luxury Apartments + Brand new Luxury apartments for lease! + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 102 + 2008-12-20 + Housing + rent + lease + + USD + 1400 + starting + Check + 1000 deposit + false + apartment + 123 Main St, Anytown, CA, 12345, USA + 2 + 2 + 1100 + Union School District + 2004 + Sue Smith + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/jobs-atom.xml b/rome-modules/src/test/resources/xml/jobs-atom.xml new file mode 100644 index 0000000..ce6fd95 --- /dev/null +++ b/rome-modules/src/test/resources/xml/jobs-atom.xml @@ -0,0 +1,70 @@ + + + + +The name of your channel + + +2003-12-13T18:30:02Z + + The name of the author + + + + + + Google Coordinator - Mountain View + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + The successful candidate will be responsible for providing excellent service to our merchants, while simultaneously helping the product run smoothly behind the scenes. This person should be proactive, organized, extremely detail-oriented, and should work well within a group. + + http://www.providers-website.com/image1.jpg + 2005-12-20 + Coordinator + Google + Online Support + + Internet + Google, Inc + Google Coordinator + full-time + USD + 40000 + starting + BS + Permanent Resident + 1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA + + + + + + Google T-Shirt Distributor + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + Love T-shirts? Just can't get enough? Why not consider a career as an official Google T-shirt Distributor. You will have first dibs on all new t-shirts, and you'll get the satisfaction of giving each Googler ONE t-shirt each. + http://www.providers-website.com/image2.jpg + 2006-01-20 + Distributor + T-Shirts + Google + + Customer Service + Google, Inc. + Distributor + part-time + USD + 25000 + starting + High School + Permanent Resident + 1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA + + + + diff --git a/rome-modules/src/test/resources/xml/jobs2.xml b/rome-modules/src/test/resources/xml/jobs2.xml new file mode 100644 index 0000000..feb301d --- /dev/null +++ b/rome-modules/src/test/resources/xml/jobs2.xml @@ -0,0 +1,63 @@ + + + + + + + The name of your channel + A description of the channels content. + http://www.providers-website.com + + + + Google Coordinator - Mountain View + The successful candidate will be responsible for providing excellent service to our merchants, while simultaneously helping the product run smoothly behind the scenes. This person should be proactive, organized, extremely detail-oriented, and should work well within a group. + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 1001 + 2005-12-20 + Coordinator + Google + Online Support + + Internet + Google, Inc + Google Coordinator + full-time + USD + 40000 + starting + BS + Permanent Resident + 1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA + + + + + + Google T-Shirt Distributor + Love T-shirts? Just can't get enough? Why not consider a career as an official Google T-shirt Distributor. You will have first dibs on all new t-shirts, and you'll get the satisfaction of giving each Googler ONE t-shirt each. + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 1002 + 2006-01-20 + Distributor + T-Shirts + Google + + Customer Service + Google, Inc. + Distributor + part-time + USD + 25000 + starting + High School + Permanent Resident + 1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA + + + + diff --git a/rome-modules/src/test/resources/xml/leshow.xml b/rome-modules/src/test/resources/xml/leshow.xml new file mode 100644 index 0000000..f6855fc --- /dev/null +++ b/rome-modules/src/test/resources/xml/leshow.xml @@ -0,0 +1,189 @@ + + + + KCRW's Le Show + Harry Shearer + http://www.kcrw.com/show/ls + A weekly, hour-long romp through the worlds of media, politics, sports and show business, leavened with an eclectic mix of mysterious music, hosted by Harry Shearer. + An hour's worth of Harry Shearer + A weekly, hour-long romp through the worlds of media, politics, sports and show business, leavened with an eclectic mix of mysterious music, hosted by Harry Shearer. + yes + http://example.org + en + + KCRW 2005 + + + Harry Shearer + + + + KCRW's Le Show + + + Comedy + + + + + + + + + + + + + + + + le Show + Harry Shearer + + + + + http://66.186.18.80/podcast/mp3/ls/ls050731le_Show.mp3 + + Sun, 31 Jul 2005 16:00:00 GMT + + + + Comedy + + + + + + + + + + + + + + no + + 46:34 + + + yes + 2 + + + + + + le Show + Harry Shearer + + + + + + + + http://66.186.18.80/podcast/mp3/ls/ls050724le_Show.mp3 + + Sun, 24 Jul 2005 16:00:00 GMT + + + + Comedy + + + + + + + + + + + + + + no + + 44:00 + + + + + + + le Show + Harry Shearer + + + + + + + + http://66.186.18.80/podcast/mp3/ls/ls050717le_Show.mp3 + + Sun, 17 Jul 2005 16:00:00 GMT + + + + Comedy + + + + + + + + + + + + + + no + + 48:33 + + + + + + + le Show + Harry Shearer + + + + + http://66.186.18.80/podcast/mp3/ls/ls050710le_Show.mp3 + + Sun, 10 Jul 2005 16:00:00 GMT + + + + Comedy + + + + + + + + + + + + + + no + + 45:56 + + + + + + + diff --git a/rome-modules/src/test/resources/xml/leshow.xml.output b/rome-modules/src/test/resources/xml/leshow.xml.output new file mode 100644 index 0000000..d7690e3 --- /dev/null +++ b/rome-modules/src/test/resources/xml/leshow.xml.output @@ -0,0 +1,87 @@ + + + + KCRW's Le Show + http://www.kcrw.com/show/ls + A weekly, hour-long romp through the worlds of media, politics, sports and show business, leavened with an eclectic mix of mysterious music, hosted by Harry Shearer. + en + KCRW 2005 + Comedy + + + Harry Shearer + + + + + Harry Shearer + no + + An hour's worth of Harry Shearer + A weekly, hour-long romp through the worlds of media, politics, sports and show business, leavened with an eclectic mix of mysterious music, hosted by Harry Shearer. + Comedy + en + KCRW 2005 + + le Show + + + Comedy + Sun, 31 Jul 2005 16:00:00 GMT + http://66.186.18.80/podcast/mp3/ls/ls050731le_Show.mp3 + 00:46:34 + Harry Shearer + no + + + + 2005-07-31T16:00:00Z + + + le Show + + + Comedy + Sun, 24 Jul 2005 16:00:00 GMT + http://66.186.18.80/podcast/mp3/ls/ls050724le_Show.mp3 + 00:44:00 + Harry Shearer + no + + + + 2005-07-24T16:00:00Z + + + le Show + + + Comedy + Sun, 17 Jul 2005 16:00:00 GMT + http://66.186.18.80/podcast/mp3/ls/ls050717le_Show.mp3 + 00:48:33 + Harry Shearer + no + + + + 2005-07-17T16:00:00Z + + + le Show + + + Comedy + Sun, 10 Jul 2005 16:00:00 GMT + http://66.186.18.80/podcast/mp3/ls/ls050710le_Show.mp3 + 00:45:56 + Harry Shearer + no + + + + 2005-07-10T16:00:00Z + + + + diff --git a/rome-modules/src/test/resources/xml/lr.xml b/rome-modules/src/test/resources/xml/lr.xml new file mode 100644 index 0000000..9690695 --- /dev/null +++ b/rome-modules/src/test/resources/xml/lr.xml @@ -0,0 +1,261 @@ + + + +KCRW's Left, Right &amp; Center +R.Scheer, A.Huffington, M.Miller &amp; T.Blankley +http://www.kcrw.com/show/lr +Support KCRW's public radio podcasts. Join online at KCRW.com or call 800-600-5279. Provocative, up-to-the-minute, alive and witty, KCRW's weekly confrontation over politics, policy and popular culture proves those with impeccable credentials needn't lack personality. Featuring four of the most insightful news analysts anywhere, this weekly "love-hate relationship of the air" reaches about 50,000 of the most influential radio listeners in Southern California. +KCRW's weekly confrontation over politics, policy and popular culture. +Provocative, up-to-the-minute, alive and witty, KCRW's weekly confrontation over politics, policy and popular culture proves those with impeccable credentials needn't lack personality. Featuring four of the most insightful news analysts anywhere, this weekly "love-hate relationship of the air" reaches about 50,000 of the most influential radio listeners in Southern California. + +en-us +KCRW 2006 + + KCRW Podmaster + podmaster@kcrw.org + + +Sat, 22 Apr 2006 23:15:03 -0700 + +60 + + http://www.kcrw.com/images/kcrw_logo_small.gif + KCRW.com + http://www.kcrw.com/ + 59 + 144 + + +Left, Right &amp; Center + +Politics + + + + + + China's Big Visit; Big Changes at the White House; Golly Gee, Gas Prices! + + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=04/21/06&tmplt_type=Show + + + + + + 00:28:59 + + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060421Chinas_Big_Visit_Big.mp3?1145657863 + Fri, 21 Apr 2006 09:00:00 -0700 + + Politics + + + + + no + + + + Iran Nukes; Rumsfeld Won't Go; Mitt Romney and Mass Healthcare + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=04/14/06&tmplt_type=Show + + + + + 00:29:00 + + + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060414Iran_Nukes_Rumsfeld_.mp3?1145062782 + Fri, 14 Apr 2006 09:00:00 -0700 + + Politics + + + + + no + + + + Did W OK Libby Leak?; Delay's Departure; Uncompromising Positions on Immigration + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=04/07/06&tmplt_type=Show + + Lawrence O'Donnell, executive producer of The West Wing, hosts. Matt Miller and Arianna Huffington are away.<br clear=all> + Lawrence O'Donnell, executive producer of The West Wing, hosts. Matt Miller and Arianna Huffington are away.<br clear=all> + Lawrence O'Donnell, executive producer of The West Wing, hosts. Matt Miller and Arianna Huffington are away.<br clear=all> + + 00:29:00 + + + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060407Did_W_OK_Libby_Leak_.mp3?1144445197 + Fri, 7 Apr 2006 09:00:00 -0700 + + Politics + + + + + no + + + + Immigration, French Employment Riots, White House Shakeup and One Last Word + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=03/31/06&tmplt_type=Show + + + + + + 00:29:00 + + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060331Immigration_French_E.mp3?1143845320 + Fri, 31 Mar 2006 08:00:00 -0800 + + + Politics + + + + no + + + + + Iraq, Third Anniversary; Media Response; Republicans and Immigration + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=03/24/06&tmplt_type=Show + Lawrence O'Donnell, executive producer of <a href=&quothttp://www.nbc.com/The_West_Wing&quot target=&quotnew&quot>The West Wing</a>, sits in for Matt Miller, who is away.<br> + + Lawrence O'Donnell, executive producer of <a href=&quothttp://www.nbc.com/The_West_Wing&quot target=&quotnew&quot>The West Wing</a>, sits in for Matt Miller, who is away.<br> + Lawrence O'Donnell, executive producer of <a href=&quothttp://www.nbc.com/The_West_Wing&quot target=&quotnew&quot>The West Wing</a>, sits in for Matt Miller, who is away.<br> + + + 00:28:59 + + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060324Iraq_Third_Anniversa.mp3?1143240653 + Fri, 24 Mar 2006 08:00:00 -0800 + + Politics + + + + + no + + + + Iran Wants to Talk; Republicans Drunk on Debt; Impeachment: New Battle Cry of Far Left, Far Right! + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=03/17/06&tmplt_type=Show + Arianna Huffington is away.<br> + Arianna Huffington is away.<br> + Arianna Huffington is away.<br> + + + 00:28:59 + + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060317Iran_Wants_to_Talk_R.mp3?1142631399 + Fri, 17 Mar 2006 08:00:00 -0800 + + Politics + + + + + no + + + + Bye-Bye, Dubai; Bush's Plummeting Polls; Why Democrats Can't Get Traction; Economic Roundup + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=03/10/06&tmplt_type=Show + Bye Bye, Dubai. Bush's plummeting polls. Why can't Democrats get traction? +Plus, Greenspan inks book deal. Stock market rallies. (Arianna Huffington is away.)<br> + Bye Bye, Dubai. Bush's plummeting polls. Why can't Democrats get traction? +Plus, Greenspan inks book deal. Stock market rallies. (Arianna Huffington is away.)<br> + Bye Bye, Dubai. Bush's plummeting polls. Why can't Democrats get traction? +Plus, Greenspan inks book deal. Stock market rallies. (Arianna Huffington is away.)<br> + + + 00:28:59 + + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060310Bye-Bye_Dubai_Bushs_.mp3?1142025475 + Fri, 10 Mar 2006 08:00:00 -0800 + + Politics + + + + + no + + + + Nukes in the News; Doubts on Dubai Ports; Katrina Culpability; Is Iraq Irreparable? + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=03/03/06&tmplt_type=Show + Lawrence O'Donnell sits in for Matt Miller as moderator.<br> + Lawrence O'Donnell sits in for Matt Miller as moderator.<br> + Lawrence O'Donnell sits in for Matt Miller as moderator.<br> + + + 00:29:00 + + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060303Nukes_in_the_News_Do.mp3?1141422299 + Fri, 3 Mar 2006 08:00:00 -0800 + + Politics + + + + + no + + + + Civil War in Iraq? Port Wars in the US? Bye Bye, Larry Summers and Defending Free Speech + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=02/24/06&tmplt_type=Show + + + + Fri, 24 Feb 2006 08:00:00 -0800 + + Politics + + + + + no + + + + + + + diff --git a/rome-modules/src/test/resources/xml/lr.xml.output b/rome-modules/src/test/resources/xml/lr.xml.output new file mode 100644 index 0000000..a5657a4 --- /dev/null +++ b/rome-modules/src/test/resources/xml/lr.xml.output @@ -0,0 +1,260 @@ + + + + KCRW's Left, Right &amp; Center + http://www.kcrw.com/show/lr + Support KCRW's public radio podcasts. Join online at KCRW.com or call 800-600-5279. Provocative, up-to-the-minute, alive and witty, KCRW's weekly confrontation over politics, policy and popular culture proves those with impeccable credentials needn't lack personality. Featuring four of the most insightful news analysts anywhere, this weekly "love-hate relationship of the air" reaches about 50,000 of the most influential radio listeners in Southern California. + en-us + KCRW 2006 + Sun, 23 Apr 2006 06:15:03 GMT + Politics + + podmaster@kcrw.org + KCRW Podmaster + + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + no + + KCRW's weekly confrontation over politics, policy and popular culture. + Provocative, up-to-the-minute, alive and witty, KCRW's weekly confrontation over politics, policy and popular culture proves those with impeccable credentials needn't lack personality. Featuring four of the most insightful news analysts anywhere, this weekly "love-hate relationship of the air" reaches about 50,000 of the most influential radio listeners in Southern California. + Politics + 2006-04-23T06:15:03Z + en-us + KCRW 2006 + + KCRW.com + http://www.kcrw.com/images/kcrw_logo_small.gif + http://www.kcrw.com/ + -1 + -1 + + + China's Big Visit; Big Changes at the White House; Golly Gee, Gas Prices! + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=04/21/06&tmplt_type=Show + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + + + 00:28:59 + + + + no + + + + Politics + Fri, 21 Apr 2006 16:00:00 GMT + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060421Chinas_Big_Visit_Big.mp3?1145657863 + 00:28:59 + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + no + + + + 2006-04-21T16:00:00Z + + + Iran Nukes; Rumsfeld Won't Go; Mitt Romney and Mass Healthcare + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=04/14/06&tmplt_type=Show + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + + + 00:29:00 + + + + no + + + + Politics + Fri, 14 Apr 2006 16:00:00 GMT + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060414Iran_Nukes_Rumsfeld_.mp3?1145062782 + 00:29:00 + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + no + + + + 2006-04-14T16:00:00Z + + + Did W OK Libby Leak?; Delay's Departure; Uncompromising Positions on Immigration + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=04/07/06&tmplt_type=Show + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + Lawrence O'Donnell, executive producer of The West Wing, hosts. Matt Miller and Arianna Huffington are away.<br clear=all> + Lawrence O'Donnell, executive producer of The West Wing, hosts. Matt Miller and Arianna Huffington are away.<br clear=all> + 00:29:00 + + + + no + + Lawrence O'Donnell, executive producer of The West Wing, hosts. Matt Miller and Arianna Huffington are away.<br clear=all> + + Politics + Fri, 07 Apr 2006 16:00:00 GMT + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060407Did_W_OK_Libby_Leak_.mp3?1144445197 + 00:29:00 + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + no + + Lawrence O'Donnell, executive producer of The West Wing, hosts. Matt Miller and Arianna Huffington are away.<br clear=all> + Lawrence O'Donnell, executive producer of The West Wing, hosts. Matt Miller and Arianna Huffington are away.<br clear=all> + 2006-04-07T16:00:00Z + + + Immigration, French Employment Riots, White House Shakeup and One Last Word + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=03/31/06&tmplt_type=Show + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + + + 00:29:00 + + + + no + + + + Politics + Fri, 31 Mar 2006 16:00:00 GMT + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060331Immigration_French_E.mp3?1143845320 + 00:29:00 + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + no + + + + 2006-03-31T16:00:00Z + + + Iraq, Third Anniversary; Media Response; Republicans and Immigration + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=03/24/06&tmplt_type=Show + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + Lawrence O'Donnell, executive producer of <a href=&quothttp://www.nbc.com/The_West_Wing&quot target=&quotnew&quot>The West Wing</a>, sits in for Matt Miller, who is away.<br> + Lawrence O'Donnell, executive producer of <a href=&quothttp://www.nbc.com/The_West_Wing&quot target=&quotnew&quot>The West Wing</a>, sits in for Matt Miller, who is away.<br> + 00:28:59 + + + + no + + Lawrence O'Donnell, executive producer of <a href=&quothttp://www.nbc.com/The_West_Wing&quot target=&quotnew&quot>The West Wing</a>, sits in for Matt Miller, who is away.<br> + + Politics + Fri, 24 Mar 2006 16:00:00 GMT + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060324Iraq_Third_Anniversa.mp3?1143240653 + 00:28:59 + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + no + + Lawrence O'Donnell, executive producer of <a href=&quothttp://www.nbc.com/The_West_Wing&quot target=&quotnew&quot>The West Wing</a>, sits in for Matt Miller, who is away.<br> + Lawrence O'Donnell, executive producer of <a href=&quothttp://www.nbc.com/The_West_Wing&quot target=&quotnew&quot>The West Wing</a>, sits in for Matt Miller, who is away.<br> + 2006-03-24T16:00:00Z + + + Iran Wants to Talk; Republicans Drunk on Debt; Impeachment: New Battle Cry of Far Left, Far Right! + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=03/17/06&tmplt_type=Show + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + Arianna Huffington is away.<br> + Arianna Huffington is away.<br> + 00:28:59 + + + + no + + Arianna Huffington is away.<br> + + Politics + Fri, 17 Mar 2006 16:00:00 GMT + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060317Iran_Wants_to_Talk_R.mp3?1142631399 + 00:28:59 + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + no + + Arianna Huffington is away.<br> + Arianna Huffington is away.<br> + 2006-03-17T16:00:00Z + + + Bye-Bye, Dubai; Bush's Plummeting Polls; Why Democrats Can't Get Traction; Economic Roundup + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=03/10/06&tmplt_type=Show + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + Bye Bye, Dubai. Bush's plummeting polls. Why can't Democrats get traction? +Plus, Greenspan inks book deal. Stock market rallies. (Arianna Huffington is away.)<br> + Bye Bye, Dubai. Bush's plummeting polls. Why can't Democrats get traction? +Plus, Greenspan inks book deal. Stock market rallies. (Arianna Huffington is away.)<br> + 00:28:59 + + + + no + + Bye Bye, Dubai. Bush's plummeting polls. Why can't Democrats get traction? +Plus, Greenspan inks book deal. Stock market rallies. (Arianna Huffington is away.)<br> + + Politics + Fri, 10 Mar 2006 16:00:00 GMT + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060310Bye-Bye_Dubai_Bushs_.mp3?1142025475 + 00:28:59 + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + no + + Bye Bye, Dubai. Bush's plummeting polls. Why can't Democrats get traction? +Plus, Greenspan inks book deal. Stock market rallies. (Arianna Huffington is away.)<br> + Bye Bye, Dubai. Bush's plummeting polls. Why can't Democrats get traction? +Plus, Greenspan inks book deal. Stock market rallies. (Arianna Huffington is away.)<br> + 2006-03-10T16:00:00Z + + + Nukes in the News; Doubts on Dubai Ports; Katrina Culpability; Is Iraq Irreparable? + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=03/03/06&tmplt_type=Show + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + Lawrence O'Donnell sits in for Matt Miller as moderator.<br> + Lawrence O'Donnell sits in for Matt Miller as moderator.<br> + 00:29:00 + + + + no + + Lawrence O'Donnell sits in for Matt Miller as moderator.<br> + + Politics + Fri, 03 Mar 2006 16:00:00 GMT + http://aolradio.podcast.aol.com/kcrw/audio/lr/lr060303Nukes_in_the_News_Do.mp3?1141422299 + 00:29:00 + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + no + + Lawrence O'Donnell sits in for Matt Miller as moderator.<br> + Lawrence O'Donnell sits in for Matt Miller as moderator.<br> + 2006-03-03T16:00:00Z + + + Civil War in Iraq? Port Wars in the US? Bye Bye, Larry Summers and Defending Free Speech + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=02/24/06&tmplt_type=Show + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + + + + + + no + + + Politics + Fri, 24 Feb 2006 16:00:00 GMT + http://www.kcrw.com/cgi-bin/db/kcrw.pl?show_code=lr&air_date=02/24/06&tmplt_type=Show + R.Scheer, A.Huffington, M.Miller &amp; T.Blankley + no + + + + 2006-02-24T16:00:00Z + + + + diff --git a/rome-modules/src/test/resources/xml/news-atom.xml b/rome-modules/src/test/resources/xml/news-atom.xml new file mode 100644 index 0000000..0ae4a03 --- /dev/null +++ b/rome-modules/src/test/resources/xml/news-atom.xml @@ -0,0 +1,58 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + First man in Space + Colonel Yuri A. Gagarin,1934 - 1968, 1961 + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + http://www.providers-website.com/image1.jpg + 2007-03-20 + news + old + + Journal + 1961-04-12 + James Smith + 1 + + + + + + Cloning in focus + Some of the issues in cloning. + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + http://www.providers-website.com/image2.jpg + 2010-03-20 + news + risk + flash + + Government Press release + 2007-02-13 + James Smith + 1 + + + diff --git a/rome-modules/src/test/resources/xml/news2.xml b/rome-modules/src/test/resources/xml/news2.xml new file mode 100644 index 0000000..574387d --- /dev/null +++ b/rome-modules/src/test/resources/xml/news2.xml @@ -0,0 +1,50 @@ + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + + First man in Space + Colonel Yuri A. Gagarin,1934 - 1968, 1961 + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 192 + 2007-03-20 + news + old + + Journal + 1961-04-12 + James Smith + 1 + + + + + + Cloning in focus + Some of the issues in cloning. + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 193 + 2010-03-20 + news + risk + flash + + Government Press release + 2007-02-13 + James Smith + 1 + + + + diff --git a/rome-modules/src/test/resources/xml/personals-atom.xml b/rome-modules/src/test/resources/xml/personals-atom.xml new file mode 100644 index 0000000..560e8d0 --- /dev/null +++ b/rome-modules/src/test/resources/xml/personals-atom.xml @@ -0,0 +1,66 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Vietnamese Asian Male + 23 year old dude looking for a girl + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + http://www.providers-website.com/image1.jpg + 2005-12-20 + Personals + m4w + + Vietnamese + M + straight + Single Women + single + Sales + Google, Inc. + 23 + Anytown, 12345, USA + + + + + + Divorced female + Looking for a partner + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02 + http://www.providers-website.com/image2.jpg + 2005-12-20 + Personals + w4m + + Latino + F + straight + Single/Divorced Male + divorced + Construction + Constrco, Inc. + 33 + Anytown, 12345, USA + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/personals2.xml b/rome-modules/src/test/resources/xml/personals2.xml new file mode 100644 index 0000000..90d97a3 --- /dev/null +++ b/rome-modules/src/test/resources/xml/personals2.xml @@ -0,0 +1,59 @@ + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + + Single South Asian Male + 23 year old man looking for a woman + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 199 + 2005-12-20 + Personals + m4w + + South Asian + M + straight + Single Women + single + Sales + Google, Inc. + 23 + Anytown, 12345, USA + + + + + + Divorced female + Looking for a partner + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 199 + 2005-12-20 + Personals + w4m + + Hispanic + F + straight + Single/Divorced Men + divorced + Construction + Constrco, Inc. + 33 + Anytown, 12345, USA + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/products-atom.xml b/rome-modules/src/test/resources/xml/products-atom.xml new file mode 100644 index 0000000..b02fcbb --- /dev/null +++ b/rome-modules/src/test/resources/xml/products-atom.xml @@ -0,0 +1,103 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Google Mini + Now the same reliable results you expect from Google web search can be yours on your intranet or public website with the Google Mini search appliance. This combined hardware and software solution is easy to use, simple to deploy, and can begin providing great search results in just a few short hours. The Google Mini can provide search for up to 100,000 documents, and it supports over 220 different file types. The price includes 1 year of full customer support, software updates, and replacement coverage. + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + + http://www.googlestore.com/appliance/images/products/GO0144E.jpg + 2005-12-20 + Web Search + Appliance + + USD + 2995 + starting + Check + MasterCard + financing available + Google + 12348573 + Google + 2325 + 234 + 10x50x20 + 2 + 300 + new + blue + ship + 1600 Amphitheatre Pkwy Mountain View, CA 94043-1351, US + + US + Standard + 5000 + + California + 8.25 + + + + + + Acme Laptop + Acme 2000 series laptop + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + + http://www.providers-website.com/image2.jpg + 2005-12-20 + Computer + Laptop + + USD + 1400 + starting + MasterCard + Visa + 20 + Acme + 2305934757 + Acme + 834 + 512 + 2 + 2000 + 14x14x3 + 2 + new + black + electronics + 123 Main St, Anytown, CA, 12345, USA + 50 + + US + Overnight + 32.95 + + California + 8.25 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/products2.xml b/rome-modules/src/test/resources/xml/products2.xml new file mode 100644 index 0000000..83c5da1 --- /dev/null +++ b/rome-modules/src/test/resources/xml/products2.xml @@ -0,0 +1,92 @@ + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + + Google Mini + Now the same reliable results you expect from Google web search can be yours on your intranet or public website with the Google Mini search appliance. This combined hardware and software solution is easy to use, simple to deploy, and can begin providing great search results in just a few short hours. The Google Mini can provide search for up to 100,000 documents, and it supports over 220 different file types. The price includes 1 year of full customer support, software updates, and replacement coverage. + http://www.googlestore.com/appliance/GO0123.asp + http://www.googlestore.com/appliance/images/products/GO0144E.jpg + 1092 + 2005-12-20 + web search + appliance + + USD + 2995 + starting + Check + MasterCard + financing available + Google + 12348573 + Google + 2325 + 234 + 10x50x20 + 2 + 300 + new + blue + 1600 Amphitheatre Pkwy Mountain View, CA 94043-1351, US + + US + Standard + 5000 + + California + 8.25 + + + + + + Acme Laptop + Acme 2000 series laptop + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 822 + 2005-12-20 + Computer + Laptop + + USD + 1400 + starting + MasterCard + Visa + 20 + Acme + 2305934757 + Acme + 834 + 512 + 2 + 2000 + 14x14x3 + 2 + new + black + electronics + 123 Main St, Anytown, CA, 12345, USA + 50 + + US + Overnight + 32.95 + + California + 8.25 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/research-atom.xml b/rome-modules/src/test/resources/xml/research-atom.xml new file mode 100644 index 0000000..fcac7d3 --- /dev/null +++ b/rome-modules/src/test/resources/xml/research-atom.xml @@ -0,0 +1,59 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Analysis of tsunami on the economy + Analysis of the recent tsumani on the economy + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Economy + Tsunami + + 2005-02-25 + James Smith + Tsunami and the Economy + III + 5 + + + + + + Google and the internet + Analysis of Google's impact on the internet + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Internet + Search Engine + + 2004-01-29 + Sue Smith + Google and the Internet + VI + 23 + + + diff --git a/rome-modules/src/test/resources/xml/research2.xml b/rome-modules/src/test/resources/xml/research2.xml new file mode 100644 index 0000000..9cca88b --- /dev/null +++ b/rome-modules/src/test/resources/xml/research2.xml @@ -0,0 +1,52 @@ + + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + + Analysis of tsunami on the economy + Analysis of the recent tsumani on the economy + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 19 + 2005-12-20 + Economy + Tsunami + + 2005-02-25 + James Smith + Tsunami and the Economy + III + 5 + + + + + + Google and the internet + Analysis of Google's impact on the internet + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 29 + 2005-12-20 + Internet + Search Engine + + 2004-01-29 + Sue Smith + Google and the Internet + VI + 23 + + + + diff --git a/rome-modules/src/test/resources/xml/reviews-atom.xml b/rome-modules/src/test/resources/xml/reviews-atom.xml new file mode 100644 index 0000000..15bb8cb --- /dev/null +++ b/rome-modules/src/test/resources/xml/reviews-atom.xml @@ -0,0 +1,64 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Google Earth - Explore the World from your PC + Read about Google Earth and its many features. + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Review + Earth + Google + + Google Earth + Product + editorial + 5 + http://earth.google.com/ + 2005-03-24 + Jimmy Smith + + + + + + Movie Review: Star Wars + Movie review for Star Wars + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Movie Review + Star Wars + + Star Wars Movie + Movies + editorial + 4 + http://www.example.com/asp/sp.asp?id=169 + 2004-04-23 + Sue Smith + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/reviews2.xml b/rome-modules/src/test/resources/xml/reviews2.xml new file mode 100644 index 0000000..05b6776 --- /dev/null +++ b/rome-modules/src/test/resources/xml/reviews2.xml @@ -0,0 +1,56 @@ + + + + + + + Provider's Title + A description of the channels content. + http://www.providers-website.com + + + + Google Earth - Explore the World from your PC + Read about Google Earth and its many features + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 193 + 2005-12-20 + Review + Earth + Google + + Google Earth + Product + editorial + 5 + http://earth.google.com/ + 2005-03-24 + Jimmy Smith + + + + + + Movie Review: Star Wars + Movie review for Star Wars + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 169 + 2005-12-20 + Movie Review + Star Wars + + Star Wars Movie + Movies + editorial + 4 + http://www.example.com/asp/sp.asp?id=169 + 2004-04-23 + Sue Smith + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/rsr.xml b/rome-modules/src/test/resources/xml/rsr.xml new file mode 100644 index 0000000..eda00c4 --- /dev/null +++ b/rome-modules/src/test/resources/xml/rsr.xml @@ -0,0 +1,251 @@ + + + + La Capsule multimédia - La 1ère - RSR + RSR - La 1ère + http://www.rsr.ch/capsule + C'est là qu'on voit le numérique dans tous ses états. C'est là que les capsules de la semaine sont téléchargeables et livrées à vos oreilles. Avec un appétit féroce vous pouvez les écouter encore et encore. C'est le podcast de la capsule multimédia. A siroter ou à croquer. + + La chronique multimédia du Journal du Matin. + + C'est là qu'on voit le numérique dans tous ses états. C'est là que les capsules de la semaine sont téléchargeables et livrées à vos oreilles. Avec un appétit féroce vous pouvez les écouter encore et encore. C'est le podcast de la capsule multimédia. A siroter ou à croquer. + + La Capsule multimédia - La 1ère - RSR + info.multimedia@rsr.ch + + + Gadgets + + + + Video Games + + radio multimedia internet jeux video games + fr-ch + © RSR + + info.multimedia@rsr.ch + Mon, 11 Dec 2006 00:00:00 GMT + Mon, 11 Dec 2006 07:23:29 GMT + + http://www1.rsr.ch/rsr/podcasting/img/logo_lp.jpg + http://www.rsr.ch/capsule + logo + + + + La Wii + http://www.rsr.ch/capsule + Radio Suisse Romande + RSR - La 1ère + + Mon, 11 Dec 2006 06:20:00 GMT + + Invité : Laurent Dormond. + + + +La nouvelle console Nintendo, appelé Wii, est arrivée. La différence la plus notable consiste dans manette de forme et avec des options différentes : pour la main droite, une télécommande et pour la main gauche, une sorte de poire appelé « Nunchuk » avec un capteur de mouvement relié à la console par Bluettoth, c’est à dire un système radio sans fil. + + + + 00:04:49.0 + + + + Le Salon IUT Telecom de Hong Kong + http://www.rsr.ch/capsule + Radio Suisse Romande + RSR - La 1ère + Fri, 08 Dec 2006 06:20:00 GMT + + + Un des grands courants qui ressort de ce salon c’est l’appareil unique. Vous aurez de plus en plus entre les mains une seule machine qui fait téléphone agenda, GPS, console de jeux, lecteur vidéo, téléchargeur de fichiers, copilote etc. + + 00:04:10.6 + + + Le salon de la découverte ITU Telecom World 2006 à Hong Kong + http://www.rsr.ch/capsule + + Radio Suisse Romande + RSR - La 1ère + Thu, 07 Dec 2006 06:20:00 GMT + + Jean-Olivier Pain est allé se balader au salon de la découverte ITU et y a découvert des caméras de surveillance-téléphone ou encore un micro à émotions. + + 00:03:41.2 + + + + Le salon de l'ITU à Hong-Kong + http://www.rsr.ch/capsule + Radio Suisse Romande + RSR - La 1ère + Wed, 06 Dec 2006 06:20:00 GMT + + + Invité : Jean-Paul Chaib, directeur du développement pour la société ATDI SA +Pour être présent sur le marché asiatique des multimédias, il faut être présent à la grande foire de l’International Telecommunication Union qui se tient actuellement à Hong-Kong. + + 00:03:42.3 + + + Salon Telecom 2007 + + http://www.rsr.ch/capsule + Radio Suisse Romande + RSR - La 1ère + Tue, 05 Dec 2006 06:20:00 GMT + + A Hong-Kong a lieu le rendez-vous de l’ITU Telecom, le salon des télécommunications ITU Telecom. On parle de convergences, de multimédia et de solutions groupées. On peut trouver des écrans haute définition, tactiles, où les textes sont hyper lisibles, aux menus accessibles au premier coup d’œil. Le téléphone IP a beaucoup la cote, ainsi que la téléphonie Wifi. + + + 00:02:47.4 + + + ITU Telecom + http://www.rsr.ch/capsule + Radio Suisse Romande + + RSR - La 1ère + Mon, 04 Dec 2006 06:20:00 GMT + + Invité : Fernando Lagrana, directeur exécutif de l’ITU Telecom. + + + +L’ITU est l’organisation faîtière qui planifie et coordonne le monde des télécommunications et des services, notamment de tout ce qui est numérique. 200 Etats membres la composent et 600 secteurs sont concernés par ses activités. + + + 00:04:22.4 + + + + Tony Hawk’s – Project 8 + http://www.rsr.ch/capsule + Radio Suisse Romande + RSR - La 1ère + Fri, 01 Dec 2006 06:20:00 GMT + + + Un nouveau jeu vidéo à roulettes sort sur PS2, Xbox 360, sans doute sur PC mais plus tard également sur Nintendo DS et PSP. Le nom de ce jeu tout-terrains ? Il s’agit du huitième opus du skateboarder Tony Hawk, « Tony Hawk’s-Project 8 ». + + 00:04:22.3 + + + Vidéo-blog-reportage-interactif + + http://www.rsr.ch/capsule + Radio Suisse Romande + RSR - La 1ère + Thu, 30 Nov 2006 06:20:00 GMT + + Invitée : Tristan Mendès France, assistant parlementaire français. +Partir dans un pays étranger, faire là-bas un reportage filmé avec des téléphones portables, influencer le reportage selon les réactions sur le blog, voilà comment pourrait s'envisager le nouveau métier de correspondant. + + + 00:03:38.6 + + + GPS Coyote + http://www.rsr.ch/capsule + Radio Suisse Romande + + RSR - La 1ère + Wed, 29 Nov 2006 06:20:00 GMT + + Ce GPS a en plus d’un appareil de navigation classique une technologie de téléphone portable, c’est à dire une carte Sim et l’opérateur mobile, afin d’avertir les automobilistes de la présence de radars. + + 00:04:43.2 + + + + Orb, logiciel permettant d’atteindre son disque dur partout dans le monde. + http://www.rsr.ch/capsule + Radio Suisse Romande + RSR - La 1ère + Tue, 28 Nov 2006 06:20:00 GMT + + + Pour accéder depuis les quatre coins du monde à son ordinateur resté en Suisse, il suffit de taper « mycast.orb.com » . Cela fait monter une demande de logon et de mot de passe et ensuite Orb retrouvera la machine souhaitée et la rendra accessible pour une liaison directe. + + 00:03:54.1 + + + Le Hawk-Eye + + http://www.rsr.ch/capsule + Radio Suisse Romande + RSR - La 1ère + Mon, 27 Nov 2006 06:20:00 GMT + + Un nouveau procédé numérique fait son apparition dans les compétitions de tennis, il s’appelle le Hawk-Eye, littéralement Œil de faucon. Le système a été inauguré lors du Masters de Miami, à Key Biscayne, avant une grande première en grand chelem lors de l'US Open 2006. La balle se retrouve donc sous étroite surveillance. En effet, des caméras situées autour du court, capturent la trajectoire de la balle et en fonction des paramètres du mouvement représente mathématiquement la trajectoire de la balle avec son impacte sur le sol. Invité : Rémy Azémar, responsable du service arbitrage à la fédération française de tennis. + + + 00:03:46.6 + + + Call of Duty III : en marche vers Paris + http://www.rsr.ch/capsule + Radio Suisse Romande + + RSR - La 1ère + Fri, 24 Nov 2006 06:20:00 GMT + + Call of Duty III est un jeu qui sort exclusivement sur Xbox 360. Ca mitraille de tous les côtés dans une France de 1944 bucolique au graphisme parfait. + + 00:03:51.1 + + + + Poker en ligne + http://www.rsr.ch/capsule + Radio Suisse Romande + RSR - La 1ère + Wed, 22 Nov 2006 06:20:00 GMT + + + Invité : Julien Brecard, coordinateur évènementiel pour Everest Poker point net. + + + +Quelques sites donnent la possibilité de passer par une école de poker gratuite et en ligne où par un logiciel à installer. Une fois le jeu appris, vous pouvez jouer sur Texas Holden No limit, la variété de Poker la plus jouée sur le Net, qui est reconnaissable à ses cartes en amandes et ses jetons en plastique du Missouri. + + + 00:03:35.8 + + + Débit France volet II + + http://www.rsr.ch/capsule + Radio Suisse Romande + RSR - La 1ère + Tue, 21 Nov 2006 06:20:00 GMT + + La connexion haut débit est nécessaire, car pour faire passer dans le tuyau, la télé, la téléphonie, le surf et le téléchargement, il faut des connexions avec du biceps. Le débit n’est pas le seul critère. On pense que plus le débit est élevé plus la réception de la TV sera de qualité, mais c’est faux. Avec l’Adsl , tout le monde ne loge pas à la même enseigne. Invité : William Rang, directeur technique d’IP Label en France. + + + 00:04:10.0 + + + Débit France + http://www.rsr.ch/capsule + Radio Suisse Romande + + RSR - La 1ère + Mon, 20 Nov 2006 06:20:00 GMT + + Invité : William Rang, directeur technique d’IP Label en France. + + + +Le « triple Play », en termes informatiques signifie qu’avec une connexion ADSL ou câble une personne peut se connecter à Internet, avoir accès aux chaînes de télévision et avoir un téléphone fixe. Tous ces services passent par une seule connexion . La situation en France. + + + 00:03:31.8 + + + + + diff --git a/rome-modules/src/test/resources/xml/rss-playlist-sse.xml b/rome-modules/src/test/resources/xml/rss-playlist-sse.xml new file mode 100644 index 0000000..8d7d99e --- /dev/null +++ b/rome-modules/src/test/resources/xml/rss-playlist-sse.xml @@ -0,0 +1,116 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + + Lucky Man.mp3 + Emerson Lake and Palmer - Lucky Man.mp3 + + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + + Riding With the King.mp3 + + + B. B. King and Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/rss-playlist.xml b/rome-modules/src/test/resources/xml/rss-playlist.xml new file mode 100644 index 0000000..b96a651 --- /dev/null +++ b/rome-modules/src/test/resources/xml/rss-playlist.xml @@ -0,0 +1,75 @@ + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + Lucky Man.mp3 + Emerson Lake and Palmer - Lucky Man.mp3 + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + Riding With the King.mp3 + + + B. B. King and Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + diff --git a/rome-modules/src/test/resources/xml/rss-test-1.xml b/rome-modules/src/test/resources/xml/rss-test-1.xml new file mode 100644 index 0000000..8e50af9 --- /dev/null +++ b/rome-modules/src/test/resources/xml/rss-test-1.xml @@ -0,0 +1,37 @@ + + + + + + + + Google Jobs +http://www.google.com/support/jobs/ +Information about job openings at Google Inc. + + +HR Analyst - Mountain View +http://www.google.com/support/jobs/bin/topic.py?dep_id=1077&loc_id=1116 + We have an immediate need for an experienced analytical HR professional. +The ideal candidate has a proven record of developing analytical frameworks to make +fact-based decisions. +2005-11-17T14:28:27-05:00 +http://www.google.com/images/google_sm.gif +2005-11-15 +Analyst +1600 Amphitheatre Parkway, Mountain View, CA, 94043, USA +Hi-Tech +Business development +Personnel +Silicon Valley +Staffing + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/rss1sample.xml b/rome-modules/src/test/resources/xml/rss1sample.xml new file mode 100644 index 0000000..576728b --- /dev/null +++ b/rome-modules/src/test/resources/xml/rss1sample.xml @@ -0,0 +1,62 @@ + + + + + + + Meerkat + http://meerkat.oreillynet.com + Meerkat: An Open Wire Service + + + + + + + + + + + + + + Meerkat Powered! + http://meerkat.oreillynet.com/icons/meerkat-powered.jpg + http://meerkat.oreillynet.com + + + + + XML: A Disruptive Technology + http://c.moreover.com/click/here.pl?r123 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/rssCreativeCommonsExample.xml b/rome-modules/src/test/resources/xml/rssCreativeCommonsExample.xml new file mode 100644 index 0000000..3765591 --- /dev/null +++ b/rome-modules/src/test/resources/xml/rssCreativeCommonsExample.xml @@ -0,0 +1,27 @@ + + + + Scripting News + http://www.scripting.com/ + A weblog about scripting and stuff like that. + en-us + Copyright 1997-2002 Dave Winer + http://www.creativecommons.org/licenses/by-nd/1.0 + Mon, 16 Dec 2002 13:00:02 GMT + http://backend.userland.com/rss + Radio UserLand v8.0.5 + dave@userland.com + dave@userland.com + + Creative Commons <a href="http://www.creativecommons.org/press-releases/entry/3476">press release</a>. "People want to bridge the public domain with the realm of private copyrights," said Stanford Law Professor and Creative Commons Chairman Lawrence Lessig. + Mon, 16 Dec 2002 12:48:41 GMT + http://scriptingnews.userland.com/backissues/2002/12/16#When:4:48:41AM + + + <a href="http://www.creativecommons.org/"><img src="http://www.creativecommons.org/icon/sa/standard.gif" width="32" height="32" align="left" hspace="5" vspace="5" border="0"></a>This morning Creative Commons opened up a formerly private part of their site containing enumerations of the different <a href="http://www.creativecommons.org/licenses/">licenses they support</a>. It's very simple. A document, a weblog, a RSS file, a PDF or whatever, can specify which license applies. On the CC site, they tell you how to do it with RDF, but I'm interested in a solution that can be used in RSS 2.0 files, so we can in turn add a user interface to Rado and Manila (and others can do it for other authoring tools) that tie into the CC system. I totally support the idea of lawyers helping creative people instead of imprisoning us, but I can't convert everything I do to RDF to do that. Tonight is their launch. I'm toing it. If we can get a namespace defined and vetted today, I can announce our support tonight. An <a href="http://www.google.com/search?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&q=%22on+internet+time%22">Internet-Time</a> solution to remind us we used to have a Can-Do attitude. + Mon, 16 Dec 2002 12:21:08 GMT + http://scriptingnews.userland.com/backissues/2002/12/16#When:4:21:08AM + http://www.creativecommons.org/licenses/by-nc/1.0 + + + diff --git a/rome-modules/src/test/resources/xml/services-atom.xml b/rome-modules/src/test/resources/xml/services-atom.xml new file mode 100644 index 0000000..eaf2b7f --- /dev/null +++ b/rome-modules/src/test/resources/xml/services-atom.xml @@ -0,0 +1,72 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Acme food delivery + Food delivery service + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Food delivery + + USD + 15 + starting + Visa + MasterCard + minimum payment on credit cards:45 + delivery + Anytown, CA, USA + 20 + Will deliver between 9am to 6pm + + US + Standard + 20 + + California + 8.25 + + + + + Acme Pest Control + Get rid of those pesky pests + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Pest + Mouse + + USD + 20 + starting + Check + Visa + pest control + Anytown, CA, USA + 50 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/services2.xml b/rome-modules/src/test/resources/xml/services2.xml new file mode 100644 index 0000000..bf96262 --- /dev/null +++ b/rome-modules/src/test/resources/xml/services2.xml @@ -0,0 +1,63 @@ + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + Acme food delivery + Food delivery service + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 69 + 2005-12-20 + Food delivery + + USD + 15 + starting + Visa + MasterCard + minimum payment on credit cards:45 + delivery + Anytown, CA, USA + 20 + will deliver between 9am -5pm + + US + Standard + 20 + + California + 8.25 + + + + + Acme Pest Control + Get rid of those pesky pests + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 69 + 2005-12-20 + Pest + Mouse + + USD + 20 + starting + Check + Visa + pest control + Anytown, CA, USA + 50 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/simple/rss-playlist-sse.xml b/rome-modules/src/test/resources/xml/simple/rss-playlist-sse.xml new file mode 100644 index 0000000..649fbf1 --- /dev/null +++ b/rome-modules/src/test/resources/xml/simple/rss-playlist-sse.xml @@ -0,0 +1,102 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake and Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + + B. B. King and Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/simple/rss-playlist.xml b/rome-modules/src/test/resources/xml/simple/rss-playlist.xml new file mode 100644 index 0000000..58069fd --- /dev/null +++ b/rome-modules/src/test/resources/xml/simple/rss-playlist.xml @@ -0,0 +1,62 @@ + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + Lucky Man.mp3 + Emerson Lake and Palmer - Lucky Man.mp3 + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + Riding With the King.mp3 + + + B. B. King and Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + diff --git a/rome-modules/src/test/resources/xml/slashdot.xml b/rome-modules/src/test/resources/xml/slashdot.xml new file mode 100644 index 0000000..3316106 --- /dev/null +++ b/rome-modules/src/test/resources/xml/slashdot.xml @@ -0,0 +1,178 @@ + + + + Slashdot + http://slashdot.org/ + News for nerds, stuff that matters + en-us + Copyright 1997-2005, OSTG - Open Source Technology Group, Inc. All Rights Reserved. + 2005-11-20T01:11:49+00:00 + OSTG + pater@slashdot.org + Technology + hourly + 1 + 1970-01-01T00:00+00:00 + + + + + + + + + + + + + + + + + + + Slashdot + http://images.slashdot.org/topics/topicslashdot.gif + http://slashdot.org/ + + + The Prisoner To Be Remade On U.K. TV + http://rss.slashdot.org/Slashdot/slashdot?m=1961 + An anonymous reader writes "Various UK news sites are reporting that Sky One is to commission a remake of the cult 60s UK TV series, The Prisoner. See u.tv and This is London." From the This Is London story: "The series, which made its debut 1967, is today credited by its fans as being ahead of its time. Featuring McGoohan as a former secret agent trapped in an isolated seaside village, it was shown in more than 60 countries. The new version will not be placed in the original setting, the north Wales village of Portmeirion, or have the arty, 'pop' feel of the original, according to the magazine Broadcast. Damien Timmer, who has been lined up to executive produce the show, told the television and radio industry magazine that the new series 'takes liberties with the original'."<img src="http://rss.slashdot.org/Slashdot/slashdot?g=1961"/> + Zonk + 2005-11-20T00:43:00+00:00 + tv + now-we-need-more-red-dwarf + mainpage + 25 + 25,22,19,12,2,0,0 + http://slashdot.org/article.pl?sid=05/11/19/2014233&from=rss + + + Spike TV Video Game Award Winners + http://rss.slashdot.org/Slashdot/slashdot?m=1960 + Gamespot reports on the results from Friday's Spike TV Video Game Awards. Top Game honor went to RE4, while King Kong and World of Warcraft both took home several category nods. From the article: "As much as Spike might have refined the show over its past pair of efforts, it was clear the network had not yet found a way to perfectly merge the subject matter, the celebrities, and the audience. Nowhere was evidence of this more pronounced than in the significant number of audience members heading for the exits right after Missy Elliott's climactic performance, having seen all they came for and not caring to find out who was going to take home the Game of the Year award. Winners for Best Gaming Publication, Best Gaming Website, and Best Gaming Blog were not announced at the show. " +<p><a href="http://rss.slashdot.org/~c/Slashdot/slashdot?a=dJ24JB"><img src="http://rss.slashdot.org/~c/Slashdot/slashdot?i=dJ24JB" border="0"></img></a></p><img src="http://rss.slashdot.org/Slashdot/slashdot?g=1960"/> + Zonk + 2005-11-19T23:40:00+00:00 + tv + at-least-there-was-some-jack-black + games + 38 + 38,36,29,21,6,4,1 + http://games.slashdot.org/article.pl?sid=05/11/19/224214&from=rss + + + Apache Comes With Too Much Community Overhead? + http://rss.slashdot.org/Slashdot/slashdot?m=1959 + drizzle writes "There's an interesting story on the Apache Marketing blog about whether or not Apache projects come with too much overhead, especially compared with other services or a roll-your-own approach. The article states, 'It's true that compared with SourceForge, Apache has a more rigorous management structure. The ASF has formalized processes and procedures that we believe represent best practices governance. All new projects must pass through an incubation period to ensure that all of the project's members have internalized these processes. However, each project's leadership has a tremendous amount of discretion in managing within this framework.' There is also a follow up article written by one of the httpd developers about 'What Apache brings to the table.' The article cites community, experience, legal framework, diversity, brand strength, and networking as reasons why developers and companies should consider bringing their projects over to Apache."<img src="http://rss.slashdot.org/Slashdot/slashdot?g=1959"/> + Zonk + 2005-11-19T22:39:00+00:00 + software + many-hands-make-light-work + apache + 62 + 62,60,40,30,18,12,8 + http://apache.slashdot.org/article.pl?sid=05/11/19/2010223&from=rss + + + The Guardian On Intellectual Property + http://rss.slashdot.org/Slashdot/slashdot?m=1958 + mykdavies writes "The Guardian has an excellent article giving lay readers an overview of some of the problems being caused by the concept of 'intellectual property', including references to stories familiar to Slashdot readers, such as DVD Jon, the Sony rootkit, Amazon and Google business patents." From the article: "Even facts about the world can, in some cases, become the property of commercial companies. It was the promise of gaining patents on the human genome that lured investors into the private consortium that attempted to sequence it in competition with the public effort. Laboratory animals have already been patented, starting with the OncoMouse, an animal whose genome has been manipulated to ensure that it develops cancer."<img src="http://rss.slashdot.org/Slashdot/slashdot?g=1958"/> + Zonk + 2005-11-19T21:27:00+00:00 + patents + ins-and-outs + yro + 110 + 110,105,76,45,20,7,2 + http://yro.slashdot.org/article.pl?sid=05/11/19/208219&from=rss + + + Cisco Moving On Set-Top Boxes + http://rss.slashdot.org/Slashdot/slashdot?m=1957 + nevermindme writes "Cisco has agreed to plunk down a whopping $6.9bn for Scientific-Atlanta, hoping to take a major share of the set-top-box market and push video efforts. The networking giant will pay $43 per share in cash for Scientific-Atlanta ($5.3bn) and swallow $1.6bn in debt. With the buy, Cisco acquires one of the more dominant set-top-box makers. In addition, it pushes well beyond the data center to touch consumers where they live." +<p><a href="http://rss.slashdot.org/~c/Slashdot/slashdot?a=UAEMGp"><img src="http://rss.slashdot.org/~c/Slashdot/slashdot?i=UAEMGp" border="0"></img></a></p><img src="http://rss.slashdot.org/Slashdot/slashdot?g=1957"/> + Zonk + 2005-11-19T20:30:00+00:00 + tv + new-horizons + hardware + 72 + 72,68,51,35,16,9,5 + http://hardware.slashdot.org/article.pl?sid=05/11/19/1810238&from=rss + + + Getting All 1,700 Parts of the Xbox 360 to Market + http://rss.slashdot.org/Slashdot/slashdot?m=1956 + Carl Bialik from the WSJ writes "Microsoft is hoping its Xbox 360 will further the company's goal to 'link the Web and entertainment of all forms in consumers' living rooms,' the Wall Street Journal reports, but 'one manufacturing misstep -- a shortage of graphics chips or a recalled hard drive -- could derail those ambitions and drag Microsoft's unprofitable videogame business even deeper into the red.' The WSJ traces the 1,700 parts that go into the device through the supply chain -- from two southern China factories, Rotterdam, and on to Toledo, Memphis, and ultimately, retailers in the U.S. -- and looks at what could go wrong along the way."<img src="http://rss.slashdot.org/Slashdot/slashdot?g=1956"/> + Zonk + 2005-11-19T19:36:00+00:00 + xbox + complicated-process + games + 141 + 141,140,103,73,19,12,8 + http://games.slashdot.org/article.pl?sid=05/11/18/156253&from=rss + + + Is Wi-Fi Ruining College? + http://rss.slashdot.org/Slashdot/slashdot?m=1955 + theodp writes "Over at Slate, Avi Zenilman has seen the real classroom of the future firsthand: Students use class time to read the Drudge Report, send e-mail, play Legend of Zelda, or update profiles on Facebook.com. But not to worry - replace laptops with crumpled notes, and the classroom of the future looks a lot like the classroom of the past." From the article: "... when Cornell University researchers outfitted classrooms with wireless Internet and monitored students' browsing habits, they concluded, 'Longer browsing sessions during class tend to lead to lower grades, but there's a hint that a greater number of browsing sessions during class may actually lead to higher grades.' It seems a bit of a stretch to impute a causal relationship, but it's certainly possible that the kind of brain that can handle multiple channels of information is also the kind of brain that earns A's."<img src="http://rss.slashdot.org/Slashdot/slashdot?g=1955"/> + Zonk + 2005-11-19T18:46:00+00:00 + ed + no + hardware + 279 + 279,272,210,140,43,23,13 + http://hardware.slashdot.org/article.pl?sid=05/11/19/186252&from=rss + + + Sony Completes First Full-Length Blu-ray Disc + http://rss.slashdot.org/Slashdot/slashdot?m=1954 + john writes "Sony Pictures Home Entertainment announced that authoring has been completed on the first Blu-ray Disc (BD) to contain a full-length, high-definition feature film. Charlie's Angels: Full Throttle was compressed and authored in MPEG 2 full high-definition (1920 x 1080) and is now being shipped to BD hardware companies for player testing." +<p><a href="http://rss.slashdot.org/~c/Slashdot/slashdot?a=OZPTC3"><img src="http://rss.slashdot.org/~c/Slashdot/slashdot?i=OZPTC3" border="0"></img></a></p><img src="http://rss.slashdot.org/Slashdot/slashdot?g=1954"/> + CowboyNeal + 2005-11-19T17:13:00+00:00 + sony + hot-off-the-presses + mainpage + 210 + 210,200,156,106,32,21,13 + http://slashdot.org/article.pl?sid=05/11/19/1534223&from=rss + + + Richard Stallman Accosted For Tinfoil Hat + http://rss.slashdot.org/Slashdot/slashdot?m=1953 + ndansmith writes "Bruce Perens posts in his blog about an amusing encounter between Richard Stallman and United Nations security at the World Summit on the Information Society in Tunis. It seems that RFID technology, which Stallman opposes for privacy reasons, was used in the identification badges for the conference. From the blog: 'You can't give Richard a visible RF ID strip without expecting him to protest. Richard acquired an entire roll of aluminum foil and wore his foil-shielded pass prominently.' During a keynote speech, Stallman also passed around the tinfoil for other to use as well. It seems that UN security was not amused, however, as they would not let him leave the room for some time." What makes this even funnier, of course, is that tin foil hats won't stop them.<img src="http://rss.slashdot.org/Slashdot/slashdot?g=1953"/> + CowboyNeal + 2005-11-19T16:04:00+00:00 + humor + of-all-the-reasons + mainpage + 425 + 425,412,333,250,97,57,42 + http://slashdot.org/article.pl?sid=05/11/19/149242&from=rss + + + Baltimore to Test Cell Phone Traffic Monitoring + http://rss.slashdot.org/Slashdot/slashdot?m=1952 + Momoru writes "The Baltimore Sun is reporting that a Canadian company, Delcan NET, will begin testing a technology that determines the flow of automobile traffic by monitoring cell phone traffic. The company promises a revolutionary way to determine backups, but privacy advocates fear the implications of a third party tracking users by their cell phones."<img src="http://rss.slashdot.org/Slashdot/slashdot?g=1952"/> + CowboyNeal + 2005-11-19T15:10:00+00:00 + privacy + big-brother-is-listening + yro + 118 + 118,114,75,49,23,20,14 + http://yro.slashdot.org/article.pl?sid=05/11/19/143247&from=rss + + + Search Slashdot + Search Slashdot stories + query + http://slashdot.org/search.pl + + + diff --git a/rome-modules/src/test/resources/xml/sunnyvale.xml b/rome-modules/src/test/resources/xml/sunnyvale.xml new file mode 100644 index 0000000..92bc02f --- /dev/null +++ b/rome-modules/src/test/resources/xml/sunnyvale.xml @@ -0,0 +1,49 @@ + + + + Yahoo! Weather - Sunnyvale, CA + http://us.rd.yahoo.com/dailynews/rss/weather/Sunnyvale__CA/*http://weather.yahoo.com/forecast/94089_f.html + Yahoo! Weather for Sunnyvale, CA + en-us + Mon, 21 Jan 2008 8:56 am PST + + 60 + + + + + + + Yahoo! Weather + + 142 + 18 + http://weather.yahoo.com/ + http://l.yimg.com/us.yimg.com/i/us/nws/th/main_142b.gif + + + Conditions for Sunnyvale, CA at 8:56 am PST + + 37.39 + -122.03 + http://us.rd.yahoo.com/dailynews/rss/weather/Sunnyvale__CA/*http://weather.yahoo.com/forecast/94089_f.html + Mon, 21 Jan 2008 8:56 am PST + +
      + Current Conditions:
      + Light Rain, 45 F

      + Forecast:
      + Mon - Showers. High: 49 Low: 40
      + Tue - Showers. High: 51 Low: 40
      +
      +Full Forecast at Yahoo! Weather
      + (provided by The Weather Channel)
      + ]]>
      + + + + 94089_2008_01_21_8_56_PST +
      +
      +
      diff --git a/rome-modules/src/test/resources/xml/test-rdf.xml b/rome-modules/src/test/resources/xml/test-rdf.xml new file mode 100644 index 0000000..77ab7f2 --- /dev/null +++ b/rome-modules/src/test/resources/xml/test-rdf.xml @@ -0,0 +1,51 @@ + + + + + Example Feed + http://www.example.org + Simply for the purpose of demonstration. + + + + + + + + + + + The Example Item + http://example.org/item/ + + + + + + + Altered This is very cool. + + + + + + This isvery cool.]]> + + + + + This is >very cool<. + + + + + + + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/totsp.xml b/rome-modules/src/test/resources/xml/totsp.xml new file mode 100644 index 0000000..12921cd --- /dev/null +++ b/rome-modules/src/test/resources/xml/totsp.xml @@ -0,0 +1,32 @@ + + + + + +screaming-penguin.com +http://www.screaming-penguin.com +Technology and software developer news and advocacy multi user weblog, with a decided Linux bent. + +http://www.screaming-penguin.com/ +screaming-penguin.com +http://www.screaming-penguin.com + +en-us + +Meridian Mississippi Howard Johnsons +http://www.screaming-penguin.com/main.php?storyid=5513 +http://www.screaming-penguin.com/main.php?storyid=5513 +I know nobody gives a crap, and personally I hate worthless blog entries like this when I have to re. . . + + +
      +No tech news to report from here, except that they have wireless net access in Mississippi. ;) ]]> +
      +Charlie "atrox" Collins +2005-11-18T21:53:35-05:00 +3 +
      +
      + +
      diff --git a/rome-modules/src/test/resources/xml/travel-atom.xml b/rome-modules/src/test/resources/xml/travel-atom.xml new file mode 100644 index 0000000..dca2b59 --- /dev/null +++ b/rome-modules/src/test/resources/xml/travel-atom.xml @@ -0,0 +1,91 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Train tickets to Anytown + Luxury train tickets + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Vacation + Train + + USD + 250 + starting + Check + Visa + minimum payment on credit cards:45 + 204 + Mytown, USA + Anytown, USA + + 2005-12-20T18:00:00 + 2005-12-22T18:00:00 + + 123 Main St, Mytown, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + + + + Cruise Hawaii + 3 day Crusie, visit Hawaii + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Cruise + Hawaii + + USD + 1200 + starting + Visa + MasterCard + minimum payment on credit cards:45 + 210 + San Francisco, CA, USA + Hawaii, USA + + 2005-11-20T18:00:00 + 2005-11-26T12:00:00 + + 123 Main St., San Francisco, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/travel2.xml b/rome-modules/src/test/resources/xml/travel2.xml new file mode 100644 index 0000000..d1c396d --- /dev/null +++ b/rome-modules/src/test/resources/xml/travel2.xml @@ -0,0 +1,82 @@ + + + + + + + Provider's Title + A description of the channels content. + http://www.providers-website.com + + + Train tickets to Anytown + Luxury train tickets + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 199 + 2005-12-20 + Vacation + Train + + USD + 250 + starting + Check + Visa + minimum payment on credit cards:45 + 204 + Mytown, USA + Anytown, USA + + 2005-12-20T18:00:00 + 2005-12-22T18:00:00 + + 123 Main St, Mytown, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + + + + Cruise Hawaii + 3 day Crusie, visit Hawaii + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 1869 + 2005-12-20 + Cruise + Hawaii + + USD + 1200 + starting + Visa + MasterCard + minimum payment on credit cards:45 + 210 + San Francisco, CA, USA + Hawaii, USA + + 2005-11-20T18:00:00 + 2005-11-26T12:00:00 + + 123 Main St., San Francisco, CA, 12345, USA + + US + Overnight + 32.95 + + California + 8.25 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/v/v1.xml b/rome-modules/src/test/resources/xml/v/v1.xml new file mode 100644 index 0000000..60c9f73 --- /dev/null +++ b/rome-modules/src/test/resources/xml/v/v1.xml @@ -0,0 +1,100 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + diff --git a/rome-modules/src/test/resources/xml/v/v2.xml b/rome-modules/src/test/resources/xml/v/v2.xml new file mode 100644 index 0000000..54cd864 --- /dev/null +++ b/rome-modules/src/test/resources/xml/v/v2.xml @@ -0,0 +1,128 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + Phish + All songs + + + + + + Moe + All songs + + + + + + Return to Forever + All songs + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/v/v3.xml b/rome-modules/src/test/resources/xml/v/v3.xml new file mode 100644 index 0000000..dbc2b87 --- /dev/null +++ b/rome-modules/src/test/resources/xml/v/v3.xml @@ -0,0 +1,132 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + Phish - Coventry Live (the last concert) + All songs + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/v/v4.xml b/rome-modules/src/test/resources/xml/v/v4.xml new file mode 100644 index 0000000..dc5a5d4 --- /dev/null +++ b/rome-modules/src/test/resources/xml/v/v4.xml @@ -0,0 +1,147 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + + + + + + + + + + Phish - Coventry Live (the last *good* concert) + All songs + + + + + Phish - Coventry Live (the last *simulcast* concert) + All songs + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/v/v5.xml b/rome-modules/src/test/resources/xml/v/v5.xml new file mode 100644 index 0000000..7d8553c --- /dev/null +++ b/rome-modules/src/test/resources/xml/v/v5.xml @@ -0,0 +1,151 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + + + + + + + + + + Phish - Coventry Live (the last *good* concert) + All songs + + + + + Phish - Coventry Live (the last *simulcast* concert) + All songs + + + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/v/v6.xml b/rome-modules/src/test/resources/xml/v/v6.xml new file mode 100644 index 0000000..069d59f --- /dev/null +++ b/rome-modules/src/test/resources/xml/v/v6.xml @@ -0,0 +1,153 @@ + + + + + playlist.xml + Sample playlist + http://www.somefakesite.com/index.html + + + + + Heart of Glass.mp3 + Blondie - Heart of Glass.mp3 + + + + + + Manic Monday.mp3 + Bangles - Manic Monday.mp3 + + + + + + Everybody Have Fun Tonight.mp3 + Wang Chung - Everybody Have Fun Tonight.mp3 + + + + + + She Blinded Me With Science.mp3 + Thomas Dolby - She Blinded Me With Science.mp3 + + + + + + Rivers of Babylon (HTC).mp3 + Jimmy Cliff - Rivers of Babylon (HTC).mp3 + + + + + + The Tide Is High.mp3 + Blondie - The Tide Is High.mp3 + + + + + + Back to the Island.mp3 + Leon Russell - Back to the Island.mp3 + + + + + + Lucky Man.mp3 + Emerson Lake & Palmer - Lucky Man.mp3 + + + + + + Up on Cripple Creek.mp3 + The Band - Up on Cripple Creek.mp3 + + + + + + Crackerbox Palace.mp3 + George Harrison - Crackerbox Palace.mp3 + + + + + + Taxi.Mp3 + Harry Chapin - Taxi.Mp3 + + + + + + Thick As A Brick.mp3 + Jethro Tull-Thick As A Brick.mp3 + + + + + + Riding With the King.mp3 + B. B. King & Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3 + + + + + + + + + + + + + + + + + + + Phish - Coventry Live (the last *simulcast* concert) + All songs + + + + + Phish - Coventry Live (the last *simulcast* concert) + All songs + + + + + + + + Moe + All songs + + + + + + + + Chick Corea and Return to Forever + All songs + + + + + + + + BrandX + All songs + + + diff --git a/rome-modules/src/test/resources/xml/vehicles-atom.xml b/rome-modules/src/test/resources/xml/vehicles-atom.xml new file mode 100644 index 0000000..06469d3 --- /dev/null +++ b/rome-modules/src/test/resources/xml/vehicles-atom.xml @@ -0,0 +1,95 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Mini Cooper S + 2006 Mini Cooper S + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + car + mini + + USD + 24000 + starting + Check + Visa + MasterCard + financing available + car + Mini + Cooper S + 2006 + 0 + new + red + 1M8GDM9AXKP042788 + 123 Main Street, Anytown, CA, 12345, USA + + US + Standard + 1000 + + California + 8.25 + + + + + + Acme Bio Truck + Acme Bio Fuel Truck + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Truck + Bio + + USD + 32000 + starting + Check + Visa + MasterCard + financing available + truck + Acme + Bio + 1999 + 20000 + used + black + 1M8GDM9AXKP034788 + 123 Main Street, Anytown, CA, 12345, USA + + US + Standard + 1000 + + California + 8.25 + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/vehicles2.xml b/rome-modules/src/test/resources/xml/vehicles2.xml new file mode 100644 index 0000000..34eb180 --- /dev/null +++ b/rome-modules/src/test/resources/xml/vehicles2.xml @@ -0,0 +1,87 @@ + + + + + + + The name of the channel + A description of the channels content. + http://www.providers-website.com + + + + Mini Cooper S + 2006 Mini Cooper S + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 39 + 2005-12-20 + car + mini + + USD + 24000 + starting + Check + Visa + MasterCard + financing available + car + Mini + Cooper S + 2006 + 0 + new + red + 1M8GDM9AXKP042788 + 123 Main Street, Anytown, CA, 12345, USA + + US + Standard + 1000 + + California + 8.25 + + + + + + Acme Bio Truck + Acme Bio Fuel Truck + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 39 + 2005-12-20 + Truck + Bio + + USD + 32000 + starting + Check + Visa + MasterCard + financing available + truck + Acme + Bio + 1999 + 20000 + used + black + 1M8GDM9AXKP034788 + 123 Main Street, Anytown, CA, 12345, USA + + US + Standard + 1000 + + California + 8.25 + + + + \ No newline at end of file diff --git a/rome-modules/src/test/resources/xml/wanted-atom.xml b/rome-modules/src/test/resources/xml/wanted-atom.xml new file mode 100644 index 0000000..4e7e80b --- /dev/null +++ b/rome-modules/src/test/resources/xml/wanted-atom.xml @@ -0,0 +1,51 @@ + + + + +The name of your feed + + +2003-12-13T18:30:02Z + + + The name of the author + + + + + Wanted: Used Acme Bio Truck + Wanted a used Acme Bio Truct + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image1.jpg + 2005-12-20 + Wanted + Truck + + 123 Main Street, Anytown, CA, 12345, USA + + + + + Wanted: Acme 2000 Camera + Wanted new or used Acme 2000 camera + + tag:providers-website-item1.com,2003:3.2397 + 2003-12-13T08:29:29-04:00 + 2003-12-13T18:30:02Z + http://www.providers-website.com/image2.jpg + 2005-12-20 + Camera + Acme + + 123 Main Street, Anytown, CA, 12345, USA + + + + diff --git a/rome-modules/src/test/resources/xml/wanted2.xml b/rome-modules/src/test/resources/xml/wanted2.xml new file mode 100644 index 0000000..34876f4 --- /dev/null +++ b/rome-modules/src/test/resources/xml/wanted2.xml @@ -0,0 +1,41 @@ + + + + + + + The name of the channel + A description of the channels content. + http://provider-website.com/ + + + Wanted: Used Acme Bio Truck + Wanted a used Acme Bio Truct + http://provider-website.com/item1-info-page.html + http://www.providers-website.com/image1.jpg + 69 + 2005-12-20 + Wanted + Truck + + 123 Main Street, Anytown, CA, 12345, USA + + + + + Wanted: Acme 2000 Camera + Wanted new or used Acme 2000 camera + http://provider-website.com/item2-info-page.html + http://www.providers-website.com/image2.jpg + 19 + 2005-12-20 + Camera + Acme + + 123 Main Street, Anytown, CA, 12345, USA + + + + diff --git a/rome-modules/src/test/resources/xml/yweather.xml b/rome-modules/src/test/resources/xml/yweather.xml new file mode 100644 index 0000000..c1f55e8 --- /dev/null +++ b/rome-modules/src/test/resources/xml/yweather.xml @@ -0,0 +1,65 @@ + + + + + + Yahoo! Weather - Milano/Linate, IT + http://us.rd.yahoo.com/dailynews/rss/weather/Milano/Linate__IT/*http://weather.yahoo.com/forecast/ITXX0090_f.html + Yahoo! Weather for Milano/Linate, IT + en-us + Sun, 20 Apr 2014 8:19 pm CEST + 60 + + + + + + + Yahoo! Weather + 142 + 18 + http://weather.yahoo.com + http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif + + + Conditions for Milano/Linate, IT at 8:19 pm CEST + 45.43 + 9.28 + http://us.rd.yahoo.com/dailynews/rss/weather/Milano/Linate__IT/*http://weather.yahoo.com/forecast/ITXX0090_f.html + Sun, 20 Apr 2014 8:19 pm CEST + +
      +Current Conditions:
      +Mostly Cloudy, 59 F
      +
      Forecast:
      +Sun - Rain. High: 65 Low: 52
      +Mon - Light Rain. High: 61 Low: 50
      +Tue - PM Showers. High: 69 Low: 49
      +Wed - Sunny. High: 74 Low: 50
      +Thu - Mostly Sunny. High: 76 Low: 52
      +
      +Full Forecast at Yahoo! Weather

      +(provided by The Weather Channel)
      +]]>
      + + + + + + ITXX0090_2014_04_24_7_00_CEST +
      +
      +
      + + diff --git a/rome-opml/.gitignore b/rome-opml/.gitignore new file mode 100644 index 0000000..2e975ff --- /dev/null +++ b/rome-opml/.gitignore @@ -0,0 +1,4 @@ +/.classpath +/.project +/.settings +/target \ No newline at end of file diff --git a/rome-opml/README.md b/rome-opml/README.md new file mode 100644 index 0000000..65a6e36 --- /dev/null +++ b/rome-opml/README.md @@ -0,0 +1,6 @@ +rome +==== + +ROME is a set of RSS and Atom Utilities for Java. It makes it easy to work in Java with most syndication formats: RSS 0.90, RSS 0.91 Netscape, RSS 0.91 Userland, RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, RSS 2.0, Atom 0.3, Atom 1.0 + +More Information: http://rometools.github.io/rome-opml/ diff --git a/rome-opml/pom.xml b/rome-opml/pom.xml new file mode 100644 index 0000000..b8d6cc4 --- /dev/null +++ b/rome-opml/pom.xml @@ -0,0 +1,91 @@ + + + 4.0.0 + + + com.rometools + rome-parent + 1.6.0-SNAPSHOT + + + rome-opml + 1.6.0-SNAPSHOT + jar + + rome-opml + + Support for OPML 1 and OPML 2 in ROME + + http://rometools.github.io/rome-opml/ + + + scm:git:ssh://github.com/rometools/rome-opml.git + scm:git:ssh://git@github.com/rometools/rome-opml.git + https://github.com/rometools/rome-opml + + + + + kebernet + kebernet@gmail.com + Robert Cooper + + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + gh-pages + ${project.scm.developerConnection} + ${project.build.directory}/site + + + + + + + + com.rometools + rome + 1.6.0-SNAPSHOT + + + ch.qos.logback + logback-classic + test + + + junit + junit + test + + + org.hamcrest + hamcrest-library + + + xmlunit + xmlunit + 1.6 + test + + + + diff --git a/rome-opml/src/main/java/com/rometools/opml/feed/opml/Attribute.java b/rome-opml/src/main/java/com/rometools/opml/feed/opml/Attribute.java new file mode 100644 index 0000000..d89fb48 --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/feed/opml/Attribute.java @@ -0,0 +1,87 @@ +/* + * Attribute.java + * + * Created on April 24, 2006, 11:11 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.opml.feed.opml; + +import java.io.Serializable; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; + +/** + * This is a simple name-value pair attribute for outlines. + * + * @author Robert "kebernet" Cooper + */ +public class Attribute implements Cloneable, Serializable { + + private static final long serialVersionUID = 1L; + + private String name; + private String value; + + /** + * Creates a new instance of Attribute. + * + * @param name name of the attribute. + * @param value value of the attribute. + */ + public Attribute(final String name, final String value) { + if (name == null || value == null) { + throw new NullPointerException("Name and value are required."); + } + setName(name); + setValue(value); + } + + public void setName(final String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setValue(final String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public Object clone() { + return new Attribute(name, value); + } + + @Override + public boolean equals(final Object obj) { + return new EqualsBean(Attribute.class, this).beanEquals(obj); + } + + @Override + public int hashCode() { + return new EqualsBean(Attribute.class, this).beanHashCode(); + } + + @Override + public String toString() { + return new ToStringBean(Attribute.class, this).toString(); + } + +} diff --git a/rome-opml/src/main/java/com/rometools/opml/feed/opml/Opml.java b/rome-opml/src/main/java/com/rometools/opml/feed/opml/Opml.java new file mode 100644 index 0000000..29c654a --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/feed/opml/Opml.java @@ -0,0 +1,322 @@ +/* + * Opml.java + * + * Created on April 24, 2006, 11:00 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.opml.feed.opml; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.rometools.rome.feed.WireFeed; + +/** + * This class represents the root of an OPML 1/2 feed and contains the elements that may appear in the <head> tag + * of the feed. + * + * @author Robert "kebernet" Cooper + */ +public class Opml extends WireFeed { + + private static final long serialVersionUID = 1L; + + private Date created; + private Date modified; + private Integer verticalScrollState; + private Integer windowBottom; + private Integer windowLeft; + private Integer windowRight; + private Integer windowTop; + private List outlines; + private String docs; + private String ownerEmail; + private String ownerId; + private String ownerName; + private String title; + private int[] expansionState; + + /** + * is a date-time, indicating when the document was created. + * + * @param created date-time, indicating when the document was created. + */ + public void setCreated(final Date created) { + this.created = created; + } + + /** + * <dateCreated> is a date-time, indicating when the document was created. + * + * @return date-time, indicating when the document was created. + */ + public Date getCreated() { + return created; + } + + /** + * (OPML 2) <docs> is the http address of documentation for the format used in the OPML file. It's probably a + * pointer to this page for people who might stumble across the file on a + * web server 25 years from now and wonder what it is. + * + * @param docs http address of documentation for the format used + */ + public void setDocs(final String docs) { + this.docs = docs; + } + + /** + * (OPML 2) <docs> is the http address of documentation for the format used in the OPML file. It's probably a + * pointer to this page for people who might stumble across the file on a + * web server 25 years from now and wonder what it is. + * + * @return http address of documentation for the format used + */ + public String getDocs() { + return docs; + } + + /** + * <expansionState>is a comma-separated list of line numbers that are expanded. The line numbers in the list + * tell you which headlines to expand. The order is important. For each element in the list, X, starting at the + * first summit, navigate flatdown X times and expand. Repeat for each element in the list. + * + * @param expansionState int array containing expanded elements. + */ + public void setExpansionState(final int[] expansionState) { + this.expansionState = expansionState; + } + + /** + * <expansionState> is a comma-separated list of line numbers that are expanded. The line numbers in the list + * tell you which headlines to expand. The order is important. For each element in the list, X, starting at the + * first summit, navigate flatdown X times and expand. Repeat for each element in the list. + * + * @return int array containing expanded elements. + */ + public int[] getExpansionState() { + return expansionState; + } + + /** + * <dateModified> is a date-time, indicating when the document was last modified. + * + * @param modified date-time, indicating when the document was last modified. + */ + public void setModified(final Date modified) { + this.modified = modified; + } + + /** + * <dateModified> is a date-time, indicating when the document was last modified. + * + * @return date-time, indicating when the document was last modified. + */ + public Date getModified() { + return modified; + } + + /** + * Root level Outline object that should appear in the <body> + * + * @param outlines Root level Outline object that should appear in the <body> + */ + public void setOutlines(final List outlines) { + this.outlines = outlines; + } + + /** + * Root level Outline object that should appear in the <body> + * + * @return Root level Outline object that should appear in the <body> + */ + public List getOutlines() { + if (outlines == null) { + outlines = new ArrayList(); + } + + return outlines; + } + + /** + * <ownerEmail> is a string, the email address of the owner of the document. + * + * @param ownerEmail the email address of the owner of the document. + */ + public void setOwnerEmail(final String ownerEmail) { + this.ownerEmail = ownerEmail; + } + + /** + * <ownerEmail> is a string, the email address of the owner of the document. + * + * @return the email address of the owner of the document. + */ + public String getOwnerEmail() { + return ownerEmail; + } + + /** + * (OPML 2) <ownerId> is the http address of a web page that contains an HTML a form that + * allows a human reader to communicate with the author of the document via email or other means. + * + * @param ownerId http address of a web page that contains an HTML a form that allows a human + * reader to communicate with the author of the document via email or other means. + */ + public void setOwnerId(final String ownerId) { + this.ownerId = ownerId; + } + + /** + * (OPML 2) <ownerId> is the http address of a web page that contains an HTML a form that + * allows a human reader to communicate with the author of the document via email or other means. + * + * @return http address of a web page that contains an HTML a form that allows a human reader to + * communicate with the author of the document via email or other means. + */ + public String getOwnerId() { + return ownerId; + } + + /** + * <ownerName> is a string, the owner of the document. + * + * @param ownerName the owner of the document. + */ + public void setOwnerName(final String ownerName) { + this.ownerName = ownerName; + } + + /** + * <ownerName> is a string, the owner of the document. + * + * @return the owner of the document. + */ + public String getOwnerName() { + return ownerName; + } + + /** + * <title> is the title of the document. + * + * @param title title of the document. + */ + public void setTitle(final String title) { + this.title = title; + } + + /** + * <title> is the title of the document. + * + * @return title of the document. + */ + public String getTitle() { + return title; + } + + /** + * <vertScrollState> is a number, saying which line of the outline is displayed on the top line of the window. + * This number is calculated with the expansion state already applied. + * + * @param verticalScrollState which line of the outline is displayed on the top line of the window. + */ + public void setVerticalScrollState(final Integer verticalScrollState) { + this.verticalScrollState = verticalScrollState; + } + + /** + * <vertScrollState> is a number, saying which line of the outline is displayed on the top line of the window. + * This number is calculated with the expansion state already applied. + * + * @return which line of the outline is displayed on the top line of the window. This number is calculated with the + * expansion state already applied. + */ + public Integer getVerticalScrollState() { + return verticalScrollState; + } + + /** + * <windowBottom> is a number, the pixel location of the bottom edge of the window. + * + * @param windowBottom the pixel location of the bottom edge of the window. + */ + public void setWindowBottom(final Integer windowBottom) { + this.windowBottom = windowBottom; + } + + /** + * <windowBottom> is a number, the pixel location of the bottom edge of the window. + * + * @return the pixel location of the bottom edge of the window. + */ + public Integer getWindowBottom() { + return windowBottom; + } + + /** + * <windowLeft> is a number, the pixel location of the left edge of the window. + * + * @param windowLeft the pixel location of the left edge of the window. + */ + public void setWindowLeft(final Integer windowLeft) { + this.windowLeft = windowLeft; + } + + /** + * <windowLeft> is a number, the pixel location of the left edge of the window. + * + * @return the pixel location of the left edge of the window. + */ + public Integer getWindowLeft() { + return windowLeft; + } + + /** + * <windowRight> is a number, the pixel location of the right edge of the window. + * + * @param windowRight the pixel location of the right edge of the window. + */ + public void setWindowRight(final Integer windowRight) { + this.windowRight = windowRight; + } + + /** + * <windowRight> is a number, the pixel location of the right edge of the window. + * + * @return the pixel location of the right edge of the window. + */ + public Integer getWindowRight() { + return windowRight; + } + + /** + * <windowTop> is a number, the pixel location of the top edge of the window. + * + * @param windowTop the pixel location of the top edge of the window. + */ + public void setWindowTop(final Integer windowTop) { + this.windowTop = windowTop; + } + + /** + * <windowTop> is a number, the pixel location of the top edge of the window. + * + * @return the pixel location of the top edge of the window. + */ + public Integer getWindowTop() { + return windowTop; + } + +} diff --git a/rome-opml/src/main/java/com/rometools/opml/feed/opml/Outline.java b/rome-opml/src/main/java/com/rometools/opml/feed/opml/Outline.java new file mode 100644 index 0000000..2e0309e --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/feed/opml/Outline.java @@ -0,0 +1,367 @@ +/* + * Outline.java + * + * Created on April 24, 2006, 11:04 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.opml.feed.opml; + +import java.io.Serializable; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import com.rometools.rome.feed.impl.EqualsBean; +import com.rometools.rome.feed.impl.ToStringBean; +import com.rometools.rome.feed.module.Module; + +/** + * This class represents an OPML outline element. + * + * @author Robert "kebernet" Cooper + */ +public class Outline implements Cloneable, Serializable { + + private static final long serialVersionUID = 1L; + + private Date created; + private List attributes; + private List categories; + private List children; + private List modules; + private String text; + private String title; + private String type; + private boolean breakpoint; + private boolean comment; + + public Outline() { + } + + /** + * Creates a new outline with the specified type and text values. + * + * @param type type attribute value/ + * @param text text attribute value + */ + public Outline(final String type, final String text) { + setType(type); + setText(text); + } + + /** + * Creates an outline with the given title, xmlUrl and htmlUrl. This is traditionally used for aggregator feed lists + * and will get a type of "rss". + * + * @param title Title of the entry. + * @param xmlUrl link to XML file. + * @param htmlUrl link to html page. + */ + public Outline(final String title, final URL xmlUrl, final URL htmlUrl) { + super(); + setType("rss"); + setTitle(title); + setAttributes(new ArrayList()); + + if (xmlUrl != null) { + getAttributes().add(new Attribute("xmlUrl", xmlUrl.toString())); + } + + if (htmlUrl != null) { + getAttributes().add(new Attribute("htmlUrl", htmlUrl.toString())); + } + } + + /** + * List of attributes on this outline excluding the "common types" for the specification. + * + * @param attributes List of attributes on this outline. + */ + public void setAttributes(final List attributes) { + this.attributes = attributes; + } + + /** + * List of attributes on this outline excluding the "common types" for the specification. + * + * @return List of attributes on this outline. + */ + public List getAttributes() { + if (attributes == null) { + attributes = new ArrayList(); + } + + return attributes; + } + + /** + * isBreakpoint is a string, either "true" or "false", indicating whether a breakpoint is set on this outline. This + * attribute is mainly necessary for outlines used to edit scripts. If it's not present, the value is false. + * + * @param breakpoint whether a breakpoint is set on this outline. + */ + public void setBreakpoint(final boolean breakpoint) { + this.breakpoint = breakpoint; + } + + /** + * isBreakpoint is a string, either "true" or "false", indicating whether a breakpoint is set on this outline. This + * attribute is mainly necessary for outlines used to edit scripts. If it's not present, the value is false. + * + * @return whether a breakpoint is set on this outline + */ + public boolean isBreakpoint() { + return breakpoint; + } + + /** + * (OPML 2) A List of Strings indicating values in the category attribute. + * + * @param categories (OPML 2) A List of Strings indicating values in the category attribute. + */ + public void setCategories(final List categories) { + this.categories = categories; + } + + /** + * (OPML 2) A List of Strings indicating values in the category attribute. + * + * @return (OPML 2) A List of Strings indicating values in the category attribute. + */ + public List getCategories() { + if (categories == null) { + categories = new ArrayList(); + } + + return categories; + } + + /** + * A list of sub-outlines for this entry. + * + * @param children A list of sub-outlines for this entry. + */ + public void setChildren(final List children) { + this.children = children; + } + + /** + * A list of sub-outlines for this entry. + * + * @return A list of sub-outlines for this entry. + */ + public List getChildren() { + if (children == null) { + children = new ArrayList(); + } + + return children; + } + + /** + * isComment is a string, either "true" or "false", indicating whether the outline is commented or not. By + * convention if an outline is commented, all subordinate outlines are considered to also be commented. If it's not + * present, the value is false. + * + * @param comment whether the outline is commented + */ + public void setComment(final boolean comment) { + this.comment = comment; + } + + /** + * isComment is a string, either "true" or "false", indicating whether the outline is commented or not. By + * convention if an outline is commented, all subordinate outlines are considered to also be commented. If it's not + * present, the value is false. + * + * @return whether the outline is commented + */ + public boolean isComment() { + return comment; + } + + /** + * (OPML 2) created is the date-time that the outline node was created. + * + * @param created date-time that the outline node was created. + */ + public void setCreated(final Date created) { + this.created = created; + } + + /** + * (OPML 2) created is the date-time that the outline node was created. + * + * @return date-time that the outline node was created. + */ + public Date getCreated() { + return created; + } + + /** + * A convenience method to return the value of the url attribute. + * + * @return value of the htmlUrl attribute. + */ + public String getUrl() { + return getAttributeValue("url"); + } + + /** + * A convenience method to return the value of the htmlUrl attribute. + * + * @return value of the htmlUrl attribute. + */ + public String getHtmlUrl() { + return getAttributeValue("htmlUrl"); + } + + public void setModules(final List modules) { + this.modules = modules; + } + + public List getModules() { + if (modules == null) { + modules = new ArrayList(); + } + + return modules; + } + + /** + * The "text" attribute of the outline. + * + * @param text The "text" attribute of the outline. + */ + public void setText(final String text) { + this.text = text; + } + + /** + * The "text" attribute of the outline. + * + * @return The "text" attribute of the outline. + */ + public String getText() { + return text; + } + + /** + * The "title" attribute of the outline. + * + * @param title The "title" attribute of the outline. + */ + public void setTitle(final String title) { + this.title = title; + } + + /** + * The "title" attribute of the outline. + * + * @return The "title" attribute of the outline. + */ + public String getTitle() { + return title; + } + + /** + * The "type" attribute of the outline. + * + * @param type The "type" attribute of the outline. + */ + public void setType(final String type) { + this.type = type; + } + + /** + * The "type" attribute of the outline. + * + * @return The "type" attribute of the outline. + */ + public String getType() { + return type; + } + + /** + * A convenience method to return the value of the xmlUrl attribute. + * + * @return value of the xmlUrl attribute. + */ + public String getXmlUrl() { + return getAttributeValue("xmlUrl"); + } + + /** + * Returns the value of an attribute on the outline or null. + * + * @param name name of the attribute. + */ + public String getAttributeValue(final String name) { + final List attributes = Collections.synchronizedList(getAttributes()); + for (int i = 0; i < attributes.size(); i++) { + final Attribute a = attributes.get(i); + + if (a.getName() != null && a.getName().equals(name)) { + return a.getValue(); + } + } + return null; + } + + @Override + public Object clone() { + + final Outline o = new Outline(); + o.setBreakpoint(isBreakpoint()); + o.setCategories(new ArrayList(getCategories())); + o.setComment(isComment()); + o.setCreated(created != null ? (Date) created.clone() : null); + o.setModules(new ArrayList(getModules())); + o.setText(getText()); + o.setTitle(getTitle()); + o.setType(getType()); + + final ArrayList children = new ArrayList(); + for (int i = 0; i < getChildren().size(); i++) { + children.add((Outline) this.children.get(i).clone()); + } + o.setChildren(children); + + final ArrayList attributes = new ArrayList(); + for (int i = 0; i < getAttributes().size(); i++) { + attributes.add((Attribute) this.attributes.get(i).clone()); + } + o.setAttributes(attributes); + + return o; + } + + @Override + public boolean equals(final Object obj) { + return new EqualsBean(Outline.class, this).beanEquals(obj); + } + + @Override + public int hashCode() { + return new EqualsBean(Outline.class, this).beanHashCode(); + } + + @Override + public String toString() { + return new ToStringBean(Outline.class, this).toString(); + } + +} diff --git a/rome-opml/src/main/java/com/rometools/opml/feed/opml/package.html b/rome-opml/src/main/java/com/rometools/opml/feed/opml/package.html new file mode 100644 index 0000000..3e0dfed --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/feed/opml/package.html @@ -0,0 +1,47 @@ + + + + + + + + This package represents the base objects for OPML support for ROME. +

      + There are three classes here that are relevant. Opml, + which represents the root document and head information, + Outline which represents a single node on an Opml + outline tree, and provides convenience methods for commonly used + attributes such as xmlUrl. Finally, the + Attribute class, which represents a specific attribute + on an Outline object. Since OPML supports free-form attribute + assignments, this is a very multi-purpose class. +

      +

      Sample Usage: + To use this parser, simply include the jar file in your classpath + as you are using ROME. Be sure it exists at the same level as ROME, + such that, if ROME is in the common classpath of an application server, + don't include this jar in your webapps WEB-INF/lib. +

      +  WireFeedInput input = new WireFeedInput();
      +  Opml feed = (Opml) input.build( new File("myOpml.xml") );
      +  List<Outline> outlines = (List<Outline>) feed.getOutlines();
      +        
      +

      + + +
      + *
      + * 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/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/ConverterForOPML10.java b/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/ConverterForOPML10.java new file mode 100644 index 0000000..2240842 --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/ConverterForOPML10.java @@ -0,0 +1,349 @@ +/* + * ConverterForOPML10.java + * + * Created on April 25, 2006, 1:26 AM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.opml.feed.synd.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Stack; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.opml.feed.opml.Attribute; +import com.rometools.opml.feed.opml.Opml; +import com.rometools.opml.feed.opml.Outline; +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.feed.synd.Converter; +import com.rometools.rome.feed.synd.SyndCategory; +import com.rometools.rome.feed.synd.SyndCategoryImpl; +import com.rometools.rome.feed.synd.SyndContent; +import com.rometools.rome.feed.synd.SyndContentImpl; +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndEntryImpl; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndLink; +import com.rometools.rome.feed.synd.SyndLinkImpl; +import com.rometools.rome.feed.synd.SyndPerson; +import com.rometools.rome.feed.synd.SyndPersonImpl; + +/** + * @author cooper + */ +public class ConverterForOPML10 implements Converter { + + private static final Logger LOG = LoggerFactory.getLogger(ConverterForOPML10.class); + + public static final String URI_TREE = "urn:rome.tree"; + public static final String URI_ATTRIBUTE = "urn:rome.attribute#"; + + protected void addOwner(final Opml opml, final SyndFeed syndFeed) { + if (opml.getOwnerEmail() != null || opml.getOwnerName() != null) { + final List authors = new ArrayList(); + final SyndPerson person = new SyndPersonImpl(); + person.setEmail(opml.getOwnerEmail()); + person.setName(opml.getOwnerName()); + authors.add(person); + syndFeed.setAuthors(authors); + } + } + + /** + * Makes a deep copy/conversion of the values of a real feed into a SyndFeedImpl. + *

      + * 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. + */ + @Override + public void copyInto(final WireFeed feed, final SyndFeed syndFeed) { + final Opml opml = (Opml) feed; + syndFeed.setTitle(opml.getTitle()); + addOwner(opml, syndFeed); + syndFeed.setPublishedDate(opml.getModified() != null ? opml.getModified() : opml.getCreated()); + syndFeed.setFeedType(opml.getFeedType()); + syndFeed.setModules(opml.getModules()); + syndFeed.setFeedType(getType()); + + createEntries(new Stack(), syndFeed.getEntries(), opml.getOutlines()); + } + + protected void createEntries(final Stack context, final List allEntries, final List outlines) { + final List so = Collections.synchronizedList(outlines); + + for (int i = 0; i < so.size(); i++) { + createEntry(context, allEntries, so.get(i)); + } + } + + protected SyndEntry createEntry(final Stack context, final List allEntries, final Outline outline) { + final SyndEntry entry = new SyndEntryImpl(); + + if (outline.getType() != null && outline.getType().equals("rss")) { + entry.setLink(outline.getHtmlUrl() != null ? outline.getHtmlUrl() : outline.getXmlUrl()); + } else if (outline.getType() != null && outline.getType().equals("link")) { + entry.setLink(outline.getUrl()); + } + + if (outline.getHtmlUrl() != null) { + final SyndLink link = new SyndLinkImpl(); + link.setRel("alternate"); + link.setType("text/html"); + link.setHref(outline.getHtmlUrl()); + entry.getLinks().add(link); + entry.setLink(outline.getHtmlUrl()); + } + + if (outline.getXmlUrl() != null && outline.getType() != null && outline.getType().equalsIgnoreCase("rss")) { + final SyndLink link = new SyndLinkImpl(); + link.setRel("alternate"); + link.setType("application/rss+xml"); + link.setHref(outline.getXmlUrl()); + entry.getLinks().add(link); + + if (entry.getLink() == null) { + entry.setLink(outline.getXmlUrl()); + } + } + + if (outline.getXmlUrl() != null && outline.getType() != null && outline.getType().equalsIgnoreCase("atom")) { + final SyndLink link = new SyndLinkImpl(); + link.setRel("alternate"); + link.setType("application/atom+xml"); + link.setHref(outline.getXmlUrl()); + entry.getLinks().add(link); + + if (entry.getLink() == null) { + entry.setLink(outline.getXmlUrl()); + } + } + + if (outline.getType() != null && outline.getType().equals("rss")) { + entry.setTitle(outline.getTitle()); + } else { + entry.setTitle(outline.getText()); + } + + if (outline.getText() == null && entry.getTitle() != null) { + final SyndContent c = new SyndContentImpl(); + c.setValue(outline.getText()); + entry.setDescription(c); + } + + entry.setPublishedDate(outline.getCreated()); + + final String nodeName = "node." + outline.hashCode(); + + final SyndCategory cat = new TreeCategoryImpl(); + cat.setTaxonomyUri(URI_TREE); + cat.setName(nodeName); + entry.getCategories().add(cat); + + if (!context.isEmpty()) { + final Integer parent = context.peek(); + final SyndCategory pcat = new TreeCategoryImpl(); + pcat.setTaxonomyUri(URI_TREE); + pcat.setName("parent." + parent); + entry.getCategories().add(pcat); + } + + final List attributes = Collections.synchronizedList(outline.getAttributes()); + + for (int i = 0; i < attributes.size(); i++) { + final Attribute a = attributes.get(i); + final SyndCategory acat = new SyndCategoryImpl(); + acat.setName(a.getValue()); + acat.setTaxonomyUri(URI_ATTRIBUTE + a.getName()); + entry.getCategories().add(acat); + } + + entry.setModules(outline.getModules()); + allEntries.add(entry); + context.push(new Integer(outline.hashCode())); + createEntries(context, allEntries, outline.getChildren()); + context.pop(); + + return entry; + } + + /** + * Creates real feed with a deep copy/conversion of the values of a SyndFeedImpl. + *

      + * + * @param syndFeed SyndFeedImpl to copy/convert value from. + * @return a real feed with copied/converted values of the SyndFeedImpl. + */ + @Override + public WireFeed createRealFeed(final SyndFeed syndFeed) { + + final List entries = Collections.synchronizedList(syndFeed.getEntries()); + + final HashMap entriesByNode = new HashMap(); + + // this will hold entries that we can't parent the first time. + final ArrayList doAfterPass = new ArrayList(); + + // this holds root level outlines; + final ArrayList root = new ArrayList(); + + for (int i = 0; i < entries.size(); i++) { + final SyndEntry entry = entries.get(i); + final Outline o = new Outline(); + + final List cats = Collections.synchronizedList(entry.getCategories()); + boolean parentFound = false; + final StringBuffer category = new StringBuffer(); + + for (int j = 0; j < cats.size(); j++) { + final SyndCategory cat = cats.get(j); + + if (cat.getTaxonomyUri() != null && cat.getTaxonomyUri().equals(URI_TREE)) { + final String nodeVal = cat.getName().substring(cat.getName().lastIndexOf("."), cat.getName().length()); + + if (cat.getName().startsWith("node.")) { + entriesByNode.put(nodeVal, o); + } else if (cat.getName().startsWith("parent.")) { + parentFound = true; + + final Outline parent = entriesByNode.get(nodeVal); + + if (parent != null) { + parent.getChildren().add(o); + } else { + doAfterPass.add(new OutlineHolder(o, nodeVal)); + } + } + } else if (cat.getTaxonomyUri() != null && cat.getTaxonomyUri().startsWith(URI_ATTRIBUTE)) { + final String name = cat.getTaxonomyUri().substring(cat.getTaxonomyUri().indexOf("#") + 1, cat.getTaxonomyUri().length()); + o.getAttributes().add(new Attribute(name, cat.getName())); + } else { + if (category.length() > 0) { + category.append(", "); + } + + category.append(cat.getName()); + } + } + + if (!parentFound) { + root.add(o); + } + + if (category.length() > 0) { + o.getAttributes().add(new Attribute("category", category.toString())); + } + + final List links = Collections.synchronizedList(entry.getLinks()); + // final String entryLink = entry.getLink(); + + for (int j = 0; j < links.size(); j++) { + final SyndLink link = links.get(j); + + // if(link.getHref().equals(entryLink)) { + if (link.getType() != null && link.getRel() != null && link.getRel().equals("alternate") + && (link.getType().equals("application/rss+xml") || link.getType().equals("application/atom+xml"))) { + o.setType("rss"); + + if (o.getXmlUrl() == null) { + o.getAttributes().add(new Attribute("xmlUrl", link.getHref())); + } + } else if (link.getType() != null && link.getType().equals("text/html")) { + if (o.getHtmlUrl() == null) { + o.getAttributes().add(new Attribute("htmlUrl", link.getHref())); + } + } else { + o.setType(link.getType()); + } + + // } + } + + if (o.getType() == null || o.getType().equals("link")) { + o.setText(entry.getTitle()); + + } else { + o.setTitle(entry.getTitle()); + } + + if (o.getText() == null && entry.getDescription() != null) { + o.setText(entry.getDescription().getValue()); + } + } + + // Do back and parenting for things we missed. + for (int i = 0; i < doAfterPass.size(); i++) { + final OutlineHolder o = doAfterPass.get(i); + final Outline parent = entriesByNode.get(o.parent); + + if (parent == null) { + root.add(o.outline); + LOG.warn("Unable to find parent node: {}", o.parent); + } else { + parent.getChildren().add(o.outline); + } + } + + final Opml opml = new Opml(); + opml.setFeedType(getType()); + opml.setCreated(syndFeed.getPublishedDate()); + opml.setTitle(syndFeed.getTitle()); + + final List authors = Collections.synchronizedList(syndFeed.getAuthors()); + + for (int i = 0; i < authors.size(); i++) { + final SyndPerson p = authors.get(i); + + if (syndFeed.getAuthor() == null || syndFeed.getAuthor().equals(p.getName())) { + opml.setOwnerName(p.getName()); + opml.setOwnerEmail(p.getEmail()); + opml.setOwnerId(p.getUri()); + } + } + + opml.setOutlines(root); + + return opml; + } + + /** + * Returns the type (version) of the real feed this converter handles. + * + * @return the real feed type. + * @see WireFeed for details on the format of this string. + */ + @Override + public String getType() { + return "opml_1.0"; + } + + private static class OutlineHolder { + + private final Outline outline; + private final String parent; + + public OutlineHolder(final Outline outline, final String parent) { + this.outline = outline; + this.parent = parent; + } + + } + +} diff --git a/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/ConverterForOPML20.java b/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/ConverterForOPML20.java new file mode 100644 index 0000000..305a0e0 --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/ConverterForOPML20.java @@ -0,0 +1,50 @@ +package com.rometools.opml.feed.synd.impl; + +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.feed.synd.SyndFeed; + +/** + * @author cooper + */ +public class ConverterForOPML20 extends ConverterForOPML10 { + + /** + * Returns the type (version) of the real feed this converter handles. + *

      + * + * @return the real feed type. + * @see WireFeed for details on the format of this string. + *

      + */ + @Override + public String getType() { + return "opml_2.0"; + } + + /** + * 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. + */ + @Override + public void copyInto(final WireFeed feed, final SyndFeed syndFeed) { + super.copyInto(feed, 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. + */ + @Override + public WireFeed createRealFeed(final SyndFeed syndFeed) { + return super.createRealFeed(syndFeed); + } + +} diff --git a/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/TreeCategoryImpl.java b/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/TreeCategoryImpl.java new file mode 100644 index 0000000..54e3b95 --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/TreeCategoryImpl.java @@ -0,0 +1,23 @@ +package com.rometools.opml.feed.synd.impl; + +import com.rometools.rome.feed.synd.SyndCategory; +import com.rometools.rome.feed.synd.SyndCategoryImpl; + +/** + * @author cooper + */ +public class TreeCategoryImpl extends SyndCategoryImpl { + + private static final long serialVersionUID = 1L; + + @Override + public boolean equals(final Object o) { + final SyndCategory c = (SyndCategory) o; + if (c.getTaxonomyUri() != null && c.getTaxonomyUri().equals(getTaxonomyUri())) { + return true; + } else { + return false; + } + } + +} diff --git a/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/package.html b/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/package.html new file mode 100644 index 0000000..40f63ad --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/feed/synd/impl/package.html @@ -0,0 +1,30 @@ + + + + + + + + + This packages contains the SyndFeed converters for the + OPML module. For information on how Opml gets turned into + other feed types through the Synd structures, see the OPML + Subproject page on the ROME wiki. + +

      + *
      + * 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/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML10Generator.java b/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML10Generator.java new file mode 100644 index 0000000..8851312 --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML10Generator.java @@ -0,0 +1,186 @@ +/* + * Opml10Generator.java + * + * Created on April 24, 2006, 11:35 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.opml.io.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Document; +import org.jdom2.Element; + +import com.rometools.opml.feed.opml.Attribute; +import com.rometools.opml.feed.opml.Opml; +import com.rometools.opml.feed.opml.Outline; +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.WireFeedGenerator; +import com.rometools.rome.io.impl.BaseWireFeedGenerator; +import com.rometools.rome.io.impl.DateParser; + +/** + * @author Robert "kebernet" Cooper + */ +public class OPML10Generator extends BaseWireFeedGenerator implements WireFeedGenerator { + + public OPML10Generator() { + super("opml_1.0"); + } + + public OPML10Generator(final String type) { + super(type); + } + + /** + * 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. + */ + @Override + public Document generate(final WireFeed feed) throws IllegalArgumentException, FeedException { + + if (!(feed instanceof Opml)) { + throw new IllegalArgumentException("Not an OPML file"); + } + + final Opml opml = (Opml) feed; + final Document doc = new Document(); + final Element root = new Element("opml"); + root.setAttribute("version", "1.0"); + doc.addContent(root); + + final Element head = generateHead(opml); + + if (head != null) { + root.addContent(head); + } + + final Element body = new Element("body"); + root.addContent(body); + super.generateFeedModules(opml.getModules(), root); + body.addContent(generateOutlines(opml.getOutlines())); + + return doc; + } + + protected boolean addNotNullAttribute(final Element target, final String name, final Object value) { + if (target == null || name == null || value == null) { + return false; + } + target.setAttribute(name, value.toString()); + return true; + } + + protected boolean addNotNullSimpleElement(final Element target, final String name, final Object value) { + if (target == null || name == null || value == null) { + return false; + } + + final Element e = new Element(name); + e.addContent(value.toString()); + target.addContent(e); + + return true; + } + + protected Element generateHead(final Opml opml) { + final Element head = new Element("head"); + boolean hasHead = false; + + if (opml.getCreated() != null) { + hasHead |= addNotNullSimpleElement(head, "dateCreated", DateParser.formatRFC822(opml.getCreated(), Locale.US)); + } + + hasHead |= addNotNullSimpleElement(head, "expansionState", intArrayToCsvString(opml.getExpansionState())); + + if (opml.getModified() != null) { + hasHead |= addNotNullSimpleElement(head, "dateModified", DateParser.formatRFC822(opml.getModified(), Locale.US)); + } + + hasHead |= addNotNullSimpleElement(head, "ownerEmail", opml.getOwnerEmail()); + hasHead |= addNotNullSimpleElement(head, "ownerName", opml.getOwnerName()); + hasHead |= addNotNullSimpleElement(head, "title", opml.getTitle()); + hasHead |= addNotNullSimpleElement(head, "vertScrollState", opml.getVerticalScrollState()); + hasHead |= addNotNullSimpleElement(head, "windowBottom", opml.getWindowBottom()); + hasHead |= addNotNullSimpleElement(head, "windowLeft", opml.getWindowLeft()); + hasHead |= addNotNullSimpleElement(head, "windowRight", opml.getWindowRight()); + hasHead |= addNotNullSimpleElement(head, "windowTop", opml.getWindowTop()); + + if (hasHead) { + return head; + } else { + return null; + } + } + + protected Element generateOutline(final Outline outline) { + final Element e = new Element("outline"); + addNotNullAttribute(e, "text", outline.getText()); + addNotNullAttribute(e, "type", outline.getType()); + addNotNullAttribute(e, "title", outline.getTitle()); + + if (outline.isBreakpoint()) { + addNotNullAttribute(e, "isBreakpoint", "true"); + } + + if (outline.isComment()) { + addNotNullAttribute(e, "isComment", "true"); + } + + final List atts = Collections.synchronizedList(outline.getAttributes()); + + for (int i = 0; i < atts.size(); i++) { + final Attribute att = atts.get(i); + addNotNullAttribute(e, att.getName(), att.getValue()); + } + + super.generateItemModules(outline.getModules(), e); + e.addContent(generateOutlines(outline.getChildren())); + + return e; + } + + protected List generateOutlines(final List outlines) { + final ArrayList elements = new ArrayList(); + for (int i = 0; outlines != null && i < outlines.size(); i++) { + elements.add(generateOutline(outlines.get(i))); + } + return elements; + } + + protected String intArrayToCsvString(final int[] value) { + if (value == null || value.length == 0) { + return null; + } + + final StringBuffer sb = new StringBuffer(); + sb.append(value[0]); + + for (int i = 1; i < value.length; i++) { + sb.append(","); + sb.append(value[i]); + } + + return sb.toString(); + } +} diff --git a/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML10Parser.java b/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML10Parser.java new file mode 100644 index 0000000..02b1bf5 --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML10Parser.java @@ -0,0 +1,260 @@ +/* + * Opml10Parser.java + * + * Created on April 24, 2006, 11:34 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.opml.io.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.StringTokenizer; + +import org.jdom2.Document; +import org.jdom2.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.opml.feed.opml.Attribute; +import com.rometools.opml.feed.opml.Opml; +import com.rometools.opml.feed.opml.Outline; +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.WireFeedParser; +import com.rometools.rome.io.impl.BaseWireFeedParser; +import com.rometools.rome.io.impl.DateParser; + +/** + * @author Robert "kebernet" Cooper + */ +public class OPML10Parser extends BaseWireFeedParser implements WireFeedParser { + + private static Logger LOG = LoggerFactory.getLogger(OPML10Parser.class); + + public OPML10Parser() { + super("opml_1.0", null); + } + + public OPML10Parser(final String type) { + super(type, null); + } + + /** + * 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. + */ + @Override + public boolean isMyType(final Document document) { + final Element e = document.getRootElement(); + + if (e.getName().equals("opml") && (e.getChild("head") == null || e.getChild("head").getChild("docs") == null) + && (e.getAttributeValue("version") == null || e.getAttributeValue("version").equals("1.0"))) { + return true; + } + + return false; + } + + /** + * Parses an XML document (JDOM Document) into a feed bean. + *

      + * + * @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). + */ + @Override + public WireFeed parse(final Document document, final boolean validate, final Locale locale) throws IllegalArgumentException, FeedException { + final Opml opml = new Opml(); + opml.setFeedType("opml_1.0"); + + final Element root = document.getRootElement(); + final Element head = root.getChild("head"); + + if (head != null) { + opml.setTitle(head.getChildText("title")); + + if (head.getChildText("dateCreated") != null) { + opml.setCreated(DateParser.parseRFC822(head.getChildText("dateCreated"), Locale.US)); + } + + if (head.getChildText("dateModified") != null) { + opml.setModified(DateParser.parseRFC822(head.getChildText("dateModified"), Locale.US)); + } + + opml.setOwnerName(head.getChildTextTrim("ownerName")); + opml.setOwnerEmail(head.getChildTextTrim("ownerEmail")); + opml.setVerticalScrollState(readInteger(head.getChildText("vertScrollState"))); + + try { + opml.setWindowBottom(readInteger(head.getChildText("windowBottom"))); + } catch (final NumberFormatException nfe) { + LOG.warn("Unable to parse windowBottom", nfe); + if (validate) { + throw new FeedException("Unable to parse windowBottom", nfe); + } + } + + try { + opml.setWindowLeft(readInteger(head.getChildText("windowLeft"))); + } catch (final NumberFormatException nfe) { + LOG.warn("Unable to parse windowLeft", nfe); + if (validate) { + throw new FeedException("Unable to parse windowLeft", nfe); + } + } + + try { + opml.setWindowRight(readInteger(head.getChildText("windowRight"))); + } catch (final NumberFormatException nfe) { + LOG.warn("Unable to parse windowRight", nfe); + if (validate) { + throw new FeedException("Unable to parse windowRight", nfe); + } + } + + try { + opml.setWindowLeft(readInteger(head.getChildText("windowLeft"))); + } catch (final NumberFormatException nfe) { + LOG.warn("Unable to parse windowLeft", nfe); + if (validate) { + throw new FeedException("Unable to parse windowLeft", nfe); + } + } + + try { + opml.setWindowTop(readInteger(head.getChildText("windowTop"))); + } catch (final NumberFormatException nfe) { + LOG.warn("Unable to parse windowTop", nfe); + if (validate) { + throw new FeedException("Unable to parse windowTop", nfe); + } + } + + try { + opml.setExpansionState(readIntArray(head.getChildText("expansionState"))); + } catch (final NumberFormatException nfe) { + LOG.warn("Unable to parse expansionState", nfe); + if (validate) { + throw new FeedException("Unable to parse expansionState", nfe); + } + } + } + + opml.setOutlines(parseOutlines(root.getChild("body").getChildren("outline"), validate, locale)); + opml.setModules(parseFeedModules(root, locale)); + + return opml; + } + + protected Outline parseOutline(final Element e, final boolean validate, final Locale locale) throws FeedException { + if (!e.getName().equals("outline")) { + throw new RuntimeException("Not an outline element."); + } + + final Outline outline = new Outline(); + outline.setText(e.getAttributeValue("text")); + outline.setType(e.getAttributeValue("type")); + outline.setTitle(e.getAttributeValue("title")); + + final List jAttributes = e.getAttributes(); + final ArrayList attributes = new ArrayList(); + + for (int i = 0; i < jAttributes.size(); i++) { + final org.jdom2.Attribute a = jAttributes.get(i); + + if (!a.getName().equals("isBreakpoint") && !a.getName().equals("isComment") && !a.getName().equals("title") && !a.getName().equals("text") + && !a.getName().equals("type")) { + attributes.add(new Attribute(a.getName(), a.getValue())); + } + } + + outline.setAttributes(attributes); + + try { + outline.setBreakpoint(readBoolean(e.getAttributeValue("isBreakpoint"))); + } catch (final Exception ex) { + LOG.warn("Unable to parse isBreakpoint value", ex); + + if (validate) { + throw new FeedException("Unable to parse isBreakpoint value", ex); + } + } + + try { + outline.setComment(readBoolean(e.getAttributeValue("isComment"))); + } catch (final Exception ex) { + LOG.warn("Unable to parse isComment value", ex); + + if (validate) { + throw new FeedException("Unable to parse isComment value", ex); + } + } + + final List children = e.getChildren("outline"); + outline.setModules(parseItemModules(e, locale)); + outline.setChildren(parseOutlines(children, validate, locale)); + + return outline; + } + + protected List parseOutlines(final List elements, final boolean validate, final Locale locale) throws FeedException { + final ArrayList results = new ArrayList(); + for (int i = 0; i < elements.size(); i++) { + results.add(parseOutline(elements.get(i), validate, locale)); + } + return results; + } + + protected boolean readBoolean(final String value) { + if (value == null) { + return false; + } else { + return Boolean.getBoolean(value.trim()); + } + } + + protected int[] readIntArray(final String value) { + if (value == null) { + return null; + } else { + final StringTokenizer tok = new StringTokenizer(value, ","); + final int[] result = new int[tok.countTokens()]; + int count = 0; + + while (tok.hasMoreElements()) { + result[count] = Integer.parseInt(tok.nextToken().trim()); + count++; + } + + return result; + } + } + + protected Integer readInteger(final String value) { + if (value != null) { + return new Integer(value); + } else { + return null; + } + } +} diff --git a/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML20Generator.java b/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML20Generator.java new file mode 100644 index 0000000..96ff4ae --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML20Generator.java @@ -0,0 +1,106 @@ +package com.rometools.opml.io.impl; + +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +import org.jdom2.Document; +import org.jdom2.Element; + +import com.rometools.opml.feed.opml.Opml; +import com.rometools.opml.feed.opml.Outline; +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.impl.DateParser; + +/** + * Generator for OPML 2.0 documents. + * + * @see http://dev.opml.org/spec2.html + */ +public class OPML20Generator extends OPML10Generator { + + public OPML20Generator() { + } + + /** + * Returns the type of feed the generator creates. + * + * @return the type of feed the generator creates. + * @see WireFeed for details on the format of this string. + */ + @Override + public String getType() { + return "opml_2.0"; + } + + /** + * 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. + */ + @Override + public Document generate(final WireFeed feed) throws IllegalArgumentException, FeedException { + final Document document = super.generate(feed); + document.getRootElement().setAttribute("version", "2.0"); + return document; + } + + @Override + protected Element generateHead(final Opml opml) { + + final Element docsElement = new Element("docs"); + docsElement.setText(opml.getDocs()); + + final Element headElement = super.generateHead(opml); + headElement.addContent(docsElement); + return headElement; + + } + + @Override + protected Element generateOutline(final Outline outline) { + + final Element outlineElement = super.generateOutline(outline); + + if (outline.getCreated() != null) { + outlineElement.setAttribute("created", DateParser.formatRFC822(outline.getCreated(), Locale.US)); + } + + final List categories = outline.getCategories(); + final String categoryValue = generateCategoryValue(categories); + addNotNullAttribute(outlineElement, "category", categoryValue); + + return outlineElement; + + } + + private String generateCategoryValue(final Collection categories) { + + final StringBuilder builder = new StringBuilder(); + + boolean first = true; + for (final String category : categories) { + if (category != null && !category.trim().isEmpty()) { + if (first) { + first = false; + } else { + builder.append(","); + } + builder.append(category.trim()); + } + } + + if (builder.length() > 0) { + return builder.toString(); + } else { + return null; + } + + } + +} diff --git a/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML20Parser.java b/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML20Parser.java new file mode 100644 index 0000000..fa56857 --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/io/impl/OPML20Parser.java @@ -0,0 +1,120 @@ +/* + * Opml20Parser.java + * + * Created on April 25, 2006, 1:04 AM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rometools.opml.io.impl; + +import java.util.List; +import java.util.Locale; + +import org.jdom2.Document; +import org.jdom2.Element; + +import com.rometools.opml.feed.opml.Attribute; +import com.rometools.opml.feed.opml.Opml; +import com.rometools.opml.feed.opml.Outline; +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.impl.DateParser; + +/** + * + * @author cooper + */ +public class OPML20Parser extends OPML10Parser { + /** Creates a new instance of Opml20Parser */ + public OPML20Parser() { + super("opml_2.0"); + } + + /** + * Inspects an XML Document (JDOM) to check if it can parse it. + *

      + * 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. + */ + @Override + public boolean isMyType(final Document document) { + final Element e = document.getRootElement(); + + if (e.getName().equals("opml") + && (e.getChild("head") != null && e.getChild("head").getChild("docs") != null || e.getAttributeValue("version") != null + && e.getAttributeValue("version").equals("2.0") || e.getChild("head") != null && e.getChild("head").getChild("ownerId") != null)) { + return true; + } + + return false; + } + + /** + * Parses an XML document (JDOM Document) into a feed bean. + *

      + * + * @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). + */ + @Override + public WireFeed parse(final Document document, final boolean validate, final Locale locale) throws IllegalArgumentException, FeedException { + Opml opml; + opml = (Opml) super.parse(document, validate, locale); + + final Element head = document.getRootElement().getChild("head"); + + if (head != null) { + opml.setOwnerId(head.getChildTextTrim("ownerId")); + opml.setDocs(head.getChildTextTrim("docs")); + + if (opml.getDocs() == null) { + opml.setDocs("http://www.opml.org/spec2"); + } + } + + opml.setFeedType("opml_2.0"); + + return opml; + } + + @Override + protected Outline parseOutline(final Element e, final boolean validate, final Locale locale) throws FeedException { + Outline retValue; + + retValue = super.parseOutline(e, validate, locale); + + if (e.getAttributeValue("created") != null) { + retValue.setCreated(DateParser.parseRFC822(e.getAttributeValue("created"), locale)); + } + + final List atts = retValue.getAttributes(); + + for (int i = 0; i < atts.size(); i++) { + final Attribute a = atts.get(i); + + if (a.getName().equals("created")) { + retValue.getAttributes().remove(a); + + break; + } + } + + return retValue; + } +} diff --git a/rome-opml/src/main/java/com/rometools/opml/io/impl/package.html b/rome-opml/src/main/java/com/rometools/opml/io/impl/package.html new file mode 100644 index 0000000..64d1989 --- /dev/null +++ b/rome-opml/src/main/java/com/rometools/opml/io/impl/package.html @@ -0,0 +1,28 @@ + + + + + + + + + This package contains the feed parsers for OPML1 and OPML2. + + +

      + *
      + * 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/rome-opml/src/main/resources/rome.properties b/rome-opml/src/main/resources/rome.properties new file mode 100644 index 0000000..f57e9e3 --- /dev/null +++ b/rome-opml/src/main/resources/rome.properties @@ -0,0 +1,22 @@ +# 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. +# + + +WireFeedGenerator.classes=com.rometools.opml.io.impl.OPML10Generator \ + com.rometools.opml.io.impl.OPML20Generator + +WireFeedParser.classes=com.rometools.opml.io.impl.OPML10Parser \ + com.rometools.opml.io.impl.OPML20Parser + +Converter.classes=com.rometools.opml.feed.synd.impl.ConverterForOPML10 \ + com.rometools.opml.feed.synd.impl.ConverterForOPML20 diff --git a/rome-opml/src/site/apt/index.apt b/rome-opml/src/site/apt/index.apt new file mode 100644 index 0000000..0e7e427 --- /dev/null +++ b/rome-opml/src/site/apt/index.apt @@ -0,0 +1,125 @@ + ----- + Home + ----- + kwebble + ----- + 2011-09-23 14:15:28.442 + ----- + +ROME OPML + + This project provides support for {{{http://www.opml.org/}OPML}} in ROME. + +*Downloads + + * {{{./apidocs/index.html}JavaDocs}} + + [] + +*Sample Usage + + To use this parser, simply include the jar file in your classpath as you are using ROME. Be sure it exists at the same level as ROME, + such that, if ROME is in the common classpath of an application server, don't include this jar in your webapps WEB\-INF/lib. + ++------+ +WireFeedInput input = new WireFeedInput(); + Opml feed = (Opml) input.build( new File("myOpml.xml") ); + List outlines = (List) feed.getOutlines(); ++------+ + +*Hierarchy vs Flat + + Since OPML is a hierarchical format, some magic is required to preserve this information when they feed is moved to a Synd\* structure. + This is accomplished by adding categories indicating the tree structure to the {{{http://wiki.java.net/bin/edit/Javawsxml/SyndEntries?topicparent\=Javawsxml.OPML;nowysiwyg\=0}SyndEntries}} ... + + For example: + ++------+ + + + Top Ten Sources for podcasting + Newsilike Media Group + opml@TopTenSources.com + + + + + + + + + + + + + + + + + + + + ++------+ + + ...\ + When converted to RSS2 becomes: + ++------+ + + Top Ten Sources for podcasting + http://foo.com + + Newsilike Media Group + + TopTenSources: podcasting + http://podcasting.TopTenSources.com/TopTenSources/ + node.-1732517202 + http://podcasting.TopTenSources.com/TopTenSources/ + http://podcasting.TopTenSources.com/TopTenSources/ + + + CBS Technology News Podcast - Larry Magid' Tech Report + node.1353657827 + + + Larry Magid's Tech Report + http://www.cbsnews.com + node.-4085850 + parent.1353657827 + http://www.cbsnews.com + http://www.cbsnews.com + + + Adam Curry: Daily Source Code + node.835791399 + + + #374 Daily Source Code for Tuesday April 25th 2006 + http://radio.weblogs.com/0001014/2006/04/26.html#a7304 + node.222050897 + parent.835791399 + http://radio.weblogs.com/0001014/2006/04/26.html#a7304 + http://radio.weblogs.com/0001014/2006/04/26.html#a7304 + + + #373 Daily Source Code for Monday April 24th 2006 + http://radio.weblogs.com/0001014/2006/04/24.html#a7303 + node.2088220478 + parent.835791399 + http://radio.weblogs.com/0001014/2006/04/24.html#a7303 + http://radio.weblogs.com/0001014/2006/04/24.html#a7303 + ++------+ + + Nodes get categories with the "urn:rome.tree" URI that is used to maintain the tree structure. + + The other thing you will notice is the "urn:rome.attribute#url". Since OPML allows you to add arbitrary attributes to each outline element, these are used to preserve these values. + + \ No newline at end of file diff --git a/rome-opml/src/site/resources/.nojekyll b/rome-opml/src/site/resources/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/rome-opml/src/site/resources/css/site.css b/rome-opml/src/site/resources/css/site.css new file mode 100644 index 0000000..43c3cd8 --- /dev/null +++ b/rome-opml/src/site/resources/css/site.css @@ -0,0 +1,8 @@ +h1 { + padding: 4px 4px 4px 6px; + border: 1px solid #999; + color: #900; + background-color: #ddd; + font-weight:900; + font-size: x-large; +} \ No newline at end of file diff --git a/rome-opml/src/site/resources/images/romelogo.png b/rome-opml/src/site/resources/images/romelogo.png new file mode 100644 index 0000000..2c90608 Binary files /dev/null and b/rome-opml/src/site/resources/images/romelogo.png differ diff --git a/rome-opml/src/site/site.xml b/rome-opml/src/site/site.xml new file mode 100644 index 0000000..5b4d4a7 --- /dev/null +++ b/rome-opml/src/site/site.xml @@ -0,0 +1,30 @@ + + + + + org.apache.maven.skins + maven-fluido-skin + 1.3.0 + + + + ROME + images/romelogo.png + http://github.com/rometools/ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rome-opml/src/test/java/com/rometools/opml/FeedOpsTest.java b/rome-opml/src/test/java/com/rometools/opml/FeedOpsTest.java new file mode 100644 index 0000000..5eb5f61 --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/FeedOpsTest.java @@ -0,0 +1,146 @@ +package com.rometools.opml; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import org.custommonkey.xmlunit.Diff; +import org.custommonkey.xmlunit.ElementNameAndAttributeQualifier; +import org.custommonkey.xmlunit.XMLAssert; +import org.custommonkey.xmlunit.XMLUnit; +import org.jdom2.Document; +import org.jdom2.output.Format; +import org.jdom2.output.XMLOutputter; + +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndFeedImpl; +import com.rometools.rome.io.WireFeedOutput; + +/** + * + *

      + * + * @author Alejandro Abdelnur + * + */ +public abstract class FeedOpsTest extends FeedTest { + + protected FeedOpsTest(final String feedType) { + super(feedType + ".xml"); + new File("target/test-reports").mkdirs(); + } + + // 1.2a + public void testWireFeedEquals() throws Exception { + final WireFeed feed1 = getCachedWireFeed(); + final WireFeed feed2 = getWireFeed(); + assertTrue(feed1.equals(feed2)); + } + + // 1.2b + public void testWireFeedNotEqual() throws Exception { + final WireFeed feed1 = getCachedWireFeed(); + final WireFeed feed2 = getWireFeed(); + feed2.setFeedType("dummy"); + assertFalse(feed1.equals(feed2)); + } + + // 1.3 + public void testWireFeedCloning() throws Exception { + final WireFeed feed1 = getCachedWireFeed(); + final WireFeed feed2 = (WireFeed) feed1.clone(); + ; + assertTrue(feed1.equals(feed2)); + } + + // 1.4 + public void testWireFeedSerialization() throws Exception { + final WireFeed feed1 = getCachedWireFeed(); + + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(feed1); + oos.close(); + + final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + final ObjectInputStream ois = new ObjectInputStream(bais); + final WireFeed feed2 = (WireFeed) ois.readObject(); + ois.close(); + + assertTrue(feed1.equals(feed2)); + } + + // 1.5 + public void testWireFeedJDOMSerialization() throws Exception { + Document inputDoc = getCachedJDomDoc(); + + final WireFeed feed = getCachedWireFeed(); + WireFeedOutput output = new WireFeedOutput(); + Document outputDoc = output.outputJDom(feed); + + XMLOutputter outputter = new XMLOutputter(Format.getCompactFormat()); + String inputString = outputter.outputString(inputDoc); + String outputString = outputter.outputString(outputDoc); + + XMLUnit.setIgnoreWhitespace(true); + XMLUnit.setIgnoreAttributeOrder(true); + Diff diff = XMLUnit.compareXML(inputString, outputString); + // ignore elements order + diff.overrideElementQualifier(new ElementNameAndAttributeQualifier()); + + XMLAssert.assertXMLEqual(diff, true); + } + + // 1.6 + public void testWireFeedSyndFeedConversion() throws Exception { + final SyndFeed sFeed1 = getCachedSyndFeed(); + final WireFeed wFeed1 = sFeed1.createWireFeed(); + final SyndFeed sFeed2 = new SyndFeedImpl(wFeed1); + + assertEquals(sFeed1, sFeed2); + } + + // 1.7a + public void testSyndFeedEquals() throws Exception { + final SyndFeed feed1 = getCachedSyndFeed(); + final SyndFeed feed2 = getSyndFeed(); + assertTrue(feed1.equals(feed2)); + } + + // 1.7b + public void testSyndFeedNotEqual() throws Exception { + final SyndFeed feed1 = getCachedSyndFeed(); + final SyndFeed feed2 = getSyndFeed(); + feed2.setFeedType("dummy"); + assertFalse(feed1.equals(feed2)); + } + + // 1.8 + public void testSyndFeedCloning() throws Exception { + final SyndFeed feed1 = getCachedSyndFeed(); + final SyndFeed feed2 = (SyndFeed) feed1.clone(); + ; + assertTrue(feed1.equals(feed2)); + } + + // 1.9 + public void testSyndFeedSerialization() throws Exception { + final SyndFeed feed1 = getCachedSyndFeed(); + + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(feed1); + oos.close(); + + final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + final ObjectInputStream ois = new ObjectInputStream(bais); + final SyndFeed feed2 = (SyndFeed) ois.readObject(); + ois.close(); + + assertTrue(feed1.equals(feed2)); + } + +} diff --git a/rome-opml/src/test/java/com/rometools/opml/FeedTest.java b/rome-opml/src/test/java/com/rometools/opml/FeedTest.java new file mode 100644 index 0000000..a2919e9 --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/FeedTest.java @@ -0,0 +1,79 @@ +package com.rometools.opml; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +import junit.framework.TestCase; + +import org.jdom2.Document; +import org.jdom2.input.SAXBuilder; +import org.jdom2.input.sax.XMLReaders; + +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.WireFeedInput; + +/** + * @author pat, tucu + * + */ +public abstract class FeedTest extends TestCase { + + private final String fileName; + private Document jDomDoc = null; + private WireFeed wireFeed = null; + private SyndFeed syndFeed = null; + + protected FeedTest(final String feedFileName) { + fileName = feedFileName; + } + + protected String getFeedFileName() { + return fileName; + } + + protected Reader getFeedReader() throws Exception { + final InputStream resource = Thread.currentThread().getContextClassLoader().getResourceAsStream(getFeedFileName()); + assertNotNull("Could not find resource " + getFeedFileName(), resource); + return new InputStreamReader(resource); + } + + protected Document getJDomDoc() throws Exception { + final SAXBuilder saxBuilder = new SAXBuilder(XMLReaders.NONVALIDATING); + return saxBuilder.build(getFeedReader()); + } + + protected WireFeed getWireFeed() throws Exception { + final WireFeedInput in = new WireFeedInput(); + return in.build(getFeedReader()); + } + + protected SyndFeed getSyndFeed() throws Exception { + final SyndFeedInput in = new SyndFeedInput(); + return in.build(getFeedReader()); + } + + protected Document getCachedJDomDoc() throws Exception { + if (jDomDoc == null) { + jDomDoc = getJDomDoc(); + } + return jDomDoc; + } + + protected WireFeed getCachedWireFeed() throws Exception { + if (wireFeed == null) { + wireFeed = getWireFeed(); + } + return wireFeed; + } + + protected SyndFeed getCachedSyndFeed() throws Exception { + if (syndFeed == null) { + syndFeed = getSyndFeed(); + } + return syndFeed; + } + +} diff --git a/rome-opml/src/test/java/com/rometools/opml/SyndFeedTest.java b/rome-opml/src/test/java/com/rometools/opml/SyndFeedTest.java new file mode 100644 index 0000000..09bc640 --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/SyndFeedTest.java @@ -0,0 +1,136 @@ +package com.rometools.opml; + +/** + * @author pat + * + */ +public abstract class SyndFeedTest extends FeedTest { + private String _prefix = null; + + protected SyndFeedTest(final String feedType) { + this(feedType, feedType + ".xml"); + } + + protected SyndFeedTest(final String feedType, final String feedFileName) { + super(feedFileName); + _prefix = feedType; + } + + protected String getPrefix() { + return _prefix; + } + + protected void assertProperty(final String property, final String value) { + assertEquals(property, getPrefix() + "." + value); + } + + public void testType() throws Exception { + assertEquals(getCachedSyndFeed().getFeedType(), getPrefix()); + } + + /* + * public void testType() throws Exception { assertEquals(getPrefix(), + * getCachedSyndFeed().getFeedType()); } public void testTitle() throws Exception { + * assertEqualsStr("channel.title", getCachedSyndFeed().getTitle()); } public void testLink() + * throws Exception { assertEqualsStr("channel.link", getCachedSyndFeed().getLink()); } public + * void testDescription() throws Exception { assertEqualsStr("channel.description", + * getCachedSyndFeed().getDescription()); } public void testLanguage() throws Exception { + * assertEqualsStr("channel.language", getCachedSyndFeed().getLanguage()); } public void + * testCategories() throws Exception { List catlist = getCachedSyndFeed().getCategories(); + * //don't understand why this one fails assertEquals(2, catlist.size()); SyndCategory cat = + * (SyndCategory)catlist.get(0); assertEqualsStr("channel.category[0]", cat.getName()); + * assertEqualsStr("channel.category[0]^domain", cat.getTaxonomyUri()); cat = + * (SyndCategory)catlist.get(1); assertEqualsStr("channel.category[1]", cat.getName()); + * assertEqualsStr("channel.category[1]^domain", cat.getTaxonomyUri()); } public void + * testPublishedDate() throws Exception { + * assertEquals(DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"), + * getCachedSyndFeed().getPublishedDate()); } //how do i get height and width? public void + * testImage() throws Exception { SyndImage img = getCachedSyndFeed().getImage(); + * assertEqualsStr("channel.image.description", img.getDescription()); + * assertEqualsStr("channel.image.link", img.getLink()); assertEqualsStr("channel.image.title", + * img.getTitle()); assertEqualsStr("channel.image.url", img.getUrl()); } public void + * testEntries() throws Exception { List entrylist = getCachedSyndFeed().getEntries(); + * assertEquals(2, entrylist.size()); } public void testEntryTitle() throws Exception { + * assertEqualsStr("channel.item[0].title", + * getEntryTitle(getCachedSyndFeed().getEntries().get(0))); + * assertEqualsStr("channel.item[1].title", + * getEntryTitle(getCachedSyndFeed().getEntries().get(1))); } public String getEntryTitle(Object + * o) throws Exception { SyndEntry e = (SyndEntry) o; return e.getTitle(); } public void + * testEntryDescription() throws Exception { assertEqualsStr("channel.item[0].description", + * getEntryDescription(getCachedSyndFeed().getEntries().get(0))); + * assertEqualsStr("channel.item[1].description", + * getEntryDescription(getCachedSyndFeed().getEntries().get(1))); } public String + * getEntryDescription(Object o) throws Exception { SyndEntry e = (SyndEntry) o; return + * e.getDescription().getValue(); } public void testEntryLink() throws Exception { + * assertEqualsStr("channel.item[0].link", + * getEntryLink(getCachedSyndFeed().getEntries().get(0))); + * assertEqualsStr("channel.item[1].link", + * getEntryLink(getCachedSyndFeed().getEntries().get(1))); } public String getEntryLink(Object + * o) { SyndEntry e = (SyndEntry) o; return e.getLink(); } public void testEntryPublishedDate() + * throws Exception { assertEquals(DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"), + * getEntryPublishedDate(getCachedSyndFeed().getEntries().get(0))); + * assertEquals(DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"), + * getEntryPublishedDate(getCachedSyndFeed().getEntries().get(1))); } public Date + * getEntryPublishedDate(Object o) { SyndEntry e = (SyndEntry) o; return e.getPublishedDate(); } + * public void testEntryCategories() throws Exception { SyndEntry e = + * (SyndEntry)getCachedSyndFeed().getEntries().get(0); List catlist = e.getCategories(); //don't + * understand why this one fails assertEquals(2, catlist.size()); SyndCategory cat = + * (SyndCategory)catlist.get(0); assertEqualsStr("channel.item[0].category[0]", cat.getName()); + * assertEqualsStr("channel.item[0].category[0]^domain", cat.getTaxonomyUri()); cat = + * (SyndCategory)catlist.get(1); assertEqualsStr("channel.item[0].category[1]", cat.getName()); + * assertEqualsStr("channel.item[0].category[1]^domain", cat.getTaxonomyUri()); //DO 2nd set of + * items } public void testEntryAuthor() throws Exception { + * assertEqualsStr("channel.item[0].author", + * getEntryAuthor(getCachedSyndFeed().getEntries().get(0))); + * assertEqualsStr("channel.item[1].author", + * getEntryAuthor(getCachedSyndFeed().getEntries().get(1))); } public String + * getEntryAuthor(Object o) { SyndEntry e = (SyndEntry) o; return e.getAuthor(); } + */ + /* + * //things you cannot get from SyndEntryImpl // item[0].source // // + * + * item0.category0 item0.category1 Thu, 08 Jul 1999 08:00:00 + * GMT Thu, 08 Jul 1999 09:00:00 GMT + * item0.author http://localhost:8080/item0/comments http://localhost:8080/item0/guid //TODO: I still have the elements + * to test + */ + /* + * public void test() { assertEqualsStr(feed, ""); } public void test() { assertEqualsStr(feed, + * ""); } + */ + // Things that you cannot get form a SyndFeedImpl today + // these need to be put in a RSS 2.0 module + // or is a roundtrip to wirefeed the right way to do this? + /* + * Search Search this site: q + * http://example.org/mt/mt-search.cgi image height and width + * //Copyright 2004, Mark Pilgrim public void test() { + * assertEqualsStr(getCachedSyndFeed()., ""); } //Sample Toolkit public + * void test() { assertEqualsStr(feed, ""); } // + * editor@example.org public void test() { + * assertEqualsStr(feed, ""); } // webmaster@example.org public void + * test() { assertEqualsStr(feed, ""); } http://blogs.law.harvard.edu/tech/rss + * 60 0 1 + * 2 3 4 5 6 7 + * 8 9.5 10 11 12 + * 13 14 15 16 17 + * 18 19 20 21 22 + * 23 Monday Tuesday + * Wednesday Thursday Friday Saturday + * Sunday + */ + + /* + * @see TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + +} \ No newline at end of file diff --git a/rome-opml/src/test/java/com/rometools/opml/TestOpsOPML10.java b/rome-opml/src/test/java/com/rometools/opml/TestOpsOPML10.java new file mode 100644 index 0000000..7f78a80 --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/TestOpsOPML10.java @@ -0,0 +1,46 @@ +/* + * TestOpsOPML10.java + * + * Created on April 25, 2006, 4:26 PM + * + * To change this template, choose Tools | Template Manager + * and open the template in the editor. + */ + +package com.rometools.opml; + +import java.io.FileOutputStream; +import java.io.PrintWriter; + +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndFeedImpl; + +/** + * + * @author cooper + */ +public class TestOpsOPML10 extends FeedOpsTest { + + /** Creates a new instance of TestOpsOPML10 */ + public TestOpsOPML10() { + super("opml_1.0"); + } + + // 1.6 + @Override + public void testWireFeedSyndFeedConversion() throws Exception { + final SyndFeed sFeed1 = getCachedSyndFeed(); + final WireFeed wFeed1 = sFeed1.createWireFeed(); + final SyndFeed sFeed2 = new SyndFeedImpl(wFeed1); + PrintWriter w = new PrintWriter(new FileOutputStream("target/test-reports/1")); + w.println(sFeed1.toString()); + w.close(); + w = new PrintWriter(new FileOutputStream("target/test-reports/2")); + w.println(sFeed2.toString()); + w.close(); + + assertEquals(sFeed1, sFeed2); + } + +} diff --git a/rome-opml/src/test/java/com/rometools/opml/TestOpsOPML10links.java b/rome-opml/src/test/java/com/rometools/opml/TestOpsOPML10links.java new file mode 100644 index 0000000..33c6216 --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/TestOpsOPML10links.java @@ -0,0 +1,63 @@ +/* + * TestOpsOPML10.java + * + * Created on April 25, 2006, 4:26 PM + * + * To change this template, choose Tools | Template Manager + * and open the template in the editor. + */ + +package com.rometools.opml; + +import java.io.FileOutputStream; +import java.io.PrintWriter; + +import com.rometools.opml.test.NullWriter; +import com.rometools.opml.test.TestUtil; +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndFeedImpl; +import com.rometools.rome.io.WireFeedInput; +import com.rometools.rome.io.WireFeedOutput; + +/** + * + * @author cooper + */ +public class TestOpsOPML10links extends FeedOpsTest { + + /** Creates a new instance of TestOpsOPML10 */ + public TestOpsOPML10links() { + super("opml_1.0_links"); + } + + // 1.6 + @Override + public void testWireFeedSyndFeedConversion() throws Exception { + final SyndFeed sFeed1 = getCachedSyndFeed(); + final WireFeed wFeed1 = sFeed1.createWireFeed(); + final SyndFeed sFeed2 = new SyndFeedImpl(wFeed1); + PrintWriter w = new PrintWriter(new FileOutputStream("target/test-reports/1")); + w.println(sFeed1.toString()); + w.close(); + w = new PrintWriter(new FileOutputStream("target/test-reports/2")); + w.println(sFeed2.toString()); + w.close(); + + assertEquals(sFeed2.createWireFeed(), sFeed1.createWireFeed()); + } + + public void testTemp() throws Exception { + final WireFeedInput input = new WireFeedInput(); + final WireFeed wf = input.build(TestUtil.loadFile("/opml_1.0_links.xml")); + final WireFeedOutput output = new WireFeedOutput(); + + final SyndFeedImpl sf = new SyndFeedImpl(wf); + sf.setFeedType("rss_2.0"); + sf.setDescription(""); + sf.setLink("http://foo.com"); + sf.setFeedType("opml_1.0"); + output.output(sf.createWireFeed(), new NullWriter()); + } + +} diff --git a/rome-opml/src/test/java/com/rometools/opml/TestOpsOPML20.java b/rome-opml/src/test/java/com/rometools/opml/TestOpsOPML20.java new file mode 100644 index 0000000..32f8348 --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/TestOpsOPML20.java @@ -0,0 +1,44 @@ +/* + * TestOpsOPML20.java + * + * Created on April 25, 2006, 5:38 PM + * + * To change this template, choose Tools | Template Manager + * and open the template in the editor. + */ + +package com.rometools.opml; + +import java.io.FileOutputStream; +import java.io.PrintWriter; + +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.feed.synd.SyndFeedImpl; + +/** + * + * @author cooper + */ +public class TestOpsOPML20 extends FeedOpsTest { + + /** Creates a new instance of TestOpsOPML20 */ + public TestOpsOPML20() { + super("opml_2.0"); + } + + @Override + public void testWireFeedSyndFeedConversion() throws Exception { + final SyndFeed sFeed1 = getCachedSyndFeed(); + final WireFeed wFeed1 = sFeed1.createWireFeed(); + final SyndFeed sFeed2 = new SyndFeedImpl(wFeed1); + PrintWriter w = new PrintWriter(new FileOutputStream("target/test-reports/3")); + w.println(sFeed1.toString()); + w.close(); + w = new PrintWriter(new FileOutputStream("target/test-reports/4")); + w.println(sFeed2.toString()); + w.close(); + assertEquals(sFeed1, sFeed2); + } + +} diff --git a/rome-opml/src/test/java/com/rometools/opml/TestXmlFixerReader.java b/rome-opml/src/test/java/com/rometools/opml/TestXmlFixerReader.java new file mode 100644 index 0000000..eea78af --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/TestXmlFixerReader.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.rometools.opml; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; + +import junit.framework.TestCase; + +import org.jdom2.input.SAXBuilder; + +import com.rometools.rome.io.XmlReader; +import com.rometools.rome.io.impl.XmlFixerReader; + +/** + * @author pat, tucu + * + */ +public class TestXmlFixerReader extends TestCase { + private static final String XML_PROLOG = ""; + + public void testTrim() throws Exception { + _testValidTrim("", ""); + _testValidTrim("", XML_PROLOG + ""); + _testValidTrim(" ", ""); + _testValidTrim(" ", XML_PROLOG + ""); + _testValidTrim(" \n", ""); + _testValidTrim(" \n", XML_PROLOG + ""); + _testValidTrim("", ""); + _testValidTrim("", XML_PROLOG + ""); + _testValidTrim(" ", ""); + _testValidTrim(" ", XML_PROLOG + ""); + _testValidTrim(" ", ""); + _testValidTrim(" ", XML_PROLOG + ""); + _testValidTrim(" ", ""); + _testValidTrim(" ", XML_PROLOG + ""); + _testValidTrim(" \n ", ""); + _testValidTrim(" \n ", XML_PROLOG + ""); + + _testInvalidTrim("x", ""); + _testInvalidTrim("x", XML_PROLOG + ""); + _testInvalidTrim(" x", ""); + _testInvalidTrim(" x", XML_PROLOG + ""); + _testInvalidTrim(" x\n", ""); + _testInvalidTrim(" x\n", XML_PROLOG + ""); + _testInvalidTrim("x ", ""); + _testInvalidTrim(" x ", XML_PROLOG + ""); + _testInvalidTrim(" x ", ""); + _testInvalidTrim(" x ", XML_PROLOG + ""); + _testInvalidTrim(" x\n ", ""); + _testInvalidTrim(" x\n ", XML_PROLOG + ""); + } + + public void testHtmlEntities() throws Exception { + _testValidEntities(""); + _testValidEntities(XML_PROLOG + ""); + _testValidEntities(" \n" + XML_PROLOG + ""); + + _testValidEntities("'¥ú¥"); + _testValidEntities(XML_PROLOG + "'¥ú¥"); + _testValidEntities(" \n" + XML_PROLOG + "'¥ú¥"); + + _testInvalidEntities("'&yexn;ú¥"); + _testInvalidEntities(XML_PROLOG + "'&yexn;ú¥"); + _testInvalidEntities(" \n" + XML_PROLOG + "'&yexn;ú¥"); + + _testInvalidEntities("'¥x50;¥"); + _testInvalidEntities(XML_PROLOG + "'¥x50;¥"); + _testInvalidEntities(" \n" + XML_PROLOG + "'¥x50;¥"); + + } + + protected void _testXmlParse(final String garbish, final String xmlDoc) throws Exception { + final InputStream is = getStream(garbish, xmlDoc); + Reader reader = new XmlReader(is); + reader = new XmlFixerReader(reader); + final SAXBuilder saxBuilder = new SAXBuilder(); + saxBuilder.build(reader); + } + + protected void _testValidTrim(final String garbish, final String xmlDoc) throws Exception { + _testXmlParse(garbish, xmlDoc); + } + + protected void _testInvalidTrim(final String garbish, final String xmlDoc) throws Exception { + try { + _testXmlParse(garbish, xmlDoc); + assertTrue(false); + } catch (final Exception ex) { + } + } + + protected void _testValidEntities(final String xmlDoc) throws Exception { + _testXmlParse("", xmlDoc); + } + + protected void _testInvalidEntities(final String xmlDoc) throws Exception { + try { + _testXmlParse("", xmlDoc); + assertTrue(false); + } catch (final Exception ex) { + } + } + + // XML Stream generator + + protected InputStream getStream(final String garbish, final String xmlDoc) throws IOException { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); + final Writer writer = new OutputStreamWriter(baos); + writer.write(garbish); + writer.write(xmlDoc); + writer.close(); + return new ByteArrayInputStream(baos.toByteArray()); + } + +} diff --git a/rome-opml/src/test/java/com/rometools/opml/TestXmlReader.java b/rome-opml/src/test/java/com/rometools/opml/TestXmlReader.java new file mode 100644 index 0000000..a7137a0 --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/TestXmlReader.java @@ -0,0 +1,269 @@ +/* + * 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.rometools.opml; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +import com.rometools.rome.io.XmlReader; + +/** + * @author pat, tucu + * + */ +public class TestXmlReader extends TestCase { + + public static void main(final String[] args) throws Exception { + final TestXmlReader test = new TestXmlReader(); + test.testRawBom(); + test.testRawNoBom(); + test.testHttp(); + } + + protected void _testRawNoBomValid(final String encoding) throws Exception { + + // TODO review this test (XmlReader is never closed, test fails when using a new XmlReader + // for each Assert) + + InputStream is = getXmlStream("no-bom", "xml", encoding, encoding); + XmlReader xmlReader = new XmlReader(is, false); + assertEquals(xmlReader.getEncoding(), "UTF-8"); + xmlReader.close(); + + is = getXmlStream("no-bom", "xml-prolog", encoding, encoding); + xmlReader = new XmlReader(is); + assertEquals(xmlReader.getEncoding(), "UTF-8"); + xmlReader.close(); + + is = getXmlStream("no-bom", "xml-prolog-encoding", encoding, encoding); + xmlReader = new XmlReader(is); + assertEquals(xmlReader.getEncoding(), encoding); + xmlReader.close(); + + } + + protected void _testRawNoBomInvalid(final String encoding) throws Exception { + final InputStream is = getXmlStream("no-bom", "xml-prolog-encoding", encoding, encoding); + try { + final XmlReader xmlReader = new XmlReader(is, false); + fail("It should have failed"); + xmlReader.close(); + } catch (final IOException ex) { + assertTrue(ex.getMessage().indexOf("Invalid encoding,") > -1); + } + } + + public void testRawNoBom() throws Exception { + _testRawNoBomValid("US-ASCII"); + _testRawNoBomValid("UTF-8"); + _testRawNoBomValid("ISO-8859-1"); + } + + protected void _testRawBomValid(final String encoding) throws Exception { + final InputStream is = getXmlStream(encoding + "-bom", "xml-prolog-encoding", encoding, encoding); + final XmlReader xmlReader = new XmlReader(is, false); + if (!encoding.equals("UTF-16")) { + assertEquals(xmlReader.getEncoding(), encoding); + } else { + assertEquals(xmlReader.getEncoding().substring(0, encoding.length()), encoding); + } + xmlReader.close(); + } + + protected void _testRawBomInvalid(final String bomEnc, final String streamEnc, final String prologEnc) throws Exception { + final InputStream is = getXmlStream(bomEnc, "xml-prolog-encoding", streamEnc, prologEnc); + try { + final XmlReader xmlReader = new XmlReader(is, false); + fail("It should have failed for BOM " + bomEnc + ", streamEnc " + streamEnc + " and prologEnc " + prologEnc); + xmlReader.close(); + } catch (final IOException ex) { + assertTrue(ex.getMessage().indexOf("Invalid encoding,") > -1); + } + } + + public void testRawBom() throws Exception { + _testRawBomValid("UTF-8"); + _testRawBomValid("UTF-16BE"); + _testRawBomValid("UTF-16LE"); + _testRawBomValid("UTF-16"); + + _testRawBomInvalid("UTF-8-bom", "US-ASCII", "US-ASCII"); + _testRawBomInvalid("UTF-8-bom", "ISO-8859-1", "ISO-8859-1"); + _testRawBomInvalid("UTF-8-bom", "UTF-8", "UTF-16"); + _testRawBomInvalid("UTF-8-bom", "UTF-8", "UTF-16BE"); + _testRawBomInvalid("UTF-8-bom", "UTF-8", "UTF-16LE"); + _testRawBomInvalid("UTF-16BE-bom", "UTF-16BE", "UTF-16LE"); + _testRawBomInvalid("UTF-16LE-bom", "UTF-16LE", "UTF-16BE"); + _testRawBomInvalid("UTF-16LE-bom", "UTF-16LE", "UTF-8"); + } + + public void testHttp() throws Exception { + _testHttpValid("application/xml", "no-bom", "US-ASCII", null); + _testHttpValid("application/xml", "UTF-8-bom", "US-ASCII", null); + _testHttpValid("application/xml", "UTF-8-bom", "UTF-8", null); + _testHttpValid("application/xml", "UTF-8-bom", "UTF-8", "UTF-8"); + _testHttpValid("application/xml;charset=UTF-8", "UTF-8-bom", "UTF-8", null); + _testHttpValid("application/xml;charset=UTF-8", "UTF-8-bom", "UTF-8", "UTF-8"); + _testHttpValid("application/xml;charset=UTF-16", "UTF-16BE-bom", "UTF-16BE", null); + _testHttpValid("application/xml;charset=UTF-16", "UTF-16BE-bom", "UTF-16BE", "UTF-16"); + _testHttpValid("application/xml;charset=UTF-16", "UTF-16BE-bom", "UTF-16BE", "UTF-16BE"); + + _testHttpInvalid("application/xml;charset=UTF-16BE", "UTF-16BE-bom", "UTF-16BE", null); + _testHttpInvalid("application/xml;charset=UTF-16BE", "UTF-16BE-bom", "UTF-16BE", "UTF-16"); + _testHttpInvalid("application/xml;charset=UTF-16BE", "UTF-16BE-bom", "UTF-16BE", "UTF-16BE"); + _testHttpInvalid("application/xml", "UTF-8-bom", "US-ASCII", "US-ASCII"); + _testHttpInvalid("application/xml;charset=UTF-16", "UTF-16LE", "UTF-8", "UTF-8"); + _testHttpInvalid("application/xml;charset=UTF-16", "no-bom", "UTF-16BE", "UTF-16BE"); + + _testHttpValid("text/xml", "no-bom", "US-ASCII", null); + _testHttpValid("text/xml;charset=UTF-8", "UTF-8-bom", "UTF-8", "UTF-8"); + _testHttpValid("text/xml;charset=UTF-8", "UTF-8-bom", "UTF-8", null); + _testHttpValid("text/xml;charset=UTF-16", "UTF-16BE-bom", "UTF-16BE", null); + _testHttpValid("text/xml;charset=UTF-16", "UTF-16BE-bom", "UTF-16BE", "UTF-16"); + _testHttpValid("text/xml;charset=UTF-16", "UTF-16BE-bom", "UTF-16BE", "UTF-16BE"); + _testHttpValid("text/xml", "UTF-8-bom", "US-ASCII", null); + + _testHttpInvalid("text/xml;charset=UTF-16BE", "UTF-16BE-bom", "UTF-16BE", null); + _testHttpInvalid("text/xml;charset=UTF-16BE", "UTF-16BE-bom", "UTF-16BE", "UTF-16"); + _testHttpInvalid("text/xml;charset=UTF-16BE", "UTF-16BE-bom", "UTF-16BE", "UTF-16BE"); + _testHttpInvalid("text/xml;charset=UTF-16", "no-bom", "UTF-16BE", "UTF-16BE"); + _testHttpInvalid("text/xml;charset=UTF-16", "no-bom", "UTF-16BE", null); + + _testHttpLenient("text/xml", "no-bom", "US-ASCII", null, "US-ASCII"); + _testHttpLenient("text/xml;charset=UTF-8", "UTF-8-bom", "UTF-8", "UTF-8", "UTF-8"); + _testHttpLenient("text/xml;charset=UTF-8", "UTF-8-bom", "UTF-8", null, "UTF-8"); + _testHttpLenient("text/xml;charset=UTF-16", "UTF-16BE-bom", "UTF-16BE", null, "UTF-16BE"); + _testHttpLenient("text/xml;charset=UTF-16", "UTF-16BE-bom", "UTF-16BE", "UTF-16", "UTF-16"); + _testHttpLenient("text/xml;charset=UTF-16", "UTF-16BE-bom", "UTF-16BE", "UTF-16BE", "UTF-16BE"); + _testHttpLenient("text/xml", "UTF-8-bom", "US-ASCII", null, "US-ASCII"); + + _testHttpLenient("text/xml;charset=UTF-16BE", "UTF-16BE-bom", "UTF-16BE", null, "UTF-16BE"); + _testHttpLenient("text/xml;charset=UTF-16BE", "UTF-16BE-bom", "UTF-16BE", "UTF-16", "UTF-16"); + _testHttpLenient("text/xml;charset=UTF-16BE", "UTF-16BE-bom", "UTF-16BE", "UTF-16BE", "UTF-16BE"); + _testHttpLenient("text/xml;charset=UTF-16", "no-bom", "UTF-16BE", "UTF-16BE", "UTF-16BE"); + _testHttpLenient("text/xml;charset=UTF-16", "no-bom", "UTF-16BE", null, "UTF-16"); + + _testHttpLenient("text/html", "no-bom", "US-ASCII", "US-ASCII", "US-ASCII"); + _testHttpLenient("text/html", "no-bom", "US-ASCII", null, "US-ASCII"); + _testHttpLenient("text/html;charset=UTF-8", "no-bom", "US-ASCII", "UTF-8", "UTF-8"); + _testHttpLenient("text/html;charset=UTF-16BE", "no-bom", "US-ASCII", "UTF-8", "UTF-8"); + } + + public void _testHttpValid(final String cT, final String bomEnc, final String streamEnc, final String prologEnc) throws Exception { + final InputStream is = getXmlStream(bomEnc, prologEnc == null ? "xml" : "xml-prolog-encoding", streamEnc, prologEnc); + final XmlReader xmlReader = new XmlReader(is, cT, false); + if (!streamEnc.equals("UTF-16")) { + // we can not assert things here becuase UTF-8, US-ASCII and ISO-8859-1 look alike for + // the chars used for detection + } else { + assertEquals(xmlReader.getEncoding().substring(0, streamEnc.length()), streamEnc); + } + xmlReader.close(); + } + + protected void _testHttpInvalid(final String cT, final String bomEnc, final String streamEnc, final String prologEnc) throws Exception { + final InputStream is = getXmlStream(bomEnc, prologEnc == null ? "xml-prolog" : "xml-prolog-encoding", streamEnc, prologEnc); + try { + final XmlReader xmlReader = new XmlReader(is, cT, false); + fail("It should have failed for HTTP Content-type " + cT + ", BOM " + bomEnc + ", streamEnc " + streamEnc + " and prologEnc " + prologEnc); + xmlReader.close(); + } catch (final IOException ex) { + assertTrue(ex.getMessage().indexOf("Invalid encoding,") > -1); + } + } + + protected void _testHttpLenient(final String cT, final String bomEnc, final String streamEnc, final String prologEnc, final String shouldbe) + throws Exception { + final InputStream is = getXmlStream(bomEnc, prologEnc == null ? "xml-prolog" : "xml-prolog-encoding", streamEnc, prologEnc); + final XmlReader xmlReader = new XmlReader(is, cT, true); + assertEquals(xmlReader.getEncoding(), shouldbe); + xmlReader.close(); + } + + // XML Stream generator + + private static final int[] NO_BOM_BYTES = {}; + private static final int[] UTF_16BE_BOM_BYTES = { 0xFE, 0xFF }; + private static final int[] UTF_16LE_BOM_BYTES = { 0xFF, 0XFE }; + private static final int[] UTF_8_BOM_BYTES = { 0xEF, 0xBB, 0xBF }; + + private static final Map BOMs = new HashMap(); + + static { + BOMs.put("no-bom", NO_BOM_BYTES); + BOMs.put("UTF-16BE-bom", UTF_16BE_BOM_BYTES); + BOMs.put("UTF-16LE-bom", UTF_16LE_BOM_BYTES); + BOMs.put("UTF-16-bom", NO_BOM_BYTES); // it's added by the writer + BOMs.put("UTF-8-bom", UTF_8_BOM_BYTES); + } + + private static final MessageFormat XML = new MessageFormat("{2}"); + private static final MessageFormat XML_WITH_PROLOG = new MessageFormat("\n{2}"); + private static final MessageFormat XML_WITH_PROLOG_AND_ENCODING = new MessageFormat("\n{2}"); + + private static final MessageFormat INFO = new MessageFormat("\nBOM : {0}\nDoc : {1}\nStream Enc : {2}\nProlog Enc : {3}\n"); + + private static final Map XMLs = new HashMap(); + + static { + XMLs.put("xml", XML); + XMLs.put("xml-prolog", XML_WITH_PROLOG); + XMLs.put("xml-prolog-encoding", XML_WITH_PROLOG_AND_ENCODING); + } + + /** + * + * @param bomType no-bom, UTF-16BE-bom, UTF-16LE-bom, UTF-8-bom + * @param xmlType xml, xml-prolog, xml-prolog-charset + * @return XML stream + */ + protected InputStream getXmlStream(final String bomType, final String xmlType, final String streamEnc, final String prologEnc) throws IOException { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); + int[] bom = BOMs.get(bomType); + if (bom == null) { + bom = new int[0]; + } + final MessageFormat xml = XMLs.get(xmlType); + for (final int element : bom) { + baos.write(element); + } + final Writer writer = new OutputStreamWriter(baos, streamEnc); + final String info = INFO.format(new Object[] { bomType, xmlType, prologEnc }); + final String xmlDoc = xml.format(new Object[] { streamEnc, prologEnc, info }); + writer.write(xmlDoc); + + // PADDDING TO TEST THINGS WORK BEYOND PUSHBACK_SIZE + writer.write("\n"); + for (int i = 0; i < 10000; i++) { + writer.write("\n"); + } + writer.write("\n"); + + writer.close(); + return new ByteArrayInputStream(baos.toByteArray()); + } + +} diff --git a/rome-opml/src/test/java/com/rometools/opml/io/impl/OPML20GeneratorTest.java b/rome-opml/src/test/java/com/rometools/opml/io/impl/OPML20GeneratorTest.java new file mode 100644 index 0000000..b69f085 --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/io/impl/OPML20GeneratorTest.java @@ -0,0 +1,73 @@ +package com.rometools.opml.io.impl; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +import java.util.Arrays; + +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +import com.rometools.opml.feed.opml.Opml; +import com.rometools.opml.feed.opml.Outline; +import com.rometools.rome.io.WireFeedOutput; + +public class OPML20GeneratorTest { + + @Test + public void testOutputOfNullCategory() { + assertThat(categoryOf((String) null).getLength(), is(equalTo(0))); + } + + @Test + public void testOutputOfEmptyCategory() { + assertThat(categoryOf("").getLength(), is(equalTo(0))); + } + + @Test + public void testOutputOfBlankCategory() { + assertThat(categoryOf(" ").getLength(), is(equalTo(0))); + } + + @Test + public void testOutputOfOneCategory() { + assertThat(categoryValueOf("category1"), is(equalTo("category1"))); + } + + @Test + public void testOutputOfMultipleCategories() { + assertThat(categoryValueOf("category1", "category2"), is(equalTo("category1,category2"))); + } + + private NodeList categoryOf(final String... categories) { + + try { + + final Outline outline = new Outline("outline1", null); + outline.setCategories(Arrays.asList(categories)); + + final Opml opml = new Opml(); + opml.setFeedType("opml_2.0"); + opml.setTitle("title"); + opml.setOutlines(Arrays.asList(outline)); + + final WireFeedOutput output = new WireFeedOutput(); + final String xml = output.outputString(opml); + + final Document document = XMLUnit.buildControlDocument(xml); + return XMLUnit.newXpathEngine().getMatchingNodes("/opml/body/outline/@category", document); + + } catch (final Exception e) { + throw new RuntimeException(e); + } + + } + + private String categoryValueOf(final String... categories) { + return categoryOf(categories).item(0).getNodeValue(); + } + +} diff --git a/rome-opml/src/test/java/com/rometools/opml/test/NullWriter.java b/rome-opml/src/test/java/com/rometools/opml/test/NullWriter.java new file mode 100644 index 0000000..c1642a7 --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/test/NullWriter.java @@ -0,0 +1,20 @@ +package com.rometools.opml.test; + +import java.io.IOException; +import java.io.Writer; + +public class NullWriter extends Writer { + + @Override + public void write(final char[] cbuf, final int off, final int len) throws IOException { + } + + @Override + public void flush() throws IOException { + } + + @Override + public void close() throws IOException { + } + +} diff --git a/rome-opml/src/test/java/com/rometools/opml/test/TestUtil.java b/rome-opml/src/test/java/com/rometools/opml/test/TestUtil.java new file mode 100644 index 0000000..ccd1b70 --- /dev/null +++ b/rome-opml/src/test/java/com/rometools/opml/test/TestUtil.java @@ -0,0 +1,15 @@ +package com.rometools.opml.test; + +import java.io.InputStreamReader; +import java.io.Reader; + +public final class TestUtil { + + private TestUtil() { + } + + public static Reader loadFile(final String path) { + return new InputStreamReader(TestUtil.class.getResourceAsStream(path)); + } + +} diff --git a/rome-opml/src/test/resources/logback-test.xml b/rome-opml/src/test/resources/logback-test.xml new file mode 100644 index 0000000..c34b099 --- /dev/null +++ b/rome-opml/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + \ No newline at end of file diff --git a/rome-opml/src/test/resources/opml_1.0.xml b/rome-opml/src/test/resources/opml_1.0.xml new file mode 100644 index 0000000..98b1524 --- /dev/null +++ b/rome-opml/src/test/resources/opml_1.0.xml @@ -0,0 +1,29 @@ + + + + Bloglines Subscriptions + Tue, 25 Apr 2006 19:19:28 GMT + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rome-opml/src/test/resources/opml_1.0_links.xml b/rome-opml/src/test/resources/opml_1.0_links.xml new file mode 100644 index 0000000..94c8236 --- /dev/null +++ b/rome-opml/src/test/resources/opml_1.0_links.xml @@ -0,0 +1,76 @@ + + + + Top Ten Sources for podcasting + Newsilike Media Group + opml@TopTenSources.com + Thu, 27 Apr 2006 05:47:27 GMT + Thu, 27 Apr 2006 05:47:27 GMT + 0 + 0 + 0 + 0 + 100 + 100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rome-opml/src/test/resources/opml_2.0.xml b/rome-opml/src/test/resources/opml_2.0.xml new file mode 100644 index 0000000..22c9586 --- /dev/null +++ b/rome-opml/src/test/resources/opml_2.0.xml @@ -0,0 +1,30 @@ + + + + Bloglines Subscriptions + Tue, 25 Apr 2006 19:19:28 GMT + http://foo.com + Robert Cooper + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rome-propono/.gitignore b/rome-propono/.gitignore new file mode 100644 index 0000000..2e975ff --- /dev/null +++ b/rome-propono/.gitignore @@ -0,0 +1,4 @@ +/.classpath +/.project +/.settings +/target \ No newline at end of file diff --git a/rome-propono/LICENSE b/rome-propono/LICENSE new file mode 100644 index 0000000..6b0b127 --- /dev/null +++ b/rome-propono/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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/rome-propono/NOTICE b/rome-propono/NOTICE new file mode 100644 index 0000000..fe019d6 --- /dev/null +++ b/rome-propono/NOTICE @@ -0,0 +1,26 @@ + +Portions of the Propono code are Copyright (C) 2007 Sun Microsystems, Inc. + +Sun Microsystems, Inc. +4150 Network Circle, Santa Clara, California 95054, U.S.A. +All rights reserved. + +U.S. Government Rights - Commercial software. Government users are subject to +the Sun Microsystems, Inc. standard license agreement and applicable provisions +of the FAR and its supplements. + +Use is subject to license terms. + +This distribution may include materials developed by third parties. + +Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered +trademarks of Sun Microsystems, Inc. in the U.S. and other countries. + +This product is covered and controlled by U.S. Export Control laws and may be +subject to the export or import laws in other countries. Nuclear, missile, +chemical biological weapons or nuclear maritime end uses or end users, whether +direct or indirect, are strictly prohibited. Export or reexport to countries +subject to U.S. embargo or to entities identified on U.S. export exclusion +lists, including, but not limited to, the denied persons and specially +designated nationals lists is strictly prohibited. + diff --git a/rome-propono/README.md b/rome-propono/README.md new file mode 100644 index 0000000..8a9f1a5 --- /dev/null +++ b/rome-propono/README.md @@ -0,0 +1,6 @@ +rome +==== + +ROME is a set of RSS and Atom Utilities for Java. It makes it easy to work in Java with most syndication formats: RSS 0.90, RSS 0.91 Netscape, RSS 0.91 Userland, RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, RSS 2.0, Atom 0.3, Atom 1.0 + +More Information: http://rometools.github.io/rome-propono/ diff --git a/rome-propono/pom.xml b/rome-propono/pom.xml new file mode 100644 index 0000000..f4768e9 --- /dev/null +++ b/rome-propono/pom.xml @@ -0,0 +1,122 @@ + + + 4.0.0 + + + com.rometools + rome-parent + 1.6.0-SNAPSHOT + + + rome-propono + 1.6.0-SNAPSHOT + jar + + rome-propono + + The ROME Propono subproject is a Java class library that + supports publishing protocols, specifically the Atom Publishing Protocol + and the legacy MetaWeblog API. Propono includes an Atom client library, + Atom server framework and a Blog client that supports both Atom protocol + and the MetaWeblog API. + + + http://rometools.github.io/rome-propono/ + + + scm:git:ssh://github.com/rometools/rome-propono.git + scm:git:ssh://git@github.com/rometools/rome-propono.git + https://github.com/rometools/rome-propono + + + + + Dave Johnson + http://rollerweblogger.org/roller + -5 + + + Robert Cooper + kebernet@gmail.com + http://www.screaming-penguin.com + -4 + + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + gh-pages + ${project.scm.developerConnection} + ${project.build.directory}/site + + + + + + + + com.rometools + rome + 1.6.0-SNAPSHOT + + + commons-httpclient + commons-httpclient + + + org.apache.commons + commons-lang3 + + + commons-beanutils + commons-beanutils + + + org.apache.xmlrpc + xmlrpc-client + + + net.oauth.core + oauth + + + javax.servlet + servlet-api + provided + + + ch.qos.logback + logback-classic + test + + + junit + junit + test + + + jetty + jetty + test + + + + diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/AtomClientFactory.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/AtomClientFactory.java new file mode 100644 index 0000000..281baaf --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/AtomClientFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright 2007 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.rometools.propono.atom.client; + +import com.rometools.propono.utils.ProponoException; +import com.rometools.rome.io.impl.Atom10Parser; + +/** + * Creates AtomService or ClientCollection based on username, password and end-point URI of Atom + * protocol service. + */ +public class AtomClientFactory { + + static { + Atom10Parser.setResolveURIs(true); + } + + /** + * Create AtomService by reading service doc from Atom Server. + */ + public static ClientAtomService getAtomService(final String uri, final AuthStrategy authStrategy) throws ProponoException { + return new ClientAtomService(uri, authStrategy); + } + + /** + * Create ClientCollection bound to URI. + */ + public static ClientCollection getCollection(final String uri, final AuthStrategy authStrategy) throws ProponoException { + return new ClientCollection(uri, authStrategy); + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/AuthStrategy.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/AuthStrategy.java new file mode 100644 index 0000000..c40ebd1 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/AuthStrategy.java @@ -0,0 +1,29 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.atom.client; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethodBase; + +import com.rometools.propono.utils.ProponoException; + +public interface AuthStrategy { + + /** + * Add authentication credenticals, tokens, etc. to HTTP method + */ + void addAuthentication(HttpClient httpClient, HttpMethodBase method) throws ProponoException; +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/BasicAuthStrategy.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/BasicAuthStrategy.java new file mode 100644 index 0000000..8bf51e4 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/BasicAuthStrategy.java @@ -0,0 +1,42 @@ +/* + * Copyright 2009 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.atom.client; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethodBase; + +import com.rometools.propono.utils.ProponoException; +import com.rometools.rome.io.impl.Base64; + +public class BasicAuthStrategy implements AuthStrategy { + private final String credentials; + + public BasicAuthStrategy(final String username, final String password) { + new Base64(); + credentials = new String(Base64.encode((username + ":" + password).getBytes())); + } + + public void init() throws ProponoException { + // op-op + } + + @Override + public void addAuthentication(final HttpClient httpClient, final HttpMethodBase method) throws ProponoException { + httpClient.getParams().setAuthenticationPreemptive(true); + final String header = "Basic " + credentials; + method.setRequestHeader("Authorization", header); + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientAtomService.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientAtomService.java new file mode 100644 index 0000000..77ca1ca --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientAtomService.java @@ -0,0 +1,139 @@ +/* + * Copyright 2007 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.rometools.propono.atom.client; + +import java.io.InputStreamReader; +import java.util.List; +import java.util.Locale; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethodBase; +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.methods.GetMethod; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.input.SAXBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.propono.atom.common.AtomService; +import com.rometools.propono.utils.ProponoException; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.io.impl.Atom10Parser; + +/** + * This class models an Atom Publising Protocol Service Document. It extends the common + * {@link com.rometools.rome.propono.atom.common.Collection} class to add a getEntry() + * method and to return {@link com.rometools.rome.propono.atom.client.ClientWorkspace} objects + * instead of common {@link com.rometools.rome.propono.atom.common.Workspace}s. + */ +public class ClientAtomService extends AtomService { + + private static final Logger LOG = LoggerFactory.getLogger(ClientAtomService.class); + + private String uri = null; + private HttpClient httpClient = null; + private AuthStrategy authStrategy = null; + + /** + * Create Atom blog service instance for specified URL and user account. + * + * @param url End-point URL of Atom service + */ + ClientAtomService(final String uri, final AuthStrategy authStrategy) throws ProponoException { + this.uri = uri; + this.authStrategy = authStrategy; + final Document doc = getAtomServiceDocument(); + parseAtomServiceDocument(doc); + } + + /** + * Get full entry from service by entry edit URI. + */ + public ClientEntry getEntry(final String uri) throws ProponoException { + final GetMethod method = new GetMethod(uri); + authStrategy.addAuthentication(httpClient, method); + try { + httpClient.executeMethod(method); + if (method.getStatusCode() != 200) { + throw new ProponoException("ERROR HTTP status code=" + method.getStatusCode()); + } + final Entry romeEntry = Atom10Parser.parseEntry(new InputStreamReader(method.getResponseBodyAsStream()), uri, Locale.US); + if (!romeEntry.isMediaEntry()) { + return new ClientEntry(this, null, romeEntry, false); + } else { + return new ClientMediaEntry(this, null, romeEntry, false); + } + } catch (final Exception e) { + throw new ProponoException("ERROR: getting or parsing entry/media", e); + } finally { + method.releaseConnection(); + } + } + + void addAuthentication(final HttpMethodBase method) throws ProponoException { + authStrategy.addAuthentication(httpClient, method); + } + + AuthStrategy getAuthStrategy() { + return authStrategy; + } + + private Document getAtomServiceDocument() throws ProponoException { + GetMethod method = null; + final int code = -1; + try { + httpClient = new HttpClient(new MultiThreadedHttpConnectionManager()); + // TODO: make connection timeout configurable + httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(30000); + + method = new GetMethod(uri); + authStrategy.addAuthentication(httpClient, method); + httpClient.executeMethod(method); + + final SAXBuilder builder = new SAXBuilder(); + final String doc = method.getResponseBodyAsString(); + LOG.debug(doc); + return builder.build(method.getResponseBodyAsStream()); + + } catch (final Throwable t) { + final String msg = "ERROR retrieving Atom Service Document, code: " + code; + LOG.debug(msg, t); + throw new ProponoException(msg, t); + } finally { + if (method != null) { + method.releaseConnection(); + } + } + } + + /** Deserialize an Atom service XML document into an object */ + private void parseAtomServiceDocument(final Document document) throws ProponoException { + final Element root = document.getRootElement(); + final List spaces = root.getChildren("workspace", AtomService.ATOM_PROTOCOL); + for (final Element e : spaces) { + addWorkspace(new ClientWorkspace(e, this, uri)); + } + } + + /** + * Package access to httpClient. + */ + HttpClient getHttpClient() { + return httpClient; + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientCategories.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientCategories.java new file mode 100644 index 0000000..229430d --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientCategories.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.client; + +import java.io.IOException; +import java.io.InputStreamReader; + +import org.apache.commons.httpclient.methods.GetMethod; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.JDOMException; +import org.jdom2.input.SAXBuilder; + +import com.rometools.propono.atom.common.Categories; +import com.rometools.propono.utils.ProponoException; + +/** + * Models an Atom protocol Categories element, which may contain ROME Atom + * {@link com.rometools.rome.feed.atom.Category} elements. + */ +public class ClientCategories extends Categories { + private ClientCollection clientCollection = null; + + /** Load select from XML element */ + public ClientCategories(final Element e, final ClientCollection clientCollection) throws ProponoException { + this.clientCollection = clientCollection; + parseCategoriesElement(e); + if (getHref() != null) { + fetchContents(); + } + } + + public void fetchContents() throws ProponoException { + final GetMethod method = new GetMethod(getHrefResolved()); + clientCollection.addAuthentication(method); + try { + clientCollection.getHttpClient().executeMethod(method); + if (method.getStatusCode() != 200) { + throw new ProponoException("ERROR HTTP status code=" + method.getStatusCode()); + } + final SAXBuilder builder = new SAXBuilder(); + final Document catsDoc = builder.build(new InputStreamReader(method.getResponseBodyAsStream())); + parseCategoriesElement(catsDoc.getRootElement()); + + } catch (final IOException ioe) { + throw new ProponoException("ERROR: reading out-of-line categories", ioe); + } catch (final JDOMException jde) { + throw new ProponoException("ERROR: parsing out-of-line categories", jde); + } finally { + method.releaseConnection(); + } + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientCollection.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientCollection.java new file mode 100644 index 0000000..a96f0b8 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientCollection.java @@ -0,0 +1,225 @@ +/* + * Copyright 2007 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.rometools.propono.atom.client; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethodBase; +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.methods.GetMethod; +import org.jdom2.Element; + +import com.rometools.propono.atom.common.AtomService; +import com.rometools.propono.atom.common.Categories; +import com.rometools.propono.atom.common.Collection; +import com.rometools.propono.atom.common.Workspace; +import com.rometools.propono.utils.ProponoException; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.io.impl.Atom10Parser; + +/** + * Models an Atom collection, extends Collection and adds methods for adding, retrieving, updateing + * and deleting entries. + */ +public class ClientCollection extends Collection { + + private final boolean writable = true; + + private HttpClient httpClient = null; + private AuthStrategy authStrategy = null; + private ClientWorkspace workspace = null; + private ClientAtomService service = null; + + ClientCollection(final Element e, final ClientWorkspace workspace, final String baseURI) throws ProponoException { + super(e, baseURI); + this.workspace = workspace; + service = workspace.getAtomService(); + httpClient = workspace.getAtomService().getHttpClient(); + authStrategy = workspace.getAtomService().getAuthStrategy(); + parseCollectionElement(e); + } + + ClientCollection(final String href, final AuthStrategy authStrategy) throws ProponoException { + super("Standalone connection", "text", href); + this.authStrategy = authStrategy; + try { + httpClient = new HttpClient(new MultiThreadedHttpConnectionManager()); + // TODO: make connection timeout configurable + httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(30000); + } catch (final Throwable t) { + throw new ProponoException("ERROR creating HTTPClient", t); + } + } + + void addAuthentication(final HttpMethodBase method) throws ProponoException { + authStrategy.addAuthentication(httpClient, method); + } + + /** + * Package access to httpClient to allow use by ClientEntry and ClientMediaEntry. + */ + HttpClient getHttpClient() { + return httpClient; + } + + /** + * Get iterator over entries in this collection. Entries returned are considered to be partial + * entries cannot be saved/updated. + */ + public Iterator getEntries() throws ProponoException { + return new EntryIterator(this); + } + + /** + * Get full entry specified by entry edit URI. Note that entry may or may not be associated with + * this collection. + * + * @return ClientEntry or ClientMediaEntry specified by URI. + */ + public ClientEntry getEntry(final String uri) throws ProponoException { + final GetMethod method = new GetMethod(uri); + authStrategy.addAuthentication(httpClient, method); + try { + httpClient.executeMethod(method); + if (method.getStatusCode() != 200) { + throw new ProponoException("ERROR HTTP status code=" + method.getStatusCode()); + } + final Entry romeEntry = Atom10Parser.parseEntry(new InputStreamReader(method.getResponseBodyAsStream()), uri, Locale.US); + if (!romeEntry.isMediaEntry()) { + return new ClientEntry(service, this, romeEntry, false); + } else { + return new ClientMediaEntry(service, this, romeEntry, false); + } + } catch (final Exception e) { + throw new ProponoException("ERROR: getting or parsing entry/media, HTTP code: ", e); + } finally { + method.releaseConnection(); + } + } + + /** + * Get workspace or null if collection is not associated with a workspace. + */ + public Workspace getWorkspace() { + return workspace; + } + + /** + * Determines if collection is writable. + */ + public boolean isWritable() { + return writable; + } + + /** + * Create new entry associated with collection, but do not save to server. + * + * @throws ProponoException if collecton is not writable. + */ + public ClientEntry createEntry() throws ProponoException { + if (!isWritable()) { + throw new ProponoException("Collection is not writable"); + } + return new ClientEntry(service, this); + } + + /** + * Create new media entry assocaited with collection, but do not save. server. Depending on the + * Atom server, you may or may not be able to persist the properties of the entry that is + * returned. + * + * @param title Title to used for uploaded file. + * @param slug String to be used in file-name of stored file + * @param contentType MIME content-type of file. + * @param bytes Data to be uploaded as byte array. + * @throws ProponoException if collecton is not writable + */ + public ClientMediaEntry createMediaEntry(final String title, final String slug, final String contentType, final byte[] bytes) throws ProponoException { + if (!isWritable()) { + throw new ProponoException("Collection is not writable"); + } + return new ClientMediaEntry(service, this, title, slug, contentType, bytes); + } + + /** + * Create new media entry assocaited with collection, but do not save. server. Depending on the + * Atom server, you may or may not be able to. persist the properties of the entry that is + * returned. + * + * @param title Title to used for uploaded file. + * @param slug String to be used in file-name of stored file + * @param contentType MIME content-type of file. + * @param is Data to be uploaded as InputStream. + * @throws ProponoException if collecton is not writable + */ + public ClientMediaEntry createMediaEntry(final String title, final String slug, final String contentType, final InputStream is) throws ProponoException { + if (!isWritable()) { + throw new ProponoException("Collection is not writable"); + } + return new ClientMediaEntry(service, this, title, slug, contentType, is); + } + + /** + * Save to collection a new entry that was created by a createEntry() or createMediaEntry() and + * save it to the server. + * + * @param entry Entry to be saved. + * @throws ProponoException on error, if collection is not writable or if entry is partial. + */ + public void addEntry(final ClientEntry entry) throws ProponoException { + if (!isWritable()) { + throw new ProponoException("Collection is not writable"); + } + entry.addToCollection(this); + } + + @Override + protected void parseCollectionElement(final Element element) throws ProponoException { + if (workspace == null) { + return; + } + + setHref(element.getAttribute("href").getValue()); + + final Element titleElem = element.getChild("title", AtomService.ATOM_FORMAT); + if (titleElem != null) { + setTitle(titleElem.getText()); + if (titleElem.getAttribute("type", AtomService.ATOM_FORMAT) != null) { + setTitleType(titleElem.getAttribute("type", AtomService.ATOM_FORMAT).getValue()); + } + } + + final List acceptElems = element.getChildren("accept", AtomService.ATOM_PROTOCOL); + if (acceptElems != null && !acceptElems.isEmpty()) { + for (final Element acceptElem : acceptElems) { + addAccept(acceptElem.getTextTrim()); + } + } + + // Loop to parse element to Categories objects + final List catsElems = element.getChildren("categories", AtomService.ATOM_PROTOCOL); + for (final Element catsElem : catsElems) { + final Categories cats = new ClientCategories(catsElem, this); + addCategories(cats); + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientEntry.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientEntry.java new file mode 100644 index 0000000..1af10cb --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientEntry.java @@ -0,0 +1,267 @@ +/* + * Copyright 2007 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.rometools.propono.atom.client; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethodBase; +import org.apache.commons.httpclient.methods.DeleteMethod; +import org.apache.commons.httpclient.methods.EntityEnclosingMethod; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.PutMethod; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.propono.utils.ProponoException; +import com.rometools.propono.utils.Utilities; +import com.rometools.rome.feed.atom.Content; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.io.impl.Atom10Generator; +import com.rometools.rome.io.impl.Atom10Parser; + +/** + * Client implementation of Atom entry, extends ROME Entry to add methods for easily getting/setting + * content, updating and removing the entry from the server. + */ +public class ClientEntry extends Entry { + + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(ClientEntry.class); + + private ClientAtomService service = null; + private ClientCollection collection = null; + protected boolean partial = false; + + public ClientEntry(final ClientAtomService service, final ClientCollection collection) { + this.service = service; + this.collection = collection; + } + + public ClientEntry(final ClientAtomService service, final ClientCollection collection, final Entry entry, final boolean partial) throws ProponoException { + this.service = service; + this.collection = collection; + this.partial = partial; + try { + BeanUtils.copyProperties(this, entry); + } catch (final Exception e) { + throw new ProponoException("ERROR: copying fields from ROME entry", e); + } + } + + /** + * Set content of entry. + * + * @param contentString content string. + * @param type Must be "text" for plain text, "html" for escaped HTML, "xhtml" for XHTML or a + * valid MIME content-type. + */ + public void setContent(final String contentString, final String type) { + final Content newContent = new Content(); + newContent.setType(type == null ? Content.HTML : type); + newContent.setValue(contentString); + final ArrayList contents = new ArrayList(); + contents.add(newContent); + setContents(contents); + } + + /** + * Convenience method to set first content object in content collection. Atom 1.0 allows only + * one content element per entry. + */ + public void setContent(final Content c) { + final ArrayList contents = new ArrayList(); + contents.add(c); + setContents(contents); + } + + /** + * Convenience method to get first content object in content collection. Atom 1.0 allows only + * one content element per entry. + */ + public Content getContent() { + if (getContents() != null && !getContents().isEmpty()) { + final Content c = getContents().get(0); + return c; + } + return null; + } + + /** + * Determines if entries are equal based on edit URI. + */ + @Override + public boolean equals(final Object o) { + if (o instanceof ClientEntry) { + final ClientEntry other = (ClientEntry) o; + if (other.getEditURI() != null && getEditURI() != null) { + return other.getEditURI().equals(getEditURI()); + } + } + return false; + } + + /** + * Update entry by posting new representation of entry to server. Note that you should not + * attempt to update entries that you get from iterating over a collection they may be "partial" + * entries. If you want to update an entry, you must get it via one of the + * getEntry() methods in {@link com.rometools.rome.propono.atom.common.Collection} + * or {@link com.rometools.rome.propono.atom.common.AtomService}. + * + * @throws ProponoException If entry is a "partial" entry. + */ + public void update() throws ProponoException { + if (partial) { + throw new ProponoException("ERROR: attempt to update partial entry"); + } + final EntityEnclosingMethod method = new PutMethod(getEditURI()); + addAuthentication(method); + final StringWriter sw = new StringWriter(); + final int code = -1; + try { + Atom10Generator.serializeEntry(this, sw); + method.setRequestEntity(new StringRequestEntity(sw.toString(), null, null)); + method.setRequestHeader("Content-type", "application/atom+xml; charset=utf-8"); + getHttpClient().executeMethod(method); + final InputStream is = method.getResponseBodyAsStream(); + if (method.getStatusCode() != 200 && method.getStatusCode() != 201) { + throw new ProponoException("ERROR HTTP status=" + method.getStatusCode() + " : " + Utilities.streamToString(is)); + } + + } catch (final Exception e) { + final String msg = "ERROR: updating entry, HTTP code: " + code; + LOG.debug(msg, e); + throw new ProponoException(msg, e); + } finally { + method.releaseConnection(); + } + } + + /** + * Remove entry from server. + */ + public void remove() throws ProponoException { + if (getEditURI() == null) { + throw new ProponoException("ERROR: cannot delete unsaved entry"); + } + final DeleteMethod method = new DeleteMethod(getEditURI()); + addAuthentication(method); + try { + getHttpClient().executeMethod(method); + } catch (final IOException ex) { + throw new ProponoException("ERROR: removing entry, HTTP code", ex); + } finally { + method.releaseConnection(); + } + } + + void setCollection(final ClientCollection collection) { + this.collection = collection; + } + + ClientCollection getCollection() { + return collection; + } + + /** + * Get the URI that can be used to edit the entry via HTTP PUT or DELETE. + */ + public String getEditURI() { + for (int i = 0; i < getOtherLinks().size(); i++) { + final Link link = getOtherLinks().get(i); + if (link.getRel() != null && link.getRel().equals("edit")) { + return link.getHrefResolved(); + } + } + return null; + } + + void addToCollection(final ClientCollection col) throws ProponoException { + setCollection(col); + final EntityEnclosingMethod method = new PostMethod(getCollection().getHrefResolved()); + addAuthentication(method); + final StringWriter sw = new StringWriter(); + int code = -1; + try { + Atom10Generator.serializeEntry(this, sw); + method.setRequestEntity(new StringRequestEntity(sw.toString(), null, null)); + method.setRequestHeader("Content-type", "application/atom+xml; charset=utf-8"); + getHttpClient().executeMethod(method); + final InputStream is = method.getResponseBodyAsStream(); + code = method.getStatusCode(); + if (code != 200 && code != 201) { + throw new ProponoException("ERROR HTTP status=" + code + " : " + Utilities.streamToString(is)); + } + final Entry romeEntry = Atom10Parser.parseEntry(new InputStreamReader(is), getCollection().getHrefResolved(), Locale.US); + BeanUtils.copyProperties(this, romeEntry); + + } catch (final Exception e) { + final String msg = "ERROR: saving entry, HTTP code: " + code; + LOG.debug(msg, e); + throw new ProponoException(msg, e); + } finally { + method.releaseConnection(); + } + final Header locationHeader = method.getResponseHeader("Location"); + if (locationHeader == null) { + LOG.warn("WARNING added entry, but no location header returned"); + } else if (getEditURI() == null) { + final List links = getOtherLinks(); + final Link link = new Link(); + link.setHref(locationHeader.getValue()); + link.setRel("edit"); + links.add(link); + setOtherLinks(links); + } + } + + void addAuthentication(final HttpMethodBase method) throws ProponoException { + if (service != null) { + service.addAuthentication(method); + } else if (collection != null) { + collection.addAuthentication(method); + } + } + + HttpClient getHttpClient() { + if (service != null) { + return service.getHttpClient(); + } else if (collection != null) { + return collection.getHttpClient(); + } + return null; + } + + @Override + public void setCreated(final Date d) { + // protected against null created property (an old Atom 0.3 property) + if (d != null) { + super.setCreated(d); + } + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientMediaEntry.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientMediaEntry.java new file mode 100644 index 0000000..049f039 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientMediaEntry.java @@ -0,0 +1,304 @@ +/* + * Copyright 2007 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.rometools.propono.atom.client; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.methods.EntityEnclosingMethod; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.InputStreamRequestEntity; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.PutMethod; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.jdom2.JDOMException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.propono.utils.ProponoException; +import com.rometools.propono.utils.Utilities; +import com.rometools.rome.feed.atom.Content; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.impl.Atom10Generator; +import com.rometools.rome.io.impl.Atom10Parser; + +/** + * Client implementation of Atom media-link entry, an Atom entry that provides meta-data for a media + * file (e.g. uploaded image or audio file). + */ +public class ClientMediaEntry extends ClientEntry { + + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(ClientMediaEntry.class); + + private String slug = null; + private byte[] bytes; + private InputStream inputStream; + + /** + * Create ClientMedieEntry for service and collection. + */ + public ClientMediaEntry(final ClientAtomService service, final ClientCollection collection) { + super(service, collection); + } + + public ClientMediaEntry(final ClientAtomService service, final ClientCollection collection, final Entry entry, final boolean partial) + throws ProponoException { + super(service, collection, entry, partial); + } + + public ClientMediaEntry(final ClientAtomService service, final ClientCollection collection, final String title, final String slug, + final String contentType, final InputStream is) { + this(service, collection); + inputStream = is; + setTitle(title); + setSlug(slug); + final Content content = new Content(); + content.setType(contentType); + final List contents = new ArrayList(); + contents.add(content); + setContents(contents); + } + + public ClientMediaEntry(final ClientAtomService service, final ClientCollection collection, final String title, final String slug, + final String contentType, final byte[] bytes) { + this(service, collection); + this.bytes = bytes; + setTitle(title); + setSlug(slug); + final Content content = new Content(); + content.setType(contentType); + final List contents = new ArrayList(); + contents.add(content); + setContents(contents); + } + + /** + * Get bytes of media resource associated with entry. + * + * @return Bytes or null if none available or if entry uses an InputStream instead. + */ + public byte[] getBytes() { + return bytes; + } + + /** + * Set media resource data as a byte array, don't try this if you have already set the data as + * an InputStream. + */ + public void setBytes(final byte[] bytes) { + if (inputStream != null) { + throw new IllegalStateException("ERROR: already has inputStream, cannot set both inputStream and bytes"); + } + this.bytes = bytes; + } + + /** + * Get input stream for media resource associated with this entry. + * + * @return InputStream or null if none available or if entry uses bytes instead. + */ + public InputStream getInputStream() { + return inputStream; + } + + /** + * Set media resource data as an input stream, don't try this if you have already set the data + * as a byte array. + */ + public void setInputStream(final InputStream inputStream) { + if (bytes != null) { + throw new IllegalStateException("ERROR: already has bytes, cannot set both bytes and inputStream"); + } + this.inputStream = inputStream; + } + + /** + * Get media link URI for editing the media resource associated with this entry via HTTP PUT or + * DELETE. + */ + public String getMediaLinkURI() { + for (int i = 0; i < getOtherLinks().size(); i++) { + final Link link = getOtherLinks().get(i); + if (link.getRel() != null && link.getRel().equals("edit-media")) { + return link.getHrefResolved(); + } + } + return null; + } + + /** + * Get media resource as an InputStream, should work regardless of whether you set the media + * resource data as an InputStream or as a byte array. + */ + public InputStream getAsStream() throws ProponoException { + if (getContents() != null && !getContents().isEmpty()) { + final Content c = getContents().get(0); + if (c.getSrc() != null) { + return getResourceAsStream(); + } else if (inputStream != null) { + return inputStream; + } else if (bytes != null) { + return new ByteArrayInputStream(bytes); + } else { + throw new ProponoException("ERROR: no src URI or binary data to return"); + } + } else { + throw new ProponoException("ERROR: no content found in entry"); + } + } + + private InputStream getResourceAsStream() throws ProponoException { + if (getEditURI() == null) { + throw new ProponoException("ERROR: not yet saved to server"); + } + final GetMethod method = new GetMethod(((Content) getContents()).getSrc()); + try { + getCollection().getHttpClient().executeMethod(method); + if (method.getStatusCode() != 200) { + throw new ProponoException("ERROR HTTP status=" + method.getStatusCode()); + } + return method.getResponseBodyAsStream(); + } catch (final IOException e) { + throw new ProponoException("ERROR: getting media entry", e); + } + } + + /** + * Update entry on server. + */ + @Override + public void update() throws ProponoException { + if (partial) { + throw new ProponoException("ERROR: attempt to update partial entry"); + } + EntityEnclosingMethod method = null; + final Content updateContent = getContents().get(0); + try { + if (getMediaLinkURI() != null && getBytes() != null) { + // existing media entry and new file, so PUT file to edit-media URI + method = new PutMethod(getMediaLinkURI()); + if (inputStream != null) { + method.setRequestEntity(new InputStreamRequestEntity(inputStream)); + } else { + method.setRequestEntity(new InputStreamRequestEntity(new ByteArrayInputStream(getBytes()))); + } + + method.setRequestHeader("Content-type", updateContent.getType()); + } else if (getEditURI() != null) { + // existing media entry and NO new file, so PUT entry to edit URI + method = new PutMethod(getEditURI()); + final StringWriter sw = new StringWriter(); + Atom10Generator.serializeEntry(this, sw); + method.setRequestEntity(new StringRequestEntity(sw.toString(), null, null)); + method.setRequestHeader("Content-type", "application/atom+xml; charset=utf8"); + } else { + throw new ProponoException("ERROR: media entry has no edit URI or media-link URI"); + } + getCollection().addAuthentication(method); + method.addRequestHeader("Title", getTitle()); + getCollection().getHttpClient().executeMethod(method); + if (inputStream != null) { + inputStream.close(); + } + final InputStream is = method.getResponseBodyAsStream(); + if (method.getStatusCode() != 200 && method.getStatusCode() != 201) { + throw new ProponoException("ERROR HTTP status=" + method.getStatusCode() + " : " + Utilities.streamToString(is)); + } + + } catch (final Exception e) { + throw new ProponoException("ERROR: saving media entry"); + } + if (method.getStatusCode() != 201) { + throw new ProponoException("ERROR HTTP status=" + method.getStatusCode()); + } + } + + /** Package access, to be called by DefaultClientCollection */ + @Override + void addToCollection(final ClientCollection col) throws ProponoException { + setCollection(col); + final EntityEnclosingMethod method = new PostMethod(col.getHrefResolved()); + getCollection().addAuthentication(method); + try { + final Content c = getContents().get(0); + if (inputStream != null) { + method.setRequestEntity(new InputStreamRequestEntity(inputStream)); + } else { + method.setRequestEntity(new InputStreamRequestEntity(new ByteArrayInputStream(getBytes()))); + } + method.setRequestHeader("Content-type", c.getType()); + method.setRequestHeader("Title", getTitle()); + method.setRequestHeader("Slug", getSlug()); + getCollection().getHttpClient().executeMethod(method); + if (inputStream != null) { + inputStream.close(); + } + final InputStream is = method.getResponseBodyAsStream(); + if (method.getStatusCode() == 200 || method.getStatusCode() == 201) { + final Entry romeEntry = Atom10Parser.parseEntry(new InputStreamReader(is), col.getHrefResolved(), Locale.US); + BeanUtils.copyProperties(this, romeEntry); + + } else { + throw new ProponoException("ERROR HTTP status-code=" + method.getStatusCode() + " status-line: " + method.getStatusLine()); + } + } catch (final IOException ie) { + throw new ProponoException("ERROR: saving media entry", ie); + } catch (final JDOMException je) { + throw new ProponoException("ERROR: saving media entry", je); + } catch (final FeedException fe) { + throw new ProponoException("ERROR: saving media entry", fe); + } catch (final IllegalAccessException ae) { + throw new ProponoException("ERROR: saving media entry", ae); + } catch (final InvocationTargetException te) { + throw new ProponoException("ERROR: saving media entry", te); + } + final Header locationHeader = method.getResponseHeader("Location"); + if (locationHeader == null) { + LOG.warn("WARNING added entry, but no location header returned"); + } else if (getEditURI() == null) { + final List links = getOtherLinks(); + final Link link = new Link(); + link.setHref(locationHeader.getValue()); + link.setRel("edit"); + links.add(link); + setOtherLinks(links); + } + } + + /** Set string to be used in file name of new media resource on server. */ + public String getSlug() { + return slug; + } + + /** Get string to be used in file name of new media resource on server. */ + public void setSlug(final String slug) { + this.slug = slug; + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientWorkspace.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientWorkspace.java new file mode 100644 index 0000000..e06b7e0 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/ClientWorkspace.java @@ -0,0 +1,62 @@ +/* + * Copyright 2007 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.rometools.propono.atom.client; + +import java.util.List; + +import org.jdom2.Element; + +import com.rometools.propono.atom.common.AtomService; +import com.rometools.propono.atom.common.Workspace; +import com.rometools.propono.utils.ProponoException; + +/** + * Represents Atom protocol workspace on client-side. It extends the common + * {@link com.rometools.rome.propono.atom.common.Workspace} to return + * {@link com.rometools.rome.propono.atom.client.ClientCollection} objects instead of common + * {@link com.rometools.rome.propono.atom.common.Collection}s. + */ +public class ClientWorkspace extends Workspace { + + private ClientAtomService atomService = null; + + ClientWorkspace(final Element e, final ClientAtomService atomService, final String baseURI) throws ProponoException { + super("dummy", "dummy"); + this.atomService = atomService; + parseWorkspaceElement(e, baseURI); + } + + /** + * Package access to parent service. + */ + ClientAtomService getAtomService() { + return atomService; + } + + /** Deserialize a Atom workspace XML element into an object */ + protected void parseWorkspaceElement(final Element element, final String baseURI) throws ProponoException { + final Element titleElem = element.getChild("title", AtomService.ATOM_FORMAT); + setTitle(titleElem.getText()); + if (titleElem.getAttribute("type", AtomService.ATOM_FORMAT) != null) { + setTitleType(titleElem.getAttribute("type", AtomService.ATOM_FORMAT).getValue()); + } + final List collections = element.getChildren("collection", AtomService.ATOM_PROTOCOL); + for (final Element e : collections) { + addCollection(new ClientCollection(e, this, baseURI)); + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/EntryIterator.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/EntryIterator.java new file mode 100644 index 0000000..a92d2ba --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/EntryIterator.java @@ -0,0 +1,129 @@ +/* + * Copyright 2007 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.rometools.propono.atom.client; + +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.apache.commons.httpclient.methods.GetMethod; +import org.jdom2.Document; +import org.jdom2.input.SAXBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.propono.utils.ProponoException; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.feed.atom.Feed; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.io.WireFeedInput; + +/** + * Enables iteration over entries in Atom protocol collection. + */ +public class EntryIterator implements Iterator { + + private static final Logger LOG = LoggerFactory.getLogger(EntryIterator.class); + + private final ClientCollection collection; + + private Iterator members = null; + private Feed col = null; + private final String collectionURI; + private String nextURI; + + EntryIterator(final ClientCollection collection) throws ProponoException { + this.collection = collection; + collectionURI = collection.getHrefResolved(); + nextURI = collectionURI; + getNextEntries(); + } + + /** + * Returns true if more entries are available. + */ + @Override + public boolean hasNext() { + if (!members.hasNext()) { + try { + getNextEntries(); + } catch (final Exception ignored) { + LOG.error("An error occured while getting next entries", ignored); + } + } + return members.hasNext(); + } + + /** + * Get next entry in collection. + */ + @Override + public ClientEntry next() { + if (hasNext()) { + final Entry romeEntry = members.next(); + try { + if (!romeEntry.isMediaEntry()) { + return new ClientEntry(null, collection, romeEntry, true); + } else { + return new ClientMediaEntry(null, collection, romeEntry, true); + } + } catch (final ProponoException e) { + throw new RuntimeException("Unexpected exception creating ClientEntry or ClientMedia", e); + } + } + throw new NoSuchElementException(); + } + + /** + * Remove entry is not implemented. + */ + @Override + public void remove() { + // optional method, not implemented + } + + private void getNextEntries() throws ProponoException { + if (nextURI == null) { + return; + } + final GetMethod colGet = new GetMethod(collection.getHrefResolved(nextURI)); + collection.addAuthentication(colGet); + try { + collection.getHttpClient().executeMethod(colGet); + final SAXBuilder builder = new SAXBuilder(); + final Document doc = builder.build(colGet.getResponseBodyAsStream()); + final WireFeedInput feedInput = new WireFeedInput(); + col = (Feed) feedInput.build(doc); + } catch (final Exception e) { + throw new ProponoException("ERROR: fetching or parsing next entries, HTTP code: " + (colGet != null ? colGet.getStatusCode() : -1), e); + } finally { + colGet.releaseConnection(); + } + members = col.getEntries().iterator(); + col.getEntries().size(); + + nextURI = null; + final List altLinks = col.getOtherLinks(); + if (altLinks != null) { + for (final Link link : altLinks) { + if ("next".equals(link.getRel())) { + nextURI = link.getHref(); + } + } + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/GDataAuthStrategy.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/GDataAuthStrategy.java new file mode 100644 index 0000000..0912397 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/GDataAuthStrategy.java @@ -0,0 +1,64 @@ +/* + * Copyright 2009 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.atom.client; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethodBase; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.PostMethod; + +import com.rometools.propono.utils.ProponoException; + +public class GDataAuthStrategy implements AuthStrategy { + private final String email; + private final String password; + private final String service; + private String authToken; + + public GDataAuthStrategy(final String email, final String password, final String service) throws ProponoException { + this.email = email; + this.password = password; + this.service = service; + init(); + } + + private void init() throws ProponoException { + try { + final HttpClient httpClient = new HttpClient(); + final PostMethod method = new PostMethod("https://www.google.com/accounts/ClientLogin"); + final NameValuePair[] data = { new NameValuePair("Email", email), new NameValuePair("Passwd", password), + new NameValuePair("accountType", "GOOGLE"), new NameValuePair("service", service), + new NameValuePair("source", "ROME Propono Atompub Client") }; + method.setRequestBody(data); + httpClient.executeMethod(method); + + final String responseBody = method.getResponseBodyAsString(); + final int authIndex = responseBody.indexOf("Auth="); + + authToken = "GoogleLogin auth=" + responseBody.trim().substring(authIndex + 5); + + } catch (final Throwable t) { + t.printStackTrace(); + throw new ProponoException("ERROR obtaining Google authentication string", t); + } + } + + @Override + public void addAuthentication(final HttpClient httpClient, final HttpMethodBase method) throws ProponoException { + httpClient.getParams().setAuthenticationPreemptive(true); + method.setRequestHeader("Authorization", authToken); + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/NoAuthStrategy.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/NoAuthStrategy.java new file mode 100644 index 0000000..2d45687 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/NoAuthStrategy.java @@ -0,0 +1,33 @@ +/* + * Copyright 2009 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.atom.client; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethodBase; + +import com.rometools.propono.utils.ProponoException; + +/** + * No authentication + */ +public class NoAuthStrategy implements AuthStrategy { + + @Override + public void addAuthentication(final HttpClient httpClient, final HttpMethodBase method) throws ProponoException { + // no-op + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/OAuthStrategy.java b/rome-propono/src/main/java/com/rometools/propono/atom/client/OAuthStrategy.java new file mode 100644 index 0000000..ae610f6 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/client/OAuthStrategy.java @@ -0,0 +1,295 @@ +/* + * Copyright 2009 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.atom.client; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import net.oauth.OAuth; +import net.oauth.OAuthAccessor; +import net.oauth.OAuthConsumer; +import net.oauth.OAuthMessage; +import net.oauth.OAuthServiceProvider; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethodBase; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.util.ParameterParser; + +import com.rometools.propono.utils.ProponoException; + +/** + * Strategy for using OAuth. + */ +public class OAuthStrategy implements AuthStrategy { + + private State state = State.UNAUTHORIZED; + + private enum State { + UNAUTHORIZED, // have not sent any requests + REQUEST_TOKEN, // have a request token + AUTHORIZED, // are authorized + ACCESS_TOKEN // have access token, ready to make calls + } + + private final String username; + private final String consumerKey; + private final String consumerSecret; + private final String keyType; + + private final String reqUrl; + private final String authzUrl; + private final String accessUrl; + + private final String nonce; + private final long timestamp; + + private String requestToken = null; + private String accessToken = null; + private String tokenSecret = null; + + /** + * Create OAuth authentcation strategy and negotiate with services to obtain access token to be + * used in subsequent calls. + * + * @param username Username to be used in authentication + * @param key Consumer key + * @param secret Consumer secret + * @param keyType Key type (e.g. "HMAC-SHA1") + * @param reqUrl URL of request token service + * @param authzUrl URL of authorize service + * @param accessUrl URL of acess token service + * @throws ProponoException on any sort of initialization error + */ + public OAuthStrategy(final String username, final String key, final String secret, final String keyType, final String reqUrl, final String authzUrl, + final String accessUrl) throws ProponoException { + + this.username = username; + this.reqUrl = reqUrl; + this.authzUrl = authzUrl; + this.accessUrl = accessUrl; + consumerKey = key; + consumerSecret = secret; + this.keyType = keyType; + + nonce = UUID.randomUUID().toString(); + timestamp = new Date().getTime() / 1000L; + + init(); + } + + private void init() throws ProponoException { + callOAuthUri(reqUrl); + callOAuthUri(authzUrl); + callOAuthUri(accessUrl); + } + + @Override + public void addAuthentication(final HttpClient httpClient, final HttpMethodBase method) throws ProponoException { + + if (state != State.ACCESS_TOKEN) { + throw new ProponoException("ERROR: authentication strategy failed init"); + } + + // add OAuth name/values to request query string + + // wish we didn't have to parse them apart first, ugh + List originalqlist = null; + if (method.getQueryString() != null) { + String qstring = method.getQueryString().trim(); + qstring = qstring.startsWith("?") ? qstring.substring(1) : qstring; + @SuppressWarnings("unchecked") + final List parameters = new ParameterParser().parse(qstring, '&'); + originalqlist = parameters; + } else { + originalqlist = new ArrayList(); + } + + // put query string into hashmap form to please OAuth.net classes + final Map params = new HashMap(); + for (final Object element : originalqlist) { + final NameValuePair pair = (NameValuePair) element; + params.put(pair.getName(), pair.getValue()); + } + + // add OAuth params to query string + params.put("xoauth_requestor_id", username); + params.put("oauth_consumer_key", consumerKey); + params.put("oauth_signature_method", keyType); + params.put("oauth_timestamp", Long.toString(timestamp)); + params.put("oauth_nonce", nonce); + params.put("oauth_token", accessToken); + params.put("oauth_token_secret", tokenSecret); + + // sign complete URI + String finalUri = null; + final OAuthServiceProvider provider = new OAuthServiceProvider(reqUrl, authzUrl, accessUrl); + final OAuthConsumer consumer = new OAuthConsumer(null, consumerKey, consumerSecret, provider); + final OAuthAccessor accessor = new OAuthAccessor(consumer); + accessor.tokenSecret = tokenSecret; + OAuthMessage message; + try { + message = new OAuthMessage(method.getName(), method.getURI().toString(), params.entrySet()); + message.sign(accessor); + + finalUri = OAuth.addParameters(message.URL, message.getParameters()); + + } catch (final Exception ex) { + throw new ProponoException("ERROR: OAuth signing request", ex); + } + + // pull query string off and put it back onto method + method.setQueryString(finalUri.substring(finalUri.lastIndexOf("?"))); + } + + private void callOAuthUri(final String uri) throws ProponoException { + + final HttpClient httpClient = new HttpClient(); + + final HttpMethodBase method; + final String content; + + final Map params = new HashMap(); + params.put("oauth_version", "1.0"); + if (username != null) { + params.put("xoauth_requestor_id", username); + } + params.put("oauth_consumer_key", consumerKey); + params.put("oauth_signature_method", keyType); + params.put("oauth_timestamp", Long.toString(timestamp)); + params.put("oauth_nonce", nonce); + params.put("oauth_callback", "none"); + + final OAuthServiceProvider provider = new OAuthServiceProvider(reqUrl, authzUrl, accessUrl); + final OAuthConsumer consumer = new OAuthConsumer(null, consumerKey, consumerSecret, provider); + final OAuthAccessor accessor = new OAuthAccessor(consumer); + + if (state == State.UNAUTHORIZED) { + + try { + final OAuthMessage message = new OAuthMessage("GET", uri, params.entrySet()); + message.sign(accessor); + + final String finalUri = OAuth.addParameters(message.URL, message.getParameters()); + method = new GetMethod(finalUri); + httpClient.executeMethod(method); + content = method.getResponseBodyAsString(); + + } catch (final Exception e) { + throw new ProponoException("ERROR fetching request token", e); + } + + } else if (state == State.REQUEST_TOKEN) { + + try { + params.put("oauth_token", requestToken); + params.put("oauth_token_secret", tokenSecret); + accessor.tokenSecret = tokenSecret; + + final OAuthMessage message = new OAuthMessage("POST", uri, params.entrySet()); + message.sign(accessor); + + final String finalUri = OAuth.addParameters(message.URL, message.getParameters()); + method = new PostMethod(finalUri); + httpClient.executeMethod(method); + content = method.getResponseBodyAsString(); + + } catch (final Exception e) { + throw new ProponoException("ERROR fetching request token", e); + } + + } else if (state == State.AUTHORIZED) { + + try { + params.put("oauth_token", accessToken); + params.put("oauth_token_secret", tokenSecret); + accessor.tokenSecret = tokenSecret; + + final OAuthMessage message = new OAuthMessage("GET", uri, params.entrySet()); + message.sign(accessor); + + final String finalUri = OAuth.addParameters(message.URL, message.getParameters()); + method = new GetMethod(finalUri); + httpClient.executeMethod(method); + content = method.getResponseBodyAsString(); + + } catch (final Exception e) { + throw new ProponoException("ERROR fetching request token", e); + } + + } else { + method = null; + content = null; + return; + } + + String token = null; + String secret = null; + + if (content != null) { + final String[] settings = content.split("&"); + for (final String setting2 : settings) { + final String[] setting = setting2.split("="); + if (setting.length > 1) { + if ("oauth_token".equals(setting[0])) { + token = setting[1]; + } else if ("oauth_token_secret".equals(setting[0])) { + secret = setting[1]; + } + } + } + } + + // TODO review switch without 'default' + + switch (state) { + + case UNAUTHORIZED: + if (token != null && secret != null) { + requestToken = token; + tokenSecret = secret; + state = State.REQUEST_TOKEN; + } else { + throw new ProponoException("ERROR: requestToken or tokenSecret is null"); + } + break; + + case REQUEST_TOKEN: + if (method.getStatusCode() == 200) { + state = State.AUTHORIZED; + } else { + throw new ProponoException("ERROR: authorization returned code: " + method.getStatusCode()); + } + break; + + case AUTHORIZED: + if (token != null && secret != null) { + accessToken = token; + tokenSecret = secret; + state = State.ACCESS_TOKEN; + } else { + throw new ProponoException("ERROR: accessToken or tokenSecret is null"); + } + break; + } + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/client/atomclient-diagram.gif b/rome-propono/src/main/java/com/rometools/propono/atom/client/atomclient-diagram.gif new file mode 100644 index 0000000..21b1094 Binary files /dev/null and b/rome-propono/src/main/java/com/rometools/propono/atom/client/atomclient-diagram.gif differ diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/common/AtomService.java b/rome-propono/src/main/java/com/rometools/propono/atom/common/AtomService.java new file mode 100644 index 0000000..43d8a64 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/common/AtomService.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.common; + +import java.util.ArrayList; +import java.util.List; + +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.propono.utils.ProponoException; + +/** + * Models an Atom Publishing Protocol Service Document. Is able to read a Service document from a + * JDOM Document and to write Service document out as a JDOM Document. + */ +public class AtomService { + + private List workspaces = new ArrayList(); + + /** Namespace for Atom Syndication Format */ + public static Namespace ATOM_FORMAT = Namespace.getNamespace("atom", "http://www.w3.org/2005/Atom"); + + /** Namespace for Atom Publishing Protocol */ + public static Namespace ATOM_PROTOCOL = Namespace.getNamespace("app", "http://www.w3.org/2007/app"); + + /** + * Create new and empty Atom service + */ + public AtomService() { + } + + /** + * Add Workspace to service. + */ + public void addWorkspace(final Workspace workspace) { + workspaces.add(workspace); + } + + /** + * Get Workspaces available from service. + */ + public List getWorkspaces() { + return workspaces; + } + + /** + * Set Workspaces of service. + */ + public void setWorkspaces(final List workspaces) { + this.workspaces = workspaces; + } + + /** + * Find workspace by title. + * + * @param title Match this title + * @return Matching Workspace or null if none found. + */ + public Workspace findWorkspace(final String title) { + for (final Object element : workspaces) { + final Workspace ws = (Workspace) element; + if (title.equals(ws.getTitle())) { + return ws; + } + } + return null; + } + + /** + * Deserialize an Atom service XML document into an object + */ + public static AtomService documentToService(final Document document) throws ProponoException { + final AtomService service = new AtomService(); + final Element root = document.getRootElement(); + final List spaces = root.getChildren("workspace", ATOM_PROTOCOL); + for (final Element e : spaces) { + service.addWorkspace(Workspace.elementToWorkspace(e)); + } + return service; + } + + /** + * Serialize an AtomService object into an XML document + */ + public Document serviceToDocument() { + final AtomService service = this; + + final Document doc = new Document(); + final Element root = new Element("service", ATOM_PROTOCOL); + doc.setRootElement(root); + final List spaces = service.getWorkspaces(); + for (final Workspace space : spaces) { + root.addContent(space.workspaceToElement()); + } + return doc; + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/common/Categories.java b/rome-propono/src/main/java/com/rometools/propono/atom/common/Categories.java new file mode 100644 index 0000000..c3bde6e --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/common/Categories.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.common; + +import java.util.ArrayList; +import java.util.List; + +import org.jdom2.Element; + +import com.rometools.rome.feed.atom.Category; +import com.rometools.rome.io.impl.Atom10Parser; + +/** + * Models an Atom protocol Categories element, which may contain ROME Atom + * {@link com.rometools.rome.feed.atom.Category} elements. + */ +public class Categories { + + private final List categories = new ArrayList(); + private String baseURI = null; + private Element categoriesElement = null; + private String href = null; + private String scheme = null; + private boolean fixed = false; + + public Categories() { + } + + /** Load select from XML element */ + public Categories(final Element e, final String baseURI) { + categoriesElement = e; + this.baseURI = baseURI; + parseCategoriesElement(e); + } + + /** Add category list of those specified */ + public void addCategory(final Category cat) { + categories.add(cat); + } + + /** + * Iterate over Category objects + * + * @return List of ROME Atom {@link com.rometools.rome.feed.atom.Category} + */ + public List getCategories() { + return categories; + } + + /** True if clients MUST use one of the categories specified */ + public boolean isFixed() { + return fixed; + } + + /** True if clients MUST use one of the categories specified */ + public void setFixed(final boolean fixed) { + this.fixed = fixed; + } + + /** Category URI scheme to use for Categories without a scheme */ + public String getScheme() { + return scheme; + } + + /** Category URI scheme to use for Categories without a scheme */ + public void setScheme(final String scheme) { + this.scheme = scheme; + } + + /** URI of out-of-line categories */ + public String getHref() { + return href; + } + + /** URI of out-of-line categories */ + public void setHref(final String href) { + this.href = href; + } + + /** Get unresolved URI of the collection, or null if impossible to determine */ + public String getHrefResolved() { + if (Atom10Parser.isAbsoluteURI(href)) { + return href; + } else if (baseURI != null && categoriesElement != null) { + return Atom10Parser.resolveURI(baseURI, categoriesElement, href); + } + return null; + } + + public Element categoriesToElement() { + final Categories cats = this; + final Element catsElem = new Element("categories", AtomService.ATOM_PROTOCOL); + catsElem.setAttribute("fixed", cats.isFixed() ? "yes" : "no", AtomService.ATOM_PROTOCOL); + if (cats.getScheme() != null) { + catsElem.setAttribute("scheme", cats.getScheme(), AtomService.ATOM_PROTOCOL); + } + if (cats.getHref() != null) { + catsElem.setAttribute("href", cats.getHref(), AtomService.ATOM_PROTOCOL); + } else { + // Loop to create elements + for (final Object element : cats.getCategories()) { + final Category cat = (Category) element; + final Element catElem = new Element("category", AtomService.ATOM_FORMAT); + catElem.setAttribute("term", cat.getTerm(), AtomService.ATOM_FORMAT); + if (cat.getScheme() != null) { // optional + catElem.setAttribute("scheme", cat.getScheme(), AtomService.ATOM_FORMAT); + } + if (cat.getLabel() != null) { // optional + catElem.setAttribute("label", cat.getLabel(), AtomService.ATOM_FORMAT); + } + catsElem.addContent(catElem); + } + } + return catsElem; + } + + protected void parseCategoriesElement(final Element catsElem) { + + if (catsElem.getAttribute("href", AtomService.ATOM_PROTOCOL) != null) { + setHref(catsElem.getAttribute("href", AtomService.ATOM_PROTOCOL).getValue()); + } + + if (catsElem.getAttribute("fixed", AtomService.ATOM_PROTOCOL) != null) { + if ("yes".equals(catsElem.getAttribute("fixed", AtomService.ATOM_PROTOCOL).getValue())) { + setFixed(true); + } + } + + if (catsElem.getAttribute("scheme", AtomService.ATOM_PROTOCOL) != null) { + setScheme(catsElem.getAttribute("scheme", AtomService.ATOM_PROTOCOL).getValue()); + } + + // Loop to parse elemenents to Category objects + final List catElems = catsElem.getChildren("category", AtomService.ATOM_FORMAT); + for (final Element catElem : catElems) { + final Category cat = new Category(); + cat.setTerm(catElem.getAttributeValue("term", AtomService.ATOM_FORMAT)); + cat.setLabel(catElem.getAttributeValue("label", AtomService.ATOM_FORMAT)); + cat.setScheme(catElem.getAttributeValue("scheme", AtomService.ATOM_FORMAT)); + addCategory(cat); + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/common/Collection.java b/rome-propono/src/main/java/com/rometools/propono/atom/common/Collection.java new file mode 100644 index 0000000..9fb0834 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/common/Collection.java @@ -0,0 +1,258 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.common; + +import java.util.ArrayList; +import java.util.List; + +import org.jdom2.Element; + +import com.rometools.propono.utils.ProponoException; +import com.rometools.rome.io.impl.Atom10Parser; + +/** + * Models an Atom workspace collection. + */ +public class Collection { + + public static final String ENTRY_TYPE = "application/atom+xml;type=entry"; + + private final List categories = new ArrayList(); + + private Element collectionElement = null; + private String baseURI = null; + private String title = null; + private String titleType = null; // may be TEXT, HTML, XHTML + private List accepts = new ArrayList(); + private String href = null; + + /** + * Collection MUST have title and href. + * + * @param title Title for collection + * @param titleType Content type of title (null for plain text) + * @param href Collection URI. + */ + public Collection(final String title, final String titleType, final String href) { + this.title = title; + this.titleType = titleType; + this.href = href; + } + + /** Load self from XML element */ + public Collection(final Element e) throws ProponoException { + collectionElement = e; + parseCollectionElement(e); + } + + /** Load self from XML element and base URI for resolving relative URIs */ + public Collection(final Element e, final String baseURI) throws ProponoException { + collectionElement = e; + this.baseURI = baseURI; + parseCollectionElement(e); + } + + /** + * List of content-type ranges accepted by collection. + */ + public List getAccepts() { + return accepts; + } + + public void addAccept(final String accept) { + accepts.add(accept); + } + + public void setAccepts(final List accepts) { + this.accepts = accepts; + } + + /** The URI of the collection */ + public String getHref() { + return href; + } + + /** + * Set URI of collection + */ + public void setHref(final String href) { + this.href = href; + } + + /** Get resolved URI of the collection, or null if impossible to determine */ + public String getHrefResolved() { + if (Atom10Parser.isAbsoluteURI(href)) { + return href; + } else if (baseURI != null && collectionElement != null) { + final int lastslash = baseURI.lastIndexOf("/"); + return Atom10Parser.resolveURI(baseURI.substring(0, lastslash), collectionElement, href); + } + return null; + } + + /** Get resolved URI using collection's baseURI, or null if impossible to determine */ + public String getHrefResolved(final String relativeUri) { + if (Atom10Parser.isAbsoluteURI(relativeUri)) { + return relativeUri; + } else if (baseURI != null && collectionElement != null) { + final int lastslash = baseURI.lastIndexOf("/"); + return Atom10Parser.resolveURI(baseURI.substring(0, lastslash), collectionElement, relativeUri); + } + return null; + } + + /** Must have human readable title */ + public String getTitle() { + return title; + } + + /** + * Set title of collection. + */ + public void setTitle(final String title) { + this.title = title; + } + + /** + * Type of title ("text", "html" or "xhtml") + */ + public String getTitleType() { + return titleType; + } + + /** + * Type of title ("text", "html" or "xhtml") + */ + public void setTitleType(final String titleType) { + this.titleType = titleType; + } + + /** Workspace can have multiple Categories objects */ + public void addCategories(final Categories cats) { + categories.add(cats); + } + + /** + * Get categories allowed by collection. + * + * @return Collection of {@link com.rometools.rome.propono.atom.common.Categories} objects. + */ + public List getCategories() { + return categories; + } + + /** + * Returns true if contentType is accepted by collection. + */ + public boolean accepts(final String ct) { + for (final Object element : accepts) { + final String accept = (String) element; + if (accept != null && accept.trim().equals("*/*")) { + return true; + } + final String entryType = "application/atom+xml"; + final boolean entry = entryType.equals(ct); + if (entry && null == accept) { + return true; + } else if (entry && "entry".equals(accept)) { + return true; + } else if (entry && entryType.equals(accept)) { + return true; + } else { + final String[] rules = accepts.toArray(new String[accepts.size()]); + for (final String rule2 : rules) { + String rule = rule2.trim(); + if (rule.equals(ct)) { + return true; + } + final int slashstar = rule.indexOf("/*"); + if (slashstar > 0) { + rule = rule.substring(0, slashstar + 1); + if (ct.startsWith(rule)) { + return true; + } + } + } + } + } + return false; + } + + /** + * Serialize an AtomService.Collection into an XML element + */ + public Element collectionToElement() { + final Collection collection = this; + final Element element = new Element("collection", AtomService.ATOM_PROTOCOL); + element.setAttribute("href", collection.getHref()); + + final Element titleElem = new Element("title", AtomService.ATOM_FORMAT); + titleElem.setText(collection.getTitle()); + if (collection.getTitleType() != null && !collection.getTitleType().equals("TEXT")) { + titleElem.setAttribute("type", collection.getTitleType(), AtomService.ATOM_FORMAT); + } + element.addContent(titleElem); + + // Loop to create elements + for (final Object element2 : collection.getCategories()) { + final Categories cats = (Categories) element2; + element.addContent(cats.categoriesToElement()); + } + + for (final Object element2 : collection.getAccepts()) { + final String range = (String) element2; + final Element acceptElem = new Element("accept", AtomService.ATOM_PROTOCOL); + acceptElem.setText(range); + element.addContent(acceptElem); + } + + return element; + } + + /** Deserialize an Atom service collection XML element into an object */ + public Collection elementToCollection(final Element element) throws ProponoException { + return new Collection(element); + } + + protected void parseCollectionElement(final Element element) throws ProponoException { + setHref(element.getAttribute("href").getValue()); + + final Element titleElem = element.getChild("title", AtomService.ATOM_FORMAT); + if (titleElem != null) { + setTitle(titleElem.getText()); + if (titleElem.getAttribute("type", AtomService.ATOM_FORMAT) != null) { + setTitleType(titleElem.getAttribute("type", AtomService.ATOM_FORMAT).getValue()); + } + } + + final List acceptElems = element.getChildren("accept", AtomService.ATOM_PROTOCOL); + if (acceptElems != null && !acceptElems.isEmpty()) { + for (final Element acceptElem : acceptElems) { + addAccept(acceptElem.getTextTrim()); + } + } + + // Loop to parse element to Categories objects + final List catsElems = element.getChildren("categories", AtomService.ATOM_PROTOCOL); + for (final Element catsElem : catsElems) { + final Categories cats = new Categories(catsElem, baseURI); + addCategories(cats); + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/common/Workspace.java b/rome-propono/src/main/java/com/rometools/propono/atom/common/Workspace.java new file mode 100644 index 0000000..c7452c2 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/common/Workspace.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.common; + +import java.util.ArrayList; +import java.util.List; + +import org.jdom2.Element; + +import com.rometools.propono.utils.ProponoException; + +/** + * Models an Atom workspace. + */ +public class Workspace { + + private String title = null; + private String titleType = null; // may be TEXT, HTML, XHTML + private final List collections = new ArrayList(); + + /** + * Collection MUST have title. + * + * @param title Title for collection + * @param titleType Content type of title (null for plain text) + */ + public Workspace(final String title, final String titleType) { + this.title = title; + this.titleType = titleType; + } + + public Workspace(final Element elem) throws ProponoException { + parseWorkspaceElement(elem); + } + + /** Iterate over collections in workspace */ + public List getCollections() { + return collections; + } + + /** Add new collection to workspace */ + public void addCollection(final Collection col) { + collections.add(col); + } + + /** + * DefaultWorkspace must have a human readable title + */ + public String getTitle() { + return title; + } + + /** + * Set title of workspace. + */ + public void setTitle(final String title) { + this.title = title; + } + + /** + * Get title type ("text", "html", "xhtml" or MIME content-type) + */ + public String getTitleType() { + return titleType; + } + + /** + * Set title type ("text", "html", "xhtml" or MIME content-type) + */ + public void setTitleType(final String titleType) { + this.titleType = titleType; + } + + /** + * Find collection by title and/or content-type. + * + * @param title Title or null to match all titles. + * @param contentType Content-type or null to match all content-types. + * @return First Collection that matches title and/or content-type. + */ + public Collection findCollection(final String title, final String contentType) { + for (final Object element : collections) { + final Collection col = (Collection) element; + if (title != null && col.accepts(contentType)) { + return col; + } else if (col.accepts(contentType)) { + return col; + } + } + return null; + } + + /** Deserialize a Atom workspace XML element into an object */ + public static Workspace elementToWorkspace(final Element element) throws ProponoException { + return new Workspace(element); + } + + /** + * Serialize an AtomService.DefaultWorkspace object into an XML element + */ + public Element workspaceToElement() { + final Workspace space = this; + + final Element element = new Element("workspace", AtomService.ATOM_PROTOCOL); + + final Element titleElem = new Element("title", AtomService.ATOM_FORMAT); + titleElem.setText(space.getTitle()); + if (space.getTitleType() != null && !space.getTitleType().equals("TEXT")) { + titleElem.setAttribute("type", space.getTitleType(), AtomService.ATOM_FORMAT); + } + element.addContent(titleElem); + + for (final Collection col : space.getCollections()) { + element.addContent(col.collectionToElement()); + } + + return element; + } + + /** Deserialize a Atom workspace XML element into an object */ + protected void parseWorkspaceElement(final Element element) throws ProponoException { + final Element titleElem = element.getChild("title", AtomService.ATOM_FORMAT); + setTitle(titleElem.getText()); + if (titleElem.getAttribute("type", AtomService.ATOM_FORMAT) != null) { + setTitleType(titleElem.getAttribute("type", AtomService.ATOM_FORMAT).getValue()); + } + final List collections = element.getChildren("collection", AtomService.ATOM_PROTOCOL); + for (final Element e : collections) { + addCollection(new Collection(e)); + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModule.java b/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModule.java new file mode 100644 index 0000000..dde22be --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModule.java @@ -0,0 +1,44 @@ +/* + * Copyright 2007 Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.common.rome; + +import java.util.Date; + +import com.rometools.rome.feed.module.Module; + +/** + * ROME Extension Module to Atom protocol extensions to Atom format. + */ +public interface AppModule extends Module { + + public static final String URI = "http://www.w3.org/2007/app"; + + /** True if entry is a draft */ + public Boolean getDraft(); + + /** Set to true if entry is a draft */ + public void setDraft(Boolean draft); + + /** Time of last edit */ + public Date getEdited(); + + /** Set time of last edit */ + public void setEdited(Date edited); +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModuleGenerator.java b/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModuleGenerator.java new file mode 100644 index 0000000..7f57b6d --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModuleGenerator.java @@ -0,0 +1,87 @@ +/* + * Copyright 2007 Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.common.rome; + +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import java.util.TimeZone; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleGenerator; + +/** + * Creates JDOM representation for APP Extension Module. + */ +public class AppModuleGenerator implements ModuleGenerator { + + private static final Namespace APP_NS = Namespace.getNamespace("app", AppModule.URI); + + @Override + public String getNamespaceUri() { + return AppModule.URI; + } + + private static final Set NAMESPACES; + + static { + final Set nss = new HashSet(); + nss.add(APP_NS); + NAMESPACES = Collections.unmodifiableSet(nss); + } + + /** Get namespaces associated with this module */ + @Override + public Set getNamespaces() { + return NAMESPACES; + } + + /** Generate JDOM element for module and add it to parent element */ + @Override + public void generate(final Module module, final Element parent) { + final AppModule m = (AppModule) module; + + if (m.getDraft() != null) { + final String draft = m.getDraft().booleanValue() ? "yes" : "no"; + final Element control = new Element("control", APP_NS); + control.addContent(generateSimpleElement("draft", draft)); + parent.addContent(control); + } + if (m.getEdited() != null) { + final Element edited = new Element("edited", APP_NS); + // Inclulde millis in date/time + final SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); + dateFormater.setTimeZone(TimeZone.getTimeZone("GMT")); + edited.addContent(dateFormater.format(m.getEdited())); + parent.addContent(edited); + } + } + + private Element generateSimpleElement(final String name, final String value) { + final Element element = new Element(name, APP_NS); + element.addContent(value); + return element; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModuleImpl.java b/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModuleImpl.java new file mode 100644 index 0000000..c1a42e3 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModuleImpl.java @@ -0,0 +1,80 @@ +/* + * Copyright 2007 Apache Software Foundation + * Copyright 2011 The ROME Teams + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.common.rome; + +import java.util.Date; + +import com.rometools.rome.feed.CopyFrom; +import com.rometools.rome.feed.module.ModuleImpl; + +/** + * Bean representation of APP module. + */ +public class AppModuleImpl extends ModuleImpl implements AppModule { + + private static final long serialVersionUID = 1L; + + private boolean draft = false; + private Date edited = null; + + public AppModuleImpl() { + super(AppModule.class, AppModule.URI); + } + + /** True if entry is draft */ + @Override + public Boolean getDraft() { + return draft ? Boolean.TRUE : Boolean.FALSE; + } + + /** Set to true if entry is draft */ + @Override + public void setDraft(final Boolean draft) { + this.draft = draft.booleanValue(); + } + + /** Time of last edit */ + @Override + public Date getEdited() { + return edited; + } + + /** Set time of last edit */ + @Override + public void setEdited(final Date edited) { + this.edited = edited; + } + + /** Get interface class of module */ + @Override + public Class getInterface() { + return AppModule.class; + } + + /** Copy from other module */ + @Override + public void copyFrom(final CopyFrom obj) { + final AppModule m = (AppModule) obj; + setDraft(m.getDraft()); + setEdited(m.getEdited()); + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModuleParser.java b/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModuleParser.java new file mode 100644 index 0000000..a9d0e87 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/common/rome/AppModuleParser.java @@ -0,0 +1,72 @@ +/* + * Copyright 2007 Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.common.rome; + +import java.util.Locale; + +import org.jdom2.Element; +import org.jdom2.Namespace; + +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.ModuleParser; +import com.rometools.rome.io.impl.DateParser; + +/** + * Parses APP module information from a JDOM element and into AppModule form. + */ +public class AppModuleParser implements ModuleParser { + + /** Get URI of module namespace */ + @Override + public String getNamespaceUri() { + return AppModule.URI; + } + + /** Get namespace of module */ + public Namespace getContentNamespace() { + return Namespace.getNamespace(AppModule.URI); + } + + /** Parse JDOM element into module */ + @Override + public Module parse(final Element elem, final Locale locale) { + final AppModule m = new AppModuleImpl(); + final Element control = elem.getChild("control", getContentNamespace()); + if (control != null) { + final Element draftElem = control.getChild("draft", getContentNamespace()); + if (draftElem != null) { + if ("yes".equals(draftElem.getText())) { + m.setDraft(Boolean.TRUE); + } + if ("no".equals(draftElem.getText())) { + m.setDraft(Boolean.FALSE); + } + } + } + final Element edited = elem.getChild("edited", getContentNamespace()); + if (edited != null) { + try { + m.setEdited(DateParser.parseW3CDateTime(edited.getTextTrim(), locale)); + } catch (final Exception ignored) { + } + } + return m; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomException.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomException.java new file mode 100644 index 0000000..c8d06e4 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomException.java @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.server; + +import javax.servlet.http.HttpServletResponse; + +/** + * Exception thrown by {@link com.rometools.rome.propono.atom.server.AtomHandler} and extended by + * other Propono Atom exception classes. + */ +public class AtomException extends Exception { + + private static final long serialVersionUID = 1L; + + /** Construct new exception */ + public AtomException() { + super(); + } + + /** Construct new exception with message */ + public AtomException(final String msg) { + super(msg); + } + + /** Contruct new exception with message and wrapping existing exception */ + public AtomException(final String msg, final Throwable t) { + super(msg, t); + } + + /** Construct new exception to wrap existing one. */ + public AtomException(final Throwable t) { + super(t); + } + + /* Get HTTP status code associated with exception (HTTP 500 server error) */ + /** + * Get HTTP status associated with exception. + */ + public int getStatus() { + return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomHandler.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomHandler.java new file mode 100644 index 0000000..f08762b --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomHandler.java @@ -0,0 +1,150 @@ +/* + * Copyright 2007 Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.server; + +import com.rometools.propono.atom.common.AtomService; +import com.rometools.propono.atom.common.Categories; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.feed.atom.Feed; + +/** + * Interface for handling single Atom protocol requests. + * + *

      + * To create your own Atom protocol implementation you must implement this interface and create a + * concrete sub-class of {@link com.rometools.rome.propono.atom.server.AtomHandlerFactory} which is + * capable of instantiating it. + *

      + */ +public interface AtomHandler { + /** + * Get username of authenticated user. Return the username of the authenticated user + */ + public String getAuthenticatedUsername(); + + /** + * Return {@link com.rometools.rome.propono.atom.common.AtomService} object that contains the + * {@link com.rometools.rome.propono.atom.common.Workspace} objects available to the currently + * authenticated user and within those the + * {@link com.rometools.rome.propono.atom.common.Collection} avalaible. + */ + public AtomService getAtomService(AtomRequest req) throws AtomException; + + /** + * Get categories, a list of Categories objects + */ + public Categories getCategories(AtomRequest req) throws AtomException; + + /** + * Return collection or portion of collection specified by request. + * + * @param req Details of HTTP request + */ + public Feed getCollection(AtomRequest req) throws AtomException; + + /** + * Store new entry in collection specified by request and return representation of entry as it + * is stored on server. + * + * @param req Details of HTTP request + * @return Location URL of new entry + */ + public Entry postEntry(AtomRequest req, Entry entry) throws AtomException; + + /** + * Get entry specified by request. + * + * @param req Details of HTTP request + */ + public Entry getEntry(AtomRequest req) throws AtomException; + + /** + * Get media resource specified by request. + * + * @param req Details of HTTP request + */ + public AtomMediaResource getMediaResource(AtomRequest req) throws AtomException; + + /** + * Update entry specified by request and return new entry as represented on the server. + * + * @param req Details of HTTP request + */ + public void putEntry(AtomRequest req, Entry entry) throws AtomException; + + /** + * Delete entry specified by request. + * + * @param req Details of HTTP request + */ + public void deleteEntry(AtomRequest req) throws AtomException; + + /** + * Store media data in collection specified by request, create an Atom media-link entry to store + * metadata for the new media file and return that entry to the caller. + * + * @param req Details of HTTP request + * @param entry New entry initialzied with only title and content type + * @return Location URL of new media entry + */ + public Entry postMedia(AtomRequest req, Entry entry) throws AtomException; + + /** + * Update the media file part of a media-link entry. + * + * @param req Details of HTTP request + */ + public void putMedia(AtomRequest req) throws AtomException; + + /** + * Return true if specified request represents URI of a Service Document. + * + * @param req Details of HTTP request + */ + public boolean isAtomServiceURI(AtomRequest req); + + /** + * Return true if specified request represents URI of a Categories Document. + * + * @param req Details of HTTP request + */ + public boolean isCategoriesURI(AtomRequest req); + + /** + * Return true if specified request represents URI of a collection. + * + * @param req Details of HTTP request + */ + public boolean isCollectionURI(AtomRequest req); + + /** + * Return true if specified request represents URI of an Atom entry. + * + * @param req Details of HTTP request + */ + public boolean isEntryURI(AtomRequest req); + + /** + * Return true if specified patrequesthinfo represents media-edit URI. + * + * @param req Details of HTTP request + */ + public boolean isMediaEditURI(AtomRequest req); +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomHandlerFactory.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomHandlerFactory.java new file mode 100644 index 0000000..3bd635f --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomHandlerFactory.java @@ -0,0 +1,100 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Defines a factory that enables the {@link com.rometools.rome.propono.atom.server.AtomServlet} to + * obtain an {@link com.rometools.rome.propono.atom.server.AtomHandler} that handles an Atom + * request. + * + *

      + * To create your own Atom protocol implementation you must sub-class this class with your own + * factory that is capable of creating instances of your + * {@link com.rometools.rome.propono.atom.server.AtomHandler} impementation. + *

      + */ +public abstract class AtomHandlerFactory { + + private static final Logger LOG = LoggerFactory.getLogger(AtomHandlerFactory.class); + + private static final String DEFAULT_PROPERTY_NAME = "com.rometools.propono.atom.server.AtomHandlerFactory"; + private static final String FALLBACK_IMPL_NAME = "com.rometools.propono.atom.server.impl.FileBasedAtomHandlerFactory"; + + /* + *

      Protected constructor to prevent instantiation. Use {@link #newInstance()}.

      + */ + protected AtomHandlerFactory() { + } + + /** + * Obtain a new instance of a AtomHandlerFactory. This static method creates a new + * factory instance. This method uses the following ordered lookup procedure to determine the + * AtomHandlerFactory implementation class to load: + *
        + *
      • + * Use the com.rometools.rome.propono.atom.server.AtomHandlerFactory system + * property.
      • + *
      • + * Use the properties file "/propono.properties" in the classpath. This configuration file is in + * standard java.util.Properties format and contains the fully qualified name of + * the implementation class with the key being the system property defined above. + * + * The propono.properties file is read only once by Propono and it's values are then cached for + * future use. If the file does not exist when the first attempt is made to read from it, no + * further attempts are made to check for its existence. It is not possible to change the value + * of any property in propono.properties after it has been read for the first time.
      • + *
      • + * If not available, to determine the classname. The Services API will look for a classname in + * the file: META-INF/services/com.rometools.rome.AtomHandlerFactory in jars + * available to the runtime.
      • + *
      • + * Platform default AtomHandlerFactory instance.
      • + *
      + * + * Once an application has obtained a reference to a AtomHandlerFactory it can use + * the factory to configure and obtain parser instances. + * + * @return New instance of a AtomHandlerFactory + * + * @throws FactoryConfigurationError if the implementation is not available or cannot be + * instantiated. + */ + public static AtomHandlerFactory newInstance() { + try { + return (AtomHandlerFactory) FactoryFinder.find(DEFAULT_PROPERTY_NAME, FALLBACK_IMPL_NAME); + } catch (final ConfigurationError e) { + LOG.error("An error occured while finding factory", e); + throw new FactoryConfigurationError(e.getException(), e.getMessage()); + } + } + + /** + * Creates a new instance of a {@link com.rometools.rome.propono.atom.server.AtomHandler} using + * the currently configured parameters. + * + * @return A new instance of a AtomHandler. + * + * @throws AtomConfigurationException if a AtomHandler cannot be created which satisfies the + * configuration requested. + */ + public abstract AtomHandler newAtomHandler(HttpServletRequest req, HttpServletResponse res); +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomMediaResource.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomMediaResource.java new file mode 100644 index 0000000..6b427d7 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomMediaResource.java @@ -0,0 +1,95 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.Date; + +import javax.activation.FileTypeMap; +import javax.activation.MimetypesFileTypeMap; + +/** + * Represents a media link entry. + */ +public class AtomMediaResource { + private String contentType = null; + private long contentLength = 0; + private InputStream inputStream = null; + private Date lastModified = null; + private static FileTypeMap map = null; + + static { + // TODO: figure out why PNG is missing from Java MIME types + map = FileTypeMap.getDefaultFileTypeMap(); + if (map instanceof MimetypesFileTypeMap) { + try { + ((MimetypesFileTypeMap) map).addMimeTypes("image/png png PNG"); + } catch (final Exception ignored) { + } + } + } + + public AtomMediaResource(final File resource) throws FileNotFoundException { + contentType = map.getContentType(resource.getName()); + contentLength = resource.length(); + lastModified = new Date(resource.lastModified()); + inputStream = new FileInputStream(resource); + } + + public AtomMediaResource(final String name, final long length, final Date lastModified, final InputStream is) throws FileNotFoundException { + contentType = map.getContentType(name); + contentLength = length; + this.lastModified = lastModified; + inputStream = is; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(final String contentType) { + this.contentType = contentType; + } + + public long getContentLength() { + return contentLength; + } + + public void setContentLength(final long contentLength) { + this.contentLength = contentLength; + } + + public InputStream getInputStream() { + return inputStream; + } + + public void setInputStream(final InputStream inputStream) { + this.inputStream = inputStream; + } + + public Date getLastModified() { + return lastModified; + } + + public void setLastModified(final Date lastModified) { + this.lastModified = lastModified; + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomNotAuthorizedException.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomNotAuthorizedException.java new file mode 100644 index 0000000..8cd2e00 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomNotAuthorizedException.java @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.server; + +import javax.servlet.http.HttpServletResponse; + +/** + * Exception to be thrown by AtomHandler implementations in the case that a user is not + * authorized to access a resource. + */ +public class AtomNotAuthorizedException extends AtomException { + + private static final long serialVersionUID = 1L; + + /** Construct new exception */ + public AtomNotAuthorizedException() { + super(); + } + + /** Construct new exception with message */ + public AtomNotAuthorizedException(final String msg) { + super(msg); + } + + /** Construct new exception with message and root cause */ + public AtomNotAuthorizedException(final String msg, final Throwable t) { + super(msg, t); + } + + /** Construct new exception to wrap root cause */ + public AtomNotAuthorizedException(final Throwable t) { + super(t); + } + + /** Get HTTP status code of exception (HTTP 403 unauthorized) */ + @Override + public int getStatus() { + return HttpServletResponse.SC_UNAUTHORIZED; + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomNotFoundException.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomNotFoundException.java new file mode 100644 index 0000000..4655656 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomNotFoundException.java @@ -0,0 +1,56 @@ +/* + * Copyright 2007 Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.server; + +import javax.servlet.http.HttpServletResponse; + +/** + * Exception thrown by AtomHandler in that case a resource is not found. + */ +public class AtomNotFoundException extends AtomException { + + private static final long serialVersionUID = 1L; + + /** Construct new exception */ + public AtomNotFoundException() { + super(); + } + + /** Construct new exception with message */ + public AtomNotFoundException(final String msg) { + super(msg); + } + + /** Construct new exception with message and root cause */ + public AtomNotFoundException(final String msg, final Throwable t) { + super(msg, t); + } + + /** Construct new exception with root cause */ + public AtomNotFoundException(final Throwable t) { + super(t); + } + + /** Get HTTP status code associated with exception (404 not found) */ + @Override + public int getStatus() { + return HttpServletResponse.SC_NOT_FOUND; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomRequest.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomRequest.java new file mode 100644 index 0000000..cb8d1a2 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomRequest.java @@ -0,0 +1,137 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.server; + +import java.io.IOException; +import java.io.InputStream; +import java.security.Principal; +import java.util.Enumeration; +import java.util.Map; + +/** + * Represents HTTP request to be processed by AtomHandler. + */ +public interface AtomRequest { + + /** + * Returns any extra path information associated with the URL the client sent when it made this + * request. + */ + public String getPathInfo(); + + /** + * Returns the query string that is contained in the request URL after the path. + */ + public String getQueryString(); + + /** + * Returns the login of the user making this request, if the user has been authenticated, or + * null if the user has not been authenticated. + */ + public String getRemoteUser(); + + /** + * Returns a boolean indicating whether the authenticated user is included in the specified + * logical "role". + */ + public boolean isUserInRole(String arg0); + + /** + * Returns a java.security.Principal object containing the name of the current authenticated + * user. + */ + public Principal getUserPrincipal(); + + /** + * Returns the part of this request's URL from the protocol name up to the query string in the + * first line of the HTTP request. + */ + public String getRequestURI(); + + /** + * Reconstructs the URL the client used to make the request. + */ + public StringBuffer getRequestURL(); + + /** + * Returns the length, in bytes, of the request body and made available by the input stream, or + * -1 if the length is not known. + */ + public int getContentLength(); + + /** + * Returns the MIME type of the body of the request, or null if the type is not known. + */ + public String getContentType(); + + /** + * Returns the value of a request parameter as a String, or null if the parameter does not + * exist. + */ + public String getParameter(String arg0); + + /** + * Returns an Enumeration of String objects containing the names of the parameters contained in + * this request. + */ + public Enumeration getParameterNames(); + + /** + * Returns an array of String objects containing all of the values the given request parameter + * has, or null if the parameter does not exist. + */ + public String[] getParameterValues(String arg0); + + /** + * Returns a java.util.Map of the parameters of this request. + */ + public Map getParameterMap(); + + /** + * Retrieves the body of the request as binary data using a ServletInputStream. + */ + public InputStream getInputStream() throws IOException; + + /** + * Returns the value of the specified request header as a long value that represents a Date + * object. + */ + public long getDateHeader(String arg0); + + /** + * Returns the value of the specified request header as a String. + */ + public String getHeader(String arg0); + + /** + * Returns all the values of the specified request header as an Enumeration of String objects. + */ + public Enumeration getHeaders(String arg0); + + /** + * Returns an enumeration of all the header names this request contains. + */ + public Enumeration getHeaderNames(); + + /** + * Returns the value of the specified request header as an int. + */ + public int getIntHeader(String arg0); +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomRequestImpl.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomRequestImpl.java new file mode 100644 index 0000000..3de3fc9 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomRequestImpl.java @@ -0,0 +1,139 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.server; + +import java.io.IOException; +import java.io.InputStream; +import java.security.Principal; +import java.util.Enumeration; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +/** + * Default request implementation. + */ +public class AtomRequestImpl implements AtomRequest { + + private HttpServletRequest wrapped = null; + + public AtomRequestImpl(final HttpServletRequest wrapped) { + this.wrapped = wrapped; + } + + @Override + public String getPathInfo() { + return wrapped.getPathInfo() != null ? wrapped.getPathInfo() : ""; + } + + @Override + public String getQueryString() { + return wrapped.getQueryString(); + } + + @Override + public String getRemoteUser() { + return wrapped.getRemoteUser(); + } + + @Override + public boolean isUserInRole(final String arg0) { + return wrapped.isUserInRole(arg0); + } + + @Override + public Principal getUserPrincipal() { + return wrapped.getUserPrincipal(); + } + + @Override + public String getRequestURI() { + return wrapped.getRequestURI(); + } + + @Override + public StringBuffer getRequestURL() { + return wrapped.getRequestURL(); + } + + @Override + public int getContentLength() { + return wrapped.getContentLength(); + } + + @Override + public String getContentType() { + return wrapped.getContentType(); + } + + @Override + public String getParameter(final String arg0) { + return wrapped.getParameter(arg0); + } + + @Override + @SuppressWarnings("unchecked") + public Enumeration getParameterNames() { + return wrapped.getParameterNames(); + } + + @Override + public String[] getParameterValues(final String arg0) { + return wrapped.getParameterValues(arg0); + } + + @Override + @SuppressWarnings("unchecked") + public Map getParameterMap() { + return wrapped.getParameterMap(); + } + + @Override + public InputStream getInputStream() throws IOException { + return wrapped.getInputStream(); + } + + @Override + public long getDateHeader(final String arg0) { + return wrapped.getDateHeader(arg0); + } + + @Override + public String getHeader(final String arg0) { + return wrapped.getHeader(arg0); + } + + @Override + @SuppressWarnings("unchecked") + public Enumeration getHeaders(final String arg0) { + return wrapped.getHeaders(arg0); + } + + @Override + @SuppressWarnings("unchecked") + public Enumeration getHeaderNames() { + return wrapped.getHeaderNames(); + } + + @Override + public int getIntHeader(final String arg0) { + return wrapped.getIntHeader(arg0); + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomServlet.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomServlet.java new file mode 100644 index 0000000..9933f33 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/AtomServlet.java @@ -0,0 +1,371 @@ +/* + * Copyright 2007 Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package com.rometools.propono.atom.server; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Writer; +import java.util.Collections; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.jdom2.Document; +import org.jdom2.output.Format; +import org.jdom2.output.XMLOutputter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.propono.atom.common.AtomService; +import com.rometools.propono.atom.common.Categories; +import com.rometools.propono.utils.Utilities; +import com.rometools.rome.feed.atom.Content; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.feed.atom.Feed; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.io.WireFeedOutput; +import com.rometools.rome.io.impl.Atom10Generator; +import com.rometools.rome.io.impl.Atom10Parser; + +/** + * Atom Servlet implements Atom protocol by calling an + * {@link com.rometools.rome.propono.atom.server.AtomHandler} implementation. This servlet takes + * care of parsing incoming XML into ROME Atom {@link com.rometools.rome.feed.atom.Entry} objects, + * passing those to the handler and serializing to the response the entries and feeds returned by + * the handler. + */ +public class AtomServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + /** + * Get feed type support by Servlet, "atom_1.0" + */ + public static final String FEED_TYPE = "atom_1.0"; + private static String contextDirPath = null; + + private static final Logger LOG = LoggerFactory.getLogger(AtomServlet.class); + + static { + Atom10Parser.setResolveURIs(true); + } + + // ----------------------------------------------------------------------------- + /** + * Create an Atom request handler. TODO: make AtomRequestHandler implementation configurable. + */ + private AtomHandler createAtomRequestHandler(final HttpServletRequest request, final HttpServletResponse response) throws ServletException { + final AtomHandlerFactory ahf = AtomHandlerFactory.newInstance(); + return ahf.newAtomHandler(request, response); + } + + // ----------------------------------------------------------------------------- + /** + * Handles an Atom GET by calling handler and writing results to response. + */ + @Override + protected void doGet(final HttpServletRequest req, final HttpServletResponse res) throws ServletException, IOException { + LOG.debug("Entering"); + final AtomHandler handler = createAtomRequestHandler(req, res); + final String userName = handler.getAuthenticatedUsername(); + if (userName != null) { + final AtomRequest areq = new AtomRequestImpl(req); + try { + if (handler.isAtomServiceURI(areq)) { + // return an Atom Service document + final AtomService service = handler.getAtomService(areq); + final Document doc = service.serviceToDocument(); + res.setContentType("application/atomsvc+xml; charset=utf-8"); + final Writer writer = res.getWriter(); + final XMLOutputter outputter = new XMLOutputter(); + outputter.setFormat(Format.getPrettyFormat()); + outputter.output(doc, writer); + writer.close(); + res.setStatus(HttpServletResponse.SC_OK); + } else if (handler.isCategoriesURI(areq)) { + final Categories cats = handler.getCategories(areq); + res.setContentType("application/xml"); + final Writer writer = res.getWriter(); + final Document catsDoc = new Document(); + catsDoc.setRootElement(cats.categoriesToElement()); + final XMLOutputter outputter = new XMLOutputter(); + outputter.output(catsDoc, writer); + writer.close(); + res.setStatus(HttpServletResponse.SC_OK); + } else if (handler.isCollectionURI(areq)) { + // return a collection + final Feed col = handler.getCollection(areq); + col.setFeedType(FEED_TYPE); + final WireFeedOutput wireFeedOutput = new WireFeedOutput(); + final Document feedDoc = wireFeedOutput.outputJDom(col); + res.setContentType("application/atom+xml; charset=utf-8"); + final Writer writer = res.getWriter(); + final XMLOutputter outputter = new XMLOutputter(); + outputter.setFormat(Format.getPrettyFormat()); + outputter.output(feedDoc, writer); + writer.close(); + res.setStatus(HttpServletResponse.SC_OK); + } else if (handler.isEntryURI(areq)) { + // return an entry + final Entry entry = handler.getEntry(areq); + if (entry != null) { + res.setContentType("application/atom+xml; type=entry; charset=utf-8"); + final Writer writer = res.getWriter(); + Atom10Generator.serializeEntry(entry, writer); + writer.close(); + } else { + res.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } else if (handler.isMediaEditURI(areq)) { + final AtomMediaResource entry = handler.getMediaResource(areq); + res.setContentType(entry.getContentType()); + res.setContentLength((int) entry.getContentLength()); + Utilities.copyInputToOutput(entry.getInputStream(), res.getOutputStream()); + res.getOutputStream().flush(); + res.getOutputStream().close(); + } else { + res.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } catch (final AtomException ae) { + res.sendError(ae.getStatus(), ae.getMessage()); + LOG.debug("An error occured while processing GET", ae); + } catch (final Exception e) { + res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + LOG.debug("An error occured while processing GET", e); + } + } else { + res.setHeader("WWW-Authenticate", "BASIC realm=\"AtomPub\""); + res.sendError(HttpServletResponse.SC_UNAUTHORIZED); + } + LOG.debug("Exiting"); + } + + // ----------------------------------------------------------------------------- + /** + * Handles an Atom POST by calling handler to identify URI, reading/parsing data, calling + * handler and writing results to response. + */ + @Override + protected void doPost(final HttpServletRequest req, final HttpServletResponse res) throws ServletException, IOException { + LOG.debug("Entering"); + final AtomHandler handler = createAtomRequestHandler(req, res); + final String userName = handler.getAuthenticatedUsername(); + if (userName != null) { + final AtomRequest areq = new AtomRequestImpl(req); + try { + if (handler.isCollectionURI(areq)) { + + if (req.getContentType().startsWith("application/atom+xml")) { + + // parse incoming entry + final Entry entry = Atom10Parser.parseEntry(new BufferedReader(new InputStreamReader(req.getInputStream(), "UTF-8")), null, Locale.US); + + // call handler to post it + final Entry newEntry = handler.postEntry(areq, entry); + + // set Location and Content-Location headers + for (final Object element : newEntry.getOtherLinks()) { + final Link link = (Link) element; + if ("edit".equals(link.getRel())) { + res.addHeader("Location", link.getHrefResolved()); + break; + } + } + for (final Object element : newEntry.getAlternateLinks()) { + final Link link = (Link) element; + if ("alternate".equals(link.getRel())) { + res.addHeader("Content-Location", link.getHrefResolved()); + break; + } + } + + // write entry back out to response + res.setStatus(HttpServletResponse.SC_CREATED); + res.setContentType("application/atom+xml; type=entry; charset=utf-8"); + + final Writer writer = res.getWriter(); + Atom10Generator.serializeEntry(newEntry, writer); + writer.close(); + + } else if (req.getContentType() != null) { + + // get incoming title and slug from HTTP header + final String title = areq.getHeader("Title"); + + // create new entry for resource, set title and type + final Entry resource = new Entry(); + resource.setTitle(title); + final Content content = new Content(); + content.setType(areq.getContentType()); + resource.setContents(Collections.singletonList(content)); + + // hand input stream off to hander to post file + final Entry newEntry = handler.postMedia(areq, resource); + + // set Location and Content-Location headers + for (final Object element : newEntry.getOtherLinks()) { + final Link link = (Link) element; + if ("edit".equals(link.getRel())) { + res.addHeader("Location", link.getHrefResolved()); + break; + } + } + for (final Object element : newEntry.getAlternateLinks()) { + final Link link = (Link) element; + if ("alternate".equals(link.getRel())) { + res.addHeader("Content-Location", link.getHrefResolved()); + break; + } + } + + res.setStatus(HttpServletResponse.SC_CREATED); + res.setContentType("application/atom+xml; type=entry; charset=utf-8"); + + final Writer writer = res.getWriter(); + Atom10Generator.serializeEntry(newEntry, writer); + writer.close(); + + } else { + res.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, "No content-type specified in request"); + } + + } else { + res.sendError(HttpServletResponse.SC_NOT_FOUND, "Invalid collection specified in request"); + } + } catch (final AtomException ae) { + res.sendError(ae.getStatus(), ae.getMessage()); + LOG.debug("An error occured while processing POST", ae); + } catch (final Exception e) { + res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + LOG.debug("An error occured while processing POST", e); + } + } else { + res.setHeader("WWW-Authenticate", "BASIC realm=\"AtomPub\""); + res.sendError(HttpServletResponse.SC_UNAUTHORIZED); + } + LOG.debug("Exiting"); + } + + // ----------------------------------------------------------------------------- + /** + * Handles an Atom PUT by calling handler to identify URI, reading/parsing data, calling handler + * and writing results to response. + */ + @Override + protected void doPut(final HttpServletRequest req, final HttpServletResponse res) throws ServletException, IOException { + LOG.debug("Entering"); + final AtomHandler handler = createAtomRequestHandler(req, res); + final String userName = handler.getAuthenticatedUsername(); + if (userName != null) { + final AtomRequest areq = new AtomRequestImpl(req); + try { + if (handler.isEntryURI(areq)) { + + // parse incoming entry + final Entry unsavedEntry = Atom10Parser.parseEntry(new BufferedReader(new InputStreamReader(req.getInputStream(), "UTF-8")), null, + Locale.US); + + // call handler to put entry + handler.putEntry(areq, unsavedEntry); + + res.setStatus(HttpServletResponse.SC_OK); + + } else if (handler.isMediaEditURI(areq)) { + + // hand input stream to handler + handler.putMedia(areq); + + res.setStatus(HttpServletResponse.SC_OK); + + } else { + res.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } catch (final AtomException ae) { + res.sendError(ae.getStatus(), ae.getMessage()); + LOG.debug("An error occured while processing PUT", ae); + } catch (final Exception e) { + res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + LOG.debug("An error occured while processing PUT", e); + } + } else { + res.setHeader("WWW-Authenticate", "BASIC realm=\"AtomPub\""); + // Wanted to use sendError() here but Tomcat sends 403 forbidden + // when I do that, so sticking with setStatus() for time being. + res.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + LOG.debug("Exiting"); + } + + // ----------------------------------------------------------------------------- + /** + * Handle Atom DELETE by calling appropriate handler. + */ + @Override + protected void doDelete(final HttpServletRequest req, final HttpServletResponse res) throws ServletException, IOException { + LOG.debug("Entering"); + final AtomHandler handler = createAtomRequestHandler(req, res); + final String userName = handler.getAuthenticatedUsername(); + if (userName != null) { + final AtomRequest areq = new AtomRequestImpl(req); + try { + if (handler.isEntryURI(areq)) { + handler.deleteEntry(areq); + res.setStatus(HttpServletResponse.SC_OK); + } else { + res.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } catch (final AtomException ae) { + res.sendError(ae.getStatus(), ae.getMessage()); + LOG.debug("An error occured while processing DELETE", ae); + } catch (final Exception e) { + res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + LOG.debug("An error occured while processing DELETE", e); + } + } else { + res.setHeader("WWW-Authenticate", "BASIC realm=\"AtomPub\""); + // Wanted to use sendError() here but Tomcat sends 403 forbidden + // when I do that, so sticking with setStatus() for time being. + res.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + LOG.debug("Exiting"); + } + + /** + * Initialize servlet. + */ + @Override + public void init(final ServletConfig config) throws ServletException { + super.init(config); + contextDirPath = getServletContext().getRealPath("/"); + + } + + /** + * Get absolute path to Servlet context directory. + */ + public static String getContextDirPath() { + return contextDirPath; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/ConfigurationError.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/ConfigurationError.java new file mode 100644 index 0000000..120f28d --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/ConfigurationError.java @@ -0,0 +1,21 @@ +package com.rometools.propono.atom.server; + +class ConfigurationError extends Error { + + private static final long serialVersionUID = 1L; + + private final Exception exception; + + /** + * Construct a new instance with the specified detail string and exception. + */ + ConfigurationError(final String msg, final Exception x) { + super(msg); + exception = x; + } + + Exception getException() { + return exception; + } + +} \ No newline at end of file diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/FactoryConfigurationError.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/FactoryConfigurationError.java new file mode 100644 index 0000000..62a1b98 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/FactoryConfigurationError.java @@ -0,0 +1,101 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server; + +/** + * Thrown when a problem with configuration with the + * {@link com.rometools.rome.propono.atom.server.AtomHandlerFactory} exists. This error will + * typically be thrown when the class of a parser factory specified in the system properties cannot + * be found or instantiated. + */ +public class FactoryConfigurationError extends Error { + + private static final long serialVersionUID = 1L; + + /** + * Exception that represents the error. + */ + private final Exception exception; + + /** + * Create a new FactoryConfigurationError with no detail mesage. + */ + public FactoryConfigurationError() { + super(); + exception = null; + } + + /** + * Create a new FactoryConfigurationError with the String specified + * as an error message. + * + * @param msg The error message for the exception. + */ + public FactoryConfigurationError(final String msg) { + super(msg); + exception = null; + } + + /** + * Create a new FactoryConfigurationError with a given Exception base + * cause of the error. + * + * @param e The exception to be encapsulated in a FactoryConfigurationError. + */ + public FactoryConfigurationError(final Exception e) { + super(e.toString()); + exception = e; + } + + /** + * Create a new FactoryConfigurationError with the given Exception + * base cause and detail message. + * + * @param e The exception to be encapsulated in a FactoryConfigurationError + * @param msg The detail message. + */ + public FactoryConfigurationError(final Exception e, final String msg) { + super(msg); + exception = e; + } + + /** + * Return the message (if any) for this error . If there is no message for the exception and + * there is an encapsulated exception then the message of that exception, if it exists will be + * returned. Else the name of the encapsulated exception will be returned. + * + * @return The error message. + */ + @Override + public String getMessage() { + final String message = super.getMessage(); + + if (message == null && exception != null) { + return exception.getMessage(); + } + + return message; + } + + /** + * Return the actual exception (if any) that caused this exception to be raised. + * + * @return The encapsulated exception, or null if there is none. + */ + public Exception getException() { + return exception; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/FactoryFinder.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/FactoryFinder.java new file mode 100644 index 0000000..12f0b05 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/FactoryFinder.java @@ -0,0 +1,248 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Properties; + +/** + * Find {@link com.rometools.rome.propono.atom.server.AtomHandlerFactory} based on properties + * files. + */ +class FactoryFinder { + + private static boolean debug = false; + private static Properties cacheProps = new Properties(); + private static SecuritySupport ss = new SecuritySupport(); + private static boolean firstTime = true; + + private static void dPrint(final String msg) { + if (debug) { + System.err.println("Propono: " + msg); + } + } + + /** + * Create an instance of a class using the specified ClassLoader and optionally fall back to the + * current ClassLoader if not found. + * + * @param className Name of the concrete class corresponding to the service provider + * + * @param cl ClassLoader to use to load the class, null means to use the bootstrap ClassLoader + * + * @param doFallback true if the current ClassLoader should be tried as a fallback if the class + * is not found using cl + */ + private static Object newInstance(final String className, ClassLoader cl, final boolean doFallback) throws ConfigurationError { + + try { + Class providerClass; + if (cl == null) { + // If classloader is null Use the bootstrap ClassLoader. + // Thus Class.forName(String) will use the current + // ClassLoader which will be the bootstrap ClassLoader. + providerClass = Class.forName(className); + } else { + try { + providerClass = cl.loadClass(className); + } catch (final ClassNotFoundException x) { + if (doFallback) { + // Fall back to current classloader + cl = FactoryFinder.class.getClassLoader(); + providerClass = cl.loadClass(className); + } else { + throw x; + } + } + } + + final Object instance = providerClass.newInstance(); + dPrint("created new instance of " + providerClass + " using ClassLoader: " + cl); + return instance; + } catch (final ClassNotFoundException x) { + throw new ConfigurationError("Provider " + className + " not found", x); + } catch (final Exception x) { + throw new ConfigurationError("Provider " + className + " could not be instantiated: " + x, x); + } + } + + /** + * Finds the implementation Class object in the specified order. Main entry point. + * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as a property name + * @param fallbackClassName Implementation class name, if nothing else is found. Use null to + * mean no fallback. + * + * Package private so this code can be shared. + */ + static Object find(final String factoryId, final String fallbackClassName) throws ConfigurationError { + + // Figure out which ClassLoader to use for loading the provider + // class. If there is a Context ClassLoader then use it. + + ClassLoader classLoader = ss.getContextClassLoader(); + + if (classLoader == null) { + // if we have no Context ClassLoader + // so use the current ClassLoader + classLoader = FactoryFinder.class.getClassLoader(); + } + + dPrint("find factoryId =" + factoryId); + + // Use the system property first + try { + final String systemProp = ss.getSystemProperty(factoryId); + if (systemProp != null) { + dPrint("found system property, value=" + systemProp); + return newInstance(systemProp, classLoader, true); + } + } catch (final SecurityException se) { + // if first option fails due to any reason we should try next option in the + // look up algorithm. + } + + // try to read from /propono.properties + try { + final String configFile = "/propono.properties"; + String factoryClassName = null; + if (firstTime) { + synchronized (cacheProps) { + if (firstTime) { + try { + final InputStream is = FactoryFinder.class.getResourceAsStream(configFile); + firstTime = false; + if (is != null) { + dPrint("Read properties file: " + configFile); + cacheProps.load(is); + } + } catch (final Exception intentionallyIgnored) { + } + } + } + } + factoryClassName = cacheProps.getProperty(factoryId); + + if (factoryClassName != null) { + dPrint("found in $java.home/propono.properties, value=" + factoryClassName); + return newInstance(factoryClassName, classLoader, true); + } + } catch (final Exception ex) { + if (debug) { + ex.printStackTrace(); + } + } + + // Try Jar Service Provider Mechanism + final Object provider = findJarServiceProvider(factoryId); + if (provider != null) { + return provider; + } + if (fallbackClassName == null) { + throw new ConfigurationError("Provider for " + factoryId + " cannot be found", null); + } + + dPrint("loaded from fallback value: " + fallbackClassName); + return newInstance(fallbackClassName, classLoader, true); + } + + /* + * Try to find provider using Jar Service Provider Mechanism + * @return instance of provider class if found or null + */ + private static Object findJarServiceProvider(final String factoryId) throws ConfigurationError { + + final String serviceId = "META-INF/services/" + factoryId; + InputStream is = null; + + // First try the Context ClassLoader + ClassLoader cl = ss.getContextClassLoader(); + if (cl != null) { + is = ss.getResourceAsStream(cl, serviceId); + + // If no provider found then try the current ClassLoader + if (is == null) { + cl = FactoryFinder.class.getClassLoader(); + is = ss.getResourceAsStream(cl, serviceId); + } + } else { + // No Context ClassLoader, try the current + // ClassLoader + cl = FactoryFinder.class.getClassLoader(); + is = ss.getResourceAsStream(cl, serviceId); + } + + if (is == null) { + // No provider found + return null; + } + + dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); + + // Read the service provider name in UTF-8 as specified in + // the jar spec. Unfortunately this fails in Microsoft + // VJ++, which does not implement the UTF-8 + // encoding. Theoretically, we should simply let it fail in + // that case, since the JVM is obviously broken if it + // doesn't support such a basic standard. But since there + // are still some users attempting to use VJ++ for + // development, we have dropped in a fallback which makes a + // second attempt using the platform's default encoding. In + // VJ++ this is apparently ASCII, which is a subset of + // UTF-8... and since the strings we'll be reading here are + // also primarily limited to the 7-bit ASCII range (at + // least, in English versions), this should work well + // enough to keep us on the air until we're ready to + // officially decommit from VJ++. [Edited comment from + // jkesselm] + BufferedReader rd; + try { + rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); + } catch (final java.io.UnsupportedEncodingException e) { + rd = new BufferedReader(new InputStreamReader(is)); + } + + String factoryClassName = null; + try { + // XXX Does not handle all possible input as specified by the + // Jar Service Provider specification + factoryClassName = rd.readLine(); + rd.close(); + } catch (final IOException x) { + // No provider found + return null; + } + + if (factoryClassName != null && !"".equals(factoryClassName)) { + dPrint("found in resource, value=" + factoryClassName); + + // Note: here we do not want to fall back to the current + // ClassLoader because we want to avoid the case where the + // resource file was found using one ClassLoader and the + // provider class was instantiated using a different one. + return newInstance(factoryClassName, cl, false); + } + + // No provider found + return null; + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/SecuritySupport.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/SecuritySupport.java new file mode 100644 index 0000000..5f7b2b4 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/SecuritySupport.java @@ -0,0 +1,98 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * This class is duplicated for each subpackage, it is package private and therefore is not exposed + * as part of the public API. + */ +class SecuritySupport { + + ClassLoader getContextClassLoader() { + final PrivilegedAction action = new PrivilegedAction() { + @Override + public ClassLoader run() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } catch (final SecurityException ex) { + } + return cl; + } + }; + return AccessController.doPrivileged(action); + } + + String getSystemProperty(final String propName) { + final PrivilegedAction action = new PrivilegedAction() { + @Override + public String run() { + return System.getProperty(propName); + } + }; + return AccessController.doPrivileged(action); + } + + FileInputStream getFileInputStream(final File file) throws FileNotFoundException { + try { + final PrivilegedExceptionAction action = new PrivilegedExceptionAction() { + @Override + public FileInputStream run() throws FileNotFoundException { + return new FileInputStream(file); + } + }; + return AccessController.doPrivileged(action); + } catch (final PrivilegedActionException e) { + throw (FileNotFoundException) e.getException(); + } + } + + InputStream getResourceAsStream(final ClassLoader cl, final String name) { + final PrivilegedAction action = new PrivilegedAction() { + @Override + public InputStream run() { + InputStream ris; + if (cl == null) { + ris = ClassLoader.getSystemResourceAsStream(name); + } else { + ris = cl.getResourceAsStream(name); + } + return ris; + } + }; + return AccessController.doPrivileged(action); + } + + boolean doesFileExist(final File f) { + final PrivilegedAction action = new PrivilegedAction() { + @Override + public Boolean run() { + return f.exists(); + } + }; + return AccessController.doPrivileged(action).booleanValue(); + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedAtomHandler.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedAtomHandler.java new file mode 100644 index 0000000..dc754da --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedAtomHandler.java @@ -0,0 +1,469 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server.impl; + +import java.io.File; +import java.util.StringTokenizer; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.propono.atom.common.AtomService; +import com.rometools.propono.atom.common.Categories; +import com.rometools.propono.atom.server.AtomException; +import com.rometools.propono.atom.server.AtomHandler; +import com.rometools.propono.atom.server.AtomMediaResource; +import com.rometools.propono.atom.server.AtomRequest; +import com.rometools.propono.atom.server.AtomServlet; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.feed.atom.Feed; + +/** + * File-based {@link com.rometools.rome.propono.atom.server.AtomHandler} implementation that stores + * entries and media-entries to disk. Implemented using + * {@link com.rometools.rome.propono.atom.server.impl.FileBasedAtomService}. + */ +public class FileBasedAtomHandler implements AtomHandler { + + private static final Logger LOG = LoggerFactory.getLogger(FileBasedAtomHandler.class); + + private String userName = null; + private String atomProtocolURL = null; + private String contextURI = null; + private FileBasedAtomService service = null; + + /** + * Construct handler to handle one request. + * + * @param req Request to be handled. + */ + public FileBasedAtomHandler(final HttpServletRequest req) { + this(req, AtomServlet.getContextDirPath()); + } + + /** + * Contruct handler for one request, using specified file storage directory. + * + * @param req Request to be handled. + * @param uploaddir File storage upload dir. + */ + public FileBasedAtomHandler(final HttpServletRequest req, final String uploaddir) { + LOG.debug("ctor"); + + userName = authenticateBASIC(req); + + atomProtocolURL = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + req.getContextPath() + req.getServletPath(); + + contextURI = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + req.getContextPath(); + + try { + service = new FileBasedAtomService(userName, uploaddir, contextURI, req.getContextPath(), req.getServletPath()); + } catch (final Throwable t) { + throw new RuntimeException("ERROR creating FileBasedAtomService", t); + } + } + + /** + * Method used for validating user. Developers can overwrite this method and use credentials + * stored in Database or LDAP to confirm if the user is allowed to access this service. + * + * @param login user submitted login id + * @param password user submitted password + */ + public boolean validateUser(final String login, final String password) { + return true; + } + + /** + * Get username of authenticated user + * + * @return User name. + */ + @Override + public String getAuthenticatedUsername() { + // For now return userName as the login id entered for authorization + return userName; + } + + /** + * Get base URI of Atom protocol implementation. + * + * @return Base URI of Atom protocol implemenation. + */ + public String getAtomProtocolURL() { + if (atomProtocolURL == null) { + return "app"; + } else { + return atomProtocolURL; + } + } + + /** + * Return introspection document + * + * @throws com.rometools.rome.propono.atom.server.AtomException Unexpected exception. + * @return AtomService object with workspaces and collections. + */ + @Override + public AtomService getAtomService(final AtomRequest areq) throws AtomException { + return service; + } + + /** + * Returns null because we use in-line categories. + * + * @throws com.rometools.rome.propono.atom.server.AtomException Unexpected exception. + * @return Categories object + */ + @Override + public Categories getCategories(final AtomRequest areq) throws AtomException { + LOG.debug("getCollection"); + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + final FileBasedCollection col = service.findCollectionByHandle(handle, collection); + return col.getCategories(true).get(0); + } + + /** + * Get collection specified by pathinfo. + * + * @param areq Details of HTTP request + * @return ROME feed representing collection. + * @throws com.rometools.rome.propono.atom.server.AtomException Invalid collection or other + * exception. + */ + @Override + public Feed getCollection(final AtomRequest areq) throws AtomException { + LOG.debug("getCollection"); + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + final FileBasedCollection col = service.findCollectionByHandle(handle, collection); + return col.getFeedDocument(); + } + + /** + * Create a new entry specified by pathInfo and posted entry. We save the submitted Atom entry + * verbatim, but we do set the id and reset the update time. + * + * @param entry Entry to be added to collection. + * @param areq Details of HTTP request + * @throws com.rometools.rome.propono.atom.server.AtomException On invalid collection or other + * error. + * @return Entry as represented on server. + */ + @Override + public Entry postEntry(final AtomRequest areq, final Entry entry) throws AtomException { + LOG.debug("postEntry"); + + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + final FileBasedCollection col = service.findCollectionByHandle(handle, collection); + try { + return col.addEntry(entry); + + } catch (final Exception fe) { + fe.printStackTrace(); + throw new AtomException(fe); + } + } + + /** + * Get entry specified by pathInfo. + * + * @param areq Details of HTTP request + * @throws com.rometools.rome.propono.atom.server.AtomException On invalid pathinfo or other + * error. + * @return ROME Entry object. + */ + @Override + public Entry getEntry(final AtomRequest areq) throws AtomException { + LOG.debug("getEntry"); + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + final String fileName = pathInfo[2]; + final FileBasedCollection col = service.findCollectionByHandle(handle, collection); + try { + return col.getEntry(fileName); + + } catch (final Exception re) { + if (re instanceof AtomException) { + throw (AtomException) re; + } + throw new AtomException("ERROR: getting entry", re); + } + } + + /** + * Update entry specified by pathInfo and posted entry. + * + * @param entry + * @param areq Details of HTTP request + * @throws com.rometools.rome.propono.atom.server.AtomException + */ + @Override + public void putEntry(final AtomRequest areq, final Entry entry) throws AtomException { + LOG.debug("putEntry"); + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + final String fileName = pathInfo[2]; + final FileBasedCollection col = service.findCollectionByHandle(handle, collection); + try { + col.updateEntry(entry, fileName); + + } catch (final Exception fe) { + throw new AtomException(fe); + } + } + + /** + * Delete entry specified by pathInfo. + * + * @param areq Details of HTTP request + */ + @Override + public void deleteEntry(final AtomRequest areq) throws AtomException { + LOG.debug("deleteEntry"); + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + final String fileName = pathInfo[2]; + final FileBasedCollection col = service.findCollectionByHandle(handle, collection); + try { + col.deleteEntry(fileName); + + } catch (final Exception e) { + final String msg = "ERROR in atom.deleteResource"; + LOG.error(msg, e); + throw new AtomException(msg); + } + } + + /** + * Store media data in collection specified by pathInfo, create an Atom media-link entry to + * store metadata for the new media file and return that entry to the caller. + * + * @param areq Details of HTTP request + * @param entry New entry initialzied with only title and content type + * @return Location URL of new media entry + */ + @Override + public Entry postMedia(final AtomRequest areq, final Entry entry) throws AtomException { + + // get incoming slug from HTTP header + final String slug = areq.getHeader("Slug"); + + if (LOG.isDebugEnabled()) { + LOG.debug("postMedia - title: " + entry.getTitle() + " slug:" + slug); + } + + try { + final File tempFile = null; + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + final FileBasedCollection col = service.findCollectionByHandle(handle, collection); + try { + col.addMediaEntry(entry, slug, areq.getInputStream()); + + } catch (final Exception e) { + e.printStackTrace(); + final String msg = "ERROR reading posted file"; + LOG.error(msg, e); + throw new AtomException(msg, e); + } finally { + if (tempFile != null) { + tempFile.delete(); + } + } + + } catch (final Exception re) { + throw new AtomException("ERROR: posting media"); + } + return entry; + } + + /** + * Update the media file part of a media-link entry. + * + * @param areq Details of HTTP request Assuming pathInfo of form /user-name/resource/name + */ + @Override + public void putMedia(final AtomRequest areq) throws AtomException { + + LOG.debug("putMedia"); + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + final String fileName = pathInfo[3]; + final FileBasedCollection col = service.findCollectionByHandle(handle, collection); + try { + col.updateMediaEntry(fileName, areq.getContentType(), areq.getInputStream()); + + } catch (final Exception re) { + throw new AtomException("ERROR: posting media"); + } + } + + @Override + public AtomMediaResource getMediaResource(final AtomRequest areq) throws AtomException { + LOG.debug("putMedia"); + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + final String fileName = pathInfo[3]; + final FileBasedCollection col = service.findCollectionByHandle(handle, collection); + try { + return col.getMediaResource(fileName); + + } catch (final Exception re) { + throw new AtomException("ERROR: posting media"); + } + } + + /** + * Return true if specified pathinfo represents URI of service doc. + */ + @Override + public boolean isAtomServiceURI(final AtomRequest areq) { + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + if (pathInfo.length == 0) { + return true; + } + return false; + } + + /** + * Return true if specified pathinfo represents URI of category doc. + */ + @Override + public boolean isCategoriesURI(final AtomRequest areq) { + LOG.debug("isCategoriesDocumentURI"); + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + if (pathInfo.length == 3 && "categories".equals(pathInfo[2])) { + return true; + } + return false; + } + + /** + * Return true if specified pathinfo represents URI of a collection. + */ + @Override + public boolean isCollectionURI(final AtomRequest areq) { + LOG.debug("isCollectionURI"); + // workspace/collection-plural + // if length is 2 and points to a valid collection then YES + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + if (pathInfo.length == 2) { + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + if (service.findCollectionByHandle(handle, collection) != null) { + return true; + } + } + return false; + + } + + /** + * Return true if specified pathinfo represents URI of an Atom entry. + */ + @Override + public boolean isEntryURI(final AtomRequest areq) { + LOG.debug("isEntryURI"); + // workspace/collection-singular/fsid + // if length is 3 and points to a valid collection then YES + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + if (pathInfo.length == 3) { + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + if (service.findCollectionByHandle(handle, collection) != null) { + return true; + } + } + return false; + } + + /** + * Return true if specified pathinfo represents media-edit URI. + */ + @Override + public boolean isMediaEditURI(final AtomRequest areq) { + LOG.debug("isMediaEditURI"); + // workspace/collection-singular/fsid/media/fsid + // if length is 4, points to a valid collection and fsid is mentioned + // twice then YES + final String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/"); + if (pathInfo.length == 4) { + final String handle = pathInfo[0]; + final String collection = pathInfo[1]; + final String media = pathInfo[2]; + // final String fsid = pathInfo[3]; + if (service.findCollectionByHandle(handle, collection) != null && media.equals("media")) { + return true; + } + } + return false; + + } + + /** + * BASIC authentication. + */ + public String authenticateBASIC(final HttpServletRequest request) { + LOG.debug("authenticateBASIC"); + boolean valid = false; + String userID = null; + String password = null; + try { + final String authHeader = request.getHeader("Authorization"); + if (authHeader != null) { + final StringTokenizer st = new StringTokenizer(authHeader); + if (st.hasMoreTokens()) { + final String basic = st.nextToken(); + if (basic.equalsIgnoreCase("Basic")) { + final String credentials = st.nextToken(); + final String userPass = new String(Base64.decodeBase64(credentials.getBytes())); + final int p = userPass.indexOf(":"); + if (p != -1) { + userID = userPass.substring(0, p); + password = userPass.substring(p + 1); + + // Validate the User. + valid = validateUser(userID, password); + } + } + } + } + } catch (final Exception e) { + LOG.debug("An error occured while processing Basic authentication", e); + } + if (valid) { + // For now assume userID as userName + return userID; + } + return null; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedAtomHandlerFactory.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedAtomHandlerFactory.java new file mode 100644 index 0000000..f4cb6bc --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedAtomHandlerFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server.impl; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.rometools.propono.atom.server.AtomHandler; +import com.rometools.propono.atom.server.AtomHandlerFactory; + +/** + * Extends {@link com.rometools.rome.propono.atom.server.AtomHandlerFactory} to create and return + * {@link com.rometools.rome.propono.atom.server.impl.FileBasedAtomHandler}. + */ +public class FileBasedAtomHandlerFactory extends AtomHandlerFactory { + + /** + * Create new AtomHandler. + */ + @Override + public AtomHandler newAtomHandler(final HttpServletRequest req, final HttpServletResponse res) { + return new FileBasedAtomHandler(req); + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedAtomService.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedAtomService.java new file mode 100644 index 0000000..3df365c --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedAtomService.java @@ -0,0 +1,193 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server.impl; + +import java.io.InputStream; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; + +import com.rometools.propono.atom.common.AtomService; +import com.rometools.propono.utils.Utilities; + +/** + * File based Atom service. Supports one workspace per user. Collections in workspace are defined in + * /propono.properties, for example: + * + *
      + *    # Define list of collections to be offered
      + *    propono.atomserver.filebased.collections=entries,gifimages
      + * 
      + *    # Defines 'entries' collection, accepts entries
      + *    propono.atomserver.filebased.collection.entries.title=Entries
      + *    propono.atomserver.filebased.collection.entries.singular=entry
      + *    propono.atomserver.filebased.collection.entries.plural=entries
      + *    propono.atomserver.filebased.collection.entries.accept=application/atom+xml;type=entry
      + *    propono.atomserver.filebased.collection.entries.categories=general,category1,category2
      + * 
      + *    # Defines 'gifimages' collection, accepts only GIF files
      + *    propono.atomserver.filebased.collection.gifimages.title=GIF Images
      + *    propono.atomserver.filebased.collection.gifimages.singular=gif
      + *    propono.atomserver.filebased.collection.gifimages.plural=gifs
      + *    propono.atomserver.filebased.collection.gifimages.accept=image/gif
      + *    propono.atomserver.filebased.collection.gifimages.categories=general,category1,category2
      + * 
      + * + * If no such properties are found, then service will fall back to two collections: 'entries' for + * Atom entries and 'resources' for any content-type. + * + * + *

      + * URI structure used for accessing collections and entries + *

      + * + *

      + * Collection feed (URI allows GET to get collection, POST to add to it)
      + * [servlet-context-uri]/app/[workspace-handle]/[collection-plural] + *

      + * + *

      + * Collection entry (URI allows GET, PUT and DELETE)
      + * [servlet-context-uri]/app/[workspace-handle]/[collection-singular]/[entryid] + *

      + * + *

      + * Collection entry media (URI allows GET, PUT and DELETE)
      + * [servlet-context-uri]/app/[workspace-handle]/[collection-singular]/media/[entryid] + *

      + * + *

      + * Categories URI if not using inline categories (URI allows GET)
      + * [servlet-context-uri]/app/[workspace-handle]/[collection-plural]/categories + *

      + * + * + *

      + * Directory structure used to store collections and entries + *

      + * + *

      + * Collection feed (kept constantly up to date)
      + * [servlet-context-dir]/[workspace-handle]/[collection-plural]/feed.xml + *

      + * + *

      + * Collection entry (individual entries also stored as entry.xml files)
      + * [servlet-context-dir]/[workspace-handle]/[collection-plural]/id/entry.xml + *

      + * + *

      + * Collection entry media (media file stored under entry directory)
      + * [servlet-context-dir]/[workspace-handle]/[collection-plural]/id/media/id + *

      + */ +public class FileBasedAtomService extends AtomService { + + private final Map workspaceMap = new TreeMap(); + private final Map collectionMap = new TreeMap(); + private static Properties cacheProps = new Properties(); + private boolean firstTime = true; + + /** + * Creates a new instance of FileBasedAtomService. + */ + public FileBasedAtomService(final String userName, final String baseDir, final String contextURI, final String contextPath, final String servletPath) + throws Exception { + final String workspaceHandle = userName; + + // One workspace per user + final FileBasedWorkspace workspace = new FileBasedWorkspace(workspaceHandle, baseDir); + workspaceMap.put(userName, workspace); + + if (firstTime) { + synchronized (cacheProps) { + final InputStream is = getClass().getResourceAsStream("/propono.properties"); + if (is != null) { + cacheProps.load(is); + } + firstTime = false; + } + } + // can't find propono.properties, so use system props instead + if (cacheProps == null) { + cacheProps = System.getProperties(); + } + + final String relativeURIsString = cacheProps.getProperty("propono.atomserver.filebased.relativeURIs"); + final boolean relativeURIs = "true".equals(relativeURIsString); + + final String inlineCategoriesString = cacheProps.getProperty("propono.atomserver.filebased.inlineCategories"); + final boolean inlineCategories = "true".equals(inlineCategoriesString); + + final String colnames = cacheProps.getProperty("propono.atomserver.filebased.collections"); + if (colnames != null) { + + // collections specified in propono.properties, use those + + final String[] colarray = Utilities.stringToStringArray(colnames, ","); + for (final String element : colarray) { + final String prefix = "propono.atomserver.filebased.collection." + element + "."; + final String collectionTitle = cacheProps.getProperty(prefix + "title"); + final String collectionSingular = cacheProps.getProperty(prefix + "singular"); + final String collectionPlural = cacheProps.getProperty(prefix + "plural"); + final String collectionAccept = cacheProps.getProperty(prefix + "accept"); + + final String catNamesString = cacheProps.getProperty(prefix + "categories"); + final String[] catNames = Utilities.stringToStringArray(catNamesString, ","); + + final FileBasedCollection entries = new FileBasedCollection(collectionTitle, workspaceHandle, collectionPlural, collectionSingular, + collectionAccept, inlineCategories, catNames, relativeURIs, contextURI, contextPath, servletPath, baseDir); + workspace.addCollection(entries); + // want to be able to look up collection by singular and plural names + collectionMap.put(workspaceHandle + "|" + collectionSingular, entries); + collectionMap.put(workspaceHandle + "|" + collectionPlural, entries); + } + } else { + + // Fallback to two collections. One collection for accepting entries + // and other collection for other ( resources/uploaded images etc.) + + final String[] catNames = new String[] { "general", "category1", "category2" }; + + final FileBasedCollection entries = new FileBasedCollection("Entries", workspaceHandle, "entries", "entry", "application/atom+xml;type=entry", + inlineCategories, catNames, relativeURIs, contextURI, contextPath, servletPath, baseDir); + workspace.addCollection(entries); + // want to be able to look up collection by singular and plural names + collectionMap.put(workspaceHandle + "|entry", entries); + collectionMap.put(workspaceHandle + "|entries", entries); + + final FileBasedCollection resources = new FileBasedCollection("Resources", workspaceHandle, "resources", "resource", "*/*", inlineCategories, + catNames, relativeURIs, contextURI, contextPath, servletPath, baseDir); + // want to be able to look up collection by singular and plural names + workspace.addCollection(resources); + collectionMap.put(workspaceHandle + "|resource", resources); + collectionMap.put(workspaceHandle + "|resources", resources); + } + + getWorkspaces().add(workspace); + } + + /** + * Find workspace by handle, returns null of not found. + */ + FileBasedWorkspace findWorkspaceByHandle(final String handle) { + return workspaceMap.get(handle); + } + + FileBasedCollection findCollectionByHandle(final String handle, final String collection) { + return collectionMap.get(handle + "|" + collection); + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedCollection.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedCollection.java new file mode 100644 index 0000000..ab296c7 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedCollection.java @@ -0,0 +1,815 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server.impl; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.StringTokenizer; + +import javax.activation.FileTypeMap; +import javax.activation.MimetypesFileTypeMap; + +import org.jdom2.Document; +import org.jdom2.output.XMLOutputter; + +import com.rometools.propono.atom.common.Categories; +import com.rometools.propono.atom.common.Collection; +import com.rometools.propono.atom.common.rome.AppModule; +import com.rometools.propono.atom.common.rome.AppModuleImpl; +import com.rometools.propono.atom.server.AtomException; +import com.rometools.propono.atom.server.AtomMediaResource; +import com.rometools.propono.atom.server.AtomNotFoundException; +import com.rometools.propono.utils.Utilities; +import com.rometools.rome.feed.WireFeed; +import com.rometools.rome.feed.atom.Category; +import com.rometools.rome.feed.atom.Content; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.feed.atom.Feed; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.WireFeedInput; +import com.rometools.rome.io.WireFeedOutput; +import com.rometools.rome.io.impl.Atom10Generator; +import com.rometools.rome.io.impl.Atom10Parser; + +/** + * File based Atom collection implementation. This is the heart of the file-based Atom service + * implementation. It provides methods for adding, getting updating and deleting Atom entries and + * media entries. + */ +public class FileBasedCollection extends Collection { + + private String handle = null; + private String singular = null; + private String collection = null; + + private boolean inlineCats = false; + private String[] catNames = null; + + private boolean relativeURIs = false; + private String contextURI = null; + private String servletPath = null; + private String baseDir = null; + + private static final String FEED_TYPE = "atom_1.0"; + + /** + * Construct by providing title (plain text, no HTML), a workspace handle, a plural collection + * name (e.g. entries), a singular collection name (e.g. entry), the base directory for file + * storage, the content-type range accepted by the collection and the root Atom protocol URI for + * the service. + * + * @param title Title of collection (plain text, no HTML) + * @param handle Workspace handle + * @param collection Collection handle, plural + * @param singular Collection handle, singular + * @param accept Content type range accepted by collection + * @param inlineCats True for inline categories + * @param catNames Category names for this workspace + * @param baseDir Base directory for file storage + * @param relativeURIs True for relative URIs + * @param contextURI Absolute URI of context that hosts APP service + * @param contextPath Context path of APP service (e.g. "/sample-atomserver") + * @param servletPath Servlet path of APP service (e.g. "/app") + */ + public FileBasedCollection(final String title, final String handle, final String collection, final String singular, final String accept, + final boolean inlineCats, final String[] catNames, final boolean relativeURIs, final String contextURI, final String contextPath, + final String servletPath, final String baseDir) { + super(title, "text", relativeURIs ? servletPath.substring(1) + "/" + handle + "/" + collection : contextURI + servletPath + "/" + handle + "/" + + collection); + + this.handle = handle; + this.collection = collection; + this.singular = singular; + this.inlineCats = inlineCats; + this.catNames = catNames; + this.baseDir = baseDir; + this.relativeURIs = relativeURIs; + this.contextURI = contextURI; + this.servletPath = servletPath; + + addAccept(accept); + } + + /** + * Get feed document representing collection. + * + * @throws com.rometools.rome.propono.atom.server.AtomException On error retrieving feed file. + * @return Atom Feed representing collection. + */ + public Feed getFeedDocument() throws AtomException { + InputStream in = null; + synchronized (FileStore.getFileStore()) { + in = FileStore.getFileStore().getFileInputStream(getFeedPath()); + if (in == null) { + in = createDefaultFeedDocument(contextURI + servletPath + "/" + handle + "/" + collection); + } + } + try { + final WireFeedInput input = new WireFeedInput(); + final WireFeed wireFeed = input.build(new InputStreamReader(in, "UTF-8")); + return (Feed) wireFeed; + } catch (final Exception ex) { + throw new AtomException(ex); + } + } + + /** + * Get list of one Categories object containing categories allowed by collection. + * + * @param inline True if Categories object should contain collection of in-line Categories + * objects or false if it should set the Href for out-of-line categories. + */ + public List getCategories(final boolean inline) { + final Categories cats = new Categories(); + cats.setFixed(true); + cats.setScheme(contextURI + "/" + handle + "/" + singular); + if (inline) { + for (final String catName : catNames) { + final Category cat = new Category(); + cat.setTerm(catName); + cats.addCategory(cat); + } + } else { + cats.setHref(getCategoriesURI()); + } + return Collections.singletonList(cats); + } + + /** + * Get list of one Categories object containing categories allowed by collection, returns + * in-line categories if collection set to use in-line categories. + */ + @Override + public List getCategories() { + return getCategories(inlineCats); + } + + /** + * Add entry to collection. + * + * @param entry Entry to be added to collection. Entry will be saved to disk in a directory + * under the collection's directory and the path will follow the pattern + * [collection-plural]/[entryid]/entry.xml. The entry will be added to the + * collection's feed in [collection-plural]/feed.xml. + * @throws java.lang.Exception On error. + * @return Entry as it exists on the server. + */ + public Entry addEntry(final Entry entry) throws Exception { + synchronized (FileStore.getFileStore()) { + final Feed f = getFeedDocument(); + + final String fsid = FileStore.getFileStore().getNextId(); + updateTimestamps(entry); + + // Save entry to file + final String entryPath = getEntryPath(fsid); + + final OutputStream os = FileStore.getFileStore().getFileOutputStream(entryPath); + updateEntryAppLinks(entry, fsid, true); + Atom10Generator.serializeEntry(entry, new OutputStreamWriter(os, "UTF-8")); + os.flush(); + os.close(); + + // Update feed file + updateEntryAppLinks(entry, fsid, false); + updateFeedDocumentWithNewEntry(f, entry); + + return entry; + } + } + + /** + * Add media entry to collection. Accepts a media file to be added to collection. The file will + * be saved to disk in a directory under the collection's directory and the path will follow the + * pattern [collection-plural]/[entryid]/media/[entryid]. An Atom entry will be + * created to store metadata for the entry and it will exist at the path + * [collection-plural]/[entryid]/entry.xml. The entry will be added to the + * collection's feed in [collection-plural]/feed.xml. + * + * @param entry Entry object + * @param slug String to be used in file-name + * @param is Source of media data + * @throws java.lang.Exception On Error + * @return Location URI of entry + */ + public String addMediaEntry(final Entry entry, final String slug, final InputStream is) throws Exception { + synchronized (FileStore.getFileStore()) { + + // Save media file temp file + final Content content = entry.getContents().get(0); + if (entry.getTitle() == null) { + entry.setTitle(slug); + } + final String fileName = createFileName(slug != null ? slug : entry.getTitle(), content.getType()); + final File tempFile = File.createTempFile(fileName, "tmp"); + final FileOutputStream fos = new FileOutputStream(tempFile); + Utilities.copyInputToOutput(is, fos); + fos.close(); + + // Save media file + final FileInputStream fis = new FileInputStream(tempFile); + saveMediaFile(fileName, content.getType(), tempFile.length(), fis); + fis.close(); + final File resourceFile = new File(getEntryMediaPath(fileName)); + + // Create media-link entry + updateTimestamps(entry); + + // Save media-link entry + final String entryPath = getEntryPath(fileName); + final OutputStream os = FileStore.getFileStore().getFileOutputStream(entryPath); + updateMediaEntryAppLinks(entry, resourceFile.getName(), true); + Atom10Generator.serializeEntry(entry, new OutputStreamWriter(os, "UTF-8")); + os.flush(); + os.close(); + + // Update feed with new entry + final Feed f = getFeedDocument(); + updateMediaEntryAppLinks(entry, resourceFile.getName(), false); + updateFeedDocumentWithNewEntry(f, entry); + + return getEntryEditURI(fileName, false, true); + } + } + + /** + * Get an entry from the collection. + * + * @param fsid Internal ID of entry to be returned + * @throws java.lang.Exception On error + * @return Entry specified by fileName/ID + */ + public Entry getEntry(String fsid) throws Exception { + if (fsid.endsWith(".media-link")) { + fsid = fsid.substring(0, fsid.length() - ".media-link".length()); + } + + final String entryPath = getEntryPath(fsid); + + checkExistence(entryPath); + final InputStream in = FileStore.getFileStore().getFileInputStream(entryPath); + + final Entry entry; + final File resource = new File(fsid); + if (resource.exists()) { + entry = loadAtomResourceEntry(in, resource); + updateMediaEntryAppLinks(entry, fsid, true); + } else { + entry = loadAtomEntry(in); + updateEntryAppLinks(entry, fsid, true); + } + return entry; + } + + /** + * Get media resource wrapping a file. + */ + public AtomMediaResource getMediaResource(final String fileName) throws Exception { + final String filePath = getEntryMediaPath(fileName); + final File resource = new File(filePath); + return new AtomMediaResource(resource); + } + + /** + * Update an entry in the collection. + * + * @param entry Updated entry to be stored + * @param fsid Internal ID of entry + * @throws java.lang.Exception On error + */ + public void updateEntry(final Entry entry, String fsid) throws Exception { + synchronized (FileStore.getFileStore()) { + + final Feed f = getFeedDocument(); + + if (fsid.endsWith(".media-link")) { + fsid = fsid.substring(0, fsid.length() - ".media-link".length()); + } + + updateTimestamps(entry); + + updateEntryAppLinks(entry, fsid, false); + updateFeedDocumentWithExistingEntry(f, entry); + + final String entryPath = getEntryPath(fsid); + final OutputStream os = FileStore.getFileStore().getFileOutputStream(entryPath); + updateEntryAppLinks(entry, fsid, true); + Atom10Generator.serializeEntry(entry, new OutputStreamWriter(os, "UTF-8")); + os.flush(); + os.close(); + } + } + + /** + * Update media associated with a media-link entry. + * + * @param fileName Internal ID of entry being updated + * @param contentType Content type of data + * @param is Source of updated data + * @throws java.lang.Exception On error + * @return Updated Entry as it exists on server + */ + public Entry updateMediaEntry(final String fileName, final String contentType, final InputStream is) throws Exception { + synchronized (FileStore.getFileStore()) { + + final File tempFile = File.createTempFile(fileName, "tmp"); + final FileOutputStream fos = new FileOutputStream(tempFile); + Utilities.copyInputToOutput(is, fos); + fos.close(); + + // Update media file + final FileInputStream fis = new FileInputStream(tempFile); + saveMediaFile(fileName, contentType, tempFile.length(), fis); + fis.close(); + final File resourceFile = new File(getEntryMediaPath(fileName)); + + // Load media-link entry to return + final String entryPath = getEntryPath(fileName); + final InputStream in = FileStore.getFileStore().getFileInputStream(entryPath); + final Entry atomEntry = loadAtomResourceEntry(in, resourceFile); + + updateTimestamps(atomEntry); + updateMediaEntryAppLinks(atomEntry, fileName, false); + + // Update feed with new entry + final Feed f = getFeedDocument(); + updateFeedDocumentWithExistingEntry(f, atomEntry); + + // Save updated media-link entry + final OutputStream os = FileStore.getFileStore().getFileOutputStream(entryPath); + updateMediaEntryAppLinks(atomEntry, fileName, true); + Atom10Generator.serializeEntry(atomEntry, new OutputStreamWriter(os, "UTF-8")); + os.flush(); + os.close(); + + return atomEntry; + } + } + + /** + * Delete an entry and any associated media file. + * + * @param fsid Internal ID of entry + * @throws java.lang.Exception On error + */ + public void deleteEntry(final String fsid) throws Exception { + synchronized (FileStore.getFileStore()) { + + // Remove entry from Feed + final Feed feed = getFeedDocument(); + updateFeedDocumentRemovingEntry(feed, fsid); + + final String entryFilePath = getEntryPath(fsid); + FileStore.getFileStore().deleteFile(entryFilePath); + + final String entryMediaPath = getEntryMediaPath(fsid); + if (entryMediaPath != null) { + FileStore.getFileStore().deleteFile(entryMediaPath); + } + + final String entryDirPath = getEntryDirPath(fsid); + FileStore.getFileStore().deleteDirectory(entryDirPath); + + try { + Thread.sleep(500L); + } catch (final Exception ignored) { + } + } + } + + private void updateFeedDocumentWithNewEntry(final Feed f, final Entry e) throws AtomException { + boolean inserted = false; + for (int i = 0; i < f.getEntries().size(); i++) { + final Entry entry = f.getEntries().get(i); + final AppModule mod = (AppModule) entry.getModule(AppModule.URI); + final AppModule newMod = (AppModule) e.getModule(AppModule.URI); + if (newMod.getEdited().before(mod.getEdited())) { + f.getEntries().add(i, e); + inserted = true; + break; + } + } + if (!inserted) { + f.getEntries().add(0, e); + } + updateFeedDocument(f); + } + + private void updateFeedDocumentRemovingEntry(final Feed f, final String id) throws AtomException { + final Entry e = findEntry("urn:uuid:" + id, f); + f.getEntries().remove(e); + updateFeedDocument(f); + } + + private void updateFeedDocumentWithExistingEntry(final Feed f, final Entry e) throws AtomException { + final Entry old = findEntry(e.getId(), f); + f.getEntries().remove(old); + + boolean inserted = false; + for (int i = 0; i < f.getEntries().size(); i++) { + final Entry entry = f.getEntries().get(i); + final AppModule entryAppModule = (AppModule) entry.getModule(AppModule.URI); + final AppModule eAppModule = (AppModule) entry.getModule(AppModule.URI); + if (eAppModule.getEdited().before(entryAppModule.getEdited())) { + f.getEntries().add(i, e); + inserted = true; + break; + } + } + if (!inserted) { + f.getEntries().add(0, e); + } + updateFeedDocument(f); + } + + private Entry findEntry(final String id, final Feed feed) { + for (final Entry entry : feed.getEntries()) { + if (id.equals(entry.getId())) { + return entry; + } + } + return null; + } + + private void updateFeedDocument(final Feed f) throws AtomException { + try { + synchronized (FileStore.getFileStore()) { + final WireFeedOutput wireFeedOutput = new WireFeedOutput(); + final Document feedDoc = wireFeedOutput.outputJDom(f); + final XMLOutputter outputter = new XMLOutputter(); + // outputter.setFormat(Format.getPrettyFormat()); + final OutputStream fos = FileStore.getFileStore().getFileOutputStream(getFeedPath()); + outputter.output(feedDoc, new OutputStreamWriter(fos, "UTF-8")); + } + } catch (final FeedException fex) { + throw new AtomException(fex); + } catch (final IOException ex) { + throw new AtomException(ex); + } + } + + private InputStream createDefaultFeedDocument(final String uri) throws AtomException { + + final Feed f = new Feed(); + f.setTitle("Feed"); + f.setId(uri); + f.setFeedType(FEED_TYPE); + + final Link selfLink = new Link(); + selfLink.setRel("self"); + selfLink.setHref(uri); + f.getOtherLinks().add(selfLink); + + try { + final WireFeedOutput wireFeedOutput = new WireFeedOutput(); + final Document feedDoc = wireFeedOutput.outputJDom(f); + final XMLOutputter outputter = new XMLOutputter(); + // outputter.setFormat(Format.getCompactFormat()); + final OutputStream fos = FileStore.getFileStore().getFileOutputStream(getFeedPath()); + outputter.output(feedDoc, new OutputStreamWriter(fos, "UTF-8")); + + } catch (final FeedException ex) { + throw new AtomException(ex); + } catch (final IOException ex) { + throw new AtomException(ex); + } catch (final Exception e) { + + e.printStackTrace(); + } + return FileStore.getFileStore().getFileInputStream(getFeedPath()); + } + + private Entry loadAtomResourceEntry(final InputStream in, final File file) { + try { + final Entry entry = Atom10Parser.parseEntry(new BufferedReader(new InputStreamReader(in)), null, Locale.US); + updateMediaEntryAppLinks(entry, file.getName(), true); + return entry; + + } catch (final Exception e) { + e.printStackTrace(); + return null; + } + } + + private void updateEntryAppLinks(final Entry entry, final String fsid, final boolean singleEntry) { + + entry.setId("urn:uuid:" + fsid); + + // Look for existing alt links and the alt link + Link altLink = null; + List altLinks = entry.getAlternateLinks(); + if (altLinks != null) { + for (final Link link : altLinks) { + if (link.getRel() == null || "alternate".equals(link.getRel())) { + altLink = link; + break; + } + } + } else { + // No alt links found, so add them now + altLinks = new ArrayList(); + entry.setAlternateLinks(altLinks); + } + // The alt link not found, so add it now + if (altLink == null) { + altLink = new Link(); + altLinks.add(altLink); + } + // Set correct value for the alt link + altLink.setRel("alternate"); + altLink.setHref(getEntryViewURI(fsid)); + + // Look for existing other links and the edit link + Link editLink = null; + List otherLinks = entry.getOtherLinks(); + if (otherLinks != null) { + for (final Link link : otherLinks) { + if ("edit".equals(link.getRel())) { + editLink = link; + break; + } + } + } else { + // No other links found, so add them now + otherLinks = new ArrayList(); + entry.setOtherLinks(otherLinks); + } + // The edit link not found, so add it now + if (editLink == null) { + editLink = new Link(); + otherLinks.add(editLink); + } + // Set correct value for the edit link + editLink.setRel("edit"); + editLink.setHref(getEntryEditURI(fsid, relativeURIs, singleEntry)); + } + + private void updateMediaEntryAppLinks(final Entry entry, final String fileName, final boolean singleEntry) { + + // TODO: figure out why PNG is missing from Java MIME types + final FileTypeMap map = FileTypeMap.getDefaultFileTypeMap(); + if (map instanceof MimetypesFileTypeMap) { + try { + ((MimetypesFileTypeMap) map).addMimeTypes("image/png png PNG"); + } catch (final Exception ignored) { + } + } + entry.setId(getEntryMediaViewURI(fileName)); + entry.setTitle(fileName); + entry.setUpdated(new Date()); + + final List otherlinks = new ArrayList(); + entry.setOtherLinks(otherlinks); + + final Link editlink = new Link(); + editlink.setRel("edit"); + editlink.setHref(getEntryEditURI(fileName, relativeURIs, singleEntry)); + otherlinks.add(editlink); + + final Link editMedialink = new Link(); + editMedialink.setRel("edit-media"); + editMedialink.setHref(getEntryMediaEditURI(fileName, relativeURIs, singleEntry)); + otherlinks.add(editMedialink); + + final Content content = entry.getContents().get(0); + content.setSrc(getEntryMediaViewURI(fileName)); + final List contents = new ArrayList(); + contents.add(content); + entry.setContents(contents); + } + + /** + * Create a Rome Atom entry based on a Roller entry. Content is escaped. Link is stored as + * rel=alternate link. + */ + private Entry loadAtomEntry(final InputStream in) { + try { + return Atom10Parser.parseEntry(new BufferedReader(new InputStreamReader(in, "UTF-8")), null, Locale.US); + } catch (final Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * Update existing or add new app:edited. + */ + private void updateTimestamps(final Entry entry) { + // We're not differenting between an update and an edit (yet) + entry.setUpdated(new Date()); + + AppModule appModule = (AppModule) entry.getModule(AppModule.URI); + if (appModule == null) { + appModule = new AppModuleImpl(); + final List modules = entry.getModules() == null ? new ArrayList() : entry.getModules(); + modules.add(appModule); + entry.setModules(modules); + } + appModule.setEdited(entry.getUpdated()); + } + + /** + * Save file to website's resource directory. + * + * @param handle Weblog handle to save to + * @param name Name of file to save + * @param size Size of file to be saved + * @param is Read file from input stream + */ + private void saveMediaFile(final String name, final String contentType, final long size, final InputStream is) throws AtomException { + + final byte[] buffer = new byte[8192]; + int bytesRead = 0; + + final File dirPath = new File(getEntryMediaPath(name)); + if (!dirPath.getParentFile().exists()) { + dirPath.getParentFile().mkdirs(); + } + OutputStream bos = null; + try { + bos = new FileOutputStream(dirPath.getAbsolutePath()); + while ((bytesRead = is.read(buffer, 0, 8192)) != -1) { + bos.write(buffer, 0, bytesRead); + } + } catch (final Exception e) { + throw new AtomException("ERROR uploading file", e); + } finally { + try { + bos.flush(); + bos.close(); + } catch (final Exception ignored) { + } + } + + } + + /** + * Creates a file name for a file based on a weblog handle, title string and a content-type. + * + * @param handle Weblog handle + * @param title Title to be used as basis for file name (or null) + * @param contentType Content type of file (must not be null) + * + * If a title is specified, the method will apply the same create-anchor logic we use + * for weblog entries to create a file name based on the title. + * + * If title is null, the base file name will be the weblog handle plus a YYYYMMDDHHSS + * timestamp. + * + * The extension will be formed by using the part of content type that comes after he + * slash. + * + * For example: weblog.handle = "daveblog" title = "Port Antonio" content-type = + * "image/jpg" Would result in port_antonio.jpg + * + * Another example: weblog.handle = "daveblog" title = null content-type = + * "image/jpg" Might result in daveblog-200608201034.jpg + */ + private String createFileName(final String title, final String contentType) { + + if (handle == null) { + throw new IllegalArgumentException("weblog handle cannot be null"); + } + if (contentType == null) { + throw new IllegalArgumentException("contentType cannot be null"); + } + + String fileName = null; + + final SimpleDateFormat sdf = new SimpleDateFormat(); + sdf.applyPattern("yyyyMMddHHssSSS"); + + // Determine the extension based on the contentType. This is a hack. + // The info we need to map from contentType to file extension is in + // JRE/lib/content-type.properties, but Java Activation doesn't provide + // a way to do a reverse mapping or to get at the data. + final String[] typeTokens = contentType.split("/"); + final String ext = typeTokens[1]; + + if (title != null && !title.trim().equals("")) { + // We've got a title, so use it to build file name + final String base = Utilities.replaceNonAlphanumeric(title, ' '); + final StringTokenizer toker = new StringTokenizer(base); + String tmp = null; + int count = 0; + while (toker.hasMoreTokens() && count < 5) { + String s = toker.nextToken(); + s = s.toLowerCase(); + tmp = tmp == null ? s : tmp + "_" + s; + count++; + } + fileName = tmp + "-" + sdf.format(new Date()) + "." + ext; + + } else { + // No title or text, so instead we'll use the item's date + // in YYYYMMDD format to form the file name + fileName = handle + "-" + sdf.format(new Date()) + "." + ext; + } + + return fileName; + } + + // ------------------------------------------------------------ URI methods + + private String getEntryEditURI(final String fsid, final boolean relative, final boolean singleEntry) { + String entryURI = null; + if (relative) { + if (singleEntry) { + entryURI = fsid; + } else { + entryURI = singular + "/" + fsid; + } + } else { + entryURI = contextURI + servletPath + "/" + handle + "/" + singular + "/" + fsid; + } + return entryURI; + } + + private String getEntryViewURI(final String fsid) { + return contextURI + "/" + handle + "/" + collection + "/" + fsid + "/entry.xml"; + } + + private String getEntryMediaEditURI(final String fsid, final boolean relative, final boolean singleEntry) { + String entryURI = null; + if (relative) { + if (singleEntry) { + entryURI = "media/" + fsid; + } else { + entryURI = singular + "/media/" + fsid; + } + } else { + entryURI = contextURI + servletPath + "/" + handle + "/" + singular + "/media/" + fsid; + } + return entryURI; + + } + + private String getEntryMediaViewURI(final String fsid) { + return contextURI + "/" + handle + "/" + collection + "/" + fsid + "/media/" + fsid; + } + + private String getCategoriesURI() { + if (!relativeURIs) { + return contextURI + servletPath + "/" + handle + "/" + singular + "/categories"; + } else { + return servletPath + "/" + handle + "/" + singular + "/categories"; + } + } + + // ------------------------------------------------------- File path methods + + private String getBaseDir() { + return baseDir; + } + + private String getFeedPath() { + return getBaseDir() + handle + File.separator + collection + File.separator + "feed.xml"; + } + + private String getEntryDirPath(final String id) { + return getBaseDir() + handle + File.separator + collection + File.separator + id; + } + + private String getEntryPath(final String id) { + return getEntryDirPath(id) + File.separator + "entry.xml"; + } + + private String getEntryMediaPath(final String id) { + return getEntryDirPath(id) + File.separator + "media" + File.separator + id; + } + + private static void checkExistence(final String path) throws AtomNotFoundException { + if (!FileStore.getFileStore().exists(path)) { + throw new AtomNotFoundException("Entry does not exist"); + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedWorkspace.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedWorkspace.java new file mode 100644 index 0000000..163c6cc --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileBasedWorkspace.java @@ -0,0 +1,30 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server.impl; + +import com.rometools.propono.atom.common.Workspace; + +/** + * File based Atom service Workspace. + */ +public class FileBasedWorkspace extends Workspace { + + /** Creates a new instance of FileBasedWorkspace */ + public FileBasedWorkspace(final String handle, final String baseDir) { + super(handle, "text"); + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileStore.java b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileStore.java new file mode 100644 index 0000000..035c341 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/atom/server/impl/FileStore.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server.impl; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.commons.lang3.RandomStringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class which helps in handling File persistence related operations. + */ +class FileStore { + + private static final Logger LOG = LoggerFactory.getLogger(FileStore.class); + + private static final FileStore fileStore = new FileStore(); + + public String getNextId() { + // return UUID.randomUUID().toString(); // requires JDK 1.5 + return RandomStringUtils.randomAlphanumeric(20); + } + + public boolean exists(final String path) { + final File f = new File(path); + return f.exists(); + } + + public InputStream getFileInputStream(final String path) { + LOG.debug("getFileContents path: " + path); + try { + return new BufferedInputStream(new FileInputStream(path)); + } catch (final FileNotFoundException e) { + LOG.debug(" File not found: " + path); + return null; + } + } + + public OutputStream getFileOutputStream(final String path) { + LOG.debug("getFileOutputStream path: " + path); + try { + final File f = new File(path); + f.getParentFile().mkdirs(); + return new BufferedOutputStream(new FileOutputStream(f)); + } catch (final FileNotFoundException e) { + LOG.debug(" File not found: " + path); + return null; + } + } + + public void createOrUpdateFile(final String path, final InputStream content) throws FileNotFoundException, IOException { + LOG.debug("createOrUpdateFile path: " + path); + final File f = new File(path); + f.mkdirs(); + final FileOutputStream out = new FileOutputStream(f); + + final byte[] buffer = new byte[2048]; + int read; + while ((read = content.read(buffer)) != -1) { + out.write(buffer, 0, read); + } + out.close(); + } + + public void deleteFile(final String path) { + LOG.debug("deleteFile path: " + path); + final File f = new File(path); + if (!f.delete()) { + LOG.debug(" Failed to delete: " + f.getAbsolutePath()); + } + } + + public static FileStore getFileStore() { + return fileStore; + } + + public boolean deleteDirectory(final String path) { + return deleteDirectory(new File(path)); + } + + public boolean deleteDirectory(final File path) { + LOG.debug("deleteDirectory path: " + path); + if (path.exists()) { + final File[] files = path.listFiles(); + for (final File file : files) { + if (file.isDirectory()) { + deleteDirectory(file); + } else { + file.delete(); + } + } + } + return path.delete(); + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/BaseBlogEntry.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/BaseBlogEntry.java new file mode 100644 index 0000000..7d5aca9 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/BaseBlogEntry.java @@ -0,0 +1,212 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Base implementation of a blog entry. + */ +public abstract class BaseBlogEntry implements BlogEntry { + protected String id = null; + protected Person author = null; + protected Content content = null; + protected String title = null; + protected String permalink = null; + protected String summary = null; + protected Date modificationDate = null; + protected Date publicationDate = null; + protected List categories = new ArrayList(); + protected boolean draft = false; + private Blog blog = null; + + /** + * Contruct abstract blog entry. + */ + public BaseBlogEntry(final Blog blog) { + this.blog = blog; + } + + /** + * {@inheritDoc} + */ + @Override + public String getId() { + return id; + } + + /** + * {@inheritDoc} + */ + @Override + public String getPermalink() { + return permalink; + } + + void setPermalink(final String permalink) { + this.permalink = permalink; + } + + /** + * {@inheritDoc} + */ + @Override + public Person getAuthor() { + return author; + } + + /** + * {@inheritDoc} + */ + @Override + public void setAuthor(final Person author) { + this.author = author; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getContent() { + return content; + } + + /** + * {@inheritDoc} + */ + @Override + public void setContent(final Content content) { + this.content = content; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getDraft() { + return draft; + } + + /** + * {@inheritDoc} + */ + @Override + public void setDraft(final boolean draft) { + this.draft = draft; + } + + /** + * {@inheritDoc} + */ + @Override + public Date getPublicationDate() { + return publicationDate; + } + + /** + * {@inheritDoc} + */ + @Override + public void setPublicationDate(final Date pubDate) { + publicationDate = pubDate; + } + + /** + * {@inheritDoc} + */ + @Override + public Date getModificationDate() { + return modificationDate; + } + + /** + * {@inheritDoc} + */ + @Override + public void setModificationDate(final Date date) { + modificationDate = date; + } + + /** + * {@inheritDoc} + */ + @Override + public String getTitle() { + return title; + } + + /** + * {@inheritDoc} + */ + @Override + public void setTitle(final String title) { + this.title = title; + } + + /** + * {@inheritDoc} + */ + @Override + public String getSummary() { + return summary; + } + + /** + * {@inheritDoc} + */ + @Override + public void setSummary(final String summary) { + this.summary = summary; + } + + /** + * {@inheritDoc} + */ + @Override + public List getCategories() { + return categories; + } + + /** + * {@inheritDoc} + */ + @Override + public void setCategories(final List categories) { + this.categories = categories; + } + + /** + * {@inheritDoc} + */ + @Override + public Blog getBlog() { + return blog; + } + + void setBlog(final Blog blog) { + this.blog = blog; + } + + /** + * String representation, returns id. + */ + @Override + public String toString() { + return id; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/Blog.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/Blog.java new file mode 100644 index 0000000..eb5d505 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/Blog.java @@ -0,0 +1,235 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient; + +import java.util.Iterator; +import java.util.List; + +/** + *

      + * Represents a blog, which has collections of entries and resources. You can access the collections + * using the getCollections() and getCollection(String name) methods, which return Blog.Collection + * objects, which you can use to create, retrieve update or delete entries within a collection. + *

      + */ +public interface Blog { + + /** + * Token can be used to fetch this blog again from getBlog() method. + * + * @return Blog object specified by token. + */ + public String getToken(); + + /** + * Name of this blog. + * + * @return Display name of this blog. + */ + public String getName(); + + /** + * Get a single BlogEntry (or BlogResource) by token. + * + * @param token Token from blog entry's getToken() method. + * @throws com.rometools.rome.propono.blogclient.BlogClientException On error fetching the blog + * entry. + * @return Blog entry specified by token. + */ + public BlogEntry getEntry(String token) throws BlogClientException; + + /** + * Gets listing of entry and resource collections available in the blog, including the primary + * collections. + * + * @throws BlogClientException On error fetching collections. + * @return List of Blog.Collection objects. + */ + public List getCollections() throws BlogClientException; + + /** + * Get collection by token. + * + * @param token Token from a collection's getToken() method. + * @throws BlogClientException On error fetching collection. + * @return Blog.Collection object. + */ + public Collection getCollection(String token) throws BlogClientException; + + /** + * Represents an entry or resource collection on a blog server. + */ + public interface Collection { + + /** + * Get blog that contains this collection. + * + * @return Blog that contains this collection. + */ + public Blog getBlog(); + + /** + * Title of collection. + * + * @return Title of collecton. + */ + public String getTitle(); + + /** + * Token that can be used to fetch collection. + * + * @return Token that can be used to fetch collection. + */ + public String getToken(); + + /** + * Content-types accepted by collection. + * + * @return Comma-separated list of content-types accepted. + */ + public List getAccepts(); + + /** + * Determines if collection will accept a content-type. + * + * @param contentType Content-type to be considered. + * @return True of content type will be accepted, false otherwise. + */ + public boolean accepts(String contentType); + + /** + * Return categories allowed by colletion. + * + * @throws BlogClientException On error fetching categories. + * @return List of BlogEntry.Category objects for this collection. + */ + public List getCategories() throws BlogClientException; + + /** + * Create but do not save new entry in collection. To save entry, call its save() method. + * + * @throws BlogClientException On error creating entry. + * @return New BlogEntry object. + */ + public BlogEntry newEntry() throws BlogClientException; + + /** + * Create but do not save new resource in collection. To save resource, call its save() + * method. + * + * @param name Name of new resource. + * @param contentType MIME content-type of new resource. + * @param bytes Data for new resource. + * @throws BlogClientException On error creating entry. + * @return New BlogResource object, + */ + public BlogResource newResource(String name, String contentType, byte[] bytes) throws BlogClientException; + + /** + * Get iterator over entries/resources in this collection. + * + * @return List of BlogEntry objects, some may be BlogResources. + * @throws BlogClientException On error fetching entries/resources. + */ + public Iterator getEntries() throws BlogClientException; + + /** + * Save or update a BlogEntry in this collection by adding it to this collection and then + * calling it's entry.save() method. + * + * @param entry BlogEntry to be saved. + * @throws BlogClientException On error saving entry. + * @return URI of entry. + */ + public String saveEntry(BlogEntry entry) throws BlogClientException; + + /** + * Save or update resource in this collection + * + * @param resource BlogResource to be saved. + * @throws BlogClientException On error saving resource. + * @return URI of resource. + */ + public String saveResource(BlogResource resource) throws BlogClientException; + } + + // Deprecated primary collection methods, instead use collections directly. + + /** + * Get iterator over entries in primary entries collection (the first collection that accepts + * entries). Note that entries may be partial, so don't try to update and save them: to update + * and entry, first fetch it with getEntry(), change fields, then call entry.save(); + * + * @return To iterate over all entries in collection. + * @throws BlogClientException On failure or if there is no primary entries collection. + * + * @deprecated Instead use collections directly. + */ + @Deprecated + public Iterator getEntries() throws BlogClientException; + + /** + * Get entries in primary resources collection (the first collection that accepts anything other + * than entries). + * + * @throws BlogClientException On failure or if there is no primary resources collection. + * @return To iterate over all resojrces in collection. + * + * @deprecated Instead use collections directly. + */ + @Deprecated + public Iterator getResources() throws BlogClientException; + + /** + * Create but do not save it to server new BlogEntry in primary entries collection (the first + * collection found that accepts entries). To save the entry to the server to a collection, use + * the entry's save() method. + * + * @throws BlogClientException On error or if there is no primary entries collection. + * @return Unsaved BlogEntry in primary entries collection. + * + * @deprecated Instead use collections directly. + */ + @Deprecated + public BlogEntry newEntry() throws BlogClientException; + + /** + * Create but do not save it to server new BlogResource in primary resources collection (the + * first collection found that accepts resources). To save the resource to the server to a + * collection, use the resource's save() method. + * + * @param name Name of resource to be saved. + * @param type MIME content type of resource data. + * @param bytes Bytes of resource data. + * @throws BlogClientException On error or if there is no primary respurces collection. + * @return Unsaved BlogEntry in primary resources collection. + * + * @deprecated Instead use collections directly. + */ + @Deprecated + public BlogResource newResource(String name, String type, byte[] bytes) throws BlogClientException; + + /** + * Returns list of available BlogEntry.Category in primary entries collection. + * + * @throws BlogClientException On error or if there is no primary entries collection. + * @return List of BlogEntry.Category objects. + * + * @deprecated Instead use collections directly. + */ + @Deprecated + public List getCategories() throws BlogClientException; +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogClientException.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogClientException.java new file mode 100644 index 0000000..ac44e48 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogClientException.java @@ -0,0 +1,44 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient; + +/** + * Represents a Blog Client exception, the library throws these instead of implementation specific + * exceptions. + */ +public class BlogClientException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Construct a new exception + * + * @param msg Text message that explains exception + */ + public BlogClientException(final String msg) { + super(msg); + } + + /** + * Construct a new exception which wraps a throwable. + * + * @param msg Text message that explains exception + * @param t Throwable to be wrapped by exception + */ + public BlogClientException(final String msg, final Throwable t) { + super(msg, t); + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogConnection.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogConnection.java new file mode 100644 index 0000000..4eb2fcc --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogConnection.java @@ -0,0 +1,34 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient; + +import java.util.List; + +/** + * A BlogConnection is a single-user connection to a blog server where the user has access to + * multiple blogs, which are each represented by a Blog interface. + */ +public interface BlogConnection { + + /** Returns collection of blogs available from this connection */ + public abstract List getBlogs(); + + /** Get blog by token */ + public abstract Blog getBlog(String token); + + /** Set appkey (optional, needed by some blog servers) */ + public void setAppkey(String appkey); +} \ No newline at end of file diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogConnectionFactory.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogConnectionFactory.java new file mode 100644 index 0000000..0494a37 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogConnectionFactory.java @@ -0,0 +1,74 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient; + +import java.lang.reflect.Constructor; + +/** + * Entry point to the Blogapps blog client library. + */ +public class BlogConnectionFactory { + + // BlogConnection implementations must: + // 1) implement BlogConnection + // 2) privide contructor that accepts three strings args: url, username and password. + + // TODO: make implementations configurable + private static String ATOMPROTOCOL_IMPL_CLASS = "com.rometools.propono.blogclient.atomprotocol.AtomConnection"; + + private static String METAWEBLOG_IMPL_CLASS = "com.rometools.propono.blogclient.metaweblog.MetaWeblogConnection"; + + /** + * Create a connection to a blog server. + * + * @param type Connection type, must be "atom" or "metaweblog" + * @param url End-point URL to connect to + * @param username Username for login to blog server + * @param password Password for login to blog server + */ + public static BlogConnection getBlogConnection(final String type, final String url, final String username, final String password) + throws BlogClientException { + BlogConnection blogConnection = null; + if (type == null || type.equals("metaweblog")) { + blogConnection = createBlogConnection(METAWEBLOG_IMPL_CLASS, url, username, password); + } else if (type.equals("atom")) { + blogConnection = createBlogConnection(ATOMPROTOCOL_IMPL_CLASS, url, username, password); + } else { + throw new BlogClientException("Type must be 'atom' or 'metaweblog'"); + } + return blogConnection; + } + + private static BlogConnection createBlogConnection(final String className, final String url, final String username, final String password) + throws BlogClientException { + + Class conClass; + try { + conClass = Class.forName(className); + } catch (final ClassNotFoundException ex) { + throw new BlogClientException("BlogConnection impl. class not found: " + className, ex); + } + final Class[] args = new Class[] { String.class, String.class, String.class }; + Constructor ctor; + try { + ctor = conClass.getConstructor(args); + return (BlogConnection) ctor.newInstance(new Object[] { url, username, password }); + } catch (final Throwable t) { + throw new BlogClientException("ERROR instantiating BlogConnection impl.", t); + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogEntry.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogEntry.java new file mode 100644 index 0000000..854e5a6 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogEntry.java @@ -0,0 +1,261 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient; + +import java.util.Date; +import java.util.List; + +/** + * Represents a single blog entry. + */ +public interface BlogEntry { + + /** Get token, which can be used to fetch the blog entry */ + public String getToken(); + + /** + * Save this entry to it's collection. If this is a new entry and does not have a collection + * yet, then save() will save it to the primary collection. + */ + public void save() throws BlogClientException; + + /** Delete this entry from blog server */ + public void delete() throws BlogClientException; + + /** Permanent link to this entry (assigned by server) */ + public String getPermalink(); + + /** Blog is associated with a blog */ + public Blog getBlog(); + + /** Get categories, a list of BlogEntry.Category objects */ + public List getCategories(); + + /** Set categories, a list of BlogEntry.Category objects */ + public void setCategories(List categories); + + /** Get globally unique ID of this blog entry */ + public String getId(); + + /** Get title of this blog entry */ + public String getTitle(); + + /** Set title of this blog entry */ + public void setTitle(String title); + + /** Get summary of this blog entry */ + public String getSummary(); + + /** Set summary of this blog entry */ + public void setSummary(String summary); + + /** Get content of this blog entry */ + public Content getContent(); + + /** Set content of this blog entry */ + public void setContent(Content content); + + /** Get draft status of this entry */ + public boolean getDraft(); + + /** Set draft status of this entry */ + public void setDraft(boolean draft); + + /** Get author of this entry */ + public Person getAuthor(); + + /** Set author of this entry */ + public void setAuthor(Person author); + + /** Set publish date of this entry */ + public Date getPublicationDate(); + + /** Get publish date of this entry */ + public void setPublicationDate(Date date); + + /** Get update date of this entry */ + public Date getModificationDate(); + + /** Set update date of this entry */ + public void setModificationDate(Date date); + + /** Represents blog entry content */ + public class Content { + String type = "html"; + String value = null; + String src = null; + + /** Construct content */ + public Content() { + } + + /** Construct content with value (and type="html") */ + public Content(final String value) { + this.value = value; + } + + /** Get value of content if in-line */ + public String getValue() { + return value; + } + + /** Set value of content if in-line */ + public void setValue(final String value) { + this.value = value; + } + + /** + * Get type of content, either "text", "html", "xhtml" or a MIME content-type. Defaults to + * HTML. + */ + public String getType() { + return type; + } + + /** + * Set type of content, either "text", "html", "xhtml" or a MIME content-type. Defaults to + * HTML. + */ + public void setType(final String type) { + this.type = type; + } + + /** Get URI of content if out-of-line */ + public String getSrc() { + return src; + } + + /** Set URI of content if out-of-line */ + public void setSrc(final String src) { + this.src = src; + } + } + + /** Represents a blog author or contributor */ + public class Person { + String name; + String email; + String url; + + /** Get person's email */ + public String getEmail() { + return email; + } + + /** Set person's email */ + public void setEmail(final String email) { + this.email = email; + } + + /** Get person's name */ + public String getName() { + return name; + } + + /** Set person's name */ + public void setName(final String name) { + this.name = name; + } + + /** Get person's URL */ + public String getUrl() { + return url; + } + + /** Set person's URL */ + public void setUrl(final String url) { + this.url = url; + } + + /** Returns person's name */ + @Override + public String toString() { + return name; + } + } + + /** Represents a weblog category */ + public class Category { + String id; + String name; + String url; + + /** + * Create new Catetory + */ + public Category() { + } + + /** + * Create new category with name. + */ + public Category(final String id) { + this.id = id; + name = id; + } + + /** + * Determines if categories are equal based on id. + */ + @Override + public boolean equals(final Object obj) { + final Category other = (Category) obj; + if (obj == null) { + return false; + } + if (getId() != null && other.getId() != null && getId().equals(other.getId())) { + return true; + } + return false; + } + + /** Get category id */ + public String getId() { + return id; + } + + /** Set category id */ + public void setId(final String id) { + this.id = id; + } + + /** Get category display name */ + public String getName() { + return name; + } + + /** Set category display name */ + public void setName(final String name) { + this.name = name; + } + + /** Get URL of category domain */ + public String getUrl() { + return url; + } + + /** Set URL of category domain */ + public void setUrl(final String url) { + this.url = url; + } + + /** Return category's name or id for display */ + @Override + public String toString() { + return name != null ? name : id; + } + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogResource.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogResource.java new file mode 100644 index 0000000..e9ffa55 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/BlogResource.java @@ -0,0 +1,37 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient; + +import java.io.InputStream; + +/** + * Represents a file that has been uploaded to a blog. + *

      + * Resources are modeled as a type of BlogEntry, but be aware: not all servers can save resource + * metadata (i.e. title, category, author, etc.). MetaWeblog based servers can't save metadata at + * all and Atom protocol servers are not required to preserve uploaded file metadata. + */ +public interface BlogResource extends BlogEntry { + + /** Get resource name (name is required) */ + public String getName(); + + /** Get resource as stream, using content.src as URL */ + public InputStream getAsStream() throws BlogClientException; + + /** Update resource by immediately uploading new bytes to server */ + public void update(byte[] newBytes) throws BlogClientException; +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomBlog.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomBlog.java new file mode 100644 index 0000000..03c3949 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomBlog.java @@ -0,0 +1,231 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient.atomprotocol; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import com.rometools.propono.atom.client.ClientAtomService; +import com.rometools.propono.atom.client.ClientCollection; +import com.rometools.propono.atom.client.ClientEntry; +import com.rometools.propono.atom.client.ClientMediaEntry; +import com.rometools.propono.atom.client.ClientWorkspace; +import com.rometools.propono.blogclient.Blog; +import com.rometools.propono.blogclient.BlogClientException; +import com.rometools.propono.blogclient.BlogEntry; +import com.rometools.propono.blogclient.BlogResource; +import com.rometools.propono.utils.ProponoException; + +/** + * Atom protocol implementation of the BlogClient Blog interface. + */ +public class AtomBlog implements Blog { + + private String name = null; + private ClientAtomService service; + private ClientWorkspace workspace = null; + private AtomCollection entriesCollection = null; + private AtomCollection resourcesCollection = null; + private final Map collections = new TreeMap(); + + /** + * Create AtomBlog using specified HTTPClient, user account and workspace, called by + * AtomConnection. Fetches Atom Service document and creates an AtomCollection object for each + * collection found. The first entry collection is considered the primary entry collection. And + * the first resource collection is considered the primary resource collection. + */ + AtomBlog(final ClientAtomService service, final ClientWorkspace workspace) { + + setService(service); + setWorkspace(workspace); + name = workspace.getTitle(); + final List collect = workspace.getCollections(); + final Iterator members = collect.iterator(); + + while (members.hasNext()) { + final ClientCollection col = (ClientCollection) members.next(); + if (col.accepts("entry") && entriesCollection == null) { + // first entry collection is primary entry collection + entriesCollection = new AtomCollection(this, col); + } else if (!col.accepts("entry") && resourcesCollection == null) { + // first non-entry collection is primary resource collection + resourcesCollection = new AtomCollection(this, col); + } + collections.put(col.getHrefResolved(), new AtomCollection(this, col)); + } + + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * String display of blog, returns name. + */ + @Override + public String toString() { + return getName(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getToken() { + return entriesCollection.getToken(); + } + + /** + * {@inheritDoc} + */ + @Override + public BlogEntry newEntry() throws BlogClientException { + if (entriesCollection == null) { + throw new BlogClientException("No entry collection"); + } + return entriesCollection.newEntry(); + } + + /** + * {@inheritDoc} + */ + @Override + public BlogEntry getEntry(final String token) throws BlogClientException { + ClientEntry clientEntry = null; + try { + clientEntry = getService().getEntry(token); + } catch (final ProponoException ex) { + throw new BlogClientException("ERROR: fetching entry", ex); + } + if (clientEntry != null && clientEntry instanceof ClientMediaEntry) { + return new AtomResource(this, (ClientMediaEntry) clientEntry); + } else if (clientEntry != null && clientEntry instanceof ClientEntry) { + return new AtomEntry(this, clientEntry); + } else { + throw new BlogClientException("ERROR: unknown object type returned"); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator getEntries() throws BlogClientException { + if (entriesCollection == null) { + throw new BlogClientException("No primary entry collection"); + } + return new AtomEntryIterator(entriesCollection); + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator getResources() throws BlogClientException { + if (resourcesCollection == null) { + throw new BlogClientException("No primary entry collection"); + } + return new AtomEntryIterator(resourcesCollection); + } + + String saveEntry(final BlogEntry entry) throws BlogClientException { + if (entriesCollection == null) { + throw new BlogClientException("No primary entry collection"); + } + return entriesCollection.saveEntry(entry); + } + + void deleteEntry(final BlogEntry entry) throws BlogClientException { + if (entriesCollection == null) { + throw new BlogClientException("No primary entry collection"); + } + entriesCollection.deleteEntry(entry); + } + + /** + * {@inheritDoc} + */ + @Override + public List getCategories() throws BlogClientException { + if (entriesCollection == null) { + throw new BlogClientException("No primary entry collection"); + } + return entriesCollection.getCategories(); + } + + /** + * {@inheritDoc} + */ + @Override + public BlogResource newResource(final String name, final String contentType, final byte[] bytes) throws BlogClientException { + if (resourcesCollection == null) { + throw new BlogClientException("No resource collection"); + } + return resourcesCollection.newResource(name, contentType, bytes); + } + + String saveResource(final BlogResource res) throws BlogClientException { + if (resourcesCollection == null) { + throw new BlogClientException("No primary resource collection"); + } + return resourcesCollection.saveResource(res); + } + + void deleteResource(final BlogResource resource) throws BlogClientException { + deleteEntry(resource); + } + + /** + * {@inheritDoc} + */ + @Override + public List getCollections() throws BlogClientException { + return new ArrayList(collections.values()); + } + + /** + * {@inheritDoc} + */ + @Override + public Blog.Collection getCollection(final String token) throws BlogClientException { + return collections.get(token); + } + + ClientAtomService getService() { + return service; + } + + void setService(final ClientAtomService service) { + this.service = service; + } + + ClientWorkspace getWorkspace() { + return workspace; + } + + void setWorkspace(final ClientWorkspace workspace) { + this.workspace = workspace; + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomCollection.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomCollection.java new file mode 100644 index 0000000..d944b89 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomCollection.java @@ -0,0 +1,173 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient.atomprotocol; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.rometools.propono.atom.client.ClientAtomService; +import com.rometools.propono.atom.client.ClientCollection; +import com.rometools.propono.atom.client.ClientEntry; +import com.rometools.propono.atom.common.Categories; +import com.rometools.propono.blogclient.Blog; +import com.rometools.propono.blogclient.BlogClientException; +import com.rometools.propono.blogclient.BlogEntry; +import com.rometools.propono.blogclient.BlogResource; +import com.rometools.rome.feed.atom.Category; + +/** + * Atom protocol implementation of BlogClient Blog.Collection. + */ +public class AtomCollection implements Blog.Collection { + + private Blog blog = null; + private List categories = new ArrayList(); + + private ClientCollection clientCollection = null; + + AtomCollection(final AtomBlog blog, final ClientCollection col) { + this.blog = blog; + clientCollection = col; + for (final Object element : col.getCategories()) { + final Categories cats = (Categories) element; + for (final Object element2 : cats.getCategories()) { + final Category cat = (Category) element2; + final BlogEntry.Category blogCat = new BlogEntry.Category(cat.getTerm()); + blogCat.setName(cat.getLabel()); + blogCat.setUrl(cat.getScheme()); + getCategories().add(blogCat); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getTitle() { + return getClientCollection().getTitle(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getToken() { + return getClientCollection().getHrefResolved(); + } + + /** + * {@inheritDoc} + */ + @Override + public List getAccepts() { + return getClientCollection().getAccepts(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean accepts(final String ct) { + return getClientCollection().accepts(ct); + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator getEntries() throws BlogClientException { + return new AtomEntryIterator(this); + } + + /** + * {@inheritDoc} + */ + @Override + public BlogEntry newEntry() throws BlogClientException { + final AtomBlog atomBlog = (AtomBlog) getBlog(); + final BlogEntry entry = new AtomEntry(atomBlog, this); + return entry; + } + + /** + * {@inheritDoc} + */ + @Override + public BlogResource newResource(final String name, final String contentType, final byte[] bytes) throws BlogClientException { + return new AtomResource(this, name, contentType, bytes); + } + + /** + * {@inheritDoc} + */ + @Override + public String saveResource(final BlogResource res) throws BlogClientException { + ((AtomResource) res).setCollection(this); + res.save(); + return res.getContent().getSrc(); + } + + /** + * {@inheritDoc} + */ + @Override + public String saveEntry(final BlogEntry entry) throws BlogClientException { + ((AtomEntry) entry).setCollection(this); + entry.save(); + return entry.getPermalink(); + } + + void deleteEntry(final BlogEntry entry) throws BlogClientException { + try { + final ClientAtomService service = ((AtomBlog) getBlog()).getService(); + final ClientEntry clientEntry = service.getEntry(entry.getToken()); + clientEntry.remove(); + + } catch (final Exception e) { + throw new BlogClientException("ERROR deleting entry", e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Blog getBlog() { + return blog; + } + + void setBlog(final AtomBlog blog) { + this.blog = blog; + } + + /** + * {@inheritDoc} + */ + @Override + public List getCategories() { + return categories; + } + + void setCategories(final List categories) { + this.categories = categories; + } + + ClientCollection getClientCollection() { + return clientCollection; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomConnection.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomConnection.java new file mode 100644 index 0000000..db2cc78 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomConnection.java @@ -0,0 +1,85 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient.atomprotocol; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.rometools.propono.atom.client.AtomClientFactory; +import com.rometools.propono.atom.client.BasicAuthStrategy; +import com.rometools.propono.atom.client.ClientAtomService; +import com.rometools.propono.atom.client.ClientWorkspace; +import com.rometools.propono.atom.common.Workspace; +import com.rometools.propono.blogclient.Blog; +import com.rometools.propono.blogclient.BlogClientException; +import com.rometools.propono.blogclient.BlogConnection; + +/** + * Atom protocol of BlogConnection. Connects to Atom server, creates AtomBlog object for each Atom + * workspace found and within each blog a collection for each Atom collection found. + */ +public class AtomConnection implements BlogConnection { + + private final Map blogs = new HashMap(); + + /** + * Create Atom blog client instance for specified URL and user account. + * + * @param uri End-point URL of Atom service + * @param username Username of account + * @param password Password of account + */ + public AtomConnection(final String uri, final String username, final String password) throws BlogClientException { + + try { + final ClientAtomService service = AtomClientFactory.getAtomService(uri, new BasicAuthStrategy(username, password)); + final Iterator iter = service.getWorkspaces().iterator(); + while (iter.hasNext()) { + final ClientWorkspace workspace = (ClientWorkspace) iter.next(); + final Blog blog = new AtomBlog(service, workspace); + blogs.put(blog.getToken(), blog); + } + } catch (final Throwable t) { + throw new BlogClientException("Error connecting to blog server", t); + } + } + + /** + * {@inheritDoc} + */ + @Override + public List getBlogs() { + return new ArrayList(blogs.values()); + } + + /** + * {@inheritDoc} + */ + @Override + public Blog getBlog(final String token) { + return blogs.get(token); + } + + /** + * {@inheritDoc} + */ + @Override + public void setAppkey(final String appkey) { + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomEntry.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomEntry.java new file mode 100644 index 0000000..945473b --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomEntry.java @@ -0,0 +1,226 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient.atomprotocol; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.rometools.propono.atom.client.ClientEntry; +import com.rometools.propono.atom.common.rome.AppModule; +import com.rometools.propono.atom.common.rome.AppModuleImpl; +import com.rometools.propono.blogclient.BaseBlogEntry; +import com.rometools.propono.blogclient.BlogClientException; +import com.rometools.propono.blogclient.BlogEntry; +import com.rometools.propono.utils.ProponoException; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.module.Module; +import com.rometools.rome.feed.synd.SyndPerson; + +/** + * Atom protocol implementation of BlogEntry. + */ +public class AtomEntry extends BaseBlogEntry implements BlogEntry { + + String editURI = null; + AtomCollection collection = null; + + AtomEntry(final AtomBlog blog, final AtomCollection collection) throws BlogClientException { + super(blog); + this.collection = collection; + } + + AtomEntry(final AtomCollection collection, final ClientEntry entry) throws BlogClientException { + this((AtomBlog) collection.getBlog(), collection); + // clientEntry = entry; + copyFromRomeEntry(entry); + } + + AtomEntry(final AtomBlog blog, final ClientEntry entry) throws BlogClientException { + super(blog); + // clientEntry = entry; + copyFromRomeEntry(entry); + } + + @Override + public String getToken() { + return editURI; + } + + AtomCollection getCollection() { + return collection; + } + + void setCollection(final AtomCollection collection) { + this.collection = collection; + } + + /** + * True if entry's token's are equal. + */ + @Override + public boolean equals(final Object o) { + if (o instanceof AtomEntry) { + final AtomEntry other = (AtomEntry) o; + if (other.getToken() != null && getToken() != null) { + return other.getToken().equals(getToken()); + } + } + return false; + } + + @Override + public void save() throws BlogClientException { + final boolean create = getToken() == null; + if (create && getCollection() == null) { + throw new BlogClientException("Cannot save entry, no collection"); + } else if (create) { + try { + final ClientEntry clientEntry = collection.getClientCollection().createEntry(); + copyToRomeEntry(clientEntry); + collection.getClientCollection().addEntry(clientEntry); + copyFromRomeEntry(clientEntry); + } catch (final ProponoException ex) { + throw new BlogClientException("Error saving entry", ex); + } + } else { + try { + final ClientEntry clientEntry = ((AtomBlog) getBlog()).getService().getEntry(getToken()); + copyToRomeEntry(clientEntry); + clientEntry.update(); + copyFromRomeEntry(clientEntry); + } catch (final ProponoException ex) { + throw new BlogClientException("Error updating entry", ex); + } + } + } + + @Override + public void delete() throws BlogClientException { + if (getToken() == null) { + throw new BlogClientException("Cannot delete unsaved entry"); + } + try { + final ClientEntry clientEntry = ((AtomBlog) getBlog()).getService().getEntry(editURI); + clientEntry.remove(); + } catch (final ProponoException ex) { + throw new BlogClientException("Error removing entry", ex); + } + } + + void copyFromRomeEntry(final ClientEntry entry) { + id = entry.getId(); + title = entry.getTitle(); + editURI = entry.getEditURI(); + final List altlinks = entry.getAlternateLinks(); + if (altlinks != null) { + for (final Link link : altlinks) { + if ("alternate".equals(link.getRel()) || link.getRel() == null) { + permalink = link.getHrefResolved(); + break; + } + } + } + final List contents = entry.getContents(); + com.rometools.rome.feed.atom.Content romeContent = null; + if (contents != null && !contents.isEmpty()) { + romeContent = contents.get(0); + } + if (romeContent != null) { + content = new BlogEntry.Content(romeContent.getValue()); + content.setType(romeContent.getType()); + content.setSrc(romeContent.getSrc()); + } + if (entry.getCategories() != null) { + final List cats = new ArrayList(); + final List romeCats = entry.getCategories(); + for (final com.rometools.rome.feed.atom.Category romeCat : romeCats) { + final BlogEntry.Category cat = new BlogEntry.Category(); + cat.setId(romeCat.getTerm()); + cat.setUrl(romeCat.getScheme()); + cat.setName(romeCat.getLabel()); + cats.add(cat); + } + categories = cats; + } + final List authors = entry.getAuthors(); + if (authors != null && !authors.isEmpty()) { + final com.rometools.rome.feed.atom.Person romeAuthor = (com.rometools.rome.feed.atom.Person) authors.get(0); + if (romeAuthor != null) { + author = new Person(); + author.setName(romeAuthor.getName()); + author.setEmail(romeAuthor.getEmail()); + author.setUrl(romeAuthor.getUrl()); + } + } + publicationDate = entry.getPublished(); + modificationDate = entry.getModified(); + + final AppModule control = (AppModule) entry.getModule(AppModule.URI); + if (control != null && control.getDraft() != null) { + draft = control.getDraft().booleanValue(); + } else { + draft = false; + } + } + + Entry copyToRomeEntry(final ClientEntry entry) { + if (id != null) { + entry.setId(id); + } + entry.setTitle(title); + if (author != null) { + final com.rometools.rome.feed.atom.Person person = new com.rometools.rome.feed.atom.Person(); + person.setName(author.getName()); + person.setEmail(author.getEmail()); + person.setUrl(author.getUrl()); + final List authors = new ArrayList(); + authors.add(person); + entry.setAuthors(authors); + } + if (content != null) { + final com.rometools.rome.feed.atom.Content romeContent = new com.rometools.rome.feed.atom.Content(); + romeContent.setValue(content.getValue()); + romeContent.setType(content.getType()); + final List contents = new ArrayList(); + contents.add(romeContent); + entry.setContents(contents); + } + if (categories != null) { + final List romeCats = new ArrayList(); + for (final Category cat : categories) { + final com.rometools.rome.feed.atom.Category romeCategory = new com.rometools.rome.feed.atom.Category(); + romeCategory.setTerm(cat.getId()); + romeCategory.setScheme(cat.getUrl()); + romeCategory.setLabel(cat.getName()); + romeCats.add(romeCategory); + } + entry.setCategories(romeCats); + } + entry.setPublished(publicationDate == null ? new Date() : publicationDate); + entry.setModified(modificationDate == null ? new Date() : modificationDate); + + final List modules = new ArrayList(); + final AppModule control = new AppModuleImpl(); + control.setDraft(new Boolean(draft)); + modules.add(control); + entry.setModules(modules); + + return entry; + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomEntryIterator.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomEntryIterator.java new file mode 100644 index 0000000..74e0956 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomEntryIterator.java @@ -0,0 +1,80 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient.atomprotocol; + +import java.util.Iterator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.propono.atom.client.ClientEntry; +import com.rometools.propono.atom.client.ClientMediaEntry; +import com.rometools.propono.blogclient.BlogClientException; +import com.rometools.propono.blogclient.BlogEntry; + +/** + * Atom protocol implementation of BlogClient entry iterator. + */ +public class AtomEntryIterator implements Iterator { + + private static final Logger LOG = LoggerFactory.getLogger(AtomEntryIterator.class); + + private Iterator iterator = null; + private AtomCollection collection = null; + + AtomEntryIterator(final AtomCollection collection) throws BlogClientException { + try { + this.collection = collection; + iterator = collection.getClientCollection().getEntries(); + } catch (final Exception e) { + throw new BlogClientException("ERROR fetching collection", e); + } + } + + /** + * True if more entries are available. + */ + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + /** + * Get next entry. + */ + @Override + public BlogEntry next() { + try { + final ClientEntry entry = iterator.next(); + if (entry instanceof ClientMediaEntry) { + return new AtomResource(collection, (ClientMediaEntry) entry); + } else { + return new AtomEntry(collection, entry); + } + } catch (final Exception e) { + LOG.error("An error occured while fetching entry", e); + } + return null; + } + + /** + * Remove is not supported. + */ + @Override + public void remove() { + // optional method, not implemented + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomResource.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomResource.java new file mode 100644 index 0000000..59ccf60 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/atomprotocol/AtomResource.java @@ -0,0 +1,132 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient.atomprotocol; + +import java.io.InputStream; +import java.util.List; + +import com.rometools.propono.atom.client.ClientAtomService; +import com.rometools.propono.atom.client.ClientCollection; +import com.rometools.propono.atom.client.ClientEntry; +import com.rometools.propono.atom.client.ClientMediaEntry; +import com.rometools.propono.blogclient.BlogClientException; +import com.rometools.propono.blogclient.BlogEntry; +import com.rometools.propono.blogclient.BlogResource; +import com.rometools.rome.feed.atom.Link; + +/** + * Atom protocol implementation of BlogResource. + */ +public class AtomResource extends AtomEntry implements BlogResource { + + private AtomCollection collection; + private byte[] bytes; + + AtomResource(final AtomCollection collection, final String name, final String contentType, final byte[] bytes) throws BlogClientException { + super((AtomBlog) collection.getBlog(), collection); + this.collection = collection; + this.bytes = bytes; + final BlogEntry.Content rcontent = new BlogEntry.Content(); + rcontent.setType(contentType); + setContent(rcontent); + } + + AtomResource(final AtomCollection collection, final ClientMediaEntry entry) throws BlogClientException { + super(collection, entry); + } + + AtomResource(final AtomBlog blog, final ClientMediaEntry entry) throws BlogClientException { + super(blog, entry); + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return getTitle(); + } + + byte[] getBytes() { + return bytes; + } + + /** + * {@inheritDoc} + */ + @Override + public InputStream getAsStream() throws BlogClientException { + try { + return null; // ((ClientMediaEntry)clientEntry).getAsStream(); + } catch (final Exception e) { + throw new BlogClientException("Error creating entry", e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void save() throws BlogClientException { + try { + if (getToken() == null) { + final ClientAtomService clientService = ((AtomBlog) getBlog()).getService(); + final ClientCollection clientCollection = collection.getClientCollection(); + + final ClientMediaEntry clientEntry = new ClientMediaEntry(clientService, clientCollection, getTitle(), "", getContent().getType(), getBytes()); + + copyToRomeEntry(clientEntry); + collection.getClientCollection().addEntry(clientEntry); + editURI = clientEntry.getEditURI(); + + } else { + final ClientAtomService clientService = ((AtomBlog) getBlog()).getService(); + final ClientMediaEntry clientEntry = (ClientMediaEntry) clientService.getEntry(editURI); + clientEntry.update(); + } + } catch (final Exception e) { + throw new BlogClientException("Error creating entry", e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void update(final byte[] newBytes) throws BlogClientException { + try { + // ((ClientMediaEntry)clientEntry).setBytes(newBytes); + // clientEntry.update(); + } catch (final Exception e) { + throw new BlogClientException("Error creating entry", e); + } + } + + @Override + void copyFromRomeEntry(final ClientEntry entry) { + super.copyFromRomeEntry(entry); + final List links = entry.getOtherLinks(); + if (links != null) { + for (final Link link : links) { + if ("edit-media".equals(link.getRel())) { + id = link.getHrefResolved(); + break; + } + } + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/blogclient-diagram.gif b/rome-propono/src/main/java/com/rometools/propono/blogclient/blogclient-diagram.gif new file mode 100644 index 0000000..35dac52 Binary files /dev/null and b/rome-propono/src/main/java/com/rometools/propono/blogclient/blogclient-diagram.gif differ diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogBlog.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogBlog.java new file mode 100644 index 0000000..5367d57 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogBlog.java @@ -0,0 +1,467 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient.metaweblog; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import org.apache.xmlrpc.client.XmlRpcClient; +import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; + +import com.rometools.propono.blogclient.Blog; +import com.rometools.propono.blogclient.BlogClientException; +import com.rometools.propono.blogclient.BlogEntry; +import com.rometools.propono.blogclient.BlogEntry.Category; +import com.rometools.propono.blogclient.BlogResource; + +/** + * Blog implementation that uses a mix of Blogger and MetaWeblog API methods. + */ +public class MetaWeblogBlog implements Blog { + + private final String blogid; + private final String name; + private final URL url; + private final String userName; + private final String password; + private final Map collections; + + private String appkey = "dummy"; + private XmlRpcClient xmlRpcClient = null; + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public String getToken() { + return blogid; + } + + /** + * String representation of blog, returns the name. + */ + @Override + public String toString() { + return getName(); + } + + private XmlRpcClient getXmlRpcClient() { + + if (xmlRpcClient == null) { + final XmlRpcClientConfigImpl xmlrpcConfig = new XmlRpcClientConfigImpl(); + xmlrpcConfig.setServerURL(url); + xmlRpcClient = new XmlRpcClient(); + xmlRpcClient.setConfig(xmlrpcConfig); + } + return xmlRpcClient; + } + + MetaWeblogBlog(final String blogid, final String name, final URL url, final String userName, final String password) { + this.blogid = blogid; + this.name = name; + this.url = url; + this.userName = userName; + this.password = password; + collections = new TreeMap(); + collections.put("entries", new MetaWeblogBlogCollection(this, "entries", "Entries", "entry")); + collections.put("resources", new MetaWeblogBlogCollection(this, "resources", "Resources", "*")); + } + + MetaWeblogBlog(final String blogId, final String name, final URL url, final String userName, final String password, final String appkey) { + this(blogId, name, url, userName, password); + this.appkey = appkey; + } + + /** + * {@inheritDoc} + */ + @Override + public BlogEntry newEntry() { + return new MetaWeblogEntry(this, new HashMap()); + } + + String saveEntry(final BlogEntry entry) throws BlogClientException { + final Blog.Collection col = collections.get("entries"); + return col.saveEntry(entry); + } + + /** + * {@inheritDoc} + */ + @Override + public BlogEntry getEntry(final String id) throws BlogClientException { + try { + final Object[] params = new Object[] { id, userName, password }; + final Object response = getXmlRpcClient().execute("metaWeblog.getPost", params); + @SuppressWarnings("unchecked") + final Map result = (Map) response; + return new MetaWeblogEntry(this, result); + } catch (final Exception e) { + throw new BlogClientException("ERROR: XML-RPC error getting entry", e); + } + } + + void deleteEntry(final String id) throws BlogClientException { + try { + getXmlRpcClient().execute("blogger.deletePost", new Object[] { appkey, id, userName, password, Boolean.FALSE }); + } catch (final Exception e) { + throw new BlogClientException("ERROR: XML-RPC error getting entry", e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator getEntries() throws BlogClientException { + return new EntryIterator(); + } + + /** + * {@inheritDoc} + */ + @Override + public BlogResource newResource(final String name, final String contentType, final byte[] bytes) throws BlogClientException { + return new MetaWeblogResource(this, name, contentType, bytes); + } + + String saveResource(final MetaWeblogResource resource) throws BlogClientException { + final Blog.Collection col = collections.get("resources"); + return col.saveResource(resource); + } + + BlogResource getResource(final String token) throws BlogClientException { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public NoOpIterator getResources() throws BlogClientException { + return new NoOpIterator(); + } + + void deleteResource(final BlogResource resource) throws BlogClientException { + // no-op + } + + /** + * {@inheritDoc} + */ + @Override + public List getCategories() throws BlogClientException { + + final ArrayList ret = new ArrayList(); + + try { + + final Object result = getXmlRpcClient().execute("metaWeblog.getCategories", new Object[] { blogid, userName, password }); + + if (result != null && result instanceof HashMap) { + + // Standard MetaWeblog API style: struct of struts + @SuppressWarnings("unchecked") + final Map catsmap = (Map) result; + + final Set keys = catsmap.keySet(); + for (final String key : keys) { + @SuppressWarnings("unchecked") + final Map catmap = (Map) catsmap.get(key); + final BlogEntry.Category category = new BlogEntry.Category(key); + final String description = (String) catmap.get("description"); + category.setName(description); + // catmap.get("htmlUrl"); + // catmap.get("rssUrl"); + ret.add(category); + } + + } else if (result != null && result instanceof Object[]) { + // Wordpress style: array of structs + final Object[] array = (Object[]) result; + for (final Object map : array) { + @SuppressWarnings("unchecked") + final Map catmap = (Map) map; + final String categoryId = (String) catmap.get("categoryId"); + final String categoryName = (String) catmap.get("categoryName"); + final BlogEntry.Category category = new BlogEntry.Category(categoryId); + category.setName(categoryName); + ret.add(category); + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + + return ret; + + } + + private Map createPostStructure(final BlogEntry entry) { + return ((MetaWeblogEntry) entry).toPostStructure(); + } + + /** + * {@inheritDoc} + */ + @Override + public List getCollections() throws BlogClientException { + return new ArrayList(collections.values()); + } + + /** + * {@inheritDoc} + */ + @Override + public Blog.Collection getCollection(final String token) throws BlogClientException { + return collections.get(token); + } + + // ------------------------------------------------------------------------- + + /** MetaWeblog API impplementation of Blog.Collection */ + public class MetaWeblogBlogCollection implements Blog.Collection { + private String accept = null; + private String title = null; + private String token = null; + private Blog blog = null; + + /** + * @param token Identifier for collection, unique within blog + * @param title Title of collection + * @param accept Content types accepted, either "entry" or "*" + */ + public MetaWeblogBlogCollection(final Blog blog, final String token, final String title, final String accept) { + this.blog = blog; + this.accept = accept; + this.title = title; + this.token = token; + } + + /** + * {@inheritDoc} + */ + @Override + public String getTitle() { + return title; + } + + /** + * {@inheritDoc} + */ + @Override + public String getToken() { + return token; + } + + /** + * {@inheritDoc} + */ + @Override + public List getAccepts() { + return Collections.singletonList(accept); + } + + /** + * {@inheritDoc} + */ + @Override + public BlogResource newResource(final String name, final String contentType, final byte[] bytes) throws BlogClientException { + return blog.newResource(name, contentType, bytes); + } + + /** + * {@inheritDoc} + */ + @Override + public BlogEntry newEntry() throws BlogClientException { + return blog.newEntry(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean accepts(final String ct) { + if (accept.equals("*")) { + // everything accepted + return true; + } else if (accept.equals("entry") && ct.equals("application/metaweblog+xml")) { + // entries only accepted and "application/metaweblog+xml" means entry + return true; + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator getEntries() throws BlogClientException { + Iterator ret = null; + if (accept.equals("entry")) { + ret = MetaWeblogBlog.this.getEntries(); + } else { + ret = getResources(); + } + return ret; + } + + /** + * {@inheritDoc} + */ + @Override + public String saveEntry(final BlogEntry entry) throws BlogClientException { + String ret = entry.getId(); + if (entry.getId() == null) { + try { + ret = (String) getXmlRpcClient().execute("metaWeblog.newPost", + new Object[] { blogid, userName, password, createPostStructure(entry), new Boolean(!entry.getDraft()) }); + } catch (final Exception e) { + throw new BlogClientException("ERROR: XML-RPC error saving new entry", e); + } + } else { + try { + getXmlRpcClient().execute("metaWeblog.editPost", + new Object[] { entry.getId(), userName, password, createPostStructure(entry), new Boolean(!entry.getDraft()) }); + } catch (final Exception e) { + throw new BlogClientException("ERROR: XML-RPC error updating entry", e); + } + } + return ret; + } + + /** + * {@inheritDoc} + */ + @Override + public String saveResource(final BlogResource res) throws BlogClientException { + final MetaWeblogResource resource = (MetaWeblogResource) res; + try { + final HashMap resmap = new HashMap(); + resmap.put("name", resource.getName()); + resmap.put("type", resource.getContent().getType()); + resmap.put("bits", resource.getBytes()); + final Object[] params = new Object[] { blogid, userName, password, resmap }; + final Object response = getXmlRpcClient().execute("metaWeblog.newMediaObject", params); + @SuppressWarnings("unchecked") + final Map result = (Map) response; + final String url = (String) result.get("url"); + res.getContent().setSrc(url); + return url; + } catch (final Exception e) { + throw new BlogClientException("ERROR: loading or uploading file", e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public List getCategories() throws BlogClientException { + return MetaWeblogBlog.this.getCategories(); + } + + /** + * {@inheritDoc} + */ + @Override + public Blog getBlog() { + return blog; + } + } + + // ------------------------------------------------------------------------- + /** + * Iterates over MetaWeblog API entries. + */ + public class EntryIterator implements Iterator { + + private int pos = 0; + private boolean eod = false; + private static final int BUFSIZE = 30; + private List> results = null; + + /** + * Iterator for looping over MetaWeblog API entries. + */ + public EntryIterator() throws BlogClientException { + getNextEntries(); + } + + /** + * Returns true if more entries are avialable. + */ + @Override + public boolean hasNext() { + if (pos == results.size() && !eod) { + try { + getNextEntries(); + } catch (final Exception ignored) { + } + } + return pos < results.size(); + } + + /** + * Get next entry. + */ + @Override + public BlogEntry next() { + return new MetaWeblogEntry(MetaWeblogBlog.this, results.get(pos++)); + } + + /** + * Remove is not implemented. + */ + @Override + public void remove() { + } + + private void getNextEntries() throws BlogClientException { + final int requestSize = pos + BUFSIZE; + try { + final Object[] params = new Object[] { blogid, userName, password, new Integer(requestSize) }; + final Object response = getXmlRpcClient().execute("metaWeblog.getRecentPosts", params); + @SuppressWarnings("unchecked") + final Map[] resultsArray = (Map[]) response; + results = Arrays.asList(resultsArray); + } catch (final Exception e) { + throw new BlogClientException("ERROR: XML-RPC error getting entry", e); + } + if (results.size() < requestSize) { + eod = true; + } + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogConnection.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogConnection.java new file mode 100644 index 0000000..8800f19 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogConnection.java @@ -0,0 +1,106 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient.metaweblog; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.xmlrpc.XmlRpcException; +import org.apache.xmlrpc.client.XmlRpcClient; +import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; + +import com.rometools.propono.blogclient.Blog; +import com.rometools.propono.blogclient.BlogClientException; +import com.rometools.propono.blogclient.BlogConnection; + +/** + * BlogClient implementation that uses a mix of Blogger and MetaWeblog API methods. + */ +public class MetaWeblogConnection implements BlogConnection { + + private URL url = null; + private String userName = null; + private String password = null; + private String appkey = "null"; + private Map blogs = null; + + private XmlRpcClient xmlRpcClient = null; + + public MetaWeblogConnection(final String url, final String userName, final String password) throws BlogClientException { + this.userName = userName; + this.password = password; + try { + this.url = new URL(url); + blogs = createBlogMap(); + } catch (final Throwable t) { + throw new BlogClientException("ERROR connecting to server", t); + } + } + + private XmlRpcClient getXmlRpcClient() { + if (xmlRpcClient == null) { + final XmlRpcClientConfigImpl xmlrpcConfig = new XmlRpcClientConfigImpl(); + xmlrpcConfig.setServerURL(url); + xmlRpcClient = new XmlRpcClient(); + xmlRpcClient.setConfig(xmlrpcConfig); + } + return xmlRpcClient; + } + + /** + * {@inheritDoc} + */ + @Override + public List getBlogs() { + return new ArrayList(blogs.values()); + } + + /** + * {@inheritDoc} + */ + private Map createBlogMap() throws XmlRpcException, IOException { + final Map blogMap = new HashMap(); + final Object[] results = (Object[]) getXmlRpcClient().execute("blogger.getUsersBlogs", new Object[] { appkey, userName, password }); + for (final Object result : results) { + @SuppressWarnings("unchecked") + final Map blog = (Map) result; + final String blogid = (String) blog.get("blogid"); + final String name = (String) blog.get("blogName"); + blogMap.put(blogid, new MetaWeblogBlog(blogid, name, url, userName, password)); + } + return blogMap; + } + + /** + * {@inheritDoc} + */ + @Override + public Blog getBlog(final String token) { + return blogs.get(token); + } + + /** + * {@inheritDoc} + */ + @Override + public void setAppkey(final String appkey) { + this.appkey = appkey; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogEntry.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogEntry.java new file mode 100644 index 0000000..f558773 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogEntry.java @@ -0,0 +1,126 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient.metaweblog; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.rometools.propono.blogclient.BaseBlogEntry; +import com.rometools.propono.blogclient.BlogClientException; +import com.rometools.propono.blogclient.BlogEntry; + +/** + * MetaWeblog API implementation of an entry. + */ +public class MetaWeblogEntry extends BaseBlogEntry { + + MetaWeblogEntry(final MetaWeblogBlog blog, final Map entryMap) { + super(blog); + id = (String) entryMap.get("postid"); + + content = new Content((String) entryMap.get("description")); + + // let's pretend MetaWeblog API has a content-type + content.setType("application/metaweblog+xml"); + + // no way to tell if entry is draft or not + draft = false; + + title = (String) entryMap.get("title"); + publicationDate = (Date) entryMap.get("dateCreated"); + permalink = (String) entryMap.get("permaLink"); + + // AlexisMP: fix to get the author value populated. + author.setName((String) entryMap.get("userid")); + author.setEmail((String) entryMap.get("author")); + + categories = new ArrayList(); + final Object[] catArray = (Object[]) entryMap.get("categories"); + if (catArray != null) { + for (final Object element : catArray) { + final Category cat = new Category((String) element); + categories.add(cat); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getToken() { + return id; + } + + /** + * True if tokens are equal + */ + @Override + public boolean equals(final Object o) { + if (o instanceof MetaWeblogEntry) { + final MetaWeblogEntry other = (MetaWeblogEntry) o; + if (other.id != null && id != null) { + return other.id.equals(id); + } + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public void save() throws BlogClientException { + id = ((MetaWeblogBlog) getBlog()).saveEntry(this); + } + + /** + * {@inheritDoc} + */ + @Override + public void delete() throws BlogClientException { + ((MetaWeblogBlog) getBlog()).deleteEntry(id); + } + + Map toPostStructure() { + final Map struct = new HashMap(); + if (getTitle() != null) { + struct.put("title", getTitle()); + } + if (getContent() != null && getContent().getValue() != null) { + struct.put("description", getContent().getValue()); + } + if (getCategories() != null && !getCategories().isEmpty()) { + final List catArray = new ArrayList(); + final List cats = getCategories(); + for (int i = 0; i < cats.size(); i++) { + final BlogEntry.Category cat = cats.get(i); + catArray.add(cat.getName()); + } + struct.put("categories", catArray); + } + if (getPublicationDate() != null) { + struct.put("dateCreated", getPublicationDate()); + } + if (getId() != null) { + struct.put("postid", getId()); + } + return struct; + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogResource.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogResource.java new file mode 100644 index 0000000..440cd74 --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/MetaWeblogResource.java @@ -0,0 +1,121 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.blogclient.metaweblog; + +import java.io.InputStream; +import java.util.HashMap; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.methods.GetMethod; + +import com.rometools.propono.blogclient.BlogClientException; +import com.rometools.propono.blogclient.BlogResource; + +/** + * MetaWeblog API implementation of an resource entry. + */ +public class MetaWeblogResource extends MetaWeblogEntry implements BlogResource { + private final MetaWeblogBlog blog; + private final String name; + private final String contentType; + private byte[] bytes; + + MetaWeblogResource(final MetaWeblogBlog blog, final String name, final String contentType, final byte[] bytes) { + super(blog, new HashMap()); + this.blog = blog; + this.name = name; + this.contentType = contentType; + this.bytes = bytes; + content = new Content(); + content.setType(contentType); + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public String getToken() { + return null; + } + + /** + * Get content-type of associated media resource. + */ + public String getContentType() { + return contentType; + } + + /** + * Get media resource as input stream. + */ + @Override + public InputStream getAsStream() throws BlogClientException { + final HttpClient httpClient = new HttpClient(); + final GetMethod method = new GetMethod(permalink); + try { + httpClient.executeMethod(method); + } catch (final Exception e) { + throw new BlogClientException("ERROR: error reading file", e); + } + if (method.getStatusCode() != 200) { + throw new BlogClientException("ERROR HTTP status=" + method.getStatusCode()); + } + try { + return method.getResponseBodyAsStream(); + } catch (final Exception e) { + throw new BlogClientException("ERROR: error reading file", e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void save() throws BlogClientException { + blog.saveResource(this); + } + + /** + * {@inheritDoc} + */ + @Override + public void update(final byte[] bytes) throws BlogClientException { + this.bytes = bytes; + save(); + } + + /** + * Get resource data as byte array. + */ + public byte[] getBytes() { + return bytes; + } + + /** + * Not supported by MetaWeblog API + */ + @Override + public void delete() throws BlogClientException { + } +} diff --git a/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/NoOpIterator.java b/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/NoOpIterator.java new file mode 100644 index 0000000..7a77bcb --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/blogclient/metaweblog/NoOpIterator.java @@ -0,0 +1,24 @@ +package com.rometools.propono.blogclient.metaweblog; + +import java.util.Iterator; + +class NoOpIterator implements Iterator { + + /** No-op */ + @Override + public boolean hasNext() { + return false; + } + + /** No-op */ + @Override + public T next() { + return null; + } + + /** No-op */ + @Override + public void remove() { + } + +} \ No newline at end of file diff --git a/rome-propono/src/main/java/com/rometools/propono/utils/ProponoException.java b/rome-propono/src/main/java/com/rometools/propono/utils/ProponoException.java new file mode 100644 index 0000000..0ba8a6f --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/utils/ProponoException.java @@ -0,0 +1,154 @@ +/* + * Copyright 2007 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.rometools.propono.utils; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * Base Propono exception class. + */ +public class ProponoException extends Exception { + + private static final long serialVersionUID = 1L; + private Throwable mRootCause = null; + + /** + * Construct emtpy exception object. + */ + public ProponoException() { + super(); + } + + /** + * Construct ProponoException with message string. + * + * @param s Error message string. + */ + public ProponoException(final String s) { + super(s); + } + + /** + * Construct ProponoException with message string. + * + * @param s Error message string. + */ + public ProponoException(final String s, final String longMessage) { + super(s); + } + + /** + * Construct ProponoException, wrapping existing throwable. + * + * @param s Error message + * @param t Existing connection to wrap. + */ + public ProponoException(final String s, final Throwable t) { + super(s); + mRootCause = t; + } + + /** + * Construct ProponoException, wrapping existing throwable. + * + * @param s Error message + * @param t Existing connection to wrap. + */ + public ProponoException(final String s, final String longMessage, final Throwable t) { + super(s); + mRootCause = t; + } + + /** + * Construct ProponoException, wrapping existing throwable. + * + * @param t Existing exception to be wrapped. + */ + public ProponoException(final Throwable t) { + mRootCause = t; + } + + /** + * Get root cause object, or null if none. + * + * @return Root cause or null if none. + */ + public Throwable getRootCause() { + return mRootCause; + } + + /** + * Get root cause message. + * + * @return Root cause message. + */ + public String getRootCauseMessage() { + String rcmessage = null; + if (getRootCause() != null) { + if (getRootCause().getCause() != null) { + rcmessage = getRootCause().getCause().getMessage(); + } + rcmessage = rcmessage == null ? getRootCause().getMessage() : rcmessage; + rcmessage = rcmessage == null ? super.getMessage() : rcmessage; + rcmessage = rcmessage == null ? "NONE" : rcmessage; + } + return rcmessage; + } + + /** + * Print stack trace for exception and for root cause exception if htere is one. + * + * @see java.lang.Throwable#printStackTrace() + */ + @Override + public void printStackTrace() { + super.printStackTrace(); + if (mRootCause != null) { + System.out.println("--- ROOT CAUSE ---"); + mRootCause.printStackTrace(); + } + } + + /** + * Print stack trace for exception and for root cause exception if htere is one. + * + * @param s Stream to print to. + */ + @Override + public void printStackTrace(final PrintStream s) { + super.printStackTrace(s); + if (mRootCause != null) { + s.println("--- ROOT CAUSE ---"); + mRootCause.printStackTrace(s); + } + } + + /** + * Print stack trace for exception and for root cause exception if htere is one. + * + * @param s Writer to write to. + */ + @Override + public void printStackTrace(final PrintWriter s) { + super.printStackTrace(s); + if (null != mRootCause) { + s.println("--- ROOT CAUSE ---"); + mRootCause.printStackTrace(s); + } + } + +} diff --git a/rome-propono/src/main/java/com/rometools/propono/utils/Utilities.java b/rome-propono/src/main/java/com/rometools/propono/utils/Utilities.java new file mode 100644 index 0000000..e0da06e --- /dev/null +++ b/rome-propono/src/main/java/com/rometools/propono/utils/Utilities.java @@ -0,0 +1,270 @@ +/* + * Copyright 2007 Dave Johnson (Blogapps project) + * + * 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.rometools.propono.utils; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; +import java.util.regex.Pattern; + +/** + * Utilities for file I/O and string manipulation. + */ +public final class Utilities { + + private static final String LS = System.getProperty("line.separator"); + + private Utilities() { + } + + /** + * Returns the contents of the file in a byte array (from JavaAlmanac). + */ + public static byte[] getBytesFromFile(final File file) throws IOException { + + final InputStream is = new FileInputStream(file); + try { + + // Get the size of the file + final long length = file.length(); + + // You cannot create an array using a long type. + // It needs to be an int type. + // Before converting to an int type, check + // to ensure that file is not larger than Integer.MAX_VALUE. + if (length > Integer.MAX_VALUE) { + // File is too large + } + + // Create the byte array to hold the data + final byte[] bytes = new byte[(int) length]; + + // Read in the bytes + int offset = 0; + int numRead = 0; + while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) { + offset += numRead; + } + + // Ensure all the bytes have been read in + if (offset < bytes.length) { + throw new IOException("Could not completely read file " + file.getName()); + } + + return bytes; + + } finally { + is.close(); + } + } + + /** + * Read input from stream and into string. + */ + public static String streamToString(final InputStream is) throws IOException { + final StringBuffer sb = new StringBuffer(); + final BufferedReader in = new BufferedReader(new InputStreamReader(is)); + String line; + while ((line = in.readLine()) != null) { + sb.append(line); + sb.append(LS); + } + return sb.toString(); + } + + /** + * Copy input stream to output stream using 8K buffer. + */ + public static void copyInputToOutput(final InputStream input, final OutputStream output) throws IOException { + final BufferedInputStream in = new BufferedInputStream(input); + final BufferedOutputStream out = new BufferedOutputStream(output); + final byte buffer[] = new byte[8192]; + for (int count = 0; count != -1;) { + count = in.read(buffer, 0, 8192); + if (count != -1) { + out.write(buffer, 0, count); + } + } + + try { + in.close(); + out.close(); + } catch (final IOException ex) { + throw new IOException("Closing file streams, " + ex.getMessage()); + } + } + + /** + * Replaces occurences of non-alphanumeric characters with a supplied char. + */ + public static String replaceNonAlphanumeric(final String str, final char subst) { + final StringBuffer ret = new StringBuffer(str.length()); + final char[] testChars = str.toCharArray(); + for (final char testChar : testChars) { + if (Character.isLetterOrDigit(testChar)) { + ret.append(testChar); + } else { + ret.append(subst); + } + } + return ret.toString(); + } + + /** + * Convert string to string array. + */ + public static String[] stringToStringArray(final String instr, final String delim) throws NoSuchElementException, NumberFormatException { + final StringTokenizer toker = new StringTokenizer(instr, delim); + final String stringArray[] = new String[toker.countTokens()]; + int i = 0; + while (toker.hasMoreTokens()) { + stringArray[i++] = toker.nextToken(); + } + return stringArray; + } + + /** + * Convert string array to string. + */ + public static String stringArrayToString(final String[] stringArray, final String delim) { + String ret = ""; + for (final String element : stringArray) { + if (ret.length() > 0) { + ret = ret + delim + element; + } else { + ret = element; + } + } + return ret; + } + + static Pattern absoluteURIPattern = Pattern.compile("^[a-z0-9]*:.*$"); + + // private static boolean isAbsoluteURI(final String uri) { + // return absoluteURIPattern.matcher(uri).find(); + // } + + // private static boolean isRelativeURI(final String uri) { + // return !isAbsoluteURI(uri); + // } + + // /** + // * } Resolve URI based considering xml:base and baseURI. + // * + // * @param baseURI Base URI of feed + // * @param parent Parent from which to consider xml:base + // * @param url URL to be resolved + // */ + // private static String resolveURI(final String baseURI, final Parent parent, String url) { + // if (isRelativeURI(url)) { + // url = !".".equals(url) && !"./".equals(url) ? url : ""; + // + // // Relative URI with parent + // if (parent != null && parent instanceof Element) { + // + // // Do we have an xml:base? + // String xmlbase = ((Element) parent).getAttributeValue("base", Namespace.XML_NAMESPACE); + // if (xmlbase != null && xmlbase.trim().length() > 0) { + // if (isAbsoluteURI(xmlbase)) { + // // Absolute xml:base, so form URI right now + // if (url.startsWith("/")) { + // // Host relative URI + // final int slashslash = xmlbase.indexOf("//"); + // final int nextslash = xmlbase.indexOf("/", slashslash + 2); + // if (nextslash != -1) { + // xmlbase = xmlbase.substring(0, nextslash); + // } + // return formURI(xmlbase, url); + // } + // if (!xmlbase.endsWith("/")) { + // // Base URI is filename, strip it off + // xmlbase = xmlbase.substring(0, xmlbase.lastIndexOf("/")); + // } + // return formURI(xmlbase, url); + // } else { + // // Relative xml:base, so walk up tree + // return resolveURI(baseURI, parent.getParent(), stripTrailingSlash(xmlbase) + "/" + + // stripStartingSlash(url)); + // } + // } + // // No xml:base so walk up tree + // return resolveURI(baseURI, parent.getParent(), url); + // + // // Relative URI with no parent (i.e. top of tree), so form URI right now + // } else if (parent == null || parent instanceof Document) { + // return formURI(baseURI, url); + // } + // } + // return url; + // } + + // /** + // * Form URI by combining base with append portion and giving special consideration to append + // * portions that begin with ".." + // * + // * @param base Base of URI, may end with trailing slash + // * @param append String to append, may begin with slash or ".." + // */ + // private static String formURI(String base, String append) { + // base = stripTrailingSlash(base); + // append = stripStartingSlash(append); + // if (append.startsWith("..")) { + // final String ret = null; + // final String[] parts = append.split("/"); + // for (final String part : parts) { + // if ("..".equals(part)) { + // final int last = base.lastIndexOf("/"); + // if (last != -1) { + // base = base.substring(0, last); + // append = append.substring(3, append.length()); + // } else { + // break; + // } + // } + // } + // } + // return base + "/" + append; + // } + + // /** + // * Strip starting slash from beginning of string. + // */ + // private static String stripStartingSlash(String s) { + // if (s != null && s.startsWith("/")) { + // s = s.substring(1, s.length()); + // } + // return s; + // } + + // /** + // * Strip trailing slash from end of string. + // */ + // private static String stripTrailingSlash(String s) { + // if (s != null && s.endsWith("/")) { + // s = s.substring(0, s.length() - 1); + // } + // return s; + // } + +} diff --git a/rome-propono/src/main/resources/propono-version.properties b/rome-propono/src/main/resources/propono-version.properties new file mode 100644 index 0000000..118b2be --- /dev/null +++ b/rome-propono/src/main/resources/propono-version.properties @@ -0,0 +1 @@ +rome.propono.version=2.0.0 \ No newline at end of file diff --git a/rome-propono/src/main/resources/rome.properties b/rome-propono/src/main/resources/rome.properties new file mode 100644 index 0000000..a3e4af9 --- /dev/null +++ b/rome-propono/src/main/resources/rome.properties @@ -0,0 +1,7 @@ +# Configures Propono APP extension module + +atom_1.0.item.ModuleParser.classes=\ +com.rometools.propono.atom.common.rome.AppModuleParser + +atom_1.0.item.ModuleGenerator.classes=\ +com.rometools.propono.atom.common.rome.AppModuleGenerator diff --git a/rome-propono/src/site/apt/ROMEProponoVersion0.4.apt b/rome-propono/src/site/apt/ROMEProponoVersion0.4.apt new file mode 100644 index 0000000..5022c68 --- /dev/null +++ b/rome-propono/src/site/apt/ROMEProponoVersion0.4.apt @@ -0,0 +1,29 @@ + ----- + ROME Propono Version 0.4 + ----- + mkurz + ----- + 2011-08-16 04:52:04.427 + ----- + +ROME Propono Version 0.4 + + This is the first release of the {{{./index.html}Rome Propono}} publishing library. It's a beta release and will be followed closely by Propono 0.5. + +*Downloads + + * {{{./rome\-propono\-0.4\-src.zip}rome\-propono\-0.4\-src.zip}} + + * {{{./rome\-propono\-0.4.tar.gz}rome\-propono\-0.4.tar.gz}} + + * {{{./rome\-propono\-0.4.zip}rome\-propono\-0.4.zip}} + + * {{{./rome\-propono\-0.4\-src.tar.gz}rome\-propono\-0.4\-src.tar.gz}} + + [] + +*API Docs + + * {{{https://rome.dev.java.net/apidocs/subprojects/propono/0.4/overview\-summary.html}Propono 0.4 API Docs}} + + [] diff --git a/rome-propono/src/site/apt/ROMEProponoVersion0.5.apt b/rome-propono/src/site/apt/ROMEProponoVersion0.5.apt new file mode 100644 index 0000000..a125d44 --- /dev/null +++ b/rome-propono/src/site/apt/ROMEProponoVersion0.5.apt @@ -0,0 +1,39 @@ + ----- + ROME Propono Version 0.5 + ----- + mkurz + ----- + 2011-08-16 04:50:16.111 + ----- + +ROME Propono Version 0.5 + + This is the second release of the {{{./index.html}Rome Propono}} publishing library. It's a bug fix release follow\-on to 0.4. Here are the changes: + + * Fixes in Blog Client constructors + + * AtomServlet uses application/atomsvc\+xml for the Service Document + + * Fixed issue #66: don't expect entry to be returned from update + + * Made example builds more configurable + + [] + +*Downloads + + * {{{./rome\-propono\-0.5\-src.zip}rome\-propono\-0.5\-src.zip}} + + * {{{./rome\-propono\-0.5.tar.gz}rome\-propono\-0.5.tar.gz}} + + * {{{./rome\-propono\-0.5.zip}rome\-propono\-0.5.zip}} + + * {{{./rome\-propono\-0.5\-src.tar.gz}rome\-propono\-0.5\-src.tar.gz}} + + [] + +*API Docs + + * {{{https://rome.dev.java.net/apidocs/subprojects/propono/0.5/overview\-summary.html}Propono 0.5 API Docs}} + + [] diff --git a/rome-propono/src/site/apt/ROMEProponoVersion0.6.apt b/rome-propono/src/site/apt/ROMEProponoVersion0.6.apt new file mode 100644 index 0000000..5ecb57f --- /dev/null +++ b/rome-propono/src/site/apt/ROMEProponoVersion0.6.apt @@ -0,0 +1,85 @@ + ----- + ROME Propono Version 0.6 + ----- + mkurz + ----- + 2011-08-16 04:48:12.766 + ----- + +ROME Propono Version 0.6 + + September 30, 2007 + + This is the third release of the {{{./index.html}Rome Propono}} publishing library. It includes major changes to add support for the final + Atom Publishing Protocol specification relative URIs and out\-of\-line categories. It's an an interim release it includes a pre\-release + version of ROME 0.9.1\-dev. A new version will follow as soon as ROME 0.9.1 (or 1.0) has been finalized. + +*Downloads + + * {{{./rome\-propono\-0.6\-src.zip}rome\-propono\-0.6\-src.zip}} + + * {{{./rome\-propono\-0.6.tar.gz}rome\-propono\-0.6.tar.gz}} + + * {{{./rome\-propono\-0.6.zip}rome\-propono\-0.6.zip}} + + * {{{./rome\-propono\-0.6\-src.tar.gz}rome\-propono\-0.6\-src.tar.gz}} + + [] + +*API Docs + + * {{{https://rome.dev.java.net/apidocs/subprojects/propono/0.6/overview\-summary.html}Propono 0.6 API Docs}} + + [] + +*Changes + + * Updated for APP final (draft #17) w/new APP URI "http://www.w3.org/2007/app" + + * Tested file\-based server against Tim Bray's Ape (from CVS September 30, 2007). + + * Now includes pre\-release of ROME 0.9.1 with key Atom parse fixes. + + * Changed arguements in Atom server's AtomHandler interface to accept AtomRequest objects instead of String\[\] pathinfo arrays. + + * Added support for relative URIs in the Service Document + + * Fixes {{{http://java.net/jira/browse/ROME\-67}http://java.net/jira/browse/ROME\-67}} + + * Added Collection.getHrefResolved() + + * Added Categories.getHrefResolved() + + * Added new options to the file\-based server's propono.properties file so you can turn on/off relative URIs and inline categories. + + * propono.atomserver.filebased.relativeURIs\=true + + * propono.atomserver.filebased.inlineCategories\=true + + * Added support for out\-of\-line categories in Atom client classes + + * Added new Categories.href property + + * New ClientCategories classes can fetch remote categories from href URI + + * Fixes {{{http://java.net/jira/browse/ROME\-68}http://java.net/jira/browse/ROME\-68}} + + * Added support for out\-of\-line categories in Atom server classes + + * New AtomHandler.getCategoriesDocument(String\[\] pathInfo) method + + * New AtomHandler.isCategoriesDocumentURI(String\[\] pathInfo) method + + * Renamed Introspection to Service Document + + * AtomHandler.isIntrospectionURI() \-\> AtomHandler.isSerivceDocumentURI() + + * AtomHandler.getIntrospection() \-\> AtomHandler.getServiceDocument() + + * Added String\[\] pathInfo argument to getServiceDocument() + + * Renamed PubControlModule to AppModule becuase it also supports app:edited + + * Added rome.properties file to configure AppModule + + [] diff --git a/rome-propono/src/site/apt/ROMEProponoVersion1.0.apt b/rome-propono/src/site/apt/ROMEProponoVersion1.0.apt new file mode 100644 index 0000000..621a6f5 --- /dev/null +++ b/rome-propono/src/site/apt/ROMEProponoVersion1.0.apt @@ -0,0 +1,41 @@ + ----- + ROME Propono Version 1.0 + ----- + mkurz + ----- + 2011-08-16 04:44:34.302 + ----- + +ROME Propono Version 1.0 + + April 2009 + + ROME Propono 1.0 is coming soon. If you'd like to help out, you can try 1.0 RC1 and provide feedback to us on the ROME dev mail list. + +*Downloads + + * {{{./rome\-propono\-1.0RC1\-src.zip}rome\-propono\-1.0RC1\-src.zip}} + + * {{{./rome\-propono\-1.0RC1.tar.gz}rome\-propono\-1.0RC1.tar.gz}} + + * {{{./rome\-propono\-1.0RC1.zip}rome\-propono\-1.0RC1.zip}} + + * {{{./rome\-propono\-1.0RC1\-src.tar.gz}rome\-propono\-1.0RC1\-src.tar.gz}} + + [] + +*API Docs + + * {{{https://rome.dev.java.net/apidocs/subprojects/propono/1.0/overview\-summary.html}Propono 1.0 API Docs}} + + [] + +*Changes + + * Updated to ROME 1.0 + + * Added support for pluggable authentication in the AtomPub client + + * Added support for OAuth in the AtomPub client, see Javadocs for details + + [] diff --git a/rome-propono/src/site/apt/index.apt b/rome-propono/src/site/apt/index.apt new file mode 100644 index 0000000..724bd95 --- /dev/null +++ b/rome-propono/src/site/apt/index.apt @@ -0,0 +1,31 @@ + ----- + Home + ----- + mkurz + ----- + 2011-08-16 04:43:25.062 + ----- + +ROME Propono + + The ROME Propono subproject is a Java class library that supports publishing protocols, specifically the Atom Publishing Protocol and the legacy MetaWeblog API. + Propono includes an Atom client library, an Atom server framework and a Blog client that supports both Atom protocol and the MetaWeblog API. + +Documentation + + * See the {{{./apidocs/overview\-summary.html}Propono API docs}} for an explanation of Propono usage, diagrams and code examples. + + [] + +Releases + + * {{{./ROMEProponoVersion1.0.html}ROME Propono Version 1.0 (propono)}} \- Release 1.0 coming soon... + + * {{{./ROMEProponoVersion0.6.html}ROME Propono Version 0.6 (propono)}} + + * {{{./ROMEProponoVersion0.5.html}ROME Propono Version 0.5 (propono)}} + + * {{{./ROMEProponoVersion0.4.html}ROME Propono Version 0.4 (propono)}} + + [] + \ No newline at end of file diff --git a/rome-propono/src/site/resources/.nojekyll b/rome-propono/src/site/resources/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/rome-propono/src/site/resources/css/site.css b/rome-propono/src/site/resources/css/site.css new file mode 100644 index 0000000..43c3cd8 --- /dev/null +++ b/rome-propono/src/site/resources/css/site.css @@ -0,0 +1,8 @@ +h1 { + padding: 4px 4px 4px 6px; + border: 1px solid #999; + color: #900; + background-color: #ddd; + font-weight:900; + font-size: x-large; +} \ No newline at end of file diff --git a/rome-propono/src/site/resources/images/romelogo.png b/rome-propono/src/site/resources/images/romelogo.png new file mode 100644 index 0000000..2c90608 Binary files /dev/null and b/rome-propono/src/site/resources/images/romelogo.png differ diff --git a/rome-propono/src/site/resources/rome-propono-0.4-src.tar.gz b/rome-propono/src/site/resources/rome-propono-0.4-src.tar.gz new file mode 100644 index 0000000..39dd993 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.4-src.tar.gz differ diff --git a/rome-propono/src/site/resources/rome-propono-0.4-src.zip b/rome-propono/src/site/resources/rome-propono-0.4-src.zip new file mode 100644 index 0000000..e65fb8a Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.4-src.zip differ diff --git a/rome-propono/src/site/resources/rome-propono-0.4.tar.gz b/rome-propono/src/site/resources/rome-propono-0.4.tar.gz new file mode 100644 index 0000000..a7f1ddf Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.4.tar.gz differ diff --git a/rome-propono/src/site/resources/rome-propono-0.4.zip b/rome-propono/src/site/resources/rome-propono-0.4.zip new file mode 100644 index 0000000..fedeae3 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.4.zip differ diff --git a/rome-propono/src/site/resources/rome-propono-0.5-src.tar.gz b/rome-propono/src/site/resources/rome-propono-0.5-src.tar.gz new file mode 100644 index 0000000..03f79b4 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.5-src.tar.gz differ diff --git a/rome-propono/src/site/resources/rome-propono-0.5-src.zip b/rome-propono/src/site/resources/rome-propono-0.5-src.zip new file mode 100644 index 0000000..421dbac Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.5-src.zip differ diff --git a/rome-propono/src/site/resources/rome-propono-0.5.tar.gz b/rome-propono/src/site/resources/rome-propono-0.5.tar.gz new file mode 100644 index 0000000..013163b Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.5.tar.gz differ diff --git a/rome-propono/src/site/resources/rome-propono-0.5.zip b/rome-propono/src/site/resources/rome-propono-0.5.zip new file mode 100644 index 0000000..5489239 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.5.zip differ diff --git a/rome-propono/src/site/resources/rome-propono-0.6-src.tar.gz b/rome-propono/src/site/resources/rome-propono-0.6-src.tar.gz new file mode 100644 index 0000000..f98f9f4 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.6-src.tar.gz differ diff --git a/rome-propono/src/site/resources/rome-propono-0.6-src.zip b/rome-propono/src/site/resources/rome-propono-0.6-src.zip new file mode 100644 index 0000000..641f438 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.6-src.zip differ diff --git a/rome-propono/src/site/resources/rome-propono-0.6.tar.gz b/rome-propono/src/site/resources/rome-propono-0.6.tar.gz new file mode 100644 index 0000000..e287903 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.6.tar.gz differ diff --git a/rome-propono/src/site/resources/rome-propono-0.6.zip b/rome-propono/src/site/resources/rome-propono-0.6.zip new file mode 100644 index 0000000..8986f22 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-0.6.zip differ diff --git a/rome-propono/src/site/resources/rome-propono-1.0RC1-src.tar.gz b/rome-propono/src/site/resources/rome-propono-1.0RC1-src.tar.gz new file mode 100644 index 0000000..a187e6f Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-1.0RC1-src.tar.gz differ diff --git a/rome-propono/src/site/resources/rome-propono-1.0RC1-src.zip b/rome-propono/src/site/resources/rome-propono-1.0RC1-src.zip new file mode 100644 index 0000000..b3b9fa9 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-1.0RC1-src.zip differ diff --git a/rome-propono/src/site/resources/rome-propono-1.0RC1.tar.gz b/rome-propono/src/site/resources/rome-propono-1.0RC1.tar.gz new file mode 100644 index 0000000..5ef8766 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-1.0RC1.tar.gz differ diff --git a/rome-propono/src/site/resources/rome-propono-1.0RC1.zip b/rome-propono/src/site/resources/rome-propono-1.0RC1.zip new file mode 100644 index 0000000..de9ca52 Binary files /dev/null and b/rome-propono/src/site/resources/rome-propono-1.0RC1.zip differ diff --git a/rome-propono/src/site/site.xml b/rome-propono/src/site/site.xml new file mode 100644 index 0000000..08f97b4 --- /dev/null +++ b/rome-propono/src/site/site.xml @@ -0,0 +1,30 @@ + + + + + org.apache.maven.skins + maven-fluido-skin + 1.3.0 + + + + ROME + images/romelogo.png + http://github.com/rometools/ + + + + + + + +

      + + + + + + \ No newline at end of file diff --git a/rome-propono/src/test/java/com/rometools/propono/atom/client/AtomClientTest.java b/rome-propono/src/test/java/com/rometools/propono/atom/client/AtomClientTest.java new file mode 100644 index 0000000..58739e3 --- /dev/null +++ b/rome-propono/src/test/java/com/rometools/propono/atom/client/AtomClientTest.java @@ -0,0 +1,420 @@ +/* + * Copyright 2007 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.rometools.propono.atom.client; + +import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.junit.Ignore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.propono.atom.common.Categories; +import com.rometools.propono.atom.common.Collection; +import com.rometools.propono.utils.ProponoException; +import com.rometools.rome.feed.atom.Category; +import com.rometools.rome.feed.atom.Content; + +/** + * Simple APP test designed to run against a live Atom server. + */ +@Ignore +public class AtomClientTest extends TestCase { + + private static Logger log = LoggerFactory.getLogger(AtomClientTest.class); + + private static ClientAtomService service = null; + + // Basic Auth example + private static String endpoint = "http://localhost:8080/sample-atomserver/app"; + private static String username = "admin"; + private static String password = "admin"; + static { + try { + service = AtomClientFactory.getAtomService(endpoint, new BasicAuthStrategy(username, password)); + } catch (final Exception e) { + log.error("ERROR creating service", e); + } + } + + /* + * // Roller OAuth example private static String endpoint = + * "http://macsnoopdave:8080/roller-services/app"; private static String consumerKey = + * "55132608a2fb68816bcd3d1caeafc933"; private static String consumerSecret = + * "bb420783-fdea-4270-ab83-36445c18c307"; private static String requestUri = + * "http://macsnoopdave:8080/roller-services/oauth/requestToken"; private static String + * authorizeUri = + * "http://macsnoopdave:8080/roller-services/oauth/authorize?userId=roller&oauth_callback=none"; + * private static String accessUri = + * "http://macsnoopdave:8080/roller-services/oauth/accessToken"; private static String username + * = "roller"; private static String password = "n/a"; static { try { service = + * AtomClientFactory.getAtomService(endpoint, new OAuthStrategy( username, consumerKey, + * consumerSecret, "HMAC-SHA1", requestUri, authorizeUri, accessUri)); } catch (Exception e) { + * log.error("ERROR creating service", e); } } + */ + + // GData Blogger API + /* + * private static String endpoint = + * "http://www.blogger.com/feeds/default/blogs?alt=atom-service"; private static String email = + * "EMAIL"; private static String password = "PASSWORD"; private static String serviceName = + * "blogger"; static { try { service = AtomClientFactory.getAtomService(endpoint, new + * GDataAuthStrategy(email, password, serviceName)); } catch (Exception e) { + * log.error("ERROR creating service", e); } } + */ + + public AtomClientTest(final String testName) { + super(testName); + } + + public String getEndpoint() { + return endpoint; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + public static Test suite() { + final TestSuite suite = new TestSuite(AtomClientTest.class); + return suite; + } + + /** + * Tests that server has introspection doc with at least one workspace. + */ + public void testGetAtomService() throws Exception { + assertNotNull(service); + assertTrue(!service.getWorkspaces().isEmpty()); + for (final Object element : service.getWorkspaces()) { + final ClientWorkspace space = (ClientWorkspace) element; + assertNotNull(space.getTitle()); + log.debug("Workspace: " + space.getTitle()); + for (final Object element2 : space.getCollections()) { + final ClientCollection col = (ClientCollection) element2; + log.debug(" Collection: " + col.getTitle() + " Accepts: " + col.getAccepts()); + log.debug(" href: " + col.getHrefResolved()); + assertNotNull(col.getTitle()); + } + } + } + + /** + * Tests that entries can be posted and removed in all collections that accept entries. Fails if + * no collections found that accept entries. + */ + public void testSimpleEntryPostAndRemove() throws Exception { + assertNotNull(service); + assertTrue(!service.getWorkspaces().isEmpty()); + int count = 0; + for (final Object element : service.getWorkspaces()) { + final ClientWorkspace space = (ClientWorkspace) element; + assertNotNull(space.getTitle()); + + for (final Object element2 : space.getCollections()) { + final ClientCollection col = (ClientCollection) element2; + if (col.accepts(Collection.ENTRY_TYPE)) { + + // we found a collection that accepts entries, so post one + final ClientEntry m1 = col.createEntry(); + m1.setTitle("Test post"); + final Content c = new Content(); + c.setValue("This is a test post"); + c.setType("html"); + m1.setContent(c); + + col.addEntry(m1); + + // entry should now exist on server + final ClientEntry m2 = col.getEntry(m1.getEditURI()); + assertNotNull(m2); + + // remove entry + m2.remove(); + + // fetching entry now should result in exception + boolean failed = false; + try { + col.getEntry(m1.getEditURI()); + } catch (final ProponoException e) { + failed = true; + } + assertTrue(failed); + count++; + } + } + } + assertTrue(count > 0); + } + + /** + * Tests that entries can be posted, updated and removed in all collections that accept entries. + * Fails if no collections found that accept entries. + */ + public void testSimpleEntryPostUpdateAndRemove() throws Exception { + assertNotNull(service); + assertTrue(!service.getWorkspaces().isEmpty()); + int count = 0; + for (final Object element : service.getWorkspaces()) { + final ClientWorkspace space = (ClientWorkspace) element; + assertNotNull(space.getTitle()); + + for (final Object element2 : space.getCollections()) { + final ClientCollection col = (ClientCollection) element2; + if (col.accepts(Collection.ENTRY_TYPE)) { + + // we found a collection that accepts entries, so post one + final ClientEntry m1 = col.createEntry(); + m1.setTitle(col.getTitle() + ": Test post"); + final Content c = new Content(); + c.setValue("This is a test post"); + c.setType("html"); + m1.setContent(c); + + col.addEntry(m1); + + // entry should now exist on server + final ClientEntry m2 = col.getEntry(m1.getEditURI()); + assertNotNull(m2); + + m2.setTitle(col.getTitle() + ": Updated title"); + m2.update(); + + // entry should now be updated on server + final ClientEntry m3 = col.getEntry(m1.getEditURI()); + assertEquals(col.getTitle() + ": Updated title", m3.getTitle()); + + // remove entry + m3.remove(); + + // fetching entry now should result in exception + boolean failed = false; + try { + col.getEntry(m1.getEditURI()); + } catch (final ProponoException e) { + failed = true; + } + assertTrue(failed); + count++; + } + } + } + assertTrue(count > 0); + } + + public void testFindWorkspace() throws Exception { + assertNotNull(service); + final ClientWorkspace ws = (ClientWorkspace) service.findWorkspace("adminblog"); + if (ws != null) { + final ClientCollection col = (ClientCollection) ws.findCollection(null, "entry"); + final ClientEntry entry = col.createEntry(); + entry.setTitle("NPE on submitting order query"); + entry.setContent("This is a bad one!", Content.HTML); + col.addEntry(entry); + + // entry should now exist on server + final ClientEntry saved = col.getEntry(entry.getEditURI()); + assertNotNull(saved); + + // remove entry + saved.remove(); + + // fetching entry now should result in exception + boolean failed = false; + try { + col.getEntry(saved.getEditURI()); + } catch (final ProponoException e) { + failed = true; + } + assertTrue(failed); + } + } + + /** + * Test posting an entry to every available collection with a fixed and an unfixed category if + * server support allows, then cleanup. + */ + public void testEntryPostWithCategories() throws Exception { + assertNotNull(service); + assertTrue(!service.getWorkspaces().isEmpty()); + int count = 0; + for (final Object element2 : service.getWorkspaces()) { + final ClientWorkspace space = (ClientWorkspace) element2; + assertNotNull(space.getTitle()); + + for (final Object element3 : space.getCollections()) { + final ClientCollection col = (ClientCollection) element3; + if (col.accepts(Collection.ENTRY_TYPE)) { + + // we found a collection that accepts GIF, so post one + final ClientEntry m1 = col.createEntry(); + m1.setTitle("Test post"); + final Content c = new Content(); + c.setValue("This is a test post"); + c.setType("html"); + m1.setContent(c); + + // if possible, pick one fixed an un unfixed category + Category fixedCat = null; + Category unfixedCat = null; + final List entryCats = new ArrayList(); + for (int i = 0; i < col.getCategories().size(); i++) { + final Categories cats = col.getCategories().get(i); + if (cats.isFixed() && fixedCat == null) { + final String scheme = cats.getScheme(); + fixedCat = cats.getCategories().get(0); + if (fixedCat.getScheme() == null) { + fixedCat.setScheme(scheme); + } + entryCats.add(fixedCat); + } else if (!cats.isFixed() && unfixedCat == null) { + final String scheme = cats.getScheme(); + unfixedCat = new Category(); + unfixedCat.setScheme(scheme); + unfixedCat.setTerm("tagster"); + entryCats.add(unfixedCat); + } + } + m1.setCategories(entryCats); + col.addEntry(m1); + + // entry should now exist on server + final ClientEntry m2 = col.getEntry(m1.getEditURI()); + assertNotNull(m2); + + if (fixedCat != null) { + // we added a fixed category, let's make sure it's there + boolean foundCat = false; + for (final Object element : m2.getCategories()) { + final Category cat = (Category) element; + if (cat.getTerm().equals(fixedCat.getTerm())) { + foundCat = true; + } + } + assertTrue(foundCat); + } + + if (unfixedCat != null) { + // we added an unfixed category, let's make sure it's there + boolean foundCat = false; + for (final Object element : m2.getCategories()) { + final Category cat = (Category) element; + if (cat.getTerm().equals(unfixedCat.getTerm())) { + foundCat = true; + } + } + assertTrue(foundCat); + } + + // remove entry + m2.remove(); + + // fetching entry now should result in exception + boolean failed = false; + try { + col.getEntry(m1.getEditURI()); + } catch (final ProponoException e) { + failed = true; + } + assertTrue(failed); + count++; + } + } + } + assertTrue(count > 0); + } + + /** + * Post media entry to every media colletion avialable on server, then cleanup. + */ + public void testMediaPost() throws Exception { + assertNotNull(service); + assertTrue(!service.getWorkspaces().isEmpty()); + int count = 0; + for (final Object element : service.getWorkspaces()) { + final ClientWorkspace space = (ClientWorkspace) element; + assertNotNull(space.getTitle()); + + for (final Object element2 : space.getCollections()) { + final ClientCollection col = (ClientCollection) element2; + if (col.accepts("image/gif")) { + + // we found a collection that accepts GIF, so post one + final ClientMediaEntry m1 = col.createMediaEntry("duke" + count, "duke" + count, "image/gif", new FileInputStream( + "test/testdata/duke-wave-shadow.gif")); + col.addEntry(m1); + + // entry should now exist on server + final ClientMediaEntry m2 = (ClientMediaEntry) col.getEntry(m1.getEditURI()); + assertNotNull(m2); + + // remove entry + m2.remove(); + + // fetching entry now should result in exception + boolean failed = false; + try { + col.getEntry(m1.getEditURI()); + } catch (final ProponoException e) { + failed = true; + } + assertTrue(failed); + count++; + } + } + } + assertTrue(count > 0); + } + + /** + * Post X media entries each media collection found, test paging, then cleanup. + * + * public void testMediaPaging() throws Exception { ClientAtomService service = + * getClientAtomService(); assertNotNull(service); assertTrue(service.getWorkspaces().size() > + * 0); int count = 0; for (Iterator it = service.getWorkspaces().iterator(); it.hasNext();) { + * ClientWorkspace space = (ClientWorkspace) it.next(); assertNotNull(space.getTitle()); + * + * for (Iterator colit = space.getCollections().iterator(); colit.hasNext();) { ClientCollection + * col = (ClientCollection) colit.next(); if (col.accepts("image/gif")) { + * + * // we found a collection that accepts GIF, so post 100 of them List posted = new ArrayList(); + * for (int i=0; i= maxPagingEntries); count++; break; } } } + * assertTrue(count > 0); } + */ +} diff --git a/rome-propono/src/test/java/com/rometools/propono/atom/client/BloggerDotComTest.java b/rome-propono/src/test/java/com/rometools/propono/atom/client/BloggerDotComTest.java new file mode 100644 index 0000000..b1aa31b --- /dev/null +++ b/rome-propono/src/test/java/com/rometools/propono/atom/client/BloggerDotComTest.java @@ -0,0 +1,88 @@ +/* + * Copyright 2007 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.rometools.propono.atom.client; + +import java.util.Iterator; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.junit.Ignore; + +import com.rometools.rome.feed.atom.Content; + +/** + * Simple APP test designed to run against Blogger.com. + */ +@Ignore +public class BloggerDotComTest extends TestCase { + + private final String collectionURI = "http://www.blogger.com/feeds/BLOGID/posts/default"; + // private final String atomServiceURI = + // "http://www.blogger.com/feeds/default/blogs?alt=atom-service"; + private final String email = "EMAIL"; + private final String password = "PASSWORD"; + + public BloggerDotComTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + public static Test suite() { + final TestSuite suite = new TestSuite(BloggerDotComTest.class); + return suite; + } + + /** + * Verify that server returns service document containing workspaces containing collections. + */ + public void testGetEntries() throws Exception { + + // no auth necessary for iterating through entries + ClientCollection col = AtomClientFactory.getCollection(collectionURI, new GDataAuthStrategy(email, password, "blogger")); + assertNotNull(col); + int count = 0; + for (final Iterator it = col.getEntries(); it.hasNext();) { + final ClientEntry entry = it.next(); + assertNotNull(entry); + count++; + } + assertTrue(count > 0); + + col = AtomClientFactory.getCollection(collectionURI, new GDataAuthStrategy(email, password, "blogger")); + final ClientEntry p1 = col.createEntry(); + p1.setTitle("Propono post"); + final Content c = new Content(); + c.setValue("This is content from ROME Propono"); + p1.setContent(c); + col.addEntry(p1); + + final ClientEntry p2 = col.getEntry(p1.getEditURI()); + assertNotNull(p2); + + final ClientAtomService atomService = AtomClientFactory.getAtomService(collectionURI, new GDataAuthStrategy(email, password, "blogger")); + assertNotNull(atomService); + + } +} diff --git a/rome-propono/src/test/java/com/rometools/propono/atom/common/AtomServiceTest.java b/rome-propono/src/test/java/com/rometools/propono/atom/common/AtomServiceTest.java new file mode 100644 index 0000000..86f6f6b --- /dev/null +++ b/rome-propono/src/test/java/com/rometools/propono/atom/common/AtomServiceTest.java @@ -0,0 +1,148 @@ +/* + * Copyright 2007 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.rometools.propono.atom.common; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.input.SAXBuilder; + +/** + * Tests reading and writing of service document, no server needed. + */ +public class AtomServiceTest extends TestCase { + + public AtomServiceTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + public static Test suite() { + final TestSuite suite = new TestSuite(AtomServiceTest.class); + + return suite; + } + + /** + * Test of documentToService method, of class AtomService. + */ + public void testDocumentToService() { + try { + // Load service document from disk + final SAXBuilder builder = new SAXBuilder(); + final Document document = builder.build(this.getClass().getResourceAsStream("/servicedoc1.xml")); + assertNotNull(document); + final AtomService service = AtomService.documentToService(document); + + int workspaceCount = 0; + + // Verify that service contains expected workspaces, collections and categories + for (final Object element : service.getWorkspaces()) { + final Workspace space = (Workspace) element; + assertNotNull(space.getTitle()); + workspaceCount++; + for (final Object element2 : space.getCollections()) { + final Collection col = (Collection) element2; + assertNotNull(col.getTitle()); + assertNotNull(col.getHrefResolved()); + int catCount = 0; + if (!col.getCategories().isEmpty()) { + for (final Object element3 : col.getCategories()) { + final Categories cats = (Categories) element3; + catCount += cats.getCategories().size(); + assertTrue(catCount > 0); + } + } + } + } + + assertTrue(workspaceCount > 0); + + } catch (final Exception e) { + e.printStackTrace(); + fail(); + } + } + + /** + * Test of documentToService method, of class AtomService. + */ + public void testServiceToDocument() { + try { + // Create service with workspace and collections + final AtomService service = new AtomService(); + + final Workspace workspace1 = new Workspace("workspace1", null); + final Workspace workspace2 = new Workspace("workspace1", null); + service.addWorkspace(workspace1); + service.addWorkspace(workspace2); + + final Collection collection11 = new Collection("collection11", null, "http://example.com/app/col11"); + final Collection collection12 = new Collection("collection12", null, "http://example.com/app/col12"); + workspace1.addCollection(collection11); + workspace1.addCollection(collection12); + + final Collection collection21 = new Collection("collection21", null, "http://example.com/app/col21"); + final Collection collection22 = new Collection("collection22", null, "http://example.com/app/col22"); + workspace2.addCollection(collection21); + workspace2.addCollection(collection22); + + // TODO: add categories at collection level + + // Convert to JDOM document + final Document document = service.serviceToDocument(); + + // verify that JDOM document contains service, workspace and collection + assertEquals("service", document.getRootElement().getName()); + int workspaceCount = 0; + for (final Object element : document.getRootElement().getChildren()) { + final Element elem = (Element) element; + if ("workspace".equals(elem.getName())) { + workspaceCount++; + } + boolean workspaceTitle = false; + int collectionCount = 0; + for (final Object element2 : elem.getChildren()) { + final Element colelem = (Element) element2; + if ("title".equals(colelem.getName())) { + workspaceTitle = true; + } else if ("collection".equals(colelem.getName())) { + collectionCount++; + } + + // TODO: test for categories at the collection level + } + assertTrue(workspaceTitle); + assertTrue(collectionCount > 0); + } + assertTrue(workspaceCount > 0); + + } catch (final Exception e) { + e.printStackTrace(); + fail(); + } + } +} diff --git a/rome-propono/src/test/java/com/rometools/propono/atom/common/CollectionTest.java b/rome-propono/src/test/java/com/rometools/propono/atom/common/CollectionTest.java new file mode 100644 index 0000000..267f85c --- /dev/null +++ b/rome-propono/src/test/java/com/rometools/propono/atom/common/CollectionTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2007 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.rometools.propono.atom.common; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import junit.framework.TestCase; + +/** + * Tests Collection class, no server needed. + */ +public class CollectionTest extends TestCase { + + public CollectionTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + /** + * Test of accepts method, of class com.rometools.rome.propono.atom.common.Collection. + */ + public void testAccepts() { + + final Collection col = new Collection("dummy_title", "dummy_titletype", "dummy_href"); + + col.setAccepts(Collections.singletonList("image/*")); + assertTrue(col.accepts("image/gif")); + assertTrue(col.accepts("image/jpg")); + assertTrue(col.accepts("image/png")); + assertFalse(col.accepts("test/html")); + + final List accepts = new ArrayList(); + accepts.add("image/*"); + accepts.add("text/*"); + col.setAccepts(accepts); + assertTrue(col.accepts("image/gif")); + assertTrue(col.accepts("image/jpg")); + assertTrue(col.accepts("image/png")); + assertTrue(col.accepts("text/html")); + + col.setAccepts(Collections.singletonList("*/*")); + assertTrue(col.accepts("image/gif")); + assertTrue(col.accepts("image/jpg")); + assertTrue(col.accepts("image/png")); + assertTrue(col.accepts("text/html")); + } +} diff --git a/rome-propono/src/test/java/com/rometools/propono/atom/server/AtomClientServerTest.java b/rome-propono/src/test/java/com/rometools/propono/atom/server/AtomClientServerTest.java new file mode 100644 index 0000000..c68752d --- /dev/null +++ b/rome-propono/src/test/java/com/rometools/propono/atom/server/AtomClientServerTest.java @@ -0,0 +1,428 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertTrue; + +import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mortbay.http.HttpContext; +import org.mortbay.http.HttpServer; +import org.mortbay.http.SocketListener; +import org.mortbay.jetty.servlet.ServletHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.propono.atom.client.AtomClientFactory; +import com.rometools.propono.atom.client.BasicAuthStrategy; +import com.rometools.propono.atom.client.ClientAtomService; +import com.rometools.propono.atom.client.ClientCollection; +import com.rometools.propono.atom.client.ClientEntry; +import com.rometools.propono.atom.client.ClientMediaEntry; +import com.rometools.propono.atom.client.ClientWorkspace; +import com.rometools.propono.atom.common.Categories; +import com.rometools.propono.atom.common.Collection; +import com.rometools.propono.atom.common.Workspace; +import com.rometools.propono.utils.ProponoException; +import com.rometools.rome.feed.atom.Category; +import com.rometools.rome.feed.atom.Content; + +/** + * Test Propono Atom Client against Atom Server via Jetty. Extends AtomClientTest to + * start Jetty server, run tests and then stop the Jetty server. + */ +public class AtomClientServerTest { + + private static final Logger LOG = LoggerFactory.getLogger(AtomClientServerTest.class); + + private HttpServer server = null; + public static final int TESTPORT = 8283; + public static final String ENDPOINT = "http://localhost:" + TESTPORT + "/rome/app"; + public static final String USERNAME = "admin"; + public static final String PASSWORD = "admin"; + + private static ClientAtomService service = null; + + public String getEndpoint() { + return ENDPOINT; + } + + public String getUsername() { + return USERNAME; + } + + public String getPassword() { + return PASSWORD; + } + + protected HttpServer getServer() { + return server; + } + + @Before + public void setUpClass() throws Exception { + + LOG.info("---------------------------------------------"); + LOG.info("Starting Jetty"); + LOG.info("---------------------------------------------"); + + setupServer(); + final HttpContext context = createContext(); + final ServletHandler servlets = createServletHandler(); + context.addHandler(servlets); + server.addContext(context); + server.start(); + + service = AtomClientFactory.getAtomService(getEndpoint(), new BasicAuthStrategy(getUsername(), getPassword())); + } + + @After + public void tearDownClass() throws Exception { + if (server != null) { + LOG.info("Stoping Jetty"); + server.stop(); + server.destroy(); + server = null; + } + } + + private void setupServer() throws InterruptedException { + // Create the server + if (server != null) { + server.stop(); + server = null; + } + server = new HttpServer(); + + // Create a port listener + final SocketListener listener = new SocketListener(); + listener.setPort(TESTPORT); + server.addListener(listener); + } + + private ServletHandler createServletHandler() { + System.setProperty("com.rometools.propono.atom.server.AtomHandlerFactory", "com.rometools.propono.atom.server.TestAtomHandlerFactory"); + final ServletHandler servlets = new ServletHandler(); + servlets.addServlet("app", "/app/*", "com.rometools.propono.atom.server.AtomServlet"); + return servlets; + } + + private HttpContext createContext() { + final HttpContext context = new HttpContext(); + context.setContextPath("/rome/*"); + return context; + } + + /** + * Tests that server has introspection doc with at least one workspace. + */ + @Test + public void testGetAtomService() throws Exception { + assertNotNull(service); + assertTrue(!service.getWorkspaces().isEmpty()); + for (final Workspace workspace : service.getWorkspaces()) { + final ClientWorkspace space = (ClientWorkspace) workspace; + assertNotNull(space.getTitle()); + LOG.debug("Workspace: {}", space.getTitle()); + for (final Object element : space.getCollections()) { + final ClientCollection col = (ClientCollection) element; + LOG.debug(" Collection: {} Accepts: {}", col.getTitle(), col.getAccepts()); + LOG.debug(" href: {}", col.getHrefResolved()); + assertNotNull(col.getTitle()); + } + } + } + + /** + * Tests that entries can be posted and removed in all collections that accept entries. Fails if + * no collections found that accept entries. + */ + @Test + public void testSimpleEntryPostAndRemove() throws Exception { + assertNotNull(service); + assertTrue(!service.getWorkspaces().isEmpty()); + int count = 0; + for (final Object element : service.getWorkspaces()) { + final ClientWorkspace space = (ClientWorkspace) element; + assertNotNull(space.getTitle()); + + for (final Object element2 : space.getCollections()) { + final ClientCollection col = (ClientCollection) element2; + if (col.accepts(Collection.ENTRY_TYPE)) { + + // we found a collection that accepts entries, so post one + final ClientEntry m1 = col.createEntry(); + m1.setTitle("Test post"); + final Content c = new Content(); + c.setValue("This is a test post"); + c.setType("html"); + m1.setContent(c); + + col.addEntry(m1); + + // entry should now exist on server + final ClientEntry m2 = col.getEntry(m1.getEditURI()); + assertNotNull(m2); + + // remove entry + m2.remove(); + + // fetching entry now should result in exception + boolean failed = false; + try { + col.getEntry(m1.getEditURI()); + } catch (final ProponoException e) { + failed = true; + } + assertTrue(failed); + count++; + } + } + } + assertTrue(count > 0); + } + + /** + * Tests that entries can be posted, updated and removed in all collections that accept entries. + * Fails if no collections found that accept entries. + */ + @Test + public void testSimpleEntryPostUpdateAndRemove() throws Exception { + assertNotNull(service); + assertTrue(!service.getWorkspaces().isEmpty()); + int count = 0; + for (final Object element : service.getWorkspaces()) { + final ClientWorkspace space = (ClientWorkspace) element; + assertNotNull(space.getTitle()); + + for (final Object element2 : space.getCollections()) { + final ClientCollection col = (ClientCollection) element2; + if (col.accepts(Collection.ENTRY_TYPE)) { + + // we found a collection that accepts entries, so post one + final ClientEntry m1 = col.createEntry(); + m1.setTitle(col.getTitle() + ": Test post"); + final Content c = new Content(); + c.setValue("This is a test post"); + c.setType("html"); + m1.setContent(c); + + col.addEntry(m1); + + // entry should now exist on server + final ClientEntry m2 = col.getEntry(m1.getEditURI()); + assertNotNull(m2); + + m2.setTitle(col.getTitle() + ": Updated title"); + m2.update(); + + // entry should now be updated on server + final ClientEntry m3 = col.getEntry(m1.getEditURI()); + assertEquals(col.getTitle() + ": Updated title", m3.getTitle()); + + // remove entry + m3.remove(); + + // fetching entry now should result in exception + boolean failed = false; + try { + col.getEntry(m1.getEditURI()); + } catch (final ProponoException e) { + failed = true; + } + assertTrue(failed); + count++; + } + } + } + assertTrue(count > 0); + } + + @Test + public void testFindWorkspace() throws Exception { + assertNotNull(service); + final ClientWorkspace ws = (ClientWorkspace) service.findWorkspace("adminblog"); + if (ws != null) { + final ClientCollection col = (ClientCollection) ws.findCollection(null, "entry"); + final ClientEntry entry = col.createEntry(); + entry.setTitle("NPE on submitting order query"); + entry.setContent("This is a bad one!", Content.HTML); + col.addEntry(entry); + + // entry should now exist on server + final ClientEntry saved = col.getEntry(entry.getEditURI()); + assertNotNull(saved); + + // remove entry + saved.remove(); + + // fetching entry now should result in exception + boolean failed = false; + try { + col.getEntry(saved.getEditURI()); + } catch (final ProponoException e) { + failed = true; + } + assertTrue(failed); + } + } + + /** + * Test posting an entry to every available collection with a fixed and an unfixed category if + * server support allows, then cleanup. + */ + @Test + public void testEntryPostWithCategories() throws Exception { + assertNotNull(service); + assertTrue(!service.getWorkspaces().isEmpty()); + int count = 0; + for (final Object element2 : service.getWorkspaces()) { + final ClientWorkspace space = (ClientWorkspace) element2; + assertNotNull(space.getTitle()); + + for (final Object element3 : space.getCollections()) { + final ClientCollection col = (ClientCollection) element3; + if (col.accepts(Collection.ENTRY_TYPE)) { + + // we found a collection that accepts GIF, so post one + final ClientEntry m1 = col.createEntry(); + m1.setTitle("Test post"); + final Content c = new Content(); + c.setValue("This is a test post"); + c.setType("html"); + m1.setContent(c); + + // if possible, pick one fixed an un unfixed category + Category fixedCat = null; + Category unfixedCat = null; + final List entryCats = new ArrayList(); + for (int i = 0; i < col.getCategories().size(); i++) { + final Categories cats = col.getCategories().get(i); + if (cats.isFixed() && fixedCat == null) { + final String scheme = cats.getScheme(); + fixedCat = cats.getCategories().get(0); + if (fixedCat.getScheme() == null) { + fixedCat.setScheme(scheme); + } + entryCats.add(fixedCat); + } else if (!cats.isFixed() && unfixedCat == null) { + final String scheme = cats.getScheme(); + unfixedCat = new Category(); + unfixedCat.setScheme(scheme); + unfixedCat.setTerm("tagster"); + entryCats.add(unfixedCat); + } + } + m1.setCategories(entryCats); + col.addEntry(m1); + + // entry should now exist on server + final ClientEntry m2 = col.getEntry(m1.getEditURI()); + assertNotNull(m2); + + if (fixedCat != null) { + // we added a fixed category, let's make sure it's there + boolean foundCat = false; + for (final Object element : m2.getCategories()) { + final Category cat = (Category) element; + if (cat.getTerm().equals(fixedCat.getTerm())) { + foundCat = true; + } + } + assertTrue(foundCat); + } + + if (unfixedCat != null) { + // we added an unfixed category, let's make sure it's there + boolean foundCat = false; + for (final Object element : m2.getCategories()) { + final Category cat = (Category) element; + if (cat.getTerm().equals(unfixedCat.getTerm())) { + foundCat = true; + } + } + assertTrue(foundCat); + } + + // remove entry + m2.remove(); + + // fetching entry now should result in exception + boolean failed = false; + try { + col.getEntry(m1.getEditURI()); + } catch (final ProponoException e) { + failed = true; + } + assertTrue(failed); + count++; + } + } + } + assertTrue(count > 0); + } + + /** + * Post media entry to every media colletion avialable on server, then cleanup. + */ + public void testMediaPost() throws Exception { + assertNotNull(service); + assertTrue(!service.getWorkspaces().isEmpty()); + int count = 0; + for (final Object element : service.getWorkspaces()) { + final ClientWorkspace space = (ClientWorkspace) element; + assertNotNull(space.getTitle()); + + for (final Object element2 : space.getCollections()) { + final ClientCollection col = (ClientCollection) element2; + if (col.accepts("image/gif")) { + + // we found a collection that accepts GIF, so post one + final ClientMediaEntry m1 = col.createMediaEntry("duke" + count, "duke" + count, "image/gif", new FileInputStream( + "test/testdata/duke-wave-shadow.gif")); + col.addEntry(m1); + + // entry should now exist on server + final ClientMediaEntry m2 = (ClientMediaEntry) col.getEntry(m1.getEditURI()); + assertNotNull(m2); + + // remove entry + m2.remove(); + + // fetching entry now should result in exception + boolean failed = false; + try { + col.getEntry(m1.getEditURI()); + } catch (final ProponoException e) { + failed = true; + } + assertTrue(failed); + count++; + } + } + } + assertTrue(count > 0); + } + +} diff --git a/rome-propono/src/test/java/com/rometools/propono/atom/server/TestAtomHandlerFactory.java b/rome-propono/src/test/java/com/rometools/propono/atom/server/TestAtomHandlerFactory.java new file mode 100644 index 0000000..eec2e59 --- /dev/null +++ b/rome-propono/src/test/java/com/rometools/propono/atom/server/TestAtomHandlerFactory.java @@ -0,0 +1,28 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class TestAtomHandlerFactory extends AtomHandlerFactory { + + @Override + public AtomHandler newAtomHandler(final HttpServletRequest req, final HttpServletResponse res) { + return new TestAtomHandlerImpl(req, "target/testuploaddir"); + } +} diff --git a/rome-propono/src/test/java/com/rometools/propono/atom/server/TestAtomHandlerImpl.java b/rome-propono/src/test/java/com/rometools/propono/atom/server/TestAtomHandlerImpl.java new file mode 100644 index 0000000..c1eb257 --- /dev/null +++ b/rome-propono/src/test/java/com/rometools/propono/atom/server/TestAtomHandlerImpl.java @@ -0,0 +1,33 @@ +/* + * Copyright 2007 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.rometools.propono.atom.server; + +import javax.servlet.http.HttpServletRequest; + +import com.rometools.propono.atom.server.impl.FileBasedAtomHandler; + +public class TestAtomHandlerImpl extends FileBasedAtomHandler { + + public TestAtomHandlerImpl(final HttpServletRequest req, final String uploaddir) { + super(req, uploaddir); + } + + @Override + public boolean validateUser(final String loginId, final String password) { + return AtomClientServerTest.USERNAME.equals(loginId) && AtomClientServerTest.PASSWORD.equals(password); + } +} \ No newline at end of file diff --git a/rome-propono/src/test/java/com/rometools/propono/blogclient/SimpleBlogClientTest.java b/rome-propono/src/test/java/com/rometools/propono/blogclient/SimpleBlogClientTest.java new file mode 100644 index 0000000..55ae45c --- /dev/null +++ b/rome-propono/src/test/java/com/rometools/propono/blogclient/SimpleBlogClientTest.java @@ -0,0 +1,215 @@ +/* + * Copyright 2007 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.rometools.propono.blogclient; + +import java.io.File; +import java.util.Iterator; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.junit.Ignore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rometools.propono.blogclient.Blog.Collection; +import com.rometools.propono.utils.Utilities; +import com.rometools.rome.io.impl.Atom10Parser; + +/** + * Tests Atom and MetaWeblog API CRUD via BlogClient. Exclude this from automated tests because it + * requires a live blog server. + */ +@Ignore +public class SimpleBlogClientTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(SimpleBlogClientTest.class); + + private final String metaweblogEndpoint = "http://localhost:8080/roller/roller-services/xmlrpc"; + // private String atomEndpoint = "http://localhost:8080/roller/roller-services/app"; + private final String atomEndpoint = "http://localhost:8080/sample-atomserver/app"; + + // private final String endpoint = "http://localhost:8080/atom-fileserver/app"; + private final String username = "admin"; + private final String password = "admin"; + + public SimpleBlogClientTest(final String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + public void testBlogClientAtom() throws Exception { + testBlogClient("atom", atomEndpoint); + } + + public void testBlogClientMetaWeblog() throws Exception { + testBlogClient("metaweblog", metaweblogEndpoint); + } + + public void testBlogClient(final String type, final String endpoint) throws Exception { + final BlogConnection conn = BlogConnectionFactory.getBlogConnection(type, endpoint, username, password); + + int blogCount = 0; + for (final Blog blog : conn.getBlogs()) { + LOG.debug(blog.getName()); + blogCount++; + } + assertTrue(blogCount > 0); + } + + public void testPostAndDeleteAtom() throws Exception { + testPostAndDelete("atom", atomEndpoint); + } + + public void testPostAndDeleteMetaWeblog() throws Exception { + testPostAndDelete("metaweblog", metaweblogEndpoint); + } + + public void testMediaPostAtom() throws Exception { + testMediaPost("atom", atomEndpoint); + } + + public void testMediaPostMetaWeblog() throws Exception { + testMediaPost("metaweblog", metaweblogEndpoint); + } + + public void testPostAndDelete(final String type, final String endpoint) throws Exception { + final BlogConnection conn = BlogConnectionFactory.getBlogConnection(type, endpoint, username, password); + assertNotNull(conn); + + final String title1 = "Test content"; + final String content1 = "Test content"; + + final Blog blog = conn.getBlogs().get(0); + BlogEntry entry = blog.newEntry(); + entry.setTitle(title1); + entry.setContent(new BlogEntry.Content(content1)); + entry.save(); + final String token = entry.getToken(); + assertNotNull(token); + + entry = blog.getEntry(token); + + assertEquals(title1, entry.getTitle()); + assertEquals(content1, entry.getContent().getValue()); + + assertNotNull(entry); + entry.delete(); + entry = null; + + boolean notFound = false; + try { + entry = blog.getEntry(token); + } catch (final Exception e) { + notFound = true; + } + assertTrue(notFound); + } + + /** + * Post media entry to every media colletion avialable on server, then cleanup. + */ + public void testMediaPost(final String type, final String endpoint) throws Exception { + final BlogConnection conn = BlogConnectionFactory.getBlogConnection(type, endpoint, username, password); + assertNotNull(conn); + + assertTrue(!conn.getBlogs().isEmpty()); + int count = 0; + for (final Blog blog2 : conn.getBlogs()) { + final Blog blog = blog2; + assertNotNull(blog.getName()); + + for (final Collection collection : blog.getCollections()) { + final Blog.Collection col = collection; + if (col.accepts("image/gif")) { + + // we found a collection that accepts GIF, so post one + final BlogResource m1 = col.newResource("duke" + count, "image/gif", + Utilities.getBytesFromFile(new File("test/testdata/duke-wave-shadow.gif"))); + col.saveResource(m1); + + if ("atom".equals(type)) { // additional tests for Atom + + // entry should now exist on server + final BlogResource m2 = (BlogResource) blog.getEntry(m1.getToken()); + assertNotNull(m2); + + // remove entry + m2.delete(); + + // fetching entry now should result in exception + boolean failed = false; + try { + blog.getEntry(m1.getToken()); + } catch (final Exception e) { + failed = true; + } + assertTrue(failed); + } + count++; + } + } + } + assertTrue(count > 0); + } + + public void testEntryIterationAtom() throws Exception { + testEntryIteration("atom", atomEndpoint); + } + + public void testEntryIterationMetaWeblog() throws Exception { + testEntryIteration("metaweblog", metaweblogEndpoint); + } + + public void testEntryIteration(final String type, final String endpoint) throws Exception { + final BlogConnection conn = BlogConnectionFactory.getBlogConnection(type, endpoint, username, password); + assertNotNull(conn); + + final String title1 = "Test content"; + final String content1 = "Test content"; + + final Blog blog = conn.getBlogs().get(0); + + for (int i = 0; i < 10; i++) { + final BlogEntry entry = blog.newEntry(); + entry.setTitle(title1); + entry.setContent(new BlogEntry.Content(content1)); + entry.save(); + final String token = entry.getToken(); + assertTrue(Atom10Parser.isAbsoluteURI(token)); + assertNotNull(token); + } + + for (final Iterator it = blog.getEntries(); it.hasNext();) { + final BlogEntry blogEntry = it.next(); + assertTrue(Atom10Parser.isAbsoluteURI(blogEntry.getToken())); + blogEntry.delete(); + } + } + + public static Test suite() { + return new TestSuite(SimpleBlogClientTest.class); + } + +} diff --git a/rome-propono/src/test/resources/commons-logging.properties b/rome-propono/src/test/resources/commons-logging.properties new file mode 100644 index 0000000..a7bb501 --- /dev/null +++ b/rome-propono/src/test/resources/commons-logging.properties @@ -0,0 +1,16 @@ +# +# Copyright 2007 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. +# +org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog \ No newline at end of file diff --git a/rome-propono/src/test/resources/duke-wave-shadow.gif b/rome-propono/src/test/resources/duke-wave-shadow.gif new file mode 100644 index 0000000..1e5ac90 Binary files /dev/null and b/rome-propono/src/test/resources/duke-wave-shadow.gif differ diff --git a/rome-propono/src/test/resources/logback-test.xml b/rome-propono/src/test/resources/logback-test.xml new file mode 100644 index 0000000..c34b099 --- /dev/null +++ b/rome-propono/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + \ No newline at end of file diff --git a/rome-propono/src/test/resources/servicedoc1.xml b/rome-propono/src/test/resources/servicedoc1.xml new file mode 100644 index 0000000..57270ce --- /dev/null +++ b/rome-propono/src/test/resources/servicedoc1.xml @@ -0,0 +1,18 @@ + + + + adminblog1 + + Weblog Entries + + + + + entry + + + Media Files + */* + + + \ No newline at end of file diff --git a/rome-propono/src/test/resources/simplelog.properties b/rome-propono/src/test/resources/simplelog.properties new file mode 100644 index 0000000..0e47e22 --- /dev/null +++ b/rome-propono/src/test/resources/simplelog.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. The ASF licenses this file to You +# 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. For additional information regarding +# copyright in this work, please see the NOTICE file in the top level +# directory of this distribution. + +org.apache.commons.logging.simplelog.log.com.rometools.propono.atom=debug +org.apache.commons.logging.simplelog.log.com.rometools.propono.atom.server.impl.FileBasedAtomHandler=debug +org.apache.commons.logging.simplelog.log.com.rometools.propono.atom.client.AtomClientServerTest=debug diff --git a/rome-utils/.gitignore b/rome-utils/.gitignore new file mode 100644 index 0000000..c708c36 --- /dev/null +++ b/rome-utils/.gitignore @@ -0,0 +1,4 @@ +/target +/.settings +/.classpath +/.project diff --git a/rome-utils/LICENSE b/rome-utils/LICENSE new file mode 100644 index 0000000..6b0b127 --- /dev/null +++ b/rome-utils/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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/rome-utils/README.md b/rome-utils/README.md new file mode 100644 index 0000000..18a85fb --- /dev/null +++ b/rome-utils/README.md @@ -0,0 +1,4 @@ +rome-utils +========== + +Utility classes for ROME projects diff --git a/rome-utils/pom.xml b/rome-utils/pom.xml new file mode 100644 index 0000000..2945b69 --- /dev/null +++ b/rome-utils/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + + + com.rometools + rome-parent + 1.6.0-SNAPSHOT + + + rome-utils + 1.6.0-SNAPSHOT + jar + + rome-utils + + Utility classes for ROME projects + + http://rometools.github.io/rome-utils/ + + + scm:git:ssh://github.com/rometools/rome-utils.git + scm:git:ssh://git@github.com/rometools/rome-utils.git + https://github.com/rometools/rome-utils + + + + + Patrick Gotthard + http://www.patrick-gotthard.de + +1 + + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + org.slf4j + slf4j-api + + + junit + junit + test + + + org.hamcrest + hamcrest-library + test + + + + \ No newline at end of file diff --git a/rome-utils/src/main/java/com/rometools/utils/Alternatives.java b/rome-utils/src/main/java/com/rometools/utils/Alternatives.java new file mode 100644 index 0000000..ab0abd8 --- /dev/null +++ b/rome-utils/src/main/java/com/rometools/utils/Alternatives.java @@ -0,0 +1,37 @@ +/* + * 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.rometools.utils; + +public final class Alternatives { + + private Alternatives() { + } + + /** + * Returns the first object that is not null + * + * @param objects The objects to process + * @return The first value that is not null. null when there is no not-null value + */ + public static T firstNotNull(final T... objects) { + for (final T object : objects) { + if (object != null) { + return object; + } + } + return null; + } + +} diff --git a/rome-utils/src/main/java/com/rometools/utils/Dates.java b/rome-utils/src/main/java/com/rometools/utils/Dates.java new file mode 100644 index 0000000..a1c2f95 --- /dev/null +++ b/rome-utils/src/main/java/com/rometools/utils/Dates.java @@ -0,0 +1,38 @@ +/* + * 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.rometools.utils; + +import java.util.Date; + +public final class Dates { + + private Dates() { + } + + /** + * Creates a copy on a Date. + * + * @param d The Date to copy, can be null + * @return null when the input Date was null, a copy of the Date otherwise + */ + public static Date copy(final Date d) { + if (d == null) { + return null; + } else { + return new Date(d.getTime()); + } + } + +} diff --git a/rome-utils/src/main/java/com/rometools/utils/Doubles.java b/rome-utils/src/main/java/com/rometools/utils/Doubles.java new file mode 100644 index 0000000..96fecac --- /dev/null +++ b/rome-utils/src/main/java/com/rometools/utils/Doubles.java @@ -0,0 +1,39 @@ +/* + * 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.rometools.utils; + +public class Doubles { + + private Doubles() { + } + + /** + * Converts a String into an Double. + * + * @param s The String to convert, may be null + * @return The parsed Double or null when parsing is not possible + */ + public static Double parse(final String s) { + Double parsed = null; + try { + if (s != null) { + parsed = Double.parseDouble(s); + } + } catch (final NumberFormatException e) { + } + return parsed; + } + +} diff --git a/rome-utils/src/main/java/com/rometools/utils/IO.java b/rome-utils/src/main/java/com/rometools/utils/IO.java new file mode 100644 index 0000000..7c7c57f --- /dev/null +++ b/rome-utils/src/main/java/com/rometools/utils/IO.java @@ -0,0 +1,63 @@ +/* + * 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.rometools.utils; + +import java.io.Closeable; +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class to handle I/O operations. + * + * @author Patrick Gotthard + * + */ +public final class IO { + + private static final Logger LOG = LoggerFactory.getLogger(IO.class); + + private IO() { + } + + /** + * Closes a {@link Closeable} object without suppressing a possible {@link IOException}. + * + * @param closeable The {@link Closeable} to close + * @throws IOException when the {@link Closeable} can't be closed + */ + public static void close(final Closeable closeable) throws IOException { + if (closeable != null) { + closeable.close(); + } + } + + /** + * Closes a {@link Closeable} object and suppresses a possible {@link IOException}. + * + * @param closeable The {@link Closeable} to close + */ + public static void closeQuietly(final Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (final IOException e) { + LOG.warn("Unable to close resource", e); + } + } + } + +} diff --git a/rome-utils/src/main/java/com/rometools/utils/Integers.java b/rome-utils/src/main/java/com/rometools/utils/Integers.java new file mode 100644 index 0000000..4314a36 --- /dev/null +++ b/rome-utils/src/main/java/com/rometools/utils/Integers.java @@ -0,0 +1,36 @@ +/* + * 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.rometools.utils; + +public final class Integers { + + private Integers() { + } + + /** + * Converts a String into an Integer. + * + * @param s The String to convert, may be null + * @return The parsed Integer or null when parsing is not possible + */ + public static Integer parse(final String s) { + try { + return Integer.parseInt(s); + } catch (final NumberFormatException e) { + return null; + } + } + +} diff --git a/rome-utils/src/main/java/com/rometools/utils/Lists.java b/rome-utils/src/main/java/com/rometools/utils/Lists.java new file mode 100644 index 0000000..be6186c --- /dev/null +++ b/rome-utils/src/main/java/com/rometools/utils/Lists.java @@ -0,0 +1,116 @@ +/* + * 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.rometools.utils; + +import java.util.ArrayList; +import java.util.List; + +public final class Lists { + + private Lists() { + } + + /** + * Returns the list when it is not null. Returns a new list otherwise. + * + * @param list The list to process, can be null + * @return The input list when it is not null, a new list otherwise + */ + public static List createWhenNull(final List list) { + if (list == null) { + return new ArrayList(); + } else { + return list; + } + } + + /** + * Creates a new List with the given item as the first entry. + * + * @param item The item to add to the new list + * @return List containing the given item + */ + public static List create(final T item) { + final List list = new ArrayList(); + list.add(item); + return list; + } + + /** + * Extracts the first entry of the list when it is not null and contains values. + * + * @param list The list to extract the first entry from, can be null + * @return The first entry of the list when it is not null or empty, null otherwise + */ + public static T firstEntry(final List list) { + if (list != null && !list.isEmpty()) { + return list.get(0); + } else { + return null; + } + } + + /** + * Checks whether the list is null or empty. + * + * @param list The list to check + * @return true when the list is null or empty, false otherwise + */ + public static boolean isEmpty(final List list) { + return list == null || list.isEmpty(); + } + + /** + * Checks whether the list is not null and not empty. + * + * @param list The list to check + * @return true when the list is not null and not empty + */ + public static boolean isNotEmpty(final List list) { + return !isEmpty(list); + } + + /** + * Checks whether the list has the given size. A null list is treated like a list without + * entries. + * + * @param list The list to check + * @param size The size to check + * @return true when the list has the given size or when size = 0 and the list is null, false + * otherwise + */ + public static boolean sizeIs(final List list, final int size) { + if (size == 0) { + return list == null || list.isEmpty(); + } else { + return list != null && list.size() == size; + } + } + + /** + * Returns null, when the given list is empty or null + * + * @param list The list to process + * @return null when the list is empty or null, the given list otherwise + */ + public static List emptyToNull(final List list) { + if (isEmpty(list)) { + return null; + } else { + return list; + } + } + +} diff --git a/rome-utils/src/main/java/com/rometools/utils/Longs.java b/rome-utils/src/main/java/com/rometools/utils/Longs.java new file mode 100644 index 0000000..e3e55d1 --- /dev/null +++ b/rome-utils/src/main/java/com/rometools/utils/Longs.java @@ -0,0 +1,39 @@ +/* + * 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.rometools.utils; + +public final class Longs { + + private Longs() { + } + + /** + * Converts a String into a Long by first parsing it as Double and then casting it to Long. + * + * @param s The String to convert, may be null or in decimal format + * @return The parsed Long or null when parsing is not possible + */ + public static Long parseDecimal(final String s) { + Long parsed = null; + try { + if (s != null) { + parsed = (long) Double.parseDouble(s); + } + } catch (final NumberFormatException e) { + } + return parsed; + } + +} diff --git a/rome-utils/src/main/java/com/rometools/utils/Strings.java b/rome-utils/src/main/java/com/rometools/utils/Strings.java new file mode 100644 index 0000000..f8ff575 --- /dev/null +++ b/rome-utils/src/main/java/com/rometools/utils/Strings.java @@ -0,0 +1,126 @@ +/* + * 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.rometools.utils; + +import java.util.Locale; + +public final class Strings { + + private Strings() { + } + + /** + * Checks whether a String is null. + * + * @param s The String to check + * @return true when the String is null, false otherwise + */ + public static boolean isNull(final String s) { + return s == null; + } + + /** + * Checks whether a String is null or empty. + * + * @param s The String to check + * @return true when the String is null or empty, false otherwise + */ + public static boolean isEmpty(final String s) { + return isNull(s) || s.isEmpty(); + } + + /** + * Checks whether a String is neither null nor empty. + * + * @param s The String to check + * @return true when the String is neither null nor empty, false otherwise + */ + public static boolean isNotEmpty(final String s) { + return !isEmpty(s); + } + + /** + * Checks whether a String is null, empty or blank. + * + * @param s The String to check + * @return true when the String is null, empty or blank, false otherwise + */ + public static boolean isBlank(final String s) { + return isEmpty(s) || s.trim().isEmpty(); + } + + /** + * Removes the whitespace at the beginning and end of a String. + * + * @param s The String to trim, may be null + * @return null when the input String is null, the trimmed String otherwise + */ + public static String trim(final String s) { + if (s == null) { + return null; + } else { + return s.trim(); + } + } + + /** + * Removes the whitespace at the beginning and end of a String. When the String only contains + * whitespace, it returns null. + * + * @param s The String to trim, may be null + * @return null when the input String is null or does only contain whitespace, the trimmed + * String otherwise + */ + public static String trimToNull(final String s) { + final String trimmed = trim(s); + if (trimmed == null || trimmed.isEmpty()) { + return null; + } else { + return trimmed; + } + } + + /** + * Removes the whitespace at the beginning and end of a String. When the String only contains + * whitespace, it returns null. + * + * @param s The String to trim, may be null + * @return null when the input String is null or does only contain whitespace, the trimmed + * String otherwise + */ + public static String trimToEmpty(final String s) { + final String trimmed = trim(s); + if (trimmed == null || trimmed.isEmpty()) { + return ""; + } else { + return trimmed; + } + } + + /** + * null-safe lower-case conversion of a String. + * + * @param s The String to process, may be null + * @return null when the input String is null, the String in lower-case otherwise + */ + public static String toLowerCase(final String s) { + if (s == null) { + return null; + } else { + return s.toLowerCase(Locale.ENGLISH); + } + } + +} diff --git a/rome-utils/src/main/resources/.gitignore b/rome-utils/src/main/resources/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/rome-utils/src/test/java/com/rometools/utils/AlternativesTest.java b/rome-utils/src/test/java/com/rometools/utils/AlternativesTest.java new file mode 100644 index 0000000..3e3e45d --- /dev/null +++ b/rome-utils/src/test/java/com/rometools/utils/AlternativesTest.java @@ -0,0 +1,37 @@ +/* + * 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.rometools.utils; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +public class AlternativesTest { + + @Test + public void testFirstNotNull() { + + final Integer nullInteger = null; + final Integer notNullInteger = 1; + + assertThat(Alternatives.firstNotNull(notNullInteger, nullInteger), is(notNullInteger)); + assertThat(Alternatives.firstNotNull(nullInteger, notNullInteger), is(notNullInteger)); + assertThat(Alternatives.firstNotNull(nullInteger, nullInteger), is(nullValue())); + + } + +} diff --git a/rome-utils/src/test/java/com/rometools/utils/DatesTest.java b/rome-utils/src/test/java/com/rometools/utils/DatesTest.java new file mode 100644 index 0000000..955a965 --- /dev/null +++ b/rome-utils/src/test/java/com/rometools/utils/DatesTest.java @@ -0,0 +1,40 @@ +/* + * 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.rometools.utils; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.util.Date; + +import org.junit.Test; + +public class DatesTest { + + @Test + public void testCopy() { + + final Date date = new Date(); + final Date nullDate = null; + + assertThat(Dates.copy(date), is(notNullValue())); + assertThat(Dates.copy(date).getTime(), is(date.getTime())); + assertThat(Dates.copy(nullDate), is(nullValue())); + + } + +} diff --git a/rome-utils/src/test/java/com/rometools/utils/DoublesTest.java b/rome-utils/src/test/java/com/rometools/utils/DoublesTest.java new file mode 100644 index 0000000..6426cad --- /dev/null +++ b/rome-utils/src/test/java/com/rometools/utils/DoublesTest.java @@ -0,0 +1,40 @@ +/* + * 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.rometools.utils; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +import org.junit.Test; + +public class DoublesTest { + + @Test + public void testParse() { + + final String nullString = null; + final String emptyString = null; + final String integerString = "1"; + final String decimalString = "1.0"; + + assertThat(Doubles.parse(nullString), is(nullValue())); + assertThat(Doubles.parse(emptyString), is(nullValue())); + assertThat(Doubles.parse(integerString), is(1.0)); + assertThat(Doubles.parse(decimalString), is(1.0)); + + } + +} diff --git a/rome-utils/src/test/java/com/rometools/utils/IntegersTest.java b/rome-utils/src/test/java/com/rometools/utils/IntegersTest.java new file mode 100644 index 0000000..f910a4b --- /dev/null +++ b/rome-utils/src/test/java/com/rometools/utils/IntegersTest.java @@ -0,0 +1,40 @@ +/* + * 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.rometools.utils; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +import org.junit.Test; + +public class IntegersTest { + + @Test + public void testParse() { + + final String nullString = null; + final String emptyString = null; + final String integerString = "1"; + final String decimalString = "1.0"; + + assertThat(Integers.parse(nullString), is(nullValue())); + assertThat(Integers.parse(emptyString), is(nullValue())); + assertThat(Integers.parse(integerString), is(1)); + assertThat(Integers.parse(decimalString), is(nullValue())); + + } + +} diff --git a/rome-utils/src/test/java/com/rometools/utils/ListsTest.java b/rome-utils/src/test/java/com/rometools/utils/ListsTest.java new file mode 100644 index 0000000..2871cff --- /dev/null +++ b/rome-utils/src/test/java/com/rometools/utils/ListsTest.java @@ -0,0 +1,119 @@ +/* + * 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.rometools.utils; + +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +public class ListsTest { + + @Test + public void testCreateWhenNull() { + + final List list = new ArrayList(); + final List nullList = null; + + assertThat(Lists.createWhenNull(list), is(notNullValue())); + assertThat(Lists.createWhenNull(list), is(list)); + assertThat(Lists.createWhenNull(nullList), is(notNullValue())); + + } + + @Test + public void testCreate() { + + final List create = Lists.create(1); + assertThat(create, is(notNullValue())); + assertThat(create.size(), is(1)); + assertThat(create, hasItem(1)); + + } + + @Test + public void testFirstEntry() { + + final List nullList = null; + final List listWithoutEntries = new ArrayList(); + final List listWithOneEntry = Arrays.asList(1); + final List listWithTwoEntries = Arrays.asList(1, 2); + + assertThat(Lists.firstEntry(nullList), is(nullValue())); + assertThat(Lists.firstEntry(listWithoutEntries), is(nullValue())); + assertThat(Lists.firstEntry(listWithOneEntry), is(1)); + assertThat(Lists.firstEntry(listWithTwoEntries), is(1)); + + } + + @Test + public void testIsEmpty() { + + final List nullList = null; + final List listWithoutEntries = new ArrayList(); + final List listWithOneEntry = Arrays.asList(1); + + assertThat(Lists.isEmpty(nullList), is(true)); + assertThat(Lists.isEmpty(listWithoutEntries), is(true)); + assertThat(Lists.isEmpty(listWithOneEntry), is(false)); + + } + + @Test + public void testIsNotEmpty() { + + final List nullList = null; + final List listWithoutEntries = new ArrayList(); + final List listWithOneEntry = Arrays.asList(1); + + assertThat(Lists.isNotEmpty(nullList), is(false)); + assertThat(Lists.isNotEmpty(listWithoutEntries), is(false)); + assertThat(Lists.isNotEmpty(listWithOneEntry), is(true)); + } + + @Test + public void testSizeIs() { + + final List nullList = null; + final List listWithoutEntries = new ArrayList(); + final List listWithOneEntry = Arrays.asList(1); + + assertThat(Lists.sizeIs(nullList, 0), is(true)); + assertThat(Lists.sizeIs(listWithoutEntries, 0), is(true)); + assertThat(Lists.sizeIs(listWithOneEntry, 1), is(true)); + + } + + @Test + public void testEmptyToNull() { + + final List nullList = null; + final List listWithoutEntries = new ArrayList(); + final List listWithOneEntry = Arrays.asList(1); + + assertThat(Lists.emptyToNull(nullList), is(nullValue())); + assertThat(Lists.emptyToNull(listWithoutEntries), is(nullValue())); + assertThat(Lists.emptyToNull(listWithOneEntry), is(notNullValue())); + + } + +} diff --git a/rome-utils/src/test/java/com/rometools/utils/LongsTest.java b/rome-utils/src/test/java/com/rometools/utils/LongsTest.java new file mode 100644 index 0000000..2069c04 --- /dev/null +++ b/rome-utils/src/test/java/com/rometools/utils/LongsTest.java @@ -0,0 +1,40 @@ +/* + * 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.rometools.utils; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +import org.junit.Test; + +public class LongsTest { + + @Test + public void testParseDecimal() { + + final String nullString = null; + final String emptyString = ""; + final String longString = String.valueOf(Long.MAX_VALUE); + final String decimalString = String.valueOf(Double.MAX_VALUE); + + assertThat(Longs.parseDecimal(nullString), is(nullValue())); + assertThat(Longs.parseDecimal(emptyString), is(nullValue())); + assertThat(Longs.parseDecimal(longString), is(Long.MAX_VALUE)); + assertThat(Longs.parseDecimal(decimalString), is((long) Double.MAX_VALUE)); + + } + +} diff --git a/rome-utils/src/test/java/com/rometools/utils/StringsTest.java b/rome-utils/src/test/java/com/rometools/utils/StringsTest.java new file mode 100644 index 0000000..fd17c51 --- /dev/null +++ b/rome-utils/src/test/java/com/rometools/utils/StringsTest.java @@ -0,0 +1,139 @@ +/* + * 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.rometools.utils; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +public class StringsTest { + + @Test + public void testIsNull() { + + final String nullString = null; + final String emptyString = ""; + final String blankString = " "; + final String string = "a"; + + assertThat(Strings.isNull(nullString), is(true)); + assertThat(Strings.isNull(emptyString), is(false)); + assertThat(Strings.isNull(blankString), is(false)); + assertThat(Strings.isNull(string), is(false)); + + } + + @Test + public void testIsEmpty() { + + final String nullString = null; + final String emptyString = ""; + final String blankString = " "; + final String string = "a"; + + assertThat(Strings.isEmpty(nullString), is(true)); + assertThat(Strings.isEmpty(emptyString), is(true)); + assertThat(Strings.isEmpty(blankString), is(false)); + assertThat(Strings.isEmpty(string), is(false)); + + } + + @Test + public void testIsNotEmpty() { + + final String nullString = null; + final String emptyString = ""; + final String blankString = " "; + final String string = "a"; + + assertThat(Strings.isNotEmpty(nullString), is(false)); + assertThat(Strings.isNotEmpty(emptyString), is(false)); + assertThat(Strings.isNotEmpty(blankString), is(true)); + assertThat(Strings.isNotEmpty(string), is(true)); + } + + @Test + public void testIsBlank() { + + final String nullString = null; + final String emptyString = ""; + final String blankString = " "; + final String string = "a"; + + assertThat(Strings.isBlank(nullString), is(true)); + assertThat(Strings.isBlank(emptyString), is(true)); + assertThat(Strings.isBlank(blankString), is(true)); + assertThat(Strings.isBlank(string), is(false)); + } + + @Test + public void testTrim() { + + final String nullString = null; + final String emptyString = ""; + final String blankString = " "; + final String string = " a "; + + assertThat(Strings.trim(nullString), is(nullValue())); + assertThat(Strings.trim(emptyString), is("")); + assertThat(Strings.trim(blankString), is("")); + assertThat(Strings.trim(string), is("a")); + } + + @Test + public void testTrimToEmpty() { + + final String nullString = null; + final String emptyString = ""; + final String blankString = " "; + final String string = " a "; + + assertThat(Strings.trimToEmpty(nullString), is("")); + assertThat(Strings.trimToEmpty(emptyString), is("")); + assertThat(Strings.trimToEmpty(blankString), is("")); + assertThat(Strings.trimToEmpty(string), is("a")); + } + + @Test + public void testTrimToNull() { + + final String nullString = null; + final String emptyString = ""; + final String blankString = " "; + final String string = " a "; + + assertThat(Strings.trimToNull(nullString), is(nullValue())); + assertThat(Strings.trimToNull(emptyString), is(nullValue())); + assertThat(Strings.trimToNull(blankString), is(nullValue())); + assertThat(Strings.trimToNull(string), is("a")); + } + + @Test + public void testToLowerCase() { + + final String nullString = null; + final String emptyString = ""; + final String blankString = " "; + final String string = "A"; + + assertThat(Strings.toLowerCase(nullString), is(nullValue())); + assertThat(Strings.toLowerCase(emptyString), is("")); + assertThat(Strings.toLowerCase(blankString), is(" ")); + assertThat(Strings.toLowerCase(string), is("a")); + } + +} diff --git a/rome-utils/src/test/resources/.gitignore b/rome-utils/src/test/resources/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/rome/.gitignore b/rome/.gitignore new file mode 100644 index 0000000..5966e2d --- /dev/null +++ b/rome/.gitignore @@ -0,0 +1,5 @@ +/.checkstyle +/.classpath +/.project +/.settings +/target \ No newline at end of file diff --git a/rome/LICENSE b/rome/LICENSE new file mode 100644 index 0000000..d4ba69e --- /dev/null +++ b/rome/LICENSE @@ -0,0 +1,16 @@ +Copyright 2004 Sun Microsystems, Inc. +Copyright 2011 The ROME Team + + +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/rome/README.md b/rome/README.md new file mode 100644 index 0000000..b1c6816 --- /dev/null +++ b/rome/README.md @@ -0,0 +1,27 @@ +# ROME + +ROME is a set of RSS and Atom Utilities for Java. It makes it easy to work in Java with most syndication formats: RSS 0.90, RSS 0.91 Netscape, +RSS 0.91 Userland, RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, RSS 2.0, Atom 0.3, Atom 1.0 + +More Information: http://rometools.github.io/rome/ + +## Changelog + +### 1.5.1 + +- solved an [XML bomb](https://en.wikipedia.org/wiki/Billion_laughs) vulnerability + +Important note: due to the security fix ROME now forbids all Doctype declarations by default. This will break compatibility with RSS 0.91 Netscape +because it requires a Doctype declaration. When you experience problems you have to activate the property **allowDoctypes** on the SyndFeedInput object. You +should only use this possibility when the feeds that you process are absolutely trustful. + +### 1.5.0 + +- many (untracked) enhancements +- code cleanup +- renamed packages (was required to be able to push to Maven Central after years again) +- updated sourcecode to Java 1.6 + +### Prior to 1.5.0 + +- see [http://rometools.github.io/rome/ROMEReleases](http://rometools.github.io/rome/ROMEReleases) \ No newline at end of file diff --git a/rome/pom.xml b/rome/pom.xml new file mode 100644 index 0000000..f2c0bb8 --- /dev/null +++ b/rome/pom.xml @@ -0,0 +1,161 @@ + + + 4.0.0 + + + com.rometools + rome-parent + 1.6.0-SNAPSHOT + + + rome + 1.6.0-SNAPSHOT + jar + + rome + + All Roads Lead to ROME. ROME is a set of Atom/RSS Java utilities that make it + easy to work in Java with most syndication formats. Today it accepts all flavors of RSS + (0.90, 0.91, 0.92, 0.93, 0.94, 1.0 and 2.0), Atom 0.3 and Atom 1.0 feeds. Rome includes + a set of parsers and generators for the various flavors of feeds, as well as converters + to convert from one format to another. The parsers can give you back Java objects that + are either specific for the format you want to work with, or a generic normalized + SyndFeed object that lets you work on with the data without bothering about the + underlying format. + + + http://rometools.github.io/rome/ + + + scm:git:ssh://github.com/rometools/rome.git + scm:git:ssh://git@github.com/rometools/rome.git + https://github.com/rometools/rome + + + + + Alejandro Abdelnur + http://blog.sun.com/roller/page/tucu + 0 + + + Dave Johnson + http://rollerweblogger.org/roller + -5 + + + Elaine Chien + 0 + + + Patrick Chanezon + http://www.chanezon.com/pat/weblog + -9 + + + Patrick Gotthard + http://www.patrick-gotthard.de + +1 + + + Robert Cooper + kebernet@gmail.com + http://www.screaming-penguin.com + -4 + + + farrukhnajmi + Farrukh Najmi + http://www.wellfleetsoftware.com/farrukh + + + imk + Martin Kurz + Europe/Berlin + + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + true + true + + + + + + org.apache.maven.plugins + maven-site-plugin + + + org.apache.maven.doxia + doxia-module-markdown + 1.5 + + + org.apache.maven.doxia + doxia-module-confluence + 1.5 + + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + gh-pages + ${project.scm.developerConnection} + ${project.build.directory}/site + + + + + + + + com.rometools + rome-utils + 1.6.0-SNAPSHOT + + + org.jdom + jdom2 + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + test + + + junit + junit + test + + + + diff --git a/src/main/java/com/rometools/rome/feed/CopyFrom.java b/rome/src/main/java/com/rometools/rome/feed/CopyFrom.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/CopyFrom.java rename to rome/src/main/java/com/rometools/rome/feed/CopyFrom.java diff --git a/src/main/java/com/rometools/rome/feed/WireFeed.java b/rome/src/main/java/com/rometools/rome/feed/WireFeed.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/WireFeed.java rename to rome/src/main/java/com/rometools/rome/feed/WireFeed.java diff --git a/src/main/java/com/rometools/rome/feed/atom/Category.java b/rome/src/main/java/com/rometools/rome/feed/atom/Category.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/atom/Category.java rename to rome/src/main/java/com/rometools/rome/feed/atom/Category.java diff --git a/src/main/java/com/rometools/rome/feed/atom/Content.java b/rome/src/main/java/com/rometools/rome/feed/atom/Content.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/atom/Content.java rename to rome/src/main/java/com/rometools/rome/feed/atom/Content.java diff --git a/src/main/java/com/rometools/rome/feed/atom/Entry.java b/rome/src/main/java/com/rometools/rome/feed/atom/Entry.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/atom/Entry.java rename to rome/src/main/java/com/rometools/rome/feed/atom/Entry.java diff --git a/src/main/java/com/rometools/rome/feed/atom/Feed.java b/rome/src/main/java/com/rometools/rome/feed/atom/Feed.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/atom/Feed.java rename to rome/src/main/java/com/rometools/rome/feed/atom/Feed.java diff --git a/src/main/java/com/rometools/rome/feed/atom/Generator.java b/rome/src/main/java/com/rometools/rome/feed/atom/Generator.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/atom/Generator.java rename to rome/src/main/java/com/rometools/rome/feed/atom/Generator.java diff --git a/src/main/java/com/rometools/rome/feed/atom/Link.java b/rome/src/main/java/com/rometools/rome/feed/atom/Link.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/atom/Link.java rename to rome/src/main/java/com/rometools/rome/feed/atom/Link.java diff --git a/src/main/java/com/rometools/rome/feed/atom/Person.java b/rome/src/main/java/com/rometools/rome/feed/atom/Person.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/atom/Person.java rename to rome/src/main/java/com/rometools/rome/feed/atom/Person.java diff --git a/src/main/java/com/rometools/rome/feed/impl/BeanIntrospector.java b/rome/src/main/java/com/rometools/rome/feed/impl/BeanIntrospector.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/impl/BeanIntrospector.java rename to rome/src/main/java/com/rometools/rome/feed/impl/BeanIntrospector.java diff --git a/src/main/java/com/rometools/rome/feed/impl/CloneableBean.java b/rome/src/main/java/com/rometools/rome/feed/impl/CloneableBean.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/impl/CloneableBean.java rename to rome/src/main/java/com/rometools/rome/feed/impl/CloneableBean.java diff --git a/src/main/java/com/rometools/rome/feed/impl/ConfigurableClassLoader.java b/rome/src/main/java/com/rometools/rome/feed/impl/ConfigurableClassLoader.java similarity index 96% rename from src/main/java/com/rometools/rome/feed/impl/ConfigurableClassLoader.java rename to rome/src/main/java/com/rometools/rome/feed/impl/ConfigurableClassLoader.java index 4ceccf5..3644fea 100644 --- a/src/main/java/com/rometools/rome/feed/impl/ConfigurableClassLoader.java +++ b/rome/src/main/java/com/rometools/rome/feed/impl/ConfigurableClassLoader.java @@ -1,40 +1,40 @@ -package com.rometools.rome.feed.impl; - -/** - * This class addresses some ClassLoader problems in OSGi environments. If you have ClassLoader - * problems, simply override the default ClassLoader by calling the - * {@link #setClassLoader(ClassLoader)} method before calling any ROME code. Unfortunately I don't - * know whether this works because I have absolutely no experience with OSGi. - * - * @author Patrick Gotthard - * - */ -public enum ConfigurableClassLoader { - - INSTANCE; - - private ClassLoader classLoader; - - /** - * Get the configured ClassLoader. Returns - * - * @return The configured ClassLoader. Returns the ClassLoader of this enum when the ClassLoader - * was not overridden. - */ - public ClassLoader getClassLoader() { - if (classLoader == null) { - classLoader = ConfigurableClassLoader.class.getClassLoader(); - } - return classLoader; - } - - /** - * Overrides the default ClassLoader (the ClassLoader of this enum). - * - * @param classLoader The ClassLoader to set. - */ - public void setClassLoader(final ClassLoader classLoader) { - this.classLoader = classLoader; - } - -} +package com.rometools.rome.feed.impl; + +/** + * This class addresses some ClassLoader problems in OSGi environments. If you have ClassLoader + * problems, simply override the default ClassLoader by calling the + * {@link #setClassLoader(ClassLoader)} method before calling any ROME code. Unfortunately I don't + * know whether this works because I have absolutely no experience with OSGi. + * + * @author Patrick Gotthard + * + */ +public enum ConfigurableClassLoader { + + INSTANCE; + + private ClassLoader classLoader; + + /** + * Get the configured ClassLoader. Returns + * + * @return The configured ClassLoader. Returns the ClassLoader of this enum when the ClassLoader + * was not overridden. + */ + public ClassLoader getClassLoader() { + if (classLoader == null) { + classLoader = ConfigurableClassLoader.class.getClassLoader(); + } + return classLoader; + } + + /** + * Overrides the default ClassLoader (the ClassLoader of this enum). + * + * @param classLoader The ClassLoader to set. + */ + public void setClassLoader(final ClassLoader classLoader) { + this.classLoader = classLoader; + } + +} diff --git a/src/main/java/com/rometools/rome/feed/impl/CopyFromHelper.java b/rome/src/main/java/com/rometools/rome/feed/impl/CopyFromHelper.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/impl/CopyFromHelper.java rename to rome/src/main/java/com/rometools/rome/feed/impl/CopyFromHelper.java diff --git a/src/main/java/com/rometools/rome/feed/impl/EqualsBean.java b/rome/src/main/java/com/rometools/rome/feed/impl/EqualsBean.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/impl/EqualsBean.java rename to rome/src/main/java/com/rometools/rome/feed/impl/EqualsBean.java diff --git a/src/main/java/com/rometools/rome/feed/impl/ObjectBean.java b/rome/src/main/java/com/rometools/rome/feed/impl/ObjectBean.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/impl/ObjectBean.java rename to rome/src/main/java/com/rometools/rome/feed/impl/ObjectBean.java diff --git a/src/main/java/com/rometools/rome/feed/impl/ToStringBean.java b/rome/src/main/java/com/rometools/rome/feed/impl/ToStringBean.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/impl/ToStringBean.java rename to rome/src/main/java/com/rometools/rome/feed/impl/ToStringBean.java diff --git a/src/main/java/com/rometools/rome/feed/module/DCModule.java b/rome/src/main/java/com/rometools/rome/feed/module/DCModule.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/module/DCModule.java rename to rome/src/main/java/com/rometools/rome/feed/module/DCModule.java diff --git a/src/main/java/com/rometools/rome/feed/module/DCModuleImpl.java b/rome/src/main/java/com/rometools/rome/feed/module/DCModuleImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/module/DCModuleImpl.java rename to rome/src/main/java/com/rometools/rome/feed/module/DCModuleImpl.java diff --git a/src/main/java/com/rometools/rome/feed/module/DCSubject.java b/rome/src/main/java/com/rometools/rome/feed/module/DCSubject.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/module/DCSubject.java rename to rome/src/main/java/com/rometools/rome/feed/module/DCSubject.java diff --git a/src/main/java/com/rometools/rome/feed/module/DCSubjectImpl.java b/rome/src/main/java/com/rometools/rome/feed/module/DCSubjectImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/module/DCSubjectImpl.java rename to rome/src/main/java/com/rometools/rome/feed/module/DCSubjectImpl.java diff --git a/src/main/java/com/rometools/rome/feed/module/Extendable.java b/rome/src/main/java/com/rometools/rome/feed/module/Extendable.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/module/Extendable.java rename to rome/src/main/java/com/rometools/rome/feed/module/Extendable.java diff --git a/src/main/java/com/rometools/rome/feed/module/Module.java b/rome/src/main/java/com/rometools/rome/feed/module/Module.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/module/Module.java rename to rome/src/main/java/com/rometools/rome/feed/module/Module.java diff --git a/src/main/java/com/rometools/rome/feed/module/ModuleImpl.java b/rome/src/main/java/com/rometools/rome/feed/module/ModuleImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/module/ModuleImpl.java rename to rome/src/main/java/com/rometools/rome/feed/module/ModuleImpl.java diff --git a/src/main/java/com/rometools/rome/feed/module/SyModule.java b/rome/src/main/java/com/rometools/rome/feed/module/SyModule.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/module/SyModule.java rename to rome/src/main/java/com/rometools/rome/feed/module/SyModule.java diff --git a/src/main/java/com/rometools/rome/feed/module/SyModuleImpl.java b/rome/src/main/java/com/rometools/rome/feed/module/SyModuleImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/module/SyModuleImpl.java rename to rome/src/main/java/com/rometools/rome/feed/module/SyModuleImpl.java diff --git a/src/main/java/com/rometools/rome/feed/module/impl/ModuleUtils.java b/rome/src/main/java/com/rometools/rome/feed/module/impl/ModuleUtils.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/module/impl/ModuleUtils.java rename to rome/src/main/java/com/rometools/rome/feed/module/impl/ModuleUtils.java diff --git a/src/main/java/com/rometools/rome/feed/rss/Category.java b/rome/src/main/java/com/rometools/rome/feed/rss/Category.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/Category.java rename to rome/src/main/java/com/rometools/rome/feed/rss/Category.java diff --git a/src/main/java/com/rometools/rome/feed/rss/Channel.java b/rome/src/main/java/com/rometools/rome/feed/rss/Channel.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/Channel.java rename to rome/src/main/java/com/rometools/rome/feed/rss/Channel.java diff --git a/src/main/java/com/rometools/rome/feed/rss/Cloud.java b/rome/src/main/java/com/rometools/rome/feed/rss/Cloud.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/Cloud.java rename to rome/src/main/java/com/rometools/rome/feed/rss/Cloud.java diff --git a/src/main/java/com/rometools/rome/feed/rss/Content.java b/rome/src/main/java/com/rometools/rome/feed/rss/Content.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/Content.java rename to rome/src/main/java/com/rometools/rome/feed/rss/Content.java diff --git a/src/main/java/com/rometools/rome/feed/rss/Description.java b/rome/src/main/java/com/rometools/rome/feed/rss/Description.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/Description.java rename to rome/src/main/java/com/rometools/rome/feed/rss/Description.java diff --git a/src/main/java/com/rometools/rome/feed/rss/Enclosure.java b/rome/src/main/java/com/rometools/rome/feed/rss/Enclosure.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/Enclosure.java rename to rome/src/main/java/com/rometools/rome/feed/rss/Enclosure.java diff --git a/src/main/java/com/rometools/rome/feed/rss/Guid.java b/rome/src/main/java/com/rometools/rome/feed/rss/Guid.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/Guid.java rename to rome/src/main/java/com/rometools/rome/feed/rss/Guid.java diff --git a/src/main/java/com/rometools/rome/feed/rss/Image.java b/rome/src/main/java/com/rometools/rome/feed/rss/Image.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/Image.java rename to rome/src/main/java/com/rometools/rome/feed/rss/Image.java diff --git a/src/main/java/com/rometools/rome/feed/rss/Item.java b/rome/src/main/java/com/rometools/rome/feed/rss/Item.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/Item.java rename to rome/src/main/java/com/rometools/rome/feed/rss/Item.java diff --git a/src/main/java/com/rometools/rome/feed/rss/Source.java b/rome/src/main/java/com/rometools/rome/feed/rss/Source.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/Source.java rename to rome/src/main/java/com/rometools/rome/feed/rss/Source.java diff --git a/src/main/java/com/rometools/rome/feed/rss/TextInput.java b/rome/src/main/java/com/rometools/rome/feed/rss/TextInput.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/rss/TextInput.java rename to rome/src/main/java/com/rometools/rome/feed/rss/TextInput.java diff --git a/src/main/java/com/rometools/rome/feed/synd/Converter.java b/rome/src/main/java/com/rometools/rome/feed/synd/Converter.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/Converter.java rename to rome/src/main/java/com/rometools/rome/feed/synd/Converter.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndCategory.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndCategory.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndCategory.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndCategory.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndCategoryImpl.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndCategoryImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndCategoryImpl.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndCategoryImpl.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndCategoryListFacade.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndCategoryListFacade.java similarity index 96% rename from src/main/java/com/rometools/rome/feed/synd/SyndCategoryListFacade.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndCategoryListFacade.java index 310c245..96da572 100644 --- a/src/main/java/com/rometools/rome/feed/synd/SyndCategoryListFacade.java +++ b/rome/src/main/java/com/rometools/rome/feed/synd/SyndCategoryListFacade.java @@ -1,162 +1,162 @@ -package com.rometools.rome.feed.synd; - -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.List; - -import com.rometools.rome.feed.module.DCSubject; - -/** - * 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 final 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(final List subjects) { - this.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. - * - */ - @Override - public SyndCategory get(final int index) { - return new SyndCategoryImpl(subjects.get(index)); - } - - /** - * Returns the size of the list. - *

      - * - * @return the size of the list. - * - */ - @Override - 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. - * - */ - @Override - public SyndCategory set(final int index, final SyndCategory obj) { - final SyndCategoryImpl sCat = (SyndCategoryImpl) obj; - DCSubject subject; - if (sCat != null) { - subject = sCat.getSubject(); - } else { - subject = null; - } - subject = subjects.set(index, subject); - if (subject != null) { - return new SyndCategoryImpl(subject); - } else { - return null; - } - } - - /** - * Adds a category to the list. - *

      - * - * @param index position to add the category. - * @param obj the SyndCategoryImpl object to add. - * - */ - @Override - public void add(final int index, final SyndCategory obj) { - final SyndCategoryImpl sCat = (SyndCategoryImpl) obj; - DCSubject subject; - if (sCat != null) { - subject = sCat.getSubject(); - } else { - subject = 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. - * - */ - @Override - public SyndCategory remove(final int index) { - final DCSubject subject = subjects.remove(index); - if (subject != null) { - return new SyndCategoryImpl(subject); - } else { - return 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(final List cList) { - List sList = null; - if (cList != null) { - sList = new ArrayList(); - for (int i = 0; i < cList.size(); i++) { - final SyndCategoryImpl sCat = (SyndCategoryImpl) cList.get(i); - DCSubject subject = null; - if (sCat != null) { - subject = sCat.getSubject(); - } - sList.add(subject); - } - } - return sList; - } - +package com.rometools.rome.feed.synd; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.List; + +import com.rometools.rome.feed.module.DCSubject; + +/** + * 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 final 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(final List subjects) { + this.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. + * + */ + @Override + public SyndCategory get(final int index) { + return new SyndCategoryImpl(subjects.get(index)); + } + + /** + * Returns the size of the list. + *

      + * + * @return the size of the list. + * + */ + @Override + 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. + * + */ + @Override + public SyndCategory set(final int index, final SyndCategory obj) { + final SyndCategoryImpl sCat = (SyndCategoryImpl) obj; + DCSubject subject; + if (sCat != null) { + subject = sCat.getSubject(); + } else { + subject = null; + } + subject = subjects.set(index, subject); + if (subject != null) { + return new SyndCategoryImpl(subject); + } else { + return null; + } + } + + /** + * Adds a category to the list. + *

      + * + * @param index position to add the category. + * @param obj the SyndCategoryImpl object to add. + * + */ + @Override + public void add(final int index, final SyndCategory obj) { + final SyndCategoryImpl sCat = (SyndCategoryImpl) obj; + DCSubject subject; + if (sCat != null) { + subject = sCat.getSubject(); + } else { + subject = 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. + * + */ + @Override + public SyndCategory remove(final int index) { + final DCSubject subject = subjects.remove(index); + if (subject != null) { + return new SyndCategoryImpl(subject); + } else { + return 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(final List cList) { + List sList = null; + if (cList != null) { + sList = new ArrayList(); + for (int i = 0; i < cList.size(); i++) { + final SyndCategoryImpl sCat = (SyndCategoryImpl) cList.get(i); + DCSubject subject = null; + if (sCat != null) { + subject = sCat.getSubject(); + } + sList.add(subject); + } + } + return sList; + } + } \ No newline at end of file diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndContent.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndContent.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndContent.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndContent.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndContentImpl.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndContentImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndContentImpl.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndContentImpl.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndEnclosure.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndEnclosure.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndEnclosure.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndEnclosure.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndEnclosureImpl.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndEnclosureImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndEnclosureImpl.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndEnclosureImpl.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndEntry.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndEntry.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndEntry.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndEntry.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndEntryImpl.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndEntryImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndEntryImpl.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndEntryImpl.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndFeed.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndFeed.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndFeed.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndFeed.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndFeedImpl.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndFeedImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndFeedImpl.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndFeedImpl.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndImage.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndImage.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndImage.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndImage.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndImageImpl.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndImageImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndImageImpl.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndImageImpl.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndLink.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndLink.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndLink.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndLink.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndLinkImpl.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndLinkImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndLinkImpl.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndLinkImpl.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndPerson.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndPerson.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndPerson.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndPerson.java diff --git a/src/main/java/com/rometools/rome/feed/synd/SyndPersonImpl.java b/rome/src/main/java/com/rometools/rome/feed/synd/SyndPersonImpl.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/SyndPersonImpl.java rename to rome/src/main/java/com/rometools/rome/feed/synd/SyndPersonImpl.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForAtom03.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForAtom03.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/ConverterForAtom03.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForAtom03.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForAtom10.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForAtom10.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/ConverterForAtom10.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForAtom10.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS090.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS090.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS090.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS090.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS091Netscape.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS091Netscape.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS091Netscape.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS091Netscape.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS091Userland.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS091Userland.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS091Userland.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS091Userland.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS092.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS092.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS092.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS092.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS093.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS093.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS093.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS093.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS094.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS094.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS094.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS094.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS10.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS10.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS10.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS10.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS20.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS20.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS20.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/ConverterForRSS20.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/Converters.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/Converters.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/Converters.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/Converters.java diff --git a/src/main/java/com/rometools/rome/feed/synd/impl/URINormalizer.java b/rome/src/main/java/com/rometools/rome/feed/synd/impl/URINormalizer.java similarity index 100% rename from src/main/java/com/rometools/rome/feed/synd/impl/URINormalizer.java rename to rome/src/main/java/com/rometools/rome/feed/synd/impl/URINormalizer.java diff --git a/src/main/java/com/rometools/rome/io/DelegatingModuleGenerator.java b/rome/src/main/java/com/rometools/rome/io/DelegatingModuleGenerator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/DelegatingModuleGenerator.java rename to rome/src/main/java/com/rometools/rome/io/DelegatingModuleGenerator.java diff --git a/src/main/java/com/rometools/rome/io/DelegatingModuleParser.java b/rome/src/main/java/com/rometools/rome/io/DelegatingModuleParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/DelegatingModuleParser.java rename to rome/src/main/java/com/rometools/rome/io/DelegatingModuleParser.java diff --git a/src/main/java/com/rometools/rome/io/FeedException.java b/rome/src/main/java/com/rometools/rome/io/FeedException.java similarity index 100% rename from src/main/java/com/rometools/rome/io/FeedException.java rename to rome/src/main/java/com/rometools/rome/io/FeedException.java diff --git a/src/main/java/com/rometools/rome/io/ModuleGenerator.java b/rome/src/main/java/com/rometools/rome/io/ModuleGenerator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/ModuleGenerator.java rename to rome/src/main/java/com/rometools/rome/io/ModuleGenerator.java diff --git a/src/main/java/com/rometools/rome/io/ModuleParser.java b/rome/src/main/java/com/rometools/rome/io/ModuleParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/ModuleParser.java rename to rome/src/main/java/com/rometools/rome/io/ModuleParser.java diff --git a/src/main/java/com/rometools/rome/io/ParsingFeedException.java b/rome/src/main/java/com/rometools/rome/io/ParsingFeedException.java similarity index 100% rename from src/main/java/com/rometools/rome/io/ParsingFeedException.java rename to rome/src/main/java/com/rometools/rome/io/ParsingFeedException.java diff --git a/src/main/java/com/rometools/rome/io/SAXBuilder.java b/rome/src/main/java/com/rometools/rome/io/SAXBuilder.java similarity index 100% rename from src/main/java/com/rometools/rome/io/SAXBuilder.java rename to rome/src/main/java/com/rometools/rome/io/SAXBuilder.java diff --git a/src/main/java/com/rometools/rome/io/SyndFeedInput.java b/rome/src/main/java/com/rometools/rome/io/SyndFeedInput.java similarity index 100% rename from src/main/java/com/rometools/rome/io/SyndFeedInput.java rename to rome/src/main/java/com/rometools/rome/io/SyndFeedInput.java diff --git a/src/main/java/com/rometools/rome/io/SyndFeedOutput.java b/rome/src/main/java/com/rometools/rome/io/SyndFeedOutput.java similarity index 100% rename from src/main/java/com/rometools/rome/io/SyndFeedOutput.java rename to rome/src/main/java/com/rometools/rome/io/SyndFeedOutput.java diff --git a/src/main/java/com/rometools/rome/io/WireFeedGenerator.java b/rome/src/main/java/com/rometools/rome/io/WireFeedGenerator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/WireFeedGenerator.java rename to rome/src/main/java/com/rometools/rome/io/WireFeedGenerator.java diff --git a/src/main/java/com/rometools/rome/io/WireFeedInput.java b/rome/src/main/java/com/rometools/rome/io/WireFeedInput.java similarity index 100% rename from src/main/java/com/rometools/rome/io/WireFeedInput.java rename to rome/src/main/java/com/rometools/rome/io/WireFeedInput.java diff --git a/src/main/java/com/rometools/rome/io/WireFeedOutput.java b/rome/src/main/java/com/rometools/rome/io/WireFeedOutput.java similarity index 100% rename from src/main/java/com/rometools/rome/io/WireFeedOutput.java rename to rome/src/main/java/com/rometools/rome/io/WireFeedOutput.java diff --git a/src/main/java/com/rometools/rome/io/WireFeedParser.java b/rome/src/main/java/com/rometools/rome/io/WireFeedParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/WireFeedParser.java rename to rome/src/main/java/com/rometools/rome/io/WireFeedParser.java diff --git a/src/main/java/com/rometools/rome/io/XmlReader.java b/rome/src/main/java/com/rometools/rome/io/XmlReader.java similarity index 100% rename from src/main/java/com/rometools/rome/io/XmlReader.java rename to rome/src/main/java/com/rometools/rome/io/XmlReader.java diff --git a/src/main/java/com/rometools/rome/io/XmlReaderException.java b/rome/src/main/java/com/rometools/rome/io/XmlReaderException.java similarity index 100% rename from src/main/java/com/rometools/rome/io/XmlReaderException.java rename to rome/src/main/java/com/rometools/rome/io/XmlReaderException.java diff --git a/src/main/java/com/rometools/rome/io/impl/Atom03Generator.java b/rome/src/main/java/com/rometools/rome/io/impl/Atom03Generator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/Atom03Generator.java rename to rome/src/main/java/com/rometools/rome/io/impl/Atom03Generator.java diff --git a/src/main/java/com/rometools/rome/io/impl/Atom03Parser.java b/rome/src/main/java/com/rometools/rome/io/impl/Atom03Parser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/Atom03Parser.java rename to rome/src/main/java/com/rometools/rome/io/impl/Atom03Parser.java diff --git a/src/main/java/com/rometools/rome/io/impl/Atom10Generator.java b/rome/src/main/java/com/rometools/rome/io/impl/Atom10Generator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/Atom10Generator.java rename to rome/src/main/java/com/rometools/rome/io/impl/Atom10Generator.java diff --git a/src/main/java/com/rometools/rome/io/impl/Atom10Parser.java b/rome/src/main/java/com/rometools/rome/io/impl/Atom10Parser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/Atom10Parser.java rename to rome/src/main/java/com/rometools/rome/io/impl/Atom10Parser.java diff --git a/src/main/java/com/rometools/rome/io/impl/Base64.java b/rome/src/main/java/com/rometools/rome/io/impl/Base64.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/Base64.java rename to rome/src/main/java/com/rometools/rome/io/impl/Base64.java diff --git a/src/main/java/com/rometools/rome/io/impl/BaseWireFeedGenerator.java b/rome/src/main/java/com/rometools/rome/io/impl/BaseWireFeedGenerator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/BaseWireFeedGenerator.java rename to rome/src/main/java/com/rometools/rome/io/impl/BaseWireFeedGenerator.java diff --git a/src/main/java/com/rometools/rome/io/impl/BaseWireFeedParser.java b/rome/src/main/java/com/rometools/rome/io/impl/BaseWireFeedParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/BaseWireFeedParser.java rename to rome/src/main/java/com/rometools/rome/io/impl/BaseWireFeedParser.java diff --git a/src/main/java/com/rometools/rome/io/impl/DCModuleGenerator.java b/rome/src/main/java/com/rometools/rome/io/impl/DCModuleGenerator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/DCModuleGenerator.java rename to rome/src/main/java/com/rometools/rome/io/impl/DCModuleGenerator.java diff --git a/src/main/java/com/rometools/rome/io/impl/DCModuleParser.java b/rome/src/main/java/com/rometools/rome/io/impl/DCModuleParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/DCModuleParser.java rename to rome/src/main/java/com/rometools/rome/io/impl/DCModuleParser.java diff --git a/src/main/java/com/rometools/rome/io/impl/DateParser.java b/rome/src/main/java/com/rometools/rome/io/impl/DateParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/DateParser.java rename to rome/src/main/java/com/rometools/rome/io/impl/DateParser.java diff --git a/src/main/java/com/rometools/rome/io/impl/FeedGenerators.java b/rome/src/main/java/com/rometools/rome/io/impl/FeedGenerators.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/FeedGenerators.java rename to rome/src/main/java/com/rometools/rome/io/impl/FeedGenerators.java diff --git a/src/main/java/com/rometools/rome/io/impl/FeedParsers.java b/rome/src/main/java/com/rometools/rome/io/impl/FeedParsers.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/FeedParsers.java rename to rome/src/main/java/com/rometools/rome/io/impl/FeedParsers.java diff --git a/src/main/java/com/rometools/rome/io/impl/ModuleGenerators.java b/rome/src/main/java/com/rometools/rome/io/impl/ModuleGenerators.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/ModuleGenerators.java rename to rome/src/main/java/com/rometools/rome/io/impl/ModuleGenerators.java diff --git a/src/main/java/com/rometools/rome/io/impl/ModuleParsers.java b/rome/src/main/java/com/rometools/rome/io/impl/ModuleParsers.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/ModuleParsers.java rename to rome/src/main/java/com/rometools/rome/io/impl/ModuleParsers.java diff --git a/src/main/java/com/rometools/rome/io/impl/NumberParser.java b/rome/src/main/java/com/rometools/rome/io/impl/NumberParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/NumberParser.java rename to rome/src/main/java/com/rometools/rome/io/impl/NumberParser.java diff --git a/src/main/java/com/rometools/rome/io/impl/PluginManager.java b/rome/src/main/java/com/rometools/rome/io/impl/PluginManager.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/PluginManager.java rename to rome/src/main/java/com/rometools/rome/io/impl/PluginManager.java diff --git a/src/main/java/com/rometools/rome/io/impl/PropertiesLoader.java b/rome/src/main/java/com/rometools/rome/io/impl/PropertiesLoader.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/PropertiesLoader.java rename to rome/src/main/java/com/rometools/rome/io/impl/PropertiesLoader.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS090Generator.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS090Generator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS090Generator.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS090Generator.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS090Parser.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS090Parser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS090Parser.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS090Parser.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS091NetscapeGenerator.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS091NetscapeGenerator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS091NetscapeGenerator.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS091NetscapeGenerator.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS091NetscapeParser.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS091NetscapeParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS091NetscapeParser.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS091NetscapeParser.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS091UserlandGenerator.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS091UserlandGenerator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS091UserlandGenerator.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS091UserlandGenerator.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS091UserlandParser.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS091UserlandParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS091UserlandParser.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS091UserlandParser.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS092Generator.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS092Generator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS092Generator.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS092Generator.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS092Parser.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS092Parser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS092Parser.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS092Parser.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS093Generator.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS093Generator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS093Generator.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS093Generator.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS093Parser.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS093Parser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS093Parser.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS093Parser.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS094Generator.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS094Generator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS094Generator.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS094Generator.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS094Parser.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS094Parser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS094Parser.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS094Parser.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS10Generator.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS10Generator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS10Generator.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS10Generator.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS10Parser.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS10Parser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS10Parser.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS10Parser.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS20Generator.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS20Generator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS20Generator.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS20Generator.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS20Parser.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS20Parser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS20Parser.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS20Parser.java diff --git a/src/main/java/com/rometools/rome/io/impl/RSS20wNSParser.java b/rome/src/main/java/com/rometools/rome/io/impl/RSS20wNSParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/RSS20wNSParser.java rename to rome/src/main/java/com/rometools/rome/io/impl/RSS20wNSParser.java diff --git a/src/main/java/com/rometools/rome/io/impl/SyModuleGenerator.java b/rome/src/main/java/com/rometools/rome/io/impl/SyModuleGenerator.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/SyModuleGenerator.java rename to rome/src/main/java/com/rometools/rome/io/impl/SyModuleGenerator.java diff --git a/src/main/java/com/rometools/rome/io/impl/SyModuleParser.java b/rome/src/main/java/com/rometools/rome/io/impl/SyModuleParser.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/SyModuleParser.java rename to rome/src/main/java/com/rometools/rome/io/impl/SyModuleParser.java diff --git a/src/main/java/com/rometools/rome/io/impl/XmlFixerReader.java b/rome/src/main/java/com/rometools/rome/io/impl/XmlFixerReader.java similarity index 100% rename from src/main/java/com/rometools/rome/io/impl/XmlFixerReader.java rename to rome/src/main/java/com/rometools/rome/io/impl/XmlFixerReader.java diff --git a/src/main/resources/com/rometools/rome/rome.properties b/rome/src/main/resources/com/rometools/rome/rome.properties similarity index 100% rename from src/main/resources/com/rometools/rome/rome.properties rename to rome/src/main/resources/com/rometools/rome/rome.properties diff --git a/src/site/apt/ChangeLog.apt b/rome/src/site/apt/ChangeLog.apt similarity index 100% rename from src/site/apt/ChangeLog.apt rename to rome/src/site/apt/ChangeLog.apt diff --git a/src/site/apt/HowRomeWorks/RomeV0.4TutorialDefiningACustomModuleBeanParserAndGenerator.apt b/rome/src/site/apt/HowRomeWorks/RomeV0.4TutorialDefiningACustomModuleBeanParserAndGenerator.apt similarity index 100% rename from src/site/apt/HowRomeWorks/RomeV0.4TutorialDefiningACustomModuleBeanParserAndGenerator.apt rename to rome/src/site/apt/HowRomeWorks/RomeV0.4TutorialDefiningACustomModuleBeanParserAndGenerator.apt diff --git a/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt b/rome/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt similarity index 100% rename from src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt rename to rome/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt diff --git a/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt b/rome/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt similarity index 100% rename from src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt rename to rome/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt diff --git a/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToCreateAndWriteASyndicationFeed.apt b/rome/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToCreateAndWriteASyndicationFeed.apt similarity index 100% rename from src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToCreateAndWriteASyndicationFeed.apt rename to rome/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToCreateAndWriteASyndicationFeed.apt diff --git a/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToReadASyndicationFeed.apt b/rome/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToReadASyndicationFeed.apt similarity index 100% rename from src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToReadASyndicationFeed.apt rename to rome/src/site/apt/HowRomeWorks/RomeV0.4TutorialUsingRomeToReadASyndicationFeed.apt diff --git a/src/site/apt/HowRomeWorks/UnderstandingTheRomeCommonClassesAndInterfaces.apt b/rome/src/site/apt/HowRomeWorks/UnderstandingTheRomeCommonClassesAndInterfaces.apt similarity index 100% rename from src/site/apt/HowRomeWorks/UnderstandingTheRomeCommonClassesAndInterfaces.apt rename to rome/src/site/apt/HowRomeWorks/UnderstandingTheRomeCommonClassesAndInterfaces.apt diff --git a/src/site/apt/HowRomeWorks/index.apt b/rome/src/site/apt/HowRomeWorks/index.apt similarity index 100% rename from src/site/apt/HowRomeWorks/index.apt rename to rome/src/site/apt/HowRomeWorks/index.apt diff --git a/src/site/apt/HowToBuildRome.apt b/rome/src/site/apt/HowToBuildRome.apt similarity index 100% rename from src/site/apt/HowToBuildRome.apt rename to rome/src/site/apt/HowToBuildRome.apt diff --git a/src/site/apt/PreservingWireFeeds.apt b/rome/src/site/apt/PreservingWireFeeds.apt similarity index 100% rename from src/site/apt/PreservingWireFeeds.apt rename to rome/src/site/apt/PreservingWireFeeds.apt diff --git a/src/site/apt/ProductsOrSitesPoweredByROME.apt b/rome/src/site/apt/ProductsOrSitesPoweredByROME.apt similarity index 100% rename from src/site/apt/ProductsOrSitesPoweredByROME.apt rename to rome/src/site/apt/ProductsOrSitesPoweredByROME.apt diff --git a/src/site/apt/ROMEAndMaven2.apt b/rome/src/site/apt/ROMEAndMaven2.apt similarity index 100% rename from src/site/apt/ROMEAndMaven2.apt rename to rome/src/site/apt/ROMEAndMaven2.apt diff --git a/src/site/apt/ROMEAndOSGI.apt b/rome/src/site/apt/ROMEAndOSGI.apt similarity index 100% rename from src/site/apt/ROMEAndOSGI.apt rename to rome/src/site/apt/ROMEAndOSGI.apt diff --git a/src/site/apt/ROMEDevelopmentProcess.apt b/rome/src/site/apt/ROMEDevelopmentProcess.apt similarity index 100% rename from src/site/apt/ROMEDevelopmentProcess.apt rename to rome/src/site/apt/ROMEDevelopmentProcess.apt diff --git a/src/site/apt/ROMEDevelopmentProposals/ROME21stProposalJune10th2006NOTCURRENT.apt b/rome/src/site/apt/ROMEDevelopmentProposals/ROME21stProposalJune10th2006NOTCURRENT.apt similarity index 100% rename from src/site/apt/ROMEDevelopmentProposals/ROME21stProposalJune10th2006NOTCURRENT.apt rename to rome/src/site/apt/ROMEDevelopmentProposals/ROME21stProposalJune10th2006NOTCURRENT.apt diff --git a/src/site/apt/ROMEDevelopmentProposals/ROME22ndProposalJuly18th2006CURRENT.apt b/rome/src/site/apt/ROMEDevelopmentProposals/ROME22ndProposalJuly18th2006CURRENT.apt similarity index 100% rename from src/site/apt/ROMEDevelopmentProposals/ROME22ndProposalJuly18th2006CURRENT.apt rename to rome/src/site/apt/ROMEDevelopmentProposals/ROME22ndProposalJuly18th2006CURRENT.apt diff --git a/src/site/apt/ROMEDevelopmentProposals/ROMEFeatureRequests.apt b/rome/src/site/apt/ROMEDevelopmentProposals/ROMEFeatureRequests.apt similarity index 100% rename from src/site/apt/ROMEDevelopmentProposals/ROMEFeatureRequests.apt rename to rome/src/site/apt/ROMEDevelopmentProposals/ROMEFeatureRequests.apt diff --git a/src/site/apt/ROMEDevelopmentProposals/index.apt b/rome/src/site/apt/ROMEDevelopmentProposals/index.apt similarity index 100% rename from src/site/apt/ROMEDevelopmentProposals/index.apt rename to rome/src/site/apt/ROMEDevelopmentProposals/index.apt diff --git a/src/site/apt/ROMEROADMAPProposed.apt b/rome/src/site/apt/ROMEROADMAPProposed.apt similarity index 100% rename from src/site/apt/ROMEROADMAPProposed.apt rename to rome/src/site/apt/ROMEROADMAPProposed.apt diff --git a/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1HowToBuildAndRunTheTutorialsSampleCode.apt b/rome/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1HowToBuildAndRunTheTutorialsSampleCode.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1HowToBuildAndRunTheTutorialsSampleCode.apt rename to rome/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1HowToBuildAndRunTheTutorialsSampleCode.apt diff --git a/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt b/rome/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt rename to rome/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt diff --git a/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt b/rome/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt rename to rome/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt diff --git a/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToReadASyndicationFeed.apt b/rome/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToReadASyndicationFeed.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToReadASyndicationFeed.apt rename to rome/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/RomeV0.1TutorialUsingRomeToReadASyndicationFeed.apt diff --git a/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/index.apt b/rome/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/index.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/index.apt rename to rome/src/site/apt/ROMEReleases/ROME0.1Beta/RomeV0.1Tutorials/index.apt diff --git a/src/site/apt/ROMEReleases/ROME0.1Beta/index.apt b/rome/src/site/apt/ROMEReleases/ROME0.1Beta/index.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.1Beta/index.apt rename to rome/src/site/apt/ROMEReleases/ROME0.1Beta/index.apt diff --git a/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt b/rome/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt rename to rome/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt diff --git a/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt b/rome/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt rename to rome/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt diff --git a/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToReadASyndicationFeed.apt b/rome/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToReadASyndicationFeed.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToReadASyndicationFeed.apt rename to rome/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/RomeV0.2TutorialUsingRomeToReadASyndicationFeed.apt diff --git a/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/index.apt b/rome/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/index.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/index.apt rename to rome/src/site/apt/ROMEReleases/ROME0.2Beta/RomeV0.2Tutorials/index.apt diff --git a/src/site/apt/ROMEReleases/ROME0.2Beta/index.apt b/rome/src/site/apt/ROMEReleases/ROME0.2Beta/index.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.2Beta/index.apt rename to rome/src/site/apt/ROMEReleases/ROME0.2Beta/index.apt diff --git a/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3HowToBuildAndRunTheTutorialsSampleCode.apt b/rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3HowToBuildAndRunTheTutorialsSampleCode.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3HowToBuildAndRunTheTutorialsSampleCode.apt rename to rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3HowToBuildAndRunTheTutorialsSampleCode.apt diff --git a/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialDefiningACustomModuleBeanParserAndGenerator.apt b/rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialDefiningACustomModuleBeanParserAndGenerator.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialDefiningACustomModuleBeanParserAndGenerator.apt rename to rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialDefiningACustomModuleBeanParserAndGenerator.apt diff --git a/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt b/rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt rename to rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToAggregateManySyndicationFeedsIntoASingleOne.apt diff --git a/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt b/rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt rename to rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToConvertASyndicationFeedFromOneTypeToAnother.apt diff --git a/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToCreateAndWriteASyndicationFeed.apt b/rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToCreateAndWriteASyndicationFeed.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToCreateAndWriteASyndicationFeed.apt rename to rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToCreateAndWriteASyndicationFeed.apt diff --git a/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToReadASyndicationFeed.apt b/rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToReadASyndicationFeed.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToReadASyndicationFeed.apt rename to rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/RomeV0.3TutorialUsingRomeToReadASyndicationFeed.apt diff --git a/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/index.apt b/rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/index.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/index.apt rename to rome/src/site/apt/ROMEReleases/ROME0.3Beta/RomeV0.3Tutorials/index.apt diff --git a/src/site/apt/ROMEReleases/ROME0.3Beta/index.apt b/rome/src/site/apt/ROMEReleases/ROME0.3Beta/index.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.3Beta/index.apt rename to rome/src/site/apt/ROMEReleases/ROME0.3Beta/index.apt diff --git a/src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/RomeV0.4HowToBuildAndRunTheTutorialsSampleCode.apt b/rome/src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/RomeV0.4HowToBuildAndRunTheTutorialsSampleCode.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/RomeV0.4HowToBuildAndRunTheTutorialsSampleCode.apt rename to rome/src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/RomeV0.4HowToBuildAndRunTheTutorialsSampleCode.apt diff --git a/src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/RomeV0.4TutorialUsingRomeWithinAServletToCreateAndReturnAFeed.apt b/rome/src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/RomeV0.4TutorialUsingRomeWithinAServletToCreateAndReturnAFeed.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/RomeV0.4TutorialUsingRomeWithinAServletToCreateAndReturnAFeed.apt rename to rome/src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/RomeV0.4TutorialUsingRomeWithinAServletToCreateAndReturnAFeed.apt diff --git a/src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/index.apt b/rome/src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/index.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/index.apt rename to rome/src/site/apt/ROMEReleases/ROME0.4Beta/RomeV0.4Tutorials/index.apt diff --git a/src/site/apt/ROMEReleases/ROME0.4Beta/index.apt b/rome/src/site/apt/ROMEReleases/ROME0.4Beta/index.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.4Beta/index.apt rename to rome/src/site/apt/ROMEReleases/ROME0.4Beta/index.apt diff --git a/src/site/apt/ROMEReleases/ROME0.5Beta/ROMET-Shirt.apt b/rome/src/site/apt/ROMEReleases/ROME0.5Beta/ROMET-Shirt.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.5Beta/ROMET-Shirt.apt rename to rome/src/site/apt/ROMEReleases/ROME0.5Beta/ROMET-Shirt.apt diff --git a/src/site/apt/ROMEReleases/ROME0.5Beta/index.apt b/rome/src/site/apt/ROMEReleases/ROME0.5Beta/index.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.5Beta/index.apt rename to rome/src/site/apt/ROMEReleases/ROME0.5Beta/index.apt diff --git a/src/site/apt/ROMEReleases/ROME0.6Beta.apt b/rome/src/site/apt/ROMEReleases/ROME0.6Beta.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.6Beta.apt rename to rome/src/site/apt/ROMEReleases/ROME0.6Beta.apt diff --git a/src/site/apt/ROMEReleases/ROME0.7Beta.apt b/rome/src/site/apt/ROMEReleases/ROME0.7Beta.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.7Beta.apt rename to rome/src/site/apt/ROMEReleases/ROME0.7Beta.apt diff --git a/src/site/apt/ROMEReleases/ROME0.8Beta.apt b/rome/src/site/apt/ROMEReleases/ROME0.8Beta.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.8Beta.apt rename to rome/src/site/apt/ROMEReleases/ROME0.8Beta.apt diff --git a/src/site/apt/ROMEReleases/ROME0.9Beta.apt b/rome/src/site/apt/ROMEReleases/ROME0.9Beta.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME0.9Beta.apt rename to rome/src/site/apt/ROMEReleases/ROME0.9Beta.apt diff --git a/src/site/apt/ROMEReleases/ROME1.0RC1.apt b/rome/src/site/apt/ROMEReleases/ROME1.0RC1.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME1.0RC1.apt rename to rome/src/site/apt/ROMEReleases/ROME1.0RC1.apt diff --git a/src/site/apt/ROMEReleases/ROME1.0RC2.apt b/rome/src/site/apt/ROMEReleases/ROME1.0RC2.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME1.0RC2.apt rename to rome/src/site/apt/ROMEReleases/ROME1.0RC2.apt diff --git a/src/site/apt/ROMEReleases/ROME1.0Release.apt b/rome/src/site/apt/ROMEReleases/ROME1.0Release.apt similarity index 100% rename from src/site/apt/ROMEReleases/ROME1.0Release.apt rename to rome/src/site/apt/ROMEReleases/ROME1.0Release.apt diff --git a/src/site/apt/ROMEReleases/index.apt b/rome/src/site/apt/ROMEReleases/index.apt similarity index 100% rename from src/site/apt/ROMEReleases/index.apt rename to rome/src/site/apt/ROMEReleases/index.apt diff --git a/src/site/apt/RomeAPIFAQ.apt b/rome/src/site/apt/RomeAPIFAQ.apt similarity index 100% rename from src/site/apt/RomeAPIFAQ.apt rename to rome/src/site/apt/RomeAPIFAQ.apt diff --git a/src/site/apt/RomeV0.4FeedAndEntryURIMapping.apt b/rome/src/site/apt/RomeV0.4FeedAndEntryURIMapping.apt similarity index 100% rename from src/site/apt/RomeV0.4FeedAndEntryURIMapping.apt rename to rome/src/site/apt/RomeV0.4FeedAndEntryURIMapping.apt diff --git a/src/site/apt/RssAndAtOMUtiliEsROMEV0.7DateAndTimeParsing.apt b/rome/src/site/apt/RssAndAtOMUtiliEsROMEV0.7DateAndTimeParsing.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtiliEsROMEV0.7DateAndTimeParsing.apt rename to rome/src/site/apt/RssAndAtOMUtiliEsROMEV0.7DateAndTimeParsing.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/FeedAndEntryURIMappingHowSyndFeedAndSyndEntryUriPropertiesMapToRSSAndAtomElements.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/FeedAndEntryURIMappingHowSyndFeedAndSyndEntryUriPropertiesMapToRSSAndAtomElements.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/FeedAndEntryURIMappingHowSyndFeedAndSyndEntryUriPropertiesMapToRSSAndAtomElements.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/FeedAndEntryURIMappingHowSyndFeedAndSyndEntryUriPropertiesMapToRSSAndAtomElements.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/FeedsDateElementsMappingToSyndFeedAndSyndEntry.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/FeedsDateElementsMappingToSyndFeedAndSyndEntry.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/FeedsDateElementsMappingToSyndFeedAndSyndEntry.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/FeedsDateElementsMappingToSyndFeedAndSyndEntry.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEPluginsMechanism.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEPluginsMechanism.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEPluginsMechanism.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEPluginsMechanism.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5HowToBuildAndRunTheTutorialsSampleCode.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5HowToBuildAndRunTheTutorialsSampleCode.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5HowToBuildAndRunTheTutorialsSampleCode.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5HowToBuildAndRunTheTutorialsSampleCode.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialDefiningACustomModuleBeanParserAndGenerator.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialDefiningACustomModuleBeanParserAndGenerator.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialDefiningACustomModuleBeanParserAndGenerator.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialDefiningACustomModuleBeanParserAndGenerator.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToAggregateManySyndicationFeedsIntoASingleOne.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToAggregateManySyndicationFeedsIntoASingleOne.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToAggregateManySyndicationFeedsIntoASingleOne.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToAggregateManySyndicationFeedsIntoASingleOne.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToConvertASyndicationFeedFromOneTypeToAnother.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToConvertASyndicationFeedFromOneTypeToAnother.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToConvertASyndicationFeedFromOneTypeToAnother.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToConvertASyndicationFeedFromOneTypeToAnother.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToCreateAndWriteASyndicationFeed.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToCreateAndWriteASyndicationFeed.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToCreateAndWriteASyndicationFeed.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToCreateAndWriteASyndicationFeed.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToReadASyndicationFeed.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToReadASyndicationFeed.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToReadASyndicationFeed.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEToReadASyndicationFeed.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEWithinAServletToCreateAndReturnAFeed.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEWithinAServletToCreateAndReturnAFeed.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEWithinAServletToCreateAndReturnAFeed.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/RssAndAtOMUtilitiEsROMEV0.5TutorialUsingROMEWithinAServletToCreateAndReturnAFeed.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/TheCopyFromInterface.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/TheCopyFromInterface.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/TheCopyFromInterface.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/TheCopyFromInterface.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/UnderstandingRssAndAtOMUtilitiEsROMEBeanUtilities.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/UnderstandingRssAndAtOMUtilitiEsROMEBeanUtilities.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/UnderstandingRssAndAtOMUtilitiEsROMEBeanUtilities.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/UnderstandingRssAndAtOMUtilitiEsROMEBeanUtilities.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/XMLCharsetEncodingDetectionHowRssAndAtOMUtilitiEsROMEHelpsGettingTheRightCharsetEncoding.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/XMLCharsetEncodingDetectionHowRssAndAtOMUtilitiEsROMEHelpsGettingTheRightCharsetEncoding.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/XMLCharsetEncodingDetectionHowRssAndAtOMUtilitiEsROMEHelpsGettingTheRightCharsetEncoding.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/XMLCharsetEncodingDetectionHowRssAndAtOMUtilitiEsROMEHelpsGettingTheRightCharsetEncoding.apt diff --git a/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/index.apt b/rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/index.apt similarity index 100% rename from src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/index.apt rename to rome/src/site/apt/RssAndAtOMUtilitiEsROMEV0.5AndAboveTutorialsAndArticles/index.apt diff --git a/src/site/apt/SitesToMoveFromJava.net.apt b/rome/src/site/apt/SitesToMoveFromJava.net.apt similarity index 100% rename from src/site/apt/SitesToMoveFromJava.net.apt rename to rome/src/site/apt/SitesToMoveFromJava.net.apt diff --git a/src/site/apt/TutorialsAndArticles.apt b/rome/src/site/apt/TutorialsAndArticles.apt similarity index 100% rename from src/site/apt/TutorialsAndArticles.apt rename to rome/src/site/apt/TutorialsAndArticles.apt diff --git a/src/site/apt/WhatPartOfTheAPIYouShouldBeUsing.apt b/rome/src/site/apt/WhatPartOfTheAPIYouShouldBeUsing.apt similarity index 100% rename from src/site/apt/WhatPartOfTheAPIYouShouldBeUsing.apt rename to rome/src/site/apt/WhatPartOfTheAPIYouShouldBeUsing.apt diff --git a/src/site/apt/WhatSWrongWithOtherExistingRSSParsingLibraries.apt b/rome/src/site/apt/WhatSWrongWithOtherExistingRSSParsingLibraries.apt similarity index 100% rename from src/site/apt/WhatSWrongWithOtherExistingRSSParsingLibraries.apt rename to rome/src/site/apt/WhatSWrongWithOtherExistingRSSParsingLibraries.apt diff --git a/src/site/apt/WhyThisProject.apt b/rome/src/site/apt/WhyThisProject.apt similarity index 100% rename from src/site/apt/WhyThisProject.apt rename to rome/src/site/apt/WhyThisProject.apt diff --git a/src/site/apt/index.apt b/rome/src/site/apt/index.apt similarity index 100% rename from src/site/apt/index.apt rename to rome/src/site/apt/index.apt diff --git a/rome/src/site/resources/.nojekyll b/rome/src/site/resources/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/src/site/resources/HowRomeWorks/HowRomeWorks.png b/rome/src/site/resources/HowRomeWorks/HowRomeWorks.png similarity index 100% rename from src/site/resources/HowRomeWorks/HowRomeWorks.png rename to rome/src/site/resources/HowRomeWorks/HowRomeWorks.png diff --git a/src/site/resources/ROMEDevelopmentProposals/rome2proto.zip b/rome/src/site/resources/ROMEDevelopmentProposals/rome2proto.zip similarity index 100% rename from src/site/resources/ROMEDevelopmentProposals/rome2proto.zip rename to rome/src/site/resources/ROMEDevelopmentProposals/rome2proto.zip diff --git a/src/site/resources/ROMEDevelopmentProposals/rome2proto2.zip b/rome/src/site/resources/ROMEDevelopmentProposals/rome2proto2.zip similarity index 100% rename from src/site/resources/ROMEDevelopmentProposals/rome2proto2.zip rename to rome/src/site/resources/ROMEDevelopmentProposals/rome2proto2.zip diff --git a/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1-src.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1-src.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1-src.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1-src.zip b/rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1-src.zip rename to rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1-src.zip diff --git a/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1.zip b/rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1.zip rename to rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-0.1.zip diff --git a/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1-src.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1-src.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1-src.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1-src.zip b/rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1-src.zip rename to rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1-src.zip diff --git a/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1.zip b/rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1.zip rename to rome/src/site/resources/ROMEReleases/ROME0.1Beta/rome-samples-0.1.zip diff --git a/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2-src.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2-src.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2-src.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2-src.zip b/rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2-src.zip rename to rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2-src.zip diff --git a/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2.zip b/rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2.zip rename to rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-0.2.zip diff --git a/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2-src.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2-src.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2-src.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2-src.zip b/rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2-src.zip rename to rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2-src.zip diff --git a/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2.zip b/rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2.zip rename to rome/src/site/resources/ROMEReleases/ROME0.2Beta/rome-samples-0.2.zip diff --git a/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3-src.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3-src.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3-src.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3-src.zip b/rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3-src.zip rename to rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3-src.zip diff --git a/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3.zip b/rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3.zip rename to rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-0.3.zip diff --git a/src/site/resources/ROMEReleases/ROME0.3Beta/rome-samples-0.3-src.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-samples-0.3-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.3Beta/rome-samples-0.3-src.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-samples-0.3-src.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.3Beta/rome-samples-0.3-src.zip b/rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-samples-0.3-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.3Beta/rome-samples-0.3-src.zip rename to rome/src/site/resources/ROMEReleases/ROME0.3Beta/rome-samples-0.3-src.zip diff --git a/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4-src.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4-src.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4-src.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4-src.zip b/rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4-src.zip rename to rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4-src.zip diff --git a/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4.zip b/rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4.zip rename to rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-0.4.zip diff --git a/src/site/resources/ROMEReleases/ROME0.4Beta/rome-samples-0.4-src.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-samples-0.4-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.4Beta/rome-samples-0.4-src.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-samples-0.4-src.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.4Beta/rome-samples-0.4-src.zip b/rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-samples-0.4-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.4Beta/rome-samples-0.4-src.zip rename to rome/src/site/resources/ROMEReleases/ROME0.4Beta/rome-samples-0.4-src.zip diff --git a/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5-src.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5-src.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5-src.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5-src.zip b/rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5-src.zip rename to rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5-src.zip diff --git a/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5.zip b/rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5.zip rename to rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-0.5.zip diff --git a/src/site/resources/ROMEReleases/ROME0.5Beta/rome-samples-0.5-src.tar.gz b/rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-samples-0.5-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.5Beta/rome-samples-0.5-src.tar.gz rename to rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-samples-0.5-src.tar.gz diff --git a/src/site/resources/ROMEReleases/ROME0.5Beta/rome-samples-0.5-src.zip b/rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-samples-0.5-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/ROME0.5Beta/rome-samples-0.5-src.zip rename to rome/src/site/resources/ROMEReleases/ROME0.5Beta/rome-samples-0.5-src.zip diff --git a/src/site/resources/ROMEReleases/rome-0.6-src.tar.gz b/rome/src/site/resources/ROMEReleases/rome-0.6-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.6-src.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-0.6-src.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-0.6-src.zip b/rome/src/site/resources/ROMEReleases/rome-0.6-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.6-src.zip rename to rome/src/site/resources/ROMEReleases/rome-0.6-src.zip diff --git a/src/site/resources/ROMEReleases/rome-0.6.tar.gz b/rome/src/site/resources/ROMEReleases/rome-0.6.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.6.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-0.6.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-0.6.zip b/rome/src/site/resources/ROMEReleases/rome-0.6.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.6.zip rename to rome/src/site/resources/ROMEReleases/rome-0.6.zip diff --git a/src/site/resources/ROMEReleases/rome-0.7-src.tar.gz b/rome/src/site/resources/ROMEReleases/rome-0.7-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.7-src.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-0.7-src.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-0.7-src.zip b/rome/src/site/resources/ROMEReleases/rome-0.7-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.7-src.zip rename to rome/src/site/resources/ROMEReleases/rome-0.7-src.zip diff --git a/src/site/resources/ROMEReleases/rome-0.7.tar.gz b/rome/src/site/resources/ROMEReleases/rome-0.7.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.7.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-0.7.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-0.7.zip b/rome/src/site/resources/ROMEReleases/rome-0.7.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.7.zip rename to rome/src/site/resources/ROMEReleases/rome-0.7.zip diff --git a/src/site/resources/ROMEReleases/rome-0.8-src.tar.gz b/rome/src/site/resources/ROMEReleases/rome-0.8-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.8-src.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-0.8-src.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-0.8-src.zip b/rome/src/site/resources/ROMEReleases/rome-0.8-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.8-src.zip rename to rome/src/site/resources/ROMEReleases/rome-0.8-src.zip diff --git a/src/site/resources/ROMEReleases/rome-0.8.tar.gz b/rome/src/site/resources/ROMEReleases/rome-0.8.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.8.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-0.8.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-0.8.zip b/rome/src/site/resources/ROMEReleases/rome-0.8.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.8.zip rename to rome/src/site/resources/ROMEReleases/rome-0.8.zip diff --git a/src/site/resources/ROMEReleases/rome-0.9-src.tar.gz b/rome/src/site/resources/ROMEReleases/rome-0.9-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.9-src.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-0.9-src.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-0.9-src.zip b/rome/src/site/resources/ROMEReleases/rome-0.9-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.9-src.zip rename to rome/src/site/resources/ROMEReleases/rome-0.9-src.zip diff --git a/src/site/resources/ROMEReleases/rome-0.9.tar.gz b/rome/src/site/resources/ROMEReleases/rome-0.9.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.9.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-0.9.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-0.9.zip b/rome/src/site/resources/ROMEReleases/rome-0.9.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-0.9.zip rename to rome/src/site/resources/ROMEReleases/rome-0.9.zip diff --git a/src/site/resources/ROMEReleases/rome-1.0-javadoc.jar b/rome/src/site/resources/ROMEReleases/rome-1.0-javadoc.jar similarity index 100% rename from src/site/resources/ROMEReleases/rome-1.0-javadoc.jar rename to rome/src/site/resources/ROMEReleases/rome-1.0-javadoc.jar diff --git a/src/site/resources/ROMEReleases/rome-1.0-sources.jar b/rome/src/site/resources/ROMEReleases/rome-1.0-sources.jar similarity index 100% rename from src/site/resources/ROMEReleases/rome-1.0-sources.jar rename to rome/src/site/resources/ROMEReleases/rome-1.0-sources.jar diff --git a/src/site/resources/ROMEReleases/rome-1.0.jar b/rome/src/site/resources/ROMEReleases/rome-1.0.jar similarity index 100% rename from src/site/resources/ROMEReleases/rome-1.0.jar rename to rome/src/site/resources/ROMEReleases/rome-1.0.jar diff --git a/src/site/resources/ROMEReleases/rome-1.0RC1-src.tar.gz b/rome/src/site/resources/ROMEReleases/rome-1.0RC1-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-1.0RC1-src.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-1.0RC1-src.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-1.0RC1-src.zip b/rome/src/site/resources/ROMEReleases/rome-1.0RC1-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-1.0RC1-src.zip rename to rome/src/site/resources/ROMEReleases/rome-1.0RC1-src.zip diff --git a/src/site/resources/ROMEReleases/rome-1.0RC1.tar.gz b/rome/src/site/resources/ROMEReleases/rome-1.0RC1.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-1.0RC1.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-1.0RC1.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-1.0RC1.zip b/rome/src/site/resources/ROMEReleases/rome-1.0RC1.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-1.0RC1.zip rename to rome/src/site/resources/ROMEReleases/rome-1.0RC1.zip diff --git a/src/site/resources/ROMEReleases/rome-1.0RC2-javadoc.jar b/rome/src/site/resources/ROMEReleases/rome-1.0RC2-javadoc.jar similarity index 100% rename from src/site/resources/ROMEReleases/rome-1.0RC2-javadoc.jar rename to rome/src/site/resources/ROMEReleases/rome-1.0RC2-javadoc.jar diff --git a/src/site/resources/ROMEReleases/rome-1.0RC2-sources.jar b/rome/src/site/resources/ROMEReleases/rome-1.0RC2-sources.jar similarity index 100% rename from src/site/resources/ROMEReleases/rome-1.0RC2-sources.jar rename to rome/src/site/resources/ROMEReleases/rome-1.0RC2-sources.jar diff --git a/src/site/resources/ROMEReleases/rome-1.0RC2.jar b/rome/src/site/resources/ROMEReleases/rome-1.0RC2.jar similarity index 100% rename from src/site/resources/ROMEReleases/rome-1.0RC2.jar rename to rome/src/site/resources/ROMEReleases/rome-1.0RC2.jar diff --git a/rome/src/site/resources/ROMEReleases/rome-fetcher-1.0RC2-src.zip b/rome/src/site/resources/ROMEReleases/rome-fetcher-1.0RC2-src.zip new file mode 100644 index 0000000..d2ac106 Binary files /dev/null and b/rome/src/site/resources/ROMEReleases/rome-fetcher-1.0RC2-src.zip differ diff --git a/src/site/resources/ROMEReleases/rome-samples-0.6-src.tar.gz b/rome/src/site/resources/ROMEReleases/rome-samples-0.6-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-samples-0.6-src.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-samples-0.6-src.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-samples-0.6-src.zip b/rome/src/site/resources/ROMEReleases/rome-samples-0.6-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-samples-0.6-src.zip rename to rome/src/site/resources/ROMEReleases/rome-samples-0.6-src.zip diff --git a/src/site/resources/ROMEReleases/rome-samples-0.7-src.tar.gz b/rome/src/site/resources/ROMEReleases/rome-samples-0.7-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-samples-0.7-src.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-samples-0.7-src.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-samples-0.7-src.zip b/rome/src/site/resources/ROMEReleases/rome-samples-0.7-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-samples-0.7-src.zip rename to rome/src/site/resources/ROMEReleases/rome-samples-0.7-src.zip diff --git a/src/site/resources/ROMEReleases/rome-samples-0.9-src.tar.gz b/rome/src/site/resources/ROMEReleases/rome-samples-0.9-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-samples-0.9-src.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-samples-0.9-src.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-samples-0.9-src.zip b/rome/src/site/resources/ROMEReleases/rome-samples-0.9-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-samples-0.9-src.zip rename to rome/src/site/resources/ROMEReleases/rome-samples-0.9-src.zip diff --git a/src/site/resources/ROMEReleases/rome-samples-0.9.tar.gz b/rome/src/site/resources/ROMEReleases/rome-samples-0.9.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-samples-0.9.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-samples-0.9.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-samples-0.9.zip b/rome/src/site/resources/ROMEReleases/rome-samples-0.9.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-samples-0.9.zip rename to rome/src/site/resources/ROMEReleases/rome-samples-0.9.zip diff --git a/src/site/resources/ROMEReleases/rome-samples-1.0RC1-src.tar.gz b/rome/src/site/resources/ROMEReleases/rome-samples-1.0RC1-src.tar.gz similarity index 100% rename from src/site/resources/ROMEReleases/rome-samples-1.0RC1-src.tar.gz rename to rome/src/site/resources/ROMEReleases/rome-samples-1.0RC1-src.tar.gz diff --git a/src/site/resources/ROMEReleases/rome-samples-1.0RC1-src.zip b/rome/src/site/resources/ROMEReleases/rome-samples-1.0RC1-src.zip similarity index 100% rename from src/site/resources/ROMEReleases/rome-samples-1.0RC1-src.zip rename to rome/src/site/resources/ROMEReleases/rome-samples-1.0RC1-src.zip diff --git a/rome/src/site/resources/css/site.css b/rome/src/site/resources/css/site.css new file mode 100644 index 0000000..43c3cd8 --- /dev/null +++ b/rome/src/site/resources/css/site.css @@ -0,0 +1,8 @@ +h1 { + padding: 4px 4px 4px 6px; + border: 1px solid #999; + color: #900; + background-color: #ddd; + font-weight:900; + font-size: x-large; +} \ No newline at end of file diff --git a/rome/src/site/resources/images/romelogo.png b/rome/src/site/resources/images/romelogo.png new file mode 100644 index 0000000..2c90608 Binary files /dev/null and b/rome/src/site/resources/images/romelogo.png differ diff --git a/rome/src/site/resources/romelogo.png b/rome/src/site/resources/romelogo.png new file mode 100644 index 0000000..2c90608 Binary files /dev/null and b/rome/src/site/resources/romelogo.png differ diff --git a/src/site/site.xml b/rome/src/site/site.xml similarity index 100% rename from src/site/site.xml rename to rome/src/site/site.xml diff --git a/src/test/data/atom_0.3.xml b/rome/src/test/data/atom_0.3.xml similarity index 100% rename from src/test/data/atom_0.3.xml rename to rome/src/test/data/atom_0.3.xml diff --git a/src/test/data/atom_0.3_DC_Sy.xml b/rome/src/test/data/atom_0.3_DC_Sy.xml similarity index 100% rename from src/test/data/atom_0.3_DC_Sy.xml rename to rome/src/test/data/atom_0.3_DC_Sy.xml diff --git a/src/test/resources/atom_1.0.xml b/rome/src/test/data/atom_1.0.xml similarity index 100% rename from src/test/resources/atom_1.0.xml rename to rome/src/test/data/atom_1.0.xml diff --git a/src/test/data/atom_1.0_b.xml b/rome/src/test/data/atom_1.0_b.xml similarity index 100% rename from src/test/data/atom_1.0_b.xml rename to rome/src/test/data/atom_1.0_b.xml diff --git a/src/test/data/atom_1.0_bray.xml b/rome/src/test/data/atom_1.0_bray.xml similarity index 100% rename from src/test/data/atom_1.0_bray.xml rename to rome/src/test/data/atom_1.0_bray.xml diff --git a/src/test/data/atom_1.0_prefix.xml b/rome/src/test/data/atom_1.0_prefix.xml similarity index 100% rename from src/test/data/atom_1.0_prefix.xml rename to rome/src/test/data/atom_1.0_prefix.xml diff --git a/src/test/data/atom_1.0_ruby.xml b/rome/src/test/data/atom_1.0_ruby.xml similarity index 100% rename from src/test/data/atom_1.0_ruby.xml rename to rome/src/test/data/atom_1.0_ruby.xml diff --git a/src/test/data/rss_0.9.xml b/rome/src/test/data/rss_0.9.xml similarity index 100% rename from src/test/data/rss_0.9.xml rename to rome/src/test/data/rss_0.9.xml diff --git a/src/test/data/rss_0.91N.xml b/rome/src/test/data/rss_0.91N.xml similarity index 100% rename from src/test/data/rss_0.91N.xml rename to rome/src/test/data/rss_0.91N.xml diff --git a/src/test/data/rss_0.91U.xml b/rome/src/test/data/rss_0.91U.xml similarity index 100% rename from src/test/data/rss_0.91U.xml rename to rome/src/test/data/rss_0.91U.xml diff --git a/src/test/data/rss_0.92.xml b/rome/src/test/data/rss_0.92.xml similarity index 100% rename from src/test/data/rss_0.92.xml rename to rome/src/test/data/rss_0.92.xml diff --git a/src/test/data/rss_0.92_alt.xml b/rome/src/test/data/rss_0.92_alt.xml similarity index 100% rename from src/test/data/rss_0.92_alt.xml rename to rome/src/test/data/rss_0.92_alt.xml diff --git a/src/test/data/rss_0.93.xml b/rome/src/test/data/rss_0.93.xml similarity index 100% rename from src/test/data/rss_0.93.xml rename to rome/src/test/data/rss_0.93.xml diff --git a/src/test/data/rss_0.94.xml b/rome/src/test/data/rss_0.94.xml similarity index 100% rename from src/test/data/rss_0.94.xml rename to rome/src/test/data/rss_0.94.xml diff --git a/src/test/data/rss_1.0.xml b/rome/src/test/data/rss_1.0.xml similarity index 100% rename from src/test/data/rss_1.0.xml rename to rome/src/test/data/rss_1.0.xml diff --git a/src/test/data/rss_1.0_DC_Sy.xml b/rome/src/test/data/rss_1.0_DC_Sy.xml similarity index 100% rename from src/test/data/rss_1.0_DC_Sy.xml rename to rome/src/test/data/rss_1.0_DC_Sy.xml diff --git a/src/test/data/rss_1.0_DC_multi.xml b/rome/src/test/data/rss_1.0_DC_multi.xml similarity index 100% rename from src/test/data/rss_1.0_DC_multi.xml rename to rome/src/test/data/rss_1.0_DC_multi.xml diff --git a/src/test/data/rss_2.0.xml b/rome/src/test/data/rss_2.0.xml similarity index 100% rename from src/test/data/rss_2.0.xml rename to rome/src/test/data/rss_2.0.xml diff --git a/src/test/java/com/rometools/rome/io/XmlReaderTest.java b/rome/src/test/java/com/rometools/rome/io/XmlReaderTest.java similarity index 100% rename from src/test/java/com/rometools/rome/io/XmlReaderTest.java rename to rome/src/test/java/com/rometools/rome/io/XmlReaderTest.java diff --git a/src/test/java/com/rometools/rome/io/impl/RSS20ParserTest.java b/rome/src/test/java/com/rometools/rome/io/impl/RSS20ParserTest.java similarity index 100% rename from src/test/java/com/rometools/rome/io/impl/RSS20ParserTest.java rename to rome/src/test/java/com/rometools/rome/io/impl/RSS20ParserTest.java diff --git a/src/test/java/com/rometools/rome/unittest/FeedOpsTest.java b/rome/src/test/java/com/rometools/rome/unittest/FeedOpsTest.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/FeedOpsTest.java rename to rome/src/test/java/com/rometools/rome/unittest/FeedOpsTest.java diff --git a/src/test/java/com/rometools/rome/unittest/FeedTest.java b/rome/src/test/java/com/rometools/rome/unittest/FeedTest.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/FeedTest.java rename to rome/src/test/java/com/rometools/rome/unittest/FeedTest.java diff --git a/src/test/java/com/rometools/rome/unittest/SyndFeedTest.java b/rome/src/test/java/com/rometools/rome/unittest/SyndFeedTest.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/SyndFeedTest.java rename to rome/src/test/java/com/rometools/rome/unittest/SyndFeedTest.java diff --git a/src/test/java/com/rometools/rome/unittest/TestAtomContent.java b/rome/src/test/java/com/rometools/rome/unittest/TestAtomContent.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestAtomContent.java rename to rome/src/test/java/com/rometools/rome/unittest/TestAtomContent.java diff --git a/src/test/java/com/rometools/rome/unittest/TestBase64.java b/rome/src/test/java/com/rometools/rome/unittest/TestBase64.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestBase64.java rename to rome/src/test/java/com/rometools/rome/unittest/TestBase64.java diff --git a/src/test/java/com/rometools/rome/unittest/TestDateParser.java b/rome/src/test/java/com/rometools/rome/unittest/TestDateParser.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestDateParser.java rename to rome/src/test/java/com/rometools/rome/unittest/TestDateParser.java diff --git a/src/test/java/com/rometools/rome/unittest/TestDublinCore.java b/rome/src/test/java/com/rometools/rome/unittest/TestDublinCore.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestDublinCore.java rename to rome/src/test/java/com/rometools/rome/unittest/TestDublinCore.java diff --git a/src/test/java/com/rometools/rome/unittest/TestEqualsBean.java b/rome/src/test/java/com/rometools/rome/unittest/TestEqualsBean.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestEqualsBean.java rename to rome/src/test/java/com/rometools/rome/unittest/TestEqualsBean.java diff --git a/src/test/java/com/rometools/rome/unittest/TestOpsAtom03.java b/rome/src/test/java/com/rometools/rome/unittest/TestOpsAtom03.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestOpsAtom03.java rename to rome/src/test/java/com/rometools/rome/unittest/TestOpsAtom03.java diff --git a/src/test/java/com/rometools/rome/unittest/TestOpsAtom10.java b/rome/src/test/java/com/rometools/rome/unittest/TestOpsAtom10.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestOpsAtom10.java rename to rome/src/test/java/com/rometools/rome/unittest/TestOpsAtom10.java diff --git a/src/test/java/com/rometools/rome/unittest/TestOpsRSS090.java b/rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS090.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestOpsRSS090.java rename to rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS090.java diff --git a/src/test/java/com/rometools/rome/unittest/TestOpsRSS091N.java b/rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS091N.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestOpsRSS091N.java rename to rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS091N.java diff --git a/src/test/java/com/rometools/rome/unittest/TestOpsRSS091U.java b/rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS091U.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestOpsRSS091U.java rename to rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS091U.java diff --git a/src/test/java/com/rometools/rome/unittest/TestOpsRSS092.java b/rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS092.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestOpsRSS092.java rename to rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS092.java diff --git a/src/test/java/com/rometools/rome/unittest/TestOpsRSS093.java b/rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS093.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestOpsRSS093.java rename to rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS093.java diff --git a/src/test/java/com/rometools/rome/unittest/TestOpsRSS094.java b/rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS094.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestOpsRSS094.java rename to rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS094.java diff --git a/src/test/java/com/rometools/rome/unittest/TestOpsRSS10.java b/rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS10.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestOpsRSS10.java rename to rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS10.java diff --git a/src/test/java/com/rometools/rome/unittest/TestOpsRSS20.java b/rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS20.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestOpsRSS20.java rename to rome/src/test/java/com/rometools/rome/unittest/TestOpsRSS20.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom03.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom03.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom03.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom03.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom03DCSyModules.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom03DCSyModules.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom03DCSyModules.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom03DCSyModules.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10Bray.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10Bray.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10Bray.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10Bray.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10Ruby.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10Ruby.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10Ruby.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10Ruby.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10b.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10b.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10b.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10b.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10prefix.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10prefix.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10prefix.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedAtom10prefix.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS090.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS090.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS090.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS090.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS091N.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS091N.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS091N.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS091N.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS091U.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS091U.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS091U.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS091U.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS092.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS092.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS092.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS092.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS092Alt.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS092Alt.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS092Alt.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS092Alt.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS093.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS093.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS093.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS093.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS094.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS094.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS094.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS094.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10DCMulti.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10DCMulti.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10DCMulti.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10DCMulti.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10DCSyModules.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10DCSyModules.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10DCSyModules.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS10DCSyModules.java diff --git a/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS20.java b/rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS20.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS20.java rename to rome/src/test/java/com/rometools/rome/unittest/TestSyndFeedRSS20.java diff --git a/src/test/java/com/rometools/rome/unittest/TestXmlBomb.java b/rome/src/test/java/com/rometools/rome/unittest/TestXmlBomb.java similarity index 97% rename from src/test/java/com/rometools/rome/unittest/TestXmlBomb.java rename to rome/src/test/java/com/rometools/rome/unittest/TestXmlBomb.java index ce15c1e..a6123ec 100644 --- a/src/test/java/com/rometools/rome/unittest/TestXmlBomb.java +++ b/rome/src/test/java/com/rometools/rome/unittest/TestXmlBomb.java @@ -1,54 +1,54 @@ -package com.rometools.rome.unittest; - - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.Charset; - -import com.rometools.rome.io.ParsingFeedException; -import com.rometools.rome.io.WireFeedInput; -import junit.framework.TestCase; - -public class TestXmlBomb extends TestCase { - - public void testXmlBomb() throws Exception { - - // https://en.wikipedia.org/wiki/Billion_laughs - // https://msdn.microsoft.com/en-us/magazine/ee335713.aspx - String content = "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "]>\n" + - "\n" + - " &lol9;\n" + - " subtitle\n" + - " \n" + - " id1\n" + - " title1\n" + - " \n" + - ""; - - InputStream is = new ByteArrayInputStream(content.getBytes("UTF-8")); - WireFeedInput feedInput = new WireFeedInput(); - Reader reader = new InputStreamReader(is, Charset.forName("UTF-8")); - try { - feedInput.build(reader); - fail("Expected exception"); - } - catch (ParsingFeedException ex) { - } - } - +package com.rometools.rome.unittest; + + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +import com.rometools.rome.io.ParsingFeedException; +import com.rometools.rome.io.WireFeedInput; +import junit.framework.TestCase; + +public class TestXmlBomb extends TestCase { + + public void testXmlBomb() throws Exception { + + // https://en.wikipedia.org/wiki/Billion_laughs + // https://msdn.microsoft.com/en-us/magazine/ee335713.aspx + String content = "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "]>\n" + + "\n" + + " &lol9;\n" + + " subtitle\n" + + " \n" + + " id1\n" + + " title1\n" + + " \n" + + ""; + + InputStream is = new ByteArrayInputStream(content.getBytes("UTF-8")); + WireFeedInput feedInput = new WireFeedInput(); + Reader reader = new InputStreamReader(is, Charset.forName("UTF-8")); + try { + feedInput.build(reader); + fail("Expected exception"); + } + catch (ParsingFeedException ex) { + } + } + } \ No newline at end of file diff --git a/src/test/java/com/rometools/rome/unittest/TestXmlFixerReader.java b/rome/src/test/java/com/rometools/rome/unittest/TestXmlFixerReader.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/TestXmlFixerReader.java rename to rome/src/test/java/com/rometools/rome/unittest/TestXmlFixerReader.java diff --git a/src/test/java/com/rometools/rome/unittest/issues/Issue131Test.java b/rome/src/test/java/com/rometools/rome/unittest/issues/Issue131Test.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/issues/Issue131Test.java rename to rome/src/test/java/com/rometools/rome/unittest/issues/Issue131Test.java diff --git a/src/test/java/com/rometools/rome/unittest/issues/Issue134Test.java b/rome/src/test/java/com/rometools/rome/unittest/issues/Issue134Test.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/issues/Issue134Test.java rename to rome/src/test/java/com/rometools/rome/unittest/issues/Issue134Test.java diff --git a/src/test/java/com/rometools/rome/unittest/issues/Issue137Test.java b/rome/src/test/java/com/rometools/rome/unittest/issues/Issue137Test.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/issues/Issue137Test.java rename to rome/src/test/java/com/rometools/rome/unittest/issues/Issue137Test.java diff --git a/src/test/java/com/rometools/rome/unittest/issues/Issue158Test.java b/rome/src/test/java/com/rometools/rome/unittest/issues/Issue158Test.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/issues/Issue158Test.java rename to rome/src/test/java/com/rometools/rome/unittest/issues/Issue158Test.java diff --git a/src/test/java/com/rometools/rome/unittest/issues/Issue161Test.java b/rome/src/test/java/com/rometools/rome/unittest/issues/Issue161Test.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/issues/Issue161Test.java rename to rome/src/test/java/com/rometools/rome/unittest/issues/Issue161Test.java diff --git a/src/test/java/com/rometools/rome/unittest/issues/Issue162Test.java b/rome/src/test/java/com/rometools/rome/unittest/issues/Issue162Test.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/issues/Issue162Test.java rename to rome/src/test/java/com/rometools/rome/unittest/issues/Issue162Test.java diff --git a/src/test/java/com/rometools/rome/unittest/issues/Issue1Test.java b/rome/src/test/java/com/rometools/rome/unittest/issues/Issue1Test.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/issues/Issue1Test.java rename to rome/src/test/java/com/rometools/rome/unittest/issues/Issue1Test.java diff --git a/src/test/java/com/rometools/rome/unittest/issues/Issue2Test.java b/rome/src/test/java/com/rometools/rome/unittest/issues/Issue2Test.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/issues/Issue2Test.java rename to rome/src/test/java/com/rometools/rome/unittest/issues/Issue2Test.java diff --git a/src/test/java/com/rometools/rome/unittest/issues/Issue88Test.java b/rome/src/test/java/com/rometools/rome/unittest/issues/Issue88Test.java similarity index 100% rename from src/test/java/com/rometools/rome/unittest/issues/Issue88Test.java rename to rome/src/test/java/com/rometools/rome/unittest/issues/Issue88Test.java diff --git a/src/test/resources/CDATATestFeed.xml b/rome/src/test/resources/CDATATestFeed.xml similarity index 100% rename from src/test/resources/CDATATestFeed.xml rename to rome/src/test/resources/CDATATestFeed.xml diff --git a/src/test/resources/atom_0.3.xml b/rome/src/test/resources/atom_0.3.xml similarity index 100% rename from src/test/resources/atom_0.3.xml rename to rome/src/test/resources/atom_0.3.xml diff --git a/src/test/resources/atom_0.3_DC_Sy.xml b/rome/src/test/resources/atom_0.3_DC_Sy.xml similarity index 100% rename from src/test/resources/atom_0.3_DC_Sy.xml rename to rome/src/test/resources/atom_0.3_DC_Sy.xml diff --git a/rome/src/test/resources/atom_1.0.xml b/rome/src/test/resources/atom_1.0.xml new file mode 100644 index 0000000..9d83939 --- /dev/null +++ b/rome/src/test/resources/atom_1.0.xml @@ -0,0 +1,78 @@ + + + atom_1.0.feed.title + + + + rometest + + atom_1.0.feed.author.name + http://example.com + author0@example.com + + + atom_1.0.feed.contributor.name + http://example.com + author1@example.com + + atom_1.0.feed.tagline + http://example.com/blog/atom_1.0.xml + atom_1.0.feed.generator +atom_1.0.feed.copyright + 2000-01-01T00:00:00Z + + atom_1.0.feed.entry[0].title + + + + + http://example.com/blog/entry1 + + atom_1.0.feed.entry[0].author.name + http://example.com + author0@example.com + + + atom_1.0.feed.entry[0].contributor.name + http://example.com + author1@example.com + + 2000-01-01T00:00:00Z + 2000-01-01T01:00:00Z +

      atom_1.0.feed.entry[0].summary + atom_1.0.feed.entry[0].content[0] + rometest + atom_1.0.feed.entry[0].rights + + + atom_1.0.feed.entry[1].title + + + + http://example.com/blog/entry2 + + atom_1.0.feed.entry[1].author.name + http://example.com + author0@example.com + + + atom_1.0.feed.entry[1].contributor.name + http://example.com + author1@example.com + + 2000-02-01T00:00:00Z + 2000-02-01T01:00:00Z + atom_1.0.feed.entry[1].summary + atom_1.0.feed.entry[1].content[0] + rometest + + diff --git a/src/test/resources/atom_1.0_b.xml b/rome/src/test/resources/atom_1.0_b.xml similarity index 100% rename from src/test/resources/atom_1.0_b.xml rename to rome/src/test/resources/atom_1.0_b.xml diff --git a/src/test/resources/atom_1.0_bray.xml b/rome/src/test/resources/atom_1.0_bray.xml similarity index 100% rename from src/test/resources/atom_1.0_bray.xml rename to rome/src/test/resources/atom_1.0_bray.xml diff --git a/src/test/resources/atom_1.0_prefix.xml b/rome/src/test/resources/atom_1.0_prefix.xml similarity index 100% rename from src/test/resources/atom_1.0_prefix.xml rename to rome/src/test/resources/atom_1.0_prefix.xml diff --git a/src/test/resources/atom_1.0_ruby.xml b/rome/src/test/resources/atom_1.0_ruby.xml similarity index 100% rename from src/test/resources/atom_1.0_ruby.xml rename to rome/src/test/resources/atom_1.0_ruby.xml diff --git a/src/test/resources/dublinCoreTest.xml b/rome/src/test/resources/dublinCoreTest.xml similarity index 100% rename from src/test/resources/dublinCoreTest.xml rename to rome/src/test/resources/dublinCoreTest.xml diff --git a/src/test/resources/issue131-rss.xml b/rome/src/test/resources/issue131-rss.xml similarity index 100% rename from src/test/resources/issue131-rss.xml rename to rome/src/test/resources/issue131-rss.xml diff --git a/src/test/resources/issue137-rss.xml b/rome/src/test/resources/issue137-rss.xml similarity index 98% rename from src/test/resources/issue137-rss.xml rename to rome/src/test/resources/issue137-rss.xml index a4b541b..eb4dff2 100644 --- a/src/test/resources/issue137-rss.xml +++ b/rome/src/test/resources/issue137-rss.xml @@ -1,80 +1,80 @@ - - - - Spotlight - http://www.moe.gov.sg/media/spotlight/ - - en - Copyright 2009 - Fri, 25 Sep 2009 10:00:00 +0800 - http://www.rssboard.org/rss-specification - - - Single-Session Primary Schools - Teacher and his students tossing frisbees into the airMOE will be building 11 new primary - schools and upgrading another 28 existing schools from November 2009. This is the first phase of - MOE's plans to enhance primary school infrastructure to facilitate the transition of all primary schools - to a single-session model to support a higher quality primary education.

      ]]>
      - http://feedproxy.google.com/~r/singapore-education/spotlight/~3/vnNsA4Hdk6U/ - http://www.moe.gov.sg/media/spotlight/ - - - Fri, 25 Sep 2009 10:00:00 +0800 - http://www.moe.gov.sg/media/spotlight/
      - - - Work Plan Seminar 2009 - ]]>At the Work Plan Seminar 2009, Minister for Education - Dr Ng Eng Hen talked - about the importance of language & communication skills and growing a world-class education service -. He spoke of strengthening the teaching track and of a teacher-driven culture of professional excellence.

      ]]>
      - http://feedproxy.google.com/~r/singapore-education/spotlight/~3/vnNsA4Hdk6U/ - http://www.moe.gov.sg/media/spotlight/ - - - Thu, 17 Sep 2009 15:33:15 +0800 - http://www.moe.gov.sg/media/spotlight/
      - - - Recognising School Achievements in 2009 - <img src="http://www.moe.gov.sg/media/spotlight/assets_c/2009/09/spotlight-moa-2009-thumb-120x80-278.jpg" alt="Students at a podcast session" /> - A total of 275 schools will receive 580 Special and Level - Two Awards this year under the MOE Masterplan of Awards. These awards will be presented at the 2009 - MOE Work Plan Seminar on 17 Sep 09 by the Minister for Education, Dr Ng Eng Hen.

      ]]>
      - http://feedproxy.google.com/~r/singapore-education/spotlight/~3/vnNsA4Hdk6U/ - http://www.moe.gov.sg/media/spotlight/ - - - Thu, 10 Sep 2009 17:00:00 +0800 - http://www.moe.gov.sg/media/spotlight/
      - - - New Programmes in Special Assistance Plan (SAP) Schools - Students engaged in discussionAt the Special Assistance Plan (SAP) Seminar - 2009 on 4 Sep 09, Ms Grace Fu, -Senior Minister of State for Education, shared on the new initiatives -rolled out in SAP schools.

      ]]>
      - http://feedproxy.google.com/~r/singapore-education/spotlight/~3/vnNsA4Hdk6U/ - http://www.moe.gov.sg/media/spotlight/ - - - Fri, 04 Sep 2009 09:30:00 +0800 - http://www.moe.gov.sg/media/spotlight/
      - -
      -
      + + + + Spotlight + http://www.moe.gov.sg/media/spotlight/ + + en + Copyright 2009 + Fri, 25 Sep 2009 10:00:00 +0800 + http://www.rssboard.org/rss-specification + + + Single-Session Primary Schools + Teacher and his students tossing frisbees into the airMOE will be building 11 new primary + schools and upgrading another 28 existing schools from November 2009. This is the first phase of + MOE's plans to enhance primary school infrastructure to facilitate the transition of all primary schools + to a single-session model to support a higher quality primary education.

      ]]>
      + http://feedproxy.google.com/~r/singapore-education/spotlight/~3/vnNsA4Hdk6U/ + http://www.moe.gov.sg/media/spotlight/ + + + Fri, 25 Sep 2009 10:00:00 +0800 + http://www.moe.gov.sg/media/spotlight/
      + + + Work Plan Seminar 2009 + ]]>At the Work Plan Seminar 2009, Minister for Education + Dr Ng Eng Hen talked + about the importance of language & communication skills and growing a world-class education service +. He spoke of strengthening the teaching track and of a teacher-driven culture of professional excellence.

      ]]>
      + http://feedproxy.google.com/~r/singapore-education/spotlight/~3/vnNsA4Hdk6U/ + http://www.moe.gov.sg/media/spotlight/ + + + Thu, 17 Sep 2009 15:33:15 +0800 + http://www.moe.gov.sg/media/spotlight/
      + + + Recognising School Achievements in 2009 + <img src="http://www.moe.gov.sg/media/spotlight/assets_c/2009/09/spotlight-moa-2009-thumb-120x80-278.jpg" alt="Students at a podcast session" /> + A total of 275 schools will receive 580 Special and Level + Two Awards this year under the MOE Masterplan of Awards. These awards will be presented at the 2009 + MOE Work Plan Seminar on 17 Sep 09 by the Minister for Education, Dr Ng Eng Hen.

      ]]>
      + http://feedproxy.google.com/~r/singapore-education/spotlight/~3/vnNsA4Hdk6U/ + http://www.moe.gov.sg/media/spotlight/ + + + Thu, 10 Sep 2009 17:00:00 +0800 + http://www.moe.gov.sg/media/spotlight/
      + + + New Programmes in Special Assistance Plan (SAP) Schools + Students engaged in discussionAt the Special Assistance Plan (SAP) Seminar + 2009 on 4 Sep 09, Ms Grace Fu, +Senior Minister of State for Education, shared on the new initiatives +rolled out in SAP schools.

      ]]>
      + http://feedproxy.google.com/~r/singapore-education/spotlight/~3/vnNsA4Hdk6U/ + http://www.moe.gov.sg/media/spotlight/ + + + Fri, 04 Sep 2009 09:30:00 +0800 + http://www.moe.gov.sg/media/spotlight/
      + +
      +
      diff --git a/src/test/resources/jira_issue1.xml b/rome/src/test/resources/jira_issue1.xml similarity index 97% rename from src/test/resources/jira_issue1.xml rename to rome/src/test/resources/jira_issue1.xml index 30856ca..86e003d 100644 --- a/src/test/resources/jira_issue1.xml +++ b/rome/src/test/resources/jira_issue1.xml @@ -1,118 +1,118 @@ - - - - - test - rss_2.0.channel.title - rss_2.0.channel.link - rss_2.0.channel.description - rss_2.0.channel.language - rss_2.0.channel.rating - rss_2.0.channel.copyright - Mon, 01 Jan 2001 00:00:00 GMT - - Mon, 01 Jan 2001 01:00:00 GMT - rss_2.0.channel.docs - rss_2.0.channel.managingEditor - rss_2.0.channel.webMaster - rss_2.0.channel.category[0] - rss_2.0.channel.category[1] - rss_2.0.channel.generator - 100 - - - rss_2.0.channel.image.title - rss_2.0.channel.image.url - rss_2.0.channel.image.link - 100 - 200 - rss_2.0.channel.image.description - - - - rss_2.0.channel.item[0].title - rss_2.0.channel.item[0].description - rss_2.0.channel.item[0].link - rss_2.0.channel.item[0].source - - - rss_2.0.channel.item[0].category[0] - rss_2.0.channel.item[0].category[1] - Mon, 01 Jan 2001 00:00:00 GMT - Mon, 01 Jan 2001 01:00:00 GMT - rss_2.0.channel.item[0].author - rss_2.0.channel.item[0].comments - rss_2.0.channel.item[0].guid - test - rss_2.0.channel.item[0].content - - - rss_2.0.channel.item[1].title - rss_2.0.channel.item[1].description - rss_2.0.channel.item[1].link - rss_2.0.channel.item[1].source - - - rss_2.0.channel.item[1].category[0] - rss_2.0.channel.item[1].category[1] - Mon, 02 Jan 2001 00:00:00 GMT - Mon, 01 Jan 2001 01:00:00 GMT - rss_2.0.channel.item[1].author - rss_2.0.channel.item[1].comments - rss_2.0.channel.item[1].guid - test - rss_2.0.channel.item[1].content - - - - rss_2.0.channel.textInput.title - rss_2.0.channel.textInput.description - rss_2.0.channel.textInput.name - rss_2.0.channel.textInput.link - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 23 - - - Monday - Tuesday - Wednesday - Thursday - Friday - Saturday - Sunday - - - - - + + + + + test + rss_2.0.channel.title + rss_2.0.channel.link + rss_2.0.channel.description + rss_2.0.channel.language + rss_2.0.channel.rating + rss_2.0.channel.copyright + Mon, 01 Jan 2001 00:00:00 GMT + + Mon, 01 Jan 2001 01:00:00 GMT + rss_2.0.channel.docs + rss_2.0.channel.managingEditor + rss_2.0.channel.webMaster + rss_2.0.channel.category[0] + rss_2.0.channel.category[1] + rss_2.0.channel.generator + 100 + + + rss_2.0.channel.image.title + rss_2.0.channel.image.url + rss_2.0.channel.image.link + 100 + 200 + rss_2.0.channel.image.description + + + + rss_2.0.channel.item[0].title + rss_2.0.channel.item[0].description + rss_2.0.channel.item[0].link + rss_2.0.channel.item[0].source + + + rss_2.0.channel.item[0].category[0] + rss_2.0.channel.item[0].category[1] + Mon, 01 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_2.0.channel.item[0].author + rss_2.0.channel.item[0].comments + rss_2.0.channel.item[0].guid + test + rss_2.0.channel.item[0].content + + + rss_2.0.channel.item[1].title + rss_2.0.channel.item[1].description + rss_2.0.channel.item[1].link + rss_2.0.channel.item[1].source + + + rss_2.0.channel.item[1].category[0] + rss_2.0.channel.item[1].category[1] + Mon, 02 Jan 2001 00:00:00 GMT + Mon, 01 Jan 2001 01:00:00 GMT + rss_2.0.channel.item[1].author + rss_2.0.channel.item[1].comments + rss_2.0.channel.item[1].guid + test + rss_2.0.channel.item[1].content + + + + rss_2.0.channel.textInput.title + rss_2.0.channel.textInput.description + rss_2.0.channel.textInput.name + rss_2.0.channel.textInput.link + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 23 + + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + + diff --git a/rome/src/test/resources/logback-test.xml b/rome/src/test/resources/logback-test.xml new file mode 100644 index 0000000..c34b099 --- /dev/null +++ b/rome/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/rome.properties b/rome/src/test/resources/rome.properties similarity index 100% rename from src/test/resources/rome.properties rename to rome/src/test/resources/rome.properties diff --git a/src/test/resources/rss_0.9.xml b/rome/src/test/resources/rss_0.9.xml similarity index 100% rename from src/test/resources/rss_0.9.xml rename to rome/src/test/resources/rss_0.9.xml diff --git a/src/test/resources/rss_0.91N.xml b/rome/src/test/resources/rss_0.91N.xml similarity index 100% rename from src/test/resources/rss_0.91N.xml rename to rome/src/test/resources/rss_0.91N.xml diff --git a/src/test/resources/rss_0.91U.xml b/rome/src/test/resources/rss_0.91U.xml similarity index 100% rename from src/test/resources/rss_0.91U.xml rename to rome/src/test/resources/rss_0.91U.xml diff --git a/src/test/resources/rss_0.92.xml b/rome/src/test/resources/rss_0.92.xml similarity index 100% rename from src/test/resources/rss_0.92.xml rename to rome/src/test/resources/rss_0.92.xml diff --git a/src/test/resources/rss_0.92_alt.xml b/rome/src/test/resources/rss_0.92_alt.xml similarity index 100% rename from src/test/resources/rss_0.92_alt.xml rename to rome/src/test/resources/rss_0.92_alt.xml diff --git a/src/test/resources/rss_0.93.xml b/rome/src/test/resources/rss_0.93.xml similarity index 100% rename from src/test/resources/rss_0.93.xml rename to rome/src/test/resources/rss_0.93.xml diff --git a/src/test/resources/rss_0.94.xml b/rome/src/test/resources/rss_0.94.xml similarity index 100% rename from src/test/resources/rss_0.94.xml rename to rome/src/test/resources/rss_0.94.xml diff --git a/src/test/resources/rss_1.0-ns-on-channel.xml b/rome/src/test/resources/rss_1.0-ns-on-channel.xml similarity index 100% rename from src/test/resources/rss_1.0-ns-on-channel.xml rename to rome/src/test/resources/rss_1.0-ns-on-channel.xml diff --git a/src/test/resources/rss_1.0.xml b/rome/src/test/resources/rss_1.0.xml similarity index 100% rename from src/test/resources/rss_1.0.xml rename to rome/src/test/resources/rss_1.0.xml diff --git a/src/test/resources/rss_1.0_DC_Sy.xml b/rome/src/test/resources/rss_1.0_DC_Sy.xml similarity index 100% rename from src/test/resources/rss_1.0_DC_Sy.xml rename to rome/src/test/resources/rss_1.0_DC_Sy.xml diff --git a/src/test/resources/rss_1.0_DC_multi.xml b/rome/src/test/resources/rss_1.0_DC_multi.xml similarity index 100% rename from src/test/resources/rss_1.0_DC_multi.xml rename to rome/src/test/resources/rss_1.0_DC_multi.xml diff --git a/src/test/resources/rss_2.0.xml b/rome/src/test/resources/rss_2.0.xml similarity index 100% rename from src/test/resources/rss_2.0.xml rename to rome/src/test/resources/rss_2.0.xml