diff --git a/src/main/java/com/rometools/modules/atomthread/ThreadModule.java b/src/main/java/com/rometools/modules/atomthread/ThreadModule.java deleted file mode 100644 index 09e0f2a..0000000 --- a/src/main/java/com/rometools/modules/atomthread/ThreadModule.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.atomthread; - -/** - * - * @author robert.cooper - */ -public interface ThreadModule { - -} diff --git a/src/main/java/com/rometools/modules/thr/ThreadingModule.java b/src/main/java/com/rometools/modules/thr/ThreadingModule.java new file mode 100644 index 0000000..98f19b9 --- /dev/null +++ b/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/src/main/java/com/rometools/modules/thr/ThreadingModuleImpl.java b/src/main/java/com/rometools/modules/thr/ThreadingModuleImpl.java new file mode 100644 index 0000000..e0a44c3 --- /dev/null +++ b/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/src/main/java/com/rometools/modules/thr/io/ThreadingModuleGenerator.java b/src/main/java/com/rometools/modules/thr/io/ThreadingModuleGenerator.java new file mode 100644 index 0000000..af51f83 --- /dev/null +++ b/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/src/main/java/com/rometools/modules/thr/io/ThreadingModuleParser.java b/src/main/java/com/rometools/modules/thr/io/ThreadingModuleParser.java new file mode 100644 index 0000000..ecba871 --- /dev/null +++ b/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/src/main/resources/rome.properties b/src/main/resources/rome.properties index 0fb85df..1a8707f 100644 --- a/src/main/resources/rome.properties +++ b/src/main/resources/rome.properties @@ -76,7 +76,8 @@ atom_1.0.item.ModuleParser.classes=com.rometools.modules.cc.io.ModuleParserRSS2 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.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 \ @@ -141,7 +142,8 @@ atom_1.0.item.ModuleGenerator.classes=com.rometools.modules.cc.io.CCModuleGenera 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.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 diff --git a/src/test/java/com/rometools/modules/thr/io/ThreadingModuleTest.java b/src/test/java/com/rometools/modules/thr/io/ThreadingModuleTest.java new file mode 100644 index 0000000..3c01c8d --- /dev/null +++ b/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/src/test/resources/thr/threading-main.xml b/src/test/resources/thr/threading-main.xml new file mode 100644 index 0000000..6d22220 --- /dev/null +++ b/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 + +