package org.jboss.pitbull.internal.util.registry;
import org.jboss.pitbull.internal.util.PathHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public abstract class ParentSegment<T> extends Segment<T>
{
protected Map<String, SimpleSegment> simpleSegments = new HashMap<String, SimpleSegment>();
protected Map<String, PathParamSegment> pathParamSegments = new HashMap<String, PathParamSegment>();
protected List<PathParamSegment> sortedPathParamSegments = new ArrayList<PathParamSegment>();
/**
* returns a copied list of all child segments
*
* @return
*/
public List<Segment> getChildren()
{
List<Segment> children = new ArrayList<Segment>();
children.addAll(simpleSegments.values());
children.addAll(pathParamSegments.values());
return children;
}
protected static StringBuffer pullPathParamExpressions(String path, List<String> pathParamExpr)
{
// Regular expressions can have '{' and '}' characters. Replace them to do match
path = PathHelper.replaceEnclosedCurlyBraces(path);
Matcher matcher = PathHelper.URI_REGEX_PATTERN.matcher(path);
StringBuffer newPath = new StringBuffer();
while (matcher.find())
{
String regex = matcher.group(1);
// Regular expressions can have '{' and '}' characters. Recover original replacement
pathParamExpr.add(PathHelper.recoverEnclosedCurlyBraces(regex));
matcher.appendReplacement(newPath, "{x}");
}
matcher.appendTail(newPath);
return newPath;
}
protected static String putBackPathParamExpressions(String path, List<String> pathParamExpr)
{
Matcher matcher = PathHelper.URI_REGEX_PATTERN.matcher(path);
StringBuffer newPath = new StringBuffer();
int index = 0;
while (matcher.find())
{
String val = pathParamExpr.get(index++);
// double encode slashes, so that slashes stay where they are
val = val.replace("\\", "\\\\");
matcher.appendReplacement(newPath, "{" + val + "}");
}
matcher.appendTail(newPath);
return newPath.toString();
}
protected Segment addPath(String[] segments, int index, T resource)
{
String segment = segments[index];
// Regular expressions can have '{' and '}' characters. Replace them to do match
String replacedCurlySegment = PathHelper.replaceEnclosedCurlyBraces(segment);
Matcher withPathParam = PathHelper.URI_REGEX_PATTERN.matcher(replacedCurlySegment);
if (withPathParam.find())
{
String expression = recombineSegments(segments, index);
PathParamSegment segmentNode = pathParamSegments.get(expression);
if (segmentNode == null)
{
segmentNode = new PathParamSegment(expression);
pathParamSegments.put(segmentNode.getPathExpression(), segmentNode);
sortedPathParamSegments.add(segmentNode);
Collections.sort(sortedPathParamSegments);
segmentNode.setParent(this);
}
segmentNode.addMatch(resource);
return segmentNode;
}
else
{
SimpleSegment segmentNode = simpleSegments.get(segment);
if (segmentNode == null)
{
segmentNode = new SimpleSegment(segment);
segmentNode.setParent(this);
simpleSegments.put(segment, segmentNode);
}
if (segments.length > index + 1)
{
return segmentNode.addPath(segments, index + 1, resource);
}
else
{
segmentNode.addMatch(resource);
return segmentNode;
}
}
}
protected String recombineSegments(String[] segments, int index)
{
String expression = "";
boolean first = true;
for (int i = index; i < segments.length; i++)
{
if (first)
{
first = false;
}
else
{
expression += "/";
}
expression += segments[i];
}
return expression;
}
protected List<T> matchChildren(String path, int start)
{
String simpleSegment = null;
if (start == path.length())
{
simpleSegment = "";
}
else
{
int endOfSegmentIndex = path.indexOf('/', start);
if (endOfSegmentIndex > -1) simpleSegment = path.substring(start, endOfSegmentIndex);
else simpleSegment = path.substring(start);
}
RegistryFailure lastFailure = null;
SimpleSegment<T> segment = simpleSegments.get(simpleSegment);
if (segment != null)
{
try
{
return segment.matchSimple(path, start);
}
catch (RegistryFailure e)
{
lastFailure = e;
}
}
for (PathParamSegment<T> pathParamSegment : sortedPathParamSegments)
{
try
{
return pathParamSegment.matchPattern(path, start);
}
catch (RegistryFailure e)
{
// try and propagate matched path that threw non-404 responses, i.e. MethodNotAllowed, etc.
if (lastFailure == null || lastFailure instanceof NotFoundException) lastFailure = e;
}
}
if (lastFailure != null) throw lastFailure;
throw new NotFoundException("Could not find resource for relative : " + path);
}
protected List<T> matchMultiChildren(String path, int start)
{
List<T> list = new ArrayList<T>();
String simpleSegment = null;
if (start == path.length())
{
simpleSegment = "";
}
else
{
int endOfSegmentIndex = path.indexOf('/', start);
if (endOfSegmentIndex > -1) simpleSegment = path.substring(start, endOfSegmentIndex);
else simpleSegment = path.substring(start);
}
RegistryFailure lastFailure = null;
SimpleSegment<T> segment = simpleSegments.get(simpleSegment);
if (segment != null)
{
try
{
list.addAll(segment.matchMulti(path, start));
}
catch (RegistryFailure e)
{
lastFailure = e;
}
}
for (PathParamSegment<T> pathParamSegment : sortedPathParamSegments)
{
try
{
list.addAll(pathParamSegment.matchPattern(path, start));
}
catch (RegistryFailure e)
{
// try and propagate matched path that threw non-404 responses, i.e. MethodNotAllowed, etc.
if (lastFailure == null || lastFailure instanceof NotFoundException) lastFailure = e;
}
}
return list;
}
public List<T> matchMulti(String path, int start)
{
if (start < path.length() && path.charAt(start) == '/') start++;
return matchMultiChildren(path, start);
}
public List<T> match(String path, int start)
{
if (start < path.length() && path.charAt(start) == '/') start++;
return matchChildren(path, start);
}
}