Skip to content

Commit 8782005

Browse files
committed
prepare for round 12 of techempower tests ref jooby-project#259
1 parent d0fc5f2 commit 8782005

20 files changed

Lines changed: 530 additions & 415 deletions

coverage-report/src/test/java/org/jooby/RequestLocalsFeature.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package org.jooby;
22

3+
import static org.junit.Assert.assertEquals;
34
import static org.junit.Assert.assertFalse;
45
import static org.junit.Assert.assertTrue;
56

67
import java.util.Optional;
8+
import java.util.Set;
79

10+
import org.elasticsearch.common.collect.Sets;
811
import org.jooby.test.ServerFeature;
912
import org.junit.Test;
1013

14+
import com.google.common.base.Splitter;
15+
1116
public class RequestLocalsFeature extends ServerFeature {
1217

1318
{
@@ -51,7 +56,11 @@ public void unset() throws Exception {
5156
public void attributes() throws Exception {
5257
request()
5358
.get("/locals/attributes")
54-
.expect("{contextPath=, path=/locals/attributes, l1=v1}");
59+
.expect(c -> {
60+
String s = c.substring(1, c.length() - 1).trim();
61+
Set<String> values = Sets.newHashSet(Splitter.on(",").trimResults().split(s));
62+
assertEquals(Sets.newHashSet("contextPath=", "path=/locals/attributes", "l1=v1"), values);
63+
});
5564

5665
}
5766

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
33
import org.jooby.test.ServerFeature;
44
import org.junit.Test;
55

6+
import com.typesafe.config.ConfigFactory;
7+
import com.typesafe.config.ConfigValueFactory;
8+
69
public class Issue128 extends ServerFeature {
710

811
{
12+
use(ConfigFactory.empty()
13+
.withValue("server.http.Method", ConfigValueFactory.fromAnyRef("_method")));
914
put("/fake/put", req -> req.method());
1015
}
1116

jooby/src/main/java/org/jooby/MediaType.java

Lines changed: 91 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,17 @@
2626
import java.util.ArrayList;
2727
import java.util.Collections;
2828
import java.util.LinkedHashMap;
29-
import java.util.LinkedList;
3029
import java.util.List;
3130
import java.util.Map;
3231
import java.util.Optional;
3332

33+
import com.google.common.base.Throwables;
34+
import com.google.common.cache.CacheBuilder;
35+
import com.google.common.cache.CacheLoader;
36+
import com.google.common.cache.LoadingCache;
3437
import com.google.common.collect.ImmutableList;
3538
import com.google.common.collect.ImmutableMap;
39+
import com.google.common.util.concurrent.UncheckedExecutionException;
3640
import com.typesafe.config.Config;
3741
import com.typesafe.config.ConfigFactory;
3842

@@ -169,7 +173,7 @@ public List<MediaType> filter(final List<MediaType> types) {
169173
if (types.size() == 1) {
170174
sortedTypes = ImmutableList.of(types.get(0));
171175
} else {
172-
sortedTypes = new LinkedList<>(types);
176+
sortedTypes = new ArrayList<>(types);
173177
Collections.sort(sortedTypes);
174178
}
175179
for (MediaType accept : acceptable) {
@@ -290,20 +294,34 @@ private MediaType doFirst(final List<MediaType> candidates) {
290294
*/
291295
private final boolean wildcardSubtype;
292296

297+
/** Name . */
298+
private String name;
299+
300+
private int hc;
301+
293302
/**
294303
* Alias for most used types.
295304
*/
296-
private static final Map<String, MediaType> alias = ImmutableMap.<String, MediaType> builder()
297-
.put("html", html)
298-
.put("json", json)
299-
.put("css", css)
300-
.put("js", js)
301-
.put("octetstream", octetstream)
302-
.put("form", form)
303-
.put("multipart", multipart)
304-
.put("xml", xml)
305-
.put("*", all)
306-
.build();
305+
private static final LoadingCache<String, List<MediaType>> cache = CacheBuilder.newBuilder()
306+
.build(new CacheLoader<String, List<MediaType>>() {
307+
@Override
308+
public List<MediaType> load(final String type) throws Exception {
309+
return parseInternal(type);
310+
}
311+
312+
});
313+
314+
static {
315+
cache.put("html", ImmutableList.of(html));
316+
cache.put("json", ImmutableList.of(json));
317+
cache.put("css", ImmutableList.of(css));
318+
cache.put("js", ImmutableList.of(js));
319+
cache.put("octetstream", ImmutableList.of(octetstream));
320+
cache.put("form", ImmutableList.of(form));
321+
cache.put("multipart", ImmutableList.of(multipart));
322+
cache.put("xml", ImmutableList.of(xml));
323+
cache.put("*", ALL);
324+
}
307325

308326
static final Config types = ConfigFactory
309327
.parseResources("mime.properties")
@@ -322,6 +340,10 @@ private MediaType(final String type, final String subtype, final Map<String, Str
322340
this.params = ImmutableMap.copyOf(requireNonNull(parameters, "Parameters are required."));
323341
this.wildcardType = "*".equals(type);
324342
this.wildcardSubtype = "*".equals(subtype);
343+
this.name = type + "/" + subtype;
344+
345+
hc = 31 + name.hashCode();
346+
hc = 31 * hc + params.hashCode();
325347
}
326348

327349
/**
@@ -363,7 +385,7 @@ public String subtype() {
363385
* @return The qualified type {@link #type()}/{@link #subtype()}.
364386
*/
365387
public String name() {
366-
return type + "/" + subtype;
388+
return name;
367389
}
368390

369391
/**
@@ -374,10 +396,10 @@ public boolean isText() {
374396
return false;
375397
}
376398

377-
if (text.matches(this)) {
399+
if (this == text || text.matches(this)) {
378400
return true;
379401
}
380-
if (js.matches(this)) {
402+
if (this == js || js.matches(this)) {
381403
return true;
382404
}
383405
if (jsonLike.matches(this)) {
@@ -474,16 +496,12 @@ public boolean equals(final Object obj) {
474496

475497
@Override
476498
public int hashCode() {
477-
final int prime = 31;
478-
int result = prime + type.hashCode();
479-
result = prime * result + subtype.hashCode();
480-
result = prime * result + params.hashCode();
481-
return result;
499+
return hc;
482500
}
483501

484502
@Override
485503
public final String toString() {
486-
return name();
504+
return name;
487505
}
488506

489507
/**
@@ -493,32 +511,55 @@ public final String toString() {
493511
* @return An immutable {@link MediaType}.
494512
*/
495513
public static MediaType valueOf(final String type) {
496-
requireNonNull(type, "A mediaType is required.");
497-
MediaType aliastype = alias.get(type.trim());
498-
if (aliastype != null) {
499-
return aliastype;
500-
}
501-
String[] parts = type.trim().split(";");
502-
if (parts[0].equals("*")) {
503-
// odd and ugly media type
504-
return MediaType.all;
505-
}
506-
String[] typeAndSubtype = parts[0].split("/");
507-
checkArgument(typeAndSubtype.length == 2, "Bad media type: %s", type);
508-
String stype = typeAndSubtype[0].trim();
509-
String subtype = typeAndSubtype[1].trim();
510-
checkArgument(!(stype.equals("*") && !subtype.equals("*")), "Bad media type: %s", type);
511-
Map<String, String> parameters = DEFAULT_PARAMS;
512-
if (parts.length > 1) {
513-
parameters = new LinkedHashMap<>(DEFAULT_PARAMS);
514-
for (int i = 1; i < parts.length; i++) {
515-
String[] parameter = parts[i].split("=");
516-
if (parameter.length > 1) {
517-
parameters.put(parameter[0].trim(), parameter[1].trim().toLowerCase());
514+
return parse(type).get(0);
515+
}
516+
517+
private static List<MediaType> parseInternal(final String value) {
518+
String[] types = value.split(",");
519+
@SuppressWarnings("serial")
520+
List<MediaType> result = new ArrayList<MediaType>(types.length) {
521+
int hc = 1;
522+
523+
@Override
524+
public boolean add(final MediaType e) {
525+
hc = 31 * hc + e.hashCode();
526+
return super.add(e);
527+
}
528+
529+
@Override
530+
public int hashCode() {
531+
return hc;
532+
}
533+
};
534+
for (String type : types) {
535+
requireNonNull(type, "A mediaType is required.");
536+
String[] parts = type.trim().split(";");
537+
if (parts[0].equals("*")) {
538+
// odd and ugly media type
539+
result.add(all);
540+
} else {
541+
String[] typeAndSubtype = parts[0].split("/");
542+
checkArgument(typeAndSubtype.length == 2, "Bad media type: %s", type);
543+
String stype = typeAndSubtype[0].trim();
544+
String subtype = typeAndSubtype[1].trim();
545+
checkArgument(!(stype.equals("*") && !subtype.equals("*")), "Bad media type: %s", type);
546+
Map<String, String> parameters = DEFAULT_PARAMS;
547+
if (parts.length > 1) {
548+
parameters = new LinkedHashMap<>(DEFAULT_PARAMS);
549+
for (int i = 1; i < parts.length; i++) {
550+
String[] parameter = parts[i].split("=");
551+
if (parameter.length > 1) {
552+
parameters.put(parameter[0].trim(), parameter[1].trim().toLowerCase());
553+
}
554+
}
518555
}
556+
result.add(new MediaType(stype, subtype, parameters));
519557
}
520558
}
521-
return new MediaType(stype, subtype, parameters);
559+
if (result.size() > 1) {
560+
Collections.sort(result);
561+
}
562+
return result;
522563
}
523564

524565
/**
@@ -543,7 +584,11 @@ public static List<MediaType> valueOf(final String... types) {
543584
* @return One ore more {@link MediaType}.
544585
*/
545586
public static List<MediaType> parse(final String value) {
546-
return valueOf(value.split(","));
587+
try {
588+
return cache.getUnchecked(value);
589+
} catch (UncheckedExecutionException ex) {
590+
throw Throwables.propagate(ex.getCause());
591+
}
547592
}
548593

549594
/**

jooby/src/main/java/org/jooby/Route.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ class Definition {
736736
/**
737737
* A route pattern.
738738
*/
739-
private RoutePattern compiledPattern;
739+
private RoutePattern cpattern;
740740

741741
/**
742742
* The target route.
@@ -816,9 +816,9 @@ public Definition(final String method, final String pattern,
816816
requireNonNull(filter, "A filter is required.");
817817

818818
this.method = method.toUpperCase();
819-
this.compiledPattern = new RoutePattern(method, pattern);
819+
this.cpattern = new RoutePattern(method, pattern);
820820
// normalized pattern
821-
this.pattern = compiledPattern.pattern();
821+
this.pattern = cpattern.pattern();
822822
this.filter = filter;
823823
}
824824

@@ -864,7 +864,7 @@ public String pattern() {
864864
* @return List of path variables (if any).
865865
*/
866866
public List<String> vars() {
867-
return compiledPattern.vars();
867+
return cpattern.vars();
868868
}
869869

870870
/**
@@ -879,11 +879,11 @@ public List<String> vars() {
879879
public Optional<Route> matches(final String verb,
880880
final String path, final MediaType contentType,
881881
final List<MediaType> accept) {
882-
String fpath = verb.toUpperCase() + path;
883-
if (excludes(fpath)) {
882+
String fpath = verb + path;
883+
if (excludes.size() > 0 && excludes(fpath)) {
884884
return Optional.empty();
885885
}
886-
RouteMatcher matcher = compiledPattern.matcher(fpath);
886+
RouteMatcher matcher = cpattern.matcher(fpath);
887887
if (matcher.matches()) {
888888
List<MediaType> result = MediaType.matcher(accept).filter(this.produces);
889889
if (result.size() > 0 && canConsume(contentType)) {

jooby/src/main/java/org/jooby/internal/AbstractRendererContext.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,9 @@
2626
import java.nio.CharBuffer;
2727
import java.nio.channels.FileChannel;
2828
import java.nio.charset.Charset;
29-
import java.util.Iterator;
30-
import java.util.LinkedList;
29+
import java.util.ArrayList;
3130
import java.util.List;
3231
import java.util.Map;
33-
import java.util.Set;
3432

3533
import org.jooby.Err;
3634
import org.jooby.MediaType;
@@ -43,7 +41,7 @@
4341

4442
public abstract class AbstractRendererContext implements Renderer.Context {
4543

46-
private Set<Renderer> renderers;
44+
private List<Renderer> renderers;
4745

4846
private Matcher matcher;
4947

@@ -55,20 +53,23 @@ public abstract class AbstractRendererContext implements Renderer.Context {
5553

5654
private boolean committed;
5755

58-
public AbstractRendererContext(final Set<Renderer> renderers, final List<MediaType> produces,
56+
private int rsize;
57+
58+
public AbstractRendererContext(final List<Renderer> renderers, final List<MediaType> produces,
5959
final Charset charset, final Map<String, Object> locals) {
6060
this.renderers = renderers;
6161
this.produces = produces;
6262
this.matcher = MediaType.matcher(produces);
6363
this.charset = charset;
6464
this.locals = locals;
65+
rsize = this.renderers.size();
6566
}
6667

6768
public void render(final Object value) throws Exception {
68-
Iterator<Renderer> it = renderers.iterator();
69-
List<String> notFound = new LinkedList<>();
70-
while (!committed && it.hasNext()) {
71-
Renderer next = it.next();
69+
int i = 0;
70+
List<String> notFound = new ArrayList<>();
71+
while (!committed && i < rsize) {
72+
Renderer next = renderers.get(i);
7273
try {
7374
next.render(value, this);
7475
} catch (FileNotFoundException ex) {
@@ -79,6 +80,7 @@ public void render(final Object value) throws Exception {
7980
throw ex;
8081
}
8182
}
83+
i += 1;
8284
}
8385
if (!committed) {
8486
if (notFound.size() > 0) {
@@ -131,7 +133,9 @@ public void send(final Reader reader) throws Exception {
131133
@Override
132134
public void send(final String text) throws Exception {
133135
type(MediaType.html);
134-
_send(text);
136+
byte[] bytes = text.getBytes(charset);
137+
length(bytes.length);
138+
_send(bytes);
135139
committed = true;
136140
}
137141

0 commit comments

Comments
 (0)