1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 package complex.framework.autosave; 29 30 // __________ Imports __________ 31 32 // structs, const, ... 33 import com.sun.star.beans.PropertyValue; 34 import com.sun.star.bridge.XUnoUrlResolver; 35 36 // exceptions 37 import com.sun.star.container.NoSuchElementException; 38 import com.sun.star.uno.Exception; 39 import com.sun.star.uno.RuntimeException; 40 import java.io.IOException; 41 import java.lang.InterruptedException; 42 import java.net.ConnectException; 43 44 // interfaces 45 import com.sun.star.lang.XMultiServiceFactory; 46 import com.sun.star.uno.Any; 47 48 // helper 49 import com.sun.star.uno.IBridge; 50 import com.sun.star.uno.UnoRuntime; 51 52 // others 53 import javax.swing.*; 54 import javax.swing.border.*; 55 import java.awt.*; 56 import java.lang.*; 57 import java.io.*; 58 import java.util.*; 59 import java.sql.*; 60 61 // __________ Implementation __________ 62 63 /** 64 * Implements a log mechanism to create a protocol of all steps of e.g. an api test 65 * It provides the possibility to write the logged meesages to a file and/or 66 * to stdout/stderr (if neccessary at the same time!). 67 * 68 * TODO 69 * - implement filter, which e.g. supress showing of INFO data 70 */ 71 public class Protocol extends JComponent 72 { 73 // ____________________ 74 /** 75 * Note: Following values can be combined - they are interpreted as flags. 76 * 77 * @const MODE_STDOUT messages are logged to stdout 78 * @const MODE_STDERR messages are logged to stderr 79 * @const MODE_ASCII messages are logged to an ascii file 80 * @const MODE_HTML messages are logged to a html file 81 * 82 * @const TYPE_SCOPE_OPEN open, mark or count a new scope for following log statements 83 * @const TYPE_SCOPE_CLOSE close, mark or count the current scope 84 * @const TYPE_TESTMARK it marks the beginning of a (sub)test, can be used for statistic purposes 85 * @const TYPE_OK this protocol line is marked as a OK message 86 * @const TYPE_ERROR this protocol line is marked as an error 87 * @const TYPE_WARNING this protocol line is marked as a warning 88 * @const TYPE_INFO this protocol line represent some debug data for analyzing 89 */ 90 public static final int MODE_STDOUT = 1; 91 public static final int MODE_STDERR = 2; 92 public static final int MODE_ASCII = 4; 93 public static final int MODE_HTML = 8; 94 95 public static final int TYPE_OK = 1; 96 public static final int TYPE_ERROR = 2; 97 public static final int TYPE_WARNING = 4; 98 public static final int TYPE_INFO = 8; 99 public static final int TYPE_SCOPE_OPEN = 16; 100 public static final int TYPE_SCOPE_CLOSE = 32; 101 public static final int TYPE_TESTMARK = 64; 102 public static final int TYPE_ERROR_INFO = 128; 103 public static final int TYPE_WARNING_INFO = 256; 104 public static final int TYPE_STATISTIC = 512; 105 public static final int TYPE_LINK = 1024; 106 107 public static final int FILTER_NONE = 0; 108 public static final int FILTER_OK = TYPE_OK; 109 public static final int FILTER_ERROR = TYPE_ERROR; 110 public static final int FILTER_WARNING = TYPE_WARNING; 111 public static final int FILTER_INFO = TYPE_INFO; 112 public static final int FILTER_SCOPES = TYPE_SCOPE_OPEN | TYPE_SCOPE_CLOSE; 113 public static final int FILTER_TESTMARK = TYPE_TESTMARK; 114 public static final int FILTER_ERROR_INFO = TYPE_ERROR_INFO; 115 public static final int FILTER_WARNING_INFO = TYPE_WARNING_INFO; 116 public static final int FILTER_STATISTIC = TYPE_STATISTIC; 117 public static final int FILTER_LINK = TYPE_LINK; 118 119 // ____________________ 120 /** 121 */ 122 private static final int MARK_DIFF = 5; 123 124 private static final String BGCOLOR_LINECOL = "#95CC77"; 125 private static final String FGCOLOR_LINECOL_NORMAL = "#ffffbd"; 126 private static final String FGCOLOR_LINECOL_MARKED = "#000088"; 127 128 private static final String BGCOLOR_STANDARD = "#ffffff"; 129 private static final String FGCOLOR_STANDARD = "#000000"; 130 131 private static final String BGCOLOR_SCOPE = "#eeeeee"; 132 private static final String FGCOLOR_SCOPE = "#000000"; 133 134 private static final String BGCOLOR_TIMESTAMP = "#e0e0e0"; 135 private static final String FGCOLOR_TIMESTAMP = "#000000"; 136 137 private static final String BGCOLOR_TESTMARK = "#0000ff"; 138 private static final String FGCOLOR_TESTMARK = "#ffffff"; 139 140 private static final String BGCOLOR_OK = "#88dd88"; 141 private static final String FGCOLOR_OK = "#ffffff"; 142 143 private static final String BGCOLOR_WARNING = "#ffff00"; 144 private static final String FGCOLOR_WARNING = "#000000"; 145 146 private static final String BGCOLOR_WARNING_INFO = "#ffffcc"; 147 private static final String FGCOLOR_WARNING_INFO = "#000000"; 148 149 private static final String BGCOLOR_ERROR = "#ff0000"; 150 private static final String FGCOLOR_ERROR = "#ffff00"; 151 152 private static final String BGCOLOR_ERROR_INFO = "#ffbbbb"; 153 private static final String FGCOLOR_ERROR_INFO = "#000000"; 154 155 private static final String BGCOLOR_INFO = "#eeeeee"; 156 private static final String FGCOLOR_INFO = "#000000"; 157 158 private static final String BGCOLOR_STATISTIC = "#0000ff"; 159 private static final String FGCOLOR_STATISTIC = "#ffffff"; 160 161 private static final String BGCOLOR_LINK = BGCOLOR_INFO; 162 private static final String FGCOLOR_LINK = FGCOLOR_INFO; 163 164 // ____________________ 165 /** 166 * @member m_nMode the mode, in which this protocol object runs 167 * @member m_nFilter can be used to filter log messages by type 168 * @member m_sFileName we need it to open the log file on demand (if nMode require such log file) 169 * @member m_nLine used as line number for the protocol 170 * @member m_nScope used to format scopes 171 * @member m_nErrors count errors in protocol 172 * @member m_nWarnings count warnings in protocol 173 * @member m_nTestMarks count test marker in protocol 174 */ 175 private int m_nMode ; 176 private int m_nFilter ; 177 private String m_sFileName ; 178 private long m_nLine ; 179 private long m_nScope ; 180 private long m_nErrors ; 181 private long m_nWarnings ; 182 private long m_nTestMarks; 183 private Timestamp m_aStartTime; 184 private Timestamp m_aEndTime ; 185 186 // ____________________ 187 /** 188 * special helper class to represent one line of a protocol. 189 * Such line can be specified as a special one (ERROR, WARNING ...). 190 * That makes it possible to analyze the whole protocol using tools. 191 */ 192 class ProtocolLine 193 { 194 /// the line number of this protocol line (size of the vector of all protocol lines cn be used to count such lines!) 195 private long m_nLine; 196 /// deepness of the current scope 197 private long m_nScope; 198 /// mark line as an error, warning, data entry ... (see const definitions before) 199 private int m_nType; 200 /// of course, we have to know the logged message too :-) 201 private String m_sMessage; 202 /// and it can be usefull to know the current time, when this line was created 203 private Timestamp m_aStamp; 204 205 /** ctor for fast initializing of such line */ 206 public ProtocolLine( long nLine , 207 long nScope , 208 int nType , 209 String sMessage ) 210 { 211 m_aStamp = new Timestamp(System.currentTimeMillis()); 212 m_nLine = nLine ; 213 m_nScope = nScope ; 214 m_nType = nType ; 215 m_sMessage = sMessage; 216 } 217 218 /** format this line as an ascii string for writing log files */ 219 public synchronized String toString() 220 { 221 StringBuffer sLine = new StringBuffer(1000); 222 223 // insert line number 224 // Use right bound notation and format 6 digits! 225 sLine.append("[" ); 226 if (m_nLine<10) 227 sLine.append(" "); 228 else 229 if (m_nLine<100) 230 sLine.append(" "); 231 else 232 if (m_nLine<1000) 233 sLine.append(" "); 234 else 235 if (m_nLine<10000) 236 sLine.append(" "); 237 else 238 if (m_nLine<100000) 239 sLine.append(" "); 240 sLine.append(m_nLine); 241 sLine.append("] " ); 242 243 // add time stamp 244 // close with a "TAB" ... because some time stamps are not normalized to 245 // a well defined string length .-) 246 sLine.append(m_aStamp.toString()+" \t"); 247 248 // add special line type 249 if ((m_nType & TYPE_OK) == TYPE_OK) 250 sLine.append(" OK "); 251 else 252 if ((m_nType & TYPE_ERROR) == TYPE_ERROR) 253 sLine.append(" ERROR "); 254 else 255 if ((m_nType & TYPE_ERROR_INFO) == TYPE_ERROR_INFO) 256 sLine.append(" ERROR INFO "); 257 else 258 if ((m_nType & TYPE_WARNING) == TYPE_WARNING) 259 sLine.append(" WARNING "); 260 else 261 if ((m_nType & TYPE_WARNING_INFO) == TYPE_WARNING_INFO) 262 sLine.append(" WARNING INFO "); 263 else 264 if ((m_nType & TYPE_INFO) == TYPE_INFO) 265 sLine.append(" INFO "); 266 else 267 if ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK) 268 sLine.append(" TEST "); 269 else 270 if ((m_nType & TYPE_LINK) == TYPE_LINK) 271 sLine.append(" LINK "); 272 else 273 if ((m_nType & TYPE_STATISTIC) == TYPE_STATISTIC) 274 sLine.append(" STATISTIC "); 275 else 276 if ( 277 ((m_nType & TYPE_SCOPE_OPEN ) == TYPE_SCOPE_OPEN ) || 278 ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) 279 ) 280 sLine.append(" SCOPE "); 281 else 282 sLine.append(" "); 283 284 // add scope information 285 for (int s=0; s<m_nScope; ++s) 286 sLine.append(" "); 287 288 if ((m_nType & TYPE_SCOPE_OPEN) == TYPE_SCOPE_OPEN) 289 sLine.append(" { "); 290 else 291 if ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) 292 sLine.append(" } "); 293 else 294 sLine.append(" "); 295 296 // add message 297 sLine.append(m_sMessage); 298 sLine.append("\n" ); 299 300 return sLine.toString(); 301 } 302 303 /** 304 * format this line as a string for writing log files 305 * using the html format 306 */ 307 public synchronized String toHTML() 308 { 309 StringBuffer sLine = new StringBuffer(1000); 310 sLine.append("<tr>"); 311 312 // insert line number 313 if (m_nLine % MARK_DIFF == 0) 314 impl_generateColoredHTMLCell(sLine, new Long(m_nLine).toString(), BGCOLOR_LINECOL, FGCOLOR_LINECOL_MARKED, true); 315 else 316 impl_generateColoredHTMLCell(sLine, new Long(m_nLine).toString(), BGCOLOR_LINECOL, FGCOLOR_LINECOL_NORMAL, false); 317 318 // add time stamp 319 impl_generateColoredHTMLCell(sLine, m_aStamp.toString()+" ", BGCOLOR_TIMESTAMP, FGCOLOR_TIMESTAMP, false); 320 321 // add log type info 322 boolean bTypeCellFilled = false; 323 if ((m_nType & TYPE_ERROR_INFO) == TYPE_ERROR_INFO) 324 { 325 impl_generateColoredHTMLCell(sLine, "ERROR INFO", BGCOLOR_ERROR_INFO, FGCOLOR_ERROR_INFO, false); 326 bTypeCellFilled = true; 327 } 328 else 329 if ((m_nType & TYPE_ERROR) == TYPE_ERROR) 330 { 331 impl_generateColoredHTMLCell(sLine, "ERROR", BGCOLOR_ERROR, FGCOLOR_ERROR, true); 332 bTypeCellFilled = true; 333 } 334 else 335 if ((m_nType & TYPE_WARNING_INFO) == TYPE_WARNING_INFO) 336 { 337 impl_generateColoredHTMLCell(sLine, "WARNING INFO", BGCOLOR_WARNING_INFO, FGCOLOR_WARNING_INFO, false); 338 bTypeCellFilled = true; 339 } 340 else 341 if ((m_nType & TYPE_WARNING) == TYPE_WARNING) 342 { 343 impl_generateColoredHTMLCell(sLine, "WARNING", BGCOLOR_WARNING, FGCOLOR_WARNING, true); 344 bTypeCellFilled = true; 345 } 346 else 347 if ((m_nType & TYPE_OK) == TYPE_OK) 348 { 349 impl_generateColoredHTMLCell(sLine, "OK", BGCOLOR_OK, FGCOLOR_OK, true); 350 bTypeCellFilled = true; 351 } 352 else 353 if ((m_nType & TYPE_INFO) == TYPE_INFO) 354 { 355 impl_generateColoredHTMLCell(sLine, "INFO", BGCOLOR_INFO, FGCOLOR_INFO, false); 356 bTypeCellFilled = true; 357 } 358 else 359 if ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK) 360 { 361 impl_generateColoredHTMLCell(sLine, "TEST", BGCOLOR_TESTMARK, FGCOLOR_TESTMARK, true); 362 bTypeCellFilled = true; 363 } 364 else 365 if ((m_nType & TYPE_STATISTIC) == TYPE_STATISTIC) 366 { 367 impl_generateColoredHTMLCell(sLine, "STATISTIC", BGCOLOR_STATISTIC, FGCOLOR_STATISTIC, false); 368 bTypeCellFilled = true; 369 } 370 else 371 if ((m_nType & TYPE_LINK) == TYPE_LINK) 372 { 373 impl_generateColoredHTMLCell(sLine, "LINK", BGCOLOR_LINK, FGCOLOR_LINK, false); 374 bTypeCellFilled = true; 375 } 376 else 377 if ( 378 ((m_nType & TYPE_SCOPE_OPEN ) == TYPE_SCOPE_OPEN ) || 379 ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) 380 ) 381 { 382 impl_generateColoredHTMLCell(sLine, "SCOPE", BGCOLOR_SCOPE, FGCOLOR_SCOPE, false); 383 bTypeCellFilled = true; 384 } 385 386 // if no tyope information was added to the current coloum, we must 387 // write any content into this cell. Otherwise some browser 388 // shows a strange layout! 389 if (! bTypeCellFilled) 390 impl_generateColoredHTMLCell(sLine, " ", BGCOLOR_STANDARD, FGCOLOR_STANDARD, false); 391 392 // add scope information 393 sLine.append("<td>"); 394 for (int s=0; s<m_nScope; ++s) 395 sLine.append(" "); 396 String sColor = "#000000"; 397 if ((m_nScope % 2) == 0) 398 sColor = "#808080"; 399 if ((m_nType & TYPE_SCOPE_OPEN) == TYPE_SCOPE_OPEN) 400 sLine.append("<font color=\""+sColor+"\">{ "+m_nScope+"</font>"); 401 else 402 if ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) 403 sLine.append("<font color=\""+sColor+"\">"+m_nScope+" }</font>"); 404 sLine.append("</td>\n"); 405 406 // add message 407 sLine.append("<td>" ); 408 sLine.append(m_sMessage); 409 sLine.append("</td>\n" ); 410 411 sLine.append("</tr>\n" ); 412 413 return sLine.toString(); 414 } 415 416 /** detect, if this line object represent an error */ 417 public synchronized boolean isError() 418 { 419 return ( 420 ((m_nType & TYPE_ERROR) == TYPE_ERROR) && 421 ((m_nType & TYPE_INFO ) != TYPE_INFO ) 422 ); 423 } 424 425 /** detect, if this line object represent a warning */ 426 public synchronized boolean isWarning() 427 { 428 return ( 429 ((m_nType & TYPE_WARNING) == TYPE_WARNING) && 430 ((m_nType & TYPE_INFO ) != TYPE_INFO ) 431 ); 432 } 433 434 /** detect, if this line object represent a marked position */ 435 public synchronized boolean isTestMark() 436 { 437 return ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK); 438 } 439 440 /** 441 * create a colored table cell formated as HTML. 442 * 443 * @param sCell 444 * an outside string buffer, which can be 445 * used to generate the 446 * needed HTML code there. 447 * 448 * @param sContent 449 * the text content of this cell. 450 * 451 * @param sBGColor 452 * a string, which represent the background color 453 * coded in HTML. 454 * 455 * @param sFGColor 456 * a string, which represent the foreground color 457 * coded in HTML. 458 * 459 * @param bBold 460 * enable/disable bold state for the text content. 461 */ 462 private void impl_generateColoredHTMLCell(StringBuffer sCell , 463 String sContent, 464 String sBGColor, 465 String sFGColor, 466 boolean bBold ) 467 { 468 sCell.append("<td bgcolor=\""+sBGColor+"\">"); 469 sCell.append("<font color=\""+sFGColor+"\">"); 470 if (bBold) 471 sCell.append("<b>"); 472 sCell.append(sContent); 473 if (bBold) 474 sCell.append("</b>"); 475 sCell.append("</font></td>\n"); 476 } 477 } 478 479 // ____________________ 480 /** 481 * ctor 482 * It creates a new instance of this class and innitialize it in the right mode. 483 * 484 * @param nMode 485 * specify how the log should be generated. 486 * 487 * @param nFilter 488 * can be used to filter log messages by it's type. 489 * 490 * @param sFileName 491 * the name of the log file (if nMode requires a log file) 492 */ 493 public Protocol(int nMode , 494 int nFilter , 495 String sFileName) 496 { 497 m_nMode = nMode; 498 m_nFilter = nFilter; 499 m_sFileName = sFileName; 500 m_nLine = 0; 501 m_nScope = 1; 502 m_nWarnings = 0; 503 m_nErrors = 0; 504 m_aStartTime = new Timestamp(System.currentTimeMillis()); 505 } 506 507 // ____________________ 508 /** 509 * For some modes it's neccessary, that we write some additional 510 * informations to the log. E.g. for html we must generate close targets. 511 */ 512 public synchronized void finish() 513 { 514 // Preferr HTML ... because we can't write ASCII and HTML contents to the same log file! 515 String sContent; 516 if ((m_nMode & MODE_HTML) == MODE_HTML) 517 sContent = impl_generateHTMLFooter(); 518 else 519 if ((m_nMode & MODE_ASCII) == MODE_ASCII) 520 sContent = impl_generateAsciiFooter(); 521 else 522 return; 523 524 impl_writeToLogFile(m_sFileName, true, sContent); 525 } 526 527 // ____________________ 528 /** 529 * log an unspecified message. 530 * 531 * Sometimes it's not neccessary to set a special type for an message. 532 * The pure message seams to be enough. The type of such "pure messages" 533 * will be set to INFO. 534 * 535 * @param sMessage 536 * the pure message 537 * 538 * @see log(type,message) 539 */ 540 public synchronized void log( /*IN*/ String sMessage ) 541 { 542 log(TYPE_INFO, sMessage); 543 } 544 545 // ____________________ 546 /** 547 * log an exception. 548 * 549 * It uses all informations available by this exception object 550 * to generate the log. So exceptions are printed out using a 551 * standard format. 552 * 553 * @param exThrowable 554 * the exception 555 */ 556 public synchronized void log( /*IN*/ Throwable exThrowable ) 557 { 558 log(TYPE_SCOPE_OPEN | TYPE_ERROR, "exception \""+exThrowable.getMessage()+"\""); 559 560 StackTraceElement[] lStack = exThrowable.getStackTrace(); 561 for (int i=0; i<lStack.length; ++i) 562 log(TYPE_ERROR_INFO, lStack[i].toString()); 563 564 log(TYPE_SCOPE_CLOSE | TYPE_ERROR_INFO, ""); 565 } 566 567 // ____________________ 568 /** 569 * log different property arrays. 570 * 571 * @param lProps 572 * the array of properties 573 */ 574 public synchronized void log( /*IN*/ com.sun.star.beans.NamedValue[] lProps ) 575 { 576 StringBuffer sValues = new StringBuffer(1000); 577 impl_logPropertyArray(sValues, lProps); 578 579 log(TYPE_SCOPE_OPEN | TYPE_INFO, "property array ["+lProps.length+"]:"); 580 log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValues.toString() ); 581 } 582 583 public synchronized void log( /*IN*/ com.sun.star.beans.PropertyValue[] lProps ) 584 { 585 StringBuffer sValues = new StringBuffer(1000); 586 impl_logPropertyArray(sValues, lProps); 587 588 log(TYPE_SCOPE_OPEN | TYPE_INFO, "property array ["+lProps.length+"]:"); 589 log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValues.toString() ); 590 } 591 592 public synchronized void log( /*IN*/ com.sun.star.beans.NamedValue aProp ) 593 { 594 StringBuffer sValue = new StringBuffer(1000); 595 impl_logProperty(sValue, aProp); 596 597 log(TYPE_SCOPE_OPEN | TYPE_INFO, "property:" ); 598 log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValue.toString()); 599 } 600 601 public synchronized void log( /*IN*/ com.sun.star.beans.PropertyValue aProp ) 602 { 603 StringBuffer sValue = new StringBuffer(1000); 604 impl_logProperty(sValue, aProp); 605 606 log(TYPE_SCOPE_OPEN | TYPE_INFO, "property:" ); 607 log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValue.toString()); 608 } 609 610 public synchronized void log( /*IN*/ Object aAny ) 611 { 612 StringBuffer sValue = new StringBuffer(1000); 613 impl_logAny(sValue, aAny); 614 615 log(TYPE_SCOPE_OPEN | TYPE_INFO, "any:" ); 616 log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValue.toString()); 617 } 618 619 // ____________________ 620 /** 621 * log a message. 622 * 623 * It looks for the internal set mode and decide, how this message 624 * will be handled. Then it generates a special object which represent 625 * one protocol line, format it and print it out. 626 * 627 * @param nType 628 * mark a line as a special one or open/close scopes 629 * 630 * @param sMessage 631 * the message, which the outside code wish to be written into the log 632 */ 633 public synchronized void log( /*IN*/ int nType , 634 /*IN*/ String sMessage ) 635 { 636 nType = (nType & ~m_nFilter); 637 if (nType == 0) 638 return; 639 640 ++m_nLine; 641 642 // it's neccessary to open scopes before creatig the protocol line 643 // to guarantee right tab handling for new scope value! 644 if ((nType & TYPE_SCOPE_OPEN) == TYPE_SCOPE_OPEN) 645 ++m_nScope; 646 647 // create the protocol line 648 ProtocolLine aLine = new ProtocolLine(m_nLine, m_nScope, nType, sMessage); 649 String sAsciiLog = aLine.toString(); 650 String sHTMLLog = aLine.toHTML(); 651 652 // it's neccessary to close scope after creatig the protocol line 653 // to guarantee right tab handling for old scope value! 654 if ( 655 ( m_nScope > 0 ) && 656 ((nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) 657 ) 658 { 659 --m_nScope; 660 } 661 662 // update statistic values 663 if (aLine.isTestMark()) 664 ++m_nTestMarks; 665 if (aLine.isWarning()) 666 ++m_nWarnings; 667 if (aLine.isError()) 668 ++m_nErrors; 669 670 // no else - it's a bit field of possible reactions! 671 if ((m_nMode & MODE_STDOUT) == MODE_STDOUT) 672 System.out.print(sAsciiLog); 673 // no else - it's a bit field of possible reactions! 674 if ((m_nMode & MODE_STDERR) == MODE_STDERR) 675 System.err.print(sAsciiLog); 676 // no else - it's a bit field of possible reactions! 677 // But these both conditions must be handled together. 678 // Because we cant generate different types of log contents to the same log file. 679 // We preferr HTML if both types are set. 680 if ( 681 ((m_nMode & MODE_HTML ) == MODE_HTML ) || 682 ((m_nMode & MODE_ASCII) == MODE_ASCII) 683 ) 684 { 685 boolean bAppend = (m_nLine>1); 686 String sContent; 687 if ((m_nMode & MODE_HTML) == MODE_HTML) 688 { 689 if (! bAppend) 690 sContent = impl_generateHTMLHeader()+sHTMLLog; 691 else 692 sContent = sHTMLLog; 693 } 694 else 695 { 696 if (! bAppend) 697 sContent = impl_generateAsciiHeader()+sAsciiLog; 698 else 699 sContent = sAsciiLog; 700 } 701 702 impl_writeToLogFile(m_sFileName, bAppend, sContent); 703 } 704 } 705 706 // ____________________ 707 public synchronized void defineHyperlink( /*IN*/ String sTarget , 708 /*IN*/ String sDescription) 709 { 710 if ((m_nMode & MODE_HTML) != MODE_HTML) 711 return; 712 713 StringBuffer sLog = new StringBuffer(1000); 714 sLog.append("<a href=\""); 715 sLog.append(sTarget ); 716 sLog.append("\">" ); 717 sLog.append(sDescription); 718 sLog.append("</a>" ); 719 720 log(TYPE_LINK, sLog.toString()); 721 } 722 723 // ____________________ 724 /** 725 * log the current statistic values 726 * We write it into our protocol buffer and 727 * reset it. 728 */ 729 public synchronized void logStatistics() 730 { 731 m_aEndTime = new Timestamp(System.currentTimeMillis()); 732 Timestamp aDiff = new Timestamp(m_aEndTime.getTime()-m_aStartTime.getTime()); 733 734 int nLogType = TYPE_STATISTIC; 735 if (m_nErrors > 0) 736 nLogType = TYPE_ERROR_INFO; 737 else 738 if (m_nWarnings > 0) 739 nLogType = TYPE_WARNING_INFO; 740 741 log(nLogType | TYPE_SCOPE_OPEN , "statistic:" ); 742 log(nLogType , "tests = "+m_nTestMarks ); 743 log(nLogType , "errors = "+m_nErrors ); 744 log(nLogType , "warnings = "+m_nWarnings ); 745 log(nLogType , "elapsed time = "+aDiff.toString()); 746 log(nLogType | TYPE_SCOPE_CLOSE, "" ); 747 748 resetStatistics(); 749 } 750 751 public synchronized void resetStatistics() 752 { 753 m_nTestMarks = 0; 754 m_nWarnings = 0; 755 m_nErrors = 0; 756 m_aStartTime = new Timestamp(System.currentTimeMillis()); 757 } 758 759 // ____________________ 760 /** 761 * returns a generic html header for generating html log files 762 * 763 * It's used from the method finish() to generate a valid html formated file. 764 * For that its neccessary to open some special html targets like e.g. <html>. 765 * 766 * @return A string, which includes the whole header. 767 * 768 * @see finish() 769 * @see generateHTMLFooter() 770 */ 771 private String impl_generateHTMLHeader() 772 { 773 return "<html>\n<head>\n<title>"+m_sFileName+"</title>\n</head>\n<body>\n<table>\n"; 774 } 775 776 private String impl_generateAsciiHeader() 777 { 778 return "********************************************************************************\n"; 779 } 780 781 private String impl_generateHTMLFooter() 782 { 783 return "\n</table>\n</body>\n</html>\n"; 784 } 785 786 private String impl_generateAsciiFooter() 787 { 788 return "\n\n"; 789 } 790 791 // ____________________ 792 /** 793 * helper to log different representations of a property(array) 794 * 795 * @param sOut 796 * used to generate the log output there. 797 * 798 * @param lProps/aProp 799 * represent the property(array) to be logged. 800 */ 801 private void impl_logPropertyArray( /*OUT*/ StringBuffer sOut , 802 /*IN */ com.sun.star.beans.PropertyValue[] lProps ) 803 { 804 int i = 0; 805 int c = lProps.length; 806 807 for (i=0; i<c; ++i) 808 impl_logProperty(sOut, lProps[i]); 809 } 810 811 private void impl_logPropertyArray( /*OUT*/ StringBuffer sOut , 812 /*IN */ com.sun.star.beans.NamedValue[] lProps ) 813 { 814 int i = 0; 815 int c = lProps.length; 816 817 for (i=0; i<c; ++i) 818 impl_logProperty(sOut, lProps[i]); 819 } 820 821 private void impl_logProperty( /*OUT*/ StringBuffer sOut , 822 /*IN*/ com.sun.star.beans.NamedValue aProp ) 823 { 824 sOut.append("\""+aProp.Name+"\" = "); 825 impl_logAny(sOut, aProp.Value); 826 } 827 828 private void impl_logProperty( /*OUT*/ StringBuffer sOut , 829 /*IN*/ com.sun.star.beans.PropertyValue aProp ) 830 { 831 sOut.append("\""+aProp.Name+"\" = "); 832 impl_logAny(sOut, aProp.Value); 833 } 834 835 // ____________________ 836 /** 837 * it trys to convert the given any into a suitable string notation .-) 838 */ 839 private synchronized void impl_logAny( /*OUT*/ StringBuffer sOut , 840 /*IN */ Object aAny ) 841 { 842 try 843 { 844 if (com.sun.star.uno.AnyConverter.isVoid(aAny)) 845 { 846 sOut.append("[void] {"); 847 } 848 else 849 if (com.sun.star.uno.AnyConverter.isChar(aAny)) 850 { 851 sOut.append("[char] {"); 852 sOut.append(com.sun.star.uno.AnyConverter.toChar(aAny)); 853 sOut.append("}"); 854 } 855 else 856 if (com.sun.star.uno.AnyConverter.isBoolean(aAny)) 857 { 858 sOut.append("[boolean] {"); 859 if (com.sun.star.uno.AnyConverter.toBoolean(aAny)) 860 sOut.append("TRUE"); 861 else 862 sOut.append("FALSE"); 863 sOut.append("}"); 864 } 865 else 866 if (com.sun.star.uno.AnyConverter.isByte(aAny)) 867 { 868 sOut.append("[byte] {"); 869 sOut.append(com.sun.star.uno.AnyConverter.toByte(aAny)); 870 sOut.append("}"); 871 } 872 else 873 if (com.sun.star.uno.AnyConverter.isShort(aAny)) 874 { 875 sOut.append("[short] {"); 876 sOut.append(com.sun.star.uno.AnyConverter.toShort(aAny)); 877 sOut.append("}"); 878 } 879 else 880 if (com.sun.star.uno.AnyConverter.isInt(aAny)) 881 { 882 sOut.append("[int] {"); 883 sOut.append(com.sun.star.uno.AnyConverter.toInt(aAny)); 884 sOut.append("}"); 885 } 886 else 887 if (com.sun.star.uno.AnyConverter.isLong(aAny)) 888 { 889 sOut.append("[long] {"); 890 sOut.append(com.sun.star.uno.AnyConverter.toLong(aAny)); 891 sOut.append("}"); 892 } 893 else 894 if (com.sun.star.uno.AnyConverter.isFloat(aAny)) 895 { 896 sOut.append("[float] {"); 897 sOut.append(com.sun.star.uno.AnyConverter.toFloat(aAny)); 898 sOut.append("}"); 899 } 900 else 901 if (com.sun.star.uno.AnyConverter.isDouble(aAny)) 902 { 903 sOut.append("[double] {"); 904 sOut.append(com.sun.star.uno.AnyConverter.toDouble(aAny)); 905 sOut.append("}"); 906 } 907 else 908 if (com.sun.star.uno.AnyConverter.isString(aAny)) 909 { 910 sOut.append("[string] {"); 911 sOut.append(com.sun.star.uno.AnyConverter.toString(aAny)); 912 sOut.append("}"); 913 } 914 else 915 if (com.sun.star.uno.AnyConverter.isEnum(aAny)) 916 { 917 sOut.append("[enum] {"); 918 sOut.append("}"); 919 } 920 else 921 if (com.sun.star.uno.AnyConverter.isType(aAny)) 922 { 923 sOut.append("[type] {"); 924 sOut.append("}"); 925 } 926 else 927 if (com.sun.star.uno.AnyConverter.isArray(aAny)) 928 { 929 if (aAny instanceof java.lang.String[]) 930 { 931 sOut.append("[sequence< string >] {"); 932 sOut.append("}"); 933 } 934 else 935 if (aAny instanceof com.sun.star.beans.PropertyValue[]) 936 { 937 sOut.append("[sequence< PropertyValue >] {"); 938 com.sun.star.beans.PropertyValue[] lSubProps = (com.sun.star.beans.PropertyValue[])com.sun.star.uno.AnyConverter.toArray(aAny); 939 impl_logPropertyArray(sOut, lSubProps); 940 sOut.append("}"); 941 } 942 else 943 if (aAny instanceof com.sun.star.beans.NamedValue[]) 944 { 945 sOut.append("[sequence< NamedValue >] {"); 946 com.sun.star.beans.NamedValue[] lSubProps = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(aAny); 947 impl_logPropertyArray(sOut, lSubProps); 948 sOut.append("}"); 949 } 950 else 951 { 952 sOut.append("[unknown array] {-}"); 953 } 954 } 955 else 956 if (com.sun.star.uno.AnyConverter.isObject(aAny)) 957 { 958 sOut.append("[object] {"); 959 // TODO 960 sOut.append("}"); 961 } 962 963 if ((m_nMode & MODE_HTML) == MODE_HTML) 964 sOut.append("<br>"); 965 else 966 sOut.append("\n"); 967 } 968 catch(com.sun.star.lang.IllegalArgumentException exIll) 969 { 970 sOut.append("Got exception during property conversion.\n"); 971 sOut.append(exIll.getMessage()); 972 sOut.append("\n"); 973 } 974 } 975 976 // ____________________ 977 /** 978 * Writes the given content to the specified log file. 979 */ 980 private void impl_writeToLogFile(String sFileName, 981 boolean bAppend , 982 String sContent ) 983 { 984 try 985 { 986 FileWriter aLogFile = new FileWriter(sFileName, bAppend); 987 aLogFile.write(sContent); 988 aLogFile.flush(); 989 aLogFile.close(); 990 aLogFile = null; 991 } 992 catch (java.io.IOException exIO) 993 { 994 System.err.println("Can't dump protocol into log file."); 995 System.err.println(exIO); 996 exIO.printStackTrace(); 997 } 998 } 999 } 1000