All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jwall.web.audit.io.ConcurrentAuditReader Maven / Gradle / Ivy

/*
 *  Copyright (C) 2007-2014 Christian Bockermann 
 *
 *  This file is part of the  web-audit  library.
 *
 *  web-audit library is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  The  web-audit  library 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 for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see .
 *
 */
package org.jwall.web.audit.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import org.jwall.web.audit.AuditEvent;
import org.jwall.web.audit.util.ParserUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * This class read the index-file of a concurrent auditlog and
 * creates audit-events from the appopriate event-files, if 
 * available.
 * 
 * @author Christian Bockermann <[email protected]>
 *
 */
public class ConcurrentAuditReader
extends AbstractAuditEventReader
//implements AuditEventReader
{
    /** A unique logger for this class */
    private static Logger log = LoggerFactory.getLogger( ConcurrentAuditReader.class );
    
    private File index;
    
    /* The data-directory where all the event-files are stored (in subdirectories) */
    private File dataDir; 

    private boolean finished = false;
    
    private long bytesRead = 0L;
    
    private boolean tail = true;
    
    
    /**
     * This constructor creates a new concurrent audit-reader that reads from the
     * given index file and expects the audit data-files to exist relative to the
     * given data-directory.
     * 
     * @param dataDir The base directory of the data-files.
     * @param indexFile The file containing the summary-lines for all events.
     * @throws IOException In case any of the files cannot be read or does not exist.
     */
    public ConcurrentAuditReader( File dataDir, File indexFile, boolean tail ) throws IOException {
        super( new FileInputStream( indexFile ) );
        this.dataDir = dataDir;
        this.tail = tail;

        index = indexFile;
        if( ! ( index.exists() && index.canRead() ) )
            throw new IOException("Cannot read index-file: "+index.toString() );

        if( tail ){
            log.debug( "Listening on tail of index-file (skipping " + index.length() + " bytes)..." );
        	reader.skip( index.length() );
        } else
            log.debug("Reading complete index-file...");
    }
    
    
    public ConcurrentAuditReader( InputStream index, File dataDir ) throws IOException {
        super( index );
        this.dataDir = dataDir;
        log.debug( "Listening on tail of index-file..." );
    }
    
    public ConcurrentAuditReader( File data, File index ) throws IOException {
    	this( data, index, false );
    }
    
    /**
     * This constructor creates a new concurrent audit-reader that
     * listens on the index file in the given data-directory. The
     * index-file is assumed to be called index and
     * has to exists in the given data-directory.
     * 
     * @param dataDir The directory where all audit-data is stored.
     * @throws IOException In case the index file does not exists or 
     *         cannot be read.
     */
    public ConcurrentAuditReader( File dataDir, boolean tail ) throws IOException {
    	this( dataDir, new File( dataDir.getAbsolutePath() + "/index" ), tail );
    }

    public ConcurrentAuditReader( File dataDir ) throws IOException {
    	this( dataDir, false );
    }

    
    /**
     * 
     * This method read the next event from the file-system. If there
     * is none available it waits and listens for another one to be
     * appended to the index-file.
     * 
     * @throws IOException
     */
    public AuditEvent readNext()
    	throws IOException, ParseException 
    {
        log.debug("ConcurrentAuditReader.readNext()");
        String line = null;

        do {
            line = reader.readLine();
            while( line == null && tail ){
            	try {
            		log.debug( "Waiting for next event..." );
            		Thread.sleep( 1000 );
            		line = reader.readLine();
            	} catch (Exception e) {
            		e.printStackTrace();
            	}
            }
            log.debug("line: "+line);
            
            if( line == null ){
                this.eofReached = true;
                
                if( tail )
                    return null;
                else {
                    log.debug( "End-of-file reached, not in \"continuous-reading\"-mode. Closing." );
                    finished = true;
                }
            } else {
                return this.readEvent( line );
            }

        } while( !finished );

        log.debug("index-line: "+line);
        
        return null;
    }

    /**
     * This method creates an audit-event instance from a file. The filename is
     * extracted from the given index-entry line s and the basic
     * data directory that was specified at creation of this audit-reader.
     * 
     * @param s The index entry line.
     * @return An audit-event.
     * @throws IOException In case the file cannot be read (due to non-existence
     *         or missing rights) an exception is thrown.
     */
    public AuditEvent readEvent( String s ) throws IOException, ParseException {

        String line = s.replaceFirst("\\[", "\"").replaceFirst("\\]", "\"");
        String[] token = ParserUtils.splitQuotedString( line );
        token = AccessLogAuditReader.splitAccessLine( line );

        File evtFile = new File( dataDir.getAbsolutePath() + "/" + token[12] );
        
        log.debug("Reading event from "+evtFile.getAbsoluteFile());
        
        int retries = 3;
        while(retries > 0 && ! (evtFile.exists() && evtFile.canRead() ) ) {
            try {
                log.debug("waiting for file {} to be created...", evtFile.getAbsolutePath() );
                retries--;
                Thread.sleep(200);
            } catch (InterruptedException ie) {
                ie.printStackTrace();
            }
        }
        
        if( ! evtFile.exists() )
            throw new IOException("File not found: "+evtFile.getAbsolutePath());
            
        if(! evtFile.canRead() )
            throw new IOException("Cannot read event from file: "+evtFile.getAbsolutePath() );
        
        try {
        	AbstractAuditEventReader ms2ar = new ModSecurity2AuditReader( evtFile );
        	AuditEvent evt = ms2ar.readNext();
        	ms2ar.close();
        	return evt;
        } catch (Exception e){
        	throw new IOException( e.getMessage() );
        }
    }


    
    public void finish(){
    	finished = true;
    }
    
    public void close() throws IOException {
    	reader.close();
    }
    
    public long bytesRead(){
    	return bytesRead;
    }
    
    public long bytesAvailable(){
    	if( index != null )
    		return index.length();
    	
    	return Long.MAX_VALUE;
    }
    


    @Override
    public Iterator iterator() {
        try {
            return new AuditEventIterator( this );
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy