001/* 002 * (C) Copyright 2011-2015 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Julien Carsique 018 * 019 */ 020 021package org.nuxeo.launcher.gui.logs; 022 023import java.io.BufferedReader; 024import java.io.File; 025import java.io.FileReader; 026import java.io.IOException; 027import java.util.Observable; 028 029import org.apache.commons.io.IOUtils; 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032 033/** 034 * @author jcarsique 035 * @since 5.4.2 036 */ 037public class LogsSource extends Observable implements Runnable { 038 static final Log log = LogFactory.getLog(LogsSource.class); 039 040 private static final long WAIT_FOR_FILE_EXISTS = 2000; 041 042 private static final long WAIT_FOR_READING_CONTENT = 1000; 043 044 private File logFile; 045 046 private boolean pause = true; 047 048 private long charsToSkip = 0; 049 050 /** 051 * @param logFile Log file to manage 052 */ 053 public LogsSource(File logFile) { 054 this.logFile = logFile; 055 } 056 057 @Override 058 public void run() { 059 BufferedReader in = null; 060 try { 061 while (!logFile.exists()) { 062 Thread.sleep(WAIT_FOR_FILE_EXISTS); 063 } 064 in = new BufferedReader(new FileReader(logFile)); 065 // Avoid reading and formating chars which won't be displayed 066 if (charsToSkip > 0) { 067 in.skip(charsToSkip); 068 } 069 // marker for detecting log rotate 070 long lastModified = logFile.lastModified(); 071 while (true) { 072 if (pause) { 073 synchronized (this) { 074 wait(); 075 } 076 } 077 String line = in.readLine(); 078 if (line != null) { 079 lastModified = logFile.lastModified(); 080 setChanged(); 081 notifyObservers(line); 082 } else { 083 if (logFile.lastModified() > lastModified) { 084 log.debug("File rotation detected"); 085 IOUtils.closeQuietly(in); 086 in = new BufferedReader(new FileReader(logFile)); 087 } else { 088 synchronized (this) { 089 wait(WAIT_FOR_READING_CONTENT); 090 } 091 } 092 } 093 } 094 } catch (InterruptedException e) { 095 log.debug(e); 096 } catch (IOException e) { 097 log.error(e); 098 } finally { 099 IOUtils.closeQuietly(in); 100 } 101 } 102 103 /** 104 * Ask thread to pause until {@link #resume()} 105 */ 106 public synchronized void pause() { 107 pause = true; 108 } 109 110 /** 111 * Resume thread after call to {@link #pause()} 112 */ 113 public void resume() { 114 pause = false; 115 synchronized (this) { 116 notify(); 117 } 118 } 119 120 /** 121 * @param length 122 */ 123 public void skip(long length) { 124 charsToSkip = length; 125 } 126 127}