Package org.apache.wicket.request.target.coding

Source Code of org.apache.wicket.request.target.coding.HybridUrlCodingStrategy$HybridBookmarkablePageRequestTarget

/*
* 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.wicket.request.target.coding;

import java.lang.ref.WeakReference;

import org.apache.wicket.Application;
import org.apache.wicket.IRedirectListener;
import org.apache.wicket.IRequestTarget;
import org.apache.wicket.MetaDataKey;
import org.apache.wicket.Page;
import org.apache.wicket.PageParameters;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.Session;
import org.apache.wicket.protocol.http.PageExpiredException;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.protocol.http.request.WebRequestCodingStrategy;
import org.apache.wicket.request.RequestParameters;
import org.apache.wicket.request.target.component.BookmarkableListenerInterfaceRequestTarget;
import org.apache.wicket.request.target.component.BookmarkablePageRequestTarget;
import org.apache.wicket.request.target.component.PageRequestTarget;
import org.apache.wicket.request.target.component.listener.ListenerInterfaceRequestTarget;
import org.apache.wicket.util.string.AppendingStringBuffer;
import org.apache.wicket.util.string.Strings;


/**
* An URL coding strategy that encodes the mount point, page parameters and page instance
* information into the URL. The benefits compared to mounting page with
* {@link BookmarkablePageRequestTargetUrlCodingStrategy} are that the mount point is preserved even
* after invoking listener interfaces (thus you don't lose bookmarkability after clicking links) and
* that for ajax only pages the state is preserved on refresh.
* <p>
* The url with {@link HybridUrlCodingStrategy} looks like /mount/path/param1/value1.3. or
* /mount/path/param1/value1.3.2 where 3 is page Id and 2 is version number.
* <p>
* Also to preserve state on refresh with ajax-only pages the {@link HybridUrlCodingStrategy} does
* an immediate redirect after hitting bookmarkable URL, e.g. it immediately redirects from
* /mount/path to /mount/path.3 where 3 is the next page id. This preserves the page instance on
* subsequent page refresh.
*
* @author Matej Knopp
*/
public class HybridUrlCodingStrategy extends AbstractRequestTargetUrlCodingStrategy
{
  /** bookmarkable page class. */
  protected final WeakReference<Class<? extends Page>> pageClassRef;

  private final boolean redirectOnBookmarkableRequest;

  /**
   * Meta data key to store PageParameters in page instance. This is used to save the
   * PageParameters that were used to create the page instance so that later they can be used when
   * generating page URL
   */
  public static final PageParametersMetaDataKey PAGE_PARAMETERS_META_DATA_KEY = new PageParametersMetaDataKey();

  private static class PageParametersMetaDataKey extends MetaDataKey<PageParameters>
  {
    private static final long serialVersionUID = 1L;
  }

  // used to store number of trailing slashes in page url (prior the PageInfo) part. This is
  // necessary to maintain the exact number of slashes after page redirect, so that we don't break
  // things that rely on URL depth (other mounted URLs)
  private static final OriginalUrlTrailingSlashesCountMetaDataKey ORIGINAL_TRAILING_SLASHES_COUNT_METADATA_KEY = new OriginalUrlTrailingSlashesCountMetaDataKey();

  private static class OriginalUrlTrailingSlashesCountMetaDataKey extends MetaDataKey<Integer>
  {
    private static final long serialVersionUID = 1L;
  }

  /**
   * Sets the initial page parameters for page instance. Use this only if you know what you are
   * doing.
   *
   * @param page
   * @param pageParameters
   */
  public static void setInitialPageParameters(final Page page, final PageParameters pageParameters)
  {
    page.setMetaData(PAGE_PARAMETERS_META_DATA_KEY, pageParameters);
  }

  /**
   * @param page
   * @return initial page parameters
   */
  public static PageParameters getInitialPagePageParameters(final Page page)
  {
    return page.getMetaData(PAGE_PARAMETERS_META_DATA_KEY);
  }

  /**
   * Construct.
   *
   * @param mountPath
   * @param pageClass
   * @param redirectOnBookmarkableRequest
   *            whether after hitting the page with URL in bookmarkable form it should be
   *            redirected to hybrid URL - needed for ajax to work properly after page refresh
   */
  public HybridUrlCodingStrategy(final String mountPath, final Class<? extends Page> pageClass,
    final boolean redirectOnBookmarkableRequest)
  {
    super(mountPath);

    if (mountPath.endsWith("/"))
    {
      throw new IllegalArgumentException("mountPath can not end with a '/': " + mountPath);
    }

    pageClassRef = new WeakReference<Class<? extends Page>>(pageClass);
    this.redirectOnBookmarkableRequest = redirectOnBookmarkableRequest;
  }

  /**
   * Construct.
   *
   * @param mountPath
   * @param pageClass
   */
  public HybridUrlCodingStrategy(final String mountPath, final Class<? extends Page> pageClass)
  {
    this(mountPath, pageClass, true);
  }

  /**
   *
   * @param seq
   * @return Returns the amount of trailing slashes in the given string
   */
  private int getTrailingSlashesCount(final CharSequence seq)
  {
    int count = 0;
    for (int i = seq.length() - 1; i >= 0; --i)
    {
      if (seq.charAt(i) == '/')
      {
        ++count;
      }
      else
      {
        break;
      }
    }
    return count;
  }

  /**
   * Returns whether after hitting bookmarkable url the request should be redirected to a hybrid
   * URL. This is recommended for pages with Ajax.
   *
   * @return true if redirect on bookmarkable request
   */
  protected boolean isRedirectOnBookmarkableRequest()
  {
    return redirectOnBookmarkableRequest;
  }

  /**
   * Returns whether to redirect when there is pageMap specified in bookmarkable URL
   *
   * @return true if always redirect when page map is specified
   */
  protected boolean alwaysRedirectWhenPageMapIsSpecified()
  {
    // returns true if the pageId is unique, so we can get rid of the
    // pageMap name in the url this way
    return Application.exists() &&
      Application.get().getSessionSettings().isPageIdUniquePerSession();
  }

  /**
   * @see org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy#decode(org.apache.wicket.request.RequestParameters)
   */
  public IRequestTarget decode(final RequestParameters requestParameters)
  {
    String parametersFragment = requestParameters.getPath().substring(getMountPath().length());

    // try to extract page info
    PageInfoExtraction extraction = extractPageInfo(parametersFragment);

    PageInfo pageInfo = extraction.getPageInfo();
    String pageMapName = pageInfo != null ? pageInfo.getPageMapName() : null;
    Integer pageVersion = pageInfo != null ? pageInfo.getVersionNumber() : null;
    Integer pageId = pageInfo != null ? pageInfo.getPageId() : null;

    // decode parameters
    PageParameters parameters = new PageParameters(decodeParameters(
      extraction.getUrlAfterExtraction(), requestParameters.getParameters()));

    if (requestParameters.getPageMapName() == null)
    {
      requestParameters.setPageMapName(pageMapName);
    }
    else
    {
      pageMapName = requestParameters.getPageMapName();
    }

    // do some extra work for checking whether this is a normal request to a
    // bookmarkable page, or a request to a stateless page (in which case a
    // wicket:interface parameter should be available
    final String interfaceParameter = (String)parameters.remove(WebRequestCodingStrategy.INTERFACE_PARAMETER_NAME);

    // we need to remember the amount of trailing slashes after the redirect
    // (otherwise we'll break relative urls)
    int originalUrlTrailingSlashesCount = getTrailingSlashesCount(extraction.getUrlAfterExtraction());

    boolean redirect = isRedirectOnBookmarkableRequest();
    if ((Strings.isEmpty(pageMapName) != true) && alwaysRedirectWhenPageMapIsSpecified())
    {
      redirect = true;
    }

    if (interfaceParameter != null)
    {
      // stateless listener interface
      WebRequestCodingStrategy.addInterfaceParameters(interfaceParameter, requestParameters);
      return new BookmarkableListenerInterfaceRequestTarget(pageMapName, pageClassRef.get(),
        parameters, requestParameters.getComponentPath(),
        requestParameters.getInterfaceName(), requestParameters.getVersionNumber());
    }
    else if (pageId == null)
    {
      // bookmarkable page request
      return new HybridBookmarkablePageRequestTarget(pageMapName, pageClassRef.get(),
        parameters, originalUrlTrailingSlashesCount, redirect);
    }
    else
    // hybrid url
    {
      Page page;

      if (Strings.isEmpty(pageMapName) && Application.exists() &&
        Application.get().getSessionSettings().isPageIdUniquePerSession())
      {
        page = Session.get().getPage(pageId.intValue(),
          pageVersion != null ? pageVersion.intValue() : 0);
      }
      else
      {
        page = Session.get().getPage(pageMapName, "" + pageId,
          pageVersion != null ? pageVersion.intValue() : 0);
      }

      // check if the found page match the required class
      if ((page != null) && page.getClass().equals(pageClassRef.get()))
      {
        requestParameters.setInterfaceName(IRedirectListener.INTERFACE.getName());
        RequestCycle.get().getRequest().setPage(page);
        return new PageRequestTarget(page);
      }
      else
      {
        // we didn't find the page, act as bookmarkable page request -
        // create new instance, but only if there is no callback to a non-existing page
        if (requestParameters.getInterface() != null)
        {
          handleExpiredPage(pageMapName, pageClassRef.get(),
            originalUrlTrailingSlashesCount, redirect);
        }
        return new HybridBookmarkablePageRequestTarget(pageMapName, pageClassRef.get(),
          parameters, originalUrlTrailingSlashesCount, redirect);
      }
    }
  }

  /**
   * Handles the case where a non-bookmarkable url with a hybrid base refers to a page that is no
   * longer in session. eg <code>/context/hybrid-mount.0.23?wicket:interface=...</code>. The
   * default behavior is to throw a <code>PageExpiredException</code>.
   *
   * This method can be overwritten to, for example, return the user to a new instance of the
   * bookmarkable page that was mounted using hybrid strategy - this, however, should only be used
   * in cases where the page expects no page parameters because they are no longer available.
   *
   * @param pageMapName
   *            page map name this page is mounted in
   * @param pageClass
   *            class of mounted page
   * @param trailingSlashesCount
   *            count of trailing slsahes in the url
   * @param redirect
   *            whether or not a redirect should be issued
   * @return request target used to handle this situation
   */
  protected IRequestTarget handleExpiredPage(final String pageMapName,
    final Class<? extends Page> pageClass, final int trailingSlashesCount,
    final boolean redirect)
  {
    throw new PageExpiredException(
      "Request cannot be processed. The target page does not exist anymore.");
  }

  /**
   * Returns the number of trailing slashes in the url when the page in request target was created
   * or null if the number can't be determined.
   *
   * @param requestTarget
   * @return the number of trailing slashes
   */
  private Integer getOriginalOriginalTrailingSlashesCount(final IRequestTarget requestTarget)
  {
    if (requestTarget instanceof ListenerInterfaceRequestTarget)
    {
      ListenerInterfaceRequestTarget target = (ListenerInterfaceRequestTarget)requestTarget;
      Page page = target.getPage();
      return page.getMetaData(ORIGINAL_TRAILING_SLASHES_COUNT_METADATA_KEY);
    }
    return null;
  }

  /**
   * Extracts the PageParameters from given request target
   *
   * @param requestTarget
   * @return page parameters
   */
  private PageParameters getPageParameters(final IRequestTarget requestTarget)
  {
    if (requestTarget instanceof BookmarkablePageRequestTarget)
    {
      BookmarkablePageRequestTarget target = (BookmarkablePageRequestTarget)requestTarget;
      return target.getPageParameters();
    }
    else if (requestTarget instanceof ListenerInterfaceRequestTarget)
    {
      ListenerInterfaceRequestTarget target = (ListenerInterfaceRequestTarget)requestTarget;
      Page page = target.getPage();
      return getInitialPagePageParameters(page);
    }
    else
    {
      return null;
    }
  }

  /**
   * Extracts the PageInfo from given request target
   *
   * @param requestTarget
   * @return page info
   */
  private PageInfo getPageInfo(final IRequestTarget requestTarget)
  {
    if (requestTarget instanceof BookmarkablePageRequestTarget)
    {
      BookmarkablePageRequestTarget target = (BookmarkablePageRequestTarget)requestTarget;
      if (target.getPageMapName() != null)
      {
        return new PageInfo(null, null, target.getPageMapName());
      }
      else
      {
        return null;
      }
    }
    else if (requestTarget instanceof ListenerInterfaceRequestTarget)
    {
      ListenerInterfaceRequestTarget target = (ListenerInterfaceRequestTarget)requestTarget;
      Page page = target.getPage();
      return new PageInfo(new Integer(page.getNumericId()), new Integer(
        page.getCurrentVersionNumber()), page.getPageMapName());
    }
    else
    {
      return null;
    }
  }

  /**
   * Fix the amount of trailing slashes in the specified buffer.
   *
   * @param buffer
   * @param desiredCount
   */
  private void fixTrailingSlashes(final AppendingStringBuffer buffer, final int desiredCount)
  {
    int current = getTrailingSlashesCount(buffer);
    if (current > desiredCount)
    {
      buffer.setLength(buffer.length() - (current - desiredCount));
    }
    else if (desiredCount > current)
    {
      int toAdd = desiredCount - current;
      while (toAdd > 0)
      {
        buffer.append("/");
        --toAdd;
      }
    }
  }

  /**
   * @see org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy#encode(org.apache.wicket.IRequestTarget)
   */
  public CharSequence encode(final IRequestTarget requestTarget)
  {
    if (matches(requestTarget) == false)
    {
      throw new IllegalArgumentException("Unsupported request target type.");
    }

    PageParameters parameters = getPageParameters(requestTarget);
    PageInfo pageInfo = getPageInfo(requestTarget);

    final AppendingStringBuffer url = new AppendingStringBuffer(40);
    url.append(getMountPath());

    // there are cases where the parameters are null
    if (parameters != null)
    {
      appendParameters(url, parameters);
    }

    // check whether we know if the initial URL ended with slash
    Integer trailingSlashesCount = getOriginalOriginalTrailingSlashesCount(requestTarget);
    if (trailingSlashesCount != null)
    {
      fixTrailingSlashes(url, trailingSlashesCount.intValue());
    }

    return addPageInfo(url.toString(), pageInfo);
  }

  /**
   * @see org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy#matches(org.apache.wicket.IRequestTarget)
   */
  public boolean matches(final IRequestTarget requestTarget)
  {
    if (requestTarget instanceof BookmarkablePageRequestTarget)
    {
      BookmarkablePageRequestTarget target = (BookmarkablePageRequestTarget)requestTarget;
      return target.getPageClass().equals(pageClassRef.get());
    }
    else if (requestTarget instanceof ListenerInterfaceRequestTarget)
    {
      ListenerInterfaceRequestTarget target = (ListenerInterfaceRequestTarget)requestTarget;
      return target.getPage().getClass().equals(pageClassRef.get()) &&
        target.getRequestListenerInterface().equals(IRedirectListener.INTERFACE);
    }
    return false;
  }

  /**
   * Extracts the PageInfo string.
   *
   * @param url
   * @return extract page info
   */
  protected PageInfoExtraction extractPageInfo(final String url)
  {
    int begin = url.lastIndexOf(getBeginSeparator());
    PageInfo last = null;
    String lastSubstring = "";
    while (begin != -1)
    {
      String substring = url.substring(begin);
      if ((substring.length() > getBeginSeparator().length() + getEndSeparator().length()) &&
        substring.startsWith(getBeginSeparator()) && substring.endsWith(getEndSeparator()))
      {
        String pageInfoString = substring.substring(getBeginSeparator().length(), //
          substring.length() - getEndSeparator().length());
        PageInfo info = PageInfo.parsePageInfo(pageInfoString);
        if (info != null)
        {
          last = info;
          lastSubstring = substring;
        }
        else
        {
          break;
        }
      }
      begin = url.lastIndexOf(getBeginSeparator(), begin - 1);
    }

    if (last != null)
    {
      return new PageInfoExtraction(url.substring(0, url.length() - lastSubstring.length()),
        last);
    }
    else
    {
      return new PageInfoExtraction(url, null);
    }
  }

  /**
   * @return begin separator
   */
  protected String getBeginSeparator()
  {
    return ".";
  }

  /**
   * @return end separator
   */
  protected String getEndSeparator()
  {
    return "";
  }

  /**
   * Encodes the PageInfo part to the URL
   *
   * @param url
   * @param pageInfo
   * @return URL
   */
  protected String addPageInfo(final String url, final PageInfo pageInfo)
  {
    if (pageInfo != null)
    {
      return url + getBeginSeparator() + pageInfo.toString() + getEndSeparator();
    }
    else
    {
      return url;
    }
  }

  /**
   * @see org.apache.wicket.request.target.coding.AbstractRequestTargetUrlCodingStrategy#matches(java.lang.String)
   */
  @Override
  public boolean matches(final String path, final boolean caseSensitive)
  {
    RequestCycle rc = RequestCycle.get();

    // the null check is necessary, as this method is first time called from WicketFilter when
    // no RequestCycle exists yet
    if ((rc != null) && ((WebRequest)rc.getRequest()).isAjax())
    {
      // HybridUrlCodingStrategy doesn't make sense for ajax request
      return false;
    }

    if (Strings.startsWith(path, getMountPath(), caseSensitive))
    {
      /*
       * We need to match /mount/point or /mount/point/with/extra/path, but not
       * /mount/pointXXX
       */
      String remainder = path.substring(getMountPath().length());
      if ((remainder.length() == 0) || remainder.startsWith("/"))
      {
        return true;
      }
      /*
       * We also need to accept /mount/point(XXX)
       */
      if ((remainder.length() > getBeginSeparator().length() + getEndSeparator().length()) &&
        remainder.startsWith(getBeginSeparator()) && remainder.endsWith(getEndSeparator()))
      {
        String substring = remainder.substring(getBeginSeparator().length(), //
          remainder.length() - getEndSeparator().length());
        PageInfo info = PageInfo.parsePageInfo(substring);
        if (info != null)
        {
          return true;
        }
      }
    }
    return false;
  }

  /**
   *
   * @see java.lang.Object#toString()
   */
  @Override
  public String toString()
  {
    return "HybridUrlCodingStrategy[page=" + pageClassRef.get() + "]";
  }

  /**
   * Possible string representation of PageInfo:
   * <ul>
   * <li>pageId
   * <li>pageId.version
   * <li>pageMap (only if pageMap starts with a letter)
   * <li>.pageMap
   * <li>pageMap.pageId.version
   * <li>pageMap.pageId (only if pageMap name starts with a letter)
   * </ul>
   *
   * @author Matej Knopp
   */
  protected static class PageInfo
  {
    private final Integer pageId;
    private final Integer versionNumber;
    private final String pageMapName;

    /**
     * Construct.
     *
     * @param pageId
     * @param versionNumber
     * @param pageMapName
     */
    public PageInfo(final Integer pageId, final Integer versionNumber, final String pageMapName)
    {
      if (((pageId == null) && ((versionNumber != null) || (pageMapName == null))) ||
        ((versionNumber == null) && ((pageId != null) || (pageMapName == null))))
      {
        throw new IllegalArgumentException(
          "Either both pageId and versionNumber must be null or none of them.");
      }
      this.pageId = pageId;
      this.versionNumber = versionNumber;
      this.pageMapName = pageMapName;
    }

    /**
     * @return page id
     */
    public Integer getPageId()
    {
      return pageId;
    }

    /**
     * @return version number
     */
    public Integer getVersionNumber()
    {
      return versionNumber;
    }

    /**
     * @return page map name
     */
    public String getPageMapName()
    {
      return pageMapName;
    }

    /**
     *
     * @return page info separator
     */
    private static char getPageInfoSeparator()
    {
      return '.';
    }

    /**
     * <ul>
     * <li>pageId
     * <li>pageId.version
     * <li>pageMap (only in if pagemap starts with a letter)
     * <li>.pageMap
     * <li>pageMap.pageId (only in if pageMap name starts with a letter)
     * <li>pageMap.pageId.version
     * </ul>
     */
    @Override
    public String toString()
    {
      String pageMapName = this.pageMapName;

      // we don't need to encode the pageMapName when the pageId is unique
      // per session
      if ((pageMapName != null) && (pageId != null) && Application.exists() &&
        Application.get().getSessionSettings().isPageIdUniquePerSession())
      {
        pageMapName = null;
      }

      AppendingStringBuffer buffer = new AppendingStringBuffer(5);

      final boolean pmEmpty = Strings.isEmpty(pageMapName);
      final boolean pmContainsLetter = !pmEmpty && !isNumber(pageMapName);


      if ((pageId != null) && pmEmpty && (versionNumber.intValue() == 0))
      {
        // pageId
        buffer.append(pageId);
      }
      else if ((pageId != null) && pmEmpty && (versionNumber.intValue() != 0))
      {
        // pageId.version
        buffer.append(pageId);
        buffer.append(getPageInfoSeparator());
        buffer.append(versionNumber);
      }
      else if ((pageId == null) && pmContainsLetter)
      {
        // pageMap (must start with letter)
        buffer.append(pageMapName);
      }
      else if ((pageId == null) && !pmEmpty && !pmContainsLetter)
      {
        // .pageMap
        buffer.append(getPageInfoSeparator());
        buffer.append(pageMapName);
      }
      else if (pmContainsLetter && (pageId != null) && (versionNumber.intValue() == 0))
      {
        // pageMap.pageId (pageMap must start with a letter)
        buffer.append(pageMapName);
        buffer.append(getPageInfoSeparator());
        buffer.append(pageId);
      }
      else if (!pmEmpty && (pageId != null))
      {
        // pageMap.pageId.pageVersion
        buffer.append(pageMapName);
        buffer.append(getPageInfoSeparator());
        buffer.append(pageId);
        buffer.append(getPageInfoSeparator());
        buffer.append(versionNumber);
      }

      return buffer.toString();
    }

    /**
     * Method that rigidly checks if the string consists of digits only.
     *
     * @param string
     * @return true if is a number
     */
    private static boolean isNumber(final String string)
    {
      if ((string == null) || (string.length() == 0))
      {
        return false;
      }
      for (int i = 0; i < string.length(); ++i)
      {
        if (Character.isDigit(string.charAt(i)) == false)
        {
          return false;
        }
      }
      return true;
    }

    /**
     * <ul>
     * <li>pageId
     * <li>pageId.version
     * <li>pageMap (only in if pagemap starts with a letter)
     * <li>.pageMap
     * <li>pageMap.pageId (only in if pageMap name starts with a letter)
     * <li>pageMap.pageId.version
     * </ul>
     *
     * @param src
     * @return page info
     */
    public static PageInfo parsePageInfo(final String src)
    {
      if ((src == null) || (src.length() == 0))
      {
        return null;
      }

      String segments[] = Strings.split(src, getPageInfoSeparator());

      if (segments.length > 3)
      {
        return null;
      }

      // go trhough the segments to determine if they don't contains invalid characters
      for (int i = 0; i < segments.length; ++i)
      {
        for (int j = 0; j < segments[i].length(); ++j)
        {
          char c = segments[i].charAt(j);
          if (!Character.isLetterOrDigit(c) && (c != '-') && (c != '_'))
          {
            return null;
          }
        }
      }

      if ((segments.length == 1) && isNumber(segments[0]))
      {
        // pageId
        return new PageInfo(Integer.valueOf(segments[0]), new Integer(0), null);
      }
      else if ((segments.length == 2) && isNumber(segments[0]) && isNumber(segments[1]))
      {
        // pageId:pageVersion
        return new PageInfo(Integer.valueOf(segments[0]), Integer.valueOf(segments[1]),
          null);
      }
      else if ((segments.length == 1) && !isNumber(segments[0]))
      {
        // pageMap (starts with letter)
        return new PageInfo(null, null, segments[0]);
      }
      else if ((segments.length == 2) && (segments[0].length() == 0))
      {
        // .pageMap
        return new PageInfo(null, null, segments[1]);
      }
      else if ((segments.length == 2) && !isNumber(segments[0]) && isNumber(segments[1]))
      {
        // pageMap.pageId (pageMap starts with letter)
        return new PageInfo(Integer.valueOf(segments[1]), new Integer(0), segments[0]);
      }
      else if (segments.length == 3)
      {
        if ((segments[2].length() == 0) && isNumber(segments[1]))
        {
          // we don't encode it like this, but we still should be able
          // to parse it
          // pageMapName.pageId.
          return new PageInfo(Integer.valueOf(segments[1]), new Integer(0), segments[0]);
        }
        else if (isNumber(segments[1]) && isNumber(segments[2]))
        {
          // pageMapName.pageId.pageVersion
          return new PageInfo(Integer.valueOf(segments[1]), Integer.valueOf(segments[2]),
            segments[0]);
        }
      }

      return null;
    }

  };

  /**
   * BookmarkablePage request target that does a redirect after bookmarkable page was rendered
   * (only if the bookmarkable page is stateful though)
   *
   * @author Matej Knopp
   */
  public static class HybridBookmarkablePageRequestTarget extends BookmarkablePageRequestTarget
  {
    private final int originalUrlTrailingSlashesCount;
    private final boolean redirect;

    /**
     * Construct.
     *
     * @param pageMapName
     * @param pageClass
     * @param pageParameters
     * @param originalUrlTrailingSlashesCount
     * @param redirect
     */
    public HybridBookmarkablePageRequestTarget(final String pageMapName,
      final Class<? extends Page> pageClass, final PageParameters pageParameters,
      final int originalUrlTrailingSlashesCount, final boolean redirect)
    {
      super(pageMapName, pageClass, pageParameters);
      this.originalUrlTrailingSlashesCount = originalUrlTrailingSlashesCount;
      this.redirect = redirect;
    }

    /**
     * @see org.apache.wicket.request.target.component.BookmarkablePageRequestTarget#newPage(java.lang.Class,
     *      org.apache.wicket.RequestCycle)
     */
    @Override
    protected <C extends Page> Page newPage(final Class<C> pageClass,
      final RequestCycle requestCycle)
    {
      Page page = super.newPage(pageClass, requestCycle);
      page.setMetaData(PAGE_PARAMETERS_META_DATA_KEY, new PageParameters(getPageParameters()));
      page.setMetaData(ORIGINAL_TRAILING_SLASHES_COUNT_METADATA_KEY, new Integer(
        originalUrlTrailingSlashesCount));
      return page;
    }

    /**
     * @see org.apache.wicket.request.target.component.BookmarkablePageRequestTarget#respond(org.apache.wicket.RequestCycle)
     */
    @Override
    public void respond(final RequestCycle requestCycle)
    {
      Page page = getPage(requestCycle);
      if ((page.isPageStateless() == false) && redirect)
      {
        requestCycle.redirectTo(page);
      }
      else
      {
        super.respond(requestCycle);
      }
    }
  }

  /**
   * Class that encapsulates {@link PageInfo} instance and the URL part prior the PageInfo part
   *
   * @author Matej Knopp
   */
  protected static class PageInfoExtraction
  {
    private final String urlAfterExtraction;

    private final PageInfo pageInfo;

    /**
     * Construct.
     *
     * @param urlAfterExtraction
     * @param pageInfo
     */
    public PageInfoExtraction(final String urlAfterExtraction, final PageInfo pageInfo)
    {
      this.urlAfterExtraction = urlAfterExtraction;
      this.pageInfo = pageInfo;
    }

    /**
     * @return page info
     */
    public PageInfo getPageInfo()
    {
      return pageInfo;
    }

    /**
     * @return url after extraction
     */
    public String getUrlAfterExtraction()
    {
      return urlAfterExtraction;
    }
  }
}
TOP

Related Classes of org.apache.wicket.request.target.coding.HybridUrlCodingStrategy$HybridBookmarkablePageRequestTarget

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.