/** * */ package org.openntf.domino.xsp.readers; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import lotus.domino.NotesException; import lotus.notes.addins.DominoServer; import lotus.notes.addins.ServerAccess; import org.openntf.domino.utils.Factory; import org.openntf.domino.xsp.Activator; import com.ibm.commons.util.io.SharedByteArrayOutputStream; import com.ibm.commons.util.io.StreamUtil; import com.ibm.icu.text.DecimalFormat; import com.ibm.icu.text.SimpleDateFormat; /** * @author Nathan T. Freeman * * Class for reading text files from the server */ public class LogReader { private static final Logger log_ = Logger.getLogger(LogReader.class.getName()); @SuppressWarnings("unused") private static final long serialVersionUID = 1L; private String version = "1.3"; private static volatile Transformer XFORMER; /** * Comparator, comparing last modified time of two files * * @since org.openntf.domino.xsp 4.5.0 */ public static class FileComparator implements Comparator<File> { @Override public int compare(final File arg0, final File arg1) { return Long.valueOf(arg1.lastModified()).compareTo(arg0.lastModified()); } } /** * Comparator, comparing filepaths of two files * * @since org.openntf.domino.xsp 4.5.0 */ public static class FilePathComparator implements Comparator<String> { @Override public int compare(final String arg0, final String arg1) { return Long.valueOf(new File(arg1).lastModified()).compareTo(new File(arg0).lastModified()); } } /** * Constructor */ public LogReader() { } /** * Whether or not the effective user of the Session has access to read logs * * @param session * Session (remember you can use sessionAsSigner / sessionAsSignerWithFullAccess) * @return boolean whether user has access * @since org.openntf.domino.xsp 2.5.0 */ private boolean canReadLogs(final lotus.domino.Session session) { boolean result = false; try { String username = session.getEffectiveUserName(); DominoServer server = new DominoServer(); result = server.checkServerAccess(username, ServerAccess.PROG_UNRESTRICTED); result = result || server.checkServerAccess(username, ServerAccess.VIEW_ONLY_ADMIN); } catch (NotesException ne) { ne.printStackTrace(); } return result; } /** * Gets the Domino data folder * * @return String data folder * @since org.openntf.domino.xsp 2.5.0 */ public String getDataFolder() { String filename = Factory.getDataPath(); filename = filename.replace("\\", "/"); if (!filename.endsWith("/")) filename += "/"; return filename; } /** * Gets the Domino program folder (notes for XPiNC app running locally) * * @return String domino folder * @since org.openntf.domino.xsp 2.5.0 */ public String getProgramFolder() { String filename = Factory.getProgramPath(); filename = filename.replace("\\", "/"); if (!filename.endsWith("/")) filename += "/"; return filename; } /** * Gets a folder based on a key. Options are: * <ul> * <li>tech = IBM_TECHNICAL_SUPPORT</li> * <li>ini = domino folder</li> * <li>jvm = frameworks/rcp/deploy</li> * <li>javapolicy = jvm/lib/security</li> * <li>rcp = domino/workspace/.config</li> * <li>xml = domino/workspace/logs</li> * <li>otherwise param + "/" * </ul> * * @param section * String key from which to get folder * @return String folder * @since org.openntf.domino.xsp 2.5.0 */ public String getFolder(final String section) { String folder = ""; if (section.equals("tech")) { folder = getDataFolder() + "IBM_TECHNICAL_SUPPORT/"; } else if (section.equals("ini")) { folder = getProgramFolder(); } else if (section.equals("jvm")) { folder = getProgramFolder() + "framework/rcp/deploy/"; } else if (section.equals("javapolicy")) { folder = getProgramFolder() + "jvm/lib/security/"; } else if (section.equals("rcp")) { folder = getDataFolder() + "domino/workspace/.config/"; } else if (section.equals("xml")) { folder = getDataFolder() + "domino/workspace/logs/"; } else { folder = getDataFolder() + section + "/"; } return folder; } /** * Performs a wildcard matching for the text and pattern provided. * * @param text * the text to be tested for matches. * @param pattern * the pattern to be matched for. This can contain the wildcard character '*' (asterisk). * @return <tt>true</tt> if a match is found, <tt>false</tt> otherwise. * @since org.openntf.domino.xsp 2.5.0 * @see "http://www.adarshr.com/papers/wildcard" */ public static boolean wildCardMatch(String text, final String pattern) { // Create the cards by splitting using a RegEx. If more speed // is desired, a simpler character based splitting can be done. if (pattern == null) return true; String[] cards = pattern.split("\\*"); // Iterate over the cards. for (String card : cards) { int idx = text.indexOf(card); // Card not detected in the text. if (idx == -1) { return false; } // Move ahead, towards the right of the text. text = text.substring(idx + card.length()); } return true; } /** * Converts the file size to a human readable format, e.g. "48 Kbytes" * * @param size * long file size * @return String file size in readable format * @since org.openntf.domino.xsp 2.5.0 */ public static String readableFileSize(final long size) { if (size <= 0) return "0 bytes"; final String[] units = new String[] { "bytes", "Kbytes", "Mb", "Gb", "Tb" }; int digitGroups = (int) (Math.log10(size) / Math.log10(1024)); return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups]; } /** * Converts the date to a human readable format * * @param date * long * @return String date in format yyyyMMdd'T'hhmmss */ public static String readableDate(final long date) { String DATE_FORMAT = "yyyyMMdd'T'hhmmss"; SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT); return sdf.format(date); } /** * Retrieves a list of files in the specified folder * * @param section * String key for the folder, passed to {@link #getFolder(String)} * @param filter * String wildcard search for files * @return List<File> of files in the relevant folder matching the search * @since org.openntf.domino.xsp 2.5.0 */ private List<File> getFiles(final String section, final String filter) { List<File> result = new ArrayList<File>(); String folder = getFolder(section); File dir = new File(folder); String[] entries = dir.list(); // get the folder content // convert to ArrayList and remove all directories from the list // List<String> files = new ArrayList<String>(); for (int i = 0; i < entries.length; i++) { File d = new File(folder + entries[i]); if (d.isFile()) { if (filter == null) { result.add(d); // files.add(entries[i]); } else { if (wildCardMatch(entries[i], filter)) { result.add(d); // files.add(entries[i]); } } } } Collections.sort(result, new FileComparator()); // sort the list // Collections.sort(files, new FilePathComparator()); return result; } /** * Gets all files in the specified folder * * @param section * String key for the folder, passed to {@link #getFolder(String)} * @return List<File> of files in the relevant folder matching the search * @since org.openntf.domino.xsp 2.5.0 */ private List<File> getFiles(final String section) { return getFiles(section, null); } /** * Gets a List of filenames in the specified folder * * @param session * Session with which to get the files * @param section * String key for the folder, passed to {@link #getFolder(String)} * @return List<String> of filenames * @since org.openntf.domino.xsp 2.5.0 */ public List<String> getFileNames(final lotus.domino.Session session, final String section) { List<String> results = new LinkedList<String>(); if (canReadLogs(session)) { List<File> files = getFiles(section); for (File file : files) { results.add(file.getName()); } } return results; } /** * Gets a List of filenames in the specified folder matching the optional filter * * @param session * Session with which to get the files * @param section * String key for the folder, passed to {@link #getFolder(String)} * @param filter * String wildcard search for files * @return List<String> of filenames in the relevant folder matching the search * @since org.openntf.domino.xsp 2.5.0 */ public List<String> getFileNames(final lotus.domino.Session session, final String section, final String filter) { List<String> results = new LinkedList<String>(); if (canReadLogs(session)) { List<File> files = getFiles(section, filter); for (File file : files) { results.add(file.getName()); } } return results; } /** * Reads a specific file, just getting any lines which include the filter string * * @param filename * String file path and file name * @param filter * String to search for * @return String lines from the file matching the filter * @since org.openntf.domino.xsp 2.5.0 */ public String readFileFast(final String filename, final String filter) { if (filename == null || filename.length() < 1 || filename.equalsIgnoreCase("null")) { return ""; } File file = new File(filename); if (file.isDirectory() || !file.exists()) { return ""; } StringBuilder result = new StringBuilder(); FileReader fileReader = null; BufferedReader reader = null; try { fileReader = new FileReader(file); reader = new BufferedReader(fileReader); String line = null; while ((line = reader.readLine()) != null) { if (filter == null) { result.append(line); result.append("\n"); } else { if (line.indexOf(filter, 0) >= 0) { result.append(line); result.append("\n"); } } } } catch (Exception e) { log_.log(Level.WARNING, e.toString(), e); } finally { try { if (fileReader != null) fileReader.close(); } catch (IOException e) { e.printStackTrace(); } try { if (reader != null) reader.close(); } catch (IOException e) { e.printStackTrace(); } } return result.toString(); } /** * Reads a file * * @param filename * String file path and file name * @return String output of the file * @since org.openntf.domino.xsp 2.5.0 */ public String readFileFast(final String filename) { return readFileFast(filename, null); } /** * Reads a stream, just getting any lines which include the filter string * * @param stream * SharedByteArrayOutputStream to read * @param filter * String to search for * @return String lines from the file matching the filter * @since org.openntf.domino.xsp 2.5.0 */ public String readStreamFast(final SharedByteArrayOutputStream stream, final String filter) { String result = null; try { result = StreamUtil.readString(new ByteArrayInputStream(stream.getByteArray()), "UTF-8"); } catch (Exception e) { log_.log(Level.WARNING, e.toString(), e); } finally { try { if (stream != null) stream.close(); } catch (Exception e) { e.printStackTrace(); } } return result; } /** * Reads a file from IBM_TECHNICAL_SUPPORT folder, just getting any lines which include the filter string * * @param filename * file within IBM_TECHNICAL_SUPPORT folder * @param filter * String to search for * @return String lines from the file matching the filter * @since org.openntf.domino.xsp 2.5.0 */ public String readConsole(String filename, String filter) { String html = ""; if (filename == null) return "Please select a file"; if (filter == null) filter = "HTTP"; filename = getFolder("tech") + filename; html = readFileFast(filename, filter); return html; } /** * Reads a file from IBM_TECHNICAL_SUPPORT folder * * @param filename * String file within IBM_TECHNICAL_SUPPORT folder * @return String output of the file * @since org.openntf.domino.xsp 2.5.0 */ public String readXPages(String filename) { String html = ""; if (filename == null) return "Please select a file"; filename = getFolder("tech") + filename; html = readFileFast(filename); return html; } /** * Reads the startup.log file * * @return String output of the file * @since org.openntf.domino.xsp 2.5.0 */ public String readStartup() { String html = ""; String filename = getFolder("xml") + "startup.log"; html = readFileFast(filename); return html; } /** * Reads the notes.ini * * @return String output of the file * @since org.openntf.domino.xsp 2.5.0 */ public String readNotesini() { String html = ""; String filename = getFolder("ini") + "notes.ini"; html = readFileFast(filename); return html; } /** * Reads the jvm.properties * * @return String output of the file * @since org.openntf.domino.xsp 2.5.0 */ public String readJVM() { String html = ""; String filename = getFolder("jvm") + "jvm.properties"; html = readFileFast(filename); return html; } /** * Reads the java.policy * * @return String output of the file * @since org.openntf.domino.xsp 2.5.0 */ public String readJavaPolicy() { String html = ""; String filename = getFolder("javapolicy") + "java.policy"; html = readFileFast(filename); return html; } /** * Reads the java.pol (if it has been set up) * * @return String output of the file * @since org.openntf.domino.xsp 2.5.0 */ public String readJavaPol() { String html = ""; String filename = getFolder("javapolicy") + "java.pol"; html = readFileFast(filename); return html; } /** * Reads the rcpinstall.properties * * @return String output of the file * @since org.openntf.domino.xsp 2.5.0 */ public String readRCP() { String html = ""; String filename = getFolder("rcp") + "rcpinstall.properties"; html = readFileFast(filename); return html; } /** * Reads a file in a specified folder * <ul> * <li>section="tech", filename</li> * <li>section="xml", filename or startup.log if filename is null</li> * <li>section="ini", filename in domino folder</li> * <li>section="log", just returns "log"</li> * </ul> * * @param section * String key for the folder, passed to {@link #getFolder(String)} * @param filename * String file within the specified folder * @return String output of file * @since org.openntf.domino.xsp 2.5.0 */ public String readHtml(final String section, String filename) { String html = ""; if (section == null) { /* If the String is null... */ } else if (section.equals("tech")) { if (filename == null) return "Please select a file"; filename = getFolder(section) + filename; html = readFileFast(filename, null); } else if (section.equals("xml")) { if (filename == null) filename = "startup.log"; filename = getFolder(section) + filename; html = readFileFast(filename, null); } else if (section.equals("ini")) { filename = getFolder(section) + filename; html = readFileFast(filename); } else if (section.equals("log")) { html = "log"; } else { /* DEFAULT Operation */ } return html; } /** * Gets the version of the LogReader * * @return String version label * @since org.openntf.domino.xsp 2.5.0 */ public String getVersion() { return version; } /** * Gets an XML transformer loading the log-transform.xsl resource * * @return Transformer * @since org.openntf.domino.xsp 2.5.0 */ protected static Transformer getTransformer() { if (XFORMER == null) { synchronized (LogReader.class) { TransformerFactory tFactory = TransformerFactory.newInstance(); InputStream input = null; try { input = Activator.getDefault().getResourceAsStream("/resources/log-transform.xsl"); XFORMER = tFactory.newTransformer(new StreamSource(input)); } catch (Exception e) { e.printStackTrace(); } finally { try { if (input != null) input.close(); } catch (Exception e) { // meh } } } } return XFORMER; } /** * Reads a error-log-*.xml or trace-log-*.xml file * * @param type * error or trace filename: must be one of the error-log-*.xml or trace-log-*.xml files * @return String output * @since org.openntf.domino.xsp 2.5.0 */ public String readXML(final String type, String filename) { // default file if (filename == null) { return "Please select a file"; } String path = getFolder("xml"); // Get the number of bytes in the file File file = new File(getFolder("xml") + filename); if (file.length() == 0) { log_.log(Level.FINE, "File is empty - return a blank page ..."); return ""; } // XSL transform if (true) { try { SharedByteArrayOutputStream baos = new SharedByteArrayOutputStream(); StreamResult result = new StreamResult(baos); // read the log file StreamSource inputStream = new StreamSource(path + filename); // do the transformation Transformer xfm = getTransformer(); synchronized (xfm) { xfm.transform(inputStream, result); } return readStreamFast(baos, null); } catch (Exception e) { log_.log(Level.WARNING, e.toString(), e); } } // If transformation fails - just display the xml file String html = ""; filename = getFolder("xml") + filename; html = readFileFast(filename); return html; } }