1    
2    /*
3     * ====================================================================
4     * The Apache Software License, Version 1.1
5     *
6     * Copyright (c) 2002 The Apache Software Foundation.  All rights
7     * reserved.
8     *
9     * Redistribution and use in source and binary forms, with or without
10    * modification, are permitted provided that the following conditions
11    * are met:
12    *
13    * 1. Redistributions of source code must retain the above copyright
14    *    notice, this list of conditions and the following disclaimer.
15    *
16    * 2. Redistributions in binary form must reproduce the above copyright
17    *    notice, this list of conditions and the following disclaimer in
18    *    the documentation and/or other materials provided with the
19    *    distribution.
20    *
21    * 3. The end-user documentation included with the redistribution,
22    *    if any, must include the following acknowledgment:
23    *       "This product includes software developed by the
24    *        Apache Software Foundation (http://www.apache.org/)."
25    *    Alternately, this acknowledgment may appear in the software itself,
26    *    if and wherever such third-party acknowledgments normally appear.
27    *
28    * 4. The names "Apache" and "Apache Software Foundation" and
29    *    "Apache POI" must not be used to endorse or promote products
30    *    derived from this software without prior written permission. For
31    *    written permission, please contact apache@apache.org.
32    *
33    * 5. Products derived from this software may not be called "Apache",
34    *    "Apache POI", nor may "Apache" appear in their name, without
35    *    prior written permission of the Apache Software Foundation.
36    *
37    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48    * SUCH DAMAGE.
49    * ====================================================================
50    *
51    * This software consists of voluntary contributions made by many
52    * individuals on behalf of the Apache Software Foundation.  For more
53    * information on the Apache Software Foundation, please see
54    * <http://www.apache.org/>.
55    */
56   package org.apache.poi.util;
57   
58   import org.apache.commons.logging.Log;
59   
60   import java.util.*;
61   
62   /**
63    * A logger class that strives to make it as easy as possible for
64    * developers to write log calls, while simultaneously making those
65    * calls as cheap as possible by performing lazy evaluation of the log
66    * message.<p>
67    *
68    * @author Marc Johnson (mjohnson at apache dot org)
69    * @author Glen Stampoultzis (glens at apache.org)
70    * @author Nicola Ken Barozzi (nicolaken at apache.org)
71    */
72   
73   public class POILogger
74   {
75       private Log             log   = null;
76       public static final int DEBUG = 1;
77       public static final int INFO  = 3;
78       public static final int WARN  = 5;
79       public static final int ERROR = 7;
80       public static final int FATAL = 9;
81   
82       /**
83        * package scope so it cannot be instantiated outside of the util
84        * package. You need a POILogger? Go to the POILogFactory for one
85        *
86        * @param log the object that does the real work of logging
87        */
88   
89       POILogger(final Log log)
90       {
91           this.log = log;
92       }
93   
94       /**
95        * Log a message
96        *
97        * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
98        * @param obj1 The object to log.
99        */
100  
101      public void log(final int level, final Object obj1)
102      {
103          if(level==FATAL)
104          {
105            if(log.isFatalEnabled())
106            {
107              log.fatal(obj1);
108            }
109          }
110          else if(level==ERROR)
111          {
112            if(log.isErrorEnabled())
113            {
114              log.error(obj1);
115            }
116          }
117          else if(level==WARN)
118          {
119            if(log.isWarnEnabled())
120            {
121              log.warn(obj1);
122            }
123          }
124          else if(level==INFO)
125          {
126            if(log.isInfoEnabled())
127            {
128              log.info(obj1);
129            }
130          }
131          else if(level==DEBUG)
132          {
133            if(log.isDebugEnabled())
134            {
135              log.debug(obj1);
136            }
137          }
138          else
139          {
140            if(log.isTraceEnabled())
141            {
142              log.trace(obj1);
143            }
144          }
145  
146      }
147  
148      /**
149       * Check if a logger is enabled to log at the specified level
150       *
151       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
152       * @param obj1 The logger to check.
153       */
154  
155      public boolean check(final Log log, final int level)
156      {
157          if(level==FATAL)
158          {
159            if(log.isFatalEnabled())
160            {
161              return true;
162            }
163          }
164          else if(level==ERROR)
165          {
166            if(log.isErrorEnabled())
167            {
168              return true;
169            }
170          }
171          else if(level==WARN)
172          {
173            if(log.isWarnEnabled())
174            {
175              return true;
176            }
177          }
178          else if(level==INFO)
179          {
180            if(log.isInfoEnabled())
181            {
182              return true;
183            }
184          }
185          else if(level==DEBUG)
186          {
187            if(log.isDebugEnabled())
188            {
189              return true;
190            }
191          }
192  
193          return false;
194  
195      }
196  
197      /**
198       * Log a message. Lazily appends Object parameters together.
199       *
200       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
201       * @param obj1 first object to place in the message
202       * @param obj2 second object to place in the message
203       */
204  
205      public void log(final int level, final Object obj1, final Object obj2)
206      {
207          if (check(log, level))
208          {
209              log(level, new StringBuffer(32).append(obj1).append(obj2));
210          }
211      }
212  
213      /**
214       * Log a message. Lazily appends Object parameters together.
215       *
216       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
217       * @param obj1 first Object to place in the message
218       * @param obj2 second Object to place in the message
219       * @param obj3 third Object to place in the message
220       */
221  
222      public void log(final int level, final Object obj1, final Object obj2,
223                      final Object obj3)
224      {
225          
226  
227          if (check(log, level))
228          {
229              log(level,
230                      new StringBuffer(48).append(obj1).append(obj2)
231                          .append(obj3));
232          }
233      }
234  
235      /**
236       * Log a message. Lazily appends Object parameters together.
237       *
238       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
239       * @param obj1 first Object to place in the message
240       * @param obj2 second Object to place in the message
241       * @param obj3 third Object to place in the message
242       * @param obj4 fourth Object to place in the message
243       */
244  
245      public void log(final int level, final Object obj1, final Object obj2,
246                      final Object obj3, final Object obj4)
247      {
248          
249  
250          if (check(log, level))
251          {
252              log(level,
253                      new StringBuffer(64).append(obj1).append(obj2)
254                          .append(obj3).append(obj4));
255          }
256      }
257  
258      /**
259       * Log a message. Lazily appends Object parameters together.
260       *
261       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
262       * @param obj1 first Object to place in the message
263       * @param obj2 second Object to place in the message
264       * @param obj3 third Object to place in the message
265       * @param obj4 fourth Object to place in the message
266       * @param obj5 fifth Object to place in the message
267       */
268  
269      public void log(final int level, final Object obj1, final Object obj2,
270                      final Object obj3, final Object obj4, final Object obj5)
271      {
272          
273  
274          if (check(log, level))
275          {
276              log(level,
277                      new StringBuffer(80).append(obj1).append(obj2)
278                          .append(obj3).append(obj4).append(obj5));
279          }
280      }
281  
282      /**
283       * Log a message. Lazily appends Object parameters together.
284       *
285       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
286       * @param obj1 first Object to place in the message
287       * @param obj2 second Object to place in the message
288       * @param obj3 third Object to place in the message
289       * @param obj4 fourth Object to place in the message
290       * @param obj5 fifth Object to place in the message
291       * @param obj6 sixth Object to place in the message
292       */
293  
294      public void log(final int level, final Object obj1, final Object obj2,
295                      final Object obj3, final Object obj4, final Object obj5,
296                      final Object obj6)
297      {
298          
299  
300          if (check(log, level))
301          {
302              log(level ,
303                      new StringBuffer(96).append(obj1).append(obj2)
304                          .append(obj3).append(obj4).append(obj5).append(obj6));
305          }
306      }
307  
308      /**
309       * Log a message. Lazily appends Object parameters together.
310       *
311       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
312       * @param obj1 first Object to place in the message
313       * @param obj2 second Object to place in the message
314       * @param obj3 third Object to place in the message
315       * @param obj4 fourth Object to place in the message
316       * @param obj5 fifth Object to place in the message
317       * @param obj6 sixth Object to place in the message
318       * @param obj7 seventh Object to place in the message
319       */
320  
321      public void log(final int level, final Object obj1, final Object obj2,
322                      final Object obj3, final Object obj4, final Object obj5,
323                      final Object obj6, final Object obj7)
324      {
325          
326  
327          if (check(log, level))
328          {
329              log(level,
330                      new StringBuffer(112).append(obj1).append(obj2)
331                          .append(obj3).append(obj4).append(obj5).append(obj6)
332                          .append(obj7));
333          }
334      }
335  
336      /**
337       * Log a message. Lazily appends Object parameters together.
338       *
339       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
340       * @param obj1 first Object to place in the message
341       * @param obj2 second Object to place in the message
342       * @param obj3 third Object to place in the message
343       * @param obj4 fourth Object to place in the message
344       * @param obj5 fifth Object to place in the message
345       * @param obj6 sixth Object to place in the message
346       * @param obj7 seventh Object to place in the message
347       * @param obj8 eighth Object to place in the message
348       */
349  
350      public void log(final int level, final Object obj1, final Object obj2,
351                      final Object obj3, final Object obj4, final Object obj5,
352                      final Object obj6, final Object obj7, final Object obj8)
353      {
354          
355  
356          if (check(log, level))
357          {
358              log(level,
359                      new StringBuffer(128).append(obj1).append(obj2)
360                          .append(obj3).append(obj4).append(obj5).append(obj6)
361                          .append(obj7).append(obj8));
362          }
363      }
364  
365      /**
366       * Log a message
367       *
368       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
369       * @param obj1 The object to log.  This is converted to a string.
370       * @param exception An exception to be logged
371       */
372  
373      public void log(final int level, final Object obj1,
374                      final Throwable exception)
375      {
376          log(level , obj1, exception);
377      }
378  
379      /**
380       * Log a message. Lazily appends Object parameters together.
381       *
382       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
383       * @param obj1 first Object to place in the message
384       * @param obj2 second Object to place in the message
385       * @param exception An exception to be logged
386       */
387  
388      public void log(final int level, final Object obj1, final Object obj2,
389                      final Throwable exception)
390      {
391          
392  
393          if (check(log, level))
394          {
395              log(level, new StringBuffer(32).append(obj1).append(obj2),
396                      exception);
397          }
398      }
399  
400      /**
401       * Log a message. Lazily appends Object parameters together.
402       *
403       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
404       * @param obj1 first Object to place in the message
405       * @param obj2 second Object to place in the message
406       * @param obj3 third object to place in the message
407       * @param exception An error message to be logged
408       */
409  
410      public void log(final int level, final Object obj1, final Object obj2,
411                      final Object obj3, final Throwable exception)
412      {
413          
414  
415          if (check(log, level))
416          {
417              log(level, new StringBuffer(48).append(obj1).append(obj2)
418                  .append(obj3), exception);
419          }
420      }
421  
422      /**
423       * Log a message. Lazily appends Object parameters together.
424       *
425       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
426       * @param obj1 first Object to place in the message
427       * @param obj2 second Object to place in the message
428       * @param obj3 third object to place in the message
429       * @param obj4 fourth object to place in the message
430       * @param exception An exception to be logged
431       */
432  
433      public void log(final int level, final Object obj1, final Object obj2,
434                      final Object obj3, final Object obj4,
435                      final Throwable exception)
436      {
437          
438  
439          if (check(log, level))
440          {
441              log(level, new StringBuffer(64).append(obj1).append(obj2)
442                  .append(obj3).append(obj4), exception);
443          }
444      }
445  
446      /**
447       * Log a message. Lazily appends Object parameters together.
448       *
449       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
450       * @param obj1 first Object to place in the message
451       * @param obj2 second Object to place in the message
452       * @param obj3 third object to place in the message
453       * @param obj4 fourth object to place in the message
454       * @param obj5 fifth object to place in the message
455       * @param exception An exception to be logged
456       */
457  
458      public void log(final int level, final Object obj1, final Object obj2,
459                      final Object obj3, final Object obj4, final Object obj5,
460                      final Throwable exception)
461      {
462          
463  
464          if (check(log, level))
465          {
466              log(level, new StringBuffer(80).append(obj1).append(obj2)
467                  .append(obj3).append(obj4).append(obj5), exception);
468          }
469      }
470  
471      /**
472       * Log a message. Lazily appends Object parameters together.
473       *
474       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
475       * @param obj1 first Object to place in the message
476       * @param obj2 second Object to place in the message
477       * @param obj3 third object to place in the message
478       * @param obj4 fourth object to place in the message
479       * @param obj5 fifth object to place in the message
480       * @param obj6 sixth object to place in the message
481       * @param exception An exception to be logged
482       */
483  
484      public void log(final int level, final Object obj1, final Object obj2,
485                      final Object obj3, final Object obj4, final Object obj5,
486                      final Object obj6, final Throwable exception)
487      {
488          
489  
490          if (check(log, level))
491          {
492              log(level , new StringBuffer(96).append(obj1)
493                  .append(obj2).append(obj3).append(obj4).append(obj5)
494                  .append(obj6), exception);
495          }
496      }
497  
498      /**
499       * Log a message. Lazily appends Object parameters together.
500       *
501       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
502       * @param obj1 first Object to place in the message
503       * @param obj2 second Object to place in the message
504       * @param obj3 third object to place in the message
505       * @param obj4 fourth object to place in the message
506       * @param obj5 fifth object to place in the message
507       * @param obj6 sixth object to place in the message
508       * @param obj7 seventh object to place in the message
509       * @param exception An exception to be logged
510       */
511  
512      public void log(final int level, final Object obj1, final Object obj2,
513                      final Object obj3, final Object obj4, final Object obj5,
514                      final Object obj6, final Object obj7,
515                      final Throwable exception)
516      {
517          
518  
519          if (check(log, level))
520          {
521              log(level, new StringBuffer(112).append(obj1).append(obj2)
522                  .append(obj3).append(obj4).append(obj5).append(obj6)
523                  .append(obj7), exception);
524          }
525      }
526  
527      /**
528       * Log a message. Lazily appends Object parameters together.
529       *
530       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
531       * @param obj1 first Object to place in the message
532       * @param obj2 second Object to place in the message
533       * @param obj3 third object to place in the message
534       * @param obj4 fourth object to place in the message
535       * @param obj5 fifth object to place in the message
536       * @param obj6 sixth object to place in the message
537       * @param obj7 seventh object to place in the message
538       * @param obj8 eighth object to place in the message
539       * @param exception An exception to be logged
540       */
541  
542      public void log(final int level, final Object obj1, final Object obj2,
543                      final Object obj3, final Object obj4, final Object obj5,
544                      final Object obj6, final Object obj7, final Object obj8,
545                      final Throwable exception)
546      {
547          
548  
549          if (check(log, level))
550          {
551              log(level, new StringBuffer(128).append(obj1).append(obj2)
552                  .append(obj3).append(obj4).append(obj5).append(obj6)
553                  .append(obj7).append(obj8), exception);
554          }
555      }
556  
557      /**
558       * Logs a formated message. The message itself may contain %
559       * characters as place holders. This routine will attempt to match
560       * the placeholder by looking at the type of parameter passed to
561       * obj1.<p>
562       *
563       * If the parameter is an array, it traverses the array first and
564       * matches parameters sequentially against the array items.
565       * Otherwise the parameters after <code>message</code> are matched
566       * in order.<p>
567       *
568       * If the place holder matches against a number it is printed as a
569       * whole number. This can be overridden by specifying a precision
570       * in the form %n.m where n is the padding for the whole part and
571       * m is the number of decimal places to display. n can be excluded
572       * if desired. n and m may not be more than 9.<p>
573       *
574       * If the last parameter (after flattening) is a Throwable it is
575       * logged specially.
576       *
577       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
578       * @param message The message to log.
579       * @param obj1 The first object to match against.
580       */
581  
582      public void logFormatted(final int level, final String message,
583                               final Object obj1)
584      {
585          commonLogFormatted(level, message, new Object[]
586          {
587              obj1
588          });
589      }
590  
591      /**
592       * Logs a formated message. The message itself may contain %
593       * characters as place holders. This routine will attempt to match
594       * the placeholder by looking at the type of parameter passed to
595       * obj1.<p>
596       *
597       * If the parameter is an array, it traverses the array first and
598       * matches parameters sequentially against the array items.
599       * Otherwise the parameters after <code>message</code> are matched
600       * in order.<p>
601       *
602       * If the place holder matches against a number it is printed as a
603       * whole number. This can be overridden by specifying a precision
604       * in the form %n.m where n is the padding for the whole part and
605       * m is the number of decimal places to display. n can be excluded
606       * if desired. n and m may not be more than 9.<p>
607       *
608       * If the last parameter (after flattening) is a Throwable it is
609       * logged specially.
610       *
611       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
612       * @param message The message to log.
613       * @param obj1 The first object to match against.
614       * @param obj2 The second object to match against.
615       */
616  
617      public void logFormatted(final int level, final String message,
618                               final Object obj1, final Object obj2)
619      {
620          commonLogFormatted(level, message, new Object[]
621          {
622              obj1, obj2
623          });
624      }
625  
626      /**
627       * Logs a formated message. The message itself may contain %
628       * characters as place holders. This routine will attempt to match
629       * the placeholder by looking at the type of parameter passed to
630       * obj1.<p>
631       *
632       * If the parameter is an array, it traverses the array first and
633       * matches parameters sequentially against the array items.
634       * Otherwise the parameters after <code>message</code> are matched
635       * in order.<p>
636       *
637       * If the place holder matches against a number it is printed as a
638       * whole number. This can be overridden by specifying a precision
639       * in the form %n.m where n is the padding for the whole part and
640       * m is the number of decimal places to display. n can be excluded
641       * if desired. n and m may not be more than 9.<p>
642       *
643       * If the last parameter (after flattening) is a Throwable it is
644       * logged specially.
645       *
646       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
647       * @param message The message to log.
648       * @param obj1 The first object to match against.
649       * @param obj2 The second object to match against.
650       * @param obj3 The third object to match against.
651       */
652  
653      public void logFormatted(final int level, final String message,
654                               final Object obj1, final Object obj2,
655                               final Object obj3)
656      {
657          commonLogFormatted(level, message, new Object[]
658          {
659              obj1, obj2, obj3
660          });
661      }
662  
663      /**
664       * Logs a formated message. The message itself may contain %
665       * characters as place holders. This routine will attempt to match
666       * the placeholder by looking at the type of parameter passed to
667       * obj1.<p>
668       *
669       * If the parameter is an array, it traverses the array first and
670       * matches parameters sequentially against the array items.
671       * Otherwise the parameters after <code>message</code> are matched
672       * in order.<p>
673       *
674       * If the place holder matches against a number it is printed as a
675       * whole number. This can be overridden by specifying a precision
676       * in the form %n.m where n is the padding for the whole part and
677       * m is the number of decimal places to display. n can be excluded
678       * if desired. n and m may not be more than 9.<p>
679       *
680       * If the last parameter (after flattening) is a Throwable it is
681       * logged specially.
682       *
683       * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
684       * @param message The message to log.
685       * @param obj1 The first object to match against.
686       * @param obj2 The second object to match against.
687       * @param obj3 The third object to match against.
688       * @param obj4 The forth object to match against.
689       */
690  
691      public void logFormatted(final int level, final String message,
692                               final Object obj1, final Object obj2,
693                               final Object obj3, final Object obj4)
694      {
695          commonLogFormatted(level, message, new Object[]
696          {
697              obj1, obj2, obj3, obj4
698          });
699      }
700  
701      private void commonLogFormatted(final int level, final String message,
702                                      final Object [] unflatParams)
703      {
704          
705  
706          if (check(log, level))
707          {
708              Object[] params = flattenArrays(unflatParams);
709  
710              if (params[ params.length - 1 ] instanceof Throwable)
711              {
712                  log(level, StringUtil.format(message, params),
713                      ( Throwable ) params[ params.length - 1 ]);
714              }
715              else
716              {
717                  log(level, StringUtil.format(message, params));
718              }
719          }
720      }
721  
722      /**
723       * Flattens any contained objects. Only tranverses one level deep.
724       */
725  
726      private Object [] flattenArrays(final Object [] objects)
727      {
728          List results = new ArrayList();
729  
730          for (int i = 0; i < objects.length; i++)
731          {
732              results.addAll(objectToObjectArray(objects[ i ]));
733          }
734          return ( Object [] ) results.toArray(new Object[ results.size() ]);
735      }
736  
737      private List objectToObjectArray(Object object)
738      {
739          List results = new ArrayList();
740  
741          if (object instanceof byte [])
742          {
743              byte[] array = ( byte [] ) object;
744  
745              for (int j = 0; j < array.length; j++)
746              {
747                  results.add(new Byte(array[ j ]));
748              }
749          }
750          if (object instanceof char [])
751          {
752              char[] array = ( char [] ) object;
753  
754              for (int j = 0; j < array.length; j++)
755              {
756                  results.add(new Character(array[ j ]));
757              }
758          }
759          else if (object instanceof short [])
760          {
761              short[] array = ( short [] ) object;
762  
763              for (int j = 0; j < array.length; j++)
764              {
765                  results.add(new Short(array[ j ]));
766              }
767          }
768          else if (object instanceof int [])
769          {
770              int[] array = ( int [] ) object;
771  
772              for (int j = 0; j < array.length; j++)
773              {
774                  results.add(new Integer(array[ j ]));
775              }
776          }
777          else if (object instanceof long [])
778          {
779              long[] array = ( long [] ) object;
780  
781              for (int j = 0; j < array.length; j++)
782              {
783                  results.add(new Long(array[ j ]));
784              }
785          }
786          else if (object instanceof float [])
787          {
788              float[] array = ( float [] ) object;
789  
790              for (int j = 0; j < array.length; j++)
791              {
792                  results.add(new Float(array[ j ]));
793              }
794          }
795          else if (object instanceof double [])
796          {
797              double[] array = ( double [] ) object;
798  
799              for (int j = 0; j < array.length; j++)
800              {
801                  results.add(new Double(array[ j ]));
802              }
803          }
804          else if (object instanceof Object [])
805          {
806              Object[] array = ( Object [] ) object;
807  
808              for (int j = 0; j < array.length; j++)
809              {
810                  results.add(array[ j ]);
811              }
812          }
813          else
814          {
815              results.add(object);
816          }
817          return results;
818      }
819  }   // end package scope class POILogger
820  
821