Added Atom Threading Extensions Module, see (http://purl.org/syndication/thread/1.0 - http://www.ietf.org/rfc/rfc4685.txt )
This commit is contained in:
parent
4c40079657
commit
63b23843a6
7 changed files with 379 additions and 2 deletions
29
src/main/java/com/rometools/modules/thr/ThreadingModule.java
Normal file
29
src/main/java/com/rometools/modules/thr/ThreadingModule.java
Normal file
|
@ -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 <a href="mailto:andreas@feldschmid.com">Andreas Feldschmid</a>
|
||||||
|
*/
|
||||||
|
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 href);
|
||||||
|
}
|
109
src/main/java/com/rometools/modules/thr/ThreadingModuleImpl.java
Normal file
109
src/main/java/com/rometools/modules/thr/ThreadingModuleImpl.java
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
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 <a href="mailto:andreas@feldschmid.com">Andreas Feldschmid</a>
|
||||||
|
*/
|
||||||
|
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<? extends CopyFrom> 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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 <a href="mailto:andreas@feldschmid.com">Andreas Feldschmid</a>
|
||||||
|
*/
|
||||||
|
public class ThreadingModuleGenerator implements ModuleGenerator {
|
||||||
|
|
||||||
|
private static final Namespace NAMESPACE = Namespace.getNamespace("thr", ThreadingModule.URI);
|
||||||
|
private static final Set<Namespace> NAMESPACES;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Set<Namespace> namespaces = new HashSet<Namespace>();
|
||||||
|
namespaces.add(NAMESPACE);
|
||||||
|
NAMESPACES = Collections.unmodifiableSet(namespaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespaceUri() {
|
||||||
|
return ThreadingModule.URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Namespace> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <a href="mailto:andreas@feldschmid.com">Andreas Feldschmid</a>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -74,7 +74,8 @@ atom_1.0.item.ModuleParser.classes=com.rometools.modules.cc.io.ModuleParserRSS2
|
||||||
com.rometools.modules.georss.W3CGeoParser \
|
com.rometools.modules.georss.W3CGeoParser \
|
||||||
com.rometools.modules.photocast.io.Parser \
|
com.rometools.modules.photocast.io.Parser \
|
||||||
com.rometools.modules.mediarss.io.MediaModuleParser \
|
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 \
|
rss_2.0.feed.ModuleGenerator.classes=com.rometools.modules.cc.io.CCModuleGenerator \
|
||||||
com.rometools.modules.content.io.ContentModuleGenerator \
|
com.rometools.modules.content.io.ContentModuleGenerator \
|
||||||
|
@ -137,7 +138,8 @@ atom_1.0.item.ModuleGenerator.classes=com.rometools.modules.cc.io.CCModuleGenera
|
||||||
com.rometools.modules.georss.SimpleGenerator \
|
com.rometools.modules.georss.SimpleGenerator \
|
||||||
com.rometools.modules.georss.W3CGeoGenerator \
|
com.rometools.modules.georss.W3CGeoGenerator \
|
||||||
com.rometools.modules.photocast.io.Generator \
|
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.feed.ModuleParser.classes=com.rometools.modules.mediarss.io.MediaModuleParser
|
||||||
rss_2.0wNS.item.ModuleParser.classes=com.rometools.modules.mediarss.io.MediaModuleParser
|
rss_2.0wNS.item.ModuleParser.classes=com.rometools.modules.mediarss.io.MediaModuleParser
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
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 <a href="mailto:andreas@feldschmid.com">Andreas Feldschmid</a>
|
||||||
|
*/
|
||||||
|
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<SyndEntry> 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGenerate() throws IOException, FeedException {
|
||||||
|
final SyndFeed feed = getSyndFeed("thr/threading-main.xml");
|
||||||
|
List<SyndEntry> 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");
|
||||||
|
|
||||||
|
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(generatedReplyThreadingModule.getRef(), "tag:example.org,2005:2");
|
||||||
|
assertEquals(generatedReplyThreadingModule.getType(), "application/xhtml+xml");
|
||||||
|
assertEquals(generatedReplyThreadingModule.getHref(), "http://www.example.org/entries/2");
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
src/test/resources/thr/threading-main.xml
Normal file
25
src/test/resources/thr/threading-main.xml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0">
|
||||||
|
<id>http://www.example.org/myfeed</id>
|
||||||
|
<title>My Example Feed</title>
|
||||||
|
<updated>2005-07-28T12:00:00Z</updated>
|
||||||
|
<link href="http://www.example.org/myfeed" />
|
||||||
|
<author>
|
||||||
|
<name>James</name>
|
||||||
|
</author>
|
||||||
|
<entry>
|
||||||
|
<id>tag:example.org,2005:1</id>
|
||||||
|
<title>My original entry</title>
|
||||||
|
<updated>2006-03-01T12:12:12Z</updated>
|
||||||
|
<link type="application/xhtml+xml" href="http://www.example.org/entries/1" />
|
||||||
|
<summary>This is my original entry</summary>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
<id>tag:example.org,2005:1,1</id>
|
||||||
|
<title>A response to the original</title>
|
||||||
|
<updated>2006-03-01T12:12:12Z</updated>
|
||||||
|
<link href="http://www.example.org/entries/1/1" />
|
||||||
|
<thr:in-reply-to ref="tag:example.org,2005:1" type="application/xhtml+xml"
|
||||||
|
href="http://www.example.org/entries/1" />
|
||||||
|
<summary>This is a response to the original entry</summary>
|
||||||
|
</entry>
|
||||||
|
</feed>
|
Loading…
Reference in a new issue