/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* 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
*******************************************************************************/
package org.ebayopensource.turmeric.runtime.common.impl.internal.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author ichernyshev
*/
public class RequestPatternMatcher<E> {
private final boolean m_caseSensitive;
private ArrayList<RequestPattern<E>> m_patterns = new ArrayList<RequestPattern<E>>();
public RequestPatternMatcher(boolean caseSensitive) {
m_caseSensitive = caseSensitive;
}
public E findTarget(String uri, Map<String,String> headers) {
return findTarget(uri, headers, false);
}
public E findTarget(String uri, Map<String,String> headers, boolean allowMany) {
E result = null;
for (int i=0; i<m_patterns.size(); i++) {
RequestPattern<E> pattern = m_patterns.get(i);
E result2 = pattern.match(uri, headers);
if (result2 != null) {
if (allowMany) {
result = result2;
break;
}
if (result != null) {
// this is the second pattern match, which is not allowed
// TODO: throw an exception here
return null;
}
result = result2;
}
}
return result;
}
public void addUriPattern(String uriPattern, E target) {
addPattern(new RequestPatternUriRegex<E>(uriPattern, target, m_caseSensitive));
}
public void addHeaderPattern(String headerName, String headerValue, E target)
{
// header name is always case-insensitive
headerName = headerName.toUpperCase();
if (!m_caseSensitive && headerValue != null) {
headerValue = headerValue.toUpperCase();
}
int idx = findHeaderValuePattern(headerName);
if (idx == -1) {
Map<String,E> headerValues = new HashMap<String,E>();
headerValues.put(headerValue, target);
addPattern(new RequestPatternHeaderValue<E>(headerName, headerValues));
return;
}
RequestPatternHeaderValue<E> oldPattern = (RequestPatternHeaderValue<E>)m_patterns.get(idx);
RequestPatternHeaderValue<E> newPattern = new RequestPatternHeaderValue<E>(
oldPattern, headerValue, target);
replacePattern(idx, newPattern);
}
private int findHeaderValuePattern(String headerName)
{
for (int i=0; i<m_patterns.size(); i++) {
RequestPattern<E> result = m_patterns.get(i);
if (!(result instanceof RequestPatternHeaderValue)) {
continue;
}
RequestPatternHeaderValue<E> result2 = (RequestPatternHeaderValue<E>)result;
if (result2.getHeaderName().equals(headerName)) {
return i;
}
}
return -1;
}
private void addPattern(RequestPattern<E> pattern)
{
ArrayList<RequestPattern<E>> patterns = new ArrayList<RequestPattern<E>>(m_patterns.size() + 1);
patterns.addAll(m_patterns);
patterns.add(pattern);
m_patterns = patterns;
}
private void replacePattern(int idx, RequestPattern<E> pattern)
{
ArrayList<RequestPattern<E>> patterns = new ArrayList<RequestPattern<E>>(m_patterns.size());
patterns.addAll(m_patterns);
patterns.set(idx, pattern);
m_patterns = patterns;
}
static abstract class RequestPattern<E> {
public abstract E match(String uri, Map<String,String> headers);
}
static class RequestPatternUriRegex<E> extends RequestPattern<E> {
private final Pattern m_uriPattern;
private final E m_target;
public RequestPatternUriRegex(String uriPattern, E target, boolean caseSensitive)
{
if (uriPattern == null || target == null) {
throw new NullPointerException();
}
int flags = 0;
if (!caseSensitive) {
flags |= Pattern.CASE_INSENSITIVE;
}
m_uriPattern = Pattern.compile(uriPattern, flags);
m_target = target;
}
@Override
public E match(String uri, Map<String,String> headers) {
if (uri == null) {
return null;
}
Matcher matcher = m_uriPattern.matcher(uri);
if (matcher.matches()) {
return m_target;
}
return null;
}
}
static class RequestPatternHeaderValue<E> extends RequestPattern<E> {
private final String m_headerName;
private final Map<String,E> m_headerValues;
public RequestPatternHeaderValue(String headerName,
Map<String,E> headerValues)
{
if (headerName == null || headerValues == null) {
throw new NullPointerException();
}
for (Iterator<Map.Entry<String,E>> it=headerValues.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String,E> e = it.next();
if (e.getKey() == null || e.getValue() == null) {
throw new NullPointerException();
}
}
m_headerName = headerName;
m_headerValues = headerValues;
}
public RequestPatternHeaderValue(RequestPatternHeaderValue<E> oldPattern,
String newHeaderValue, E newTarget)
{
if (newHeaderValue == null || newTarget == null) {
throw new NullPointerException();
}
m_headerName = oldPattern.m_headerName;
m_headerValues = new HashMap<String,E>(oldPattern.m_headerValues);
m_headerValues.put(newHeaderValue, newTarget);
}
public String getHeaderName() {
return m_headerName;
}
@Override
public E match(String uri, Map<String,String> headers) {
if (headers == null) {
return null;
}
String otherValue = headers.get(m_headerName);
if (otherValue == null) {
return null;
}
E result = m_headerValues.get(otherValue);
if (result == null) {
// TODO: throw an exception indicating unknown header value
}
return result;
}
}
}