You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by st...@apache.org on 2018/02/15 01:54:57 UTC

[02/17] commons-rdf git commit: Parser defactoring

Parser defactoring


Project: http://git-wip-us.apache.org/repos/asf/commons-rdf/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-rdf/commit/fff13398
Tree: http://git-wip-us.apache.org/repos/asf/commons-rdf/tree/fff13398
Diff: http://git-wip-us.apache.org/repos/asf/commons-rdf/diff/fff13398

Branch: refs/heads/fluent-parser
Commit: fff1339896acaf78a5820e64119471fcb7df417e
Parents: 7d05cc0
Author: Stian Soiland-Reyes <st...@apache.org>
Authored: Tue Feb 21 01:06:02 2017 +0000
Committer: Stian Soiland-Reyes <st...@apache.org>
Committed: Wed Feb 14 18:57:54 2018 +0000

----------------------------------------------------------------------
 .../rdf/simple/experimental/DatasetTarget.java  |  19 +
 .../rdf/simple/experimental/GraphTarget.java    |  19 +
 .../rdf/simple/experimental/IRISource.java      |  20 ++
 .../experimental/ImplicitDatasetTarget.java     |  30 ++
 .../simple/experimental/InputStreamSource.java  |  20 ++
 .../rdf/simple/experimental/ParsedImpl.java     |  34 ++
 .../rdf/simple/experimental/ParserBuilder.java  | 155 ++++++++
 .../simple/experimental/ParserFactoryImpl.java  |  52 +++
 .../experimental/ParserImplementation.java      |  14 +
 .../rdf/simple/experimental/PathSource.java     |  20 ++
 .../simple/experimental/QuadConsumerTarget.java |  22 ++
 .../commons/rdf/simple/experimental/State.java  | 356 +++++++++++++++++++
 .../simple/experimental/ParserFactoryTest.java  |  24 ++
 13 files changed, 785 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/DatasetTarget.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/DatasetTarget.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/DatasetTarget.java
new file mode 100644
index 0000000..bf60726
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/DatasetTarget.java
@@ -0,0 +1,19 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.experimental.ParserFactory.Target;
+
+public class DatasetTarget implements Target<Dataset> {
+
+    private final Dataset target;
+
+    public DatasetTarget(Dataset target) {
+        this.target = target;
+    }
+    
+    @Override
+    public Dataset target() {
+        return target;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/GraphTarget.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/GraphTarget.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/GraphTarget.java
new file mode 100644
index 0000000..8f03351
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/GraphTarget.java
@@ -0,0 +1,19 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.experimental.ParserFactory.Target;
+
+public class GraphTarget implements Target<Graph> {
+
+    private Graph graph;
+
+    public GraphTarget(Graph graph) {
+        this.graph = graph;
+    }
+
+    @Override
+    public Graph target() {
+        return graph;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/IRISource.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/IRISource.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/IRISource.java
new file mode 100644
index 0000000..8324929
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/IRISource.java
@@ -0,0 +1,20 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.experimental.ParserFactory.Source;
+
+public final class IRISource implements Source<IRI> {
+
+    private final IRI source;
+
+    public IRISource(IRI iri) {
+        this.source = iri;
+    }
+
+    @Override
+    public IRI source() {
+        return source;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ImplicitDatasetTarget.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ImplicitDatasetTarget.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ImplicitDatasetTarget.java
new file mode 100644
index 0000000..f2d0b74
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ImplicitDatasetTarget.java
@@ -0,0 +1,30 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.RDF;
+import org.apache.commons.rdf.experimental.ParserFactory.Target;
+
+public class ImplicitDatasetTarget implements Target<Dataset> {
+
+    private final RDF rdf;
+    
+    private Dataset target;
+
+    public ImplicitDatasetTarget(RDF rdf) {
+        this.rdf = rdf;
+    }    
+    
+    @Override
+    public Dataset target() {
+        if (target == null) {
+            synchronized (this) {
+                // Make sure we only make it once
+                if (target == null) {
+                    target = rdf.createDataset();
+                }
+            }
+        }
+        return target;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/InputStreamSource.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/InputStreamSource.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/InputStreamSource.java
new file mode 100644
index 0000000..f68ac78
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/InputStreamSource.java
@@ -0,0 +1,20 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import java.io.InputStream;
+
+import org.apache.commons.rdf.experimental.ParserFactory.Source;
+
+public class InputStreamSource implements Source<InputStream> {
+
+    private final InputStream source;
+
+    public InputStreamSource(InputStream source) {
+        this.source = source;
+    }
+
+    @Override
+    public InputStream source() {
+        return source;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParsedImpl.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParsedImpl.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParsedImpl.java
new file mode 100644
index 0000000..afbac1f
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParsedImpl.java
@@ -0,0 +1,34 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import org.apache.commons.rdf.experimental.ParserFactory.Parsed;
+import org.apache.commons.rdf.experimental.ParserFactory.Source;
+import org.apache.commons.rdf.experimental.ParserFactory.Target;
+
+public class ParsedImpl<T,S> implements Parsed<T, S> {
+
+    private final Source<S> source;
+    private final Target<T> target;
+    private final long count;
+
+    public ParsedImpl(Source<S> source, Target<T> target, final long count) {
+        this.source = source;
+        this.target = target;
+        this.count = count;
+    }
+
+    @Override
+    public long count() {
+        return count;
+    }
+    
+    @Override
+    public Source<S> source() {
+        return source;
+    }
+
+    @Override
+    public Target<T> target() {
+        return target;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserBuilder.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserBuilder.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserBuilder.java
new file mode 100644
index 0000000..512243c
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserBuilder.java
@@ -0,0 +1,155 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
+import java.util.function.Consumer;
+
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDF;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.ParserFactory.*;
+
+@SuppressWarnings({ "rawtypes", "unchecked" })
+public final class ParserBuilder implements NeedTargetOrRDF, NeedSourceBased, Sync, NeedSourceOrBase, OptionalTarget,
+        NeedSourceOrBaseOrSyntax, Async {
+
+    public static enum AsyncOption implements Option<ExecutorService> {
+        EXECUTOR_SERVICE
+    }
+
+    public static enum BaseOption implements Option<IRI> {
+        BASE        
+    }
+    
+    private final State state;
+
+    public ParserBuilder() {
+        this.state = new DefaultState();
+    }
+
+    public ParserBuilder(ParserImplementation impl) {
+        this.state = new WithImplementation(impl);
+    }
+
+    public ParserBuilder(State state) {
+        this.state = state;
+    }
+
+    @Override
+    public Async async() {
+        return async(ForkJoinPool.commonPool());
+    }
+
+    @Override
+    public Async async(ExecutorService executor) {
+        return newState(state.withOption(AsyncOption.EXECUTOR_SERVICE, executor));
+    }
+
+    @Override
+    public NeedSourceBased<Dataset> base(IRI iri) {
+        return newState(implicitTarget().withOption(BaseOption.BASE, iri));
+    }
+
+    @Override
+    public NeedSourceBased<Dataset> base(String iri) {
+        return base(state.rdf().createIRI(iri));
+    }
+
+    public ParserBuilder build() {
+        return newState(state.freeze());
+    }
+
+    @Override
+    public ParserBuilder option(Option o, Object v) {
+        return newState(state.withOption(o, v));
+    }
+
+    @Override
+    public Parsed parse() {
+        ParserImplementation impl = state.impl();
+        long count = impl.parse(state.source(), state.syntax(), state.target(), state.rdf(), state.optionsAsMap());
+        return new ParsedImpl<>(state.source(), state.target(), count);
+    }
+
+    @Override
+    public Future parseAsync() {
+        Map<Option, Object> options = state.optionsAsMap();
+        ExecutorService executor = (ExecutorService) options.getOrDefault(AsyncOption.EXECUTOR_SERVICE,
+                ForkJoinPool.commonPool());
+        return executor.submit(this::parse);
+    }
+
+    @Override
+    public OptionalTarget rdf(RDF rdf) {
+        return newState(state.withRDF(rdf));
+    }
+
+    @Override
+    public Sync source(InputStream is) {
+        return source(new InputStreamSource(is));
+    }
+
+    @Override
+    public Sync source(IRI iri) {
+        return source(new IRISource(iri));
+    }
+
+    @Override
+    public Sync source(Path path) {
+        return source(new PathSource(path));
+    }
+
+    @Override
+    public Sync source(Source source) {
+        return newState(implicitTarget().withSource(source));
+    }
+
+    @Override
+    public Sync source(String iri) {
+        return source(state.rdf().createIRI(iri));
+    }
+
+    public NeedSourceOrBase syntax(RDFSyntax syntax) {
+        return newState(state.withSyntax(syntax));
+    }
+
+    @Override
+    public NeedSourceOrBase<Consumer<Quad>> target(Consumer<? super Quad> consumer) {
+        return target(new QuadConsumerTarget(consumer));
+    }
+
+    @Override
+    public NeedSourceOrBase<Dataset> target(Dataset dataset) {
+        return target(new DatasetTarget(dataset));
+    }
+
+    @Override
+    public NeedSourceOrBase<Graph> target(Graph graph) {
+        return target(new GraphTarget(graph));
+    }
+
+    @Override
+    public NeedSourceOrBase target(Target target) {
+        return newState(state.withTarget(target));
+    }
+
+    private State implicitTarget() {
+        return state.withTarget(new ImplicitDatasetTarget(state.rdf()));
+    }
+
+    private ParserBuilder newState(State newState) {
+        if (this.state == newState) {
+            // probably a MutableState
+            return this;
+        }
+        return new ParserBuilder(newState);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserFactoryImpl.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserFactoryImpl.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserFactoryImpl.java
new file mode 100644
index 0000000..c136459
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserFactoryImpl.java
@@ -0,0 +1,52 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import java.util.function.Consumer;
+
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDF;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.ParserFactory;
+
+public class ParserFactoryImpl implements ParserFactory {
+
+    private State state;
+
+    public ParserFactoryImpl(ParserImplementation impl) {
+        this.state = new WithImplementation(impl);
+    }
+    
+    @Override
+    public NeedSourceOrBase<Graph> target(Graph graph) {
+        return target(new GraphTarget(graph));
+    }
+
+    @Override
+    public NeedSourceOrBase<Dataset> target(Dataset dataset) {
+        return target(new DatasetTarget(dataset));
+    }
+
+    @Override
+    public NeedSourceOrBase<Consumer<Quad>> target(Consumer<? super Quad> consumer) {
+        return target(new QuadConsumerTarget(consumer));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> NeedSourceOrBase<T> target(Target<T> target) {
+        return new ParserBuilder(state.withTarget(target));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public OptionalTarget<Dataset> rdf(RDF rdf) {
+        return new ParserBuilder(state.withRDF(rdf));
+    }
+
+    @Override
+    public NeedTargetOrRDF syntax(RDFSyntax syntax) {
+        return new ParserBuilder(state.withSyntax(syntax));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserImplementation.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserImplementation.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserImplementation.java
new file mode 100644
index 0000000..4284429
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/ParserImplementation.java
@@ -0,0 +1,14 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import java.util.Map;
+
+import org.apache.commons.rdf.api.RDF;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.ParserFactory.Option;
+import org.apache.commons.rdf.experimental.ParserFactory.Source;
+import org.apache.commons.rdf.experimental.ParserFactory.Target;
+
+public interface ParserImplementation {
+    @SuppressWarnings("rawtypes")
+    public long parse(Source source, RDFSyntax rdfSyntax, Target target, RDF rdf, Map<Option, Object> map);
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/PathSource.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/PathSource.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/PathSource.java
new file mode 100644
index 0000000..0341f47
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/PathSource.java
@@ -0,0 +1,20 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import java.nio.file.Path;
+
+import org.apache.commons.rdf.experimental.ParserFactory.Source;
+
+public class PathSource implements Source<Path> {
+    private final Path source;
+
+    public PathSource(Path source) {
+        this.source = source;
+    }
+    
+    @Override
+    public Path source() {
+        return source;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/QuadConsumerTarget.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/QuadConsumerTarget.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/QuadConsumerTarget.java
new file mode 100644
index 0000000..3e6365a
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/QuadConsumerTarget.java
@@ -0,0 +1,22 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import java.util.function.Consumer;
+
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.experimental.ParserFactory.Target;
+
+public class QuadConsumerTarget implements Target<Consumer<Quad>> {
+
+    private final Consumer<? super Quad> consumer;
+
+    public QuadConsumerTarget(Consumer<? super Quad> consumer) {
+        this.consumer = consumer;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Consumer<Quad> target() {
+        return (Consumer<Quad>) consumer;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/main/java/org/apache/commons/rdf/simple/experimental/State.java
----------------------------------------------------------------------
diff --git a/simple/src/main/java/org/apache/commons/rdf/simple/experimental/State.java b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/State.java
new file mode 100644
index 0000000..f94f827
--- /dev/null
+++ b/simple/src/main/java/org/apache/commons/rdf/simple/experimental/State.java
@@ -0,0 +1,356 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.RDF;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.ParserFactory.Option;
+import org.apache.commons.rdf.experimental.ParserFactory.Source;
+import org.apache.commons.rdf.experimental.ParserFactory.Target;
+import org.apache.commons.rdf.simple.SimpleRDF;
+
+@SuppressWarnings("rawtypes")
+interface State {
+    ParserImplementation impl();
+    RDF rdf();
+    Source source();
+    Target target();
+    RDFSyntax syntax();
+    Stream<Map.Entry<Option, Object>> options();
+    Map<Option, Object> optionsAsMap();
+    State withRDF(RDF rdf);
+    State withSource(Source p);
+    State withTarget(Target g);
+    State withSyntax(RDFSyntax s);
+    <O> State withOption(Option<O> o, O v);
+    State withImplementation(ParserImplementation impl);
+    State freeze();
+}
+
+@SuppressWarnings("rawtypes")
+final class MutableState implements State, Cloneable {
+    private ParserImplementation impl;
+    private RDF rdf = new SimpleRDF();
+    private Source source;
+    private Target target;
+    private RDFSyntax syntax;
+    private Map<Option, Object> options = new LinkedHashMap<>();
+
+    @Override
+    public ParserImplementation impl() {
+        return Objects.requireNonNull(impl);
+    }
+    public State freeze() {
+        // options will be cloned inside constructor
+        return new FrozenState(impl, source, syntax, target, rdf, options);
+    }
+    @Override
+    public RDF rdf() {
+        return Objects.requireNonNull(rdf);
+    }
+    @Override
+    public Source source() {
+        return Objects.requireNonNull(source);
+    }
+    @Override
+    public Target target() {
+        return Objects.requireNonNull(target);
+    }
+    @Override
+    public RDFSyntax syntax() {
+        return Objects.requireNonNull(syntax);
+    }
+    @Override
+    public Stream<Entry<Option, Object>> options() {
+        return options.entrySet().stream();
+    }
+    @Override
+    public Map<Option, Object> optionsAsMap() {
+        return Collections.unmodifiableMap(options);
+    }
+    @Override
+    public State withRDF(RDF rdf) {
+        this.rdf = rdf;
+        return this;
+    }
+    @Override
+    public State withSource(Source s) {
+        this.source = s;
+        return this;
+    }
+    @Override
+    public State withTarget(Target t) {
+        this.target = t;
+        return this;
+    }
+    @Override
+    public State withSyntax(RDFSyntax s) {
+        this.syntax = s;
+        return this;
+    }
+    @Override
+    public <O> State withOption(Option<O> o, O v) {
+        options.put(o, v);
+        return this;
+    }
+    @Override
+    public State withImplementation(ParserImplementation impl) {
+        this.impl = impl;
+        return this;
+    }
+}
+
+
+@SuppressWarnings("rawtypes")
+abstract class ImmutableState implements State {
+    @Override
+    public State withSource(Source src) {
+        return new WithSource(src, this);
+    }
+    @Override
+    public State withSyntax(RDFSyntax s) {
+        return new WithSyntax(s, this);
+    }
+    @Override
+    public State withTarget(Target t) {
+        return new WithTarget(t, this);
+    }
+    public State withRDF(RDF rdf) {
+        return new WithRDF(rdf, this);
+    };
+    public <O> State withOption(Option<O> o, O v) {
+        return new WithOption(o, v, this);
+    };
+    @Override
+    public State withImplementation(ParserImplementation impl) {
+        return new WithImplementation(impl, this);
+    }
+    @Override
+    public State freeze() {
+        return this;
+    }
+}
+
+@SuppressWarnings("rawtypes")
+final class DefaultState extends ImmutableState {
+    @Override
+    public Source source() {
+        throw new IllegalStateException("Source not set");
+    }
+    @Override
+    public Target target() {
+        throw new IllegalStateException("Target not set");
+    }
+    @Override
+    public RDFSyntax syntax() {
+        throw new IllegalStateException("Syntax not set");
+    }
+    @Override
+    public RDF rdf() {
+        return new SimpleRDF(); // fresh every time?
+    }
+    @Override
+    public Stream<Entry<Option, Object>> options() {
+        return Stream.empty();
+    }
+    @Override
+    public Map<Option, Object> optionsAsMap() {
+        return Collections.emptyMap();
+    }
+    @Override
+    public ParserImplementation impl() {
+        throw new IllegalStateException("Implementation not set");
+    }
+}
+
+@SuppressWarnings("rawtypes")
+final class FrozenState extends ImmutableState implements State {
+    private final ParserImplementation impl;
+    private final Source source;
+    private final RDFSyntax syntax;
+    private final Target target;
+    private final RDF rdf;
+    private final Map<Option, Object> options;
+
+    public FrozenState(ParserImplementation impl, Source source, RDFSyntax syntax, Target target, RDF rdf,
+            Map<Option, Object> options) {
+        this.impl = impl;
+        this.source = source;
+        this.syntax = syntax;
+        this.target = target;
+        this.rdf = rdf;
+        // shallow copy of options
+        this.options = Collections.unmodifiableMap(new LinkedHashMap<>(options));
+    }
+    @Override
+    public ParserImplementation impl() {
+        return impl;
+    }
+    @Override
+    public RDF rdf() {
+        return rdf;
+    }
+    @Override
+    public Source source() {
+        return source;
+    }
+    @Override
+    public Target target() {
+        return target;
+    }
+    @Override
+    public RDFSyntax syntax() {
+        return syntax;
+    }
+    @Override
+    public Stream<Entry<Option, Object>> options() {
+        return options.entrySet().stream();
+    }
+    @Override
+    public Map<Option, Object> optionsAsMap() {
+        return options;
+    }
+}
+
+@SuppressWarnings("rawtypes")
+abstract class Inherited extends ImmutableState {
+    private final ImmutableState parent;
+    public Inherited() {
+        this(new DefaultState());
+    }
+    public Inherited(ImmutableState state) {
+        parent = state;
+    }
+    @Override
+    public Source source() {
+        return parent.source();
+    }
+    @Override
+    public Target target() {
+        return parent.target();
+    }
+    @Override
+    public RDFSyntax syntax() {
+        return parent.syntax();
+    }
+    @Override
+    public RDF rdf() {
+        return parent.rdf();
+    }
+    @Override
+    public Stream<Entry<Option, Object>> options() {
+        return parent.options();
+    }
+    @Override
+    public Map<Option, Object> optionsAsMap() {
+        return parent.optionsAsMap();
+    }
+    @Override
+    public ParserImplementation impl() {
+        return parent.impl();
+    }
+}
+
+@SuppressWarnings("rawtypes")
+final class WithSource extends Inherited {
+    private final Source source;
+
+    public WithSource(final Source src) {
+        this.source = src;
+    }
+    public WithSource(final Source src, final ImmutableState state) {
+        super(state);
+        this.source = src;
+    }
+    @Override
+    public Source source() {
+        return source;
+    }
+}
+
+@SuppressWarnings("rawtypes")
+final class WithTarget extends Inherited {
+    private final Target target;
+
+    public WithTarget(final Target t) {
+        this.target = t;
+    }
+    public WithTarget(final Target t, final ImmutableState state) {
+        super(state);
+        this.target = t;
+    }
+    @Override
+    public Target target() {
+        return target;
+    }
+}
+
+final class WithSyntax extends Inherited {
+    private final RDFSyntax syntax;
+    public WithSyntax(final RDFSyntax s) {
+        syntax = s;
+    }
+    public WithSyntax(final RDFSyntax s, final ImmutableState state) {
+        super(state);
+        syntax = s;
+    }
+    @Override
+    public RDFSyntax syntax() {
+        return syntax;
+    }
+}
+
+final class WithRDF extends Inherited {
+    private final RDF rdf;
+    public WithRDF(final RDF r) {
+        rdf = r;
+    }
+    public WithRDF(final RDF r, final ImmutableState state) {
+        super(state);
+        rdf = r;
+    }
+    @Override
+    public RDF rdf() {
+        return rdf;
+    }
+}
+
+@SuppressWarnings({ "rawtypes", "unchecked" })
+final class WithOption extends Inherited {
+    private Option<? extends Object> option;
+    private Object value;
+    public <O> WithOption(Option<O> o, O v, ImmutableState immutableState) {
+        this.option = o;
+        this.value = v;
+    }
+    @Override
+    public Stream<Entry<Option, Object>> options() {
+        return Stream.concat(super.options(), Stream.of(new SimpleImmutableEntry(option, value)));
+    }
+    @Override
+    public Map<Option, Object> optionsAsMap() {
+        return options().collect(Collectors.toMap(Entry::getKey, Entry::getValue));
+    }
+}
+
+final class WithImplementation extends Inherited {
+    private final ParserImplementation impl;
+    public WithImplementation(ParserImplementation impl) {
+        this.impl = impl;
+    }
+    public WithImplementation(ParserImplementation impl, ImmutableState parent) {
+        super(parent);
+        this.impl = impl;
+    }
+    @Override
+    public ParserImplementation impl() {
+        return impl;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/fff13398/simple/src/test/java/org/apache/commons/rdf/simple/experimental/ParserFactoryTest.java
----------------------------------------------------------------------
diff --git a/simple/src/test/java/org/apache/commons/rdf/simple/experimental/ParserFactoryTest.java b/simple/src/test/java/org/apache/commons/rdf/simple/experimental/ParserFactoryTest.java
new file mode 100644
index 0000000..a5b63c2
--- /dev/null
+++ b/simple/src/test/java/org/apache/commons/rdf/simple/experimental/ParserFactoryTest.java
@@ -0,0 +1,24 @@
+package org.apache.commons.rdf.simple.experimental;
+
+import static org.junit.Assert.*;
+
+import java.io.InputStream;
+import java.util.concurrent.Future;
+
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.ParserFactory;
+import org.apache.commons.rdf.experimental.ParserFactory.*;
+import org.apache.commons.rdf.simple.SimpleRDF;
+import org.junit.Test;
+
+public class ParserFactoryTest {
+    @Test
+    public void testName() throws Exception {
+        ParserFactory f = new ParserFactoryImpl((a,b,c,d,e) -> 1);
+        InputStream is = getClass().getResourceAsStream("Fred");
+        Async g = f.syntax(RDFSyntax.JSONLD).rdf(new SimpleRDF()).base("http://example.com/").source(is).async();
+        Future<Parsed<?,?>> x = g.parseAsync();
+        Parsed<?, ?> p = x.get();
+        System.out.println(p.count());
+    }
+}