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 ;
2007-08-02 01:05:31 +08:00
import hudson.triggers.SafeTimerTask ;
2008-02-08 14:07:04 +08:00
import hudson.triggers.Trigger ;
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-02-08 14:07:04 +08:00
import org.jvnet.localizer.LocaleProvider ;
import org.kohsuke.stapler.Stapler ;
import org.kohsuke.stapler.StaplerRequest ;
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 ;
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 ;
2008-02-08 14:07:04 +08:00
import java.net.URL ;
import java.net.URLClassLoader ;
2007-12-27 08:46:21 +08:00
import java.util.Locale ;
2008-02-08 14:07:04 +08:00
import java.util.Properties ;
Merged revisions 9727,9739,9765-9766,9927,10332,10334-10338,10340,10416,10421,10553,10839-10845,10876 via svnmerge from
https://www.dev.java.net/svn/hudson/branches/tom
........
r9727 | huybrechts | 2008-05-31 12:49:18 -0700 (Sat, 31 May 2008) | 3 lines
Issue 1659
- cleaning up static Trigger, Hudson instances
- resetting commons-logging
........
r9739 | huybrechts | 2008-06-01 12:05:51 -0700 (Sun, 01 Jun 2008) | 1 line
#1770 catching and logging InstantiationError
........
r9765 | huybrechts | 2008-06-02 11:34:45 -0700 (Mon, 02 Jun 2008) | 1 line
project-based security: fixed a new isAdmin call
........
r9766 | huybrechts | 2008-06-02 11:35:27 -0700 (Mon, 02 Jun 2008) | 1 line
"theInstance = null" caused some reloading problems
........
r9927 | huybrechts | 2008-06-07 15:31:20 -0700 (Sat, 07 Jun 2008) | 8 lines
Initial commit of parameterized builds. Provided functionality:
- users can define parameters per project (only string paramters for now)
- if a project has parameters, the 'build' button will redirect to an input page
- parameter values can be used as ${variable} in Ant, Maven and CommandInterpreter builders
- after the build, parameter values can be viewed in a separate page
- tasks for parameterized builds are persisted in the queue over restarts
- queue persistence is now in XML (with backwards compatibility for text format)
........
r10332 | huybrechts | 2008-06-23 05:32:45 -0700 (Mon, 23 Jun 2008) | 1 line
made EmbedderLoggerImpl public for use in plugins
........
r10334 | huybrechts | 2008-06-23 05:48:10 -0700 (Mon, 23 Jun 2008) | 1 line
[HUDSON-1914] additional parameter types (job, run), bugfixes
........
r10335 | huybrechts | 2008-06-23 05:49:10 -0700 (Mon, 23 Jun 2008) | 1 line
[HUDSON-1573] initialize servlet filters
........
r10336 | huybrechts | 2008-06-23 05:52:14 -0700 (Mon, 23 Jun 2008) | 1 line
[HUDSON-1915] onStarted onevent
........
r10337 | huybrechts | 2008-06-23 06:07:32 -0700 (Mon, 23 Jun 2008) | 4 lines
[HUDSON-1504] basic ui for job-based access control
This allows assigning permissions per user and per job.
It is still possible to provide defaults using a global matrix.
........
r10338 | huybrechts | 2008-06-23 06:18:13 -0700 (Mon, 23 Jun 2008) | 3 lines
[HUDSON-1504] basic ui for job-based access control
adding it to the list...
........
r10340 | huybrechts | 2008-06-23 07:23:12 -0700 (Mon, 23 Jun 2008) | 1 line
[HUDSON-1504] fix compile error
........
r10416 | huybrechts | 2008-06-25 01:13:11 -0700 (Wed, 25 Jun 2008) | 1 line
initial commit staging plugin: supports doing a maven release to a staging repository, serving that repository for Hudson, and uploading it on demand
........
r10421 | huybrechts | 2008-06-25 12:32:06 -0700 (Wed, 25 Jun 2008) | 1 line
[HUDSON-1954] initial commit jbpm plugin and staging workflow example
........
r10553 | huybrechts | 2008-07-01 14:13:57 -0700 (Tue, 01 Jul 2008) | 1 line
moving registration for parameter definition out of registered class
........
r10839 | kohsuke | 2008-07-15 13:48:05 -0700 (Tue, 15 Jul 2008) | 6 lines
Making a few adjustments in preparation of merging back to the trunk.
- doc updates
- added QueueTaskFilter as a plain delegation implementation to simplify ParameterizedProjectTask.
- renamed ParameterDefinition.newInstance(...) to createValue, to avoid having two newInstance methods
in this part of the system that does different things
........
r10840 | kohsuke | 2008-07-15 13:51:16 -0700 (Tue, 15 Jul 2008) | 1 line
Hudson's coding convention is to use WS and no TAB.
........
r10841 | kohsuke | 2008-07-15 14:34:37 -0700 (Tue, 15 Jul 2008) | 2 lines
- making ParameterValue an abstract class to allow evolution without breaking plugins in the future
- tweaked the UI a bit so that parameterization don't get too much visibility.
........
r10842 | kohsuke | 2008-07-15 14:49:35 -0700 (Tue, 15 Jul 2008) | 2 lines
improving the UI a bit.
Added an icon
........
r10843 | kohsuke | 2008-07-15 15:08:28 -0700 (Tue, 15 Jul 2008) | 1 line
adding help
........
r10844 | kohsuke | 2008-07-15 15:10:42 -0700 (Tue, 15 Jul 2008) | 1 line
TAB->WS
........
r10845 | kohsuke | 2008-07-15 15:44:47 -0700 (Tue, 15 Jul 2008) | 2 lines
- Use HTTP status code to notify the automated clients that the build triggering failed.
- Overload the "/build" URL to render the parameter entry form.
........
r10876 | kohsuke | 2008-07-18 13:52:51 -0700 (Fri, 18 Jul 2008) | 10 lines
Giving more hooks to ParameterValue to affect a build
- abstracting the variable substitution process so that the actual syntax for marking
variables (e.g., %VAR% vs ${var} vs #{xyz}) and the actual resolution process are
orthogonal.
- parameter values can now contribute BuildWrapper to a build.
- parameter values can now contribute environment variables to a build.
........
git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@10950 71c3de6d-444a-0410-be80-ed276b4c234a
2008-07-22 08:48:13 +08:00
import java.util.Timer ;
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 ;
2007-12-20 14:35:28 +08:00
2006-11-06 05:16:01 +08:00
/ * *
* Entry point when Hudson is used as a webapp .
*
* @author Kohsuke Kawaguchi
* /
public class WebAppMain implements ServletContextListener {
2007-04-06 22:20:13 +08:00
private final RingBufferLogHandler handler = new RingBufferLogHandler ( ) ;
2007-11-02 06:14:22 +08:00
private static final String APP = " app " ;
2006-11-06 05:16:01 +08:00
/ * *
* Creates the sole instance of { @link Hudson } and register it to the { @link ServletContext } .
* /
public void contextInitialized ( ServletContextEvent event ) {
2007-08-10 12:36:48 +08:00
try {
2007-10-31 10:14:53 +08:00
final ServletContext context = event . getServletContext ( ) ;
2007-08-10 12:36:48 +08:00
2007-12-27 08:46:21 +08:00
// use the current request to determine the language
LocaleProvider . setProvider ( new LocaleProvider ( ) {
public Locale get ( ) {
Locale locale = null ;
StaplerRequest req = Stapler . getCurrentRequest ( ) ;
if ( req ! = null )
locale = req . getLocale ( ) ;
if ( locale = = null )
locale = Locale . getDefault ( ) ;
return locale ;
}
} ) ;
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 ) {
2007-11-02 06:14:22 +08:00
context . setAttribute ( APP , new InsufficientPermissionDetected ( e ) ) ;
2007-10-31 10:14:53 +08:00
return ;
}
2007-08-10 12:36:48 +08:00
2007-10-31 10:14:53 +08:00
installLogger ( ) ;
2006-11-06 05:16:01 +08:00
2007-10-31 10:14:53 +08:00
final File home = getHomeDir ( event ) . getAbsoluteFile ( ) ;
home . mkdirs ( ) ;
System . out . println ( " hudson home directory: " + home ) ;
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
if ( ! home . exists ( ) ) {
2007-11-02 06:14:22 +08:00
context . setAttribute ( APP , new NoHomeDir ( home ) ) ;
2007-10-31 10:14:53 +08:00
return ;
}
2006-11-06 05:16:01 +08:00
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 ) {
// nope
2007-11-02 06:14:22 +08:00
context . setAttribute ( APP , new IncompatibleVMDetected ( ) ) ;
2007-10-31 10:14:53 +08:00
return ;
}
2006-12-10 03:30:15 +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 ) {
2007-11-06 02:59:23 +08:00
context . setAttribute ( APP , new IncompatibleServletVersionDetected ( ServletResponse . class ) ) ;
2007-10-31 10:14:53 +08:00
return ;
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 ) {
context . setAttribute ( APP , new IncompatibleAntVersionDetected ( FileSet . class ) ) ;
return ;
}
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 ) {
context . setAttribute ( APP , new NoTempDir ( e ) ) ;
return ;
}
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.
Logger logger = Logger . getLogger ( WebAppMain . class . getName ( ) ) ;
2007-09-18 18:51:47 +08:00
2007-10-31 10:14:53 +08:00
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 " ) ;
2007-09-17 07:46:12 +08:00
try {
2007-10-31 10:14:53 +08:00
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. " ) ;
2007-09-17 07:46:12 +08:00
}
2007-10-31 10:14:53 +08:00
}
2007-09-17 07:46:12 +08:00
2007-12-20 14:35:28 +08:00
Stapler . setExpressionFactory ( event , new ExpressionFactory2 ( ) ) ;
2007-11-02 06:14:22 +08:00
context . setAttribute ( APP , new HudsonIsLoading ( ) ) ;
2007-10-31 10:14:53 +08:00
new Thread ( " hudson initialization thread " ) {
public void run ( ) {
try {
computeVersion ( context ) ;
try {
2007-11-02 06:14:22 +08:00
context . setAttribute ( APP , new Hudson ( home , context ) ) ;
2007-10-31 10:14:53 +08:00
} catch ( IOException e ) {
throw new Error ( e ) ;
}
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 SafeTimerTask ( ) {
public void doRun ( ) {
2008-06-10 07:11:47 +08:00
User . getUnknown ( ) . getBuilds ( ) ;
2007-10-31 10:14:53 +08:00
}
} , 1000 * 10 ) ;
} catch ( Error e ) {
LOGGER . log ( Level . SEVERE , " Failed to initialize Hudson " , e ) ;
2008-06-06 02:29:38 +08:00
context . setAttribute ( APP , new HudsonFailedToLoad ( e ) ) ;
2007-10-31 10:14:53 +08:00
throw e ;
} catch ( RuntimeException e ) {
LOGGER . log ( Level . SEVERE , " Failed to initialize Hudson " , e ) ;
2008-06-06 02:29:38 +08:00
context . setAttribute ( APP , new HudsonFailedToLoad ( e ) ) ;
2007-10-31 10:14:53 +08:00
throw e ;
2007-09-17 07:46:12 +08:00
}
2007-10-31 10:14:53 +08:00
}
} . start ( ) ;
} catch ( Error e ) {
LOGGER . log ( Level . SEVERE , " Failed to initialize Hudson " , e ) ;
throw e ;
} catch ( RuntimeException e ) {
LOGGER . log ( Level . SEVERE , " Failed to initialize Hudson " , e ) ;
throw e ;
}
2006-11-06 05:16:01 +08:00
}
2007-09-18 18:51:47 +08:00
protected void computeVersion ( ServletContext context ) {
// 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.
}
String ver = props . getProperty ( " version " ) ;
if ( ver = = null ) ver = " ? " ;
Hudson . VERSION = ver ;
context . setAttribute ( " version " , ver ) ;
2007-12-25 06:47:19 +08:00
String verHash = Util . getDigestOf ( ver ) . substring ( 0 , 8 ) ;
2007-09-18 18:51:47 +08:00
if ( ver . equals ( " ? " ) )
Hudson . RESOURCE_PATH = " " ;
else
2007-12-25 06:47:19 +08:00
Hudson . RESOURCE_PATH = " /static/ " + verHash ;
Hudson . VIEW_RESOURCE_PATH = " /resources/ " + verHash ;
}
2007-09-18 18:51:47 +08:00
/ * *
2006-11-06 05:16:01 +08:00
* Installs log handler to monitor all Hudson logs .
* /
private void installLogger ( ) {
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 {
2008-03-14 13:42:23 +08:00
InitialContext iniCtxt = new InitialContext ( ) ;
Context env = ( Context ) iniCtxt . lookup ( " java:comp/env " ) ;
2006-11-06 05:16:01 +08:00
String value = ( String ) env . lookup ( " HUDSON_HOME " ) ;
if ( value ! = null & & value . trim ( ) . length ( ) > 0 )
2007-08-11 00:00:06 +08:00
return new File ( value . trim ( ) ) ;
2008-03-14 13:42:23 +08:00
// look at one more place. See issue #1314
value = ( String ) iniCtxt . lookup ( " HUDSON_HOME " ) ;
if ( value ! = null & & value . trim ( ) . length ( ) > 0 )
return new File ( value . trim ( ) ) ;
2006-11-06 05:16:01 +08:00
} catch ( NamingException e ) {
// ignore
}
// finally check the system property
String sysProp = System . getProperty ( " HUDSON_HOME " ) ;
if ( sysProp ! = null )
2007-08-11 00:00:06 +08:00
return new File ( sysProp . trim ( ) ) ;
2008-01-30 00:35:56 +08:00
// look at the env var next
String env = EnvVars . masterEnvVars . get ( " HUDSON_HOME " ) ;
if ( env ! = null )
return new File ( env . 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 ( ) )
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
2007-08-11 00:00:06 +08:00
return ws ;
2006-11-06 05:16:01 +08:00
}
// if for some reason we can't put it within the webapp, use home directory.
2007-08-11 00:00:06 +08:00
return new File ( new File ( System . getProperty ( " user.home " ) ) , " .hudson " ) ;
2006-11-06 05:16:01 +08:00
}
public void contextDestroyed ( ServletContextEvent event ) {
Hudson instance = Hudson . getInstance ( ) ;
if ( instance ! = null )
instance . cleanUp ( ) ;
2007-04-06 22:20:13 +08:00
// Logger is in the system classloader, so if we don't do this
// the whole web app will never be undepoyed.
Logger . getLogger ( " hudson " ) . removeHandler ( handler ) ;
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
2006-11-06 05:16:01 +08:00
}