summaryrefslogtreecommitdiffstats
path: root/luni/src/main/java/java/util/logging/Handler.java
blob: 13dbdd5b3de95e292087b182099981c13524b5fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package java.util.logging;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

/**
 * A {@code Handler} object accepts a logging request and exports the desired
 * messages to a target, for example, a file, the console, etc. It can be
 * disabled by setting its logging level to {@code Level.OFF}.
 */
public abstract class Handler {

    private static final Level DEFAULT_LEVEL = Level.ALL;

    // the error manager to report errors during logging
    private ErrorManager errorMan;

    // the character encoding used by this handler
    private String encoding;

    // the logging level
    private Level level;

    // the formatter used to export messages
    private Formatter formatter;

    // the filter used to filter undesired messages
    private Filter filter;

    // class name, used for property reading
    private String prefix;

    /**
     * Constructs a {@code Handler} object with a default error manager instance
     * {@code ErrorManager}, the default encoding, and the default logging
     * level {@code Level.ALL}. It has no filter and no formatter.
     */
    protected Handler() {
        this.errorMan = new ErrorManager();
        this.level = DEFAULT_LEVEL;
        this.encoding = null;
        this.filter = null;
        this.formatter = null;
        this.prefix = this.getClass().getName();
    }

    // get a instance from given class name, using Class.forName()
    private Object getDefaultInstance(String className) {
        Object result = null;
        if (className == null) {
            return result;
        }
        try {
            result = Class.forName(className).newInstance();
        } catch (Exception e) {
            // ignore
        }
        return result;
    }

    // get a instance from given class name, using context classloader
    private Object getCustomizeInstance(final String className) throws Exception {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        if (loader == null) {
            loader = ClassLoader.getSystemClassLoader();
        }
        Class<?> c = loader.loadClass(className);
        return c.newInstance();
    }

    // print error message in some format
    void printInvalidPropMessage(String key, String value, Exception e) {
        String msg = "Invalid property value for " + prefix + ":" + key + "/" + value;
        errorMan.error(msg, e, ErrorManager.GENERIC_FAILURE);
    }

    /**
     * init the common properties, including filter, level, formatter, and
     * encoding
     */
    void initProperties(String defaultLevel, String defaultFilter,
            String defaultFormatter, String defaultEncoding) {
        LogManager manager = LogManager.getLogManager();

        // set filter
        final String filterName = manager.getProperty(prefix + ".filter");
        if (filterName != null) {
            try {
                filter = (Filter) getCustomizeInstance(filterName);
            } catch (Exception e1) {
                printInvalidPropMessage("filter", filterName, e1);
                filter = (Filter) getDefaultInstance(defaultFilter);
            }
        } else {
            filter = (Filter) getDefaultInstance(defaultFilter);
        }

        // set level
        String levelName = manager.getProperty(prefix + ".level");
        if (levelName != null) {
            try {
                level = Level.parse(levelName);
            } catch (Exception e) {
                printInvalidPropMessage("level", levelName, e);
                level = Level.parse(defaultLevel);
            }
        } else {
            level = Level.parse(defaultLevel);
        }

        // set formatter
        final String formatterName = manager.getProperty(prefix + ".formatter");
        if (formatterName != null) {
            try {
                formatter = (Formatter) getCustomizeInstance(formatterName);
            } catch (Exception e) {
                printInvalidPropMessage("formatter", formatterName, e);
                formatter = (Formatter) getDefaultInstance(defaultFormatter);
            }
        } else {
            formatter = (Formatter) getDefaultInstance(defaultFormatter);
        }

        // set encoding
        final String encodingName = manager.getProperty(prefix + ".encoding");
        try {
            internalSetEncoding(encodingName);
        } catch (UnsupportedEncodingException e) {
            printInvalidPropMessage("encoding", encodingName, e);
        }
    }

    /**
     * Closes this handler. A flush operation will be performed and all the
     * associated resources will be freed. Client applications should not use
     * this handler after closing it.
     */
    public abstract void close();

    /**
     * Flushes any buffered output.
     */
    public abstract void flush();

    /**
     * Accepts a logging request and sends it to the the target.
     *
     * @param record
     *            the log record to be logged; {@code null} records are ignored.
     */
    public abstract void publish(LogRecord record);

    /**
     * Gets the character encoding used by this handler, {@code null} for
     * default encoding.
     *
     * @return the character encoding used by this handler.
     */
    public String getEncoding() {
        return this.encoding;
    }

    /**
     * Gets the error manager used by this handler to report errors during
     * logging.
     *
     * @return the error manager used by this handler.
     */
    public ErrorManager getErrorManager() {
        LogManager.getLogManager().checkAccess();
        return this.errorMan;
    }

    /**
     * Gets the filter used by this handler.
     *
     * @return the filter used by this handler (possibly {@code null}).
     */
    public Filter getFilter() {
        return this.filter;
    }

    /**
     * Gets the formatter used by this handler to format the logging messages.
     *
     * @return the formatter used by this handler (possibly {@code null}).
     */
    public Formatter getFormatter() {
        return this.formatter;
    }

    /**
     * Gets the logging level of this handler, records with levels lower than
     * this value will be dropped.
     *
     * @return the logging level of this handler.
     */
    public Level getLevel() {
        return this.level;
    }

    /**
     * Determines whether the supplied log record needs to be logged. The
     * logging levels will be checked as well as the filter.
     *
     * @param record
     *            the log record to be checked.
     * @return {@code true} if the supplied log record needs to be logged,
     *         otherwise {@code false}.
     */
    public boolean isLoggable(LogRecord record) {
        if (record == null) {
            throw new NullPointerException("record == null");
        }
        if (this.level.intValue() == Level.OFF.intValue()) {
            return false;
        } else if (record.getLevel().intValue() >= this.level.intValue()) {
            return this.filter == null || this.filter.isLoggable(record);
        }
        return false;
    }

    /**
     * Reports an error to the error manager associated with this handler,
     * {@code ErrorManager} is used for that purpose. No security checks are
     * done, therefore this is compatible with environments where the caller
     * is non-privileged.
     *
     * @param msg
     *            the error message, may be {@code null}.
     * @param ex
     *            the associated exception, may be {@code null}.
     * @param code
     *            an {@code ErrorManager} error code.
     */
    protected void reportError(String msg, Exception ex, int code) {
        this.errorMan.error(msg, ex, code);
    }

    /**
     * Sets the character encoding used by this handler. A {@code null} value
     * indicates the use of the default encoding. This internal method does
     * not check security.
     *
     * @param newEncoding
     *            the character encoding to set.
     * @throws UnsupportedEncodingException
     *             if the specified encoding is not supported by the runtime.
     */
    void internalSetEncoding(String newEncoding) throws UnsupportedEncodingException {
        // accepts "null" because it indicates using default encoding
        if (newEncoding == null) {
            this.encoding = null;
        } else {
            if (Charset.isSupported(newEncoding)) {
                this.encoding = newEncoding;
            } else {
                throw new UnsupportedEncodingException(newEncoding);
            }
        }
    }

    /**
     * Sets the character encoding used by this handler, {@code null} indicates
     * a default encoding.
     *
     * @param encoding
     *            the character encoding to set.
     * @throws UnsupportedEncodingException
     *             if the specified encoding is not supported by the runtime.
     */
    public void setEncoding(String encoding) throws UnsupportedEncodingException {
        LogManager.getLogManager().checkAccess();
        internalSetEncoding(encoding);
    }

    /**
     * Sets the error manager for this handler.
     *
     * @param newErrorManager
     *            the error manager to set.
     * @throws NullPointerException
     *             if {@code em} is {@code null}.
     */
    public void setErrorManager(ErrorManager newErrorManager) {
        LogManager.getLogManager().checkAccess();
        if (newErrorManager == null) {
            throw new NullPointerException("newErrorManager == null");
        }
        this.errorMan = newErrorManager;
    }

    /**
     * Sets the filter to be used by this handler.
     *
     * @param newFilter
     *            the filter to set, may be {@code null}.
     */
    public void setFilter(Filter newFilter) {
        LogManager.getLogManager().checkAccess();
        this.filter = newFilter;
    }

    /**
     * Sets the formatter to be used by this handler. This internal method does
     * not check security.
     *
     * @param newFormatter
     *            the formatter to set.
     */
    void internalSetFormatter(Formatter newFormatter) {
        if (newFormatter == null) {
            throw new NullPointerException("newFormatter == null");
        }
        this.formatter = newFormatter;
    }

    /**
     * Sets the formatter to be used by this handler.
     *
     * @param newFormatter
     *            the formatter to set.
     * @throws NullPointerException
     *             if {@code newFormatter} is {@code null}.
     */
    public void setFormatter(Formatter newFormatter) {
        LogManager.getLogManager().checkAccess();
        internalSetFormatter(newFormatter);
    }

    /**
     * Sets the logging level of the messages logged by this handler, levels
     * lower than this value will be dropped.
     *
     * @param newLevel
     *            the logging level to set.
     * @throws NullPointerException
     *             if {@code newLevel} is {@code null}.
     */
    public void setLevel(Level newLevel) {
        if (newLevel == null) {
            throw new NullPointerException("newLevel == null");
        }
        LogManager.getLogManager().checkAccess();
        this.level = newLevel;
    }
}