/**
   * @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);
  }