OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [util/] [logging/] [FileHandler.java] - Blame information for rev 771

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* FileHandler.java -- a class for publishing log messages to log files
2
   Copyright (C) 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package java.util.logging;
40
 
41
import gnu.java.lang.CPStringBuilder;
42
 
43
import java.io.File;
44
import java.io.FileOutputStream;
45
import java.io.FilterOutputStream;
46
import java.io.IOException;
47
import java.io.OutputStream;
48
import java.util.LinkedList;
49
import java.util.ListIterator;
50
 
51
/**
52
 * A <code>FileHandler</code> publishes log records to a set of log
53
 * files.  A maximum file size can be specified; as soon as a log file
54
 * reaches the size limit, it is closed and the next file in the set
55
 * is taken.
56
 *
57
 * <p><strong>Configuration:</strong> Values of the subsequent
58
 * <code>LogManager</code> properties are taken into consideration
59
 * when a <code>FileHandler</code> is initialized.  If a property is
60
 * not defined, or if it has an invalid value, a default is taken
61
 * without an exception being thrown.
62
 *
63
 * <ul>
64
 *
65
 * <li><code>java.util.FileHandler.level</code> - specifies
66
 *     the initial severity level threshold. Default value:
67
 *     <code>Level.ALL</code>.</li>
68
 *
69
 * <li><code>java.util.FileHandler.filter</code> - specifies
70
 *     the name of a Filter class. Default value: No Filter.</li>
71
 *
72
 * <li><code>java.util.FileHandler.formatter</code> - specifies
73
 *     the name of a Formatter class. Default value:
74
 *     <code>java.util.logging.XMLFormatter</code>.</li>
75
 *
76
 * <li><code>java.util.FileHandler.encoding</code> - specifies
77
 *     the name of the character encoding. Default value:
78
 *     the default platform encoding.</li>
79
 *
80
 * <li><code>java.util.FileHandler.limit</code> - specifies the number
81
 *     of bytes a log file is approximately allowed to reach before it
82
 *     is closed and the handler switches to the next file in the
83
 *     rotating set.  A value of zero means that files can grow
84
 *     without limit.  Default value: 0 (unlimited growth).</li>
85
 *
86
 * <li><code>java.util.FileHandler.count</code> - specifies the number
87
 *     of log files through which this handler cycles.  Default value:
88
 *     1.</li>
89
 *
90
 * <li><code>java.util.FileHandler.pattern</code> - specifies a
91
 *     pattern for the location and name of the produced log files.
92
 *     See the section on <a href="#filePatterns">file name
93
 *     patterns</a> for details.  Default value:
94
 *     <code>"%h/java%u.log"</code>.</li>
95
 *
96
 * <li><code>java.util.FileHandler.append</code> - specifies
97
 *     whether the handler will append log records to existing
98
 *     files, or whether the handler will clear log files
99
 *     upon switching to them. Default value: <code>false</code>,
100
 *     indicating that files will be cleared.</li>
101
 *
102
 * </ul>
103
 *
104
 * <p><a name="filePatterns"><strong>File Name Patterns:</strong></a>
105
 * The name and location and log files are specified with pattern
106
 * strings. The handler will replace the following character sequences
107
 * when opening log files:
108
 *
109
 * <p><ul>
110
 * <li><code>/</code> - replaced by the platform-specific path name
111
 *     separator.  This value is taken from the system property
112
 *     <code>file.separator</code>.</li>
113
 *
114
 * <li><code>%t</code> - replaced by the platform-specific location of
115
 *     the directory intended for temporary files.  This value is
116
 *     taken from the system property <code>java.io.tmpdir</code>.</li>
117
 *
118
 * <li><code>%h</code> - replaced by the location of the home
119
 *     directory of the current user.  This value is taken from the
120
 *     system property <code>user.home</code>.</li>
121
 *
122
 * <li><code>%g</code> - replaced by a generation number for
123
 *     distinguisthing the individual items in the rotating set
124
 *     of log files.  The generation number cycles through the
125
 *     sequence 0, 1, ..., <code>count</code> - 1.</li>
126
 *
127
 * <li><code>%u</code> - replaced by a unique number for
128
 *     distinguisthing the output files of several concurrently
129
 *     running processes.  The <code>FileHandler</code> starts
130
 *     with 0 when it tries to open a log file.  If the file
131
 *     cannot be opened because it is currently in use,
132
 *     the unique number is incremented by one and opening
133
 *     is tried again.  These steps are repeated until the
134
 *     opening operation succeeds.
135
 *
136
 *     <p>FIXME: Is the following correct? Please review.  The unique
137
 *     number is determined for each log file individually when it is
138
 *     opened upon switching to the next file.  Therefore, it is not
139
 *     correct to assume that all log files in a rotating set bear the
140
 *     same unique number.
141
 *
142
 *     <p>FIXME: The Javadoc for the Sun reference implementation
143
 *     says: "Note that the use of unique ids to avoid conflicts is
144
 *     only guaranteed to work reliably when using a local disk file
145
 *     system." Why? This needs to be mentioned as well, in case
146
 *     the reviewers decide the statement is true.  Otherwise,
147
 *     file a bug report with Sun.</li>
148
 *
149
 * <li><code>%%</code> - replaced by a single percent sign.</li>
150
 * </ul>
151
 *
152
 * <p>If the pattern string does not contain <code>%g</code> and
153
 * <code>count</code> is greater than one, the handler will append
154
 * the string <code>.%g</code> to the specified pattern.
155
 *
156
 * <p>If the handler attempts to open a log file, this log file
157
 * is being used at the time of the attempt, and the pattern string
158
 * does not contain <code>%u</code>, the handler will append
159
 * the string <code>.%u</code> to the specified pattern. This
160
 * step is performed after any generation number has been
161
 * appended.
162
 *
163
 * <p><em>Examples for the GNU platform:</em>
164
 *
165
 * <p><ul>
166
 *
167
 * <li><code>%h/java%u.log</code> will lead to a single log file
168
 *     <code>/home/janet/java0.log</code>, assuming <code>count</code>
169
 *     equals 1, the user's home directory is
170
 *     <code>/home/janet</code>, and the attempt to open the file
171
 *     succeeds.</li>
172
 *
173
 * <li><code>%h/java%u.log</code> will lead to three log files
174
 *     <code>/home/janet/java0.log.0</code>,
175
 *     <code>/home/janet/java0.log.1</code>, and
176
 *     <code>/home/janet/java0.log.2</code>,
177
 *     assuming <code>count</code> equals 3, the user's home
178
 *     directory is <code>/home/janet</code>, and all attempts
179
 *     to open files succeed.</li>
180
 *
181
 * <li><code>%h/java%u.log</code> will lead to three log files
182
 *     <code>/home/janet/java0.log.0</code>,
183
 *     <code>/home/janet/java1.log.1</code>, and
184
 *     <code>/home/janet/java0.log.2</code>,
185
 *     assuming <code>count</code> equals 3, the user's home
186
 *     directory is <code>/home/janet</code>, and the attempt
187
 *     to open <code>/home/janet/java0.log.1</code> fails.</li>
188
 *
189
 * </ul>
190
 *
191
 * @author Sascha Brawer (brawer@acm.org)
192
 */
193
public class FileHandler
194
  extends StreamHandler
195
{
196
  /**
197
   * A literal that prefixes all file-handler related properties in the
198
   * logging.properties file.
199
   */
200
  private static final String PROPERTY_PREFIX = "java.util.logging.FileHandler";
201
  /**
202
   * The name of the property to set for specifying a file naming (incl. path)
203
   * pattern to use with rotating log files.
204
   */
205
  private static final String PATTERN_KEY = PROPERTY_PREFIX + ".pattern";
206
  /**
207
   * The default pattern to use when the <code>PATTERN_KEY</code> property was
208
   * not specified in the logging.properties file.
209
   */
210
  private static final String DEFAULT_PATTERN = "%h/java%u.log";
211
  /**
212
   * The name of the property to set for specifying an approximate maximum
213
   * amount, in bytes, to write to any one log output file. A value of zero
214
   * (which is the default) implies a no limit.
215
   */
216
  private static final String LIMIT_KEY = PROPERTY_PREFIX + ".limit";
217
  private static final int DEFAULT_LIMIT = 0;
218
  /**
219
   * The name of the property to set for specifying how many output files to
220
   * cycle through. The default value is 1.
221
   */
222
  private static final String COUNT_KEY = PROPERTY_PREFIX + ".count";
223
  private static final int DEFAULT_COUNT = 1;
224
  /**
225
   * The name of the property to set for specifying whether this handler should
226
   * append, or not, its output to existing files. The default value is
227
   * <code>false</code> meaning NOT to append.
228
   */
229
  private static final String APPEND_KEY = PROPERTY_PREFIX + ".append";
230
  private static final boolean DEFAULT_APPEND = false;
231
 
232
  /**
233
   * The number of bytes a log file is approximately allowed to reach
234
   * before it is closed and the handler switches to the next file in
235
   * the rotating set.  A value of zero means that files can grow
236
   * without limit.
237
   */
238
  private final int limit;
239
 
240
 
241
 /**
242
  * The number of log files through which this handler cycles.
243
  */
244
  private final int count;
245
 
246
 
247
  /**
248
   * The pattern for the location and name of the produced log files.
249
   * See the section on <a href="#filePatterns">file name patterns</a>
250
   * for details.
251
   */
252
  private final String pattern;
253
 
254
 
255
  /**
256
   * Indicates whether the handler will append log records to existing
257
   * files (<code>true</code>), or whether the handler will clear log files
258
   * upon switching to them (<code>false</code>).
259
   */
260
  private final boolean append;
261
 
262
 
263
  /**
264
   * The number of bytes that have currently been written to the stream.
265
   * Package private for use in inner classes.
266
   */
267
  long written;
268
 
269
 
270
  /**
271
   * A linked list of files we are, or have written to. The entries
272
   * are file path strings, kept in the order
273
   */
274
  private LinkedList logFiles;
275
 
276
 
277
  /**
278
   * Constructs a <code>FileHandler</code>, taking all property values
279
   * from the current {@link LogManager LogManager} configuration.
280
   *
281
   * @throws java.io.IOException FIXME: The Sun Javadoc says: "if
282
   *         there are IO problems opening the files."  This conflicts
283
   *         with the general principle that configuration errors do
284
   *         not prohibit construction. Needs review.
285
   *
286
   * @throws SecurityException if a security manager exists and
287
   *         the caller is not granted the permission to control
288
   *         the logging infrastructure.
289
   */
290
  public FileHandler()
291
    throws IOException, SecurityException
292
  {
293
    this(LogManager.getLogManager().getProperty(PATTERN_KEY),
294
         LogManager.getIntProperty(LIMIT_KEY, DEFAULT_LIMIT),
295
         LogManager.getIntProperty(COUNT_KEY, DEFAULT_COUNT),
296
         LogManager.getBooleanProperty(APPEND_KEY, DEFAULT_APPEND));
297
  }
298
 
299
 
300
  /* FIXME: Javadoc missing. */
301
  public FileHandler(String pattern)
302
    throws IOException, SecurityException
303
  {
304
    this(pattern, DEFAULT_LIMIT, DEFAULT_COUNT, DEFAULT_APPEND);
305
  }
306
 
307
 
308
  /* FIXME: Javadoc missing. */
309
  public FileHandler(String pattern, boolean append)
310
    throws IOException, SecurityException
311
  {
312
    this(pattern, DEFAULT_LIMIT, DEFAULT_COUNT, append);
313
  }
314
 
315
 
316
  /* FIXME: Javadoc missing. */
317
  public FileHandler(String pattern, int limit, int count)
318
    throws IOException, SecurityException
319
  {
320
    this(pattern, limit, count,
321
         LogManager.getBooleanProperty(APPEND_KEY, DEFAULT_APPEND));
322
  }
323
 
324
 
325
  /**
326
   * Constructs a <code>FileHandler</code> given the pattern for the
327
   * location and name of the produced log files, the size limit, the
328
   * number of log files thorough which the handler will rotate, and
329
   * the <code>append</code> property.  All other property values are
330
   * taken from the current {@link LogManager LogManager}
331
   * configuration.
332
   *
333
   * @param pattern The pattern for the location and name of the
334
   *        produced log files.  See the section on <a
335
   *        href="#filePatterns">file name patterns</a> for details.
336
   *        If <code>pattern</code> is <code>null</code>, the value is
337
   *        taken from the {@link LogManager LogManager} configuration
338
   *        property
339
   *        <code>java.util.logging.FileHandler.pattern</code>.
340
   *        However, this is a pecularity of the GNU implementation,
341
   *        and Sun's API specification does not mention what behavior
342
   *        is to be expected for <code>null</code>. Therefore,
343
   *        applications should not rely on this feature.
344
   *
345
   * @param limit specifies the number of bytes a log file is
346
   *        approximately allowed to reach before it is closed and the
347
   *        handler switches to the next file in the rotating set.  A
348
   *        value of zero means that files can grow without limit.
349
   *
350
   * @param count specifies the number of log files through which this
351
   *        handler cycles.
352
   *
353
   * @param append specifies whether the handler will append log
354
   *        records to existing files (<code>true</code>), or whether the
355
   *        handler will clear log files upon switching to them
356
   *        (<code>false</code>).
357
   *
358
   * @throws java.io.IOException FIXME: The Sun Javadoc says: "if
359
   *         there are IO problems opening the files."  This conflicts
360
   *         with the general principle that configuration errors do
361
   *         not prohibit construction. Needs review.
362
   *
363
   * @throws SecurityException if a security manager exists and
364
   *         the caller is not granted the permission to control
365
   *         the logging infrastructure.
366
   *         <p>FIXME: This seems in contrast to all other handler
367
   *         constructors -- verify this by running tests against
368
   *         the Sun reference implementation.
369
   */
370
  public FileHandler(String pattern,
371
                     int limit,
372
                     int count,
373
                     boolean append)
374
    throws IOException, SecurityException
375
  {
376
    super(/* output stream, created below */ null,
377
          PROPERTY_PREFIX,
378
          /* default level */ Level.ALL,
379
          /* formatter */ null,
380
          /* default formatter */ XMLFormatter.class);
381
 
382
    if ((limit <0) || (count < 1))
383
      throw new IllegalArgumentException();
384
 
385
    this.pattern = pattern != null ? pattern : DEFAULT_PATTERN;
386
    this.limit = limit;
387
    this.count = count;
388
    this.append = append;
389
    this.written = 0;
390
    this.logFiles = new LinkedList ();
391
 
392
    setOutputStream (createFileStream (this.pattern, limit, count, append,
393
                                       /* generation */ 0));
394
  }
395
 
396
 
397
  /* FIXME: Javadoc missing. */
398
  private OutputStream createFileStream(String pattern,
399
                                        int limit,
400
                                        int count,
401
                                        boolean append,
402
                                        int generation)
403
  {
404
    String  path;
405
    int     unique = 0;
406
 
407
    /* Throws a SecurityException if the caller does not have
408
     * LoggingPermission("control").
409
     */
410
    LogManager.getLogManager().checkAccess();
411
 
412
    /* Default value from the java.util.logging.FileHandler.pattern
413
     * LogManager configuration property.
414
     */
415
    if (pattern == null)
416
      pattern = LogManager.getLogManager().getProperty(PATTERN_KEY);
417
    if (pattern == null)
418
      pattern = DEFAULT_PATTERN;
419
 
420
    if (count > 1 && !has (pattern, 'g'))
421
      pattern = pattern + ".%g";
422
 
423
    do
424
    {
425
      path = replaceFileNameEscapes(pattern, generation, unique, count);
426
 
427
      try
428
      {
429
        File file = new File(path);
430
        if (!file.exists () || append)
431
          {
432
            FileOutputStream fout = new FileOutputStream (file, append);
433
            // FIXME we need file locks for this to work properly, but they
434
            // are not implemented yet in Classpath! Madness!
435
//             FileChannel channel = fout.getChannel ();
436
//             FileLock lock = channel.tryLock ();
437
//             if (lock != null) // We've locked the file.
438
//               {
439
                if (logFiles.isEmpty ())
440
                  logFiles.addFirst (path);
441
                return new ostr (fout);
442
//               }
443
          }
444
      }
445
      catch (Exception ex)
446
      {
447
        reportError (null, ex, ErrorManager.OPEN_FAILURE);
448
      }
449
 
450
      unique = unique + 1;
451
      if (!has (pattern, 'u'))
452
        pattern = pattern + ".%u";
453
    }
454
    while (true);
455
  }
456
 
457
 
458
  /**
459
   * Replaces the substrings <code>"/"</code> by the value of the
460
   * system property <code>"file.separator"</code>, <code>"%t"</code>
461
   * by the value of the system property
462
   * <code>"java.io.tmpdir"</code>, <code>"%h"</code> by the value of
463
   * the system property <code>"user.home"</code>, <code>"%g"</code>
464
   * by the value of <code>generation</code>, <code>"%u"</code> by the
465
   * value of <code>uniqueNumber</code>, and <code>"%%"</code> by a
466
   * single percent character.  If <code>pattern</code> does
467
   * <em>not</em> contain the sequence <code>"%g"</code>,
468
   * the value of <code>generation</code> will be appended to
469
   * the result.
470
   *
471
   * @throws NullPointerException if one of the system properties
472
   *         <code>"file.separator"</code>,
473
   *         <code>"java.io.tmpdir"</code>, or
474
   *         <code>"user.home"</code> has no value and the
475
   *         corresponding escape sequence appears in
476
   *         <code>pattern</code>.
477
   */
478
  private static String replaceFileNameEscapes(String pattern,
479
                                               int generation,
480
                                               int uniqueNumber,
481
                                               int count)
482
  {
483
    CPStringBuilder buf = new CPStringBuilder(pattern);
484
    String       replaceWith;
485
    boolean      foundGeneration = false;
486
 
487
    int pos = 0;
488
    do
489
    {
490
      // Uncomment the next line for finding bugs.
491
      // System.out.println(buf.substring(0,pos) + '|' + buf.substring(pos));
492
 
493
      if (buf.charAt(pos) == '/')
494
      {
495
        /* The same value is also provided by java.io.File.separator. */
496
        replaceWith = System.getProperty("file.separator");
497
        buf.replace(pos, pos + 1, replaceWith);
498
        pos = pos + replaceWith.length() - 1;
499
        continue;
500
      }
501
 
502
      if (buf.charAt(pos) == '%')
503
      {
504
        switch (buf.charAt(pos + 1))
505
        {
506
        case 't':
507
          replaceWith = System.getProperty("java.io.tmpdir");
508
          break;
509
 
510
        case 'h':
511
          replaceWith = System.getProperty("user.home");
512
          break;
513
 
514
        case 'g':
515
          replaceWith = Integer.toString(generation);
516
          foundGeneration = true;
517
          break;
518
 
519
        case 'u':
520
          replaceWith = Integer.toString(uniqueNumber);
521
          break;
522
 
523
        case '%':
524
          replaceWith = "%";
525
          break;
526
 
527
        default:
528
          replaceWith = "??";
529
          break; // FIXME: Throw exception?
530
        }
531
 
532
        buf.replace(pos, pos + 2, replaceWith);
533
        pos = pos + replaceWith.length() - 1;
534
        continue;
535
      }
536
    }
537
    while (++pos < buf.length() - 1);
538
 
539
    if (!foundGeneration && (count > 1))
540
    {
541
      buf.append('.');
542
      buf.append(generation);
543
    }
544
 
545
    return buf.toString();
546
  }
547
 
548
 
549
  /* FIXME: Javadoc missing. */
550
  public void publish(LogRecord record)
551
  {
552
    if (limit > 0 && written >= limit)
553
      rotate ();
554
    super.publish(record);
555
    flush ();
556
  }
557
 
558
  /**
559
   * Rotates the current log files, possibly removing one if we
560
   * exceed the file count.
561
   */
562
  private synchronized void rotate ()
563
  {
564
    if (logFiles.size () > 0)
565
      {
566
        File f1 = null;
567
        ListIterator lit = null;
568
 
569
        // If we reach the file count, ditch the oldest file.
570
        if (logFiles.size () == count)
571
          {
572
            f1 = new File ((String) logFiles.getLast ());
573
            f1.delete ();
574
            lit = logFiles.listIterator (logFiles.size () - 1);
575
          }
576
        // Otherwise, move the oldest to a new location.
577
        else
578
          {
579
            String path = replaceFileNameEscapes (pattern, logFiles.size (),
580
                                                  /* unique */ 0, count);
581
            f1 = new File (path);
582
            logFiles.addLast (path);
583
            lit = logFiles.listIterator (logFiles.size () - 1);
584
          }
585
 
586
        // Now rotate the files.
587
        while (lit.hasPrevious ())
588
          {
589
            String s = (String) lit.previous ();
590
            File f2 = new File (s);
591
            f2.renameTo (f1);
592
            f1 = f2;
593
          }
594
      }
595
 
596
    setOutputStream (createFileStream (pattern, limit, count, append,
597
                                       /* generation */ 0));
598
 
599
    // Reset written count.
600
    written = 0;
601
  }
602
 
603
  /**
604
   * Tell if <code>pattern</code> contains the pattern sequence
605
   * with character <code>escape</code>. That is, if <code>escape</code>
606
   * is 'g', this method returns true if the given pattern contains
607
   * "%g", and not just the substring "%g" (for example, in the case of
608
   * "%%g").
609
   *
610
   * @param pattern The pattern to test.
611
   * @param escape The escape character to search for.
612
   * @return True iff the pattern contains the escape sequence with the
613
   *  given character.
614
   */
615
  private static boolean has (final String pattern, final char escape)
616
  {
617
    final int len = pattern.length ();
618
    boolean sawPercent = false;
619
    for (int i = 0; i < len; i++)
620
      {
621
        char c = pattern.charAt (i);
622
        if (sawPercent)
623
          {
624
            if (c == escape)
625
              return true;
626
            if (c == '%') // Double percent
627
              {
628
                sawPercent = false;
629
                continue;
630
              }
631
          }
632
        sawPercent = (c == '%');
633
      }
634
    return false;
635
  }
636
 
637
  /**
638
   * An output stream that tracks the number of bytes written to it.
639
   */
640
  private final class ostr extends FilterOutputStream
641
  {
642
    private ostr (OutputStream out)
643
    {
644
      super (out);
645
    }
646
 
647
    public void write (final int b) throws IOException
648
    {
649
      out.write (b);
650
      FileHandler.this.written++; // FIXME: synchronize?
651
    }
652
 
653
    public void write (final byte[] b) throws IOException
654
    {
655
      write (b, 0, b.length);
656
    }
657
 
658
    public void write (final byte[] b, final int offset, final int length)
659
      throws IOException
660
    {
661
      out.write (b, offset, length);
662
      FileHandler.this.written += length; // FIXME: synchronize?
663
    }
664
  }
665
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.