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

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

There is a newer version: 3.3.3
Show newest version
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.Iterator;
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 expressionMatcher = Pattern.compile(Expressions.EL_REGEX).matcher(pattern);
      StringBuffer segmentableExpressions = new StringBuffer();

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

         expressionMatcher.appendReplacement(segmentableExpressions, Segment.parameterize(paramIndex));
         paramIndex++;
      }
      expressionMatcher.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;
      for (String segmentPattern : segmentedPattern.getSegments())
      {
         Segment segment = new Segment();
         segment.setTemplate(segmentPattern);
         StringBuffer regex = new StringBuffer();

         Matcher parameterMatcher = Segment.getTemplateMatcher(segmentPattern);
         while (parameterMatcher.find())
         {
            String group = parameterMatcher.group(1);
            PathParameter parameter = pathParameters.get(Integer.valueOf(group));
            segment.addParameter(parameter);
            parameterMatcher.appendReplacement(regex, "(" + parameter.getRegex() + ")");
         }
         parameterMatcher.appendTail(regex);

         segment.setRegex(regex.toString());
         pathSegments.add(segment);
         segmentIndex++;
      }

      List regexSegments = new ArrayList();
      for (Segment s : pathSegments)
      {
         regexSegments.add(s.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)
   {
      return Pattern.compile(urlPattern.getURL()).matcher(target.getURL()).matches();
   }

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

      String inboundUrl = url.getURL();
      if (this.matches(url))
      {
         Iterator iter = pathSegments.iterator();
         while (iter.hasNext())
         {
            Segment segment = iter.next();
            String regex = segment.getRegex();
            if (iter.hasNext() || url.hasTrailingSlash())
            {
               regex += "/";
            }

            Matcher segmentMatcher = Pattern.compile(regex).matcher(inboundUrl);
            if (!segmentMatcher.find())
            {
               throw new PrettyException("Error parsing url: <" + url
                           + ">, a parameter did not match compiled segment in pattern: " + originalPattern);
            }

            String chunk = regex;
            for (int j = 0; j < segment.numParameters(); j++)
            {
               chunk = segmentMatcher.group(0);
               String value = segmentMatcher.group(j + 1);
               PathParameter param = segment.getParameter(j).copy();
               param.setValue(value);
               result.add(param);
            }

            inboundUrl = inboundUrl.substring(inboundUrl.indexOf(chunk) + chunk.length());
         }
      }
      else
      {
         throw new IllegalArgumentException("The given URL: " + url + ", cannot be parsed by the pattern: "
                  + originalPattern);
      }
      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 URL 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 (Segment segment : pathSegments) { String template = segment.getTemplate(); Matcher parameterMatcher = Segment.getTemplateMatcher(template); StringBuffer sb = new StringBuffer(); while (parameterMatcher.find()) { parameterMatcher.appendReplacement(sb, parameters[paramIndex].toString()); paramIndex++; } parameterMatcher.appendTail(sb); resultSegments.add(sb.toString()); } 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; } /** * 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