package org.bbssh.util; import java.io.DataInputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Date; import javax.microedition.io.Connector; import javax.microedition.io.file.FileConnection; import net.rim.device.api.applicationcontrol.ApplicationPermissions; import net.rim.device.api.applicationcontrol.ApplicationPermissionsManager; import net.rim.device.api.i18n.SimpleDateFormat; import net.rim.device.api.system.DeviceInfo; import net.rim.device.api.system.EventLogger; public class Logger { public static final int LOG_LEVEL_FATAL = 0; public static final int LOG_LEVEL_ERROR = 10; public static final int LOG_LEVEL_WARN = 20; public static final int LOG_LEVEL_INFO = 50; public static final int LOG_LEVEL_DEBUG = 80; private static final String LOGGING_DISABLED_PREFIX = "disabled logging to file due to IOException - ";; private static int logLevel = LOG_LEVEL_WARN; private static OutputStreamWriter stream; private static SimpleDateFormat outputDateFormat = new SimpleDateFormat("HHmmss.SSS"); private static SimpleDateFormat filenameFormat = new SimpleDateFormat("yyyyMMdd"); private static String fileName; public static byte[] getFileContent() { if (!isFileLoggingEnabled()) return null; String name = getFileName(); byte[] data = null; disableFileLogging(); try { FileConnection fconn = (FileConnection) Connector.open(name); data = new byte[(int) fconn.fileSize()]; DataInputStream s = fconn.openDataInputStream(); s.readFully(data); s.close(); fconn.close(); } catch (IOException e) { } finally { enableFileLogging(); } return data; } public static String getFileName() { return fileName; } public static boolean isFileLoggingEnabled() { return (stream != null); } /** * Enabled file logging using a default location, first attemping to use the * SDCard then the user home directory in on-device memory. * * @throws IllegalArgumentException */ public static synchronized void enableFileLogging() throws IllegalArgumentException { Logger.disableFileLogging(); try { Logger.enableFileLogging("file:///SDCard/"); } catch (Exception e) { try { enableFileLogging("file:///store/home/user/"); } catch (IllegalArgumentException e1) { throw e1; } catch (Exception e2) { } } } public static synchronized void enableFileLogging(String outDirectory) throws IllegalArgumentException { if (outDirectory == null || outDirectory.length() == 0) throw new IllegalArgumentException("No output location provided."); if (ApplicationPermissionsManager.getInstance().getPermission(ApplicationPermissions.PERMISSION_FILE_API) == ApplicationPermissions.VALUE_DENY) { return; } closeOutput(); String name = ""; try { FileConnection fconn = (FileConnection) Connector.open(outDirectory); if (!fconn.isDirectory()) throw new IllegalArgumentException("Valid directory must be specified."); fconn.close(); name = fconn.getURL() + "BBSSH_" + filenameFormat.formatLocal(new Date().getTime()) + ".txt"; fconn.close(); fconn = (FileConnection) Connector.open(name); // Pretty darned unlikely but let's be certain they didn't happen to // make a file of the same name... if (!fconn.exists()) { fconn.create(); } stream = new OutputStreamWriter(fconn.openOutputStream(fconn.totalSize())); fconn.close(); // the stream will remain open fileName = name; logToFile(" *** BEGIN LOGGING *** "); } catch (Exception e) { String message = "Failed to open stream " + name + ": " + e.getMessage() + " " + e.toString(); logToEventLog(message); throw new IllegalArgumentException(message); } } public static void disableFileLogging() { closeOutput(); }; private synchronized static void closeOutput() { if (stream == null) { return; } logToFile(" *** END LOGGING *** "); try { stream.close(); } catch (Throwable e) { } stream = null; } private static String getLogLevelName(int level) { switch (level) { case LOG_LEVEL_DEBUG: return " DBG"; case LOG_LEVEL_ERROR: return " ERR"; case LOG_LEVEL_FATAL: return " FTL"; case LOG_LEVEL_INFO: return " INF"; case LOG_LEVEL_WARN: return " WRN"; } return " "; } public static void setLogLevel(int level) { Logger.info("Log level now set to " + getLogLevelName(level)); logLevel = level; } public static void error(String message) { // Saved the synchronzied call by pre-filtering if (LOG_LEVEL_ERROR <= logLevel) log(LOG_LEVEL_ERROR, message); } public static void debug(String message) { // Saved the synchronzied call by pre-filtering if (LOG_LEVEL_DEBUG <= logLevel) log(LOG_LEVEL_DEBUG, message); } public static void info(String message) { // Saved the synchronzied call by pre-filtering if (LOG_LEVEL_INFO <= logLevel) log(LOG_LEVEL_INFO, message); } public static void fatal(String message) { // Saved the synchronzied call by pre-filtering if (LOG_LEVEL_FATAL <= logLevel) log(LOG_LEVEL_FATAL, message); } public static void warn(String message) { // Saved the synchronzied call by pre-filtering if (LOG_LEVEL_WARN <= logLevel) log(LOG_LEVEL_WARN, message); } public static synchronized void logToEventLog(String message) { EventLogger.logEvent(Tools.NOTIFICATION_GUID, message.getBytes()); } public static void logToFile(String message) { logToFile(-1, message); } public static synchronized void flushFileLog() { if (stream != null) { try { stream.flush(); } catch (IOException e) { EventLogger.logEvent(Tools.NOTIFICATION_GUID, (LOGGING_DISABLED_PREFIX + e.getMessage()).getBytes()); disableFileLogging(); } } } /** * Log directly to the output file (if file logging is enabled) without * writing to system event log. * * @param message */ public static synchronized void logToFile(int level, String message) { if (stream == null) { return; } try { stream.write(outputDateFormat.formatLocal(new Date().getTime())); if (level > -1) { stream.write(" "); stream.write(Thread.currentThread().getName()); stream.write(" "); stream.write(getLogLevelName(level)); } stream.write(" "); stream.write(message); stream.write("\n"); } catch (IOException e) {// // nothing we can do about it if this happens; however for // performance sake let's turn // file logging back off. EventLogger.logEvent(Tools.NOTIFICATION_GUID, (LOGGING_DISABLED_PREFIX + e.getMessage()).getBytes()); disableFileLogging(); } } public static synchronized void log(int level, String message) { if (message == null) return; // This will go to the debugger "output" window. if (DeviceInfo.isSimulator() && level > LOG_LEVEL_DEBUG) { System.out.print(Thread.currentThread().getName()); System.out.print(" "); System.out.print(outputDateFormat.formatLocal(new Date().getTime())); System.out.print(" ["); System.out.print(getLogLevelName(level)); System.out.print("] "); System.out.println(message); } // Log to file controlled by log level settings if (level <= logLevel) { logToFile(level, message); } // Event log is fixed-level if (level <= LOG_LEVEL_WARN) { logToEventLog(message); } } public boolean isEnabled() { return (logLevel > -1); } public static void fatal(String message, Throwable t) { fatal(message + " : " + t.getClass().toString() + " : " + t.getMessage()); } public static boolean isLevelEnabled(int level) { return (logLevel >= level); } }