001 package railo.runtime.tag; 002 003 004 import java.awt.Dimension; 005 import java.io.ByteArrayInputStream; 006 import java.io.ByteArrayOutputStream; 007 import java.io.IOException; 008 import java.io.OutputStream; 009 import java.util.ArrayList; 010 import java.util.Iterator; 011 import java.util.Map; 012 013 import javax.servlet.http.HttpServletResponse; 014 import javax.servlet.jsp.JspException; 015 016 import railo.commons.io.IOUtil; 017 import railo.commons.io.res.Resource; 018 import railo.commons.io.res.util.ResourceUtil; 019 import railo.commons.lang.StringUtil; 020 import railo.commons.pdf.PDFDocument; 021 import railo.commons.pdf.PDFException; 022 import railo.commons.pdf.PDFPageMark; 023 import railo.runtime.Info; 024 import railo.runtime.PageContextImpl; 025 import railo.runtime.exp.ApplicationException; 026 import railo.runtime.exp.PageException; 027 import railo.runtime.exp.TemplateException; 028 import railo.runtime.ext.tag.BodyTagImpl; 029 import railo.runtime.op.Caster; 030 import railo.runtime.text.pdf.PDFUtil; 031 import railo.runtime.type.ReadOnlyStruct; 032 033 import com.lowagie.text.DocumentException; 034 import com.lowagie.text.pdf.PdfCopy; 035 import com.lowagie.text.pdf.PdfImportedPage; 036 import com.lowagie.text.pdf.PdfReader; 037 import com.lowagie.text.pdf.SimpleBookmark; 038 039 public final class Document extends BodyTagImpl { 040 041 042 //private static final String STYLE_BG_INVISIBLE = "background-color: transparent; background-image: none;"; 043 044 045 046 private Resource filename=null; 047 private boolean overwrite=false; 048 private String name=null; 049 private Dimension pagetype=PDFDocument.PAGETYPE_LETTER; 050 private double pageheight=0; 051 private double pagewidth=0; 052 private boolean isLandscape=false; 053 054 055 private double unitFactor=PDFDocument.UNIT_FACTOR_IN; 056 private int encryption=PDFDocument.ENC_NONE; 057 058 private String ownerpassword=null; 059 private String userpassword="empty"; 060 private int scale=-1; 061 062 // TODO impl. tag Document backgroundvisible,fontembed,scale 063 private boolean backgroundvisible; 064 private int fontembed=PDFDocument.FONT_EMBED_YES; 065 066 private int permissions=0; 067 private PDFDocument _document; 068 069 070 071 private ArrayList<PDFDocument> documents=new ArrayList<PDFDocument>(); 072 073 public Document() { 074 this._document=null; 075 } 076 077 @Override 078 public void release() { 079 super.release(); 080 filename=null; 081 overwrite=false; 082 name=null; 083 pagetype=PDFDocument.PAGETYPE_LETTER; 084 pageheight=0; 085 pagewidth=0; 086 isLandscape=false; 087 unitFactor=PDFDocument.UNIT_FACTOR_IN; 088 encryption=PDFDocument.ENC_NONE; 089 ownerpassword=null; 090 userpassword="empty"; 091 permissions=0; 092 scale=-1; 093 documents.clear(); 094 _document=null; 095 backgroundvisible=false; 096 fontembed=PDFDocument.FONT_EMBED_YES; 097 098 099 100 } 101 102 private PDFDocument getDocument() { 103 //SerialNumber sn = pageContext.getConfig().getSerialNumber(); 104 if(_document==null){ 105 _document=new PDFDocument(); 106 } 107 return _document; 108 } 109 110 111 112 /** set the value proxyserver 113 * Host name or IP address of a proxy server. 114 * @param proxyserver value to set 115 **/ 116 public void setProxyserver(String proxyserver) { 117 getDocument().setProxyserver(proxyserver); 118 } 119 public void setProxyhost(String proxyserver) { 120 getDocument().setProxyserver(proxyserver); 121 } 122 123 /** set the value proxyport 124 * The port number on the proxy server from which the object is requested. Default is 80. When 125 * used with resolveURL, the URLs of retrieved documents that specify a port number are automatically 126 * resolved to preserve links in the retrieved document. 127 * @param proxyport value to set 128 **/ 129 public void setProxyport(double proxyport) { 130 getDocument().setProxyport((int)proxyport); 131 } 132 133 /** set the value username 134 * When required by a proxy server, a valid username. 135 * @param proxyuser value to set 136 **/ 137 public void setProxyuser(String proxyuser) { 138 getDocument().setProxyuser(proxyuser); 139 } 140 141 /** set the value password 142 * When required by a proxy server, a valid password. 143 * @param proxypassword value to set 144 **/ 145 public void setProxypassword(String proxypassword) { 146 getDocument().setProxypassword(proxypassword); 147 } 148 149 public void setSaveasname(String saveAsName) { 150 // TODO impl 151 } 152 153 /** 154 * @param authUser the authUser to set 155 */ 156 public void setAuthuser(String authUser) { 157 getDocument().setAuthUser(authUser); 158 } 159 160 /** 161 * @param authPassword the authPassword to set 162 */ 163 public void setAuthpassword(String authPassword) { 164 getDocument().setAuthPassword(authPassword); 165 } 166 167 /** 168 * @param userAgent the userAgent to set 169 */ 170 public void setUseragent(String userAgent) { 171 getDocument().setUserAgent(userAgent); 172 } 173 174 /** 175 * @param format the format to set 176 * @throws ApplicationException 177 */ 178 public void setFormat(String format) throws ApplicationException { 179 format = StringUtil.toLowerCase(format.trim()); 180 if(!"pdf".equals(format)) 181 throw new ApplicationException("invalid format ["+format+"], only the following format is supported [pdf]"); 182 } 183 184 /** 185 * @param filename the filename to set 186 * @throws PageException 187 */ 188 public void setFilename(String filename) throws PageException { 189 this.filename = ResourceUtil.toResourceNotExisting(pageContext, filename); 190 pageContext.getConfig().getSecurityManager().checkFileLocation(this.filename); 191 } 192 193 /** 194 * @param overwrite the overwrite to set 195 */ 196 public void setOverwrite(boolean overwrite) { 197 this.overwrite = overwrite; 198 } 199 200 /** 201 * @param name the name to set 202 */ 203 public void setName(String name) { 204 this.name = name; 205 } 206 207 /** 208 * @param pagetype the pagetype to set 209 * @throws ApplicationException 210 */ 211 public void setPagetype(String strPagetype) throws ApplicationException { 212 strPagetype=StringUtil.toLowerCase(strPagetype.trim()); 213 if("legal".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_LEGAL; 214 else if("letter".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_LETTER; 215 else if("a4".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_A4; 216 else if("a5".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_A5; 217 else if("b4".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_B4; 218 else if("b5".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_B5; 219 else if("b4-jis".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_B4_JIS; 220 else if("b4 jis".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_B4_JIS; 221 else if("b4_jis".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_B4_JIS; 222 else if("b4jis".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_B4_JIS; 223 else if("b5-jis".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_B5_JIS; 224 else if("b5 jis".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_B5_JIS; 225 else if("b5_jis".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_B5_JIS; 226 else if("b5jis".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_B5_JIS; 227 else if("custom".equals(strPagetype)) pagetype=PDFDocument.PAGETYPE_CUSTOM; 228 else throw new ApplicationException("invalid page type ["+strPagetype+"], valid page types are [legal,letter,a4,a5,b4,b5,b4-jis,b5-jis,custom]"); 229 230 231 } 232 233 /** 234 * @param pageheight the pageheight to set 235 * @throws ApplicationException 236 */ 237 public void setPageheight(double pageheight) throws ApplicationException { 238 if(pageheight<1) throw new ApplicationException("pageheight must be a positive number"); 239 this.pageheight = pageheight; 240 } 241 242 /** 243 * @param pagewidth the pagewidth to set 244 * @throws ApplicationException 245 */ 246 public void setPagewidth(double pagewidth) throws ApplicationException { 247 if(pagewidth<1) throw new ApplicationException("pagewidth must be a positive number"); 248 this.pagewidth = pagewidth; 249 } 250 251 /** 252 * @param orientation the orientation to set 253 * @throws ApplicationException 254 */ 255 public void setOrientation(String strOrientation) throws ApplicationException { 256 strOrientation=StringUtil.toLowerCase(strOrientation.trim()); 257 if("portrait".equals(strOrientation)) isLandscape=false; 258 else if("landscape".equals(strOrientation)) isLandscape=true; 259 else throw new ApplicationException("invalid orientation ["+strOrientation+"], valid orientations are [portrait,landscape]"); 260 261 } 262 263 /** 264 * @param marginbottom the marginbottom to set 265 */ 266 public void setMarginbottom(double marginbottom) { 267 getDocument().setMarginbottom(marginbottom); 268 } 269 270 /** 271 * @param marginleft the marginleft to set 272 */ 273 public void setMarginleft(double marginleft) { 274 getDocument().setMarginleft(marginleft); 275 } 276 277 /** 278 * @param marginright the marginright to set 279 */ 280 public void setMarginright(double marginright) { 281 getDocument().setMarginright(marginright); 282 } 283 284 /** 285 * @param margintop the margintop to set 286 */ 287 public void setMargintop(double margintop) { 288 getDocument().setMargintop(margintop); 289 } 290 291 /** 292 * @param bookmark the bookmark to set 293 */ 294 public void setBookmark(boolean bookmark) { 295 getDocument().setBookmark(bookmark); 296 } 297 298 public void setHtmlbookmark(boolean bookmark) { 299 getDocument().setHtmlBookmark(bookmark); 300 } 301 302 /** 303 * @param localUrl the localUrl to set 304 */ 305 public void setLocalurl(boolean localUrl) { 306 getDocument().setLocalUrl(localUrl); 307 } 308 309 /** 310 * @param unitFactor the unit to set 311 * @throws ApplicationException 312 */ 313 public void setUnit(String strUnit) throws ApplicationException { 314 strUnit=StringUtil.toLowerCase(strUnit.trim()); 315 if("in".equals(strUnit)) unitFactor=PDFDocument.UNIT_FACTOR_IN; 316 else if("cm".equals(strUnit)) unitFactor=PDFDocument.UNIT_FACTOR_CM; 317 else if("point".equals(strUnit)) unitFactor=PDFDocument.UNIT_FACTOR_POINT; 318 else throw new ApplicationException("invalid unit ["+strUnit+"], valid units are [cm,in,point]"); 319 } 320 321 /** 322 * @param encryption the encryption to set 323 * @throws ApplicationException 324 */ 325 public void setEncryption(String strEncryption) throws ApplicationException { 326 strEncryption=StringUtil.toLowerCase(strEncryption.trim()); 327 if("none".equals(strEncryption)) encryption=PDFDocument.ENC_NONE; 328 else if("40-bit".equals(strEncryption)) encryption=PDFDocument.ENC_40BIT; 329 else if("40bit".equals(strEncryption)) encryption=PDFDocument.ENC_40BIT; 330 else if("40 bit".equals(strEncryption)) encryption=PDFDocument.ENC_40BIT; 331 else if("40_bit".equals(strEncryption)) encryption=PDFDocument.ENC_40BIT; 332 else if("128-bit".equals(strEncryption)) encryption=PDFDocument.ENC_128BIT; 333 else if("128bit".equals(strEncryption)) encryption=PDFDocument.ENC_128BIT; 334 else if("128 bit".equals(strEncryption)) encryption=PDFDocument.ENC_128BIT; 335 else if("128_bit".equals(strEncryption)) encryption=PDFDocument.ENC_128BIT; 336 else throw new ApplicationException("invalid encryption ["+strEncryption+"], valid encryption values are [none, 40-bit, 128-bit]"); 337 } 338 339 /** 340 * @param ownerpassword the ownerpassword to set 341 * @throws ApplicationException 342 */ 343 public void setOwnerpassword(String ownerpassword) { 344 this.ownerpassword = ownerpassword; 345 } 346 347 /** 348 * @param userpassword the userpassword to set 349 */ 350 public void setUserpassword(String userpassword) { 351 this.userpassword = userpassword; 352 } 353 354 /** 355 * @param permissions the permissions to set 356 * @throws PageException 357 */ 358 public void setPermissions(String strPermissions) throws PageException { 359 permissions=PDFUtil.toPermissions(strPermissions); 360 } 361 362 /** 363 * @param scale the scale to set 364 * @throws ApplicationException 365 */ 366 public void setScale(double scale) throws ApplicationException { 367 if(scale<0) throw new ApplicationException("scale must be a positive number"); 368 if(scale>100) throw new ApplicationException("scale must be a number less or equal than 100"); 369 this.scale = (int) scale; 370 } 371 372 /** 373 * @param src the src to set 374 * @throws ApplicationException 375 */ 376 public void setSrc(String src) throws ApplicationException { 377 try { 378 getDocument().setSrc(src); 379 } catch (PDFException e) { 380 throw new ApplicationException(e.getMessage()); 381 } 382 } 383 384 /** 385 * @param srcfile the srcfile to set 386 * @throws PageException 387 * @throws 388 */ 389 public void setSrcfile(String strSrcfile) throws PageException { 390 Resource srcfile = ResourceUtil.toResourceExisting(pageContext, strSrcfile); 391 pageContext.getConfig().getSecurityManager().checkFileLocation(srcfile); 392 try { 393 getDocument().setSrcfile(srcfile); 394 } catch (PDFException e) { 395 throw new ApplicationException(e.getMessage()); 396 } 397 } 398 399 /** 400 * @param mimetype the mimetype to set 401 */ 402 public void setMimetype(String strMimetype) { 403 getDocument().setMimetype(strMimetype); 404 strMimetype = strMimetype.toLowerCase().trim(); 405 } 406 407 408 public void setHeader(PDFPageMark header) { 409 getDocument().setHeader(header); 410 } 411 412 public void setFooter(PDFPageMark footer) { 413 getDocument().setFooter(footer); 414 } 415 416 417 public void setBackgroundvisible(boolean backgroundvisible) { 418 this.backgroundvisible=backgroundvisible; 419 } 420 421 public void setFontembed(String fontembed) throws PDFException { 422 Boolean fe=Caster.toBoolean(fontembed,null); 423 if(fe==null) { 424 fontembed=StringUtil.toLowerCase(fontembed.trim()); 425 if("selective".equals(fontembed)) 426 this.fontembed=PDFDocument.FONT_EMBED_SELECCTIVE; 427 else throw new PDFException("invalid value for fontembed ["+fontembed+"], valid values for fontembed are [yes,no,selective]"); 428 429 } 430 else if(fe.booleanValue())this.fontembed=PDFDocument.FONT_EMBED_YES; 431 else this.fontembed=PDFDocument.FONT_EMBED_NO; 432 getDocument().setFontembed(this.fontembed); 433 } 434 435 public void addPDFDocument(PDFDocument document) { 436 // set proxy settings 437 if(_document!=null) { 438 if(_document.hasProxy()) { 439 document.setProxyserver(_document.getProxyserver()); 440 document.setProxyport(_document.getProxyport()); 441 document.setProxyuser(_document.getProxyuser()); 442 document.setProxypassword(_document.getProxypassword()); 443 } 444 document.setBookmark(_document.getBookmark()); 445 document.setLocalUrl(_document.getLocalUrl()); 446 } 447 448 449 documents.add(document); 450 } 451 452 @Override 453 public int doStartTag() throws PageException { 454 // SerialNumber sn = pageContext.getConfig().getSerialNumber(); 455 //if(sn.getVersion()==SerialNumber.VERSION_COMMUNITY) 456 // throw new SecurityException("no access to this functionality with the "+sn.getStringVersion()+" version of railo"); 457 458 459 ReadOnlyStruct cfdoc=new ReadOnlyStruct(); 460 cfdoc.setEL("currentpagenumber", "{currentpagenumber}"); 461 cfdoc.setEL("totalpagecount", "{totalpagecount}"); 462 cfdoc.setEL("totalsectionpagecount", "{totalsectionpagecount}"); 463 cfdoc.setEL("currentsectionpagenumber", "{currentsectionpagenumber}"); 464 cfdoc.setReadOnly(true); 465 pageContext.variablesScope().setEL("cfdocument", cfdoc); 466 467 return EVAL_BODY_BUFFERED; 468 } 469 470 @Override 471 public void doInitBody() { 472 473 } 474 475 @Override 476 public int doAfterBody() { 477 getDocument().setBody(bodyContent.getString()); 478 479 return SKIP_BODY; 480 } 481 482 @Override 483 public int doEndTag() throws PageException { 484 try { 485 _doEndTag(); 486 } 487 catch (Exception e) { 488 throw Caster.toPageException(e); 489 } 490 return EVAL_PAGE; 491 } 492 493 public void _doEndTag() throws JspException, IOException, DocumentException { 494 // set root header/footer to sections 495 boolean doBookmarks=false; 496 boolean doHtmlBookmarks=false; 497 if(_document!=null){ 498 PDFPageMark header = _document.getHeader(); 499 PDFPageMark footer = _document.getFooter(); 500 boolean hasHeader=header!=null; 501 boolean hasFooter=footer!=null; 502 if(hasFooter || hasHeader) { 503 Iterator<PDFDocument> it = documents.iterator(); 504 PDFDocument doc; 505 while(it.hasNext()){ 506 doc=it.next(); 507 if(hasHeader && doc.getHeader()==null) doc.setHeader(header); 508 if(hasFooter && doc.getFooter()==null) doc.setFooter(footer); 509 } 510 } 511 doBookmarks=_document.getBookmark(); 512 doHtmlBookmarks=_document.getHtmlBookmark(); 513 } 514 515 516 if(filename!=null) { 517 if(filename.exists() && !overwrite) 518 throw new ApplicationException("file ["+filename+"] already exist","to allow overwrite the resource, set attribute [overwrite] to [true]"); 519 520 OutputStream os= null; 521 try { 522 os= filename.getOutputStream(); 523 render(os,doBookmarks,doHtmlBookmarks); 524 } 525 finally { 526 IOUtil.closeEL(os); 527 } 528 529 } 530 else if(!StringUtil.isEmpty(name)) { 531 render(null,doBookmarks,doHtmlBookmarks); 532 } 533 else { 534 HttpServletResponse rsp = pageContext. getHttpServletResponse(); 535 if(rsp.isCommitted()) 536 throw new ApplicationException("content is already flushed","you can't rewrite head of response after part of the page is flushed"); 537 rsp.setContentType("application/pdf"); 538 539 540 OutputStream os=getOutputStream(); 541 try { 542 render(os,doBookmarks,doHtmlBookmarks); 543 } 544 finally { 545 IOUtil.flushEL(os); 546 IOUtil.closeEL(os); 547 ((PageContextImpl)pageContext).getRootOut().setClosed(true); 548 } 549 throw new railo.runtime.exp.Abort(railo.runtime.exp.Abort.SCOPE_REQUEST); 550 } 551 552 } 553 554 555 556 private void render(OutputStream os, boolean doBookmarks, boolean doHtmlBookmarks) throws IOException, PageException, DocumentException { 557 byte[] pdf=null; 558 // merge multiple docs to 1 559 if(documents.size()>1) { 560 PDFDocument[] pdfDocs=new PDFDocument[documents.size()]; 561 PdfReader[] pdfReaders = new PdfReader[pdfDocs.length]; 562 Iterator<PDFDocument> it = documents.iterator(); 563 int index=0; 564 // generate pdf with pd4ml 565 while(it.hasNext()) { 566 pdfDocs[index]=it.next(); 567 pdfReaders[index]= 568 new PdfReader(pdfDocs[index].render(getDimension(),unitFactor,pageContext,doHtmlBookmarks)); 569 index++; 570 } 571 572 // collect together 573 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 574 com.lowagie.text.Document document = 575 new com.lowagie.text.Document(pdfReaders[0].getPageSizeWithRotation(1)); 576 PdfCopy copy = new PdfCopy(document,baos); 577 document.open(); 578 String name; 579 ArrayList bookmarks=doBookmarks?new ArrayList():null; 580 try { 581 int size,totalPage=0; 582 Map parent; 583 for(int doc=0;doc<pdfReaders.length;doc++) { 584 size=pdfReaders[doc].getNumberOfPages(); 585 586 PdfImportedPage ip; 587 588 // bookmarks 589 if(doBookmarks) { 590 name=pdfDocs[doc].getName(); 591 if(!StringUtil.isEmpty(name)) { 592 bookmarks.add(parent=PDFUtil.generateGoToBookMark(name, totalPage+1)); 593 } 594 else parent=null; 595 596 if(doHtmlBookmarks) { 597 java.util.List pageBM = SimpleBookmark.getBookmark(pdfReaders[doc]); 598 if(pageBM!=null) { 599 if(totalPage>0)SimpleBookmark.shiftPageNumbers(pageBM, totalPage, null); 600 if(parent!=null)PDFUtil.setChildBookmarks(parent,pageBM); 601 else bookmarks.addAll(pageBM); 602 } 603 } 604 } 605 606 totalPage++; 607 for(int page=1;page<=size;page++) { 608 if(page>1)totalPage++; 609 ip = copy.getImportedPage(pdfReaders[doc], page); 610 611 //ip.getPdfDocument().setHeader(arg0); 612 //ip.getPdfDocument().setFooter(arg0); 613 copy.addPage(ip); 614 } 615 } 616 if (doBookmarks && !bookmarks.isEmpty())copy.setOutlines(bookmarks); 617 } 618 finally { 619 document.close(); 620 } 621 pdf=baos.toByteArray(); 622 } 623 else if(documents.size()==1){ 624 pdf=(documents.get(0)).render(getDimension(),unitFactor,pageContext,doHtmlBookmarks); 625 } 626 else { 627 pdf=getDocument().render(getDimension(),unitFactor,pageContext,doHtmlBookmarks); 628 } 629 630 // permission/encryption 631 if(PDFDocument.ENC_NONE!=encryption) { 632 PdfReader reader = new PdfReader(pdf); 633 com.lowagie.text.Document document = new com.lowagie.text.Document(reader.getPageSize(1)); 634 document.addCreator("Railo "+Info.getVersionAsString()+" "+Info.getStateAsString()); 635 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 636 PdfCopy copy = new PdfCopy(document,baos); 637 //PdfWriter writer = PdfWriter.getInstance(document, pdfOut); 638 copy.setEncryption(PDFDocument.ENC_128BIT==encryption , userpassword , ownerpassword , permissions); 639 document.open(); 640 int size=reader.getNumberOfPages(); 641 for(int page=1;page<=size;page++) { 642 copy.addPage(copy.getImportedPage(reader, page)); 643 } 644 document.close(); 645 pdf=baos.toByteArray(); 646 } 647 648 // write out 649 if(os!=null)IOUtil.copy(new ByteArrayInputStream(pdf), os,true,false); 650 if(!StringUtil.isEmpty(name)) { 651 pageContext.setVariable(name,pdf); 652 } 653 } 654 655 private OutputStream getOutputStream() throws PageException, IOException { 656 try { 657 return ((PageContextImpl)pageContext).getResponseStream(); 658 } 659 catch(IllegalStateException ise) { 660 throw new TemplateException("content is already send to user, flush"); 661 } 662 } 663 664 665 private Dimension getDimension() throws ApplicationException { 666 // page size custom 667 if(isCustom(pagetype)) { 668 if(pageheight==0 || pagewidth==0) 669 throw new ApplicationException("when attribute pagetype has value [custom], the attributes [pageheight, pagewidth] must have a positive numeric value"); 670 pagetype=new Dimension(PDFDocument.toPoint(pagewidth,unitFactor),PDFDocument.toPoint(pageheight,unitFactor)); 671 } 672 // page orientation 673 if(isLandscape)pagetype=new Dimension(pagetype.height, pagetype.width); 674 return pagetype; 675 } 676 677 678 private boolean isCustom(Dimension d) throws ApplicationException { 679 if(d.height<=0 || d.width<=0) 680 throw new ApplicationException("if you define pagetype as custom, you have to define attribute pageheight and pagewith with a positive numeric value"); 681 682 683 return (d.width+d.height)==2; 684 } 685 686 /** 687 * sets if has body or not 688 * @param hasBody 689 */ 690 public void hasBody(boolean hasBody) { 691 692 } 693 694 695 696 } 697 698