/** * @see wicket.request.compound.IExceptionResponseStrategy#respond(wicket.RequestCycle, * java.lang.RuntimeException) */ public final void respond(final RequestCycle requestCycle, final RuntimeException e) { // If application doesn't want debug info showing up for users final Session session = requestCycle.getSession(); final Application application = session.getApplication(); final IExceptionSettings settings = application.getExceptionSettings(); final Page responsePage = requestCycle.getResponsePage(); Page override = onRuntimeException(responsePage, e); if (override != null) { // we do not want to redirect - we want to inline the error output // and preserve the url so when the refresh button is pressed we // rerun the code that caused the error requestCycle.setRedirect(false); throw new RestartResponseException(override); } else if (e instanceof AuthorizationException) { // are authorization exceptions always thrown before the real render? // else we need to make a page (see below) or set it hard to a redirect. Class<? extends Page> accessDeniedPageClass = application.getApplicationSettings().getAccessDeniedPage(); throw new RestartResponseAtInterceptPageException(accessDeniedPageClass); } else if (settings.getUnexpectedExceptionDisplay() != UnexpectedExceptionDisplay.SHOW_NO_EXCEPTION_PAGE) { // we do not want to redirect - we want to inline the error output // and preserve the url so when the refresh button is pressed we // rerun the code that caused the error requestCycle.setRedirect(false); // figure out which error page to show Class<? extends Page> internalErrorPageClass = application.getApplicationSettings().getInternalErrorPage(); Class responseClass = responsePage != null ? responsePage.getClass() : null; if (responseClass != internalErrorPageClass && settings.getUnexpectedExceptionDisplay() == UnexpectedExceptionDisplay.SHOW_INTERNAL_ERROR_PAGE) { throw new RestartResponseException(internalErrorPageClass); } else if (responseClass != ExceptionErrorPortletPage.class) { // Show full details throw new RestartResponseException(new ExceptionErrorPortletPage(e, responsePage)); } else { // give up while we're ahead! throw new WicketRuntimeException( "Internal Error: Could not render error page " + internalErrorPageClass, e); } } }
/** * Encode a shared resource target. * * <p>If you override this method to behave different then also {@link * #addResourceParameters(Request, RequestParameters)} should be overridden to by in sync with * that behaviour. * * @param requestCycle the current request cycle * @param requestTarget the target to encode * @return the encoded url */ protected CharSequence encode( RequestCycle requestCycle, ISharedResourceRequestTarget requestTarget) { final CharSequence prefix = urlPrefix(requestCycle); final String sharedResourceKey = requestTarget.getResourceKey(); if ((sharedResourceKey == null) || (sharedResourceKey.trim().length() == 0)) { return prefix; } else { final AppendingStringBuffer buffer = new AppendingStringBuffer(sharedResourceKey.length() + prefix.length() + 11); buffer.append(prefix); if ((buffer.length() > 0) && buffer.charAt(buffer.length() - 1) == '/') { buffer.append("resources/"); } else { buffer.append("/resources/"); } buffer.append(sharedResourceKey); Map<String, ? extends Object> map = requestTarget.getRequestParameters().getParameters(); if (map != null && map.size() > 0) { buffer.append('?'); for (String key : map.keySet()) { buffer.append(key); buffer.append('='); buffer.append(map.get(key)); buffer.append('&'); } buffer.setLength(buffer.length() - 1); } return requestCycle.getOriginalResponse().encodeURL(buffer); } }
/** * Simulate that an AJAX event has been fired. You add an AJAX event to a component by using: * * <pre> * ... * component.add(new AjaxEventBehavior(ClientEvent.DBLCLICK) { * public void onEvent(AjaxRequestTarget) { * // Do something. * } * }); * ... * </pre> * * You can then test that the code inside onEvent actually does what it's supposed to, using the * WicketTester: * * <pre> * ... * tester.executeAjaxEvent(component, ClientEvent.DBLCLICK); * * // Test that the code inside onEvent is correct. * ... * </pre> * * PLEASE NOTE! This method doesn't actually insert the component in the client DOM tree, using * javascript. * * @param component The component which has the AjaxEventBehavior we wan't to test. If the * component is null, the test will fail. * @param event The event which we simulate is fired. If the event is null, the test will fail. */ @SuppressWarnings("unchecked") public void executeAjaxEvent(Component component, ClientEvent event) { String failMessage = "Can't execute event on a component which is null."; Assert.assertNotNull(failMessage, component); failMessage = "event must not be null"; Assert.assertNotNull(failMessage, event); // Run through all the behavior and select the LAST ADDED behavior which // matches the event parameter. AjaxEventBehavior ajaxEventBehavior = null; List<IBehavior> behaviors = component.getBehaviors(); for (IBehavior behavior : behaviors) { // AjaxEventBehavior is the one to look for if (behavior instanceof AjaxEventBehavior) { AjaxEventBehavior tmp = (AjaxEventBehavior) behavior; if (tmp.getEvent() == event) { ajaxEventBehavior = tmp; } } } // If there haven't been found any event behaviors on the component // which maches the parameters we fail. failMessage = "No AjaxEventBehavior found on component: " + component.getId() + " which matches the event: " + event.toString(); Assert.assertNotNull(failMessage, ajaxEventBehavior); setupRequestAndResponse(); RequestCycle requestCycle = createRequestCycle(); ajaxEventBehavior.onRequest(); // process the request target requestCycle.getRequestTarget().respond(requestCycle); }
/** * Encode a listener interface target. * * <p>If you override this method to behave different then also {@link * #addInterfaceParameters(Request, RequestParameters)} should be overridden to by in sync with * that behaviour. * * @param requestCycle the current request cycle * @param requestTarget the target to encode * @return the encoded url */ protected CharSequence encode( RequestCycle requestCycle, IListenerInterfaceRequestTarget requestTarget) { final RequestListenerInterface rli = requestTarget.getRequestListenerInterface(); // Start string buffer for url final AppendingStringBuffer url = new AppendingStringBuffer(64); url.append(urlPrefix(requestCycle)); url.append('?'); url.append(INTERFACE_PARAMETER_NAME); url.append('='); // Get component and page for request target final Component component = requestTarget.getTarget(); final Page page = component.getPage(); // Add pagemap final PageMap pageMap = page.getPageMap(); if (!pageMap.isDefault()) { url.append(pageMap.getName()); } url.append(Component.PATH_SEPARATOR); // Add path to component url.append(component.getPath()); url.append(Component.PATH_SEPARATOR); // Add version final int versionNumber = component.getPage().getCurrentVersionNumber(); if (!rli.getRecordsPageVersion()) { url.append(Page.LATEST_VERSION); } else if (versionNumber > 0) { url.append(versionNumber); } url.append(Component.PATH_SEPARATOR); // Add listener interface final String listenerName = rli.getName(); if (!IRedirectListener.INTERFACE.getName().equals(listenerName)) { url.append(listenerName); } return requestCycle.getOriginalResponse().encodeURL(url); }
/** * This method is called when a runtime exception is thrown, just before the actual handling of * the runtime exception. This implemention passes the call through to {@link * RequestCycle#onRuntimeException(Page, RuntimeException)}. Note that if you override this method * or provide a whole new implementation of {@link IExceptionResponseStrategy} alltogether, {@link * RequestCycle#onRuntimeException(Page, RuntimeException)} will not be supported. * * @param page Any page context where the exception was thrown * @param e The exception * @return Any error page to redirect to */ protected Page onRuntimeException(final Page page, final RuntimeException e) { return RequestCycle.get().onRuntimeException(page, e); }
/** * Click the {@link Link} in the last rendered Page. * * <p>This method also works for {@link AjaxLink}, {@link AjaxFallbackLink} and {@link * AjaxSubmitLink}. * * <p>On AjaxLinks and AjaxFallbackLinks the onClick method is invoked with a valid * AjaxRequestTarget. In that way you can test the flow of your application when using AJAX. * * <p>When clicking an AjaxSubmitLink the form, which the AjaxSubmitLink is attached to is first * submitted, and then the onSubmit method on AjaxSubmitLink is invoked. If you have changed some * values in the form during your test, these will also be submitted. This should not be used as a * replacement for the {@link FormTester} to test your forms. It should be used to test that the * code in your onSubmit method in AjaxSubmitLink actually works. * * <p>This method is also able to simulate that AJAX (javascript) is disabled on the client. This * is done by setting the isAjax parameter to false. If you have an AjaxFallbackLink you can then * check that it doesn't fail when invoked as a normal link. * * @param path path to <code>Link</code> component * @param isAjax Whether to simulate that AJAX (javascript) is enabled or not. If it's false then * AjaxLink and AjaxSubmitLink will fail, since it wouldn't work in real life. * AjaxFallbackLink will be invoked with null as the AjaxRequestTarget parameter. */ public void clickLink(String path, boolean isAjax) { Component linkComponent = getComponentFromLastRenderedPage(path); // if the link is an AjaxLink, we process it differently // than a normal link if (linkComponent instanceof AjaxLink) { // If it's not ajax we fail if (isAjax == false) { Assert.fail( "Link " + path + "is an AjaxLink and will " + "not be invoked when AJAX (javascript) is disabled."); } AjaxLink link = (AjaxLink) linkComponent; setupRequestAndResponse(); RequestCycle requestCycle = createRequestCycle(); AjaxRequestTarget target = new AjaxRequestTarget(); requestCycle.setRequestTarget(target); link.onClick(target); // process the request target target.respond(requestCycle); } // AjaxFallbackLinks is processed like an AjaxLink if isAjax is true // If it's not handling of the linkComponent is passed through to the // Link. else if (linkComponent instanceof AjaxFallbackLink && isAjax) { AjaxFallbackLink link = (AjaxFallbackLink) linkComponent; setupRequestAndResponse(); RequestCycle requestCycle = createRequestCycle(); AjaxRequestTarget target = new AjaxRequestTarget(); requestCycle.setRequestTarget(target); link.onClick(target); // process the request target target.respond(requestCycle); } // if the link is an AjaxSubmitLink, we need to find the form // from it using reflection so we know what to submit. else if (linkComponent instanceof AjaxSubmitLink) { // If it's not ajax we fail if (isAjax == false) { Assert.fail( "Link " + path + "is an AjaxSubmitLink and " + "will not be invoked when AJAX (javascript) is disabled."); } AjaxSubmitLink link = (AjaxSubmitLink) linkComponent; // We cycle through the attached behaviors and select the // LAST matching behavior as the one we handle. List behaviors = link.getBehaviors(); AjaxFormSubmitBehavior ajaxFormSubmitBehavior = null; for (Object behavior : behaviors) { if (behavior instanceof AjaxFormSubmitBehavior) { AjaxFormSubmitBehavior submitBehavior = (AjaxFormSubmitBehavior) behavior; ajaxFormSubmitBehavior = submitBehavior; } } String failMessage = "No form submit behavior found on the submit link. Strange!!"; Assert.assertNotNull(failMessage, ajaxFormSubmitBehavior); // We need to get the form submitted, using reflection. // It needs to be "submitted". Form form = null; try { Field formField = AjaxFormSubmitBehavior.class.getDeclaredField("form"); formField.setAccessible(true); form = (Form) formField.get(ajaxFormSubmitBehavior); } catch (Exception e) { Assert.fail(e.getMessage()); } failMessage = "No form attached to the submitlink."; Assert.assertNotNull(failMessage, form); setupRequestAndResponse(); RequestCycle requestCycle = createRequestCycle(); // "Submit" the form form.visitFormComponents( new FormComponent.IVisitor() { public void formComponent(FormComponent formComponent) { if (!(formComponent instanceof Button) && !(formComponent instanceof RadioGroup)) { String name = formComponent.getInputName(); String value = formComponent.getValue(); getServletRequest().setParameter(name, value); } } }); // Ok, finally we "click" the link ajaxFormSubmitBehavior.onRequest(); // process the request target requestCycle.getRequestTarget().respond(requestCycle); } // if the link is a normal link else if (linkComponent instanceof Link) { Link link = (Link) linkComponent; newRequestToComponent(link); } else { Assert.fail("Link " + path + " is not a Link, AjaxLink, AjaxFallbackLink or AjaxSubmitLink"); } }
/** * Encode a page class target. * * <p>If you override this method to behave different then also {@link * #addBookmarkablePageParameters(Request, RequestParameters)} should be overridden to by in sync * with that behaviour. * * @param requestCycle the current request cycle * @param requestTarget the target to encode * @return the encoded url */ protected CharSequence encode( RequestCycle requestCycle, IBookmarkablePageRequestTarget requestTarget) { // Begin encoding URL final AppendingStringBuffer url = new AppendingStringBuffer(64); url.append(urlPrefix(requestCycle)); // Get page Class final Class pageClass = requestTarget.getPageClass(); final Application application = Application.get(); // Find pagemap name String pageMapName = requestTarget.getPageMapName(); if (pageMapName == null) { IRequestTarget currentTarget = requestCycle.getRequestTarget(); if (currentTarget instanceof IPageRequestTarget) { Page currentPage = ((IPageRequestTarget) currentTarget).getPage(); final PageMap pageMap = currentPage.getPageMap(); if (pageMap.isDefault()) { pageMapName = ""; } else { pageMapName = pageMap.getName(); } } else { pageMapName = ""; } } boolean firstParameter = true; if (!application.getHomePage().equals(pageClass) || !"".equals(pageMapName) || requestTarget instanceof BookmarkableListenerInterfaceRequestTarget) { firstParameter = false; url.append('?'); url.append(WebRequestCodingStrategy.BOOKMARKABLE_PAGE_PARAMETER_NAME); url.append('='); // Add <page-map-name>:<bookmarkable-page-class> url.append(pageMapName + Component.PATH_SEPARATOR + pageClass.getName()); } // Is it a bookmarkable interface listener? if (requestTarget instanceof BookmarkableListenerInterfaceRequestTarget) { BookmarkableListenerInterfaceRequestTarget listenerTarget = (BookmarkableListenerInterfaceRequestTarget) requestTarget; if (firstParameter == true) { url.append("?"); } else { url.append("&"); } firstParameter = false; url.append(INTERFACE_PARAMETER_NAME); url.append("="); url.append(Component.PATH_SEPARATOR); url.append(listenerTarget.getComponentPath()); url.append(Component.PATH_SEPARATOR); url.append(Component.PATH_SEPARATOR); url.append(listenerTarget.getInterfaceName()); } // Get page parameters final PageParameters parameters = requestTarget.getPageParameters(); if (parameters != null) { for (Object element : parameters.keySet()) { final String key = (String) element; final String value = parameters.getString(key); if (value != null) { String escapedValue = value; try { escapedValue = URLEncoder.encode( escapedValue, application.getRequestCycleSettings().getResponseRequestEncoding()); } catch (UnsupportedEncodingException ex) { log.error(ex.getMessage(), ex); } if (!firstParameter) { url.append('&'); } else { firstParameter = false; url.append('?'); } url.append(key); url.append('='); url.append(escapedValue); } } } return requestCycle.getOriginalResponse().encodeURL(url); }