1   package org.daisy.pipeline.common.calabash.impl;
2   
3   import java.util.Map;
4   
5   import javax.xml.namespace.QName;
6   
7   import com.google.common.collect.ImmutableMap;
8   
9   import com.xmlcalabash.core.XProcException;
10  import com.xmlcalabash.core.XProcRuntime;
11  import com.xmlcalabash.io.ReadablePipe;
12  import com.xmlcalabash.io.WritablePipe;
13  import com.xmlcalabash.library.DefaultStep;
14  import com.xmlcalabash.runtime.XAtomicStep;
15  
16  import net.sf.saxon.s9api.SaxonApiException;
17  
18  import org.daisy.common.xproc.calabash.CalabashExceptionFromXProcError;
19  import org.daisy.common.xproc.calabash.XMLCalabashInputValue;
20  import org.daisy.common.xproc.calabash.XProcStep;
21  import org.daisy.common.xproc.calabash.XProcStepProvider;
22  import org.daisy.common.xproc.XProcError;
23  import org.daisy.common.xproc.XProcMonitor;
24  
25  import org.osgi.service.component.annotations.Component;
26  
27  @Component(
28  	name = "pxi:error",
29  	service = { XProcStepProvider.class },
30  	property = { "type:String={http://www.daisy.org/ns/pipeline/xproc/internal}error" }
31  )
32  public class Error implements XProcStepProvider {
33  
34  	public XProcStep newStep(XProcRuntime runtime, XAtomicStep step, XProcMonitor monitor, Map<String,String> properties) {
35  		return new ErrorStep(runtime, step);
36  	}
37  
38  	/**
39  	 * Own version of <code>p:error</code> that reads one or more <code>c:errors</code> documents
40  	 * with one or more <code>c:error</code> elements in each, creates {@link XProcException}s,
41  	 * reports them, and throws the last one.
42  	 */
43  	public static class ErrorStep extends DefaultStep implements XProcStep {
44  
45  		private ReadablePipe errorPipe = null;
46  		private XProcException lastError = null;
47  
48  		private ErrorStep(XProcRuntime runtime, XAtomicStep step) {
49  			super(runtime, step);
50  		}
51  
52  		@Override
53  		public void setInput(String port, ReadablePipe pipe) {
54  			if ("error".equals(port))
55  				errorPipe = pipe;
56  		}
57  
58  		@Override
59  		public void setOutput(String port, WritablePipe pipe) {
60  		}
61  		
62  		@Override
63  		public void reset() {
64  			errorPipe.resetReader();
65  			lastError = null;
66  		}
67  		
68  		@Override
69  		public void run() throws SaxonApiException {
70  			try {
71  				lastError = null;
72  				new ErrorReporter(this::report)
73  					.transform(
74  						ImmutableMap.of(new QName("source"), new XMLCalabashInputValue(errorPipe)),
75  						ImmutableMap.of())
76  					.run();
77  				if (lastError != null)
78  					throw lastError;
79  				else
80  					throw new RuntimeException("Expected c:errors document with at least one c:error");
81  			} catch (Throwable e) {
82  				throw XProcStep.raiseError(e, step);
83  			}
84  		}
85  
86  		private void report(XProcError error) {
87  			lastError = CalabashExceptionFromXProcError.from(error);
88  			step.reportError(lastError);
89  		}
90  	}
91  }