Javadocs and other minor tweaks
This commit is contained in:
parent
c395489c5a
commit
db768391aa
|
@ -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<TypeValue> 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.
|
|
@ -115,7 +115,7 @@ public abstract class CachingResolutionStrategy
|
||||||
final TypeValue tv = Makers.type(t.id());
|
final TypeValue tv = Makers.type(t.id());
|
||||||
cache.invalidate(tv);
|
cache.invalidate(tv);
|
||||||
try {
|
try {
|
||||||
TypeValue tt = cache.get(tv, new Callable<TypeValue>() {
|
cache.get(tv, new Callable<TypeValue>() {
|
||||||
public TypeValue call() {
|
public TypeValue call() {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@ package com.ibm.common.activitystreams.registry;
|
||||||
import com.ibm.common.activitystreams.IO;
|
import com.ibm.common.activitystreams.IO;
|
||||||
import com.ibm.common.activitystreams.TypeValue;
|
import com.ibm.common.activitystreams.TypeValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preloads TypeValue instances.
|
||||||
|
*/
|
||||||
public interface PreloadStrategy {
|
public interface PreloadStrategy {
|
||||||
|
|
||||||
void load(IO io, Receiver<TypeValue> receiver);
|
void load(IO io, Receiver<TypeValue> receiver);
|
||||||
|
|
|
@ -9,6 +9,11 @@ import com.ibm.common.activitystreams.TypeValue;
|
||||||
*/
|
*/
|
||||||
public interface ResolutionStrategy {
|
public interface ResolutionStrategy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Receiver instance that is used to
|
||||||
|
* process preloaded TypeValue instances
|
||||||
|
* @return Receiver<TypeValue>
|
||||||
|
*/
|
||||||
Receiver<TypeValue> preloader();
|
Receiver<TypeValue> preloader();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +22,9 @@ public interface ResolutionStrategy {
|
||||||
*/
|
*/
|
||||||
Callable<TypeValue> resolverFor(TypeValue tv);
|
Callable<TypeValue> resolverFor(TypeValue tv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown and cleanup any resources
|
||||||
|
*/
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
public static final ResolutionStrategy nonop =
|
public static final ResolutionStrategy nonop =
|
||||||
|
|
|
@ -35,20 +35,41 @@ import com.ibm.common.activitystreams.ext.ExtModule;
|
||||||
public final class TypeValueRegistry
|
public final class TypeValueRegistry
|
||||||
implements Function<TypeValue,Future<TypeValue>> {
|
implements Function<TypeValue,Future<TypeValue>> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new TypeValueRegistry.Builder
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
public static Builder make () {
|
public static Builder make () {
|
||||||
return new Builder();
|
return new Builder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and return a default TypeValueRegistry instance
|
||||||
|
* @return TypeValueRegistry
|
||||||
|
*/
|
||||||
public static TypeValueRegistry makeDefault() {
|
public static TypeValueRegistry makeDefault() {
|
||||||
return make().get();
|
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() {
|
public static TypeValueRegistry makeDefaultSilent() {
|
||||||
return make()
|
return make()
|
||||||
.resolver(DefaultResolutionStrategy.make().silentfail().get())
|
.resolver(DefaultResolutionStrategy.make().silentfail().get())
|
||||||
.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) {
|
public static TypeValueRegistry makeDefault(final IO io) {
|
||||||
return make()
|
return make()
|
||||||
.io(io)
|
.io(io)
|
||||||
|
@ -65,6 +86,12 @@ public final class TypeValueRegistry
|
||||||
.get();
|
.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) {
|
public static TypeValueRegistry makeDefaultSilent(final IO io) {
|
||||||
return make()
|
return make()
|
||||||
.io(io)
|
.io(io)
|
||||||
|
@ -96,25 +123,48 @@ public final class TypeValueRegistry
|
||||||
DefaultResolutionStrategy.makeDefault();
|
DefaultResolutionStrategy.makeDefault();
|
||||||
private IO io;
|
private IO io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the IO object used
|
||||||
|
* @param io
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
public Builder io(IO io) {
|
public Builder io(IO io) {
|
||||||
this.io = io;
|
this.io = io;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the ExecutorService used
|
||||||
|
* @param executor
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
public Builder executor(ExecutorService executor) {
|
public Builder executor(ExecutorService executor) {
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the PreloadStrategy to be used. By default the
|
||||||
|
* ClasspathPreloader is used.
|
||||||
|
* @param strategy
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
public Builder preloader(PreloadStrategy strategy) {
|
public Builder preloader(PreloadStrategy strategy) {
|
||||||
this.preloader = strategy != null ?
|
this.preloader = strategy != null ?
|
||||||
strategy : ClasspathPreloader.instance;
|
strategy : ClasspathPreloader.instance;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the ResolutionStrategy to use. By default, the
|
||||||
|
* DefaultResolutionStrategy is used.
|
||||||
|
* @param strategy
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
public Builder resolver(ResolutionStrategy strategy) {
|
public Builder resolver(ResolutionStrategy strategy) {
|
||||||
this.strategy = strategy != null ?
|
this.strategy = strategy != null ?
|
||||||
strategy : ResolutionStrategy.nonop;
|
strategy :
|
||||||
|
DefaultResolutionStrategy.makeDefault();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,12 +244,26 @@ public final class TypeValueRegistry
|
||||||
return loadError;
|
return loadError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block indefinitely until the preload process has completed
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws ExecutionException
|
||||||
|
*/
|
||||||
public void waitForPreloader()
|
public void waitForPreloader()
|
||||||
throws InterruptedException,
|
throws InterruptedException,
|
||||||
ExecutionException {
|
ExecutionException {
|
||||||
loader.get();
|
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)
|
public void waitForPreloader(long duration, TimeUnit unit)
|
||||||
throws InterruptedException,
|
throws InterruptedException,
|
||||||
ExecutionException,
|
ExecutionException,
|
||||||
|
@ -216,18 +280,42 @@ public final class TypeValueRegistry
|
||||||
(ThreadPoolExecutor)newFixedThreadPool(1)));
|
(ThreadPoolExecutor)newFixedThreadPool(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the given ID without waiting for the preloader to finish
|
||||||
|
* @param id
|
||||||
|
* @return Future<TypeValue>
|
||||||
|
*/
|
||||||
public Future<TypeValue>resolveNoWait(String id) {
|
public Future<TypeValue>resolveNoWait(String id) {
|
||||||
return resolveNoWait(Makers.type(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 Future<TypeValue>resolve(String id) {
|
public Future<TypeValue>resolve(String id) {
|
||||||
return resolve(Makers.type(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 Future<TypeValue>resolve(String id, long duration, TimeUnit unit) {
|
public Future<TypeValue>resolve(String id, long duration, TimeUnit unit) {
|
||||||
return resolve(Makers.type(id),duration,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 Future<TypeValue>resolveNoWait(TypeValue tv) {
|
public Future<TypeValue>resolveNoWait(TypeValue tv) {
|
||||||
try {
|
try {
|
||||||
if (tv == null) return immediateCancelledFuture();
|
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<TypeValue> resolve(TypeValue tv) {
|
public Future<TypeValue> resolve(TypeValue tv) {
|
||||||
try {
|
try {
|
||||||
if (tv == null) return immediateCancelledFuture();
|
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<TypeValue> resolve(
|
public Future<TypeValue> resolve(
|
||||||
TypeValue tv,
|
TypeValue tv,
|
||||||
long timeout,
|
long timeout,
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
package com.ibm.common.activitystreams.ext.test;
|
package com.ibm.common.activitystreams.ext.test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
import org.junit.Test;
|
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.IO;
|
||||||
import com.ibm.common.activitystreams.Makers;
|
|
||||||
import com.ibm.common.activitystreams.TypeValue;
|
import com.ibm.common.activitystreams.TypeValue;
|
||||||
import com.ibm.common.activitystreams.ext.ExtModule;
|
import com.ibm.common.activitystreams.ext.ExtModule;
|
||||||
import com.ibm.common.activitystreams.registry.TypeValueRegistry;
|
import com.ibm.common.activitystreams.registry.TypeValueRegistry;
|
||||||
|
|
Loading…
Reference in New Issue