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