1 package net.avcompris.commons3.api.tests;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4 import static org.apache.commons.lang3.StringUtils.substringAfter;
5 import static org.apache.commons.lang3.StringUtils.substringBefore;
6
7 import java.lang.reflect.Method;
8
9 import javax.annotation.Nullable;
10
11 import org.apache.commons.lang3.NotImplementedException;
12 import org.springframework.web.bind.annotation.RequestMapping;
13
14 import net.avcompris.commons3.api.tests.TestsSpec.HttpMethod;
15 import net.avcompris.commons3.web.AbstractController;
16
17 public abstract class ControllerContextUtils {
18
19 public static ControllerContext extractControllerContext(
20 final HttpMethod httpMethod, final String uri,
21 final Class<? extends AbstractController> controllerClass) {
22
23 checkNotNull(httpMethod, "httpMethod");
24 checkNotNull(uri, "uri");
25 checkNotNull(controllerClass, "controllerClass");
26
27 final String path;
28 final String query;
29
30 if (uri.contains("?")) {
31
32 path = substringBefore(uri, "?");
33 query = substringAfter(uri, "?");
34
35 } else {
36
37 path = uri;
38 query = null;
39 }
40
41
42
43 for (final Method method : controllerClass.getMethods()) {
44
45 final RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
46
47 if (requestMapping == null) {
48 continue;
49 } else if (!httpMethod.name().contentEquals(requestMapping.method()[0].name())) {
50 continue;
51 }
52
53 final String requestMappingPath = requestMapping.value()[0];
54
55 if (requestMappingPath.contains("{")) {
56 continue;
57 }
58
59 if (path.contentEquals(requestMappingPath)) {
60
61 final ControllerContext context = new ControllerContext(
62 controllerClass,
63 method);
64
65 return populateWithQuery(context, query);
66 }
67 }
68
69
70
71 methods: for (final Method method : controllerClass.getMethods()) {
72
73 final RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
74
75 if (requestMapping == null) {
76 continue;
77 } else if (!httpMethod.name().contentEquals(requestMapping.method()[0].name())) {
78 continue;
79 }
80
81 final String requestMappingPath = requestMapping.value()[0];
82
83 if (!requestMappingPath.contains("{")) {
84 continue;
85 }
86
87 final int start = requestMappingPath.indexOf("{");
88
89 if (!path.startsWith(requestMappingPath.substring(0, start))) {
90 continue methods;
91 }
92
93 int pathVariableOffset = start;
94
95 final ControllerContext context = new ControllerContext(
96 controllerClass,
97 method);
98
99 for (int variableOffset = start;;) {
100
101 final int variableEnd = requestMappingPath.indexOf("}", variableOffset) + 1;
102
103 final String suffix = requestMappingPath.substring(variableEnd);
104
105 final String variableName = requestMappingPath.substring(variableOffset + 1, variableEnd - 1);
106
107 if (!suffix.contains("{")) {
108
109 final String variableValue;
110
111 if (suffix.isEmpty()) {
112
113 variableValue = path.substring(pathVariableOffset);
114
115 } else if (path.length() >= variableOffset + suffix.length() && path.endsWith(suffix)) {
116
117 variableValue = path.substring(pathVariableOffset, path.length() - suffix.length());
118
119 } else {
120
121 continue methods;
122 }
123
124 if (variableValue.contains("/")) {
125
126 continue methods;
127 }
128
129 context.addVariable(variableName, variableValue);
130
131 break;
132 }
133
134 variableOffset = requestMappingPath.indexOf("{", variableEnd);
135
136 final String fragment = requestMappingPath.substring(variableEnd, variableOffset);
137
138 if (fragment.isEmpty()
139 || fragment.charAt(0) != '/'
140 || fragment.charAt(fragment.length() - 1) != '/') {
141
142 throw new NotImplementedException("requestMappingPath: " + requestMappingPath);
143 }
144
145 final String variableValue;
146
147 final int pathVariableEnd = path.indexOf("/", pathVariableOffset);
148
149 if (pathVariableEnd == -1) {
150 continue methods;
151 }
152
153 variableValue = path.substring(pathVariableOffset, pathVariableEnd);
154
155 pathVariableOffset = pathVariableEnd + variableOffset - variableEnd;
156
157 final String pathFragment = path.substring(pathVariableEnd, pathVariableOffset);
158
159 context.addVariable(variableName, variableValue);
160
161 if (!pathFragment.contentEquals(fragment)) {
162
163 continue methods;
164 }
165 }
166
167 return context;
168 }
169
170
171
172 return null;
173 }
174
175 private static ControllerContext populateWithQuery(final ControllerContext context, @Nullable final String query) {
176
177 if (query == null) {
178
179 return context;
180 }
181
182 if (query.contains("&")) {
183 throw new NotImplementedException("query: " + query);
184 }
185
186 final String variableName = substringBefore(query, "=");
187 final String variableValue = substringAfter(query, "=").replace('+', ' ');
188
189 context.addVariable(variableName, variableValue);
190
191 return context;
192 }
193 }