/** * Copyright 2005 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.audit; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.ArrayList; import java.util.List; import org.drools.WorkingMemory; import org.drools.audit.event.LogEvent; import org.drools.event.KnowledgeRuntimeEventManager; import com.thoughtworks.xstream.XStream; /** * A logger of events generated by a working memory. * It stores its information in a file that can be specified. * All the events logged are written to the file when the * writeToDisk() method is invoked. The log will contain all * the events logged serialized to XML using XStream. * Every time a new logger is created, the old event log will * be overwritten. * * TODO: make this class more scalable, for example * - logging to several files if log becomes too large * - automatically write updates to file at certain time intervals * - ... * * @author <a href="mailto:kris_verlaenen@hotmail.com">Kris Verlaenen </a> */ public class WorkingMemoryFileLogger extends WorkingMemoryLogger { private List<LogEvent> events = new ArrayList<LogEvent>(); private String fileName = "event"; private int maxEventsInMemory = 1000; private int nbOfFile = 0; private boolean split = true; private boolean initialized = false; public WorkingMemoryFileLogger() { } /** * Creates a new WorkingMemoryFileLogger for the given working memory. * @param workingMemoryEventManager */ public WorkingMemoryFileLogger(final WorkingMemory workingMemory) { super( workingMemory ); } public WorkingMemoryFileLogger(final KnowledgeRuntimeEventManager session) { super( session ); } @SuppressWarnings("unchecked") public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); events = (List<LogEvent>)in.readObject(); fileName = (String) in.readObject(); maxEventsInMemory = in.readInt(); nbOfFile = in.readInt(); split = in.readBoolean(); initialized = in.readBoolean(); } public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeObject(events); out.writeObject(fileName); out.writeInt(maxEventsInMemory); out.writeInt(nbOfFile); out.writeBoolean(split); out.writeBoolean(initialized); } /** * Sets the name of the file the events are logged in. * No extensions should be given since .log is automatically appended * to the file name. * The default is an event.log file in the current working directory. * This can be a path relative to the current working directory * (e.g. "mydir/subDir/myLogFile"), or an absolute path * (e.g. "C:/myLogFile"). * * @param fileName The name of the file the events should be logged in. */ public void setFileName(final String fileName) { this.fileName = fileName; } /** * All events in the log are written to file. * The log is automatically cleared afterwards. */ public void writeToDisk() { if (!initialized) { initializeLog(); } FileWriter fileWriter = null; try { fileWriter = new FileWriter(this.fileName + (this.nbOfFile == 0 ? ".log" : this.nbOfFile + ".log"), true ); final XStream xstream = new XStream(); List<LogEvent> eventsToWrite = null; synchronized (this.events) { eventsToWrite = new ArrayList<LogEvent>(this.events); clear(); } for (LogEvent event : eventsToWrite) { fileWriter.write(xstream.toXML(event) + "\n"); } if (split) { this.nbOfFile++; initialized = false; } fileWriter.write("</object-stream>"); } catch ( final FileNotFoundException exc ) { throw new RuntimeException( "Could not create the log file. Please make sure that directory that the log file should be placed in does exist." ); } catch ( final Throwable t ) { t.printStackTrace( System.err ); } finally { if( fileWriter != null ) { try { fileWriter.close(); } catch(Exception e) {} } } } private void initializeLog() { try { FileWriter writer = new FileWriter(this.fileName + (this.nbOfFile == 0 ? ".log" : this.nbOfFile + ".log"), false); writer.append("<object-stream>\n"); writer.close(); initialized = true; } catch ( final FileNotFoundException exc ) { throw new RuntimeException( "Could not create the log file. Please make sure that directory that the log file should be placed in does exist." ); } catch ( final Throwable t ) { t.printStackTrace( System.err ); } } /** * Clears all the events in the log. */ private void clear() { synchronized (this.events) { this.events.clear(); } } /** * Sets the maximum number of log events that are allowed in memory. * If this number is reached, all events are written to file. * The default is 1000. * * @param maxEventsInMemory The maximum number of events in memory. */ public void setMaxEventsInMemory(final int maxEventsInMemory) { this.maxEventsInMemory = maxEventsInMemory; } /** * @see org.drools.audit.WorkingMemoryLogger */ public void logEventCreated(final LogEvent logEvent) { synchronized (this.events) { this.events.add( logEvent ); if ( this.events.size() > this.maxEventsInMemory ) { writeToDisk(); } } } public void setSplit(boolean split) { this.split = split; } }