com.ocpsoft.rewrite.bind.ParameterizedPattern Maven / Gradle / Ivy
/*
* Copyright 2011 Lincoln Baxter, III
*
* Licensed 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 com.ocpsoft.rewrite.bind;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.ocpsoft.rewrite.bind.parse.CaptureType;
import com.ocpsoft.rewrite.bind.parse.CapturingGroup;
import com.ocpsoft.rewrite.bind.parse.ParseTools;
import com.ocpsoft.rewrite.bind.util.Maps;
import com.ocpsoft.rewrite.context.EvaluationContext;
import com.ocpsoft.rewrite.event.Rewrite;
import com.ocpsoft.rewrite.param.Parameter;
import com.ocpsoft.rewrite.param.Parameterized;
/**
* An {@link Parameterized} regular expression {@link Pattern}.
*
* @author Lincoln Baxter, III
*/
public class ParameterizedPattern
{
private static final String DEFAULT_PARAMETER_PATTERN = ".*";
private Pattern pattern;
private final char[] chars;
private final Map params = new LinkedHashMap();
/**
* Create a new {@link ParameterizedPattern} instance with the default {@link CaptureType#BRACE} and parameter
* pattern of ".*".
*/
public ParameterizedPattern(final String pattern)
{
this(CaptureType.BRACE, DEFAULT_PARAMETER_PATTERN, pattern);
}
/**
* Create a new {@link ParameterizedPattern} instance with the default {@link CaptureType#BRACE}.
*/
public ParameterizedPattern(final String parameterPattern, final String pattern)
{
this(CaptureType.BRACE, parameterPattern, pattern);
}
/**
* Create a new {@link ParameterizedPattern} instance with the default parameter regex of ".*".
*/
public ParameterizedPattern(final CaptureType type, final String pattern)
{
this(type, DEFAULT_PARAMETER_PATTERN, pattern);
}
/**
* Create a new {@link ParameterizedPattern} instance.
*/
public ParameterizedPattern(final CaptureType type, final String parameterPattern, final String pattern)
{
chars = pattern.toCharArray();
if (chars.length > 0)
{
int cursor = 0;
while (cursor < chars.length)
{
switch (chars[cursor])
{
case '{':
int startPos = cursor;
CapturingGroup group = ParseTools.balancedCapture(chars, startPos, chars.length - 1, type);
cursor = group.getEnd();
params.put(new String(group.getCaptured()), new RegexParameter(group).matches(parameterPattern));
break;
default:
break;
}
cursor++;
}
}
}
/**
* Get all {@link Parameter} instances detected during expression parsing.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public Map> getParameters()
{
return (Map) params;
}
/**
* Use this expression to build a {@link String} from the given pattern. Extract needed values from registered
* {@link Binding} instances.
*/
public String build(final Rewrite event, final EvaluationContext context)
{
return build(extractBoundValues(event, context));
}
/**
* Use this expression to build a {@link String} from the given pattern and values.
*/
public String build(final Object... values)
{
if ((values == null) || (params.size() != values.length))
{
throw new IllegalArgumentException("Must supply [" + params.size() + "] values to build output string.");
}
return buildUnsafe(values);
}
/**
* Use this expression to build a {@link String} from the given pattern and values. Enforces that the number of
* values passed must equal the number of expression parameters.
*/
public String buildUnsafe(final Object... values)
{
StringBuilder builder = new StringBuilder();
CapturingGroup last = null;
int index = 0;
for (Entry entry : params.entrySet())
{
RegexParameter param = entry.getValue();
CapturingGroup capture = param.getCapture();
if ((last != null) && (last.getEnd() < capture.getStart()))
{
builder.append(Arrays.copyOfRange(chars, last.getEnd() + 1, capture.getStart()));
}
else if ((last == null) && (capture.getStart() > 0))
{
builder.append(Arrays.copyOfRange(chars, 0, capture.getStart()));
}
builder.append(values[index]);
last = capture;
}
if ((last != null) && (last.getEnd() < chars.length))
{
builder.append(Arrays.copyOfRange(chars, last.getEnd() + 1, chars.length));
}
else if (last == null)
{
builder.append(chars);
}
return builder.toString();
}
/**
* Use this expression to build a {@link String} from the given pattern and values. Enforces that the number of keys
* passed must equal the number of expression parameters.
*/
public String build(final Map> values)
{
if ((values == null) || (params.size() != values.size()))
{
throw new IllegalArgumentException("Must supply [" + params.size() + "] values to build output string.");
}
return buildUnsafe(values);
}
/**
* Use this expression to build a {@link String} from the given pattern and values.
*/
public String buildUnsafe(final Map> values)
{
StringBuilder builder = new StringBuilder();
CapturingGroup last = null;
Map pointers = new LinkedHashMap();
for (Entry entry : params.entrySet())
{
RegexParameter param = entry.getValue();
CapturingGroup capture = param.getCapture();
if ((last != null) && (last.getEnd() < capture.getStart()))
{
builder.append(Arrays.copyOfRange(chars, last.getEnd() + 1, capture.getStart()));
}
else if ((last == null) && (capture.getStart() > 0))
{
builder.append(Arrays.copyOfRange(chars, 0, capture.getStart()));
}
String name = param.getName();
int index = pointers.get(name) == null ? 0 : pointers.get(name);
builder.append(Maps.getListValue(values, name, index));
pointers.put(name, index++);
last = capture;
}
if ((last != null) && (last.getEnd() < chars.length))
{
builder.append(Arrays.copyOfRange(chars, last.getEnd() + 1, chars.length));
}
else if (last == null)
{
builder.append(chars);
}
return builder.toString();
}
/**
* Return true if this expression matches the given {@link String}.
*/
public boolean matches(final String value)
{
if (pattern == null)
{
StringBuilder patternBuilder = new StringBuilder();
CapturingGroup last = null;
for (Entry entry : params.entrySet())
{
RegexParameter param = entry.getValue();
CapturingGroup capture = param.getCapture();
if ((last != null) && (last.getEnd() < capture.getStart()))
{
patternBuilder.append(Arrays.copyOfRange(chars, last.getEnd() + 1, capture.getStart()));
}
else if ((last == null) && (capture.getStart() > 0))
{
patternBuilder.append(Arrays.copyOfRange(chars, 0, capture.getStart()));
}
patternBuilder.append('(');
patternBuilder.append(param.getPattern());
patternBuilder.append(')');
last = capture;
}
if ((last != null) && (last.getEnd() < chars.length))
{
patternBuilder.append(Arrays.copyOfRange(chars, last.getEnd() + 1, chars.length));
}
else if (last == null)
{
patternBuilder.append(chars);
}
pattern = Pattern.compile(patternBuilder.toString());
}
return pattern.matcher(value).matches();
}
/**
* Parses the given string if it matches this expression. Returns a {@link Parameter}-value map of parsed values.
*/
public Map, String[]> parseEncoded(final String path)
{
Map, String[]> values = new LinkedHashMap, String[]>();
String temp = path;
if (matches(path))
{
CapturingGroup last = null;
Set> entrySet = params.entrySet();
List> entries = new ArrayList>(entrySet);
for (int i = 0; i < entries.size(); i++)
{
Entry entry = entries.get(i);
RegexParameter param = entry.getValue();
CapturingGroup capture = param.getCapture();
if ((last != null) && (last.getEnd() < capture.getStart()))
{
temp = temp.substring(capture.getStart() - (last.getEnd() + 1));
}
else if ((last == null) && (capture.getStart() > 0))
{
temp = temp.substring(capture.getStart());
}
StringBuilder segmentBuilder = new StringBuilder();
segmentBuilder.append('(');
segmentBuilder.append(param.getPattern());
segmentBuilder.append(')');
if ((i + 1) < entries.size())
{
Entry next = entries.get(i + 1);
CapturingGroup nextCapture = next.getValue().getCapture();
char[] tail = Arrays.copyOfRange(chars, capture.getEnd() + 1, nextCapture.getStart());
segmentBuilder.append(tail);
}
else
{
char[] tail = Arrays.copyOfRange(chars, capture.getEnd() + 1, chars.length);
segmentBuilder.append(tail);
}
Pattern segmentPattern = Pattern.compile(segmentBuilder.toString() + ".*");
Matcher segmentMatcher = segmentPattern.matcher(temp);
if (segmentMatcher.matches())
{
String value = segmentMatcher.group(1);
Maps.addArrayValue(values, param, value);
temp = temp.substring(segmentMatcher.end(1));
}
last = capture;
}
}
return values;
}
/**
* Get the {@link Parameter} with the given name. Return null if no such {@link Parameter} exists.
*/
public Parameter getParameter(final String name)
{
return params.get(name);
}
/**
* Extract bound values from configured {@link Binding} instances. Return a {@link Map} of the extracted key-value
* pairs.
*/
private Map> extractBoundValues(final Rewrite event, final EvaluationContext context)
{
Map> result = new LinkedHashMap>();
for (Entry entry : params.entrySet())
{
String name = entry.getKey();
Parameter parameter = entry.getValue();
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy