Skip to content
Browse files

added smarter negotiation

still need to do wildcards, though.
  • Loading branch information...
1 parent 3406706 commit 61e6545b571a1ee5a7caeee9b223b2187ab244a0 Frank Carver committed Mar 8, 2012
View
64 src/main/java/org/rack4java/middleware/format_negotiator/FormatNegotiator.java
@@ -1,16 +1,22 @@
package org.rack4java.middleware.format_negotiator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
import org.rack4java.Context;
import org.rack4java.Rack;
+import org.rack4java.context.ContextEntry;
import org.rack4java.data.Mime;
-import org.rack4java.utils.StringUtils;
public class FormatNegotiator implements Rack {
private Rack application;
+ private List<Map.Entry<String, Double>> supportedFormats;
public FormatNegotiator(Rack application) {
this.application = application;
+ this.supportedFormats = new LinkedList<Map.Entry<String, Double>>();
}
@Override public Context<String> call(Context<String> environment) throws Exception {
@@ -19,35 +25,65 @@ public FormatNegotiator(Rack application) {
}
private void negotiate(Context<String> environment) {
+ List<Map.Entry<String, Double>> requestedFormats = new LinkedList<Map.Entry<String, Double>>();
String accept = environment.get(HTTP_ACCEPT);
- String preferred = null;
- double bestq = 0;
if (null != accept) {
String[] options = accept.split(",");
for (String option : options) {
double q = 0;
String[] detail = option.split(";");
- String type = detail[0];
+ String type = detail[0].trim();
if (detail.length == 1) {
q = 1.0;
} else {
q = Double.parseDouble((detail[1].split("="))[1].trim());
}
- if (q > bestq) {
- bestq = q;
- preferred = type;
- }
+
+ insert(requestedFormats, type, q);
}
}
- if (StringUtils.isBlank(preferred)) preferred = Mime.DEFAULT_MIME_TYPE;
- environment.with(Rack.HTTP_ACCEPT, stripq(preferred));
+ String preferred = select(requestedFormats, supportedFormats);
+
+ environment.with(Rack.HTTP_ACCEPT, preferred);
+ }
+
+ private void insert(List<Map.Entry<String, Double>> formats, String type, double q) {
+ boolean inserted = false;
+ for (int i = 0; i < formats.size(); ++i) {
+ Map.Entry<String, Double> entry = formats.get(i);
+ if (q > entry.getValue()) {
+ formats.add(i, new ContextEntry<Double>(type, q));
+ inserted = true;
+ break;
+ }
+ }
+ if (!inserted) {
+ formats.add(new ContextEntry<Double>(type, q));
+ }
+ }
+
+ private String select(List<Map.Entry<String, Double>> requestedFormats, List<Map.Entry<String, Double>> supportedFormats) {
+ for (Map.Entry<String, Double> requested : requestedFormats) {
+ String type = requested.getKey();
+ if (supportedFormats.isEmpty()) return type;
+
+ for (Map.Entry<String, Double> supported : supportedFormats) {
+ if (type.equals(supported.getKey())) {
+ return type;
+ }
+ }
+ }
+ return Mime.DEFAULT_MIME_TYPE;
+ }
+
+ public FormatNegotiator withSupportedFormat(String format, double q) {
+ insert(supportedFormats, format, q);
+ return this;
}
- private String stripq(String option) {
- int semicolon = option.indexOf(';');
- if (semicolon >= 0) option = option.substring(0, semicolon);
- return option;
+ public FormatNegotiator withSupportedFormat(String format) {
+ return withSupportedFormat(format, 1.0);
}
}
View
24 src/test/java/test/FormatNegotiatorTest.java
@@ -44,4 +44,28 @@ public void testClientHasSequenceWithPartialPrioritiesAppDoesntCare() throws Exc
assertEquals(1, stub.called);
assertEquals("text/html", stub.request.get(Rack.HTTP_ACCEPT));
}
+
+ public void testClientHasSequenceAppIsPicky() throws Exception {
+ ((FormatNegotiator)app).withSupportedFormat("application/xml");
+ request.with(Rack.HTTP_ACCEPT, "application/json,application/xml");
+ get("/lala");
+ assertEquals(1, stub.called);
+ assertEquals("application/xml", stub.request.get(Rack.HTTP_ACCEPT));
+ }
+
+ public void testClientHasSequenceAppHasSequence() throws Exception {
+ ((FormatNegotiator)app).withSupportedFormat("text/plain").withSupportedFormat("application/xml");
+ request.with(Rack.HTTP_ACCEPT, "application/json,application/xml,text/html");
+ get("/lala");
+ assertEquals(1, stub.called);
+ assertEquals("application/xml", stub.request.get(Rack.HTTP_ACCEPT));
+ }
+
+ public void testClientHasSequenceAppHasPriorities() throws Exception {
+ ((FormatNegotiator)app).withSupportedFormat("application/xml", 0.6).withSupportedFormat("text/html");
+ request.with(Rack.HTTP_ACCEPT, "application/json,application/xml,text/html");
+ get("/lala");
+ assertEquals(1, stub.called);
+ assertEquals("application/xml", stub.request.get(Rack.HTTP_ACCEPT));
+ }
}

0 comments on commit 61e6545

Please sign in to comment.
Something went wrong with that request. Please try again.