001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.util.logging;
019:
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.ObjectOutputStream;
023: import java.io.Serializable;
024: import java.util.MissingResourceException;
025: import java.util.ResourceBundle;
026:
027: import org.apache.harmony.logging.internal.nls.Messages;
028:
029: /**
030: * A <code>LogRecord</code> object represents a logging request. It is passed
031: * between the logging framework and individual logging handlers. Client
032: * applications should not modify a <code>LogRecord</code> object that has
033: * been passed into the logging framework.
034: * <p>
035: * The <code>LogRecord</code> class will infer the source method name and
036: * source class name the first time they are accessed if the client application
037: * didn't specify them explicitly. This automatic inference is based on the
038: * analysis of the call stack and is not guaranteed to be precise. Client
039: * applications should force the initialization of these two fields by calling
040: * <code>getSourceClassName</code> or <code>getSourceMethodName</code> if
041: * they expect to use them after passing the <code>LogRecord</code> object to
042: * another thread or transmitting it over RMI.
043: * </p>
044: */
045: public class LogRecord implements Serializable {
046:
047: private static final long serialVersionUID = 5372048053134512534L;
048:
049: // The major byte used in serialization.
050: private static final int MAJOR = 1;
051:
052: // The minor byte used in serialization.
053: private static final int MINOR = 4;
054:
055: // Store the current value for the sequence number.
056: private static long currentSequenceNumber = 0;
057:
058: // Store the id for each thread.
059: private static ThreadLocal<Integer> currentThreadId = new ThreadLocal<Integer>();
060:
061: // The base id as the starting point for thread ID allocation.
062: private static int initThreadId = 0;
063:
064: /**
065: * The logging level.
066: *
067: * @serial
068: */
069: private Level level;
070:
071: /**
072: * The sequence number.
073: *
074: * @serial
075: */
076: private long sequenceNumber;
077:
078: /**
079: * The name of the class that issued the logging call.
080: *
081: * @serial
082: */
083: private String sourceClassName;
084:
085: /**
086: * The name of the method that issued the logging call.
087: *
088: * @serial
089: */
090: private String sourceMethodName;
091:
092: /**
093: * The original message text.
094: *
095: * @serial
096: */
097: private String message;
098:
099: /**
100: * The ID of the thread that issued the logging call.
101: *
102: * @serial
103: */
104: private int threadID;
105:
106: /**
107: * The time that the event occurred, in milliseconds since 1970.
108: *
109: * @serial
110: */
111: private long millis;
112:
113: /**
114: * The associated <code>Throwable</code> object if any.
115: *
116: * @serial
117: */
118: private Throwable thrown;
119:
120: /**
121: * The name of the source logger.
122: *
123: * @serial
124: */
125: private String loggerName;
126:
127: /**
128: * The name of the resource bundle used to localize the log message.
129: *
130: * @serial
131: */
132: private String resourceBundleName;
133:
134: // The associated resource bundle if any.
135: private transient ResourceBundle resourceBundle;
136:
137: // The parameters.
138: private transient Object[] parameters;
139:
140: // If the source method and source class has been initialized
141: private transient boolean sourceInited;
142:
143: /**
144: * Constructs a <code>LogRecord</code> object using the supplied the
145: * logging level and message. The millis property is set to the current
146: * time. The sequence property is set to a new unique value, allocated in
147: * increasing order within a VM. The thread ID is set to a unique value for
148: * the current thread. All other properties are set to <code>null</code>.
149: *
150: * @param level
151: * the logging level which may not be null
152: * @param msg
153: * the raw message
154: */
155: public LogRecord(Level level, String msg) {
156: if (null == level) {
157: // logging.4=The 'level' parameter is null.
158: throw new NullPointerException(Messages
159: .getString("logging.4")); //$NON-NLS-1$
160: }
161: this .level = level;
162: this .message = msg;
163: this .millis = System.currentTimeMillis();
164:
165: synchronized (LogRecord.class) {
166: this .sequenceNumber = currentSequenceNumber++;
167: Integer id = currentThreadId.get();
168: if (null == id) {
169: this .threadID = initThreadId;
170: currentThreadId.set(Integer.valueOf(initThreadId++));
171: } else {
172: this .threadID = id.intValue();
173: }
174: }
175:
176: this .sourceClassName = null;
177: this .sourceMethodName = null;
178: this .loggerName = null;
179: this .parameters = null;
180: this .resourceBundle = null;
181: this .resourceBundleName = null;
182: this .thrown = null;
183: }
184:
185: /**
186: * Gets the logging level.
187: *
188: * @return the logging level
189: */
190: public Level getLevel() {
191: return level;
192: }
193:
194: /**
195: * Sets the logging level.
196: *
197: * @param level
198: * the level to set
199: */
200: public void setLevel(Level level) {
201: if (null == level) {
202: // logging.4=The 'level' parameter is null.
203: throw new NullPointerException(Messages
204: .getString("logging.4")); //$NON-NLS-1$
205: }
206: this .level = level;
207: }
208:
209: /**
210: * Gets the name of the logger.
211: *
212: * @return the logger name
213: */
214: public String getLoggerName() {
215: return loggerName;
216: }
217:
218: /**
219: * Sets the name of the logger.
220: *
221: * @param loggerName
222: * the logger name to set
223: */
224: public void setLoggerName(String loggerName) {
225: this .loggerName = loggerName;
226: }
227:
228: /**
229: * Gets the raw message.
230: *
231: * @return the raw message
232: */
233: public String getMessage() {
234: return message;
235: }
236:
237: /**
238: * Sets the raw message.
239: *
240: * @param message
241: * the raw message to set
242: */
243: public void setMessage(String message) {
244: this .message = message;
245: }
246:
247: /**
248: * Gets the time that the event occurred, in milliseconds since 1970.
249: *
250: * @return the time that the event occurred, in milliseconds since 1970
251: */
252: public long getMillis() {
253: return millis;
254: }
255:
256: /**
257: * Sets the time that the event occurred, in milliseconds since 1970.
258: *
259: * @param millis
260: * the time that the event occurred, in milliseconds since 1970
261: */
262: public void setMillis(long millis) {
263: this .millis = millis;
264: }
265:
266: /**
267: * Gets the parameters.
268: *
269: * @return the array of parameters
270: */
271: public Object[] getParameters() {
272: return parameters;
273: }
274:
275: /**
276: * Sets the parameters.
277: *
278: * @param parameters
279: * the array of parameters to set
280: */
281: public void setParameters(Object[] parameters) {
282: this .parameters = parameters;
283: }
284:
285: /**
286: * Gets the resource bundle used to localize the raw message during
287: * formatting.
288: *
289: * @return the associated resource bundle
290: */
291: public ResourceBundle getResourceBundle() {
292: return resourceBundle;
293: }
294:
295: /**
296: * Sets the resource bundle used to localize the raw message during
297: * formatting.
298: *
299: * @param resourceBundle
300: * the resource bundle to set
301: */
302: public void setResourceBundle(ResourceBundle resourceBundle) {
303: this .resourceBundle = resourceBundle;
304: }
305:
306: /**
307: * Gets the name of the resource bundle.
308: *
309: * @return the name of the resource bundle
310: */
311: public String getResourceBundleName() {
312: return resourceBundleName;
313: }
314:
315: /**
316: * Sets the name of the resource bundle.
317: *
318: * @param resourceBundleName
319: * the name of the resource bundle to set
320: */
321: public void setResourceBundleName(String resourceBundleName) {
322: this .resourceBundleName = resourceBundleName;
323: }
324:
325: /**
326: * Gets the sequence number.
327: *
328: * @return the sequence number
329: */
330: public long getSequenceNumber() {
331: return sequenceNumber;
332: }
333:
334: /**
335: * Sets the sequence number. It is usually unnecessary to call this method
336: * to change the sequence number because the number is allocated when this
337: * instance is constructed.
338: *
339: * @param sequenceNumber
340: * the sequence number to set
341: */
342: public void setSequenceNumber(long sequenceNumber) {
343: this .sequenceNumber = sequenceNumber;
344: }
345:
346: /**
347: * Gets the name of the class that issued the logging call.
348: *
349: * @return the name of the class that issued the logging call
350: */
351: public String getSourceClassName() {
352: initSource();
353: return sourceClassName;
354: }
355:
356: /*
357: * Init the sourceClass and sourceMethod fields.
358: */
359: private void initSource() {
360: if (!sourceInited) {
361: StackTraceElement[] elements = (new Throwable())
362: .getStackTrace();
363: int i = 0;
364: String current = null;
365: FINDLOG: for (; i < elements.length; i++) {
366: current = elements[i].getClassName();
367: if (current.equals(Logger.class.getName())) {
368: break FINDLOG;
369: }
370: }
371: while (++i < elements.length
372: && elements[i].getClassName().equals(current)) {
373: // do nothing
374: }
375: if (i < elements.length) {
376: this .sourceClassName = elements[i].getClassName();
377: this .sourceMethodName = elements[i].getMethodName();
378: }
379: sourceInited = true;
380: }
381: }
382:
383: /**
384: * Sets the name of the class that issued the logging call.
385: *
386: * @param sourceClassName
387: * the name of the class that issued the logging call
388: */
389: public void setSourceClassName(String sourceClassName) {
390: sourceInited = true;
391: this .sourceClassName = sourceClassName;
392: }
393:
394: /**
395: * Gets the name of the method that issued the logging call.
396: *
397: * @return the name of the method that issued the logging call
398: */
399: public String getSourceMethodName() {
400: initSource();
401: return sourceMethodName;
402: }
403:
404: /**
405: * Sets the name of the method that issued the logging call.
406: *
407: * @param sourceMethodName
408: * the name of the method that issued the logging call
409: */
410: public void setSourceMethodName(String sourceMethodName) {
411: sourceInited = true;
412: this .sourceMethodName = sourceMethodName;
413: }
414:
415: /**
416: * Gets the ID of the thread originating the message.
417: *
418: * @return the ID of the thread originating the message
419: */
420: public int getThreadID() {
421: return threadID;
422: }
423:
424: /**
425: * Sets the ID of the thread originating the message.
426: *
427: * @param threadID
428: * the ID of the thread originating the message
429: */
430: public void setThreadID(int threadID) {
431: this .threadID = threadID;
432: }
433:
434: /**
435: * Gets the <code>Throwable</code> object associated with this log record.
436: *
437: * @return the <code>Throwable</code> object associated with this log
438: * record
439: */
440: public Throwable getThrown() {
441: return thrown;
442: }
443:
444: /**
445: * Sets the <code>Throwable</code> object associated with this log record.
446: *
447: * @param thrown
448: * the <code>Throwable</code> object associated with this log
449: * record
450: */
451: public void setThrown(Throwable thrown) {
452: this .thrown = thrown;
453: }
454:
455: /*
456: * Customized serialization.
457: */
458: private void writeObject(ObjectOutputStream out) throws IOException {
459: out.defaultWriteObject();
460: out.writeByte(MAJOR);
461: out.writeByte(MINOR);
462: if (null == parameters) {
463: out.writeInt(-1);
464: } else {
465: out.writeInt(parameters.length);
466: for (Object element : parameters) {
467: out.writeObject(null == element ? null : element
468: .toString());
469: }
470: }
471: }
472:
473: /*
474: * Customized deserialization.
475: */
476: private void readObject(ObjectInputStream in) throws IOException,
477: ClassNotFoundException {
478: in.defaultReadObject();
479: byte major = in.readByte();
480: byte minor = in.readByte();
481: // only check MAJOR version
482: if (major != MAJOR) {
483: // logging.5=Different version - {0}.{1}
484: throw new IOException(Messages.getString(
485: "logging.5", major, minor)); //$NON-NLS-1$
486: }
487:
488: int length = in.readInt();
489: if (length >= 0) {
490: parameters = new Object[length];
491: for (int i = 0; i < parameters.length; i++) {
492: parameters[i] = in.readObject();
493: }
494: }
495: if (null != resourceBundleName) {
496: try {
497: resourceBundle = Logger
498: .loadResourceBundle(resourceBundleName);
499: } catch (MissingResourceException e) {
500: // Cannot find the specified resource bundle
501: resourceBundle = null;
502: }
503: }
504: }
505: }
|