You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/03/04 21:58:38 UTC

git commit: ISIS-320: better error handling if exception in PageAbstract...

Updated Branches:
  refs/heads/master ed3d01fa2 -> db4d727d9


ISIS-320: better error handling if exception in PageAbstract...

... previously was just being swallowed and sent back to the sign-in page.
Now, the exception is caught and is rendered on the page, so there is at least some
clue as to what the problem might have been.

Somewhat unrelated, have also added a new ExceptionRecognizer for handling refs to
objects that have been deleted.


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/db4d727d
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/db4d727d
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/db4d727d

Branch: refs/heads/master
Commit: db4d727d9053719f258c20eec2fb1c372e877c5e
Parents: ed3d01f
Author: Dan Haywood <da...@apache.org>
Authored: Mon Mar 4 20:31:26 2013 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Mon Mar 4 20:31:26 2013 +0000

----------------------------------------------------------------------
 ...eptionRecognizerCompositeForJdoObjectStore.java |    1 +
 ...ionRecognizerForJDOObjectNotFoundException.java |   31 +++++
 .../wicket/viewer/IsisWicketApplication.java       |   42 +++----
 .../integration/wicket/WebRequestCycleForIsis.java |   80 ++++++++----
 .../viewer/wicket/ui/errors/ExceptionModel.java    |   83 ++++++++++++
 .../wicket/ui/errors/ExceptionStackTracePanel.css  |  103 +++++++++++++++
 .../wicket/ui/errors/ExceptionStackTracePanel.html |   54 ++++++++
 .../wicket/ui/errors/ExceptionStackTracePanel.java |   65 +++++++++
 .../isis/viewer/wicket/ui/errors/div-toggle.js     |    7 +
 .../isis/viewer/wicket/ui/pages/PageAbstract.java  |   49 ++++++-
 .../viewer/wicket/ui/pages/error/ErrorPage.java    |   17 +--
 .../wicket/ui/pages/error/ExceptionModel.java      |   92 -------------
 .../ui/pages/error/ExceptionStackTracePanel.css    |  103 ---------------
 .../ui/pages/error/ExceptionStackTracePanel.html   |   58 --------
 .../ui/pages/error/ExceptionStackTracePanel.java   |   83 ------------
 .../viewer/wicket/ui/pages/error/div-toggle.js     |    7 -
 .../wicket/ui/pages/login/WicketSignInPage.css     |    4 +
 .../wicket/ui/pages/login/WicketSignInPage.html    |    1 +
 .../wicket/ui/pages/login/WicketSignInPage.java    |   46 ++++++-
 .../dom/src/main/java/dom/todo/ToDoItems.java      |   17 ++-
 .../main/java/fixture/todo/ToDoItemsFixture.java   |    3 +-
 21 files changed, 524 insertions(+), 422 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
index ed88c30..c98b097 100644
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
@@ -37,6 +37,7 @@ public class ExceptionRecognizerCompositeForJdoObjectStore extends ExceptionReco
     public ExceptionRecognizerCompositeForJdoObjectStore() {
         // most specific ones first
         add(new ExceptionRecognizerForSQLIntegrityConstraintViolationException());
+        add(new ExceptionRecognizerForJDOObjectNotFoundException());
         add(new ExceptionRecognizerForJDODataStoreException());
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDOObjectNotFoundException.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDOObjectNotFoundException.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDOObjectNotFoundException.java
new file mode 100644
index 0000000..c80a30a
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDOObjectNotFoundException.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.objectstore.jdo.applib.service.exceprecog;
+
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerForType;
+
+public class ExceptionRecognizerForJDOObjectNotFoundException extends ExceptionRecognizerForType {
+
+    public ExceptionRecognizerForJDOObjectNotFoundException() {
+        super(javax.jdo.JDOObjectNotFoundException.class, 
+            prefix("Unable to load object.  " +
+            	   "Has it been deleted by someone else?"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
index f62e71d..3f750a3 100644
--- a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
+++ b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
@@ -24,35 +24,12 @@ import java.util.ServiceLoader;
 
 import javax.servlet.ServletContext;
 
-import com.google.inject.Guice;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Module;
-
-import net.sf.cglib.transform.impl.AddInitTransformer;
-
-import org.apache.log4j.Logger;
-import org.apache.wicket.Application;
-import org.apache.wicket.ConverterLocator;
-import org.apache.wicket.IConverterLocator;
-import org.apache.wicket.Page;
-import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;
-import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
-import org.apache.wicket.guice.GuiceComponentInjector;
-import org.apache.wicket.markup.html.WebPage;
-import org.apache.wicket.request.Request;
-import org.apache.wicket.request.Response;
-import org.apache.wicket.settings.IRequestCycleSettings.RenderStrategy;
-
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
 import org.apache.isis.core.commons.authentication.AuthenticationSessionProviderAware;
-import org.apache.isis.core.commons.config.ConfigurationConstants;
 import org.apache.isis.core.commons.config.IsisConfigurationBuilder;
 import org.apache.isis.core.commons.config.IsisConfigurationBuilderPrimer;
 import org.apache.isis.core.commons.config.IsisConfigurationBuilderResourceStreams;
-import org.apache.isis.core.commons.config.NotFoundPolicy;
-import org.apache.isis.core.commons.resource.ResourceStreamSource;
 import org.apache.isis.core.commons.resource.ResourceStreamSourceComposite;
 import org.apache.isis.core.commons.resource.ResourceStreamSourceContextLoaderClassPath;
 import org.apache.isis.core.commons.resource.ResourceStreamSourceCurrentClassClassPath;
@@ -79,13 +56,29 @@ import org.apache.isis.viewer.wicket.ui.pages.BookmarkedPagesModelProvider;
 import org.apache.isis.viewer.wicket.ui.pages.PageClassList;
 import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistry;
 import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistryAccessor;
-import org.apache.isis.viewer.wicket.viewer.integration.isis.IsisContextForWicket;
 import org.apache.isis.viewer.wicket.viewer.integration.isis.WicketServer;
 import org.apache.isis.viewer.wicket.viewer.integration.isis.WicketServerPrototype;
 import org.apache.isis.viewer.wicket.viewer.integration.wicket.AuthenticatedWebSessionForIsis;
 import org.apache.isis.viewer.wicket.viewer.integration.wicket.ConverterForObjectAdapter;
 import org.apache.isis.viewer.wicket.viewer.integration.wicket.ConverterForObjectAdapterMemento;
 import org.apache.isis.viewer.wicket.viewer.integration.wicket.WebRequestCycleForIsis;
+import org.apache.log4j.Logger;
+import org.apache.wicket.Application;
+import org.apache.wicket.ConverterLocator;
+import org.apache.wicket.IConverterLocator;
+import org.apache.wicket.Page;
+import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;
+import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
+import org.apache.wicket.guice.GuiceComponentInjector;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.request.Request;
+import org.apache.wicket.request.Response;
+import org.apache.wicket.settings.IRequestCycleSettings.RenderStrategy;
+
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Module;
 
 /**
  * Main application, subclassing the Wicket {@link Application} and
@@ -214,7 +207,6 @@ public class IsisWicketApplication extends AuthenticatedWebApplication implement
         this.bookmarkedPagesModel = new BookmarkedPagesModel();
 
         initWicketComponentInjection(injector);
-        
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
index 1da58cc..19a30a8 100644
--- a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
+++ b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
@@ -33,15 +33,20 @@ import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
 import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
 import org.apache.isis.core.runtime.system.transaction.MessageBroker;
 import org.apache.isis.core.runtime.system.transaction.MessageBrokerDefault;
+import org.apache.isis.viewer.wicket.ui.errors.ExceptionModel;
 import org.apache.isis.viewer.wicket.ui.pages.error.ErrorPage;
+import org.apache.isis.viewer.wicket.ui.pages.login.WicketSignInPage;
 import org.apache.log4j.Logger;
 import org.apache.wicket.RestartResponseException;
 import org.apache.wicket.Session;
+import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
 import org.apache.wicket.core.request.handler.PageProvider;
 import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
 import org.apache.wicket.core.request.handler.RenderPageRequestHandler.RedirectPolicy;
+import org.apache.wicket.protocol.http.PageExpiredException;
 import org.apache.wicket.protocol.http.WebSession;
 import org.apache.wicket.request.IRequestHandler;
+import org.apache.wicket.request.component.IRequestablePage;
 import org.apache.wicket.request.cycle.AbstractRequestCycleListener;
 import org.apache.wicket.request.cycle.RequestCycle;
 
@@ -123,13 +128,6 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
 
     @Override
     public IRequestHandler onException(RequestCycle cycle, Exception ex) {
-        // previously we had a handler in here.  However, it seems to be sufficient to just
-        // use the exception handling in the onRequestHandlerExecuted(...) callback
-        // which fires before the onEndRequest(...) callback.
-        //return super.onException(cycle, ex);
-        
-        // hmm, maybe not.  making in edit page do a flush seems to belie that.
-        
         return new RenderPageRequestHandler(errorPageProviderFor(ex), RedirectPolicy.ALWAYS_REDIRECT);
     }
 
@@ -137,43 +135,73 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
         return new PageProvider(errorPageFor(ex));
     }
 
-    protected ErrorPage errorPageFor(Exception ex) {
-        List<ExceptionRecognizer> exceptionRecognizers;
-        try {
+    protected IRequestablePage errorPageFor(Exception ex) {
+        List<ExceptionRecognizer> exceptionRecognizers = Collections.emptyList();
+        if(inIsisSession()) {
             exceptionRecognizers = getServicesInjector().lookupServices(ExceptionRecognizer.class);
-        } catch(Exception ex2) {
-            LOG.warn("Unable to obtain exceptionRecognizers (no session?)");
-            exceptionRecognizers = Collections.emptyList();
+        } else {
+            LOG.warn("Unable to obtain exceptionRecognizers (no session), will be treated as unrecognized exception");
+        }
+        String recognizedMessageIfAny = new ExceptionRecognizerComposite(exceptionRecognizers).recognize(ex);
+        ExceptionModel exceptionModel = ExceptionModel.create(recognizedMessageIfAny, ex);
+        
+        if( isSignedIn()) {
+            return new ErrorPage(exceptionModel);
+        } else {
+            return new WicketSignInPage(null, exceptionModel);
+        }
+    }
+
+    /**
+     * TODO: this is very hacky...
+     * 
+     * <p>
+     * Matters should improve once ISIS-299 gets implemented...
+     */
+    protected boolean isSignedIn() {
+        if(!inIsisSession()) {
+            return false;
         }
-        String message = new ExceptionRecognizerComposite(exceptionRecognizers).recognize(ex);
-        final ErrorPage page = message != null ? new ErrorPage(message, ex) : new ErrorPage(ex);
-        return page;
+        if(getAuthenticationSession() == null) {
+            return false;
+        }
+        return getWicketAuthenticationSession().isSignedIn();
     }
 
 
+
     
     ///////////////////////////////////////////////////////////////
-    // Dependencies (from context)
+    // Dependencies (from isis' context)
     ///////////////////////////////////////////////////////////////
     
-    /**
-     * Factored out so can be overridden in testing.
-     */
     protected ServicesInjector getServicesInjector() {
         return IsisContext.getPersistenceSession().getServicesInjector();
     }
     
-    /**
-     * Factored out so can be overridden in testing.
-     */
     protected IsisContext getIsisContext() {
         return IsisContext.getInstance();
     }
 
-    /**
-     * Factored out so can be overridden in testing.
-     */
     protected IsisTransactionManager getTransactionManager() {
         return IsisContext.getTransactionManager();
     }
+
+    protected boolean inIsisSession() {
+        return IsisContext.inSession();
+    }
+
+    protected AuthenticationSession getAuthenticationSession() {
+        return IsisContext.getAuthenticationSession();
+    }
+
+    ///////////////////////////////////////////////////////////////
+    // Dependencies (from wicket)
+    ///////////////////////////////////////////////////////////////
+
+    
+    protected AuthenticatedWebSession getWicketAuthenticationSession() {
+        return AuthenticatedWebSession.get();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionModel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionModel.java
new file mode 100644
index 0000000..c587834
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionModel.java
@@ -0,0 +1,83 @@
+package org.apache.isis.viewer.wicket.ui.errors;
+
+import java.util.List;
+
+import org.apache.isis.viewer.wicket.model.models.ModelAbstract;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+
+public class ExceptionModel extends ModelAbstract<Exception> {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String MAIN_MESSAGE_IF_NOT_RECOGNIZED = "Sorry, an unexpected error occurred.";
+    
+    private Exception exception;
+    private boolean recognized;
+
+    private final String mainMessage;
+    
+
+    public static ExceptionModel create(String recognizedMessageIfAny, Exception ex) {
+        return recognizedMessageIfAny != null
+                ? new ExceptionModel(recognizedMessageIfAny, true, ex)
+                : new ExceptionModel(MAIN_MESSAGE_IF_NOT_RECOGNIZED, false, ex);
+    }
+
+    private ExceptionModel(String mainMessage, boolean recognized, Exception ex) {
+        this.mainMessage = mainMessage;
+        this.recognized = recognized;
+        this.exception = ex;
+    }
+
+    @Override
+    protected Exception load() {
+        return exception;
+    }
+
+    @Override
+    public void setObject(Exception ex) {
+        if(ex == null) {
+            return;
+        }
+        this.exception = ex;
+    }
+
+    public boolean isRecognized() {
+        return recognized;
+    }
+
+    public String getMainMessage() {
+        return mainMessage;
+    }
+    
+    
+    public List<StackTraceDetail> getStackTrace() {
+        return asStackTrace(exception);
+    }
+
+    
+    private static List<StackTraceDetail> asStackTrace(Throwable ex) {
+        List<StackTraceDetail> stackTrace = Lists.newArrayList();
+        List<Throwable> causalChain = Throwables.getCausalChain(ex);
+        for(Throwable cause: causalChain) {
+            stackTrace.add(StackTraceDetail.exceptionClassName(cause));
+            stackTrace.add(StackTraceDetail.exceptionMessage(cause));
+            addStackTraceElements(cause, stackTrace);
+            cause = cause.getCause();
+        }
+        return stackTrace;
+    }
+
+    private static void addStackTraceElements(Throwable ex, List<StackTraceDetail> stackTrace) {
+        for (StackTraceElement el : ex.getStackTrace()) {
+            stackTrace.add(StackTraceDetail.element(el));
+        }
+    }
+
+
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.css
new file mode 100644
index 0000000..e5b6f21
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.css
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+ .exceptionStackTracePanel .errorInfo {
+    margin-left: 50px;
+    margin-right: 50px;
+    padding-top: 50px;
+}
+
+
+.exceptionStackTracePanel .mainMessage {
+    background:#FFFFFF;
+    border-radius:4px;
+    -moz-border-radius:4px;
+    -webkit-border-radius:4px;
+    padding: 15px;
+    display: block;
+    text-align:center;
+    font-size:1.2em;
+}
+
+ .exceptionStackTracePanel .errorDetail {
+    margin-top: 30px; 
+}
+
+.exceptionStackTracePanel .heading {
+    border-radius:4px;
+    -moz-border-radius:4px;
+    -webkit-border-radius:4px;
+    background-color:#F0EFEA;
+
+    display:block;
+    font-style:normal !important;
+
+    padding:1px 6px 1px 6px;
+}
+
+.exceptionStackTracePanel .heading span {
+    display:block;
+    font-style:normal !important;
+    padding:3px 3px 3px 3px;
+    font-size: 0.8em;
+    text-transform:uppercase;
+    font-weight:bold;
+}
+
+.exceptionStackTracePanel .heading:hover {
+    background-color:#FFFFFF;
+    cursor: pointer;
+}
+
+.exceptionStackTracePanel h3 {
+    font-size: larger;
+}
+
+.exceptionStackTracePanel .exceptionMessage {
+    margin-top: 30px; 
+}
+
+.exceptionStackTracePanel .exceptionStackTrace .caused_by_label {
+    margin-top: 30px;
+    font-style:normal !important;
+    font-size: 0.8em;
+    text-transform:uppercase;
+    font-weight:bold;
+    color: #46423C;
+}
+
+.exceptionStackTracePanel .exceptionStackTrace .exception_class_name {
+    margin-top: 15px;
+    font-size: 1.2em;
+    font-weight:bold;
+    color: #46423C;
+}
+
+.exceptionStackTracePanel .exceptionStackTrace .exception_message {
+    margin-top: 10px;
+    margin-bottom: 10px;
+    font-style: italic;
+    font-size: 1.0em;
+    color: #00477F;
+}
+
+.exceptionStackTracePanel .exceptionStackTrace .stacktrace_element{
+    margin-left: 30px;
+}
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.html
new file mode 100644
index 0000000..4d81b36
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.html
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+         http://www.apache.org/licenses/LICENSE-2.0
+         
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml"  
+      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"  
+      xml:lang="en"  
+      lang="en">
+    <head>
+        <wicket:link>
+            <link href="ExceptionStackTracePanel.css" rel="stylesheet" type="text/css"/>
+        </wicket:link>
+    </head>
+    <body>
+        <wicket:panel>
+            <div class="exceptionStackTracePanel">
+                <div class="errorInfo clear">
+                    <span wicket:id="mainMessage" class="mainMessage">[main message text]</span>
+                    <div class="errorDetail" wicket:id="exceptionDetail">
+                        <div class="heading"><span>Show detail</span></div>
+                        <div class="content">
+                            <div class="exceptionStackTrace">
+                                <h3>Stack trace:</h3>
+                                <ul>
+                                    <li wicket:id="stackTraceElement">
+                                        <span wicket:id="stackTraceElementLine">[stack trace element line]</span>
+                                    </li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </wicket:panel>
+    </body>
+</html>
+
+

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java
new file mode 100644
index 0000000..9409951
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.errors;
+
+import org.apache.isis.viewer.wicket.ui.panels.PanelUtil;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+
+public class ExceptionStackTracePanel extends Panel {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String ID_MAIN_MESSAGE = "mainMessage";
+
+    private static final String ID_EXCEPTION_DETAIL = "exceptionDetail";
+    private static final String ID_EXCEPTION_MESSAGE = "exceptionMessage";
+
+    private static final String ID_STACK_TRACE_ELEMENT = "stackTraceElement";
+    private static final String ID_LINE = "stackTraceElementLine";
+
+    private static final JavaScriptResourceReference DIV_TOGGLE_JS = new JavaScriptResourceReference(ExceptionStackTracePanel.class, "div-toggle.js");
+
+    public ExceptionStackTracePanel(String id, ExceptionModel exceptionModel) {
+        super(id, exceptionModel);
+        
+        add(new Label(ID_MAIN_MESSAGE, exceptionModel.getMainMessage()).setEscapeModelStrings(false));
+
+        MarkupContainer container = new WebMarkupContainer(ID_EXCEPTION_DETAIL) {
+            private static final long serialVersionUID = 1L;
+            @Override
+            public void renderHead(IHeaderResponse response) {
+                response.render(JavaScriptReferenceHeaderItem.forReference(DIV_TOGGLE_JS));
+            }
+        };
+        container.add(new StackTraceListView(ID_STACK_TRACE_ELEMENT, ExceptionStackTracePanel.ID_LINE, exceptionModel.getStackTrace()));
+        add(container);
+    }
+
+    public void renderHead(final IHeaderResponse response) {
+        PanelUtil.renderHead(response, this.getClass());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/div-toggle.js
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/div-toggle.js b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/div-toggle.js
new file mode 100644
index 0000000..44fa4bb
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/div-toggle.js
@@ -0,0 +1,7 @@
+jQuery(document).ready(function() {
+  jQuery(".exceptionStackTracePanel .content").hide();
+  jQuery(".exceptionStackTracePanel .heading").click(function()
+  {
+    jQuery(this).next(".exceptionStackTracePanel .content").slideToggle(500);
+  });
+});

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
index 78176de..5019930 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
@@ -24,6 +24,9 @@ import java.util.Collections;
 import java.util.List;
 
 import org.apache.commons.lang.StringUtils;
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerComposite;
+import org.apache.isis.applib.services.exceprecog.RecognizedException;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.authentication.MessageBroker;
 import org.apache.isis.core.metamodel.services.ServicesInjectorSpi;
@@ -40,12 +43,18 @@ import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistryAccessor;
 import org.apache.isis.viewer.wicket.ui.components.actions.ActionPanel;
+import org.apache.isis.viewer.wicket.ui.errors.ExceptionModel;
 import org.apache.isis.viewer.wicket.ui.errors.JGrowlUtil;
 import org.apache.isis.viewer.wicket.ui.pages.about.AboutPage;
+import org.apache.isis.viewer.wicket.ui.pages.error.ErrorPage;
 import org.apache.isis.viewer.wicket.ui.pages.login.WicketSignInPage;
 import org.apache.log4j.Logger;
 import org.apache.wicket.Application;
 import org.apache.wicket.RestartResponseAtInterceptPageException;
+import org.apache.wicket.RestartResponseException;
+import org.apache.wicket.Session;
+import org.apache.wicket.core.request.handler.PageProvider;
+import org.apache.wicket.core.request.handler.RenderPageRequestHandler.RedirectPolicy;
 import org.apache.wicket.markup.head.CssReferenceHeaderItem;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.JavaScriptHeaderItem;
@@ -64,8 +73,7 @@ import com.google.inject.Inject;
 import com.google.inject.name.Named;
 
 /**
- * Convenience adapter for {@link WebPage}s built up using {@link ComponentType}
- * s.
+ * Convenience adapter for {@link WebPage}s built up using {@link ComponentType}s.
  */
 public abstract class PageAbstract extends WebPage {
 
@@ -85,7 +93,13 @@ public abstract class PageAbstract extends WebPage {
     public static final String ID_ABOUT_LINK = "aboutLink";
 
     private static final JavaScriptResourceReference JQUERY_JGROWL_JS = new JavaScriptResourceReference(PageAbstract.class, "jquery.jgrowl.js");
-    
+
+    /**
+     * This is a bit hacky, but best way I've found to pass an exception over to the WicketSignInPage
+     * if there is a problem rendering this page.
+     */
+    public static ThreadLocal<ExceptionModel> EXCEPTION = new ThreadLocal<ExceptionModel>(); 
+
     private final List<ComponentType> childComponentIds;
     private final PageParameters pageParameters;
     
@@ -121,14 +135,39 @@ public abstract class PageAbstract extends WebPage {
             addLogoutLink();
             addAboutLink();
             add(new Label(ID_PAGE_TITLE, PageParameterNames.PAGE_TITLE.getStringFrom(pageParameters, applicationName)));
-        } catch(RuntimeException ex) {
             
+        } catch(RuntimeException ex) {
+
             LOG.error("Failed to construct page, going back to sign in page", ex);
-            // hack for IE
+            
+            // REVIEW: similar code in WebRequestCycleForIsis
+            final  List<ExceptionRecognizer> exceptionRecognizers = getServicesInjector().lookupServices(ExceptionRecognizer.class);
+            final String recognizedMessageIfAny = new ExceptionRecognizerComposite(exceptionRecognizers).recognize(ex);
+            final ExceptionModel exceptionModel = ExceptionModel.create(recognizedMessageIfAny, ex);
+
             getSession().invalidate();
+            getSession().clear();
+            
+            // for the WicketSignInPage to render
+            EXCEPTION.set(exceptionModel);
+
             throw new RestartResponseAtInterceptPageException(WicketSignInPage.class);
         }
     }
+    
+
+
+    protected ExceptionModel recognizeException(Exception ex) {
+        List<ExceptionRecognizer> exceptionRecognizers;
+        try {
+            exceptionRecognizers = getServicesInjector().lookupServices(ExceptionRecognizer.class);
+        } catch(Exception ex2) {
+            LOG.warn("Unable to obtain exceptionRecognizers (no session?)");
+            exceptionRecognizers = Collections.emptyList();
+        }
+        final String recognizedMessageIfAny = new ExceptionRecognizerComposite(exceptionRecognizers).recognize(ex);
+        return ExceptionModel.create(recognizedMessageIfAny, ex);
+    }
 
     
     @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.java
index b224156..3a08492 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.viewer.wicket.ui.pages.error;
 
+import org.apache.isis.viewer.wicket.ui.errors.ExceptionModel;
+import org.apache.isis.viewer.wicket.ui.errors.ExceptionStackTracePanel;
 import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
 import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
@@ -33,21 +35,8 @@ public class ErrorPage extends PageAbstract {
 
     private static final String ID_EXCEPTION_STACK_TRACE = "exceptionStackTrace";
 
-    /**
-     * For recognized messages.
-     */
-    public ErrorPage(String message, Exception ex) {
-        this(ExceptionModel.recognized(message, ex));
-    }
-
-    /**
-     * For non-recognized messages.
-     */
-    public ErrorPage(Exception ex) {
-        this(ExceptionModel.notRecognized(ex));
-    }
 
-    private ErrorPage(ExceptionModel exceptionModel) {
+    public ErrorPage(ExceptionModel exceptionModel) {
         super(new PageParameters());
         
         addBookmarkedPages();

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionModel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionModel.java
deleted file mode 100644
index 27221a9..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionModel.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package org.apache.isis.viewer.wicket.ui.pages.error;
-
-import java.util.List;
-
-import org.apache.isis.viewer.wicket.model.models.ModelAbstract;
-import org.apache.isis.viewer.wicket.ui.errors.StackTraceDetail;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.Lists;
-
-public class ExceptionModel extends ModelAbstract<Exception> {
-
-    private static final long serialVersionUID = 1L;
-
-    private static final String MAIN_MESSAGE_IF_NOT_RECOGNIZED = "Sorry, an unexpected error occurred.";
-    
-    private Exception exception;
-    private boolean recognized;
-
-    private final String mainMessage;
-
-    private final String exceptionMessage;
-    
-
-    public static ExceptionModel recognized(String message, Exception ex) {
-        return new ExceptionModel(message, null, ex);
-    }
-
-    public static ExceptionModel notRecognized(Exception ex) {
-        return new ExceptionModel(MAIN_MESSAGE_IF_NOT_RECOGNIZED, ex.getMessage(), ex);
-    }
-
-    private ExceptionModel(String mainMessage, String exceptionMessage, Exception ex) {
-        this.mainMessage = mainMessage;
-        this.exceptionMessage = exceptionMessage;
-        this.recognized = (exceptionMessage == null);
-        this.exception = ex;
-    }
-
-    @Override
-    protected Exception load() {
-        return exception;
-    }
-
-    @Override
-    public void setObject(Exception ex) {
-        if(ex == null) {
-            return;
-        }
-        this.exception = ex;
-    }
-
-    public boolean isRecognized() {
-        return recognized;
-    }
-
-    public String getMainMessage() {
-        return mainMessage;
-    }
-    
-    public String getExceptionMessage() {
-        return exceptionMessage;
-    }
-    
-    public List<StackTraceDetail> getStackTrace() {
-        return asStackTrace(exception);
-    }
-
-    
-    private static List<StackTraceDetail> asStackTrace(Throwable ex) {
-        List<StackTraceDetail> stackTrace = Lists.newArrayList();
-        List<Throwable> causalChain = Throwables.getCausalChain(ex);
-        for(Throwable cause: causalChain) {
-            stackTrace.add(StackTraceDetail.exceptionClassName(cause));
-            stackTrace.add(StackTraceDetail.exceptionMessage(cause));
-            addStackTraceElements(cause, stackTrace);
-            cause = cause.getCause();
-        }
-        return stackTrace;
-    }
-
-    private static void addStackTraceElements(Throwable ex, List<StackTraceDetail> stackTrace) {
-        for (StackTraceElement el : ex.getStackTrace()) {
-            stackTrace.add(StackTraceDetail.element(el));
-        }
-    }
-
-
-
-
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.css
deleted file mode 100644
index e5b6f21..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.css
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
- .exceptionStackTracePanel .errorInfo {
-    margin-left: 50px;
-    margin-right: 50px;
-    padding-top: 50px;
-}
-
-
-.exceptionStackTracePanel .mainMessage {
-    background:#FFFFFF;
-    border-radius:4px;
-    -moz-border-radius:4px;
-    -webkit-border-radius:4px;
-    padding: 15px;
-    display: block;
-    text-align:center;
-    font-size:1.2em;
-}
-
- .exceptionStackTracePanel .errorDetail {
-    margin-top: 30px; 
-}
-
-.exceptionStackTracePanel .heading {
-    border-radius:4px;
-    -moz-border-radius:4px;
-    -webkit-border-radius:4px;
-    background-color:#F0EFEA;
-
-    display:block;
-    font-style:normal !important;
-
-    padding:1px 6px 1px 6px;
-}
-
-.exceptionStackTracePanel .heading span {
-    display:block;
-    font-style:normal !important;
-    padding:3px 3px 3px 3px;
-    font-size: 0.8em;
-    text-transform:uppercase;
-    font-weight:bold;
-}
-
-.exceptionStackTracePanel .heading:hover {
-    background-color:#FFFFFF;
-    cursor: pointer;
-}
-
-.exceptionStackTracePanel h3 {
-    font-size: larger;
-}
-
-.exceptionStackTracePanel .exceptionMessage {
-    margin-top: 30px; 
-}
-
-.exceptionStackTracePanel .exceptionStackTrace .caused_by_label {
-    margin-top: 30px;
-    font-style:normal !important;
-    font-size: 0.8em;
-    text-transform:uppercase;
-    font-weight:bold;
-    color: #46423C;
-}
-
-.exceptionStackTracePanel .exceptionStackTrace .exception_class_name {
-    margin-top: 15px;
-    font-size: 1.2em;
-    font-weight:bold;
-    color: #46423C;
-}
-
-.exceptionStackTracePanel .exceptionStackTrace .exception_message {
-    margin-top: 10px;
-    margin-bottom: 10px;
-    font-style: italic;
-    font-size: 1.0em;
-    color: #00477F;
-}
-
-.exceptionStackTracePanel .exceptionStackTrace .stacktrace_element{
-    margin-left: 30px;
-}
- 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.html
deleted file mode 100644
index cfd2026..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-  
-         http://www.apache.org/licenses/LICENSE-2.0
-         
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<html xmlns="http://www.w3.org/1999/xhtml"  
-      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"  
-      xml:lang="en"  
-      lang="en">
-    <head>
-        <wicket:link>
-            <link href="ExceptionStackTracePanel.css" rel="stylesheet" type="text/css"/>
-        </wicket:link>
-    </head>
-    <body>
-        <wicket:panel>
-            <div class="exceptionStackTracePanel">
-                <div class="errorInfo clear">
-                    <span wicket:id="mainMessage" class="mainMessage">[main message text]</span>
-                    <div class="errorDetail" wicket:id="exceptionDetail">
-                        <div class="heading"><span>Show detail</span></div>
-                        <div class="content">
-                            <div class="exceptionMessage">
-                                <h3>Message:</h3>
-                                <p wicket:id="exceptionMessage">[exception message]</p>
-                            </div>
-                            <div class="exceptionStackTrace">
-                                <h3>Stack trace:</h3>
-                                <ul>
-                                    <li wicket:id="stackTraceElement">
-                                        <span wicket:id="stackTraceElementLine">[stack trace element line]</span>
-                                    </li>
-                                </ul>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </wicket:panel>
-    </body>
-</html>
-
-

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.java
deleted file mode 100644
index b115288..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ExceptionStackTracePanel.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.viewer.wicket.ui.pages.error;
-
-import org.apache.isis.viewer.wicket.ui.errors.StackTraceListView;
-import org.apache.isis.viewer.wicket.ui.panels.PanelUtil;
-import org.apache.wicket.MarkupContainer;
-import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;
-import org.apache.wicket.markup.html.WebMarkupContainer;
-import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.request.resource.JavaScriptResourceReference;
-
-import com.google.common.base.Strings;
-
-public class ExceptionStackTracePanel extends Panel {
-
-    private static final long serialVersionUID = 1L;
-
-    private static final String ID_MAIN_MESSAGE = "mainMessage";
-
-    private static final String ID_EXCEPTION_DETAIL = "exceptionDetail";
-    private static final String ID_EXCEPTION_MESSAGE = "exceptionMessage";
-
-    private static final String ID_STACK_TRACE_ELEMENT = "stackTraceElement";
-    private static final String ID_LINE = "stackTraceElementLine";
-
-    private static final JavaScriptResourceReference DIV_TOGGLE_JS = new JavaScriptResourceReference(ExceptionStackTracePanel.class, "div-toggle.js");
-
-    /**
-     * For recognized messages.
-     */
-    public ExceptionStackTracePanel(String id, String message, Exception ex) {
-        this(id, ExceptionModel.recognized(message, ex));
-    }
-
-    /**
-     * For non-recognized messages.
-     */
-    public ExceptionStackTracePanel(String id, Exception ex) {
-        this(id, ExceptionModel.notRecognized(ex));
-    }
-
-    public ExceptionStackTracePanel(String id, ExceptionModel exceptionModel) {
-        super(id, exceptionModel);
-        
-        add(new Label(ID_MAIN_MESSAGE, exceptionModel.getMainMessage()).setEscapeModelStrings(false));
-
-        MarkupContainer container = new WebMarkupContainer(ID_EXCEPTION_DETAIL) {
-            private static final long serialVersionUID = 1L;
-            @Override
-            public void renderHead(IHeaderResponse response) {
-                response.render(JavaScriptReferenceHeaderItem.forReference(DIV_TOGGLE_JS));
-            }
-        };
-        container.add(new Label(ID_EXCEPTION_MESSAGE, Strings.nullToEmpty(exceptionModel.getExceptionMessage())).setVisible(exceptionModel.isRecognized()));
-        container.add(new StackTraceListView(ID_STACK_TRACE_ELEMENT, ExceptionStackTracePanel.ID_LINE, exceptionModel.getStackTrace()));
-        add(container);
-    }
-
-    public void renderHead(final IHeaderResponse response) {
-        PanelUtil.renderHead(response, this.getClass());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/div-toggle.js
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/div-toggle.js b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/div-toggle.js
deleted file mode 100644
index 7dd3f38..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/div-toggle.js
+++ /dev/null
@@ -1,7 +0,0 @@
-jQuery(document).ready(function() {
-  jQuery(".errorPage .content").hide();
-  jQuery(".errorPage .heading").click(function()
-  {
-    jQuery(this).next(".errorPage .content").slideToggle(500);
-  });
-});

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.css
index fee22a7..1e2598a 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.css
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.css
@@ -94,4 +94,8 @@
 
 .loginPanel table tr td {
 	color:#46423C;
+}
+
+.wicketSignInPanel .mainMessage {
+	margin-top: 550px;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.html
index a9be742..0ddb1d5 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.html
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.html
@@ -42,6 +42,7 @@
 		    	<h2>Member Login</h2>
 		    	<span wicket:id="signInPanel"/>
 		    </div>
+            <div wicket:id="exceptionStackTrace" class="exceptionStackTrace"/>
 	    </div>
 	</body>
 </html>

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.java
index 423d27c..5753016 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/WicketSignInPage.java
@@ -19,17 +19,32 @@
 
 package org.apache.isis.viewer.wicket.ui.pages.login;
 
+import java.io.Serializable;
+
 import com.google.inject.Inject;
 import com.google.inject.name.Named;
 
+import org.apache.wicket.Application;
+import org.apache.wicket.Session;
 import org.apache.wicket.authroles.authentication.pages.SignInPage;
 import org.apache.wicket.markup.head.CssReferenceHeaderItem;
 import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
 import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.head.PriorityHeaderItem;
+import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 
+import org.apache.commons.lang.StringUtils;
+import org.apache.isis.core.commons.authentication.MessageBroker;
+import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.viewer.wicket.model.mementos.PageParameterNames;
+import org.apache.isis.viewer.wicket.ui.errors.ExceptionModel;
+import org.apache.isis.viewer.wicket.ui.errors.ExceptionStackTracePanel;
+import org.apache.isis.viewer.wicket.ui.errors.JGrowlUtil;
+import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
 
 /**
  * Boilerplate, pick up our HTML and CSS.
@@ -41,9 +56,7 @@ public final class WicketSignInPage extends SignInPage {
     private static final String ID_PAGE_TITLE = "pageTitle";
     private static final String ID_APPLICATION_NAME = "applicationName";
 
-    public WicketSignInPage() {
-        this(null);
-    }
+    private static final String ID_EXCEPTION_STACK_TRACE = "exceptionStackTrace";
 
     /**
      * {@link Inject}ed when {@link #init() initialized}.
@@ -66,10 +79,32 @@ public final class WicketSignInPage extends SignInPage {
     @Named("applicationJs")
     private String applicationJs;
 
+    /**
+     * If set by {@link PageAbstract}. 
+     */
+    private static ExceptionModel getAndClearExceptionModelIfAny() {
+        ExceptionModel exceptionModel = PageAbstract.EXCEPTION.get();
+        PageAbstract.EXCEPTION.remove();
+        return exceptionModel;
+    }
+
+    public WicketSignInPage() {
+        this(null);
+    }
 
     public WicketSignInPage(final PageParameters parameters) {
+        this(parameters, getAndClearExceptionModelIfAny());
+    }
+
+    public WicketSignInPage(final PageParameters parameters, ExceptionModel exceptionModel) {
         addPageTitle(parameters);
         addApplicationName();
+        
+        if(exceptionModel != null) {
+            add(new ExceptionStackTracePanel(ID_EXCEPTION_STACK_TRACE, exceptionModel));
+        } else {
+            add(new WebMarkupContainer(ID_EXCEPTION_STACK_TRACE).setVisible(false));
+        }
     }
 
     private void addPageTitle(final PageParameters parameters) {
@@ -83,6 +118,8 @@ public final class WicketSignInPage extends SignInPage {
     @Override
     public void renderHead(IHeaderResponse response) {
         super.renderHead(response);
+        response.render(new PriorityHeaderItem(JavaScriptHeaderItem.forReference(Application.get().getJavaScriptLibrarySettings().getJQueryReference())));
+        
         if(applicationCss != null) {
             response.render(CssReferenceHeaderItem.forUrl(applicationCss));
         }
@@ -90,6 +127,7 @@ public final class WicketSignInPage extends SignInPage {
             response.render(JavaScriptReferenceHeaderItem.forUrl(applicationJs));
         }
     }
-    
+
+   
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItems.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItems.java b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItems.java
index 4d9b302..e130d32 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItems.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItems.java
@@ -28,6 +28,7 @@ import org.apache.isis.applib.annotation.Hidden;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Named;
 import org.apache.isis.applib.annotation.NotInServiceMenu;
+import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.clock.Clock;
 import org.apache.isis.applib.filter.Filter;
 import org.joda.time.LocalDate;
@@ -92,6 +93,7 @@ public class ToDoItems extends AbstractFactoryAndRepository {
     }
     // }}
 
+    
     // {{ newToDo  (action)
     @MemberOrder(sequence = "3")
     public ToDoItem newToDo(
@@ -107,14 +109,21 @@ public class ToDoItems extends AbstractFactoryAndRepository {
     // }}
 
 
-    // {{ AllToDos (action)
+    // {{ allToDos (action)
     @ActionSemantics(Of.SAFE)
     @MemberOrder(sequence = "4")
     public List<ToDoItem> allToDos() {
+        return allToDos(NotifyUserIfNone.YES);
+    }
+
+    public enum NotifyUserIfNone { YES, NO }
+    
+    @Programmatic
+    public List<ToDoItem> allToDos(NotifyUserIfNone notifyUser) {
         final String currentUser = currentUserName();
         final List<ToDoItem> items = allMatches(ToDoItem.class, ToDoItem.thoseOwnedBy(currentUser));
         Collections.sort(items);
-        if(items.isEmpty()) {
+        if(notifyUser == NotifyUserIfNone.YES && items.isEmpty()) {
             getContainer().warnUser("No to-do items found.");
         }
         return items;
@@ -166,7 +175,7 @@ public class ToDoItems extends AbstractFactoryAndRepository {
     }
     // }}
     
-
+    
     // {{ autoComplete (hidden)
     @Hidden
     public List<ToDoItem> autoComplete(final String description) {
@@ -189,5 +198,5 @@ public class ToDoItems extends AbstractFactoryAndRepository {
     }
     // }}
 
-    
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/db4d727d/example/application/quickstart_wicket_restful_jdo/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java b/example/application/quickstart_wicket_restful_jdo/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
index c00a441..8217ec2 100644
--- a/example/application/quickstart_wicket_restful_jdo/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
+++ b/example/application/quickstart_wicket_restful_jdo/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
@@ -28,6 +28,7 @@ import org.joda.time.LocalDate;
 import dom.todo.ToDoItem;
 import dom.todo.ToDoItem.Category;
 import dom.todo.ToDoItems;
+import dom.todo.ToDoItems.NotifyUserIfNone;
 
 public class ToDoItemsFixture extends AbstractFixture {
 
@@ -61,7 +62,7 @@ public class ToDoItemsFixture extends AbstractFixture {
     // {{ helpers
     private void removeAllToDosForCurrentUser() {
         
-        final List<ToDoItem> allToDos = toDoItems.allToDos();
+        final List<ToDoItem> allToDos = toDoItems.allToDos(NotifyUserIfNone.NO);
         for (final ToDoItem toDoItem : allToDos) {
             getContainer().remove(toDoItem);
         }