/* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores * CA 94065 USA or visit www.oracle.com if you need additional information or * have any questions. */ package com.sun.lwuit.io.util; import com.sun.lwuit.Command; import com.sun.lwuit.Display; import com.sun.lwuit.Form; import com.sun.lwuit.TextArea; import com.sun.lwuit.events.ActionEvent; import com.sun.lwuit.events.ActionListener; import com.sun.lwuit.io.FileSystemStorage; import com.sun.lwuit.io.impl.IOImplementation; import com.sun.lwuit.layouts.BorderLayout; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; /** * Pluggable logging framework that allows a developer to log into storage * using the file connector API. It is highly recommended to use this * class coupled with Netbeans preprocessing tags to reduce its overhead * completely in runtime. * * @author Shai Almog */ public class Log { /** * Constant indicating the logging level Debug is the default and the lowest level * followed by info, warning and error */ public static final int DEBUG = 1; /** * Constant indicating the logging level Debug is the default and the lowest level * followed by info, warning and error */ public static final int INFO = 2; /** * Constant indicating the logging level Debug is the default and the lowest level * followed by info, warning and error */ public static final int WARNING = 3; /** * Constant indicating the logging level Debug is the default and the lowest level * followed by info, warning and error */ public static final int ERROR = 4; private int level = DEBUG; private static Log instance = new Log(); private long zeroTime = System.currentTimeMillis(); private Writer output; private boolean fileWriteEnabled = false;//System.getProperty("microedition.io.file.FileConnection.version") != null; private String fileURL = null; /** * Installs a log subclass that can replace the logging destination/behavior * * @param newInstance the new instance for the Log object */ public static void install(Log newInstance) { instance = newInstance; } /** * Default println method invokes the print instance method, uses DEBUG level * * @param text the text to print */ public static void p(String text) { p(text, DEBUG); } /** * Default println method invokes the print instance method, uses given level * * @param text the text to print * @param level one of DEBUG, INFO, WARNING, ERROR */ public static void p(String text, int level) { instance.print(text, level); } /** * This method is a shorthand form for logThrowable * * @param t the exception */ public static void e(Throwable t) { instance.logThrowable(t); } /** * Logs an exception to the log, by default print is called with the exception * details, on supported devices the stack trace is also physically written to * the log * @param t */ protected void logThrowable(Throwable t) { print("Exception: " + t.getClass().getName() + " - " + t.getMessage(), ERROR); t.printStackTrace(); try { synchronized(this) { Writer w = getWriter(); IOImplementation.getInstance().printStackTraceToStream(t, w); w.flush(); } } catch(IOException err) { err.printStackTrace(); } } /** * Default log implementation prints to the console and the file connector * if applicable. Also prepends the thread information and time before * * @param text the text to print * @param level one of DEBUG, INFO, WARNING, ERROR */ protected void print(String text, int level) { if(this.level > level) { return; } text = getThreadAndTimeStamp() + " - " + text; System.out.println(text); try { synchronized(this) { Writer w = getWriter(); w.write(text + "\n"); w.flush(); } } catch(Throwable err) { err.printStackTrace(); } } /** * Default method for creating the output writer into which we write, this method * creates a simple log file using the file connector * * @return writer object * @throws IOException when thrown by the connector */ protected Writer createWriter() throws IOException { try { if(getFileURL() == null) { setFileURL("file:///" + FileSystemStorage.getInstance().getRoots()[0] + "/lwuit.log"); } if(FileSystemStorage.getInstance().exists(getFileURL())) { return new OutputStreamWriter(FileSystemStorage.getInstance().openOutputStream(getFileURL(), (int)FileSystemStorage.getInstance().getLength(getFileURL()))); } else { return new OutputStreamWriter(FileSystemStorage.getInstance().openOutputStream(getFileURL())); } } catch(Exception err) { setFileWriteEnabled(false); // currently return a "dummy" writer so we won't fail on device return new OutputStreamWriter(new ByteArrayOutputStream()); } } private Writer getWriter() throws IOException { if(output == null) { output = createWriter(); } return output; } /** * Returns a simple string containing a timestamp and thread name. * * @return timestamp string for use in the log */ protected String getThreadAndTimeStamp() { long time = System.currentTimeMillis() - zeroTime; long milli = time % 1000; time /= 1000; long sec = time % 60; time /= 60; long min = time % 60; time /= 60; long hour = time % 60; return "[" + Thread.currentThread().getName() + "] " + hour + ":" + min + ":" + sec + "," + milli; } /** * Sets the logging level for printing log details, the lower the value * the more verbose would the printouts be * * @param level one of DEBUG, INFO, WARNING, ERROR */ public static void setLevel(int level) { instance.level = level; } /** * Returns the logging level for printing log details, the lower the value * the more verbose would the printouts be * * @return one of DEBUG, INFO, WARNING, ERROR */ public static int getLevel() { return instance.level; } /** * Returns the contents of the log as a single long string to be displayed by * the application any way it sees fit * * @return string containing the whole log */ public static String getLogContent() { try { String text = ""; if(instance.isFileWriteEnabled()) { if(instance.getFileURL() == null) { instance.setFileURL("file:///" + FileSystemStorage.getInstance().getRoots()[0] + "/lwuit.log"); } Reader r = new InputStreamReader(FileSystemStorage.getInstance().openInputStream(instance.getFileURL())); char[] buffer = new char[1024]; int size = r.read(buffer); while(size > -1) { text += new String(buffer, 0, size); size = r.read(buffer); } r.close(); } return text; } catch (Exception ex) { ex.printStackTrace(); return ""; } } /** * Places a form with the log as a TextArea on the screen, this method can * be attached to appear at a given time or using a fixed global key. Using * this method might cause a problem with further log output */ public static void showLog() { try { String text = getLogContent(); TextArea area = new TextArea(text, 5, 20); Form f = new Form("Log"); f.setScrollable(false); final Form current = Display.getInstance().getCurrent(); Command back = new Command("Back") { public void actionPerformed(ActionEvent ev) { current.show(); } }; f.addCommand(back); f.setBackCommand(back); f.setLayout(new BorderLayout()); f.addComponent(BorderLayout.CENTER, area); f.show(); } catch (Exception ex) { ex.printStackTrace(); } } /** * Returns the singleton instance of the log * * @return the singleton instance of the log */ public static Log getInstance() { return instance; } /** * Indicates whether GCF's file writing should be used to generate the log file * * @return the fileWriteEnabled */ public boolean isFileWriteEnabled() { return fileWriteEnabled; } /** * Indicates whether GCF's file writing should be used to generate the log file * * @param fileWriteEnabled the fileWriteEnabled to set */ public void setFileWriteEnabled(boolean fileWriteEnabled) { this.fileWriteEnabled = fileWriteEnabled; } /** * Indicates the URL where the log file is saved * * @return the fileURL */ public String getFileURL() { return fileURL; } /** * Indicates the URL where the log file is saved * * @param fileURL the fileURL to set */ public void setFileURL(String fileURL) { this.fileURL = fileURL; } /** * Activates the filesystem tracking of file open/close operations */ public void trackFileSystem() { IOImplementation.getInstance().setLogListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { String s = (String)evt.getSource(); // don't log the creation of the log itself if(output != null) { p(s); } } }); } }