Skip to content

Commit

Permalink
[FIXED JENKINS-20609]
Browse files Browse the repository at this point in the history
Implemented the hook
  • Loading branch information
kohsuke committed Nov 16, 2013
1 parent 6b8b266 commit 729d41c
Show file tree
Hide file tree
Showing 18 changed files with 112 additions and 53 deletions.
3 changes: 3 additions & 0 deletions changelog.html
Expand Up @@ -55,6 +55,9 @@
<!-- Record your changes in the trunk here. -->
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image>
<li class=rfe>
Introduced the boot failure hook script that gets executed when Jenkins fails to start.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-20609">issue 20609</a>)
<li class=bug>
Fixed "java.lang.NoClassDefFoundError: JarURLConnection" on OpenJDK
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-20163">issue 20163</a>)
Expand Down
36 changes: 14 additions & 22 deletions core/src/main/java/hudson/WebAppMain.java
Expand Up @@ -26,6 +26,7 @@
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
import com.thoughtworks.xstream.core.JVM;
import hudson.model.Hudson;
import hudson.util.BootFailure;
import jenkins.model.Jenkins;
import hudson.util.HudsonIsLoading;
import hudson.util.IncompatibleServletVersionDetected;
Expand Down Expand Up @@ -82,8 +83,8 @@ public final class WebAppMain implements ServletContextListener {
* Creates the sole instance of {@link jenkins.model.Jenkins} and register it to the {@link ServletContext}.
*/
public void contextInitialized(ServletContextEvent event) {
final ServletContext context = event.getServletContext();
try {
final ServletContext context = event.getServletContext();

// use the current request to determine the language
LocaleProvider.setProvider(new LocaleProvider() {
Expand All @@ -98,8 +99,7 @@ public Locale get() {
jvm = new JVM();
new URLClassLoader(new URL[0],getClass().getClassLoader());
} catch(SecurityException e) {
context.setAttribute(APP,new InsufficientPermissionDetected(e));
return;
throw new InsufficientPermissionDetected(e);
}

try {// remove Sun PKCS11 provider if present. See http://wiki.jenkins-ci.org/display/JENKINS/Solaris+Issue+6276483
Expand All @@ -116,16 +116,12 @@ public Locale get() {
System.out.println("Jenkins home directory: "+home+" found at: "+describedHomeDir.description);

// check that home exists (as mkdirs could have failed silently), otherwise throw a meaningful error
if (! home.exists()) {
context.setAttribute(APP,new NoHomeDir(home));
return;
}
if (!home.exists())
throw new NoHomeDir(home);

// make sure that we are using XStream in the "enhanced" (JVM-specific) mode
if(jvm.bestReflectionProvider().getClass()==PureJavaReflectionProvider.class) {
// nope
context.setAttribute(APP,new IncompatibleVMDetected());
return;
throw new IncompatibleVMDetected(); // nope
}

// JNA is no longer a hard requirement. It's just nice to have. See HUDSON-4820 for more context.
Expand Down Expand Up @@ -163,22 +159,19 @@ public Locale get() {
try {
ServletResponse.class.getMethod("setCharacterEncoding",String.class);
} catch (NoSuchMethodException e) {
context.setAttribute(APP,new IncompatibleServletVersionDetected(ServletResponse.class));
return;
throw new IncompatibleServletVersionDetected(ServletResponse.class);
}

// make sure that we see Ant 1.7
try {
FileSet.class.getMethod("getDirectoryScanner");
} catch (NoSuchMethodException e) {
context.setAttribute(APP,new IncompatibleAntVersionDetected(FileSet.class));
return;
throw new IncompatibleAntVersionDetected(FileSet.class);
}

// make sure AWT is functioning, or else JFreeChart won't even load.
if(ChartUtil.awtProblemCause!=null) {
context.setAttribute(APP,new AWTProblem(ChartUtil.awtProblemCause));
return;
throw new AWTProblem(ChartUtil.awtProblemCause);
}

// some containers (in particular Tomcat) doesn't abort a launch
Expand All @@ -188,8 +181,7 @@ public Locale get() {
File f = File.createTempFile("test", "test");
f.delete();
} catch (IOException e) {
context.setAttribute(APP,new NoTempDir(e));
return;
throw new NoTempDir(e);
}

// Tomcat breaks XSLT with JDK 5.0 and onward. Check if that's the case, and if so,
Expand Down Expand Up @@ -225,12 +217,10 @@ public void run() {
LOGGER.info("Jenkins is fully up and running");
success = true;
} catch (Error e) {
LOGGER.log(Level.SEVERE, "Failed to initialize Jenkins",e);
context.setAttribute(APP,new HudsonFailedToLoad(e));
new HudsonFailedToLoad(e).publish(context);
throw e;
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Failed to initialize Jenkins",e);
context.setAttribute(APP,new HudsonFailedToLoad(e));
new HudsonFailedToLoad(e).publish(context);
} finally {
Jenkins instance = Jenkins.getInstance();
if(!success && instance!=null)
Expand All @@ -239,6 +229,8 @@ public void run() {
}
};
initThread.start();
} catch (BootFailure e) {
e.publish(context);
} catch (Error e) {
LOGGER.log(Level.SEVERE, "Failed to initialize Jenkins",e);
throw e;
Expand Down
7 changes: 6 additions & 1 deletion core/src/main/java/hudson/util/AWTProblem.java
Expand Up @@ -23,13 +23,18 @@
*/
package hudson.util;

import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/**
* @author Kohsuke Kawaguchi
*/
public class AWTProblem extends ErrorObject {
public class AWTProblem extends BootFailure {
@Restricted(NoExternalUse.class) @Deprecated
public final Throwable cause;

public AWTProblem(Throwable cause) {
super(cause);
this.cause = cause;
}
}
Expand Down
36 changes: 36 additions & 0 deletions core/src/main/java/hudson/util/BootFailure.java
@@ -0,0 +1,36 @@
package hudson.util;

import jenkins.util.groovy.GroovyHookScript;
import org.kohsuke.stapler.WebApp;

import javax.servlet.ServletContext;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Indicates a fatal boot problem, among {@link ErrorObject}
*
* @author Kohsuke Kawaguchi
*/
public abstract class BootFailure extends ErrorObject {
protected BootFailure() {
}

protected BootFailure(Throwable cause) {
super(cause);
}

/**
* Exposes this failure to UI and invoke the hook.
*/
public void publish(ServletContext context) {
LOGGER.log(Level.SEVERE, "Failed to initialize Jenkins",this);

WebApp.get(context).setApp(this);
new GroovyHookScript("boot-failure")
.bind("exception",this)
.run();
}

private static final Logger LOGGER = Logger.getLogger(BootFailure.class.getName());
}
14 changes: 13 additions & 1 deletion core/src/main/java/hudson/util/ErrorObject.java
Expand Up @@ -23,6 +23,7 @@
*/
package hudson.util;

import hudson.Functions;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

Expand All @@ -38,7 +39,18 @@
*
* @author Kohsuke Kawaguchi
*/
public abstract class ErrorObject {
public abstract class ErrorObject extends Exception {
protected ErrorObject() {
}

protected ErrorObject(Throwable cause) {
super(cause);
}

public String getStackTraceString() {
return Functions.printThrowable(this);
}

public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
rsp.setStatus(SC_SERVICE_UNAVAILABLE);
req.getView(this,"index.jelly").forward(req,rsp);
Expand Down
13 changes: 6 additions & 7 deletions core/src/main/java/hudson/util/HudsonFailedToLoad.java
Expand Up @@ -23,24 +23,23 @@
*/
package hudson.util;

import hudson.Functions;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/**
* Model object used to display the generic error when Hudson start up fails fatally during initialization.
* Model object used to display the generic error when Jenkins start up fails fatally during initialization.
*
* <p>
* <tt>index.jelly</tt> would display a nice friendly error page.
*
* @author Kohsuke Kawaguchi
*/
public class HudsonFailedToLoad extends ErrorObject {
public class HudsonFailedToLoad extends BootFailure {
@Restricted(NoExternalUse.class) @Deprecated
public final Throwable exception;

public HudsonFailedToLoad(Throwable exception) {
super(exception);
this.exception = exception;
}

public String getStackTrace() {
return Functions.printThrowable(exception);
}
}
Expand Up @@ -37,13 +37,22 @@
*
* @author Kohsuke Kawaguchi
*/
public class IncompatibleAntVersionDetected extends ErrorObject {
public class IncompatibleAntVersionDetected extends BootFailure {
private final Class antClass;

public IncompatibleAntVersionDetected(Class antClass) {
this.antClass = antClass;
}

@Override
public String getMessage() {
try {
return "Incompatible Ant loaded from "+getWhereAntIsLoaded();
} catch (IOException e) {
return "Incompatible Ant loaded";
}
}

public URL getWhereAntIsLoaded() throws IOException {
return Which.jarURL(antClass);
}
Expand Down
Expand Up @@ -37,7 +37,7 @@
*
* @author Kohsuke Kawaguchi
*/
public class IncompatibleServletVersionDetected extends ErrorObject {
public class IncompatibleServletVersionDetected extends BootFailure {
private final Class servletClass;

public IncompatibleServletVersionDetected(Class servletClass) {
Expand Down
3 changes: 1 addition & 2 deletions core/src/main/java/hudson/util/IncompatibleVMDetected.java
Expand Up @@ -34,8 +34,7 @@
*
* @author Kohsuke Kawaguchi
*/
public class IncompatibleVMDetected extends ErrorObject {

public class IncompatibleVMDetected extends BootFailure {
public Map getSystemProperties() {
return System.getProperties();
}
Expand Down
Expand Up @@ -23,7 +23,8 @@
*/
package hudson.util;

import hudson.Functions;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/**
* Model object used to display the error top page if
Expand All @@ -34,14 +35,12 @@
*
* @author Kohsuke Kawaguchi
*/
public class InsufficientPermissionDetected extends ErrorObject {
public class InsufficientPermissionDetected extends BootFailure {
@Restricted(NoExternalUse.class) @Deprecated
public final SecurityException exception;

public InsufficientPermissionDetected(SecurityException e) {
super(e);
this.exception = e;
}

public String getExceptionTrace() {
return Functions.printThrowable(exception);
}
}
7 changes: 6 additions & 1 deletion core/src/main/java/hudson/util/JenkinsReloadFailed.java
@@ -1,14 +1,19 @@
package hudson.util;

import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/**
* Indicates that Jenkins is interrupted during reload.
*
* @author Kohsuke Kawaguchi
*/
public class JenkinsReloadFailed extends ErrorObject {
public class JenkinsReloadFailed extends BootFailure {
@Restricted(NoExternalUse.class) @Deprecated
public final Throwable cause;

public JenkinsReloadFailed(Throwable cause) {
super(cause);
this.cause = cause;
}
}
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/util/NoHomeDir.java
Expand Up @@ -34,7 +34,7 @@
*
* @author Kohsuke Kawaguchi
*/
public class NoHomeDir extends ErrorObject {
public class NoHomeDir extends BootFailure {
public final File home;

public NoHomeDir(File home) {
Expand Down
10 changes: 5 additions & 5 deletions core/src/main/java/hudson/util/NoTempDir.java
Expand Up @@ -24,6 +24,8 @@
package hudson.util;

import hudson.Functions;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

import java.io.IOException;

Expand All @@ -36,17 +38,15 @@
*
* @author Kohsuke Kawaguchi
*/
public class NoTempDir extends ErrorObject {
public class NoTempDir extends BootFailure {
@Restricted(NoExternalUse.class) @Deprecated
public final IOException exception;

public NoTempDir(IOException exception) {
super(exception);
this.exception = exception;
}

public String getStackTrace() {
return Functions.printThrowable(exception);
}

public String getTempDir() {
return System.getProperty("java.io.tmpdir");
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/jenkins/model/Jenkins.java
Expand Up @@ -3086,7 +3086,7 @@ public void run() {
reload();
} catch (Exception e) {
LOGGER.log(SEVERE,"Failed to reload Jenkins config",e);
WebApp.get(servletContext).setApp(new JenkinsReloadFailed(e));
new JenkinsReloadFailed(e).publish(servletContext);
}
}
}.start();
Expand Down
Expand Up @@ -29,7 +29,7 @@ THE SOFTWARE.
<l:side-panel />
<l:main-panel>
<h1><img src="${imagesURL}/48x48/error.png" alt="[!]" height="48" width="48"/><st:nbsp/>${%Error}</h1>
<pre>${it.stackTrace}</pre>
<pre>${it.stackTraceString}</pre>
</l:main-panel>
</l:layout>
</j:jelly>
Expand Up @@ -35,7 +35,7 @@ THE SOFTWARE.
<p>
${%errorMessage.2}
</p>
<pre>${it.exceptionTrace}</pre>
<pre>${it.stackTraceString}</pre>
</l:main-panel>
</l:layout>
</j:jelly>

0 comments on commit 729d41c

Please sign in to comment.