From db768391aac572fdf2f189a7139c82e6bd0bc71f Mon Sep 17 00:00:00 2001 From: James M Snell Date: Fri, 25 Apr 2014 13:25:28 -0700 Subject: [PATCH] Javadocs and other minor tweaks --- typext/README.md | 95 ++++++++++++++++ .../registry/CachingResolutionStrategy.java | 2 +- .../registry/PreloadStrategy.java | 3 + .../registry/ResolutionStrategy.java | 8 ++ .../registry/TypeValueRegistry.java | 104 +++++++++++++++++- .../activitystreams/ext/test/ExtTest.java | 7 -- 6 files changed, 210 insertions(+), 9 deletions(-) create mode 100644 typext/README.md diff --git a/typext/README.md b/typext/README.md new file mode 100644 index 0000000..4d1f4b7 --- /dev/null +++ b/typext/README.md @@ -0,0 +1,95 @@ +# Type Value Extension Support + +This module provides two basic pieces of functionality relating to the +use of extension Type Value definitions: + +1. Verb and ObjectType objects + +2. A TypeValueRegistry that is used to resolve information about extension type value identifiers + +## The TypeValueRegistry + +Suppose we have the following Activity object: + +```json +{ + "actor": "acct:john@example.org", + "verb": "http://example.org/verbs/like", + "object": "http://example.com/notes/1" +} +``` + +The verb "http://example.org/verbs/like" is an "extension verb". The first +time an application encounters an extension verb, it may not have any idea +what to do with it, or what exactly it means. The TypeValueRegistry is +intended to provide a partial solution to that problem by allowing an +application to resolve simple TypeValue identifiers into rich object +identifiers. + +For example: + +```java +TypeValueRegistry tvr = + TypeValueRegistry + .makeDefaultSilent(io); + +TypeValue simple = Makers.type("http://example.org/verbs/like"); + +Future object = tvr.resolve(simple); + +ASObject obj = (ASObject)object.get(); +``` + +By default, the TypeValueRegistry above does three things: + +1. When created, the TypeValueRegistry checks the java classpath for Activity + Stream 2.0 Collection documents that contain TypeValue definitions. If + found, these are preloaded into an in-memory cache. + +2. When asked to resolve a simple TypeValue, the TypeValueRegistry will first + check to see if a resolved object TypeValue already exists in memory. If + it finds one, it returns it. + +3. If there currently is not a resolved object TypeValue in memory, the + TypeValueRegistry will attempt to do an HTTP fetch on the IRI given by + the TypeValue ID. If the ID is not an HTTP URL, this request will fail. + If the GET returns an Activity Streams 2.0 document, the document is + parsed and is examined for information about the given ID. If found, + this information is cached and a resolved object TypeValue is + returned. + +In other words, let's say that the URL "http://example.org/verbs/like" +points to the following Activity Streams 2.0 collection document: + +```json +{ + "objectType": "collection", + "items": [ + { + "objectType": "verb", + "id": "http://example.org/verbs/like", + "displayName": "like" + }, + { + "objectType": "objectType", + "id": "http://example.org/objects/note", + "displayName": "note" + } + ] +} +``` + +The TypeValueRegistry will, by default, find and cache both of the TypeValue +definitions included in the document. Then, it will return the object that +contains "id": "http://example.org/verbs/like". + +Because I used the "makeDefaultSilent" method, if there are any errors +encountered throughout this process, the process will be aborted and the +original simple TypeValue will be returned. + +### Customizing the TypeValueRegistry + +The TypeValueRegistry implementation can be customized by specifying your +own ResolutionStrategy and PreloadStrategy implementations using the +TypeValueRegistry.Builder. You can also provide your own ExecutorService +implementation. Refer to the Javadocs for details. diff --git a/typext/src/main/java/com/ibm/common/activitystreams/registry/CachingResolutionStrategy.java b/typext/src/main/java/com/ibm/common/activitystreams/registry/CachingResolutionStrategy.java index ff4455b..09eba1a 100644 --- a/typext/src/main/java/com/ibm/common/activitystreams/registry/CachingResolutionStrategy.java +++ b/typext/src/main/java/com/ibm/common/activitystreams/registry/CachingResolutionStrategy.java @@ -115,7 +115,7 @@ public abstract class CachingResolutionStrategy final TypeValue tv = Makers.type(t.id()); cache.invalidate(tv); try { - TypeValue tt = cache.get(tv, new Callable() { + cache.get(tv, new Callable() { public TypeValue call() { return t; } diff --git a/typext/src/main/java/com/ibm/common/activitystreams/registry/PreloadStrategy.java b/typext/src/main/java/com/ibm/common/activitystreams/registry/PreloadStrategy.java index b2254eb..a141f04 100644 --- a/typext/src/main/java/com/ibm/common/activitystreams/registry/PreloadStrategy.java +++ b/typext/src/main/java/com/ibm/common/activitystreams/registry/PreloadStrategy.java @@ -3,6 +3,9 @@ package com.ibm.common.activitystreams.registry; import com.ibm.common.activitystreams.IO; import com.ibm.common.activitystreams.TypeValue; +/** + * Preloads TypeValue instances. + */ public interface PreloadStrategy { void load(IO io, Receiver receiver); diff --git a/typext/src/main/java/com/ibm/common/activitystreams/registry/ResolutionStrategy.java b/typext/src/main/java/com/ibm/common/activitystreams/registry/ResolutionStrategy.java index c90556d..d3c3412 100644 --- a/typext/src/main/java/com/ibm/common/activitystreams/registry/ResolutionStrategy.java +++ b/typext/src/main/java/com/ibm/common/activitystreams/registry/ResolutionStrategy.java @@ -9,6 +9,11 @@ import com.ibm.common.activitystreams.TypeValue; */ public interface ResolutionStrategy { + /** + * Returns the Receiver instance that is used to + * process preloaded TypeValue instances + * @return Receiver<TypeValue> + */ Receiver preloader(); /** @@ -17,6 +22,9 @@ public interface ResolutionStrategy { */ Callable resolverFor(TypeValue tv); + /** + * Shutdown and cleanup any resources + */ void shutdown(); public static final ResolutionStrategy nonop = diff --git a/typext/src/main/java/com/ibm/common/activitystreams/registry/TypeValueRegistry.java b/typext/src/main/java/com/ibm/common/activitystreams/registry/TypeValueRegistry.java index e829e30..1cbf9e8 100644 --- a/typext/src/main/java/com/ibm/common/activitystreams/registry/TypeValueRegistry.java +++ b/typext/src/main/java/com/ibm/common/activitystreams/registry/TypeValueRegistry.java @@ -35,20 +35,41 @@ import com.ibm.common.activitystreams.ext.ExtModule; public final class TypeValueRegistry implements Function> { + /** + * Return a new TypeValueRegistry.Builder + * @return Builder + */ public static Builder make () { return new Builder(); } + /** + * Create and return a default TypeValueRegistry instance + * @return TypeValueRegistry + */ public static TypeValueRegistry makeDefault() { return make().get(); } + /** + * Create an return a default silent TypeValueRegistry instance. + * Errors encountered during the resolve process will be silenced, + * causing the process to abort and the original "simple" TypeValue + * to be returned + * @return TypeValueRegistry + */ public static TypeValueRegistry makeDefaultSilent() { return make() .resolver(DefaultResolutionStrategy.make().silentfail().get()) .get(); } + /** + * Create a default TypeValueRegistry instance using the + * given Activity Streams IO object + * @param io + * @return TypeValueRegistry + */ public static TypeValueRegistry makeDefault(final IO io) { return make() .io(io) @@ -65,6 +86,12 @@ public final class TypeValueRegistry .get(); } + /** + * Create a default silent TypeValueRegistry instance using + * the given Activity Streams IO object + * @param io + * @return TypeValueRegistry + */ public static TypeValueRegistry makeDefaultSilent(final IO io) { return make() .io(io) @@ -96,25 +123,48 @@ public final class TypeValueRegistry DefaultResolutionStrategy.makeDefault(); private IO io; + /** + * Set the IO object used + * @param io + * @return Builder + */ public Builder io(IO io) { this.io = io; return this; } + /** + * Set the ExecutorService used + * @param executor + * @return Builder + */ public Builder executor(ExecutorService executor) { this.executor = executor; return this; } + /** + * Set the PreloadStrategy to be used. By default the + * ClasspathPreloader is used. + * @param strategy + * @return Builder + */ public Builder preloader(PreloadStrategy strategy) { this.preloader = strategy != null ? strategy : ClasspathPreloader.instance; return this; } + /** + * Set the ResolutionStrategy to use. By default, the + * DefaultResolutionStrategy is used. + * @param strategy + * @return Builder + */ public Builder resolver(ResolutionStrategy strategy) { this.strategy = strategy != null ? - strategy : ResolutionStrategy.nonop; + strategy : + DefaultResolutionStrategy.makeDefault(); return this; } @@ -194,12 +244,26 @@ public final class TypeValueRegistry return loadError; } + /** + * Block indefinitely until the preload process has completed + * @throws InterruptedException + * @throws ExecutionException + */ public void waitForPreloader() throws InterruptedException, ExecutionException { loader.get(); } + /** + * Block up to the given period of time waiting for the preload + * process to complete + * @param duration + * @param unit + * @throws InterruptedException + * @throws ExecutionException + * @throws TimeoutException + */ public void waitForPreloader(long duration, TimeUnit unit) throws InterruptedException, ExecutionException, @@ -216,18 +280,42 @@ public final class TypeValueRegistry (ThreadPoolExecutor)newFixedThreadPool(1))); } + /** + * Resolve the given ID without waiting for the preloader to finish + * @param id + * @return Future<TypeValue> + */ public FutureresolveNoWait(String id) { return resolveNoWait(Makers.type(id)); } + /** + * Resolve the given ID. Will wait for the preload process to complete + * before returning + * @param id + * @return Future<TypeValue> + */ public Futureresolve(String id) { return resolve(Makers.type(id)); } + /** + * Resolve the given ID. Will wait the specified length of time for the + * preload process to complete before returning + * @param id + * @param duration + * @param unit + * @return Future<TypeValue> + */ public Futureresolve(String id, long duration, TimeUnit unit) { return resolve(Makers.type(id),duration,unit); } + /** + * Resolve the given ID without waiting for the preload process to complete + * @param tv + * @return Future<TypeValue> + */ public FutureresolveNoWait(TypeValue tv) { try { if (tv == null) return immediateCancelledFuture(); @@ -239,6 +327,12 @@ public final class TypeValueRegistry } } + /** + * Resolve the given ID. Will block indefinitely until the preload process + * is complete + * @param tv + * @return Future<TypeValue> + */ public Future resolve(TypeValue tv) { try { if (tv == null) return immediateCancelledFuture(); @@ -253,6 +347,14 @@ public final class TypeValueRegistry } } + /** + * Resolve the given ID. Will block for the given period of time until + * the preload process is complete + * @param tv + * @param timeout + * @param unit + * @return Future<TypeValue> + */ public Future resolve( TypeValue tv, long timeout, diff --git a/typext/src/test/java/com/ibm/common/activitystreams/ext/test/ExtTest.java b/typext/src/test/java/com/ibm/common/activitystreams/ext/test/ExtTest.java index 1d80d54..f9006d0 100644 --- a/typext/src/test/java/com/ibm/common/activitystreams/ext/test/ExtTest.java +++ b/typext/src/test/java/com/ibm/common/activitystreams/ext/test/ExtTest.java @@ -1,17 +1,10 @@ package com.ibm.common.activitystreams.ext.test; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.util.concurrent.Future; import org.junit.Test; -import static com.ibm.common.activitystreams.Makers.type; - -import com.google.common.util.concurrent.Monitor; -import com.ibm.common.activitystreams.Collection; import com.ibm.common.activitystreams.IO; -import com.ibm.common.activitystreams.Makers; import com.ibm.common.activitystreams.TypeValue; import com.ibm.common.activitystreams.ext.ExtModule; import com.ibm.common.activitystreams.registry.TypeValueRegistry;