/*
* Copyright 2008-2011 the original author or authors.
*
* 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.
*
*/
package com.nominanuda.dataobject.transform;
import java.io.Reader;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.function.Supplier;
import javax.xml.transform.TransformerConfigurationException;
import com.nominanuda.dataobject.DataStruct;
import com.nominanuda.dataobject.DataStructContentHandler;
import com.nominanuda.dataobject.DataStructStreamer;
import com.nominanuda.dataobject.JsonContentHandler;
import com.nominanuda.dataobject.JsonStreamer;
import com.nominanuda.dataobject.JsonStreamingParser;
import com.nominanuda.lang.Check;
import com.nominanuda.lang.ObjectFactory;
import com.nominanuda.lang.Tuple2;
public class JsonPipeline {
private final List<Object> components = new LinkedList<Object>();
private boolean looseParser = false;
class WrappingTransformer extends BaseJsonTransformer {
JsonTransformer last;
public WrappingTransformer(Tuple2<JsonTransformer, JsonTransformer> pair) {
super.setTarget(pair.get0());
this.last = pair.get1();
}
@Override
public void setTarget(JsonContentHandler target) {
last.setTarget(target);
}
}
public JsonPipeline add(ObjectFactory<? extends JsonTransformer> transformer) {
components.add(transformer);
return this;
}
public JsonPipeline setComponents(List<?> components) {
this.components.clear();
for (Object c : components) {
this.components.add(c);
}
return this;
}
public JsonPipeline withLooseParser() {
looseParser = true;
return this;
}
/**
* Build a raw pipeline without a terminating transformer. It is the caller's responsibility to set the final transformer (@see JsonTransformer.setTarget()) and to apply the pipeline to a stream.
* @return
*/
public JsonTransformer build() {
try {
return new WrappingTransformer(buildPipe());
} catch(Exception e) {
throw new RuntimeException("Failed to build pipeline: " + e.getMessage(), e);
}
}
public Runnable build(final JsonStreamer starter, final JsonContentHandler ender) {
return new Runnable() {
public void run() {
try {
starter.stream(buildPipe(ender));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
}
public Supplier<DataStruct> build(final JsonStreamer starter) {
final DataStructContentHandler dsch = new DataStructContentHandler();
final Runnable r = build(starter, dsch);
return runnableToFun(r, dsch);
}
public Runnable build(final Reader json, final JsonContentHandler ender) {
return build(new JsonStreamingParser(looseParser, json), ender);
}
public Supplier<DataStruct> build(final Reader json) {
final DataStructContentHandler dsch = new DataStructContentHandler();
final Runnable r = build(json, dsch);
return runnableToFun(r, dsch);
}
public Runnable build(final DataStruct struct, final JsonContentHandler ender) {
return build(new DataStructStreamer(struct), ender);
}
public Supplier<DataStruct> build(final DataStruct ds) {
final DataStructContentHandler dsch = new DataStructContentHandler();
final Runnable r = build(ds, dsch);
return runnableToFun(r, dsch);
}
private JsonTransformer buildJsonTransformer(Object c) throws TransformerConfigurationException {
if (c instanceof ObjectFactory) {
return (JsonTransformer)((ObjectFactory<?>)c).getObject();
} else {
return Check.illegalstate.fail();
}
}
private JsonContentHandler buildPipe(final JsonContentHandler ender) throws TransformerConfigurationException {
if (ender == null) {
throw new TransformerConfigurationException("Terminating transformer not supplied.");
}
JsonContentHandler nextTarget = ender;
ListIterator<Object> litr = components.listIterator(components.size());
while (litr.hasPrevious()) {
Object c = litr.previous();
JsonTransformer th = buildJsonTransformer(c);
th.setTarget(nextTarget);
nextTarget = th;
}
return nextTarget;
}
private Tuple2<JsonTransformer, JsonTransformer> buildPipe() throws TransformerConfigurationException {
JsonTransformer lastTarget = null;
JsonTransformer nextTarget = null;
int n = components.size();
if (n == 0) {
// let's guarantee at least one transformer, so that we always return a pipeline
JsonTransformer tr = new BaseJsonTransformer();
tr.setTarget(null);
nextTarget = tr;
lastTarget = tr;
} else {
// Iterate backwards and finish with first target in pipeline
ListIterator<Object> litr = components.listIterator(n);
while (litr.hasPrevious()) {
Object c = litr.previous();
JsonTransformer th = buildJsonTransformer(c);
th.setTarget(nextTarget);
nextTarget = th;
if (lastTarget == null) {
lastTarget = th;
}
}
}
return new Tuple2<JsonTransformer, JsonTransformer>(nextTarget, lastTarget);
}
private Supplier<DataStruct> runnableToFun(final Runnable r, final DataStructContentHandler dsch) {
return new Supplier<DataStruct>() {
public DataStruct get() {
r.run();
return dsch.getResult();
}
};
}
}