[OLINGO-659] Introduced HttpHeader for ODataResponse/Request

This commit is contained in:
Michael Bolz 2015-08-13 13:59:13 +02:00
parent b82294e1e8
commit f2c7be2d12
5 changed files with 277 additions and 24 deletions

View File

@ -18,10 +18,15 @@
******************************************************************************/
package org.apache.olingo.commons.api.http;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
/**
* HTTP header constants.
*/
public interface HttpHeader {
public class HttpHeader {
/**
* See {@link <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1">HTTP/1.1 documentation</a>}.
@ -176,4 +181,107 @@ public interface HttpHeader {
public static final String ODATA_MAX_VERSION = "OData-MaxVersion";
/** Custom Header defined in the OData standard. */
public static final String ODATA_ENTITY_ID = "OData-EntityID";
private final String name;
private final Collection<String> values;
/**
* Create header for given name
* @param name of header
*/
public HttpHeader(String name) {
this.name = name;
this.values = new ArrayList<String>();
}
/**
* Create header for given name and add given values
* @param name of header
* @param values values for header
*/
public HttpHeader(String name, Collection<String> values) {
this(name);
this.values.addAll(values);
}
/**
* Get name of header (not the canonical name)
* @return name of header
*/
public String getName() {
return name;
}
/**
* Get all values for this header
* @return all header values
*/
public Collection<String> getValues() {
return Collections.unmodifiableCollection(values);
}
/**
* Add header value
*
* @param value value to be added
* @return this header object (fluent interface)
*/
public HttpHeader addValue(String value) {
this.values.add(value);
return this;
}
/**
* Add header values
*
* @param values values to be added
* @return this header object (fluent interface)
*/
public HttpHeader addValues(Collection<String> values) {
this.values.addAll(values);
return this;
}
/**
* Get the canonical name of header
* @return canonical name of header
*/
public String getCanonicalName() {
return createCanonicalName(name);
}
/**
* Create the canonical name based on given name parameter
*
* @param name name which is canonicalised
* @return canonical name
*/
public static String createCanonicalName(String name) {
return name.toLowerCase(Locale.ROOT);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
HttpHeader that = (HttpHeader) o;
if (!name.equals(that.name)) {
return false;
}
return values.equals(that.values);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + values.hashCode();
return result;
}
}

View File

@ -0,0 +1,134 @@
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
******************************************************************************/
package org.apache.olingo.commons.api.http;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
/**
* HttpHeader container
*/
public class HttpHeaders {
private final Map<String, HttpHeader> headers = new TreeMap<String, HttpHeader>();
/**
* Add a header with given name and value.
* If header with name already exists the value is added to this header.
*
* @param name name of header
* @param value value for header
* @return this container (fluent interface)
*/
public HttpHeaders addHeader(String name, String value) {
HttpHeader eh = grantHeader(name);
eh.addValue(value);
return this;
}
/**
* Add a header with given name and values.
* If header with name already exists the values are added to this header.
*
* @param name name of header
* @param values values for header
* @return this container (fluent interface)
*/
public HttpHeaders addHeader(String name, Collection<String> values) {
HttpHeader eh = grantHeader(name);
eh.addValues(values);
return this;
}
/**
* Set a header with given name and value.
* If header with name already exists the old header is replaced with the new one.
*
* @param name name of header
* @param value value for header
* @return this container (fluent interface)
*/
public HttpHeaders setHeader(String name, String value) {
removeHeader(name);
HttpHeader eh = grantHeader(name);
eh.addValue(value);
return this;
}
/**
* Get header for given name.
*
* @param name name of header requested
* @return corresponding header
*/
public HttpHeader getHeader(String name) {
return headers.get(HttpHeader.createCanonicalName(name));
}
/**
* Remove header for given name.
*
* @param name name of header to be removed
* @return header which was removed or null if no header was known for this name
*/
public HttpHeader removeHeader(String name) {
return headers.remove(HttpHeader.createCanonicalName(name));
}
/**
* Get all headers.
*
* @return all headers
*/
public Collection<HttpHeader> getHeaders() {
return Collections.unmodifiableCollection(headers.values());
}
/**
* Get all header names.
*
* @return all header names
*/
public Collection<String> getHeaderNames() {
Collection<String> headerNames = new ArrayList<String>();
for (HttpHeader header : headers.values()) {
headerNames.add(header.getName());
}
return headerNames;
}
/**
* Get or create a header for given name.
*
* @return new or known header
*/
private HttpHeader grantHeader(String name) {
String key = HttpHeader.createCanonicalName(name);
HttpHeader eh = headers.get(key);
if(eh == null) {
eh = new HttpHeader(name);
headers.put(key, eh);
}
return eh;
}
}

View File

@ -20,11 +20,14 @@ package org.apache.olingo.server.api;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpHeaders;
import org.apache.olingo.commons.api.http.HttpMethod;
/**
@ -32,7 +35,7 @@ import org.apache.olingo.commons.api.http.HttpMethod;
*/
public class ODataRequest {
private HttpMethod method;
private Map<String, List<String>> headers = new HashMap<String, List<String>>();
private HttpHeaders headers = new HttpHeaders();
private InputStream body;
private String rawQueryPath;
private String rawRequestUri;
@ -66,18 +69,7 @@ public class ODataRequest {
* @see <a href="http://ietf.org/rfc/rfc7230.txt">RFC 7230, section 3.2.2</a>
*/
public void addHeader(final String name, final List<String> values) {
String key = name.toUpperCase();
if (headers.containsKey(key)) {
List<String> oldValues = headers.get(key);
List<String> newValues = new ArrayList<String>();
newValues.addAll(oldValues);
newValues.addAll(values);
headers.put(name.toUpperCase(), newValues);
} else {
headers.put(name.toUpperCase(), values);
}
headers.addHeader(name, values);
}
/**
@ -86,7 +78,11 @@ public class ODataRequest {
* @return the header value(s) or null if not found
*/
public List<String> getHeaders(final String name) {
return headers.get(name.toUpperCase());
HttpHeader h = headers.getHeader(name);
if(h == null) {
return null;//Collections.emptyList();
}
return new ArrayList<String>(h.getValues());
}
/**
@ -104,7 +100,14 @@ public class ODataRequest {
* @return an unmodifiable Map of header names/values
*/
public Map<String, List<String>> getAllHeaders() {
return Collections.unmodifiableMap(headers);
Collection<HttpHeader> allHeader = headers.getHeaders();
Map<String, List<String>> result = new HashMap<String, List<String>>();
for (HttpHeader httpHeader : allHeader) {
result.put(httpHeader.getName(), new ArrayList<String>(httpHeader.getValues()));
}
return Collections.unmodifiableMap(result);
}

View File

@ -19,10 +19,13 @@
package org.apache.olingo.server.api;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpHeaders;
import org.apache.olingo.commons.api.http.HttpStatusCode;
/**
@ -31,7 +34,7 @@ import org.apache.olingo.commons.api.http.HttpStatusCode;
public class ODataResponse {
private int statusCode = HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode();
private final Map<String, String> headers = new HashMap<String, String>();
private final HttpHeaders headers = new HttpHeaders();
private InputStream content;
/**
@ -56,7 +59,7 @@ public class ODataResponse {
* @param value the value
*/
public void setHeader(final String name, final String value) {
headers.put(name, value);
headers.setHeader(name, value);
}
/**
@ -64,7 +67,12 @@ public class ODataResponse {
* @return an unmodifiable Map of header names/values
*/
public Map<String, String> getHeaders() {
return Collections.unmodifiableMap(headers);
Map<String, String> result = new HashMap<String, String>();
Collection<HttpHeader> allHeaders = headers.getHeaders();
for (HttpHeader header : allHeaders) {
result.put(header.getName(), header.getValues().iterator().next());
}
return Collections.unmodifiableMap(result);
}
/**

View File

@ -86,7 +86,7 @@ public class DebugTabRequestTest extends AbstractDebugTabTest {
@Test
public void singleHeaderValue() throws Exception {
String expectedJson =
"{\"method\":\"GET\",\"uri\":\"def&\",\"protocol\":\"def&\",\"headers\":{\"HEADERNAME\":\"Value1\"}}";
"{\"method\":\"GET\",\"uri\":\"def&\",\"protocol\":\"def&\",\"headers\":{\"HeaderName\":\"Value1\"}}";
String expectedHtml = "<h2>Request Method</h2>\n"
+ "<p>GET</p>\n"
+ "<h2>Request URI</h2>\n"
@ -99,7 +99,7 @@ public class DebugTabRequestTest extends AbstractDebugTabTest {
+ "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n"
+ "</thead>\n"
+ "<tbody>\n"
+ "<tr><td class=\"name\">HEADERNAME</td><td class=\"value\">Value1</td></tr>\n"
+ "<tr><td class=\"name\">HeaderName</td><td class=\"value\">Value1</td></tr>\n"
+ "</tbody>\n"
+ "</table>\n";
@ -120,7 +120,7 @@ public class DebugTabRequestTest extends AbstractDebugTabTest {
@Test
public void multiHeaderValueResultsInMap() throws Exception {
String expectedJson = "{\"method\":\"GET\",\"uri\":\"def&\",\"protocol\":\"def&\","
+ "\"headers\":{\"HEADERNAME\":[\"Value1\",\"Value2\"]}}";
+ "\"headers\":{\"HeaderName\":[\"Value1\",\"Value2\"]}}";
String expectedHtml = "<h2>Request Method</h2>\n"
+ "<p>GET</p>\n"
+ "<h2>Request URI</h2>\n"
@ -133,8 +133,8 @@ public class DebugTabRequestTest extends AbstractDebugTabTest {
+ "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n"
+ "</thead>\n"
+ "<tbody>\n"
+ "<tr><td class=\"name\">HEADERNAME</td><td class=\"value\">Value1</td></tr>\n"
+ "<tr><td class=\"name\">HEADERNAME</td><td class=\"value\">Value2</td></tr>\n"
+ "<tr><td class=\"name\">HeaderName</td><td class=\"value\">Value1</td></tr>\n"
+ "<tr><td class=\"name\">HeaderName</td><td class=\"value\">Value2</td></tr>\n"
+ "</tbody>\n"
+ "</table>\n";