blob: 66fe6d8464ca9749f96468ca5d021d381fd28d7d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.server.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
/**
* Utility class used to match the path of the services and the path of the
* requests.
*
* @author sbegaudeau
*/
public class SiriusServerPathMatcher {
/**
* The separator of the segments of the path.
*/
private static final char SLASH = '/';
/**
* The start of a variable.
*/
private static final char VARIABLE_START = '{';
/**
* The end of a variable.
*/
private static final char VARIABLE_END = '}';
/**
* The regular expression used to capture the variables of the path.
*/
private static final String VARIABLE_REGEXP = "([^/]+?)"; //$NON-NLS-1$
/**
* The regular expression used to capture the remaining content of the path.
*/
private static final String REMAINING_PATH_REGEXP = "(.*)"; //$NON-NLS-1$
/**
* The list of the variables expected in the path.
*/
private List<String> variableNames = new ArrayList<>();
/**
* The pattern used to match the path.
*/
private Pattern pathPattern;
/**
* The constructor.
*
* @param path
* The path
*/
public SiriusServerPathMatcher(String path) {
this.initialize(path);
}
/**
* Initializes the {@link SiriusServerPathMatcher}.
*
* @param path
* The path to match
*/
private void initialize(String path) {
StringBuilder stringBuilder = new StringBuilder();
int startIndex = this.computeStartIndex(path);
int index = startIndex;
while (index < path.length()) {
char character = path.charAt(index);
if (VARIABLE_START == character) {
int variableEndIndex = path.indexOf(VARIABLE_END, index);
String variable = path.substring(index + 1, variableEndIndex);
this.variableNames.add(variable);
stringBuilder.append(VARIABLE_REGEXP);
index = variableEndIndex + 1;
} else {
stringBuilder.append(character);
index = index + 1;
}
}
if (!path.endsWith(String.valueOf(SLASH))) {
stringBuilder.append(SLASH);
}
stringBuilder.append(REMAINING_PATH_REGEXP);
this.pathPattern = Pattern.compile(stringBuilder.toString());
}
/**
* Returns the index to consider to start the analysis of the given path.
*
* @param path
* The path
* @return 0 if the path does not start with a slash, 1 otherwise
*/
private int computeStartIndex(String path) {
if (path.length() > 0 && SLASH == path.charAt(0)) {
return 1;
}
return 0;
}
/**
* Matches the path of the request against the path of the matcher.
*
* @param requestPath
* The path of the request
* @return A {@link SiriusServerMatchResult}
*/
public SiriusServerMatchResult match(String requestPath) {
String path = requestPath;
if (path.length() > 0 && SLASH == path.charAt(0)) {
path = path.substring(1);
}
if (path.length() > 0 && SLASH != path.charAt(path.length() - 1)) {
path = path + SLASH;
}
Matcher matcher = this.pathPattern.matcher(path);
Map<String, String> variables = new HashMap<>();
String remainingPart = ""; //$NON-NLS-1$
if (matcher.matches()) {
if (this.variableNames.size() <= matcher.groupCount()) {
IntStream.range(1, matcher.groupCount()).forEach(index -> {
String variable = this.variableNames.get(index - 1);
variables.put(variable, matcher.group(index));
});
}
if (matcher.groupCount() > 0) {
remainingPart = matcher.group(matcher.groupCount());
if (remainingPart.length() > 0 && SLASH == remainingPart.charAt(remainingPart.length() - 1)) {
remainingPart = remainingPart.substring(0, remainingPart.length() - 1);
}
}
}
return new SiriusServerMatchResult(variables, remainingPart, matcher.matches());
}
}