2006-11-06 05:16:01 +08:00
package hudson ;
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider ;
import com.thoughtworks.xstream.core.JVM ;
import hudson.model.Hudson ;
import hudson.model.User ;
import hudson.triggers.Trigger ;
import hudson.util.IncompatibleVMDetected ;
import hudson.util.RingBufferLogHandler ;
2006-12-10 03:30:15 +08:00
import hudson.util.IncompatibleServletVersionDetected ;
2006-11-06 05:16:01 +08:00
import javax.naming.Context ;
import javax.naming.InitialContext ;
import javax.naming.NamingException ;
import javax.servlet.ServletContext ;
import javax.servlet.ServletContextEvent ;
import javax.servlet.ServletContextListener ;
2006-12-10 03:30:15 +08:00
import javax.servlet.ServletResponse ;
2006-11-06 05:16:01 +08:00
import javax.xml.transform.TransformerFactory ;
import javax.xml.transform.TransformerFactoryConfigurationError ;
import java.io.File ;
import java.io.IOException ;
import java.io.InputStream ;
import java.util.Properties ;
import java.util.TimerTask ;
import java.util.logging.Logger ;
import java.util.logging.Level ;
/ * *
* Entry point when Hudson is used as a webapp .
*
* @author Kohsuke Kawaguchi
* /
public class WebAppMain implements ServletContextListener {
/ * *
* Creates the sole instance of { @link Hudson } and register it to the { @link ServletContext } .
* /
public void contextInitialized ( ServletContextEvent event ) {
installLogger ( ) ;
File home = getHomeDir ( event ) ;
home . mkdirs ( ) ;
System . out . println ( " hudson home directory: " + home ) ;
ServletContext context = event . getServletContext ( ) ;
// make sure that we are using XStream in the "enhenced" (JVM-specific) mode
if ( new JVM ( ) . bestReflectionProvider ( ) . getClass ( ) = = PureJavaReflectionProvider . class ) {
// nope
context . setAttribute ( " app " , new IncompatibleVMDetected ( ) ) ;
return ;
}
2006-12-10 03:30:15 +08:00
// make sure this is servlet 2.4 container or above
try {
ServletResponse . class . getMethod ( " setCharacterEncoding " , String . class ) ;
} catch ( NoSuchMethodException e ) {
context . setAttribute ( " app, " , new IncompatibleServletVersionDetected ( ) ) ;
return ;
}
2006-11-06 05:16:01 +08:00
// Tomcat breaks XSLT with JDK 5.0 and onward. Check if that's the case, and if so,
// try to correct it
try {
TransformerFactory . newInstance ( ) ;
// if this works we are all happy
} catch ( TransformerFactoryConfigurationError x ) {
// no it didn't.
Logger logger = Logger . getLogger ( WebAppMain . class . getName ( ) ) ;
logger . log ( Level . WARNING , " XSLT not configured correctly. Hudson will try to fix this. See http://issues.apache.org/bugzilla/show_bug.cgi?id=40895 for more details " , x ) ;
System . setProperty ( TransformerFactory . class . getName ( ) , " com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl " ) ;
try {
TransformerFactory . newInstance ( ) ;
logger . info ( " XSLT is set to the JAXP RI in JRE " ) ;
} catch ( TransformerFactoryConfigurationError y ) {
logger . log ( Level . SEVERE , " Failed to correct the problem. " ) ;
}
}
try {
context . setAttribute ( " app " , new Hudson ( home , context ) ) ;
} catch ( IOException e ) {
throw new Error ( e ) ;
}
// set the version
Properties props = new Properties ( ) ;
try {
InputStream is = getClass ( ) . getResourceAsStream ( " hudson-version.properties " ) ;
if ( is ! = null )
props . load ( is ) ;
} catch ( IOException e ) {
e . printStackTrace ( ) ; // if the version properties is missing, that's OK.
}
Object ver = props . get ( " version " ) ;
if ( ver = = null ) ver = " ? " ;
context . setAttribute ( " version " , ver ) ;
Trigger . init ( ) ; // start running trigger
// trigger the loading of changelogs in the background,
// but give the system 10 seconds so that the first page
// can be served quickly
Trigger . timer . schedule ( new TimerTask ( ) {
public void run ( ) {
User . get ( " nobody " ) . getBuilds ( ) ;
}
} , 1000 * 10 ) ;
}
/ * *
* Installs log handler to monitor all Hudson logs .
* /
private void installLogger ( ) {
RingBufferLogHandler handler = new RingBufferLogHandler ( ) ;
Hudson . logRecords = handler . getView ( ) ;
Logger . getLogger ( " hudson " ) . addHandler ( handler ) ;
}
/ * *
* Determines the home directory for Hudson .
*
* People makes configuration mistakes , so we are trying to be nice
* with those by doing { @link String # trim ( ) } .
* /
private File getHomeDir ( ServletContextEvent event ) {
// check JNDI for the home directory first
try {
Context env = ( Context ) new InitialContext ( ) . lookup ( " java:comp/env " ) ;
String value = ( String ) env . lookup ( " HUDSON_HOME " ) ;
if ( value ! = null & & value . trim ( ) . length ( ) > 0 )
2006-11-11 07:33:14 +08:00
return new File ( value . trim ( ) ) . getAbsoluteFile ( ) ;
2006-11-06 05:16:01 +08:00
} catch ( NamingException e ) {
// ignore
}
// look at the env var next
String env = EnvVars . masterEnvVars . get ( " HUDSON_HOME " ) ;
if ( env ! = null )
2006-11-11 07:33:14 +08:00
return new File ( env . trim ( ) ) . getAbsoluteFile ( ) ;
2006-11-06 05:16:01 +08:00
// finally check the system property
String sysProp = System . getProperty ( " HUDSON_HOME " ) ;
if ( sysProp ! = null )
2006-11-11 07:33:14 +08:00
return new File ( sysProp . trim ( ) ) . getAbsoluteFile ( ) ;
2006-11-06 05:16:01 +08:00
// otherwise pick a place by ourselves
String root = event . getServletContext ( ) . getRealPath ( " /WEB-INF/workspace " ) ;
if ( root ! = null ) {
File ws = new File ( root . trim ( ) ) ;
if ( ws . exists ( ) )
// Hudson <1.42 used to prefer this betfore ~/.hudson, so
// check the existence and if it's there, use it.
// otherwise if this is a new installation, prefer ~/.hudson
2006-11-11 07:33:14 +08:00
return ws . getAbsoluteFile ( ) ;
2006-11-06 05:16:01 +08:00
}
// if for some reason we can't put it within the webapp, use home directory.
2006-11-11 07:33:14 +08:00
return new File ( new File ( System . getProperty ( " user.home " ) ) , " .hudson " ) . getAbsoluteFile ( ) ;
2006-11-06 05:16:01 +08:00
}
public void contextDestroyed ( ServletContextEvent event ) {
Hudson instance = Hudson . getInstance ( ) ;
if ( instance ! = null )
instance . cleanUp ( ) ;
}
}