Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Commit cfa37a5

Browse files
committed
performance improvement + reduce number of worker threads fix jooby-project#690
1 parent 665864d commit cfa37a5

File tree

21 files changed

+529
-264
lines changed

21 files changed

+529
-264
lines changed

coverage-report/src/test/java/org/jooby/issues/Issue128.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,21 @@ public class Issue128 extends ServerFeature {
1616

1717
@Test
1818
public void fakePutViaParamUrl() throws Exception {
19-
request().post("/fake/put?_method=put")
19+
request().post("/fake/put?_method=PUT")
2020
.expect("PUT");
2121
}
2222

2323
@Test
2424
public void fakePutViaFormParam() throws Exception {
2525
request().post("/fake/put")
26-
.form().add("_method", "PuT")
26+
.form().add("_method", "PUT")
2727
.expect("PUT");
2828
}
2929

3030
@Test
3131
public void fakePostViaHeader() throws Exception {
3232
request().post("/fake/put")
33-
.header("_method", "put")
33+
.header("_method", "PUT")
3434
.expect("PUT");
3535
}
3636

coverage-report/src/test/java/org/jooby/issues/Issue346.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66
import java.lang.annotation.Retention;
77
import java.lang.annotation.RetentionPolicy;
88
import java.lang.annotation.Target;
9+
import java.util.HashMap;
10+
import java.util.Map;
911

1012
import org.jooby.Request;
1113
import org.jooby.mvc.GET;
1214
import org.jooby.mvc.Path;
1315
import org.jooby.test.ServerFeature;
1416
import org.junit.Test;
1517

18+
import com.google.common.collect.ImmutableMap;
19+
1620
public class Issue346 extends ServerFeature {
1721

1822
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@@ -56,30 +60,52 @@ public Object admin(final Request req) {
5660

5761
{
5862
use("/1", (req, rsp) -> {
59-
assertEquals("{priority=1.0, changefreq=always}", req.route().attributes().toString());
63+
assertEquals(ImmutableMap.of("priority", 1.0, "changefreq", "always"),
64+
req.route().attributes());
6065
});
6166

6267
use("/2", (req, rsp) -> {
63-
assertEquals("{priority=0.5, changefreq=always}", req.route().attributes().toString());
68+
assertEquals(ImmutableMap.of("priority", 0.5, "changefreq", "always"),
69+
req.route().attributes());
6470
});
6571

6672
use("/3", (req, rsp) -> {
67-
assertEquals("{role=admin, priority=0.5, changefreq=always}",
68-
req.route().attributes().toString());
73+
assertEquals(ImmutableMap.of("priority", 0.5, "changefreq", "always", "role", "admin"),
74+
req.route().attributes());
6975
});
7076
use(Resource.class);
7177
}
7278

7379
@Test
7480
public void mvcAttrs() throws Exception {
7581
request().get("/1")
76-
.expect("{priority=1.0, changefreq=always}");
82+
.expect(value -> {
83+
Map<String, Object> hash = toMap(value.substring(1, value.length() - 1));
84+
assertEquals(ImmutableMap.of("priority", "1.0", "changefreq", "always"), hash);
85+
});
7786

7887
request().get("/2")
79-
.expect("{priority=0.5, changefreq=always}");
88+
.expect(value -> {
89+
Map<String, Object> hash = toMap(value.substring(1, value.length() - 1));
90+
assertEquals(ImmutableMap.of("priority", "0.5", "changefreq", "always"), hash);
91+
});
8092

8193
request().get("/3")
82-
.expect("{role=admin, priority=0.5, changefreq=always}");
94+
.expect(value -> {
95+
Map<String, Object> hash = toMap(value.substring(1, value.length() - 1));
96+
assertEquals(ImmutableMap.of("priority", "0.5", "changefreq", "always", "role", "admin"),
97+
hash);
98+
});
99+
}
100+
101+
private Map<String, Object> toMap(final String value) {
102+
Map<String, Object> hash = new HashMap<>();
103+
String[] pairs = value.split(",");
104+
for (String pair : pairs) {
105+
String[] keyandvalue = pair.trim().split("=");
106+
hash.put(keyandvalue[0], keyandvalue[1]);
107+
}
108+
return hash;
83109
}
84110

85111
}

jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowRequest.java

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -53,31 +53,28 @@
5353
import io.undertow.util.AttachmentKey;
5454
import io.undertow.util.HeaderValues;
5555
import io.undertow.util.HttpString;
56-
import javaslang.Lazy;
57-
import javaslang.control.Try;
5856

5957
public class UndertowRequest implements NativeRequest {
6058

6159
public static final AttachmentKey<NativeWebSocket> SOCKET = AttachmentKey
6260
.create(NativeWebSocket.class);
6361

62+
private static final FormData NO_FORM = new FormData(0);
63+
6464
private HttpServerExchange exchange;
6565

66-
private Config config;
66+
private Config conf;
6767

68-
private final Lazy<FormData> form;
68+
private FormData form;
6969

70-
private final String path;
70+
private String path;
7171

7272
private Supplier<BlockingHttpExchange> blocking;
7373

74-
public UndertowRequest(final HttpServerExchange exchange, final Config conf)
75-
throws IOException {
74+
public UndertowRequest(final HttpServerExchange exchange, final Config conf) throws IOException {
7675
this.exchange = exchange;
7776
this.blocking = Suppliers.memoize(() -> this.exchange.startBlocking());
78-
this.config = conf;
79-
this.form = Lazy.of(() -> Try.of(() -> parseForm(exchange, conf.getString("application.tmpdir"),
80-
conf.getString("application.charset"))).get());
77+
this.conf = conf;
8178
this.path = URLDecoder.decode(exchange.getRequestPath(), "UTF-8");
8279
}
8380

@@ -106,7 +103,7 @@ public String rawPath() {
106103
public List<String> paramNames() {
107104
ImmutableList.Builder<String> builder = ImmutableList.<String> builder();
108105
builder.addAll(exchange.getQueryParameters().keySet());
109-
FormData formdata = this.form.get();
106+
FormData formdata = parseForm();
110107
formdata.forEach(v -> {
111108
// excludes upload from param names.
112109
if (!formdata.getFirst(v).isFile()) {
@@ -125,7 +122,7 @@ public List<String> params(final String name) {
125122
query.stream().forEach(builder::add);
126123
}
127124
// form params
128-
Optional.ofNullable(form.get().get(name)).ifPresent(values -> {
125+
Optional.ofNullable(parseForm().get(name)).ifPresent(values -> {
129126
values.stream().forEach(value -> {
130127
if (!value.isFile()) {
131128
builder.add(value.getValue());
@@ -164,7 +161,7 @@ public List<Cookie> cookies() {
164161
@Override
165162
public List<NativeUpload> files(final String name) {
166163
Builder<NativeUpload> builder = ImmutableList.builder();
167-
Deque<FormValue> values = form.get().get(name);
164+
Deque<FormValue> values = parseForm().get(name);
168165
if (values != null) {
169166
values.forEach(value -> {
170167
if (value.isFile()) {
@@ -204,7 +201,7 @@ public boolean secure() {
204201
@SuppressWarnings("unchecked")
205202
public <T> T upgrade(final Class<T> type) throws Exception {
206203
if (type == NativeWebSocket.class) {
207-
UndertowWebSocket ws = new UndertowWebSocket(config);
204+
UndertowWebSocket ws = new UndertowWebSocket(conf);
208205
exchange.putAttachment(SOCKET, ws);
209206
return (T) ws;
210207
}
@@ -222,28 +219,35 @@ public void startAsync(final Executor executor, final Runnable runnable) {
222219
exchange.dispatch(executor, runnable);
223220
}
224221

225-
private FormData parseForm(final HttpServerExchange exchange, final String tmpdir,
226-
final String charset) throws IOException {
227-
String value = exchange.getRequestHeaders().getFirst("Content-Type");
228-
if (value != null) {
229-
MediaType type = MediaType.valueOf(value);
230-
if (MediaType.form.name().equals(type.name())) {
231-
blocking.get();
232-
return new FormEncodedDataDefinition()
233-
.setDefaultEncoding(charset)
234-
.create(exchange)
235-
.parseBlocking();
236-
} else if (MediaType.multipart.name().equals(type.name())) {
237-
blocking.get();
238-
return new MultiPartParserDefinition()
239-
.setTempFileLocation(new File(tmpdir).toPath())
240-
.setDefaultEncoding(charset)
241-
.create(exchange)
242-
.parseBlocking();
243-
222+
private FormData parseForm() {
223+
if (form == null) {
224+
form = NO_FORM;
225+
try {
226+
String tmpdir = conf.getString("application.tmpdir");
227+
String charset = conf.getString("application.charset");
228+
String value = exchange.getRequestHeaders().getFirst("Content-Type");
229+
if (value != null) {
230+
MediaType type = MediaType.valueOf(value);
231+
if (MediaType.form.name().equals(type.name())) {
232+
blocking.get();
233+
form = new FormEncodedDataDefinition()
234+
.setDefaultEncoding(charset)
235+
.create(exchange)
236+
.parseBlocking();
237+
} else if (MediaType.multipart.name().equals(type.name())) {
238+
blocking.get();
239+
form = new MultiPartParserDefinition()
240+
.setTempFileLocation(new File(tmpdir).toPath())
241+
.setDefaultEncoding(charset)
242+
.create(exchange)
243+
.parseBlocking();
244+
245+
}
246+
}
247+
} catch (IOException x) {
244248
}
245249
}
246-
return new FormData(0);
250+
return form;
247251
}
248252

249253
private static Cookie cookie(final io.undertow.server.handlers.Cookie c) {

jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowResponse.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030

3131
import org.jooby.spi.NativeResponse;
3232
import org.jooby.spi.NativeWebSocket;
33-
import org.slf4j.Logger;
3433
import org.slf4j.LoggerFactory;
3534

3635
import com.google.common.collect.ImmutableList;
@@ -44,9 +43,6 @@
4443

4544
public class UndertowResponse implements NativeResponse {
4645

47-
/** The logging system. */
48-
private final Logger log = LoggerFactory.getLogger(NativeResponse.class);
49-
5046
private HttpServerExchange exchange;
5147

5248
private volatile boolean endExchange = true;
@@ -70,13 +66,13 @@ public Optional<String> header(final String name) {
7066

7167
@Override
7268
public void header(final String name, final String value) {
73-
exchange.getResponseHeaders().put(new HttpString(name), value);
69+
exchange.getResponseHeaders().put(HttpString.tryFromString(name), value);
7470
}
7571

7672
@Override
7773
public void header(final String name, final Iterable<String> values) {
7874
HeaderMap headers = exchange.getResponseHeaders();
79-
headers.putAll(new HttpString(name), ImmutableList.copyOf(values));
75+
headers.putAll(HttpString.tryFromString(name), ImmutableList.copyOf(values));
8076
}
8177

8278
@Override
@@ -103,7 +99,8 @@ public void send(final FileChannel channel) throws Exception {
10399
}
104100

105101
@Override
106-
public void send(final FileChannel channel, final long position, final long count) throws Exception {
102+
public void send(final FileChannel channel, final long position, final long count)
103+
throws Exception {
107104
endExchange = false;
108105
channel.position(position);
109106
new ChunkedStream(count).send(channel, exchange, new LogIoCallback(IoCallback.END_EXCHANGE));
@@ -138,7 +135,7 @@ public void end() {
138135
((UndertowWebSocket) ws).connect(channel);
139136
}).handleRequest(exchange);
140137
} catch (Exception ex) {
141-
log.error("Upgrade result in exception", ex);
138+
LoggerFactory.getLogger(NativeResponse.class).error("Upgrade result in exception", ex);
142139
} finally {
143140
exchange.removeAttachment(UndertowRequest.SOCKET);
144141
}

0 commit comments

Comments
 (0)