1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.linecorp.centraldogma.common;
17
18 import static com.google.common.base.Preconditions.checkArgument;
19
20 import java.util.Set;
21 import java.util.regex.Pattern;
22 import java.util.stream.Collectors;
23
24 import javax.annotation.Nullable;
25
26 import com.google.common.annotations.VisibleForTesting;
27 import com.google.common.base.MoreObjects;
28 import com.google.common.math.IntMath;
29
30 final class DefaultPathPattern implements PathPattern {
31
32 private static final Pattern PATH_PATTERN_PATTERN = Pattern.compile("^[- /*_.0-9a-zA-Z]+$");
33
34 static final String ALL = "/**";
35
36 static final DefaultPathPattern allPattern = new DefaultPathPattern(ALL, ALL);
37
38 private final String patterns;
39
40 @Nullable
41 private String encoded;
42
43 DefaultPathPattern(Set<String> patterns) {
44 this.patterns = patterns.stream()
45 .peek(DefaultPathPattern::validatePathPattern)
46 .filter(pattern -> !pattern.isEmpty())
47 .map(pattern -> {
48 if (pattern.charAt(0) != '/') {
49 return "/**/" + pattern;
50 }
51 return pattern;
52 }).collect(Collectors.joining(","));
53 }
54
55 private DefaultPathPattern(String patterns, String encoded) {
56 this.patterns = patterns;
57 this.encoded = encoded;
58 }
59
60 @Override
61 public String patternString() {
62 return patterns;
63 }
64
65 @Override
66 public String encoded() {
67 if (encoded != null) {
68 return encoded;
69 }
70 return encoded = encodePathPattern(patterns);
71 }
72
73 @VisibleForTesting
74 static String encodePathPattern(String pathPattern) {
75
76
77 int spacePos = pathPattern.indexOf(' ');
78 if (spacePos < 0) {
79 return pathPattern;
80 }
81
82 final StringBuilder buf = new StringBuilder(IntMath.saturatedMultiply(pathPattern.length(), 2));
83 for (int pos = 0;;) {
84 buf.append(pathPattern, pos, spacePos);
85 buf.append("%20");
86 pos = spacePos + 1;
87 spacePos = pathPattern.indexOf(' ', pos);
88 if (spacePos < 0) {
89 buf.append(pathPattern, pos, pathPattern.length());
90 break;
91 }
92 }
93
94 return buf.toString();
95 }
96
97 private static String validatePathPattern(String pattern) {
98 checkArgument(PATH_PATTERN_PATTERN.matcher(pattern).matches(),
99 "pattern: %s (expected: %s)", pattern, PATH_PATTERN_PATTERN);
100 return pattern;
101 }
102
103 @Override
104 public String toString() {
105 return MoreObjects.toStringHelper(this)
106 .add("patterns", patterns)
107 .add("encoded", encoded)
108 .toString();
109 }
110 }