1   package org.daisy.pipeline.common.calabash.impl;
2   
3   import java.util.Map;
4   
5   import com.xmlcalabash.core.XProcRuntime;
6   import com.xmlcalabash.io.ReadablePipe;
7   import com.xmlcalabash.io.WritablePipe;
8   import com.xmlcalabash.library.DefaultStep;
9   import com.xmlcalabash.model.RuntimeValue;
10  import com.xmlcalabash.model.Step;
11  import com.xmlcalabash.runtime.XAtomicStep;
12  
13  import net.sf.saxon.s9api.QName;
14  import net.sf.saxon.s9api.SaxonApiException;
15  import net.sf.saxon.s9api.XdmNode;
16  
17  import org.daisy.common.saxon.SaxonHelper;
18  import org.daisy.common.xproc.calabash.XMLCalabashInputValue;
19  import org.daisy.common.xproc.calabash.XMLCalabashOutputValue;
20  import org.daisy.common.xproc.calabash.XProcStep;
21  import org.daisy.common.xproc.calabash.XProcStepProvider;
22  import org.daisy.common.xproc.XProcMonitor;
23  
24  import org.osgi.service.component.annotations.Component;
25  
26  import org.slf4j.Logger;
27  import org.slf4j.LoggerFactory;
28  
29  public class ChunkerStep extends DefaultStep implements XProcStep {
30  	
31  	@Component(
32  		name = "px:chunker",
33  		service = { XProcStepProvider.class },
34  		property = { "type:String={http://www.daisy.org/ns/pipeline/xproc}xml-chunker" }
35  	)
36  	public static class Provider implements XProcStepProvider {
37  		
38  		@Override
39  		public XProcStep newStep(XProcRuntime runtime, XAtomicStep step, XProcMonitor monitor, Map<String,String> properties) {
40  			return new ChunkerStep(runtime, step);
41  		}
42  	}
43  	
44  	private ReadablePipe sourcePipe = null;
45  	private WritablePipe resultPipe = null;
46  	private WritablePipe mappingPipe = null;
47  	
48  	private static final QName ALLOW_BREAK_BEFORE = new QName("allow-break-before");
49  	private static final QName ALLOW_BREAK_AFTER = new QName("allow-break-after");
50  	private static final QName PREFER_BREAK_BEFORE = new QName("prefer-break-before");
51  	private static final QName PREFER_BREAK_AFTER = new QName("prefer-break-after");
52  	private static final QName ALWAYS_BREAK_BEFORE = new QName("always-break-before");
53  	private static final QName ALWAYS_BREAK_AFTER = new QName("always-break-after");
54  	
55  	private static final QName PART_ATTRIBUTE = new QName("part-attribute");
56  	private static final QName PROPAGATE = new QName("propagate");
57  	private static final QName MAX_CHUNK_SIZE = new QName("max-chunk-size");
58  	
59  	private ChunkerStep(XProcRuntime runtime, XAtomicStep step) {
60  		super(runtime, step);
61  	}
62  	
63  	@Override
64  	public void setInput(String port, ReadablePipe pipe) {
65  		sourcePipe = pipe;
66  	}
67  	
68  	@Override
69  	public void setOutput(String port, WritablePipe pipe) {
70  		if ("result".equals(port)) {
71  			resultPipe = pipe;
72  		} else { // "mapping"
73  			mappingPipe = pipe;
74  		}
75  	}
76  	
77  	@Override
78  	public void reset() {
79  		sourcePipe.resetReader();
80  		resultPipe.resetWriter();
81  		mappingPipe.resetWriter();
82  	}
83  	
84  	@Override
85  	public void run() throws SaxonApiException {
86  		super.run();
87  		try {
88  			RuntimeValue partAttribute = getOption(PART_ATTRIBUTE);
89  			new Chunker(
90  				getOption(ALLOW_BREAK_BEFORE),
91  				getOption(ALLOW_BREAK_AFTER),
92  				getOption(PREFER_BREAK_BEFORE),
93  				getOption(PREFER_BREAK_AFTER),
94  				getOption(ALWAYS_BREAK_BEFORE),
95  				getOption(ALWAYS_BREAK_AFTER),
96  				partAttribute != null ? SaxonHelper.jaxpQName(partAttribute.getQName()) : null,
97  				getOption(PROPAGATE, true),
98  				getOption(MAX_CHUNK_SIZE, -1),
99  				runtime.getProcessor().getUnderlyingConfiguration())
100 			.transform(
101 				new XMLCalabashInputValue(sourcePipe),
102 				new XMLCalabashOutputValue(
103 					new WritablePipe() {
104 						private int count = 0;
105 						public void write(XdmNode doc) {
106 							(count++ == 0 ? mappingPipe : resultPipe).write(doc);
107 						}
108 						public void canWriteSequence(boolean sequence) { throw new UnsupportedOperationException(); }
109 						public boolean writeSequence() { throw new UnsupportedOperationException(); }
110 						public void setWriter(Step step) { throw new UnsupportedOperationException(); }
111 						public void resetWriter() { throw new UnsupportedOperationException(); }
112 						public void close() { throw new UnsupportedOperationException(); }
113 					},
114 					runtime))
115 			.run();
116 		} catch (Throwable e) {
117 			throw XProcStep.raiseError(e, step);
118 		}
119 	}
120 	
121 	private static final Logger logger = LoggerFactory.getLogger(ChunkerStep.class);
122 	
123 }