/*
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.tools.ant.installer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildLogger;
import org.apache.tools.ant.Project;
import org.hyperic.tools.ant.BasicLogger;
import org.hyperic.util.JDK;
import org.hyperic.util.StringUtil;
import org.hyperic.util.config.EarlyExitException;
import org.hyperic.util.file.FileUtil;
import org.hyperic.util.file.WritableFile;
public class InstallerLogger implements BuildLogger {
private static final String LINE_SEP =
System.getProperty("line.separator");
public static final String PROP_LOGFILE = "install.log";
public static final String PROP_NOWRAP = "install.nowrap";
public static final String PROP_LOGFILE_PATH = "install.log.path";
public static final String PROP_TITLE = "install.title" ;
public static String PREFIX = "^^^" ;
public static final String[] MESSAGE_HANDLERS
= { "org.hyperic.tools.ant.installer.MsgInfo",
"org.hyperic.tools.ant.installer.MsgError",
"org.hyperic.tools.ant.installer.MsgCompletion",
"org.hyperic.tools.ant.installer.MsgInput",
"org.hyperic.tools.ant.installer.MsgProgress" };
public static final String DEBUG_HANDLER
= "org.hyperic.tools.ant.installer.MsgDebug";
private static final String DEFAULT_TITLE = "Installer" ;
protected Map messageHandlers = null;
/** PrintStream to write non-error messages to */
protected PrintStream out;
/** PrintStream to write error messages to */
protected PrintStream err;
protected InstallerMessageHandler currentHandler = null;
protected Project project = null;
protected WritableFile logfile = null;
protected PrintStream logfileStream = null;
/** Time of the start of the build */
private long startTime = System.currentTimeMillis();
private boolean isNoWrapMode;
private String title ;
public InstallerLogger () {
// Initialize -nowrap to true on windows, false otherwise
if (JDK.IS_WIN32) {
isNoWrapMode = true;
} else {
isNoWrapMode = false;
}
}
protected void registerMessageHandler ( String msgWriterClass ) {
InstallerMessageHandler handler;
try {
handler = (InstallerMessageHandler)
Class.forName(msgWriterClass).newInstance();
handler.setLogger(this);
messageHandlers.put(generatePrefix(handler.getPrefix()), handler);
} catch ( Exception e ) {
err.println("ERROR registering message handler: " + e);
}
}
/**
* @param prefix The prefix of a specific message handler
* @return The prefix that will be matched on - this is just the
* prefix that is passed in, with the global PREFIX prepended, and a
* colon (:) appended.
*/
public String generatePrefix ( String prefix ) {
return PREFIX + prefix + ":";
}
protected void initMessageHandlers () {
if ( messageHandlers != null ) return;
messageHandlers = new HashMap();
for ( int i=0; i<MESSAGE_HANDLERS.length; i++ ) {
registerMessageHandler(MESSAGE_HANDLERS[i]);
}
String nowrap = getProperty(PROP_NOWRAP);
if ( nowrap != null ) {
if ( Boolean.valueOf(nowrap).booleanValue() ) {
isNoWrapMode = true;
} else {
//Override windows default of true if the option is
// given on the command line.
isNoWrapMode = false;
}
}
registerMessageHandler(DEBUG_HANDLER);
BasicLogger basicLogger = this.newDelegateLogger() ;
// Make sure raw log is in the same dir as regular log
logfile = new WritableFile(logfile.getParentFile(),
logfile.getName() + ".verbose");
basicLogger.setFile(logfile);
basicLogger.setLevel("debug");
basicLogger.register(project);
// For debugging, uncomment the line below to
// see all registered message handlers.
// dumpHandlers();
// Init the input handler here too
if ( project != null ) {
project.setInputHandler(new InstallerInputHandler(this));
} else {
err.println("Error setting input handler: project is null!");
}
PREFIX = getPrefix() ;
}
protected BasicLogger newDelegateLogger() {
return new BasicLogger();
}//EOM
/** Does nothing - this logger doesn't care about levels */
public void setMessageOutputLevel(int level) {}
/** Does nothing - this logger doesn't care about emacs mode */
public void setEmacsMode(boolean emacsMode) {}
public void setOutputPrintStream(PrintStream output) {
this.out = new PrintStream(output, true);
}
public void setErrorPrintStream(PrintStream err) {
this.err = new PrintStream(err, true);
}
/** Initializes the logfile */
public void buildStarted(BuildEvent event) {
startTime = System.currentTimeMillis();
initLogging(event);
}
private void initLogging (BuildEvent event) {
if ( project == null ) project = event.getProject();
if ( project != null && logfile == null ) {
String logfileName;
// check a few places for the logfile property
logfileName = getProperty(PROP_LOGFILE);
if ( logfileName == null ) {
// Not found, use hq-install.log.
logfileName = "hq-install.log";
}
File originalFile = new File(logfileName);
File originalDir = originalFile.getParentFile();
logfile = FileUtil.findWritableFile(new File("logs"),
logfileName,
null,
"HQ_tmp");
if (logfile == null) {
err.println(nowrap("WARNING: file is not writeable: " +
logfileName +
"\nINSTALL LOG WILL NOT BE SAVED TO DISK."));
return;
}
String parentAbsPath = logfile.getParentFile().getAbsolutePath();
if ( !logfile.getOriginalLocationWasUsed() ) {
err.println(nowrap("WARNING: file was not writeable: "
+ originalFile.getAbsolutePath()
+ "\nLogs will be written to "
+ parentAbsPath
+ " instead."));
}
if (!logfile.mkdirs()) {
err.println(nowrap("ERROR: could not create log directory: "
+ parentAbsPath
+ "\nINSTALL LOG WILL NOT BE SAVED TO DISK."));
return;
}
try {
//logfileStream = new FileWriter(logfile.getAbsolutePath(), true);
logfileStream = new PrintStream(new FileOutputStream(logfile.getAbsolutePath()), true);
// set JVM property so we can pick it up from ant
System.setProperty(PROP_LOGFILE_PATH, logfile.getAbsolutePath());
} catch ( IOException ioe ) {
err.println("ERROR: could not open install.log: "
+ logfileName + ": " + ioe);
ioe.printStackTrace(err);
}
this.title = this.getProperty(PROP_TITLE) ;
if(this.title == null) this.title = DEFAULT_TITLE ;
printStartMessageToLog();
}
}
protected String getPrefix() {
return PREFIX ;
}
/** Closes the logfile */
public void buildFinished(BuildEvent event) {
// just in case this is an early bailout
// for example, if cam-setup.xml is malformed...
initMessageHandlers();
handleMessage(event);
if ( event.getException() != null ) {
Throwable t = event.getException();
String errMsg = t.getMessage();
String errPrefix = generatePrefix((new MsgError()).getPrefix());
String infoPrefix = generatePrefix((new MsgInfo()).getPrefix());
if ( errMsg != null && !errMsg.trim().startsWith(errPrefix) ) {
String location = "";
boolean isEarlyExit = false;
if ( t instanceof BuildException ) {
isEarlyExit = (t.getCause() instanceof EarlyExitException);
if ( !isEarlyExit ) {
location = "at "
+ ((BuildException) t).getLocation()
+ ": ";
}
}
if ( isEarlyExit ) {
handleMessage(infoPrefix + t.getCause().getMessage());
} else {
handleMessage(errPrefix
+ "FATAL EXCEPTION " + location
+ errMsg);
}
}
}
if ( currentHandler != null ) {
currentHandler.endMessage();
}
if ( logfileStream != null ) {
try {
logfileStream.close();
} catch ( Exception ioe ) {
err.println("ERROR: could not close install.log: "
+ logfile.getAbsolutePath() + ": " + ioe);
ioe.printStackTrace(err);
}
}
}
/**
* Determine the message type for a given message.
* @param msg The message to examine
* @param msgbuf The buffer to use to store the actual message, with the
* prefix stripped.
* @return The type of the message, one of the MSGTYPE_XXX constants.
*/
protected InstallerMessageHandler getMessageHandler (String msg,
StringBuffer msgbuf) {
// ignore null messages
if ( msg == null ) return null;
msg = msg.trim();
// ignore empty messages
if ( msg.length() == 0 ) return null;
int prefixPos = msg.indexOf(PREFIX);
// ignore messages missing the global prefix
if ( prefixPos == -1 ) return null;
int colonPos = msg.indexOf(":");
// ignore messages missing a colon
if ( colonPos == -1 ) return null;
// err.println("---> checking out: " + msg);
String prefix = msg.substring(0, colonPos+1).trim();
InstallerMessageHandler handler
= (InstallerMessageHandler) messageHandlers.get(prefix);
if ( handler == null ) {
return null;
}
if ( msgbuf != null ) {
String realMessage
= msg.substring(prefix.length()).trim();
if ( realMessage.startsWith("\\") ) {
realMessage = realMessage.substring(1);
}
msgbuf.append(realMessage);
}
return handler;
}
public void targetStarted(BuildEvent event) {
initLogging(event);
initMessageHandlers();
handleMessage(event);
}
public void targetFinished(BuildEvent event) {
handleMessage(event);
}
public void taskStarted(BuildEvent event) {
handleMessage(event);
}
public void taskFinished(BuildEvent event) {
handleMessage(event);
}
public void messageLogged(BuildEvent event) {
handleMessage(event);
}
public void handleMessage(BuildEvent event) {
handleMessage(event.getMessage());
}
public void handleMessage(String message) {
// If we're in win32 installer mode, remove all internal line breaks.
message = nowrap(message);
StringBuffer msgbuf = new StringBuffer();
InstallerMessageHandler handler;
handler = getMessageHandler(message, msgbuf);
String msg = msgbuf.toString();
// don't do anything with empty messages
if ( msg.trim().length() == 0 ) return;
if ( handler == null ) {
// do not output unclassified messages
// and do not update currentMessageType
// err.println("no handler for: " + msg);
handler = currentHandler;
}
if ( currentHandler == handler ) {
handler.continueMessage(msg);
} else {
if ( currentHandler != null ) currentHandler.endMessage();
handler.beginMessage(msg);
currentHandler = handler;
}
}
/**
* Each message handler will callback to this method to perform actual
* writes.
*/
protected void printMessage ( String message ) {
out.println(message);
logToFile(message);
}
protected void logToFile ( String message ) {
if ( logfileStream != null ) {
try {
logfileStream.append(message);
logfileStream.append(LINE_SEP);
logfileStream.flush();
} catch ( Exception ioe ) {
err.println("ERROR: could not write to log: " + ioe);
}
}
}
protected void printStartMessageToLog () {
logToFile("====================================="
+ "====================================");
logToFile(this.title + " Started");
logToFile("Current Date/Time: " + (new java.util.Date()).toString());
logToFile("====================================="
+ "====================================");
}
protected void printEndMessageToLog () {
long duration = System.currentTimeMillis() - startTime;
logToFile("====================================="
+ "====================================");
logToFile(this.title + " Completed");
logToFile("Current Date/Time: " + (new java.util.Date()).toString());
logToFile("Total Runtime: " + StringUtil.formatDuration(duration));
logToFile("====================================="
+ "====================================");
logToFile("");
logToFile("");
}
private String getProperty (String name) {
String value = null;
value = project.getProperty(name);
if ( value == null ) {
value = project.getUserProperty(name);
if ( value == null ) {
value = System.getProperty(name);
}
}
return value;
}
private String nowrap(String msg) {
if (msg == null) return null;
if (isNoWrapMode) {
String ns = msg;
ns = StringUtil.replace(ns, "\n", "");
ns = StringUtil.replace(ns, "\r", "");
msg = ns;
}
return msg;
}
}