Index: api/src/main/java/org/hippoecm/frontend/RepositoryRuntimeException.java =================================================================== --- api/src/main/java/org/hippoecm/frontend/RepositoryRuntimeException.java (revision 0) +++ api/src/main/java/org/hippoecm/frontend/RepositoryRuntimeException.java (revision 0) @@ -0,0 +1,41 @@ +/* + * Copyright 2014-2014 Hippo B.V. (http://www.onehippo.com) + * + * Licensed 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.hippoecm.frontend; + +/** + * JCR Repository runtime exception in frontend application + */ +public class RepositoryRuntimeException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public RepositoryRuntimeException() { + super(); + } + + public RepositoryRuntimeException(String message) { + super(message); + } + + public RepositoryRuntimeException(String message, Throwable cause) { + super(message, cause); + } + + public RepositoryRuntimeException(Throwable cause) { + super(cause); + } + +} Index: api/src/main/java/org/hippoecm/frontend/RepositoryUnavailableException.java =================================================================== --- api/src/main/java/org/hippoecm/frontend/RepositoryUnavailableException.java (revision 0) +++ api/src/main/java/org/hippoecm/frontend/RepositoryUnavailableException.java (revision 0) @@ -0,0 +1,41 @@ +/* + * Copyright 2014-2014 Hippo B.V. (http://www.onehippo.com) + * + * Licensed 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.hippoecm.frontend; + +/** + * Runtime exception representing the status that there's no available JCR repository. + */ +public class RepositoryUnavailableException extends RepositoryRuntimeException { + + private static final long serialVersionUID = 1L; + + public RepositoryUnavailableException() { + super(); + } + + public RepositoryUnavailableException(String message) { + super(message); + } + + public RepositoryUnavailableException(String message, Throwable cause) { + super(message, cause); + } + + public RepositoryUnavailableException(Throwable cause) { + super(cause); + } + +} Index: api/src/main/java/org/hippoecm/frontend/model/map/JcrMap.java =================================================================== --- api/src/main/java/org/hippoecm/frontend/model/map/JcrMap.java (revision 45755) +++ api/src/main/java/org/hippoecm/frontend/model/map/JcrMap.java (working copy) @@ -35,10 +35,9 @@ import javax.jcr.nodetype.NodeDefinition; import javax.jcr.nodetype.NodeType; -import org.apache.wicket.RestartResponseException; import org.apache.wicket.model.IDetachable; -import org.apache.wicket.protocol.http.WebApplication; import org.hippoecm.frontend.model.JcrNodeModel; +import org.hippoecm.frontend.session.InvalidSessionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -443,10 +442,14 @@ try { if (!getNode().getSession().isLive()) { log.error("Found session in an invalid unallowed state: not live. Return log in screen"); - throw new RestartResponseException(WebApplication.get().getHomePage()); + throw new InvalidSessionException("Invalid (non-live) session found."); } } catch (RepositoryException e) { - // log the original ex above + if (log.isDebugEnabled()) { + log.warn("Failed to check the liveness of the session.", e); + } else { + log.warn("Failed to check the liveness of the session. {}", e); + } } if (log.isDebugEnabled()) { Index: api/src/main/java/org/hippoecm/frontend/session/InvalidSessionException.java =================================================================== --- api/src/main/java/org/hippoecm/frontend/session/InvalidSessionException.java (revision 0) +++ api/src/main/java/org/hippoecm/frontend/session/InvalidSessionException.java (revision 0) @@ -0,0 +1,43 @@ +/* + * Copyright 2014-2014 Hippo B.V. (http://www.onehippo.com) + * + * Licensed 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.hippoecm.frontend.session; + +import org.hippoecm.frontend.RepositoryRuntimeException; + +/** + * Runtime exception representing the JCR session is invalid. e.g, session is no more live because it's closed. + */ +public class InvalidSessionException extends RepositoryRuntimeException { + + private static final long serialVersionUID = 1L; + + public InvalidSessionException() { + super(); + } + + public InvalidSessionException(String message) { + super(message); + } + + public InvalidSessionException(String message, Throwable cause) { + super(message, cause); + } + + public InvalidSessionException(Throwable cause) { + super(cause); + } + +} Index: engine/src/main/java/org/hippoecm/frontend/Main.java =================================================================== --- engine/src/main/java/org/hippoecm/frontend/Main.java (revision 45755) +++ engine/src/main/java/org/hippoecm/frontend/Main.java (working copy) @@ -30,6 +30,7 @@ import javax.jcr.observation.EventListener; import javax.jcr.observation.EventListenerIterator; +import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.wicket.Component; import org.apache.wicket.DefaultPageManagerProvider; @@ -58,7 +59,9 @@ import org.apache.wicket.request.Response; import org.apache.wicket.request.Url; import org.apache.wicket.request.component.IRequestablePage; +import org.apache.wicket.request.cycle.IRequestCycleListener; import org.apache.wicket.request.cycle.RequestCycle; +import org.apache.wicket.request.cycle.RequestCycleListenerCollection; import org.apache.wicket.request.handler.render.PageRenderer; import org.apache.wicket.request.handler.render.WebPageRenderer; import org.apache.wicket.request.http.WebRequest; @@ -115,6 +118,12 @@ public final static String PLUGIN_APPLICATION_NAME_PARAMETER = "config"; /** + * Custom Wicket {@link IRequestCycleListener} class names parameter + * which can be comma or whitespace-separated string to set multiple {@link IRequestCycleListener}s. + */ + public final static String REQUEST_CYCLE_LISTENERS_PARAM = "wicket.request.cycle.listeners"; + + /** * Wicket RequestCycleSettings timeout configuration parameter name in development mode. */ public final static String DEVELOPMENT_REQUEST_TIMEOUT_PARAM = "wicket.development.request.timeout"; @@ -146,6 +155,8 @@ protected void init() { super.init(); + addRequestCycleListeners(); + getPageSettings().setVersionPagesByDefault(false); // getPageSettings().setAutomaticMultiWindowSupport(false); @@ -573,5 +584,30 @@ } } + /** + * Adds the default built-in {@link IRequestCycleListener} or configured custom {@link IRequestCycleListener}s. + *
+ * If no custom {@link IRequestCycleListener}s are configured, then this simply registers the default built-in + * {@link RepositoryRuntimeExceptionHandlingRequestCycleListener}. + * Otherwise, this registers only the custom configured {@link IRequestCycleListener}s. + *
+ */ + private void addRequestCycleListeners() { + String [] listenerClassNames = StringUtils.split(getConfigurationParameter(REQUEST_CYCLE_LISTENERS_PARAM, null), " ,\t\r\n"); + RequestCycleListenerCollection requestCycleListenerCollection = getRequestCycleListeners(); + if (listenerClassNames == null || listenerClassNames.length == 0) { + requestCycleListenerCollection.add(new RepositoryRuntimeExceptionHandlingRequestCycleListener()); + } else { + for (String listenerClassName : listenerClassNames) { + try { + Class> clazz = Class.forName(listenerClassName); + IRequestCycleListener listener = (IRequestCycleListener) clazz.newInstance(); + requestCycleListenerCollection.add(listener); + } catch (Throwable th) { + log.error("Failed to register RequestCycleListener, " + listenerClassName, th); + } + } + } + } } Index: engine/src/main/java/org/hippoecm/frontend/RepositoryRuntimeExceptionHandlingRequestCycleListener.java =================================================================== --- engine/src/main/java/org/hippoecm/frontend/RepositoryRuntimeExceptionHandlingRequestCycleListener.java (revision 0) +++ engine/src/main/java/org/hippoecm/frontend/RepositoryRuntimeExceptionHandlingRequestCycleListener.java (revision 0) @@ -0,0 +1,87 @@ +/* + * Copyright 2014-2014 Hippo B.V. (http://www.onehippo.com) + * + * Licensed 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.hippoecm.frontend; + +import static org.hippoecm.frontend.util.WebApplicationHelper.HIPPO_AUTO_LOGIN_COOKIE_BASE_NAME; + +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.WebApplication; +import org.apache.wicket.request.IRequestHandler; +import org.apache.wicket.request.cycle.AbstractRequestCycleListener; +import org.apache.wicket.request.cycle.IRequestCycleListener; +import org.apache.wicket.request.cycle.RequestCycle; +import org.apache.wicket.util.lang.Exceptions; +import org.hippoecm.frontend.session.InvalidSessionException; +import org.hippoecm.frontend.session.UserSession; +import org.hippoecm.frontend.util.WebApplicationHelper; + +/** + * The default {@link IRequestCycleListener} implementation to handle {@link RepositoryRuntimeException}s. + * If a {@link RepositoryRuntimeException} occurs, then this listener redirects to either home page + * or {@link NoRepositoryAvailablePage} depending on the exception type. + */ +public class RepositoryRuntimeExceptionHandlingRequestCycleListener extends AbstractRequestCycleListener { + + @Override + public IRequestHandler onException(RequestCycle cycle, Exception ex) { + IRequestHandler handler = null; + RepositoryRuntimeException rrEx = Exceptions.findCause(ex, RepositoryRuntimeException.class); + + if (rrEx != null) { + handler = createRequestHandler(rrEx); + + if (handler != null) { + clearStates(); + } + } + + return handler; + } + + /** + * Creates IRequestHandler based on the givenRepositoryRuntimeException
.
+ * @param rrEx RepositoryRuntimeException
+ * @return
+ */
+ protected IRequestHandler createRequestHandler(final RepositoryRuntimeException rrEx) {
+ IRequestHandler handler = null;
+
+ if (rrEx instanceof InvalidSessionException) {
+ handler = new RenderPageRequestHandler(new PageProvider(WebApplication.get().getHomePage()), RedirectPolicy.AUTO_REDIRECT);
+ } else if (rrEx instanceof RepositoryUnavailableException) {
+ handler = new RenderPageRequestHandler(new PageProvider(NoRepositoryAvailablePage.class), RedirectPolicy.AUTO_REDIRECT);
+ }
+
+ return handler;
+ }
+
+ /**
+ * Clear any user states other than user session.
+ */
+ protected void clearStates() {
+ // Remove the Hippo Auto Login cookie
+ WebApplicationHelper.clearCookie(WebApplicationHelper.getFullyQualifiedCookieName(HIPPO_AUTO_LOGIN_COOKIE_BASE_NAME));
+
+ UserSession userSession = UserSession.get();
+
+ if (userSession != null) {
+ // Clears HTTP session states
+ userSession.invalidate();
+ }
+ }
+}
Index: engine/src/main/java/org/hippoecm/frontend/session/PluginUserSession.java
===================================================================
--- engine/src/main/java/org/hippoecm/frontend/session/PluginUserSession.java (revision 45755)
+++ engine/src/main/java/org/hippoecm/frontend/session/PluginUserSession.java (working copy)
@@ -31,7 +31,6 @@
import org.apache.cxf.common.util.StringUtils;
import org.apache.wicket.Application;
import org.apache.wicket.Component;
-import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ThreadContext;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
@@ -39,8 +38,8 @@
import org.apache.wicket.request.cycle.RequestCycle;
import org.hippoecm.frontend.Home;
import org.hippoecm.frontend.Main;
-import org.hippoecm.frontend.NoRepositoryAvailablePage;
import org.hippoecm.frontend.PluginApplication;
+import org.hippoecm.frontend.RepositoryUnavailableException;
import org.hippoecm.frontend.model.JcrSessionModel;
import org.hippoecm.frontend.model.UserCredentials;
import org.hippoecm.frontend.observation.FacetRootsObserver;
@@ -199,7 +198,7 @@
session = fallbackSession;
if (session == null) {
main.resetConnection();
- throw new RestartResponseException(NoRepositoryAvailablePage.class);
+ throw new RepositoryUnavailableException("Repository is not available.");
}
} else if (fallbackSession != null) {
fallbackSession.logout();
@@ -217,6 +216,7 @@
if (!result.isLive()) {
log.error("Found session in an invalid unallowed state: not live. Logout PluginUserSession");
logout();
+ throw new InvalidSessionException("Invalid (non-live) session found.");
}
return result;
}