Merge pull request #32 from icyerasor/threading-extensions

Added atom threading extensions
This commit is contained in:
David M. Johnson 2015-12-06 15:15:41 -05:00
commit a0753a6256
8 changed files with 383 additions and 28 deletions

View file

@ -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 {
}

View 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 source);
}

View file

@ -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 <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());
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();
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -76,7 +76,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 \
@ -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.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

View file

@ -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 <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());
assertNull(threadingModule.getSource());
}
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");
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);
}
}

View 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>