001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: jianwu $'
006 * '$Date: 2013-05-01 16:34:18 +0000 (Wed, 01 May 2013) $' 
007 * '$Revision: 31976 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.io;
031
032import java.io.File;
033import java.io.FileWriter;
034import java.io.IOException;
035import java.io.PrintWriter;
036import java.text.SimpleDateFormat;
037import java.util.Calendar;
038import java.util.Date;
039import java.util.Hashtable;
040import java.util.Iterator;
041
042import org.apache.commons.logging.Log;
043import org.apache.commons.logging.LogFactory;
044
045//////////////////////////////////////////////////////////////////////////
046//// Log
047
048/**
049 * Log information directed into a file. All actors can write into the same
050 * file, if they point to the same file. Format as it is, or XML. text format:
051 * date: header: text XML format:
052 * 
053 * 
054 * If the text is empty (or only white spaces), nothing will be written. So you
055 * do not need to filter out e.g. empty stderr messages before connecting to
056 * Logger actors.
057 * 
058 * @author Norbert Podhorszki
059 * @version $Id: SharedLog.java 31976 2013-05-01 16:34:18Z jianwu $
060 * @since Ptolemy II 5.0.1
061 */
062public class SharedLog {
063
064        public SharedLog(boolean xmlFormat) {
065                _xmlFormat = xmlFormat;
066        }
067        
068        public void print(File logfile, String header, String logText) {
069                print(logfile, header, logText, false);
070        }
071
072        public void print(File logfile, String header, String logText, boolean append) {
073
074                // empty string will not do anything
075                if (logText == null || logText.trim().length() == 0)
076                        return;
077
078                try {
079                        LogFile lf = getLogFile(logfile, append);
080                        Date date = Calendar.getInstance().getTime();
081                        PrintWriter writer = lf.getPrintWriter();
082                        synchronized (writer) {
083                                if (lf.isXMLFormat()) {
084                                        writer.println("  <item>");
085                                        writer.println("    <date value=\""
086                                                        + dateformat.format(date) + "\"/>");
087                                        writer.println("    <header value=\"" + header + "\"/>");
088                                        writer.println("    <text>" + logText + "</text>");
089                                        writer.println("  </item>");
090                                } else {
091                                        writer.println(dateformat.format(date) + ": " + header
092                                                        + ": " + logText);
093                                }
094                                writer.flush();
095                        }
096                } catch (Exception ex) {
097                        log.error(ex);
098                }
099
100        }
101
102        /**
103         * Close all opened log file in a synchronized way. This method prints the
104         * final line The hashtable elements cannot be removed during the iterator,
105         * because that is fail-fast. So we clear the hashtable at the end.
106         */
107        public static void closeAll() throws IOException {
108
109                synchronized (logFiles) {
110                        Iterator writers = logFiles.keySet().iterator();
111                        while (writers.hasNext()) {
112                                String path = (String) writers.next();
113                                LogFile lf = (LogFile) logFiles.get(path);
114                                PrintWriter writer = lf.getPrintWriter();
115
116                                if (lf.isXMLFormat()) {
117                                        writer.println("</log>");
118                                } else {
119                                        writer
120                                                        .println("----------------------------------------------");
121                                }
122                                writer.close();
123                                if (isDebugging)
124                                        log.debug("Closed log " + path);
125                        }
126                        logFiles.clear(); // remove all elements
127                }
128        }
129
130        private static SimpleDateFormat dateformat = new SimpleDateFormat(
131                        "MMM dd yyyy HH:mm:ss.SSS");
132        private boolean _xmlFormat = false;
133
134        // apache commons log for the source code logging.
135        private static final Log log = LogFactory.getLog(SharedLog.class.getName());
136        private static final boolean isDebugging = log.isDebugEnabled();
137
138        /*
139         * The log files already created (key = their absolute path as String),
140         * value=the LogFile
141         */
142        private static Hashtable logFiles = new Hashtable();
143
144        private LogFile getLogFile(File file, boolean append) throws IOException {
145
146                String path = file.getAbsolutePath();
147                LogFile lf = null;
148
149                synchronized (logFiles) {
150                        lf = (LogFile) logFiles.get(path);
151                        if (lf == null) {
152                                PrintWriter writer = new PrintWriter(
153                                                new FileWriter(file, append));
154                                lf = new LogFile(writer, _xmlFormat);
155                                logFiles.put(path, lf);
156                                Date date = Calendar.getInstance().getTime();
157                                if (_xmlFormat) {
158                                        writer.println("<?xml version=\"1.0\" standalone=\"no\"?>");
159                                        writer
160                                                        .println("<!DOCTYPE entity PUBLIC \"-//UC Davis//DTD Kepler Log 1//EN\" "
161                                                                        + "\"http://kepler-project.org/xml/dtd/KeplerLog_1.dtd\">");
162                                        writer.println("<log>");
163                                        writer.println("  <date format=\"" + dateformat.toPattern()
164                                                        + "\"/>");
165                                        writer.println("  <create_date value=\""
166                                                        + dateformat.format(date) + "\"/>");
167                                } else {
168                                        writer.println("Log file created on "
169                                                        + dateformat.format(date));
170                                        writer
171                                                        .println("Log date format: "
172                                                                        + dateformat.toPattern());
173                                        writer
174                                                        .println("----------------------------------------------");
175                                }
176                                writer.flush();
177                        }
178                }
179                return lf;
180        }
181
182        /**
183         * Record of { PrintWriter writer, boolean isXmlFormat } to store what we
184         * need about a log file in the hash table.
185         */
186        private class LogFile {
187                private PrintWriter writer;
188                private boolean isXmlFormat;
189
190                public LogFile(PrintWriter w, boolean xmlFormat) {
191                        writer = w;
192                        isXmlFormat = xmlFormat;
193                }
194
195                public PrintWriter getPrintWriter() {
196                        return writer;
197                }
198
199                public boolean isXMLFormat() {
200                        return isXmlFormat;
201                }
202
203        }
204
205}