/**
* Copyright 2013 OpenSocial Foundation
* Copyright 2013 International Business Machines Corporation
*
* 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.
*
* Utility library for working with Activity Streams Actions
* Requires underscorejs.
*
* @author James M Snell (jasnell@us.ibm.com)
*/
package com.ibm.common.activitystreams;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import com.ibm.common.activitystreams.internal.Adapter;
import com.ibm.common.activitystreams.internal.GsonWrapper;
import com.ibm.common.activitystreams.internal.Schema;
import com.ibm.common.activitystreams.util.Module;
/**
* The IO object is responsible for serializing and deserializing
* Activity Stream objects. Instances of IO should be created and
* defined statically. IO instances are threadsafe and immutable
* once created.
*
* <p>You can choose to use one of the default IO instances:</p>
*
* <pre>
* public static final IO io = IO.makeDefault();
*
* public static final IO prettyIo = IO.makeDefaultPrettyPrint();
* </pre>
*
* <p>Or you can use the IO.Builder to construct and configure your
* own IO instance with custom adapters, object properties and
* type mappings:</p>
*
* <pre>
* import static
*
* public static final IO io =
* IO.make()
* .schema(
* Makers.makeSchema().map(
* Schema.object.template()
* .as("foo", Foo.class)))
* .adapter(Foo.class, new MyFooAdapter())
* .get();
* </pre>
*
* <p>Once created, you can use IO instances to parse Activity Streams
* documents:</p>
*
* <pre>
* InputStream in = ...
* Activity activity = io.readAsActivity(in);
* </pre>
*
* <p>Or can use the IO instance to serialize:</p>
*
* <pre>
* OutputStream out = ...
* Activity activity = ...
* activity.writeTo(out, io);
* </pre>
*
* @author james
* @version $Revision: 1.0 $
*/
public final class IO {
/**
* Create a new IO.Builder
* @return Builder */
public static Builder make() {
return new Builder();
}
/**
* Create a new IO.Builder that uses the given schema
* @param schema Schema
* @return IO
*/
public static IO makeWithSchema(Schema schema) {
return make().schema(schema).get();
}
/**
* Create a new IO.Builder that uses the given schema
* @param schema Supplier<? extends Schema>
* @return IO
*/
public static IO makeWithSchema(Supplier<? extends Schema> schema) {
return makeWithSchema(schema.get());
}
/**
* Make or return the default IO instance
* @return IO
**/
public static IO makeDefault(Module... modules) {
IO.Builder builder = make();
if (modules != null)
for (Module mod : modules)
builder.using(mod);
return builder.get();
}
/**
* Make or return a default IO instance with Pretty Print enabled
* @return IO
*/
public static IO makeDefaultPrettyPrint(Module... modules) {
IO.Builder builder = make().prettyPrint();
if (modules != null)
for (Module mod : modules)
builder.using(mod);
return builder.get();
}
public static class Builder
implements Supplier<IO> {
private final GsonWrapper.Builder inner =
GsonWrapper.make();
private Schema schema;
private final ImmutableSet.Builder<Module> modules =
ImmutableSet.builder();
public Builder using(Module module) {
modules.add(module);
return this;
}
/**
* Turn pretty print on or off
* @param on boolean
* @return Builder
**/
public Builder prettyPrint(boolean on) {
inner.prettyPrint(on);
return this;
}
/**
* Turn pretty print on
* @return Builder
**/
public Builder prettyPrint() {
return prettyPrint(true);
}
/**
* Add an adapter
* @param type Class<? extends T>
* @param adapter Adapter<T>
* @return Builder
**/
public <T>Builder adapter(
Class<? extends T> type,
Adapter<T> adapter) {
inner.adapter(type, adapter);
return this;
}
/**
* Add an adapter
* @param type Class<? extends T>
* @return Builder
*/
public <T>Builder adapter(
Class<? extends T> type) {
return adapter(type,null);
}
/**
* Add an adapter
* @param type Class<? extends T>
* @return Builder
*/
public <T>Builder hierarchicalAdapter(
Class<? extends T> type) {
return hierarchicalAdapter(type,null);
}
/**
* Add an adapter.
* @param type Class<? extends T>
* @param adapter Adapter<T>
* @param hier boolean
* @return Builder
**/
public <T>Builder hierarchicalAdapter(
Class<? extends T> type,
Adapter<T> adapter) {
inner.adapter(type, adapter, true);
return this;
}
/**
* Set the schema
* @param schema Schema
* @return Builder
**/
public Builder schema(Schema schema) {
//inner.schema(schema);
this.schema = schema;
return this;
}
/**
* Set the schema.
* @param schema Supplier<Schema>
* @return Builder
**/
public Builder schema(Supplier<Schema> schema) {
return schema(schema.get());
}
public IO get() {
Iterable<Module> mods = modules.build();
Schema schema = this.schema;
if (schema == null) {
Schema.Builder builder = Schema.make();
for (Module mod : mods)
mod.apply(builder);
schema = builder.get();
}
inner.schema(schema);
for (Module module : modules.build())
module.apply(this, schema);
return new IO(this);
}
}
private final GsonWrapper gson;
protected IO(Builder builder) {
this.gson =
builder.inner.get();
}
/**
* Write the given object
* @param w Writable
* @return String
*/
public String write(Writable w) {
StringWriter sw = new StringWriter();
w.writeTo(sw,this);
return sw.toString();
}
/**
* Asynchronously write the given object
* @param w
* @param executor
* @return java.util.concurrent.Future<String>
*/
public Future<String> write(
final Writable w,
ExecutorService executor) {
return executor.submit(
new Callable<String>() {
public String call() throws Exception {
return write(w);
}
}
);
}
/**
* Write the object to the given outputstream
* @param w Writable
* @param out OutputStream
*/
public void write(Writable w, OutputStream out) {
gson.write(w,out);
}
/**
* Asychronously write the object to the given output stream
* @param w
* @param out
* @param executor
* @return java.util.concurrent.Future<?>
*/
public Future<?> write(
final Writable w,
final OutputStream out,
ExecutorService executor) {
return executor.submit(
new Runnable() {
public void run() {
write(w, out);
}
}
);
}
/**
* Asychronously write the object to the given writer
* @param w
* @param out
* @param executor
* @return java.util.concurrent.Future<?>
*/
public Future<?> write(
final Writable w,
final Writer out,
ExecutorService executor) {
return executor.submit(
new Runnable() {
public void run() {
write(w, out);
}
}
);
}
/**
* Write the object to the given writer
* @param w Writable
* @param out Writer
*/
public void write(Writable w, Writer out) {
gson.write(w,out);
}
/**
* Asynchronously read the given input stream and
* return a parsed object of the given type
* @param in
* @param type
* @param executor
* @return java.util.concurrent.Future<A extends ASObject>
*/
public <A extends ASObject>Future<A> readAs(
final InputStream in,
final Class<? extends A> type,
ExecutorService executor) {
return executor.submit(
new Callable<A>() {
public A call() throws Exception {
return readAs(in, type);
}
}
);
}
/**
* Read the given input stream and return a parsed object
* of the given type
* @param in InputStream
* @param type Class<? extends A>
* @return A */
public <A extends ASObject>A readAs(
InputStream in,
Class<? extends A> type) {
return gson.<A>readAs(in, type);
}
/**
* Asynchronously read the given reader and return a parsed
* object of the given type
* @param in
* @param type
* @param executor
* @return java.util.concurrent.Future<A extends ASObject>
*/
public <A extends ASObject>Future<A> readAs(
final Reader in,
final Class<? extends A> type,
ExecutorService executor) {
return executor.submit(
new Callable<A>() {
public A call() throws Exception {
return readAs(in, type);
}
}
);
}
/**
* Read the given reader and return a parsed object of the given type
* @param in Reader
* @param type Class<? extends A>
* @return A */
public <A extends ASObject>A readAs(
Reader in,
Class<? extends A> type) {
return gson.<A>readAs(in, type);
}
/**
* Asynchronously read the given string and return a parsed object of
* the given type
* @param in
* @param type
* @param executor
* @return java.util.concurrent.Future<A extends ASObject>
*/
public <A extends ASObject>Future<A> readAs(
final String in,
final Class<? extends A> type,
ExecutorService executor) {
return executor.submit(
new Callable<A>() {
public A call() throws Exception {
return readAs(in, type);
}
}
);
}
/**
* Read the given string and return a parsed object of the given type
* @param in String
* @param type Class<? extends A>
* @return A
*/
public <A extends ASObject>A readAs(
String in,
Class<? extends A> type) {
return readAs(new StringReader(in),type);
}
/**
* Asynchronously read the given string
* @param in
* @param executor
* @return java.util.concurrent.Future<ASObject>
*/
public Future<ASObject> read(String in, ExecutorService executor) {
return read(new StringReader(in), executor);
}
/**
* Read the given string
* @param in String
* @return ASObject
*/
public ASObject read(String in) {
return read(new StringReader(in));
}
/**
* Asynchronously read the given inputstream
* @param in
* @param executor
* @return java.util.concurrent.Future<ASObject>
*/
public Future<ASObject> read(InputStream in, ExecutorService executor) {
return readAs(in, ASObject.class, executor);
}
/**
* Asynchronously read the given reader
* @param in
* @param executor
* @return java.util.concurrent.Future<ASObject>
*/
public Future<ASObject> read(Reader in, ExecutorService executor) {
return readAs(in, ASObject.class, executor);
}
/**
* Read the given input stream.
* @param in InputStream
* @return ASObject
**/
public ASObject read(InputStream in) {
return readAs(in, ASObject.class);
}
/**
* Return the given input stream
* @param in InputStream
* @return A
*/
@SuppressWarnings("unchecked")
public <A extends ASObject>A readAs(InputStream in) {
return (A)read(in);
}
/**
* Read the given string as an Activity object
* @param in String
* @return Activity
*/
public Activity readAsActivity(String in) {
return readAsActivity(new StringReader(in));
}
/**
* Asynchronously read the given string as an Activity object
* @param in
* @param executor
* @return java.util.concurrent.Future<Activity>
*/
public Future<Activity> readAsActivity(String in, ExecutorService executor) {
return readAsActivity(new StringReader(in), executor);
}
/**
* Asynchronously read the given inputstream as an Activity object
* @param in
* @param executor
* @return java.util.concurrent.Future<Activity>
*/
public Future<Activity> readAsActivity(InputStream in, ExecutorService executor) {
return readAs(in, Activity.class, executor);
}
/**
* Asynchronously read the given reader as an Activity object
* @param in
* @param executor
* @return java.util.concurrent.Future<Activity>
*/
public Future<Activity> readAsActivity(Reader in, ExecutorService executor) {
return readAs(in, Activity.class, executor);
}
/**
* Asynchronously read the given string as a Collection object
* @param in
* @param executor
* @return java.util.concurrent.Future<Collection>
*/
public Future<Collection> readAsCollection(String in, ExecutorService executor) {
return readAsCollection(new StringReader(in), executor);
}
/**
* Asynchronously read the given input stream as a Collection object
* @param in
* @param executor
* @return java.util.concurrent.Future<Collection>
*/
public Future<Collection> readAsCollection(InputStream in, ExecutorService executor) {
return readAs(in, Collection.class, executor);
}
/**
* Asynchronously read the given reader as a Collection object
* @param in
* @param executor
* @return java.util.concurrent.Future<Collection>
*/
public Future<Collection> readAsCollection(Reader in, ExecutorService executor) {
return readAs(in, Collection.class, executor);
}
/**
* Read the given inputstream as an Activity.
* @param in InputStream
* @return Activity
**/
public Activity readAsActivity(InputStream in) {
return readAs(in, Activity.class);
}
/**
* Read the given string as a Collection.
* @param in InputStream
* @return Collection
**/
public Collection readAsCollection(String in) {
return readAsCollection(new StringReader(in));
}
/**
* Read the given inputstream as a Collection.
* @param in InputStream
* @return Collection
**/
public Collection readAsCollection(InputStream in) {
return readAs(in, Collection.class);
}
/**
* Read the given reader
* @param in
* @return ASObject
*/
public ASObject read(Reader in) {
return readAs(in, ASObject.class);
}
/**
* Read the given reader as an Activity
* @param in Reader
* @return Activity
**/
public Activity readAsActivity(Reader in) {
return readAs(in, Activity.class);
}
/**
* Read the given reader as a Collection
* @param in Reader
* @return Collection
**/
public Collection readAsCollection(Reader in) {
return readAs(in, Collection.class);
}
}