1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /* $Id$ */
19 
20 package org.apache.fop.fo;
21 
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.ArrayList;
25 import java.util.List;
26 
27 import javax.xml.transform.Result;
28 import javax.xml.transform.Source;
29 import javax.xml.transform.Transformer;
30 import javax.xml.transform.TransformerConfigurationException;
31 import javax.xml.transform.TransformerException;
32 import javax.xml.transform.TransformerFactory;
33 import javax.xml.transform.sax.SAXResult;
34 import javax.xml.transform.stream.StreamSource;
35 
36 import org.junit.After;
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.xml.sax.Attributes;
40 import org.xml.sax.SAXException;
41 import org.xml.sax.helpers.DefaultHandler;
42 
43 import static org.junit.Assert.assertArrayEquals;
44 
45 import org.apache.fop.apps.FOUserAgent;
46 import org.apache.fop.fo.FODocumentParser.FOEventHandlerFactory;
47 import org.apache.fop.fo.flow.BasicLink;
48 import org.apache.fop.fo.flow.Block;
49 import org.apache.fop.fo.flow.BlockContainer;
50 import org.apache.fop.fo.flow.Character;
51 import org.apache.fop.fo.flow.ExternalGraphic;
52 import org.apache.fop.fo.flow.Footnote;
53 import org.apache.fop.fo.flow.FootnoteBody;
54 import org.apache.fop.fo.flow.Inline;
55 import org.apache.fop.fo.flow.InstreamForeignObject;
56 import org.apache.fop.fo.flow.Leader;
57 import org.apache.fop.fo.flow.ListBlock;
58 import org.apache.fop.fo.flow.ListItem;
59 import org.apache.fop.fo.flow.ListItemBody;
60 import org.apache.fop.fo.flow.ListItemLabel;
61 import org.apache.fop.fo.flow.PageNumber;
62 import org.apache.fop.fo.flow.PageNumberCitation;
63 import org.apache.fop.fo.flow.PageNumberCitationLast;
64 import org.apache.fop.fo.flow.Wrapper;
65 import org.apache.fop.fo.flow.table.Table;
66 import org.apache.fop.fo.flow.table.TableBody;
67 import org.apache.fop.fo.flow.table.TableCell;
68 import org.apache.fop.fo.flow.table.TableColumn;
69 import org.apache.fop.fo.flow.table.TableFooter;
70 import org.apache.fop.fo.flow.table.TableHeader;
71 import org.apache.fop.fo.flow.table.TableRow;
72 import org.apache.fop.fo.pagination.Flow;
73 import org.apache.fop.fo.pagination.PageSequence;
74 import org.apache.fop.fo.pagination.Root;
75 import org.apache.fop.fo.pagination.StaticContent;
76 
77 /**
78  * Tests that {@link DelegatingFOEventHandler} does forward every event to its delegate
79  * event handler.
80  */
81 public class DelegatingFOEventHandlerTestCase {
82 
83     private InputStream document;
84 
85     private List<String> expectedEvents;
86 
87     private List<String> actualEvents;
88 
89     private FODocumentParser documentParser;
90 
91     private class DelegatingFOEventHandlerTester extends FOEventHandler {
92 
DelegatingFOEventHandlerTester(FOUserAgent foUserAgent)93         DelegatingFOEventHandlerTester(FOUserAgent foUserAgent) {
94             super(foUserAgent);
95         }
96 
97         private final StringBuilder eventBuilder = new StringBuilder();
98 
99         @Override
startDocument()100         public void startDocument() throws SAXException {
101             actualEvents.add("start document");
102         }
103 
104         @Override
endDocument()105         public void endDocument() throws SAXException {
106             actualEvents.add("end   document");
107         }
108 
109         @Override
startRoot(Root root)110         public void startRoot(Root root) {
111             startElement(root);
112         }
113 
114         @Override
endRoot(Root root)115         public void endRoot(Root root) {
116             endElement(root);
117         }
118 
119         @Override
startPageSequence(PageSequence pageSeq)120         public void startPageSequence(PageSequence pageSeq) {
121             startElement(pageSeq);
122         }
123 
124         @Override
endPageSequence(PageSequence pageSeq)125         public void endPageSequence(PageSequence pageSeq) {
126             endElement(pageSeq);
127         }
128 
129         @Override
startPageNumber(PageNumber pagenum)130         public void startPageNumber(PageNumber pagenum) {
131             startElement(pagenum);
132         }
133 
134         @Override
endPageNumber(PageNumber pagenum)135         public void endPageNumber(PageNumber pagenum) {
136             endElement(pagenum);
137         }
138 
139         @Override
startPageNumberCitation(PageNumberCitation pageCite)140         public void startPageNumberCitation(PageNumberCitation pageCite) {
141             startElement(pageCite);
142         }
143 
144         @Override
endPageNumberCitation(PageNumberCitation pageCite)145         public void endPageNumberCitation(PageNumberCitation pageCite) {
146             endElement(pageCite);
147         }
148 
149         @Override
startPageNumberCitationLast(PageNumberCitationLast pageLast)150         public void startPageNumberCitationLast(PageNumberCitationLast pageLast) {
151             startElement(pageLast);
152         }
153 
154         @Override
endPageNumberCitationLast(PageNumberCitationLast pageLast)155         public void endPageNumberCitationLast(PageNumberCitationLast pageLast) {
156             endElement(pageLast);
157         }
158 
159         @Override
startFlow(Flow fl)160         public void startFlow(Flow fl) {
161             startElement(fl);
162         }
163 
164         @Override
endFlow(Flow fl)165         public void endFlow(Flow fl) {
166             endElement(fl);
167         }
168 
169         @Override
startBlock(Block bl)170         public void startBlock(Block bl) {
171             startElement(bl);
172         }
173 
174         @Override
endBlock(Block bl)175         public void endBlock(Block bl) {
176             endElement(bl);
177         }
178 
179         @Override
startBlockContainer(BlockContainer blc)180         public void startBlockContainer(BlockContainer blc) {
181             startElement(blc);
182         }
183 
184         @Override
endBlockContainer(BlockContainer blc)185         public void endBlockContainer(BlockContainer blc) {
186             endElement(blc);
187         }
188 
189         @Override
startInline(Inline inl)190         public void startInline(Inline inl) {
191             startElement(inl);
192         }
193 
194         @Override
endInline(Inline inl)195         public void endInline(Inline inl) {
196             endElement(inl);
197         }
198 
199         @Override
startTable(Table tbl)200         public void startTable(Table tbl) {
201             startElement(tbl);
202         }
203 
204         @Override
endTable(Table tbl)205         public void endTable(Table tbl) {
206             endElement(tbl);
207         }
208 
209         @Override
startColumn(TableColumn tc)210         public void startColumn(TableColumn tc) {
211             startElement(tc);
212         }
213 
214         @Override
endColumn(TableColumn tc)215         public void endColumn(TableColumn tc) {
216             endElement(tc);
217         }
218 
219         @Override
startHeader(TableHeader header)220         public void startHeader(TableHeader header) {
221             startElement(header);
222         }
223 
224         @Override
endHeader(TableHeader header)225         public void endHeader(TableHeader header) {
226             endElement(header);
227         }
228 
229         @Override
startFooter(TableFooter footer)230         public void startFooter(TableFooter footer) {
231             startElement(footer);
232         }
233 
234         @Override
endFooter(TableFooter footer)235         public void endFooter(TableFooter footer) {
236             endElement(footer);
237         }
238 
239         @Override
startBody(TableBody body)240         public void startBody(TableBody body) {
241             startElement(body);
242         }
243 
244         @Override
endBody(TableBody body)245         public void endBody(TableBody body) {
246             endElement(body);
247         }
248 
249         @Override
startRow(TableRow tr)250         public void startRow(TableRow tr) {
251             startElement(tr);
252         }
253 
254         @Override
endRow(TableRow tr)255         public void endRow(TableRow tr) {
256             endElement(tr);
257         }
258 
259         @Override
startCell(TableCell tc)260         public void startCell(TableCell tc) {
261             startElement(tc);
262         }
263 
264         @Override
endCell(TableCell tc)265         public void endCell(TableCell tc) {
266             endElement(tc);
267         }
268 
269         @Override
startList(ListBlock lb)270         public void startList(ListBlock lb) {
271             startElement(lb);
272         }
273 
274         @Override
endList(ListBlock lb)275         public void endList(ListBlock lb) {
276             endElement(lb);
277         }
278 
279         @Override
startListItem(ListItem li)280         public void startListItem(ListItem li) {
281             startElement(li);
282         }
283 
284         @Override
endListItem(ListItem li)285         public void endListItem(ListItem li) {
286             endElement(li);
287         }
288 
289         @Override
startListLabel(ListItemLabel listItemLabel)290         public void startListLabel(ListItemLabel listItemLabel) {
291             startElement(listItemLabel);
292         }
293 
294         @Override
endListLabel(ListItemLabel listItemLabel)295         public void endListLabel(ListItemLabel listItemLabel) {
296             endElement(listItemLabel);
297         }
298 
299         @Override
startListBody(ListItemBody listItemBody)300         public void startListBody(ListItemBody listItemBody) {
301             startElement(listItemBody);
302         }
303 
304         @Override
endListBody(ListItemBody listItemBody)305         public void endListBody(ListItemBody listItemBody) {
306             endElement(listItemBody);
307         }
308 
309         @Override
startStatic(StaticContent staticContent)310         public void startStatic(StaticContent staticContent) {
311             startElement(staticContent);
312         }
313 
314         @Override
endStatic(StaticContent statisContent)315         public void endStatic(StaticContent statisContent) {
316             endElement(statisContent);
317         }
318 
319         @Override
startLink(BasicLink basicLink)320         public void startLink(BasicLink basicLink) {
321             startElement(basicLink);
322         }
323 
324         @Override
endLink(BasicLink basicLink)325         public void endLink(BasicLink basicLink) {
326             endElement(basicLink);
327         }
328 
329         @Override
image(ExternalGraphic eg)330         public void image(ExternalGraphic eg) {
331             startElement(eg);
332             endElement(eg);
333         }
334 
335         @Override
startInstreamForeignObject(InstreamForeignObject ifo)336         public void startInstreamForeignObject(InstreamForeignObject ifo) {
337             startElement(ifo);
338         }
339 
340         @Override
endInstreamForeignObject(InstreamForeignObject ifo)341         public void endInstreamForeignObject(InstreamForeignObject ifo) {
342             endElement(ifo);
343         }
344 
345         @Override
startFootnote(Footnote footnote)346         public void startFootnote(Footnote footnote) {
347             startElement(footnote);
348         }
349 
350         @Override
endFootnote(Footnote footnote)351         public void endFootnote(Footnote footnote) {
352             endElement(footnote);
353         }
354 
355         @Override
startFootnoteBody(FootnoteBody body)356         public void startFootnoteBody(FootnoteBody body) {
357             startElement(body);
358         }
359 
360         @Override
endFootnoteBody(FootnoteBody body)361         public void endFootnoteBody(FootnoteBody body) {
362             endElement(body);
363         }
364 
365         @Override
startLeader(Leader l)366         public void startLeader(Leader l) {
367             startElement(l);
368         }
369 
370         @Override
endLeader(Leader l)371         public void endLeader(Leader l) {
372             endElement(l);
373         }
374 
375         @Override
startWrapper(Wrapper wrapper)376         public void startWrapper(Wrapper wrapper) {
377             startElement(wrapper);
378         }
379 
380         @Override
endWrapper(Wrapper wrapper)381         public void endWrapper(Wrapper wrapper) {
382             endElement(wrapper);
383         }
384 
385         @Override
character(Character c)386         public void character(Character c) {
387             startElement(c);
388             endElement(c);
389         }
390 
startElement(FObj node)391         private void startElement(FObj node) {
392             addEvent("start ", node);
393         }
394 
endElement(FObj node)395         private void endElement(FObj node) {
396             addEvent("end   ", node);
397         }
398 
addEvent(String event, FObj node)399         private void addEvent(String event, FObj node) {
400             eventBuilder.append(event);
401             eventBuilder.append(node.getLocalName());
402             addID(node);
403             actualEvents.add(eventBuilder.toString());
404             eventBuilder.setLength(0);
405         }
406 
addID(FObj node)407         private void addID(FObj node) {
408             String id = node.getId();
409             if (id != null && id.length() > 0) {
410                 eventBuilder.append(" id=\"");
411                 eventBuilder.append(id);
412                 eventBuilder.append("\"");
413             }
414         }
415     }
416 
417     @Before
setUp()418     public void setUp() throws IOException {
419         setUpEvents();
420         loadDocument();
421         createDocumentParser();
422     }
423 
setUpEvents()424     private void setUpEvents() throws IOException {
425         loadDocument();
426         loadExpectedEvents();
427         actualEvents = new ArrayList<String>(expectedEvents.size());
428     }
429 
loadDocument()430     private void loadDocument() {
431         document = getClass().getResourceAsStream("complete_document.fo");
432     }
433 
loadExpectedEvents()434     private void loadExpectedEvents() throws IOException {
435         expectedEvents = new ArrayList<String>();
436         InputStream xslt = getClass().getResourceAsStream("extract-events.xsl");
437         try {
438             runXSLT(xslt);
439         } finally {
440             closeStream(xslt);
441             closeStream(document);
442         }
443     }
444 
runXSLT(InputStream xslt)445     private void runXSLT(InputStream xslt) {
446         Transformer transformer = createTransformer(xslt);
447         Source fo = new StreamSource(document);
448         Result result = createTransformOutputHandler();
449         try {
450             transformer.transform(fo, result);
451         } catch (TransformerException e) {
452             throw new RuntimeException(e);
453         }
454     }
455 
createTransformer(InputStream xslt)456     private Transformer createTransformer(InputStream xslt) {
457         TransformerFactory transformerFactory = TransformerFactory.newInstance();
458         try {
459             return transformerFactory.newTransformer(new StreamSource(xslt));
460         } catch (TransformerConfigurationException e) {
461             throw new RuntimeException(e);
462         }
463     }
464 
createTransformOutputHandler()465     private Result createTransformOutputHandler() {
466         return new SAXResult(new DefaultHandler() {
467 
468             private final StringBuilder event = new StringBuilder();
469 
470             @Override
471             public void startElement(String uri, String localName, String qName,
472                     Attributes attributes) throws SAXException {
473                 event.setLength(0);
474             }
475 
476             @Override
477             public void characters(char[] ch, int start, int length) throws SAXException {
478                 event.append(ch, start, length);
479             }
480 
481             @Override
482             public void endElement(String uri, String localName, String qName) throws SAXException {
483                 expectedEvents.add(event.toString());
484             }
485 
486         });
487     }
488 
closeStream(InputStream stream)489     private void closeStream(InputStream stream) {
490         try {
491             stream.close();
492         } catch (IOException e) {
493             throw new RuntimeException(e);
494         }
495     }
496 
createDocumentParser()497     private void createDocumentParser() {
498         documentParser = FODocumentParser.newInstance(new FOEventHandlerFactory() {
499 
500             public FOEventHandler newFOEventHandler(FOUserAgent foUserAgent) {
501                 return new DelegatingFOEventHandler(
502                         new DelegatingFOEventHandlerTester(foUserAgent)) {
503                 };
504             }
505         });
506     }
507 
508     @Test
testFOEventHandler()509     public void testFOEventHandler() throws Exception {
510         documentParser.parse(document);
511         assertArrayEquals(expectedEvents.toArray(), actualEvents.toArray());
512     }
513 
514     @After
unloadDocument()515     public void unloadDocument() throws IOException {
516         document.close();
517     }
518 
519     /**
520      * Prints the given list to {@code System.out}, each element on a new line. For
521      * debugging purpose.
522      *
523      * @param list a list
524      */
printList(List<?> list)525     public void printList(List<?> list) {
526         for (Object element : list) {
527             System.out.println(element);
528         }
529     }
530 
531 }
532