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