001/* 002 * (C) Copyright 2011-2015 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Julien Carsique 016 * 017 */ 018 019package org.nuxeo.launcher.gui.logs; 020 021import java.io.BufferedReader; 022import java.io.File; 023import java.io.FileReader; 024import java.io.IOException; 025import java.util.Observable; 026 027import org.apache.commons.io.IOUtils; 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030 031/** 032 * @author jcarsique 033 * @since 5.4.2 034 */ 035public class LogsSource extends Observable implements Runnable { 036 static final Log log = LogFactory.getLog(LogsSource.class); 037 038 private static final long WAIT_FOR_FILE_EXISTS = 2000; 039 040 private static final long WAIT_FOR_READING_CONTENT = 1000; 041 042 private File logFile; 043 044 private boolean pause = true; 045 046 private long charsToSkip = 0; 047 048 /** 049 * @param logFile Log file to manage 050 */ 051 public LogsSource(File logFile) { 052 this.logFile = logFile; 053 } 054 055 @Override 056 public void run() { 057 BufferedReader in = null; 058 try { 059 while (!logFile.exists()) { 060 Thread.sleep(WAIT_FOR_FILE_EXISTS); 061 } 062 in = new BufferedReader(new FileReader(logFile)); 063 // Avoid reading and formating chars which won't be displayed 064 if (charsToSkip > 0) { 065 in.skip(charsToSkip); 066 } 067 // marker for detecting log rotate 068 long lastModified = logFile.lastModified(); 069 while (true) { 070 if (pause) { 071 synchronized (this) { 072 wait(); 073 } 074 } 075 String line = in.readLine(); 076 if (line != null) { 077 lastModified = logFile.lastModified(); 078 setChanged(); 079 notifyObservers(line); 080 } else { 081 if (logFile.lastModified() > lastModified) { 082 log.debug("File rotation detected"); 083 IOUtils.closeQuietly(in); 084 in = new BufferedReader(new FileReader(logFile)); 085 } else { 086 synchronized (this) { 087 wait(WAIT_FOR_READING_CONTENT); 088 } 089 } 090 } 091 } 092 } catch (InterruptedException e) { 093 log.debug(e); 094 } catch (IOException e) { 095 log.error(e); 096 } finally { 097 IOUtils.closeQuietly(in); 098 } 099 } 100 101 /** 102 * Ask thread to pause until {@link #resume()} 103 */ 104 public synchronized void pause() { 105 pause = true; 106 } 107 108 /** 109 * Resume thread after call to {@link #pause()} 110 */ 111 public void resume() { 112 pause = false; 113 synchronized (this) { 114 notify(); 115 } 116 } 117 118 /** 119 * @param length 120 */ 121 public void skip(long length) { 122 charsToSkip = length; 123 } 124 125}