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