Skip to content

Commit

Permalink
save
Browse files Browse the repository at this point in the history
  • Loading branch information
envimate-opensource committed Jun 23, 2019
1 parent 70a1667 commit 907395e
Show file tree
Hide file tree
Showing 38 changed files with 717 additions and 92 deletions.
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<parent>
<groupId>com.envimate</groupId>
<artifactId>httpmate-parent</artifactId>
<version>1.0.21</version>
<version>1.0.22</version>
</parent>

<groupId>com.envimate.httpmate</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import lombok.RequiredArgsConstructor;
import lombok.ToString;

import static com.envimate.httpmate.chains.graph.Color.BLACK;
import static com.envimate.httpmate.chains.graph.Label.emptyLabel;
import static com.envimate.httpmate.util.Validators.validateNotNull;
import static java.lang.String.format;

Expand All @@ -38,6 +40,11 @@ public final class Edge {
private final Color color;
private final Label label;

public static Edge edge(final Node from,
final Node to) {
return edge(from, to, BLACK, emptyLabel());
}

public static Edge edge(final Node from,
final Node to,
final Color color,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import lombok.RequiredArgsConstructor;
import lombok.ToString;

import static com.envimate.httpmate.chains.graph.Color.BLACK;
import static com.envimate.httpmate.chains.graph.Label.textLabel;
import static com.envimate.httpmate.util.Validators.validateNotNull;
import static com.envimate.httpmate.util.Validators.validateNotNullNorEmpty;
Expand All @@ -39,6 +40,10 @@ public final class Node {
private final Label label;
private final Color color;

public static Node node(final String name) {
return node(name, BLACK);
}

public static Node node(final String name,
final Color color) {
return node(name, textLabel(name), color);
Expand Down
53 changes: 53 additions & 0 deletions core/src/main/java/com/envimate/httpmate/path/AnyMatcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2019 envimate GmbH - https://envimate.com/.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.envimate.httpmate.path;

import com.envimate.httpmate.path.statemachine.StateMachineMatcher;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;

import java.util.Map;
import java.util.Optional;

@EqualsAndHashCode
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class AnyMatcher implements StateMachineMatcher<String> {

static boolean isRecursiveWildcard(final String stringSpecification) {
return "*".equals(stringSpecification);
}

static StateMachineMatcher<String> anyMatcher() {
return new AnyMatcher();
}

@Override
public Optional<Map<String, String>> matchAndReturnCaptures(final String element) {
return Optional.of(Map.of());
}

@Override
public String toString() {
return "*";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@

package com.envimate.httpmate.path;

import com.envimate.httpmate.path.statemachine.StateMachineMatcher;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -34,7 +37,7 @@
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
final class WildcardPathTemplateElement implements PathTemplateElement {
final class CaptureMatcher implements StateMachineMatcher<String> {

private static final Pattern PATTERN = Pattern.compile("<(.*)>");
private final String name;
Expand All @@ -44,22 +47,18 @@ static boolean isWildcard(final String stringSpecification) {
return matcher.matches();
}

static PathTemplateElement fromStringSpecification(final String stringSpecification) {
static StateMachineMatcher<String> fromStringSpecification(final String stringSpecification) {
validateNotNullNorEmpty(stringSpecification, "stringSpecification");
final Matcher matcher = PATTERN.matcher(stringSpecification);
if(!matcher.matches()) {
throw new RuntimeException("Not a wildcard: " + stringSpecification);
}
final String name = matcher.group(1);
return new WildcardPathTemplateElement(name);
return new CaptureMatcher(name);
}

@Override
public boolean matches(final String pathElement) {
return true;
}

public String getName() {
return this.name;
public Optional<Map<String, String>> matchAndReturnCaptures(final String element) {
return Optional.of(Map.of(name, element));
}
}
89 changes: 48 additions & 41 deletions core/src/main/java/com/envimate/httpmate/path/PathTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,79 +21,86 @@

package com.envimate.httpmate.path;

import com.envimate.httpmate.path.statemachine.*;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.envimate.httpmate.path.AnyMatcher.isRecursiveWildcard;
import static com.envimate.httpmate.path.AnyMatcher.anyMatcher;
import static com.envimate.httpmate.path.CaptureMatcher.isWildcard;
import static com.envimate.httpmate.path.statemachine.ElementPosition.start;
import static com.envimate.httpmate.path.statemachine.StateMachineBuilder.stateMachineBuilder;
import static com.envimate.httpmate.path.statemachine.Transition.transition;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

@EqualsAndHashCode
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class PathTemplate {

private final List<PathTemplateElement> templateElements;
private final List<String> elements;
private final StateMachine<String> stateMachine;

public static PathTemplate pathTemplate(final String asString) {
final String[] elementsAsStrings = splitIntoElements(asString);
final List<PathTemplateElement> elements = stream(elementsAsStrings)
.map(PathTemplateElement::fromStringSpecification)
final List<String> elementsAsStrings = splitIntoElements(asString);
final List<StateMachineMatcher<String>> matchers = elementsAsStrings.stream()
.map(PathTemplate::elementFromStringSpecification)
.collect(toList());
return new PathTemplate(elements);

final StateMachineBuilder<String> stateMachineBuilder = stateMachineBuilder();
State currentState = stateMachineBuilder.createState();
for(final StateMachineMatcher<String> matcher : matchers) {
if(matcher instanceof AnyMatcher) {
stateMachineBuilder.addTransition(currentState, transition(matcher, currentState));
} else {
final State nextState = stateMachineBuilder.createState();
stateMachineBuilder.addTransition(currentState, transition(matcher, nextState));
currentState = nextState;
}
}
stateMachineBuilder.markAsFinal(currentState);
final StateMachine<String> stateMachine = stateMachineBuilder.build();

return new PathTemplate(elementsAsStrings, stateMachine);
}

public boolean matches(final Path path) {
return match(path).isSuccessful();
}

public Map<String, String> extractPathParameters(final Path path) {
return match(path).captures();
}

private MatchingResult match(final Path path) {
final String raw = path.raw();
final String[] elementsAsStrings = splitIntoElements(raw);
final int numberOfElements = elementsAsStrings.length;
if(this.templateElements.size() != numberOfElements) {
return false;
}
for(int i = 0; i < numberOfElements; ++i) {
final PathTemplateElement pathTemplateElement = this.templateElements.get(i);
final String pathElement = elementsAsStrings[i];
if(!pathTemplateElement.matches(pathElement)) {
return false;
}
}
return true;
final List<String> elementsAsStrings = splitIntoElements(raw);
final ElementPosition<String> inputPosition = start(elementsAsStrings);
return stateMachine.accept(inputPosition);
}

public String toString() {
return this.templateElements
.stream()
.map(PathTemplateElement::toString)
return this.elements.stream()
.collect(joining("/", "/", ""));
}

public Map<String, String> extractPathParameters(final Path path) {
if(!matches(path)) {
throw new RuntimeException("Can only extract path parameters from matching paths.");
private static StateMachineMatcher<String> elementFromStringSpecification(final String stringSpecification) {
if (isRecursiveWildcard(stringSpecification)) {
return anyMatcher();
}
final String[] elements = splitIntoElements(path.raw());
final Map<String, String> pathParameters = new HashMap<>();
final int length = elements.length;
for(int i = 0; i < length; i++) {
final PathTemplateElement templateElement = this.templateElements.get(i);
if(!(templateElement instanceof WildcardPathTemplateElement)) {
continue;
}
final WildcardPathTemplateElement wildcardTemplateElement = (WildcardPathTemplateElement) templateElement;
final String name = wildcardTemplateElement.getName();
final String value = elements[i];
pathParameters.put(name, value);
if (isWildcard(stringSpecification)) {
return CaptureMatcher.fromStringSpecification(stringSpecification);
}
return pathParameters;
return StaticMatcher.fromStringSpecification(stringSpecification);
}

private static String[] splitIntoElements(final String pathAsString) {
private static List<String> splitIntoElements(final String pathAsString) {
return stream(pathAsString.split("/"))
.filter(string -> !string.isEmpty())
.toArray(String[]::new);
.collect(toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,32 @@

package com.envimate.httpmate.path;

import com.envimate.httpmate.path.statemachine.StateMachineMatcher;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;

import java.util.Map;
import java.util.Optional;

import static com.envimate.httpmate.util.Validators.validateNotNullNorEmpty;

@EqualsAndHashCode
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
final class StaticPathTemplateElement implements PathTemplateElement {
final class StaticMatcher implements StateMachineMatcher<String> {
private final String value;

static PathTemplateElement fromStringSpecification(final String stringSpecification) {
static StateMachineMatcher<String> fromStringSpecification(final String stringSpecification) {
validateNotNullNorEmpty(stringSpecification, "stringSpecification");
return new StaticPathTemplateElement(stringSpecification);
return new StaticMatcher(stringSpecification);
}

@Override
public boolean matches(final String pathElement) {
return this.value.equals(pathElement);
public Optional<Map<String, String>> matchAndReturnCaptures(final String element) {
if(this.value.equals(element)) {
return Optional.of(Map.of());
}
return Optional.empty();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2019 envimate GmbH - https://envimate.com/.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.envimate.httpmate.path.statemachine;

import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

import java.util.List;

@ToString
@EqualsAndHashCode
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class ElementPosition<T> {
private final int index;
private final List<T> elements;

public static <T> ElementPosition<T> start(final List<T> elements) {
return new ElementPosition<>(0, elements);
}

public boolean isEnd() {
return elements.size() <= index;
}

public ElementPosition<T> next() {
return new ElementPosition<>(index + 1, elements);
}

public T get() {
if (isEnd()) {
throw new IndexOutOfBoundsException();
}
return elements.get(index);
}
}
Loading

0 comments on commit 907395e

Please sign in to comment.