All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ocpsoft.pretty.faces.url.URLPatternParser Maven / Gradle / Ivy

package com.ocpsoft.pretty.faces.url;

/*
 * PrettyFaces is an OpenSource JSF library to create bookmarkable URLs.
 * Copyright (C) 2009 - Lincoln Baxter, III  This program
 * is free software: you can redistribute it and/or modify it under the terms of
 * the GNU Lesser General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version. This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details. You should have received a copy of the GNU Lesser General
 * Public License along with this program. If not, see the file COPYING.LESSER
 * or visit the GNU website at .
 */
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.ocpsoft.pretty.PrettyException;
import com.ocpsoft.pretty.faces.config.mapping.PathParameter;
import com.ocpsoft.pretty.faces.el.ExpressionProcessorRunner;
import com.ocpsoft.pretty.faces.el.Expressions;

/**
 * @author Lincoln Baxter, III 
 */
public class URLPatternParser
{
   private final String originalPattern;
   private URL urlPattern = null;
   private List pathSegments = new ArrayList();
   private List pathParameters = new ArrayList();

   /**
    * Set the pattern for which this parser will match. Find and replace all el
    * expressions with regular expressions to extract values from parsed URLs.
    * Also extract all parameter names from expressions, and replace with valid
    * EL
    * 
    * @param pattern Pattern to use as a parse template
    */
   public URLPatternParser(final String pattern)
   {
      originalPattern = pattern;
      Matcher matcher = Pattern.compile(Expressions.EL_REGEX).matcher(pattern);
      StringBuffer segmentableExpressions = new StringBuffer();

      /*
       * Extract path parameters
       */
      int paramIndex = 0;
      while (matcher.find())
      {
         String expression = matcher.group(1);
         PathParameter param = ExpressionProcessorRunner.process(expression);
         param.setPosition(paramIndex);
         pathParameters.add(param);

         matcher.appendReplacement(segmentableExpressions, param.getExpression());
         paramIndex++;
      }
      matcher.appendTail(segmentableExpressions);
      this.pathParameters = Collections.unmodifiableList(pathParameters);

      URL segmentedPattern = new URL(segmentableExpressions.toString());

      /*
       * Extract path segments, overlaying regexes found during parameter
       * discovery.
       */
      int segmentIndex = 0;
      paramIndex = 0;
      for (String segment : segmentedPattern.getSegments())
      {
         PathParameter seg = ExpressionProcessorRunner.process(segment);
         seg.setPosition(segmentIndex);
         if (!seg.expressionIsPlainText())
         {
            /*
             * Overlay the custom parameter regex
             */
            seg.setRegex(pathParameters.get(paramIndex).getRegex());
            seg.setName(pathParameters.get(paramIndex).getName());
            paramIndex++;
         }

         pathSegments.add(seg);
         segmentIndex++;
      }

      List regexSegments = new ArrayList();
      for (PathParameter p : pathSegments)
      {
         regexSegments.add(p.getRegex());
      }

      urlPattern = new URL(regexSegments, segmentedPattern.getMetadata().copy());
      this.pathSegments = Collections.unmodifiableList(pathSegments);
   }

   /**
    * Return true if this parser matches the given URL, otherwise, return false.
    */
   public boolean matches(final URL target)
   {
      boolean result = true;
      if ((target.numSegments() == urlPattern.numSegments()) && (urlPattern.getMetadata().hasTrailingSlash() == target.getMetadata().hasTrailingSlash()))
      {
         List urlSegments = target.getDecodedSegments();
         List patternSegments = urlPattern.getSegments();
         for (int i = 0; i < urlPattern.numSegments(); i++)
         {
            if (!Pattern.compile(patternSegments.get(i)).matcher(urlSegments.get(i)).matches())
            {
               result = false;
               break;
            }
         }
      }
      else
      {
         result = false;
      }
      return result;
   }

   /**
    * Return true if this parser matches the given URL, otherwise, return false.
    */
   @Deprecated
   public boolean matches(final String target)
   {
      URL url = new URL(target);
      return matches(url);
   }

   /**
    * Return the list of parameters specified by this pattern.
    */
   public List getPathParameters()
   {
      return pathParameters;
   }

   /**
    * Builds a list of PathParameters for this UrlPattern, extracted from the
    * provided URL (assuming a match is found). This list excludes duplicate
    * named parameters.
    */
   public List parse(final URL url)
   {
      List result = new ArrayList();
      if (this.matches(url))
      {
         List urlSegments = url.getDecodedSegments();

         int paramIndex = 0;
         for (int i = 0; i < pathSegments.size(); i++)
         {
            PathParameter template = pathSegments.get(i);

            if (i != template.getPosition())
            {
               throw new PrettyException("Error parsing url: <" + url + ">, parameter order did not match compiled order.");
            }

            PathParameter parm = template.copy();
            parm.setPosition(paramIndex);
            parm.setValue(urlSegments.get(i));

            if (!parm.expressionIsPlainText())
            {
               result.add(parm);
               paramIndex++;
            }
         }
      }
      else
      {
         throw new IllegalArgumentException("The given URL: " + url + ", cannot be parsed by the pattern: " + urlPattern);
      }
      return result;
   }

   /**
    * URL encoding/decoding is not a concern of this method.
    * 
    * @param params Array of Object parameters, in order, to be substituted for
    *           mapping pattern values or el expressions. This method will call
    *           the toString() method on each object provided.
    *           

* If only one param is specified and it is an instance of List, * the list items will be used as parameters instead. An empty list * or a single null parameter are both treated as if no parameters * were specified. *

* E.g: getMappedUrl(12,55,"foo","bar") for a pattern of * /#{el.one}/#{el.two}/#{el.three}/#{el.four}/ will return the * String: "/12/55/foo/bar/" * @return A URL based on this object's urlPatten, with values substituted * for el expressions in the order provided */ public String getMappedUrl(final Object... params) { URL result = null; if (params != null) { Object[] parameters = params; /* * Check to see if our parameters were provided as a single List */ if ((params.length == 1) && (params[0] != null) && (params[0] instanceof List)) { List list = (List) params[0]; if (list.size() == 0) { parameters = new Object[0]; } else { parameters = list.toArray(params); } } else if ((params.length == 1) && (params[0] == null)) { parameters = new Object[0]; } /* * Assert that we have the proper number of parameters. */ if (getParameterCount() != parameters.length) { throw new PrettyException("Invalid number of parameters supplied for pattern: " + originalPattern + ", expected <" + getParameterCount() + ">, got <" + parameters.length + ">"); } /* * Build the result URL */ int paramIndex = 0; List resultSegments = new ArrayList(); for (PathParameter segment : pathSegments) { if (segment.expressionIsPlainText()) { resultSegments.add(segment.getRegex()); } else { resultSegments.add(parameters[paramIndex].toString()); paramIndex++; } } result = new URL(resultSegments, urlPattern.getMetadata()); } else if (getParameterCount() > 0) { throw new PrettyException("Invalid number of parameters supplied: " + originalPattern + ", expected <" + getParameterCount() + ">, got <0>"); } return result.getURL(); } /** * Get the number of URL parameters that this parser expects to find in any * given input string * * @return Number of parameters */ public int getParameterCount() { return pathParameters.size(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy