Source Code Cross Referenced for FileHandler.java in  » 6.0-JDK-Core » Collections-Jar-Zip-Logging-regex » java » util » logging » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » Collections Jar Zip Logging regex » java.util.logging 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025
026        package java.util.logging;
027
028        import java.io.*;
029        import java.nio.channels.FileChannel;
030        import java.nio.channels.FileLock;
031        import java.security.*;
032
033        /**
034         * Simple file logging <tt>Handler</tt>.
035         * <p>
036         * The <tt>FileHandler</tt> can either write to a specified file,
037         * or it can write to a rotating set of files.  
038         * <p>
039         * For a rotating set of files, as each file reaches a given size
040         * limit, it is closed, rotated out, and a new file opened.
041         * Successively older files are named by adding "0", "1", "2", 
042         * etc into the base filename.
043         * <p>
044         * By default buffering is enabled in the IO libraries but each log
045         * record is flushed out when it is complete. 
046         * <p>
047         * By default the <tt>XMLFormatter</tt> class is used for formatting.
048         * <p>
049         * <b>Configuration:</b>
050         * By default each <tt>FileHandler</tt> is initialized using the following
051         * <tt>LogManager</tt> configuration properties.  If properties are not defined
052         * (or have invalid values) then the specified default values are used.
053         * <ul>
054         * <li>   java.util.logging.FileHandler.level 
055         *	  specifies the default level for the <tt>Handler</tt>
056         *	  (defaults to <tt>Level.ALL</tt>).
057         * <li>   java.util.logging.FileHandler.filter 
058         * 	  specifies the name of a <tt>Filter</tt> class to use
059         *	  (defaults to no <tt>Filter</tt>).
060         * <li>   java.util.logging.FileHandler.formatter 
061         *	  specifies the name of a <tt>Formatter</tt> class to use
062         *        (defaults to <tt>java.util.logging.XMLFormatter</tt>)
063         * <li>   java.util.logging.FileHandler.encoding 
064         *	  the name of the character set encoding to use (defaults to
065         *	  the default platform encoding).
066         * <li>   java.util.logging.FileHandler.limit 
067         *	  specifies an approximate maximum amount to write (in bytes)
068         * 	  to any one file.  If this is zero, then there is no limit.
069         *	  (Defaults to no limit).
070         * <li>   java.util.logging.FileHandler.count 
071         *	  specifies how many output files to cycle through (defaults to 1).
072         * <li>   java.util.logging.FileHandler.pattern 
073         *	  specifies a pattern for generating the output file name.  See
074         *        below for details. (Defaults to "%h/java%u.log").
075         * <li>   java.util.logging.FileHandler.append
076         *	  specifies whether the FileHandler should append onto
077         *        any existing files (defaults to false).
078         * </ul>
079         * <p>
080         * <p>
081         * A pattern consists of a string that includes the following special
082         * components that will be replaced at runtime:
083         * <ul>
084         * <li>    "/"    the local pathname separator 
085         * <li>     "%t"   the system temporary directory
086         * <li>     "%h"   the value of the "user.home" system property
087         * <li>     "%g"   the generation number to distinguish rotated logs
088         * <li>     "%u"   a unique number to resolve conflicts
089         * <li>     "%%"   translates to a single percent sign "%"
090         * </ul>
091         * If no "%g" field has been specified and the file count is greater
092         * than one, then the generation number will be added to the end of
093         * the generated filename, after a dot.
094         * <p> 
095         * Thus for example a pattern of "%t/java%g.log" with a count of 2
096         * would typically cause log files to be written on Solaris to 
097         * /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they
098         * would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log
099         * <p> 
100         * Generation numbers follow the sequence 0, 1, 2, etc.
101         * <p>
102         * Normally the "%u" unique field is set to 0.  However, if the <tt>FileHandler</tt>
103         * tries to open the filename and finds the file is currently in use by
104         * another process it will increment the unique number field and try
105         * again.  This will be repeated until <tt>FileHandler</tt> finds a file name that
106         * is  not currently in use. If there is a conflict and no "%u" field has
107         * been specified, it will be added at the end of the filename after a dot.
108         * (This will be after any automatically added generation number.)
109         * <p>
110         * Thus if three processes were all trying to log to fred%u.%g.txt then 
111         * they  might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as
112         * the first file in their rotating sequences.
113         * <p>
114         * Note that the use of unique ids to avoid conflicts is only guaranteed
115         * to work reliably when using a local disk file system.
116         *
117         * @version 1.43, 05/09/07
118         * @since 1.4
119         */
120
121        public class FileHandler extends StreamHandler {
122            private MeteredStream meter;
123            private boolean append;
124            private int limit; // zero => no limit.
125            private int count;
126            private String pattern;
127            private String lockFileName;
128            private FileOutputStream lockStream;
129            private File files[];
130            private static final int MAX_LOCKS = 100;
131            private static java.util.HashMap<String, String> locks = new java.util.HashMap<String, String>();
132
133            // A metered stream is a subclass of OutputStream that
134            //   (a) forwards all its output to a target stream
135            //   (b) keeps track of how many bytes have been written
136            private class MeteredStream extends OutputStream {
137                OutputStream out;
138                int written;
139
140                MeteredStream(OutputStream out, int written) {
141                    this .out = out;
142                    this .written = written;
143                }
144
145                public void write(int b) throws IOException {
146                    out.write(b);
147                    written++;
148                }
149
150                public void write(byte buff[]) throws IOException {
151                    out.write(buff);
152                    written += buff.length;
153                }
154
155                public void write(byte buff[], int off, int len)
156                        throws IOException {
157                    out.write(buff, off, len);
158                    written += len;
159                }
160
161                public void flush() throws IOException {
162                    out.flush();
163                }
164
165                public void close() throws IOException {
166                    out.close();
167                }
168            }
169
170            private void open(File fname, boolean append) throws IOException {
171                int len = 0;
172                if (append) {
173                    len = (int) fname.length();
174                }
175                FileOutputStream fout = new FileOutputStream(fname.toString(),
176                        append);
177                BufferedOutputStream bout = new BufferedOutputStream(fout);
178                meter = new MeteredStream(bout, len);
179                setOutputStream(meter);
180            }
181
182            // Private method to configure a FileHandler from LogManager
183            // properties and/or default values as specified in the class
184            // javadoc.
185            private void configure() {
186                LogManager manager = LogManager.getLogManager();
187
188                String cname = getClass().getName();
189
190                pattern = manager.getStringProperty(cname + ".pattern",
191                        "%h/java%u.log");
192                limit = manager.getIntProperty(cname + ".limit", 0);
193                if (limit < 0) {
194                    limit = 0;
195                }
196                count = manager.getIntProperty(cname + ".count", 1);
197                if (count <= 0) {
198                    count = 1;
199                }
200                append = manager.getBooleanProperty(cname + ".append", false);
201                setLevel(manager.getLevelProperty(cname + ".level", Level.ALL));
202                setFilter(manager.getFilterProperty(cname + ".filter", null));
203                setFormatter(manager.getFormatterProperty(cname + ".formatter",
204                        new XMLFormatter()));
205                try {
206                    setEncoding(manager.getStringProperty(cname + ".encoding",
207                            null));
208                } catch (Exception ex) {
209                    try {
210                        setEncoding(null);
211                    } catch (Exception ex2) {
212                        // doing a setEncoding with null should always work.
213                        // assert false;
214                    }
215                }
216            }
217
218            /**
219             * Construct a default <tt>FileHandler</tt>.  This will be configured
220             * entirely from <tt>LogManager</tt> properties (or their default values).
221             * <p>
222             * @exception  IOException if there are IO problems opening the files.
223             * @exception  SecurityException  if a security manager exists and if
224             *             the caller does not have <tt>LoggingPermission("control"))</tt>.
225             * @exception  NullPointerException if pattern property is an empty String.
226             */
227            public FileHandler() throws IOException, SecurityException {
228                checkAccess();
229                configure();
230                openFiles();
231            }
232
233            /**
234             * Initialize a <tt>FileHandler</tt> to write to the given filename.
235             * <p>
236             * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
237             * properties (or their default values) except that the given pattern 
238             * argument is used as the filename pattern, the file limit is
239             * set to no limit, and the file count is set to one.
240             * <p>
241             * There is no limit on the amount of data that may be written,
242             * so use this with care.
243             *
244             * @param pattern  the name of the output file
245             * @exception  IOException if there are IO problems opening the files.
246             * @exception  SecurityException  if a security manager exists and if
247             *             the caller does not have <tt>LoggingPermission("control")</tt>.
248             * @exception  IllegalArgumentException if pattern is an empty string
249             */
250            public FileHandler(String pattern) throws IOException,
251                    SecurityException {
252                if (pattern.length() < 1) {
253                    throw new IllegalArgumentException();
254                }
255                checkAccess();
256                configure();
257                this .pattern = pattern;
258                this .limit = 0;
259                this .count = 1;
260                openFiles();
261            }
262
263            /**
264             * Initialize a <tt>FileHandler</tt> to write to the given filename,
265             * with optional append.
266             * <p>
267             * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
268             * properties (or their default values) except that the given pattern 
269             * argument is used as the filename pattern, the file limit is
270             * set to no limit, the file count is set to one, and the append
271             * mode is set to the given <tt>append</tt> argument.
272             * <p>
273             * There is no limit on the amount of data that may be written,
274             * so use this with care.
275             *
276             * @param pattern  the name of the output file
277             * @param append  specifies append mode
278             * @exception  IOException if there are IO problems opening the files.
279             * @exception  SecurityException  if a security manager exists and if
280             *             the caller does not have <tt>LoggingPermission("control")</tt>.
281             * @exception  IllegalArgumentException if pattern is an empty string
282             */
283            public FileHandler(String pattern, boolean append)
284                    throws IOException, SecurityException {
285                if (pattern.length() < 1) {
286                    throw new IllegalArgumentException();
287                }
288                checkAccess();
289                configure();
290                this .pattern = pattern;
291                this .limit = 0;
292                this .count = 1;
293                this .append = append;
294                openFiles();
295            }
296
297            /**
298             * Initialize a <tt>FileHandler</tt> to write to a set of files.  When
299             * (approximately) the given limit has been written to one file,
300             * another file will be opened.  The output will cycle through a set
301             * of count files.
302             * <p>
303             * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
304             * properties (or their default values) except that the given pattern 
305             * argument is used as the filename pattern, the file limit is
306             * set to the limit argument, and the file count is set to the
307             * given count argument.
308             * <p>
309             * The count must be at least 1.
310             *
311             * @param pattern  the pattern for naming the output file
312             * @param limit  the maximum number of bytes to write to any one file
313             * @param count  the number of files to use
314             * @exception  IOException if there are IO problems opening the files.
315             * @exception  SecurityException  if a security manager exists and if
316             *             the caller does not have <tt>LoggingPermission("control")</tt>.
317             * @exception IllegalArgumentException if limit < 0, or count < 1.
318             * @exception  IllegalArgumentException if pattern is an empty string
319             */
320            public FileHandler(String pattern, int limit, int count)
321                    throws IOException, SecurityException {
322                if (limit < 0 || count < 1 || pattern.length() < 1) {
323                    throw new IllegalArgumentException();
324                }
325                checkAccess();
326                configure();
327                this .pattern = pattern;
328                this .limit = limit;
329                this .count = count;
330                openFiles();
331            }
332
333            /**
334             * Initialize a <tt>FileHandler</tt> to write to a set of files
335             * with optional append.  When (approximately) the given limit has
336             * been written to one file, another file will be opened.  The
337             * output will cycle through a set of count files.
338             * <p>
339             * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
340             * properties (or their default values) except that the given pattern 
341             * argument is used as the filename pattern, the file limit is
342             * set to the limit argument, and the file count is set to the
343             * given count argument, and the append mode is set to the given
344             * <tt>append</tt> argument.
345             * <p>
346             * The count must be at least 1.
347             *
348             * @param pattern  the pattern for naming the output file
349             * @param limit  the maximum number of bytes to write to any one file
350             * @param count  the number of files to use
351             * @param append  specifies append mode
352             * @exception  IOException if there are IO problems opening the files.
353             * @exception  SecurityException  if a security manager exists and if
354             *             the caller does not have <tt>LoggingPermission("control")</tt>.
355             * @exception IllegalArgumentException if limit < 0, or count < 1.
356             * @exception  IllegalArgumentException if pattern is an empty string
357             *
358             */
359            public FileHandler(String pattern, int limit, int count,
360                    boolean append) throws IOException, SecurityException {
361                if (limit < 0 || count < 1 || pattern.length() < 1) {
362                    throw new IllegalArgumentException();
363                }
364                checkAccess();
365                configure();
366                this .pattern = pattern;
367                this .limit = limit;
368                this .count = count;
369                this .append = append;
370                openFiles();
371            }
372
373            // Private method to open the set of output files, based on the
374            // configured instance variables.
375            private void openFiles() throws IOException {
376                LogManager manager = LogManager.getLogManager();
377                manager.checkAccess();
378                if (count < 1) {
379                    throw new IllegalArgumentException("file count = " + count);
380                }
381                if (limit < 0) {
382                    limit = 0;
383                }
384
385                // We register our own ErrorManager during initialization
386                // so we can record exceptions.
387                InitializationErrorManager em = new InitializationErrorManager();
388                setErrorManager(em);
389
390                // Create a lock file.  This grants us exclusive access
391                // to our set of output files, as long as we are alive.
392                int unique = -1;
393                for (;;) {
394                    unique++;
395                    if (unique > MAX_LOCKS) {
396                        throw new IOException("Couldn't get lock for "
397                                + pattern);
398                    }
399                    // Generate a lock file name from the "unique" int.
400                    lockFileName = generate(pattern, 0, unique).toString()
401                            + ".lck";
402                    // Now try to lock that filename.
403                    // Because some systems (e.g. Solaris) can only do file locks
404                    // between processes (and not within a process), we first check
405                    // if we ourself already have the file locked.
406                    synchronized (locks) {
407                        if (locks.get(lockFileName) != null) {
408                            // We already own this lock, for a different FileHandler
409                            // object.  Try again.
410                            continue;
411                        }
412                        FileChannel fc;
413                        try {
414                            lockStream = new FileOutputStream(lockFileName);
415                            fc = lockStream.getChannel();
416                        } catch (IOException ix) {
417                            // We got an IOException while trying to open the file.
418                            // Try the next file.
419                            continue;
420                        }
421                        try {
422                            FileLock fl = fc.tryLock();
423                            if (fl == null) {
424                                // We failed to get the lock.  Try next file.
425                                continue;
426                            }
427                            // We got the lock OK.
428                        } catch (IOException ix) {
429                            // We got an IOException while trying to get the lock.
430                            // This normally indicates that locking is not supported
431                            // on the target directory.  We have to proceed without
432                            // getting a lock.   Drop through.
433                        }
434                        // We got the lock.  Remember it.
435                        locks.put(lockFileName, lockFileName);
436                        break;
437                    }
438                }
439
440                files = new File[count];
441                for (int i = 0; i < count; i++) {
442                    files[i] = generate(pattern, i, unique);
443                }
444
445                // Create the initial log file.
446                if (append) {
447                    open(files[0], true);
448                } else {
449                    rotate();
450                }
451
452                // Did we detect any exceptions during initialization?
453                Exception ex = em.lastException;
454                if (ex != null) {
455                    if (ex instanceof  IOException) {
456                        throw (IOException) ex;
457                    } else if (ex instanceof  SecurityException) {
458                        throw (SecurityException) ex;
459                    } else {
460                        throw new IOException("Exception: " + ex);
461                    }
462                }
463
464                // Install the normal default ErrorManager.
465                setErrorManager(new ErrorManager());
466            }
467
468            // Generate a filename from a pattern.
469            private File generate(String pattern, int generation, int unique)
470                    throws IOException {
471                File file = null;
472                String word = "";
473                int ix = 0;
474                boolean sawg = false;
475                boolean sawu = false;
476                while (ix < pattern.length()) {
477                    char ch = pattern.charAt(ix);
478                    ix++;
479                    char ch2 = 0;
480                    if (ix < pattern.length()) {
481                        ch2 = Character.toLowerCase(pattern.charAt(ix));
482                    }
483                    if (ch == '/') {
484                        if (file == null) {
485                            file = new File(word);
486                        } else {
487                            file = new File(file, word);
488                        }
489                        word = "";
490                        continue;
491                    } else if (ch == '%') {
492                        if (ch2 == 't') {
493                            String tmpDir = System
494                                    .getProperty("java.io.tmpdir");
495                            if (tmpDir == null) {
496                                tmpDir = System.getProperty("user.home");
497                            }
498                            file = new File(tmpDir);
499                            ix++;
500                            word = "";
501                            continue;
502                        } else if (ch2 == 'h') {
503                            file = new File(System.getProperty("user.home"));
504                            if (isSetUID()) {
505                                // Ok, we are in a set UID program.  For safety's sake
506                                // we disallow attempts to open files relative to %h.
507                                throw new IOException(
508                                        "can't use %h in set UID program");
509                            }
510                            ix++;
511                            word = "";
512                            continue;
513                        } else if (ch2 == 'g') {
514                            word = word + generation;
515                            sawg = true;
516                            ix++;
517                            continue;
518                        } else if (ch2 == 'u') {
519                            word = word + unique;
520                            sawu = true;
521                            ix++;
522                            continue;
523                        } else if (ch2 == '%') {
524                            word = word + "%";
525                            ix++;
526                            continue;
527                        }
528                    }
529                    word = word + ch;
530                }
531                if (count > 1 && !sawg) {
532                    word = word + "." + generation;
533                }
534                if (unique > 0 && !sawu) {
535                    word = word + "." + unique;
536                }
537                if (word.length() > 0) {
538                    if (file == null) {
539                        file = new File(word);
540                    } else {
541                        file = new File(file, word);
542                    }
543                }
544                return file;
545            }
546
547            // Rotate the set of output files
548            private synchronized void rotate() {
549                Level oldLevel = getLevel();
550                setLevel(Level.OFF);
551
552                super .close();
553                for (int i = count - 2; i >= 0; i--) {
554                    File f1 = files[i];
555                    File f2 = files[i + 1];
556                    if (f1.exists()) {
557                        if (f2.exists()) {
558                            f2.delete();
559                        }
560                        f1.renameTo(f2);
561                    }
562                }
563                try {
564                    open(files[0], false);
565                } catch (IOException ix) {
566                    // We don't want to throw an exception here, but we
567                    // report the exception to any registered ErrorManager.
568                    reportError(null, ix, ErrorManager.OPEN_FAILURE);
569
570                }
571                setLevel(oldLevel);
572            }
573
574            /**
575             * Format and publish a <tt>LogRecord</tt>.
576             *
577             * @param  record  description of the log event. A null record is
578             *                 silently ignored and is not published
579             */
580            public synchronized void publish(LogRecord record) {
581                if (!isLoggable(record)) {
582                    return;
583                }
584                super .publish(record);
585                flush();
586                if (limit > 0 && meter.written >= limit) {
587                    // We performed access checks in the "init" method to make sure
588                    // we are only initialized from trusted code.  So we assume
589                    // it is OK to write the target files, even if we are
590                    // currently being called from untrusted code.
591                    // So it is safe to raise privilege here.
592                    AccessController
593                            .doPrivileged(new PrivilegedAction<Object>() {
594                                public Object run() {
595                                    rotate();
596                                    return null;
597                                }
598                            });
599                }
600            }
601
602            /**
603             * Close all the files.
604             *
605             * @exception  SecurityException  if a security manager exists and if
606             *             the caller does not have <tt>LoggingPermission("control")</tt>.
607             */
608            public synchronized void close() throws SecurityException {
609                super .close();
610                // Unlock any lock file.
611                if (lockFileName == null) {
612                    return;
613                }
614                try {
615                    // Closing the lock file's FileOutputStream will close
616                    // the underlying channel and free any locks.
617                    lockStream.close();
618                } catch (Exception ex) {
619                    // Problems closing the stream.  Punt.
620                }
621                synchronized (locks) {
622                    locks.remove(lockFileName);
623                }
624                new File(lockFileName).delete();
625                lockFileName = null;
626                lockStream = null;
627            }
628
629            private static class InitializationErrorManager extends
630                    ErrorManager {
631                Exception lastException;
632
633                public void error(String msg, Exception ex, int code) {
634                    lastException = ex;
635                }
636            }
637
638            // Private native method to check if we are in a set UID program.
639            private static native boolean isSetUID();
640        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.