Package org.wicketstuff.minis.mapper

Source Code of org.wicketstuff.minis.mapper.ExtendedPackageMapper

package org.wicketstuff.minis.mapper;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.wicket.Application;
import org.apache.wicket.Page;
import org.apache.wicket.core.request.mapper.PackageMapper;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.mapper.AbstractMapper;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.lang.PackageName;

/**
* <p>
* Extended PackageMapper with Named Parameter and HomePage support. Remember to add this mapper
* before anyone else, so it will have low priority against top-level, more important mappers.
* </p>
*
* <p>
* Usage:
*
* <pre>
* add(new ExtendedPackageMapper("${username}/static/${group}", Profile.class) {
*          protected boolean validateParameters(PageParameters parameters) {
*             String username = parameters.get("username").toString();
*             String group = parameters.get("group").toString();
*             return validUsername(username)
*          }
* });
* </pre>
*
* </p>
* <p>
* Users can then use URLs like:
* <ul>
* <li>http://localhost:8080/john/static/admin -> renders Profile page</li>
* <li>http://localhost:8080/john/static/admin/Profile -> renders Profile page</li>
* <li>http://localhost:8080/john/static/admin/Groups -> renders Groups page present in same package
* as <code>Profile</code></li>
* </ul>
* Parameters can be accessed as usual (PageParameters in constructor, for example)
* </p>
*
* @author Bruno Borges
*/
public class ExtendedPackageMapper extends AbstractMapper
{

  private PackageMapper mountedMapper;
  private String mountedPath;
  private String[] mountedSegments;
  private String packageName;
  private String homePageName;

  /**
   * <p>
   * Construct an ExtendedPackageMapper for package of <code>homePage</code> class, at
   * <code>mountPath</code>. <code>homePage</code> is considered the Home Page for this mounted
   * path, in case the user does not indicate which page to render.
   * </p>
   *
   * <p>
   * Named parameters are optional and may be defined as the first mount segment
   * </p>
   *
   * @param mountPath
   *            in the form of "${some}/path/with/${named}/parameters"
   * @param homePage
   */
  public <P extends Page> ExtendedPackageMapper(String mountPath, Class<P> homePage)
  {
    homePageName = homePage.getSimpleName();
    mountedPath = mountPath;
    mountedSegments = getMountSegments(mountedPath);

    PackageName pkgNameObj = PackageName.forClass(homePage);
    packageName = pkgNameObj.getName();
    mountedMapper = new PackageMapper(packageName, pkgNameObj);
  }

  public Url mapHandler(IRequestHandler requestHandler)
  {
    Url url = mountedMapper.mapHandler(requestHandler);

    if (url != null)
    {
      List<String> newUrlSegments = new ArrayList<String>(mountedSegments.length);
      for (String segment : mountedSegments)
      {
        String newSegment = segment;
        String placeholder = getPlaceholder(segment);
        if (placeholder != null)
        {
          // segment is parameter
          // set it as Url segment and remove it from QueryParameters
          newSegment = url.getQueryParameter(placeholder).getValue();
          url.removeQueryParameters(placeholder);
        }
        newUrlSegments.add(newSegment);
      }
      List<String> urlSegments = url.getSegments();
      urlSegments.remove(0);
      urlSegments.addAll(0, newUrlSegments);

      int lastIndex = urlSegments.size() - 1;
      if (urlSegments.get(lastIndex).equals(homePageName))
      {
        urlSegments.remove(lastIndex);
      }
    }
    return url;
  }

  /**
   * Override this to validate parameters. Return true if this Mapper should handle the current
   * request based on your busines slogic
   *
   * @param parameters
   * @return true if this Mapper will handle the request. default: true
   */
  protected boolean validateParameters(PageParameters parameters)
  {
    return true;
  }

  public IRequestHandler mapRequest(Request request)
  {
    Url url = request.getUrl();

    List<String> urlSegments = url.getSegments();
    int countUrlSegments = urlSegments.size();
    if (countUrlSegments < mountedSegments.length)
    {
      return null;
    }

    PageParameters mountedParameters = new PageParameters();
    int i = 0;
    Iterator<String> urlSegmentsIterator = urlSegments.iterator();
    for (String mountedSegment : mountedSegments)
    {
      if (i == countUrlSegments)
      {
        break;
      }

      String urlSegmentValue = urlSegmentsIterator.next();
      String name = getPlaceholder(mountedSegment);
      if (name != null)
      {
        mountedParameters.add(name, urlSegmentValue);
        url.setQueryParameter(name, urlSegmentValue);
        urlSegmentsIterator.remove();
      }
      i++;
    }

    if (!validateParameters(mountedParameters))
    {
      return null;
    }

    // replace with packageName segment so PackageMapper can do its magic
    if (urlSegments.size() == 0)
    {
      urlSegments.add(packageName);
      urlSegments.add(homePageName);
    }
    else
    {
      String lastSegment = urlSegments.get(urlSegments.size() - 1);

      urlSegments.clear();
      urlSegments.add(packageName);
      if (isPackageClass(lastSegment))
      {
        urlSegments.add(lastSegment);
      }
      else
      {
        urlSegments.add(homePageName);
      }
    }

    IRequestHandler mapRequest = mountedMapper.mapRequest(request.cloneWithUrl(url));
    if (mapRequest == null)
    {
      // try adding the homePage class
      if (urlSegments.size() == 1)
      {
        urlSegments.add(homePageName);
      }
      else
      {
        urlSegments.set(1, homePageName);
      }
      mapRequest = mountedMapper.mapRequest(request.cloneWithUrl(url));
    }
    return mapRequest;
  }

  private boolean isPackageClass(String lastSegment)
  {
    String fqcn = packageName + '.' + lastSegment;
    Class resolved = null;
    try
    {
      if (Application.exists())
      {
        resolved = Application.get()
          .getApplicationSettings()
          .getClassResolver()
          .resolveClass(fqcn);
      }

      if (resolved == null)
      {
        resolved = Class.forName(fqcn, false, Thread.currentThread()
          .getContextClassLoader());
      }

      return true;
    }
    catch (Exception e)
    {
      return false;
    }
  }

  /**
   * Scores the compatibility of Request with this Mapper.
   *
   * <ul>
   * <li>+1 for segments count equals mountedSegments+1 (page referenced)</li>
   * <li>+1 for segments count equals mountedSegments</li>
   * <li>+2+(score/2) for static segments</li>
   * </ul>
   */
  public int getCompatibilityScore(Request request)
  {
    Url url = request.getUrl();
    int score = 0;

    List<String> urlSegs = url.getSegments();
    int segmentsCount = urlSegs.size();

    // path + Page
    if (segmentsCount == mountedSegments.length + 1)
    {
      score++;
    }

    // only path
    if (segmentsCount == mountedSegments.length)
    {
      score++;
    }

    // for each static segment matched, it will get 2 score + (scores / 2)
    for (int i = 0; i < mountedSegments.length; i++)
    {
      if (i == segmentsCount)
      {
        break;
      }

      String mountedSegment = mountedSegments[i];
      String urlSegment = urlSegs.get(i);
      if (getPlaceholder(mountedSegment) == null && mountedSegment.equals(urlSegment))
      {
        // static
        score = 2 + score + (score / 2);
      }
    }

    return score;
  }

}
TOP

Related Classes of org.wicketstuff.minis.mapper.ExtendedPackageMapper

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.