2009-02-07 04:05:24 +08:00
/ *
* The MIT License
*
* Copyright ( c ) 2004 - 2009 , Sun Microsystems , Inc . , Kohsuke Kawaguchi , Jean - Baptiste Quenot , Tom Huybrechts
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
* /
2006-11-06 05:16:01 +08:00
package hudson ;
2016-07-07 18:46:45 +08:00
import hudson.security.ACLContext ;
2017-03-20 20:50:46 +08:00
import java.io.OutputStream ;
import java.nio.file.Files ;
2017-04-19 21:04:33 +08:00
import java.nio.file.InvalidPathException ;
2017-03-20 20:50:46 +08:00
import java.nio.file.StandardOpenOption ;
2015-11-19 02:26:41 +08:00
import jenkins.util.SystemProperties ;
2006-11-06 05:16:01 +08:00
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider ;
import com.thoughtworks.xstream.core.JVM ;
import hudson.model.Hudson ;
2016-04-21 06:00:10 +08:00
import hudson.security.ACL ;
2013-11-17 02:24:21 +08:00
import hudson.util.BootFailure ;
2011-05-29 17:53:24 +08:00
import jenkins.model.Jenkins ;
2008-02-08 14:07:04 +08:00
import hudson.util.HudsonIsLoading ;
import hudson.util.IncompatibleServletVersionDetected ;
import hudson.util.IncompatibleVMDetected ;
import hudson.util.InsufficientPermissionDetected ;
import hudson.util.NoHomeDir ;
import hudson.util.RingBufferLogHandler ;
import hudson.util.NoTempDir ;
2008-02-29 22:10:14 +08:00
import hudson.util.IncompatibleAntVersionDetected ;
2008-06-06 02:29:38 +08:00
import hudson.util.HudsonFailedToLoad ;
2008-12-23 11:10:41 +08:00
import hudson.util.ChartUtil ;
import hudson.util.AWTProblem ;
2016-03-09 07:05:00 +08:00
import jenkins.util.JenkinsJVM ;
2008-02-08 14:07:04 +08:00
import org.jvnet.localizer.LocaleProvider ;
2020-04-22 03:27:11 +08:00
import org.kohsuke.accmod.Restricted ;
import org.kohsuke.accmod.restrictions.NoExternalUse ;
2009-03-23 02:56:36 +08:00
import org.kohsuke.stapler.jelly.JellyFacet ;
2008-02-29 22:10:14 +08:00
import org.apache.tools.ant.types.FileSet ;
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 ;
2020-04-22 03:27:11 +08:00
import javax.servlet.SessionTrackingMode ;
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 ;
2008-02-08 14:07:04 +08:00
import java.net.URL ;
import java.net.URLClassLoader ;
2013-11-17 03:09:07 +08:00
import java.util.Date ;
2020-04-22 03:27:11 +08:00
import java.util.EnumSet ;
2007-12-27 08:46:21 +08:00
import java.util.Locale ;
2006-11-06 05:16:01 +08:00
import java.util.logging.Level ;
2006-12-30 03:15:53 +08:00
import java.util.logging.Logger ;
2009-02-14 01:25:14 +08:00
import java.security.Security ;
2020-07-21 22:50:13 +08:00
import java.util.logging.ConsoleHandler ;
import java.util.logging.Formatter ;
import java.util.logging.Handler ;
2013-07-27 05:20:32 +08:00
import java.util.logging.LogRecord ;
2007-12-20 14:35:28 +08:00
2013-11-17 03:09:07 +08:00
import static java.util.logging.Level.* ;
2006-11-06 05:16:01 +08:00
/ * *
* Entry point when Hudson is used as a webapp .
*
* @author Kohsuke Kawaguchi
* /
2013-11-17 04:56:28 +08:00
public class WebAppMain implements ServletContextListener {
2016-09-21 16:39:52 +08:00
// use RingBufferLogHandler class name to configure for backward compatibility
private static final int DEFAULT_RING_BUFFER_SIZE = SystemProperties . getInteger ( RingBufferLogHandler . class . getName ( ) + " .defaultSize " , 256 ) ;
2020-04-22 03:27:11 +08:00
/ * *
* System property name to force the session tracking by cookie .
* This prevents Tomcat to use the URL tracking in addition to the cookie by default .
* This could be useful for instances that requires to have
* the { @link jenkins . security . SuspiciousRequestFilter # allowSemicolonsInPath } turned off .
* < p >
* If you allow semicolon in URL and the session to be tracked by URL and you have
* a SecurityRealm that does not invalidate session after authentication ,
* your instance is vulnerable to session hijacking .
* < p >
* The SecurityRealm should be corrected but this is a hardening in Jenkins core .
* < p >
* As this property is read during startup , you will not be able to change it at runtime
* depending on your application server ( not possible with Jetty nor Tomcat )
* < p >
* When running hpi : run , the default tracking is COOKIE + URL .
* When running java - jar with Winstone / Jetty , the default setting is set to COOKIE only .
* When running inside Tomcat , the default setting is COOKIE + URL .
* /
@Restricted ( NoExternalUse . class )
public static final String FORCE_SESSION_TRACKING_BY_COOKIE_PROP = WebAppMain . class . getName ( ) + " .forceSessionTrackingByCookie " ;
2016-09-21 16:39:52 +08:00
private final RingBufferLogHandler handler = new RingBufferLogHandler ( DEFAULT_RING_BUFFER_SIZE ) {
2013-07-27 05:20:32 +08:00
@Override public synchronized void publish ( LogRecord record ) {
if ( record . getLevel ( ) . intValue ( ) > = Level . INFO . intValue ( ) ) {
super . publish ( record ) ;
}
}
} ;
2007-11-02 06:14:22 +08:00
private static final String APP = " app " ;
2011-07-17 15:35:39 +08:00
private boolean terminated ;
private Thread initThread ;
2006-11-06 05:16:01 +08:00
/ * *
2011-05-29 17:53:24 +08:00
* Creates the sole instance of { @link jenkins . model . Jenkins } and register it to the { @link ServletContext } .
2006-11-06 05:16:01 +08:00
* /
2020-07-21 22:50:13 +08:00
@Override
2006-11-06 05:16:01 +08:00
public void contextInitialized ( ServletContextEvent event ) {
2020-07-21 22:50:13 +08:00
// Nicer console log formatting when using mvn jetty:run.
if ( Main . isDevelopmentMode & & System . getProperty ( " java.util.logging.config.file " ) = = null ) {
try {
Formatter formatter = ( Formatter ) Class . forName ( " io.jenkins.lib.support_log_formatter.SupportLogFormatter " ) . newInstance ( ) ;
for ( Handler h : java . util . logging . Logger . getLogger ( " " ) . getHandlers ( ) ) {
if ( h instanceof ConsoleHandler ) {
( ( ConsoleHandler ) h ) . setFormatter ( formatter ) ;
}
}
} catch ( ClassNotFoundException x ) {
// ignore
} catch ( Exception x ) {
LOGGER . log ( Level . WARNING , null , x ) ;
}
}
2016-03-09 07:05:00 +08:00
JenkinsJVMAccess . _setJenkinsJVM ( true ) ;
2013-11-17 02:24:21 +08:00
final ServletContext context = event . getServletContext ( ) ;
2013-11-17 03:09:07 +08:00
File home = null ;
2007-08-10 12:36:48 +08:00
try {
2007-12-27 08:46:21 +08:00
// use the current request to determine the language
LocaleProvider . setProvider ( new LocaleProvider ( ) {
public Locale get ( ) {
2011-03-01 16:15:15 +08:00
return Functions . getCurrentLocale ( ) ;
2007-12-27 08:46:21 +08:00
}
} ) ;
2007-10-31 10:14:53 +08:00
// quick check to see if we (seem to) have enough permissions to run. (see #719)
JVM jvm ;
try {
jvm = new JVM ( ) ;
new URLClassLoader ( new URL [ 0 ] , getClass ( ) . getClassLoader ( ) ) ;
} catch ( SecurityException e ) {
2013-11-17 02:24:21 +08:00
throw new InsufficientPermissionDetected ( e ) ;
2007-10-31 10:14:53 +08:00
}
2007-08-10 12:36:48 +08:00
2011-01-31 15:44:52 +08:00
try { // remove Sun PKCS11 provider if present. See http://wiki.jenkins-ci.org/display/JENKINS/Solaris+Issue+6276483
2009-02-14 01:25:14 +08:00
Security . removeProvider ( " SunPKCS11-Solaris " ) ;
} catch ( SecurityException e ) {
// ignore this error.
}
2007-10-31 10:14:53 +08:00
installLogger ( ) ;
2006-11-06 05:16:01 +08:00
2011-02-03 11:47:07 +08:00
final FileAndDescription describedHomeDir = getHomeDir ( event ) ;
2013-11-17 03:09:07 +08:00
home = describedHomeDir . file . getAbsoluteFile ( ) ;
2007-10-31 10:14:53 +08:00
home . mkdirs ( ) ;
2019-10-20 02:12:45 +08:00
LOGGER . info ( " Jenkins home directory: " + home + " found at: " + describedHomeDir . description ) ;
2006-11-06 05:16:01 +08:00
2007-10-31 10:14:53 +08:00
// check that home exists (as mkdirs could have failed silently), otherwise throw a meaningful error
2013-11-17 02:24:21 +08:00
if ( ! home . exists ( ) )
throw new NoHomeDir ( home ) ;
2006-11-06 05:16:01 +08:00
2013-11-17 03:09:07 +08:00
recordBootAttempt ( home ) ;
2007-10-31 10:14:53 +08:00
// make sure that we are using XStream in the "enhanced" (JVM-specific) mode
if ( jvm . bestReflectionProvider ( ) . getClass ( ) = = PureJavaReflectionProvider . class ) {
2013-11-17 02:24:21 +08:00
throw new IncompatibleVMDetected ( ) ; // nope
2007-10-31 10:14:53 +08:00
}
2006-12-10 03:30:15 +08:00
2009-11-26 07:21:17 +08:00
// JNA is no longer a hard requirement. It's just nice to have. See HUDSON-4820 for more context.
// // make sure JNA works. this can fail if
// // - platform is unsupported
// // - JNA is already loaded in another classloader
2011-01-31 15:44:52 +08:00
// // see http://wiki.jenkins-ci.org/display/JENKINS/JNA+is+already+loaded
2009-11-26 07:21:17 +08:00
// // TODO: or shall we instead modify Hudson to work gracefully without JNA?
// try {
// /*
// java.lang.UnsatisfiedLinkError: Native Library /builds/apps/glassfish/domains/hudson-domain/generated/jsp/j2ee-modules/hudson-1.309/loader/com/sun/jna/sunos-sparc/libjnidispatch.so already loaded in another classloader
// at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1743)
// at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1674)
// at java.lang.Runtime.load0(Runtime.java:770)
// at java.lang.System.load(System.java:1005)
// at com.sun.jna.Native.loadNativeLibraryFromJar(Native.java:746)
// at com.sun.jna.Native.loadNativeLibrary(Native.java:680)
// at com.sun.jna.Native.<clinit>(Native.java:108)
// at hudson.util.jna.GNUCLibrary.<clinit>(GNUCLibrary.java:86)
// at hudson.Util.createSymlink(Util.java:970)
// at hudson.model.Run.run(Run.java:1174)
// at hudson.matrix.MatrixBuild.run(MatrixBuild.java:149)
// at hudson.model.ResourceController.execute(ResourceController.java:88)
// at hudson.model.Executor.run(Executor.java:123)
// */
// String.valueOf(Native.POINTER_SIZE); // this meaningless operation forces the classloading and initialization
// } catch (LinkageError e) {
// if (e.getMessage().contains("another classloader"))
// context.setAttribute(APP,new JNADoublyLoaded(e));
// else
// context.setAttribute(APP,new HudsonFailedToLoad(e));
// }
2009-11-20 06:24:43 +08:00
2007-10-31 10:14:53 +08:00
// make sure this is servlet 2.4 container or above
2006-11-06 05:16:01 +08:00
try {
2007-10-31 10:14:53 +08:00
ServletResponse . class . getMethod ( " setCharacterEncoding " , String . class ) ;
} catch ( NoSuchMethodException e ) {
2013-11-17 02:24:21 +08:00
throw new IncompatibleServletVersionDetected ( ServletResponse . class ) ;
2006-11-06 05:16:01 +08:00
}
2007-09-17 07:46:12 +08:00
2008-02-29 22:10:14 +08:00
// make sure that we see Ant 1.7
try {
FileSet . class . getMethod ( " getDirectoryScanner " ) ;
} catch ( NoSuchMethodException e ) {
2013-11-17 02:24:21 +08:00
throw new IncompatibleAntVersionDetected ( FileSet . class ) ;
2008-02-29 22:10:14 +08:00
}
2008-12-23 11:10:41 +08:00
// make sure AWT is functioning, or else JFreeChart won't even load.
2008-12-25 02:11:44 +08:00
if ( ChartUtil . awtProblemCause ! = null ) {
2013-11-17 02:24:21 +08:00
throw new AWTProblem ( ChartUtil . awtProblemCause ) ;
2008-12-23 11:10:41 +08:00
}
2008-02-08 14:07:04 +08:00
// some containers (in particular Tomcat) doesn't abort a launch
// even if the temp directory doesn't exist.
// check that and report an error
try {
File f = File . createTempFile ( " test " , " test " ) ;
f . delete ( ) ;
} catch ( IOException e ) {
2013-11-17 02:24:21 +08:00
throw new NoTempDir ( e ) ;
2008-02-08 14:07:04 +08:00
}
2007-10-31 10:14:53 +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.
2013-11-17 03:09:07 +08:00
LOGGER . log ( 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 ) ;
2007-10-31 10:14:53 +08:00
System . setProperty ( TransformerFactory . class . getName ( ) , " com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl " ) ;
2007-09-17 07:46:12 +08:00
try {
2007-10-31 10:14:53 +08:00
TransformerFactory . newInstance ( ) ;
2010-03-09 10:12:50 +08:00
LOGGER . info ( " XSLT is set to the JAXP RI in JRE " ) ;
2007-10-31 10:14:53 +08:00
} catch ( TransformerFactoryConfigurationError y ) {
2013-11-17 03:09:07 +08:00
LOGGER . log ( SEVERE , " Failed to correct the problem. " ) ;
2007-09-17 07:46:12 +08:00
}
2007-10-31 10:14:53 +08:00
}
2007-09-17 07:46:12 +08:00
2008-12-25 02:11:44 +08:00
installExpressionFactory ( event ) ;
2007-12-20 14:35:28 +08:00
2007-11-02 06:14:22 +08:00
context . setAttribute ( APP , new HudsonIsLoading ( ) ) ;
2020-04-22 03:27:11 +08:00
if ( SystemProperties . getBoolean ( FORCE_SESSION_TRACKING_BY_COOKIE_PROP , true ) ) {
context . setSessionTrackingModes ( EnumSet . of ( SessionTrackingMode . COOKIE ) ) ;
}
2007-10-31 10:14:53 +08:00
2013-11-17 03:09:07 +08:00
final File _home = home ;
2013-06-22 08:38:33 +08:00
initThread = new Thread ( " Jenkins initialization thread " ) {
2009-09-15 02:08:34 +08:00
@Override
2007-10-31 10:14:53 +08:00
public void run ( ) {
2011-07-19 01:26:30 +08:00
boolean success = false ;
2007-10-31 10:14:53 +08:00
try {
2013-11-17 03:09:07 +08:00
Jenkins instance = new Hudson ( _home , context ) ;
2016-04-27 08:53:41 +08:00
// one last check to make sure everything is in order before we go live
if ( Thread . interrupted ( ) )
throw new InterruptedException ( ) ;
2011-07-17 15:35:39 +08:00
context . setAttribute ( APP , instance ) ;
2007-10-31 10:14:53 +08:00
2013-11-17 03:09:07 +08:00
BootFailure . getBootFailureFile ( _home ) . delete ( ) ;
2011-08-10 04:19:20 +08:00
// at this point we are open for business and serving requests normally
LOGGER . info ( " Jenkins is fully up and running " ) ;
2011-07-19 01:26:30 +08:00
success = true ;
2007-10-31 10:14:53 +08:00
} catch ( Error e ) {
2013-11-17 03:09:07 +08:00
new HudsonFailedToLoad ( e ) . publish ( context , _home ) ;
2007-10-31 10:14:53 +08:00
throw e ;
2009-06-20 04:54:39 +08:00
} catch ( Exception e ) {
2013-11-17 03:09:07 +08:00
new HudsonFailedToLoad ( e ) . publish ( context , _home ) ;
2011-07-17 15:35:39 +08:00
} finally {
2016-03-09 05:14:36 +08:00
Jenkins instance = Jenkins . getInstanceOrNull ( ) ;
2011-07-19 01:26:30 +08:00
if ( ! success & & instance ! = null )
2011-07-17 15:35:39 +08:00
instance . cleanUp ( ) ;
2007-09-17 07:46:12 +08:00
}
2007-10-31 10:14:53 +08:00
}
2011-07-17 15:35:39 +08:00
} ;
initThread . start ( ) ;
2013-11-17 02:24:21 +08:00
} catch ( BootFailure e ) {
2016-04-21 06:00:10 +08:00
e . publish ( context , home ) ;
2016-04-12 04:28:22 +08:00
} catch ( Error | RuntimeException e ) {
2013-11-17 03:09:07 +08:00
LOGGER . log ( SEVERE , " Failed to initialize Jenkins " , e ) ;
2007-10-31 10:14:53 +08:00
throw e ;
}
2006-11-06 05:16:01 +08:00
}
2013-11-17 04:56:28 +08:00
public void joinInit ( ) throws InterruptedException {
initThread . join ( ) ;
}
2013-11-17 03:09:07 +08:00
/ * *
* To assist boot failure script , record the number of boot attempts .
* This file gets deleted in case of successful boot .
*
* @see BootFailure
* /
private void recordBootAttempt ( File home ) {
2017-03-20 20:50:46 +08:00
try ( OutputStream o = Files . newOutputStream ( BootFailure . getBootFailureFile ( home ) . toPath ( ) , StandardOpenOption . CREATE , StandardOpenOption . APPEND ) ) {
2019-02-21 13:27:44 +08:00
o . write ( ( new Date ( ) . toString ( ) + System . getProperty ( " line.separator " , " \ n " ) ) . getBytes ( ) ) ;
2017-04-19 21:04:33 +08:00
} catch ( IOException | InvalidPathException e ) {
2013-11-17 03:09:07 +08:00
LOGGER . log ( WARNING , " Failed to record boot attempts " , e ) ;
}
}
2008-12-25 02:11:44 +08:00
public static void installExpressionFactory ( ServletContextEvent event ) {
2009-03-23 02:56:36 +08:00
JellyFacet . setExpressionFactory ( event , new ExpressionFactory2 ( ) ) ;
2008-12-25 02:11:44 +08:00
}
2007-09-18 18:51:47 +08:00
/ * *
2006-11-06 05:16:01 +08:00
* Installs log handler to monitor all Hudson logs .
* /
2016-10-16 03:53:56 +08:00
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings ( " LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE " )
2006-11-06 05:16:01 +08:00
private void installLogger ( ) {
2011-05-29 01:11:48 +08:00
Jenkins . logRecords = handler . getView ( ) ;
2013-02-26 03:13:01 +08:00
Logger . getLogger ( " " ) . addHandler ( handler ) ;
2006-11-06 05:16:01 +08:00
}
2011-02-03 11:47:07 +08:00
/** Add some metadata to a File, allowing to trace setup issues */
2012-03-11 03:37:08 +08:00
public static class FileAndDescription {
public final File file ;
public final String description ;
2011-02-03 11:47:07 +08:00
public FileAndDescription ( File file , String description ) {
this . file = file ;
this . description = description ;
}
}
2006-11-06 05:16:01 +08:00
/ * *
2011-01-31 08:25:58 +08:00
* Determines the home directory for Jenkins .
2006-11-06 05:16:01 +08:00
*
2011-01-31 08:25:58 +08:00
* < p >
* We look for a setting that affects the smallest scope first , then bigger ones later .
*
* < p >
2006-11-06 05:16:01 +08:00
* People makes configuration mistakes , so we are trying to be nice
* with those by doing { @link String # trim ( ) } .
2011-02-03 11:47:07 +08:00
*
* < p >
* @return the File alongside with some description to help the user troubleshoot issues
2006-11-06 05:16:01 +08:00
* /
2012-03-11 03:37:08 +08:00
public FileAndDescription getHomeDir ( ServletContextEvent event ) {
2006-11-06 05:16:01 +08:00
// check JNDI for the home directory first
2011-01-31 08:25:58 +08:00
for ( String name : HOME_NAMES ) {
try {
InitialContext iniCtxt = new InitialContext ( ) ;
Context env = ( Context ) iniCtxt . lookup ( " java:comp/env " ) ;
String value = ( String ) env . lookup ( name ) ;
if ( value ! = null & & value . trim ( ) . length ( ) > 0 )
2011-02-03 11:47:07 +08:00
return new FileAndDescription ( new File ( value . trim ( ) ) , " JNDI/java:comp/env/ " + name ) ;
2011-01-31 08:25:58 +08:00
// look at one more place. See issue #1314
value = ( String ) iniCtxt . lookup ( name ) ;
if ( value ! = null & & value . trim ( ) . length ( ) > 0 )
2011-02-03 11:47:07 +08:00
return new FileAndDescription ( new File ( value . trim ( ) ) , " JNDI/ " + name ) ;
2011-01-31 08:25:58 +08:00
} catch ( NamingException e ) {
// ignore
}
}
// next the system property
for ( String name : HOME_NAMES ) {
2015-11-19 02:26:41 +08:00
String sysProp = SystemProperties . getString ( name ) ;
2011-01-31 08:25:58 +08:00
if ( sysProp ! = null )
2015-11-17 09:38:51 +08:00
return new FileAndDescription ( new File ( sysProp . trim ( ) ) , " SystemProperties.getProperty( \" " + name + " \" ) " ) ;
2006-11-06 05:16:01 +08:00
}
2008-01-30 00:35:56 +08:00
// look at the env var next
2011-01-31 08:25:58 +08:00
for ( String name : HOME_NAMES ) {
String env = EnvVars . masterEnvVars . get ( name ) ;
if ( env ! = null )
2011-02-03 11:47:07 +08:00
return new FileAndDescription ( new File ( env . trim ( ) ) . getAbsoluteFile ( ) , " EnvVars.masterEnvVars.get( \" " + name + " \" ) " ) ;
2011-01-31 08:25:58 +08:00
}
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 ( ) )
2006-12-21 03:20:31 +08:00
// Hudson <1.42 used to prefer this before ~/.hudson, so
2006-11-06 05:16:01 +08:00
// check the existence and if it's there, use it.
// otherwise if this is a new installation, prefer ~/.hudson
2011-02-03 11:47:07 +08:00
return new FileAndDescription ( ws , " getServletContext().getRealPath( \" /WEB-INF/workspace \" ) " ) ;
2006-11-06 05:16:01 +08:00
}
2011-02-03 11:47:07 +08:00
File legacyHome = new File ( new File ( System . getProperty ( " user.home " ) ) , " .hudson " ) ;
if ( legacyHome . exists ( ) ) {
return new FileAndDescription ( legacyHome , " $user.home/.hudson " ) ; // before rename, this is where it was stored
}
2011-01-31 08:25:58 +08:00
2011-02-03 11:47:07 +08:00
File newHome = new File ( new File ( System . getProperty ( " user.home " ) ) , " .jenkins " ) ;
return new FileAndDescription ( newHome , " $user.home/.jenkins " ) ;
2006-11-06 05:16:01 +08:00
}
public void contextDestroyed ( ServletContextEvent event ) {
2016-07-07 18:46:45 +08:00
try ( ACLContext old = ACL . as ( ACL . SYSTEM ) ) {
Jenkins instance = Jenkins . getInstanceOrNull ( ) ;
2017-02-12 18:50:52 +08:00
try {
if ( instance ! = null ) {
instance . cleanUp ( ) ;
}
} catch ( Exception e ) {
LOGGER . log ( Level . SEVERE , " Failed to clean up. Restart will continue. " , e ) ;
2016-02-10 20:53:39 +08:00
}
2016-02-10 22:38:52 +08:00
2017-02-12 18:50:52 +08:00
terminated = true ;
2016-07-07 18:46:45 +08:00
Thread t = initThread ;
if ( t ! = null & & t . isAlive ( ) ) {
LOGGER . log ( Level . INFO , " Shutting down a Jenkins instance that was still starting up " , new Throwable ( " reason " ) ) ;
t . interrupt ( ) ;
}
2007-04-06 22:20:13 +08:00
2016-07-07 18:46:45 +08:00
// Logger is in the system classloader, so if we don't do this
2017-02-12 18:38:30 +08:00
// the whole web app will never be undeployed.
2016-07-07 18:46:45 +08:00
Logger . getLogger ( " " ) . removeHandler ( handler ) ;
2016-03-09 07:05:00 +08:00
} finally {
JenkinsJVMAccess . _setJenkinsJVM ( false ) ;
}
2006-11-06 05:16:01 +08:00
}
2007-10-31 10:14:53 +08:00
private static final Logger LOGGER = Logger . getLogger ( WebAppMain . class . getName ( ) ) ;
2007-12-20 14:35:28 +08:00
2016-03-09 07:05:00 +08:00
private static final class JenkinsJVMAccess extends JenkinsJVM {
private static void _setJenkinsJVM ( boolean jenkinsJVM ) {
JenkinsJVM . setJenkinsJVM ( jenkinsJVM ) ;
}
}
2011-01-31 08:25:58 +08:00
private static final String [ ] HOME_NAMES = { " JENKINS_HOME " , " HUDSON_HOME " } ;
2006-11-06 05:16:01 +08:00
}