emul/compact/src/main/java/java/util/logging/LogRecord.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 07 Sep 2013 13:51:24 +0200
branchjdk7-b147
changeset 1258 724f3e1ea53e
permissions -rw-r--r--
Additional set of classes to make porting of lookup library more easier
jaroslav@1258
     1
/*
jaroslav@1258
     2
 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
jaroslav@1258
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@1258
     4
 *
jaroslav@1258
     5
 * This code is free software; you can redistribute it and/or modify it
jaroslav@1258
     6
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@1258
     7
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@1258
     8
 * particular file as subject to the "Classpath" exception as provided
jaroslav@1258
     9
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@1258
    10
 *
jaroslav@1258
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@1258
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@1258
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@1258
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@1258
    15
 * accompanied this code).
jaroslav@1258
    16
 *
jaroslav@1258
    17
 * You should have received a copy of the GNU General Public License version
jaroslav@1258
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@1258
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@1258
    20
 *
jaroslav@1258
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@1258
    22
 * or visit www.oracle.com if you need additional information or have any
jaroslav@1258
    23
 * questions.
jaroslav@1258
    24
 */
jaroslav@1258
    25
jaroslav@1258
    26
package java.util.logging;
jaroslav@1258
    27
import java.util.*;
jaroslav@1258
    28
import java.util.concurrent.atomic.AtomicInteger;
jaroslav@1258
    29
import java.util.concurrent.atomic.AtomicLong;
jaroslav@1258
    30
import java.io.*;
jaroslav@1258
    31
jaroslav@1258
    32
import sun.misc.JavaLangAccess;
jaroslav@1258
    33
import sun.misc.SharedSecrets;
jaroslav@1258
    34
jaroslav@1258
    35
/**
jaroslav@1258
    36
 * LogRecord objects are used to pass logging requests between
jaroslav@1258
    37
 * the logging framework and individual log Handlers.
jaroslav@1258
    38
 * <p>
jaroslav@1258
    39
 * When a LogRecord is passed into the logging framework it
jaroslav@1258
    40
 * logically belongs to the framework and should no longer be
jaroslav@1258
    41
 * used or updated by the client application.
jaroslav@1258
    42
 * <p>
jaroslav@1258
    43
 * Note that if the client application has not specified an
jaroslav@1258
    44
 * explicit source method name and source class name, then the
jaroslav@1258
    45
 * LogRecord class will infer them automatically when they are
jaroslav@1258
    46
 * first accessed (due to a call on getSourceMethodName or
jaroslav@1258
    47
 * getSourceClassName) by analyzing the call stack.  Therefore,
jaroslav@1258
    48
 * if a logging Handler wants to pass off a LogRecord to another
jaroslav@1258
    49
 * thread, or to transmit it over RMI, and if it wishes to subsequently
jaroslav@1258
    50
 * obtain method name or class name information it should call
jaroslav@1258
    51
 * one of getSourceClassName or getSourceMethodName to force
jaroslav@1258
    52
 * the values to be filled in.
jaroslav@1258
    53
 * <p>
jaroslav@1258
    54
 * <b> Serialization notes:</b>
jaroslav@1258
    55
 * <ul>
jaroslav@1258
    56
 * <li>The LogRecord class is serializable.
jaroslav@1258
    57
 *
jaroslav@1258
    58
 * <li> Because objects in the parameters array may not be serializable,
jaroslav@1258
    59
 * during serialization all objects in the parameters array are
jaroslav@1258
    60
 * written as the corresponding Strings (using Object.toString).
jaroslav@1258
    61
 *
jaroslav@1258
    62
 * <li> The ResourceBundle is not transmitted as part of the serialized
jaroslav@1258
    63
 * form, but the resource bundle name is, and the recipient object's
jaroslav@1258
    64
 * readObject method will attempt to locate a suitable resource bundle.
jaroslav@1258
    65
 *
jaroslav@1258
    66
 * </ul>
jaroslav@1258
    67
 *
jaroslav@1258
    68
 * @since 1.4
jaroslav@1258
    69
 */
jaroslav@1258
    70
jaroslav@1258
    71
public class LogRecord implements java.io.Serializable {
jaroslav@1258
    72
    private static final AtomicLong globalSequenceNumber
jaroslav@1258
    73
        = new AtomicLong(0);
jaroslav@1258
    74
jaroslav@1258
    75
    /**
jaroslav@1258
    76
     * The default value of threadID will be the current thread's
jaroslav@1258
    77
     * thread id, for ease of correlation, unless it is greater than
jaroslav@1258
    78
     * MIN_SEQUENTIAL_THREAD_ID, in which case we try harder to keep
jaroslav@1258
    79
     * our promise to keep threadIDs unique by avoiding collisions due
jaroslav@1258
    80
     * to 32-bit wraparound.  Unfortunately, LogRecord.getThreadID()
jaroslav@1258
    81
     * returns int, while Thread.getId() returns long.
jaroslav@1258
    82
     */
jaroslav@1258
    83
    private static final int MIN_SEQUENTIAL_THREAD_ID = Integer.MAX_VALUE / 2;
jaroslav@1258
    84
jaroslav@1258
    85
    private static final AtomicInteger nextThreadId
jaroslav@1258
    86
        = new AtomicInteger(MIN_SEQUENTIAL_THREAD_ID);
jaroslav@1258
    87
jaroslav@1258
    88
    private static final ThreadLocal<Integer> threadIds = new ThreadLocal<>();
jaroslav@1258
    89
jaroslav@1258
    90
    /**
jaroslav@1258
    91
     * @serial Logging message level
jaroslav@1258
    92
     */
jaroslav@1258
    93
    private Level level;
jaroslav@1258
    94
jaroslav@1258
    95
    /**
jaroslav@1258
    96
     * @serial Sequence number
jaroslav@1258
    97
     */
jaroslav@1258
    98
    private long sequenceNumber;
jaroslav@1258
    99
jaroslav@1258
   100
    /**
jaroslav@1258
   101
     * @serial Class that issued logging call
jaroslav@1258
   102
     */
jaroslav@1258
   103
    private String sourceClassName;
jaroslav@1258
   104
jaroslav@1258
   105
    /**
jaroslav@1258
   106
     * @serial Method that issued logging call
jaroslav@1258
   107
     */
jaroslav@1258
   108
    private String sourceMethodName;
jaroslav@1258
   109
jaroslav@1258
   110
    /**
jaroslav@1258
   111
     * @serial Non-localized raw message text
jaroslav@1258
   112
     */
jaroslav@1258
   113
    private String message;
jaroslav@1258
   114
jaroslav@1258
   115
    /**
jaroslav@1258
   116
     * @serial Thread ID for thread that issued logging call.
jaroslav@1258
   117
     */
jaroslav@1258
   118
    private int threadID;
jaroslav@1258
   119
jaroslav@1258
   120
    /**
jaroslav@1258
   121
     * @serial Event time in milliseconds since 1970
jaroslav@1258
   122
     */
jaroslav@1258
   123
    private long millis;
jaroslav@1258
   124
jaroslav@1258
   125
    /**
jaroslav@1258
   126
     * @serial The Throwable (if any) associated with log message
jaroslav@1258
   127
     */
jaroslav@1258
   128
    private Throwable thrown;
jaroslav@1258
   129
jaroslav@1258
   130
    /**
jaroslav@1258
   131
     * @serial Name of the source Logger.
jaroslav@1258
   132
     */
jaroslav@1258
   133
    private String loggerName;
jaroslav@1258
   134
jaroslav@1258
   135
    /**
jaroslav@1258
   136
     * @serial Resource bundle name to localized log message.
jaroslav@1258
   137
     */
jaroslav@1258
   138
    private String resourceBundleName;
jaroslav@1258
   139
jaroslav@1258
   140
    private transient boolean needToInferCaller;
jaroslav@1258
   141
    private transient Object parameters[];
jaroslav@1258
   142
    private transient ResourceBundle resourceBundle;
jaroslav@1258
   143
jaroslav@1258
   144
    /**
jaroslav@1258
   145
     * Returns the default value for a new LogRecord's threadID.
jaroslav@1258
   146
     */
jaroslav@1258
   147
    private int defaultThreadID() {
jaroslav@1258
   148
        long tid = Thread.currentThread().getId();
jaroslav@1258
   149
        if (tid < MIN_SEQUENTIAL_THREAD_ID) {
jaroslav@1258
   150
            return (int) tid;
jaroslav@1258
   151
        } else {
jaroslav@1258
   152
            Integer id = threadIds.get();
jaroslav@1258
   153
            if (id == null) {
jaroslav@1258
   154
                id = nextThreadId.getAndIncrement();
jaroslav@1258
   155
                threadIds.set(id);
jaroslav@1258
   156
            }
jaroslav@1258
   157
            return id;
jaroslav@1258
   158
        }
jaroslav@1258
   159
    }
jaroslav@1258
   160
jaroslav@1258
   161
    /**
jaroslav@1258
   162
     * Construct a LogRecord with the given level and message values.
jaroslav@1258
   163
     * <p>
jaroslav@1258
   164
     * The sequence property will be initialized with a new unique value.
jaroslav@1258
   165
     * These sequence values are allocated in increasing order within a VM.
jaroslav@1258
   166
     * <p>
jaroslav@1258
   167
     * The millis property will be initialized to the current time.
jaroslav@1258
   168
     * <p>
jaroslav@1258
   169
     * The thread ID property will be initialized with a unique ID for
jaroslav@1258
   170
     * the current thread.
jaroslav@1258
   171
     * <p>
jaroslav@1258
   172
     * All other properties will be initialized to "null".
jaroslav@1258
   173
     *
jaroslav@1258
   174
     * @param level  a logging level value
jaroslav@1258
   175
     * @param msg  the raw non-localized logging message (may be null)
jaroslav@1258
   176
     */
jaroslav@1258
   177
    public LogRecord(Level level, String msg) {
jaroslav@1258
   178
        // Make sure level isn't null, by calling random method.
jaroslav@1258
   179
        level.getClass();
jaroslav@1258
   180
        this.level = level;
jaroslav@1258
   181
        message = msg;
jaroslav@1258
   182
        // Assign a thread ID and a unique sequence number.
jaroslav@1258
   183
        sequenceNumber = globalSequenceNumber.getAndIncrement();
jaroslav@1258
   184
        threadID = defaultThreadID();
jaroslav@1258
   185
        millis = System.currentTimeMillis();
jaroslav@1258
   186
        needToInferCaller = true;
jaroslav@1258
   187
   }
jaroslav@1258
   188
jaroslav@1258
   189
    /**
jaroslav@1258
   190
     * Get the source Logger's name.
jaroslav@1258
   191
     *
jaroslav@1258
   192
     * @return source logger name (may be null)
jaroslav@1258
   193
     */
jaroslav@1258
   194
    public String getLoggerName() {
jaroslav@1258
   195
        return loggerName;
jaroslav@1258
   196
    }
jaroslav@1258
   197
jaroslav@1258
   198
    /**
jaroslav@1258
   199
     * Set the source Logger's name.
jaroslav@1258
   200
     *
jaroslav@1258
   201
     * @param name   the source logger name (may be null)
jaroslav@1258
   202
     */
jaroslav@1258
   203
    public void setLoggerName(String name) {
jaroslav@1258
   204
        loggerName = name;
jaroslav@1258
   205
    }
jaroslav@1258
   206
jaroslav@1258
   207
    /**
jaroslav@1258
   208
     * Get the localization resource bundle
jaroslav@1258
   209
     * <p>
jaroslav@1258
   210
     * This is the ResourceBundle that should be used to localize
jaroslav@1258
   211
     * the message string before formatting it.  The result may
jaroslav@1258
   212
     * be null if the message is not localizable, or if no suitable
jaroslav@1258
   213
     * ResourceBundle is available.
jaroslav@1258
   214
     */
jaroslav@1258
   215
    public ResourceBundle getResourceBundle() {
jaroslav@1258
   216
        return resourceBundle;
jaroslav@1258
   217
    }
jaroslav@1258
   218
jaroslav@1258
   219
    /**
jaroslav@1258
   220
     * Set the localization resource bundle.
jaroslav@1258
   221
     *
jaroslav@1258
   222
     * @param bundle  localization bundle (may be null)
jaroslav@1258
   223
     */
jaroslav@1258
   224
    public void setResourceBundle(ResourceBundle bundle) {
jaroslav@1258
   225
        resourceBundle = bundle;
jaroslav@1258
   226
    }
jaroslav@1258
   227
jaroslav@1258
   228
    /**
jaroslav@1258
   229
     * Get the localization resource bundle name
jaroslav@1258
   230
     * <p>
jaroslav@1258
   231
     * This is the name for the ResourceBundle that should be
jaroslav@1258
   232
     * used to localize the message string before formatting it.
jaroslav@1258
   233
     * The result may be null if the message is not localizable.
jaroslav@1258
   234
     */
jaroslav@1258
   235
    public String getResourceBundleName() {
jaroslav@1258
   236
        return resourceBundleName;
jaroslav@1258
   237
    }
jaroslav@1258
   238
jaroslav@1258
   239
    /**
jaroslav@1258
   240
     * Set the localization resource bundle name.
jaroslav@1258
   241
     *
jaroslav@1258
   242
     * @param name  localization bundle name (may be null)
jaroslav@1258
   243
     */
jaroslav@1258
   244
    public void setResourceBundleName(String name) {
jaroslav@1258
   245
        resourceBundleName = name;
jaroslav@1258
   246
    }
jaroslav@1258
   247
jaroslav@1258
   248
    /**
jaroslav@1258
   249
     * Get the logging message level, for example Level.SEVERE.
jaroslav@1258
   250
     * @return the logging message level
jaroslav@1258
   251
     */
jaroslav@1258
   252
    public Level getLevel() {
jaroslav@1258
   253
        return level;
jaroslav@1258
   254
    }
jaroslav@1258
   255
jaroslav@1258
   256
    /**
jaroslav@1258
   257
     * Set the logging message level, for example Level.SEVERE.
jaroslav@1258
   258
     * @param level the logging message level
jaroslav@1258
   259
     */
jaroslav@1258
   260
    public void setLevel(Level level) {
jaroslav@1258
   261
        if (level == null) {
jaroslav@1258
   262
            throw new NullPointerException();
jaroslav@1258
   263
        }
jaroslav@1258
   264
        this.level = level;
jaroslav@1258
   265
    }
jaroslav@1258
   266
jaroslav@1258
   267
    /**
jaroslav@1258
   268
     * Get the sequence number.
jaroslav@1258
   269
     * <p>
jaroslav@1258
   270
     * Sequence numbers are normally assigned in the LogRecord
jaroslav@1258
   271
     * constructor, which assigns unique sequence numbers to
jaroslav@1258
   272
     * each new LogRecord in increasing order.
jaroslav@1258
   273
     * @return the sequence number
jaroslav@1258
   274
     */
jaroslav@1258
   275
    public long getSequenceNumber() {
jaroslav@1258
   276
        return sequenceNumber;
jaroslav@1258
   277
    }
jaroslav@1258
   278
jaroslav@1258
   279
    /**
jaroslav@1258
   280
     * Set the sequence number.
jaroslav@1258
   281
     * <p>
jaroslav@1258
   282
     * Sequence numbers are normally assigned in the LogRecord constructor,
jaroslav@1258
   283
     * so it should not normally be necessary to use this method.
jaroslav@1258
   284
     */
jaroslav@1258
   285
    public void setSequenceNumber(long seq) {
jaroslav@1258
   286
        sequenceNumber = seq;
jaroslav@1258
   287
    }
jaroslav@1258
   288
jaroslav@1258
   289
    /**
jaroslav@1258
   290
     * Get the  name of the class that (allegedly) issued the logging request.
jaroslav@1258
   291
     * <p>
jaroslav@1258
   292
     * Note that this sourceClassName is not verified and may be spoofed.
jaroslav@1258
   293
     * This information may either have been provided as part of the
jaroslav@1258
   294
     * logging call, or it may have been inferred automatically by the
jaroslav@1258
   295
     * logging framework.  In the latter case, the information may only
jaroslav@1258
   296
     * be approximate and may in fact describe an earlier call on the
jaroslav@1258
   297
     * stack frame.
jaroslav@1258
   298
     * <p>
jaroslav@1258
   299
     * May be null if no information could be obtained.
jaroslav@1258
   300
     *
jaroslav@1258
   301
     * @return the source class name
jaroslav@1258
   302
     */
jaroslav@1258
   303
    public String getSourceClassName() {
jaroslav@1258
   304
        if (needToInferCaller) {
jaroslav@1258
   305
            inferCaller();
jaroslav@1258
   306
        }
jaroslav@1258
   307
        return sourceClassName;
jaroslav@1258
   308
    }
jaroslav@1258
   309
jaroslav@1258
   310
    /**
jaroslav@1258
   311
     * Set the name of the class that (allegedly) issued the logging request.
jaroslav@1258
   312
     *
jaroslav@1258
   313
     * @param sourceClassName the source class name (may be null)
jaroslav@1258
   314
     */
jaroslav@1258
   315
    public void setSourceClassName(String sourceClassName) {
jaroslav@1258
   316
        this.sourceClassName = sourceClassName;
jaroslav@1258
   317
        needToInferCaller = false;
jaroslav@1258
   318
    }
jaroslav@1258
   319
jaroslav@1258
   320
    /**
jaroslav@1258
   321
     * Get the  name of the method that (allegedly) issued the logging request.
jaroslav@1258
   322
     * <p>
jaroslav@1258
   323
     * Note that this sourceMethodName is not verified and may be spoofed.
jaroslav@1258
   324
     * This information may either have been provided as part of the
jaroslav@1258
   325
     * logging call, or it may have been inferred automatically by the
jaroslav@1258
   326
     * logging framework.  In the latter case, the information may only
jaroslav@1258
   327
     * be approximate and may in fact describe an earlier call on the
jaroslav@1258
   328
     * stack frame.
jaroslav@1258
   329
     * <p>
jaroslav@1258
   330
     * May be null if no information could be obtained.
jaroslav@1258
   331
     *
jaroslav@1258
   332
     * @return the source method name
jaroslav@1258
   333
     */
jaroslav@1258
   334
    public String getSourceMethodName() {
jaroslav@1258
   335
        if (needToInferCaller) {
jaroslav@1258
   336
            inferCaller();
jaroslav@1258
   337
        }
jaroslav@1258
   338
        return sourceMethodName;
jaroslav@1258
   339
    }
jaroslav@1258
   340
jaroslav@1258
   341
    /**
jaroslav@1258
   342
     * Set the name of the method that (allegedly) issued the logging request.
jaroslav@1258
   343
     *
jaroslav@1258
   344
     * @param sourceMethodName the source method name (may be null)
jaroslav@1258
   345
     */
jaroslav@1258
   346
    public void setSourceMethodName(String sourceMethodName) {
jaroslav@1258
   347
        this.sourceMethodName = sourceMethodName;
jaroslav@1258
   348
        needToInferCaller = false;
jaroslav@1258
   349
    }
jaroslav@1258
   350
jaroslav@1258
   351
    /**
jaroslav@1258
   352
     * Get the "raw" log message, before localization or formatting.
jaroslav@1258
   353
     * <p>
jaroslav@1258
   354
     * May be null, which is equivalent to the empty string "".
jaroslav@1258
   355
     * <p>
jaroslav@1258
   356
     * This message may be either the final text or a localization key.
jaroslav@1258
   357
     * <p>
jaroslav@1258
   358
     * During formatting, if the source logger has a localization
jaroslav@1258
   359
     * ResourceBundle and if that ResourceBundle has an entry for
jaroslav@1258
   360
     * this message string, then the message string is replaced
jaroslav@1258
   361
     * with the localized value.
jaroslav@1258
   362
     *
jaroslav@1258
   363
     * @return the raw message string
jaroslav@1258
   364
     */
jaroslav@1258
   365
    public String getMessage() {
jaroslav@1258
   366
        return message;
jaroslav@1258
   367
    }
jaroslav@1258
   368
jaroslav@1258
   369
    /**
jaroslav@1258
   370
     * Set the "raw" log message, before localization or formatting.
jaroslav@1258
   371
     *
jaroslav@1258
   372
     * @param message the raw message string (may be null)
jaroslav@1258
   373
     */
jaroslav@1258
   374
    public void setMessage(String message) {
jaroslav@1258
   375
        this.message = message;
jaroslav@1258
   376
    }
jaroslav@1258
   377
jaroslav@1258
   378
    /**
jaroslav@1258
   379
     * Get the parameters to the log message.
jaroslav@1258
   380
     *
jaroslav@1258
   381
     * @return the log message parameters.  May be null if
jaroslav@1258
   382
     *                  there are no parameters.
jaroslav@1258
   383
     */
jaroslav@1258
   384
    public Object[] getParameters() {
jaroslav@1258
   385
        return parameters;
jaroslav@1258
   386
    }
jaroslav@1258
   387
jaroslav@1258
   388
    /**
jaroslav@1258
   389
     * Set the parameters to the log message.
jaroslav@1258
   390
     *
jaroslav@1258
   391
     * @param parameters the log message parameters. (may be null)
jaroslav@1258
   392
     */
jaroslav@1258
   393
    public void setParameters(Object parameters[]) {
jaroslav@1258
   394
        this.parameters = parameters;
jaroslav@1258
   395
    }
jaroslav@1258
   396
jaroslav@1258
   397
    /**
jaroslav@1258
   398
     * Get an identifier for the thread where the message originated.
jaroslav@1258
   399
     * <p>
jaroslav@1258
   400
     * This is a thread identifier within the Java VM and may or
jaroslav@1258
   401
     * may not map to any operating system ID.
jaroslav@1258
   402
     *
jaroslav@1258
   403
     * @return thread ID
jaroslav@1258
   404
     */
jaroslav@1258
   405
    public int getThreadID() {
jaroslav@1258
   406
        return threadID;
jaroslav@1258
   407
    }
jaroslav@1258
   408
jaroslav@1258
   409
    /**
jaroslav@1258
   410
     * Set an identifier for the thread where the message originated.
jaroslav@1258
   411
     * @param threadID  the thread ID
jaroslav@1258
   412
     */
jaroslav@1258
   413
    public void setThreadID(int threadID) {
jaroslav@1258
   414
        this.threadID = threadID;
jaroslav@1258
   415
    }
jaroslav@1258
   416
jaroslav@1258
   417
    /**
jaroslav@1258
   418
     * Get event time in milliseconds since 1970.
jaroslav@1258
   419
     *
jaroslav@1258
   420
     * @return event time in millis since 1970
jaroslav@1258
   421
     */
jaroslav@1258
   422
    public long getMillis() {
jaroslav@1258
   423
        return millis;
jaroslav@1258
   424
    }
jaroslav@1258
   425
jaroslav@1258
   426
    /**
jaroslav@1258
   427
     * Set event time.
jaroslav@1258
   428
     *
jaroslav@1258
   429
     * @param millis event time in millis since 1970
jaroslav@1258
   430
     */
jaroslav@1258
   431
    public void setMillis(long millis) {
jaroslav@1258
   432
        this.millis = millis;
jaroslav@1258
   433
    }
jaroslav@1258
   434
jaroslav@1258
   435
    /**
jaroslav@1258
   436
     * Get any throwable associated with the log record.
jaroslav@1258
   437
     * <p>
jaroslav@1258
   438
     * If the event involved an exception, this will be the
jaroslav@1258
   439
     * exception object. Otherwise null.
jaroslav@1258
   440
     *
jaroslav@1258
   441
     * @return a throwable
jaroslav@1258
   442
     */
jaroslav@1258
   443
    public Throwable getThrown() {
jaroslav@1258
   444
        return thrown;
jaroslav@1258
   445
    }
jaroslav@1258
   446
jaroslav@1258
   447
    /**
jaroslav@1258
   448
     * Set a throwable associated with the log event.
jaroslav@1258
   449
     *
jaroslav@1258
   450
     * @param thrown  a throwable (may be null)
jaroslav@1258
   451
     */
jaroslav@1258
   452
    public void setThrown(Throwable thrown) {
jaroslav@1258
   453
        this.thrown = thrown;
jaroslav@1258
   454
    }
jaroslav@1258
   455
jaroslav@1258
   456
    private static final long serialVersionUID = 5372048053134512534L;
jaroslav@1258
   457
jaroslav@1258
   458
    /**
jaroslav@1258
   459
     * @serialData Default fields, followed by a two byte version number
jaroslav@1258
   460
     * (major byte, followed by minor byte), followed by information on
jaroslav@1258
   461
     * the log record parameter array.  If there is no parameter array,
jaroslav@1258
   462
     * then -1 is written.  If there is a parameter array (possible of zero
jaroslav@1258
   463
     * length) then the array length is written as an integer, followed
jaroslav@1258
   464
     * by String values for each parameter.  If a parameter is null, then
jaroslav@1258
   465
     * a null String is written.  Otherwise the output of Object.toString()
jaroslav@1258
   466
     * is written.
jaroslav@1258
   467
     */
jaroslav@1258
   468
    private void writeObject(ObjectOutputStream out) throws IOException {
jaroslav@1258
   469
        // We have to call defaultWriteObject first.
jaroslav@1258
   470
        out.defaultWriteObject();
jaroslav@1258
   471
jaroslav@1258
   472
        // Write our version number.
jaroslav@1258
   473
        out.writeByte(1);
jaroslav@1258
   474
        out.writeByte(0);
jaroslav@1258
   475
        if (parameters == null) {
jaroslav@1258
   476
            out.writeInt(-1);
jaroslav@1258
   477
            return;
jaroslav@1258
   478
        }
jaroslav@1258
   479
        out.writeInt(parameters.length);
jaroslav@1258
   480
        // Write string values for the parameters.
jaroslav@1258
   481
        for (int i = 0; i < parameters.length; i++) {
jaroslav@1258
   482
            if (parameters[i] == null) {
jaroslav@1258
   483
                out.writeObject(null);
jaroslav@1258
   484
            } else {
jaroslav@1258
   485
                out.writeObject(parameters[i].toString());
jaroslav@1258
   486
            }
jaroslav@1258
   487
        }
jaroslav@1258
   488
    }
jaroslav@1258
   489
jaroslav@1258
   490
    private void readObject(ObjectInputStream in)
jaroslav@1258
   491
                        throws IOException, ClassNotFoundException {
jaroslav@1258
   492
        // We have to call defaultReadObject first.
jaroslav@1258
   493
        in.defaultReadObject();
jaroslav@1258
   494
jaroslav@1258
   495
        // Read version number.
jaroslav@1258
   496
        byte major = in.readByte();
jaroslav@1258
   497
        byte minor = in.readByte();
jaroslav@1258
   498
        if (major != 1) {
jaroslav@1258
   499
            throw new IOException("LogRecord: bad version: " + major + "." + minor);
jaroslav@1258
   500
        }
jaroslav@1258
   501
        int len = in.readInt();
jaroslav@1258
   502
        if (len == -1) {
jaroslav@1258
   503
            parameters = null;
jaroslav@1258
   504
        } else {
jaroslav@1258
   505
            parameters = new Object[len];
jaroslav@1258
   506
            for (int i = 0; i < parameters.length; i++) {
jaroslav@1258
   507
                parameters[i] = in.readObject();
jaroslav@1258
   508
            }
jaroslav@1258
   509
        }
jaroslav@1258
   510
        // If necessary, try to regenerate the resource bundle.
jaroslav@1258
   511
        if (resourceBundleName != null) {
jaroslav@1258
   512
            try {
jaroslav@1258
   513
                resourceBundle = ResourceBundle.getBundle(resourceBundleName);
jaroslav@1258
   514
            } catch (MissingResourceException ex) {
jaroslav@1258
   515
                // This is not a good place to throw an exception,
jaroslav@1258
   516
                // so we simply leave the resourceBundle null.
jaroslav@1258
   517
                resourceBundle = null;
jaroslav@1258
   518
            }
jaroslav@1258
   519
        }
jaroslav@1258
   520
jaroslav@1258
   521
        needToInferCaller = false;
jaroslav@1258
   522
    }
jaroslav@1258
   523
jaroslav@1258
   524
    // Private method to infer the caller's class and method names
jaroslav@1258
   525
    private void inferCaller() {
jaroslav@1258
   526
        needToInferCaller = false;
jaroslav@1258
   527
        JavaLangAccess access = SharedSecrets.getJavaLangAccess();
jaroslav@1258
   528
        Throwable throwable = new Throwable();
jaroslav@1258
   529
        int depth = access.getStackTraceDepth(throwable);
jaroslav@1258
   530
jaroslav@1258
   531
        boolean lookingForLogger = true;
jaroslav@1258
   532
        for (int ix = 0; ix < depth; ix++) {
jaroslav@1258
   533
            // Calling getStackTraceElement directly prevents the VM
jaroslav@1258
   534
            // from paying the cost of building the entire stack frame.
jaroslav@1258
   535
            StackTraceElement frame =
jaroslav@1258
   536
                access.getStackTraceElement(throwable, ix);
jaroslav@1258
   537
            String cname = frame.getClassName();
jaroslav@1258
   538
            boolean isLoggerImpl = isLoggerImplFrame(cname);
jaroslav@1258
   539
            if (lookingForLogger) {
jaroslav@1258
   540
                // Skip all frames until we have found the first logger frame.
jaroslav@1258
   541
                if (isLoggerImpl) {
jaroslav@1258
   542
                    lookingForLogger = false;
jaroslav@1258
   543
                }
jaroslav@1258
   544
            } else {
jaroslav@1258
   545
                if (!isLoggerImpl) {
jaroslav@1258
   546
                    // skip reflection call
jaroslav@1258
   547
                    if (!cname.startsWith("java.lang.reflect.") && !cname.startsWith("sun.reflect.")) {
jaroslav@1258
   548
                       // We've found the relevant frame.
jaroslav@1258
   549
                       setSourceClassName(cname);
jaroslav@1258
   550
                       setSourceMethodName(frame.getMethodName());
jaroslav@1258
   551
                       return;
jaroslav@1258
   552
                    }
jaroslav@1258
   553
                }
jaroslav@1258
   554
            }
jaroslav@1258
   555
        }
jaroslav@1258
   556
        // We haven't found a suitable frame, so just punt.  This is
jaroslav@1258
   557
        // OK as we are only committed to making a "best effort" here.
jaroslav@1258
   558
    }
jaroslav@1258
   559
jaroslav@1258
   560
    private boolean isLoggerImplFrame(String cname) {
jaroslav@1258
   561
        // the log record could be created for a platform logger
jaroslav@1258
   562
        return (cname.equals("java.util.logging.Logger") ||
jaroslav@1258
   563
                cname.startsWith("java.util.logging.LoggingProxyImpl") ||
jaroslav@1258
   564
                cname.startsWith("sun.util.logging."));
jaroslav@1258
   565
    }
jaroslav@1258
   566
}