This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 2c53519 org.apache.juneau.http improvements.
2c53519 is described below
commit 2c535194bef98a36cdd2e8c039d2c0a183755492
Author: JamesBognar <[email protected]>
AuthorDate: Wed Jul 8 10:51:48 2020 -0400
org.apache.juneau.http improvements.
---
.../org/apache/juneau/http/ReaderResource.java | 35 ++++++----
.../apache/juneau/http/ReaderResourceBuilder.java | 6 +-
.../juneau/http/ResolvingReaderResource.java | 12 ++--
.../http/ResolvingResourceReaderBuilder.java | 2 +-
.../main/java/org/apache/juneau/http/Resource.java | 34 ++++++++++
.../org/apache/juneau/http/StreamResource.java | 74 +++++++++-------------
.../apache/juneau/http/StreamResourceBuilder.java | 6 +-
.../java/org/apache/juneau/httppart/HttpPart.java | 28 ++++----
.../java/org/apache/juneau/rest/RestResponse.java | 18 +++++-
.../juneau/rest/reshandlers/DefaultHandler.java | 58 ++++++++++++++---
10 files changed, 173 insertions(+), 100 deletions(-)
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
index 3aef2bb..f0e6ccd 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
@@ -17,7 +17,6 @@ import static org.apache.juneau.internal.IOUtils.*;
import java.io.*;
import java.util.*;
-import org.apache.juneau.*;
import org.apache.juneau.collections.*;
import org.apache.juneau.http.annotation.*;
@@ -40,13 +39,13 @@ import org.apache.juneau.http.annotation.*;
* </ul>
*/
@Response
-public class ReaderResource implements Writable {
+public class ReaderResource {
private final MediaType mediaType;
private final Map<String,Object> headers;
@SuppressWarnings("javadoc")
- protected final Object[] contents;
+ protected final Object contents;
/**
* Constructor.
@@ -55,7 +54,7 @@ public class ReaderResource implements Writable {
* @throws IOException Thrown by underlying stream.
*/
protected ReaderResource(ReaderResourceBuilder b) throws IOException {
- this(b.mediaType, b.headers, b.cached, b.contents.toArray());
+ this(b.mediaType, b.headers, b.cached, b.contents);
}
/**
@@ -78,10 +77,10 @@ public class ReaderResource implements Writable {
* </ul>
* @throws IOException Thrown by underlying stream.
*/
- public ReaderResource(MediaType mediaType, Map<String,Object> headers,
boolean cached, Object...contents) throws IOException {
+ public ReaderResource(MediaType mediaType, Map<String,Object> headers,
boolean cached, Object contents) throws IOException {
this.mediaType = mediaType;
this.headers = AMap.unmodifiable(headers);
- this.contents = cached ? new Object[]{readAll(contents)} :
contents;
+ this.contents = cached ? read(contents) : contents;
}
//-----------------------------------------------------------------------------------------------------------------
@@ -114,16 +113,26 @@ public class ReaderResource implements Writable {
return headers;
}
+ /**
+ * TODO
+ *
+ * @param w - TODO
+ * @return TODO
+ * @throws IOException TODO
+ */
@ResponseBody
- @Override /* Writeable */
public Writer writeTo(Writer w) throws IOException {
- for (Object o : contents)
- pipe(o, w);
+ if (contents != null)
+ pipe(contents, w);
return w;
}
+ /**
+ * TODO
+ *
+ * @return TODO
+ */
@ResponseHeader("Content-Type")
- @Override /* Writeable */
public String getMediaType() {
return mediaType == null ? null : mediaType.toString();
}
@@ -131,8 +140,6 @@ public class ReaderResource implements Writable {
@Override /* Object */
public String toString() {
try {
- if (contents.length == 1)
- return read(contents[0]);
return writeTo(new StringWriter()).toString();
} catch (IOException e) {
throw new RuntimeException(e);
@@ -145,8 +152,8 @@ public class ReaderResource implements Writable {
* @return The contents of this resource.
*/
public Reader getContents() {
- if (contents.length == 1 && contents[0] instanceof Reader) {
- return (Reader)contents[0];
+ if (contents instanceof Reader) {
+ return (Reader)contents;
}
return new StringReader(toString());
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
index 02f2e48..8991aa4 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
@@ -26,7 +26,7 @@ import org.apache.juneau.internal.*;
*/
public class ReaderResourceBuilder {
- ArrayList<Object> contents = new ArrayList<>();
+ Object contents;
MediaType mediaType;
Map<String,Object> headers = new LinkedHashMap<>();
boolean cached;
@@ -74,8 +74,8 @@ public class ReaderResourceBuilder {
* @return This object (for method chaining).
*/
@FluentSetter
- public ReaderResourceBuilder contents(Object...contents) {
- Collections.addAll(this.contents, contents);
+ public ReaderResourceBuilder contents(Object contents) {
+ this.contents = contents;
return this;
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
index 14b7526..917da4b 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
@@ -80,13 +80,11 @@ public class ResolvingReaderResource extends ReaderResource
{
@ResponseBody
@Override /* Writeable */
public Writer writeTo(Writer w) throws IOException {
- for (Object o : contents) {
- if (o != null) {
- if (varSession == null)
- pipe(o, w);
- else
- varSession.resolveTo(read(o), w);
- }
+ if (contents != null) {
+ if (varSession == null)
+ pipe(contents, w);
+ else
+ varSession.resolveTo(read(contents), w);
}
return w;
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
index 3808442..838c0f5 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
@@ -59,7 +59,7 @@ public class ResolvingResourceReaderBuilder extends
ReaderResourceBuilder {
}
@Override /* GENERATED - ReaderResourceBuilder */
- public ResolvingResourceReaderBuilder contents(Object...contents) {
+ public ResolvingResourceReaderBuilder contents(Object contents) {
super.contents(contents);
return this;
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Resource.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Resource.java
new file mode 100644
index 0000000..d2cbfe9
--- /dev/null
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Resource.java
@@ -0,0 +1,34 @@
+//
***************************************************************************************************************************
+// * 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.juneau.http;
+
+import java.util.*;
+
+import org.apache.http.*;
+import org.apache.http.Header;
+import org.apache.juneau.http.annotation.*;
+
+/**
+ * An extension of an {@link HttpEntity} that also includes arbitrary headers.
+ */
+@Response
+public interface Resource extends HttpEntity {
+
+ /**
+ * Returns the list of headers associated with this resource.
+ *
+ * @return The list of headers associated with this resource.
+ */
+ @ResponseHeader("*")
+ List<Header> getHeaders();
+}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
index 449c9d3..3505a38 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
@@ -15,10 +15,8 @@ package org.apache.juneau.http;
import static org.apache.juneau.internal.IOUtils.*;
import java.io.*;
-import java.nio.*;
import java.util.*;
-import org.apache.juneau.*;
import org.apache.juneau.collections.*;
import org.apache.juneau.http.annotation.*;
@@ -40,14 +38,14 @@ import org.apache.juneau.http.annotation.*;
* </ul>
*/
@Response
-public class StreamResource implements Streamable {
+public class StreamResource {
private final MediaType mediaType;
- private final Object[] contents;
+ private final Object contents;
private final Map<String,Object> headers;
StreamResource(StreamResourceBuilder b) throws IOException {
- this(b.mediaType, b.headers, b.cached, b.contents.toArray());
+ this(b.mediaType, b.headers, b.cached, b.contents);
}
/**
@@ -71,10 +69,10 @@ public class StreamResource implements Streamable {
* </ul>
* @throws IOException Thrown by underlying stream.
*/
- public StreamResource(MediaType mediaType, Map<String,Object> headers,
boolean cached, Object...contents) throws IOException {
+ public StreamResource(MediaType mediaType, Map<String,Object> headers,
boolean cached, Object contents) throws IOException {
this.mediaType = mediaType;
this.headers = AMap.unmodifiable(headers);
- this.contents = cached ? new Object[]{readBytes(contents)} :
contents;
+ this.contents = cached ? readBytes(contents) : contents;
}
//-----------------------------------------------------------------------------------------------------------------
@@ -103,16 +101,25 @@ public class StreamResource implements Streamable {
return headers;
}
+ /**
+ * TODO
+ *
+ * @param os TODO
+ * @throws IOException TODO
+ */
@ResponseBody
- @Override /* Streamable */
public void streamTo(OutputStream os) throws IOException {
- for (Object c : contents)
- pipe(c, os);
+ if (contents != null)
+ pipe(contents, os);
os.flush();
}
+ /**
+ * TODO
+ *
+ * @return TODO
+ */
@ResponseHeader("Content-Type")
- @Override /* Streamable */
public String getMediaType() {
return mediaType == null ? null : mediaType.toString();
}
@@ -124,40 +131,17 @@ public class StreamResource implements Streamable {
* @throws IOException Thrown by underlying stream.
*/
public InputStream getContents() throws IOException {
- if (contents.length == 1) {
- Object c = contents[0];
- if (c != null) {
- if (c instanceof byte[])
- return new
ByteArrayInputStream((byte[])c);
- else if (c instanceof InputStream)
- return (InputStream)c;
- else if (c instanceof File)
- return new FileInputStream((File)c);
- else if (c instanceof CharSequence)
- return new
ByteArrayInputStream((((CharSequence)c).toString().getBytes(UTF8)));
- }
- }
- byte[][] bc = new byte[contents.length][];
- int c = 0;
- for (int i = 0; i < contents.length; i++) {
- Object o = contents[i];
- if (o == null)
- bc[i] = new byte[0];
- else if (o instanceof byte[])
- bc[i] = (byte[])o;
- else if (o instanceof InputStream)
- bc[i] = readBytes((InputStream)o, 1024);
- else if (o instanceof Reader)
- bc[i] = read((Reader)o).getBytes(UTF8);
- else if (o instanceof File)
- bc[i] = readBytes((File)o);
- else if (o instanceof CharSequence)
- bc[i] =
((CharSequence)o).toString().getBytes(UTF8);
- c += bc[i].length;
+ Object c = contents;
+ if (c != null) {
+ if (c instanceof byte[])
+ return new ByteArrayInputStream((byte[])c);
+ else if (c instanceof InputStream)
+ return (InputStream)c;
+ else if (c instanceof File)
+ return new FileInputStream((File)c);
+ else if (c instanceof CharSequence)
+ return new
ByteArrayInputStream((((CharSequence)c).toString().getBytes(UTF8)));
}
- ByteBuffer bb = ByteBuffer.allocate(c);
- for (byte[] b : bc)
- bb.put(b);
- return new ByteArrayInputStream(bb.array());
+ return null;
}
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
index 30934d6..e9770ec 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
@@ -25,7 +25,7 @@ import org.apache.juneau.internal.*;
* </ul>
*/
public class StreamResourceBuilder {
- ArrayList<Object> contents = new ArrayList<>();
+ Object contents = null;
MediaType mediaType;
Map<String,Object> headers = new LinkedHashMap<>();
boolean cached;
@@ -74,8 +74,8 @@ public class StreamResourceBuilder {
* @return This object (for method chaining).
*/
@FluentSetter
- public StreamResourceBuilder contents(Object...contents) {
- Collections.addAll(this.contents, contents);
+ public StreamResourceBuilder contents(Object contents) {
+ this.contents = contents;
return this;
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPart.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPart.java
index 0ea76bd..5b22113 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPart.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPart.java
@@ -12,8 +12,8 @@
//
***************************************************************************************************************************
package org.apache.juneau.httppart;
-import org.apache.juneau.parser.*;
-import org.apache.juneau.serializer.*;
+import org.apache.http.*;
+import org.apache.juneau.parser.ParseException;
/**
* Represents an instance of an HTTP part.
@@ -21,7 +21,7 @@ import org.apache.juneau.serializer.*;
* <p>
* Can be used to represent both request and response parts.
*/
-public class HttpPart {
+public class HttpPart implements NameValuePair {
private final String name;
private final Object opart;
private final String spart;
@@ -74,26 +74,20 @@ public class HttpPart {
this.opart = null;
}
- /**
- * Returns the name of the part.
- *
- * @return The name of the part.
- */
+ @Override /* NameValuePair */
public String getName() {
return name;
}
- /**
- * Returns the value of the part converted to a string.
- *
- * @return The value of the part converted to a string.
- * @throws SchemaValidationException HTTP part failed schema validation.
- * @throws SerializeException HTTP part could not be serialized.
- */
- public String asString() throws SchemaValidationException,
SerializeException {
+ @Override /* NameValuePair */
+ public String getValue() {
if (spart != null)
return spart;
- return serializer.serialize(partType, schema, opart);
+ try {
+ return serializer.serialize(partType, schema, opart);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
/**
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
index c715eb9..b86a75f 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
@@ -22,6 +22,7 @@ import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
+import org.apache.http.*;
import org.apache.juneau.*;
import org.apache.juneau.collections.*;
import org.apache.juneau.encoders.*;
@@ -610,6 +611,21 @@ public final class RestResponse extends
HttpServletResponseWrapper {
}
/**
+ * Sets a header from a {@link NameValuePair}.
+ *
+ * <p>
+ * Note that this bypasses the part serializer and set the header value
directly.
+ *
+ * @param pair The header to set. Nulls are ignored.
+ * @return This object (for method chaining).
+ */
+ public RestResponse header(NameValuePair pair) {
+ if (pair != null)
+ setHeader(pair.getName(), pair.getValue());
+ return this;
+ }
+
+ /**
* Sets a header on the request.
*
* @param schema
@@ -659,7 +675,7 @@ public final class RestResponse extends
HttpServletResponseWrapper {
* @throws SerializeException Header part could not be serialized.
*/
public void setHeader(HttpPart h) throws SchemaValidationException,
SerializeException {
- setHeaderSafe(h.getName(), h.asString());
+ setHeaderSafe(h.getName(), h.getValue());
}
/**
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/reshandlers/DefaultHandler.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/reshandlers/DefaultHandler.java
index 73ea7a5..c9be795 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/reshandlers/DefaultHandler.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/reshandlers/DefaultHandler.java
@@ -19,12 +19,14 @@ import java.io.*;
import java.lang.reflect.*;
import java.util.*;
+import org.apache.http.*;
import org.apache.juneau.http.*;
import org.apache.juneau.httppart.*;
import org.apache.juneau.httppart.bean.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.rest.*;
import org.apache.juneau.http.exception.*;
+import org.apache.juneau.http.header.*;
import org.apache.juneau.rest.util.FinishablePrintWriter;
import org.apache.juneau.rest.util.FinishableServletOutputStream;
import org.apache.juneau.serializer.*;
@@ -88,16 +90,29 @@ public class DefaultHandler implements ResponseHandler {
try {
Object ho = hm.getGetter().invoke(o);
String n = hm.getPartName();
- if ("*".equals(n) && ho instanceof Map)
{
- @SuppressWarnings("rawtypes")
Map m = (Map)ho;
- for (Object key : m.keySet()) {
- String k =
stringify(key);
- Object v = m.get(key);
- HttpPartSchema s =
hm.getSchema().getProperty(k);
- res.setHeader(new
HttpPart(k, RESPONSE_HEADER, s, hm.getSerializer(req.getPartSerializer()), v));
+ if ("*".equals(n)) {
+ for (Object ho2 : iterate(ho)) {
+ if (ho2 instanceof
Map.Entry) {
+
@SuppressWarnings("rawtypes")
+ Map.Entry e =
(Map.Entry)ho2;
+ String k =
stringify(e.getKey());
+ Object v =
e.getValue();
+ HttpPartSchema
s = hm.getSchema().getProperty(k);
+
res.setHeader(new HttpPart(k, RESPONSE_HEADER, s,
hm.getSerializer(req.getPartSerializer()), v));
+ } else if (ho2
instanceof NameValuePair) {
+ NameValuePair p
= (NameValuePair)ho2;
+
res.setHeader(p.getName(), p.getValue());
+ } else {
+ throw new
InternalServerError("Invalid type ''{0}'' for header ''{1}''",
hm.getPartName(), ho2 == null ? null : ho2.getClass().getName());
+ }
}
} else {
- res.setHeader(new HttpPart(n,
RESPONSE_HEADER, hm.getSchema(), hm.getSerializer(req.getPartSerializer()),
ho));
+ if (ho instanceof
NameValuePair) {
+ NameValuePair p =
(NameValuePair)ho;
+
res.setHeader(p.getName(), p.getValue());
+ } else {
+ res.setHeader(new
HttpPart(n, RESPONSE_HEADER, hm.getSchema(),
hm.getSerializer(req.getPartSerializer()), ho));
+ }
}
} catch (Exception e) {
throw new InternalServerError(e, "Could
not set header ''{0}''", hm.getPartName());
@@ -127,6 +142,19 @@ public class DefaultHandler implements ResponseHandler {
schema = rm.getSchema();
}
+ if (o instanceof HttpEntity) {
+ HttpEntity e = (HttpEntity)o;
+
res.header(e.getContentType()).header(e.getContentEncoding());
+ long contentLength = e.getContentLength();
+ if (contentLength >= 0)
+ res.header(ContentLength.of(contentLength));
+ try (OutputStream os = res.getNegotiatedOutputStream())
{
+ e.writeTo(os);
+ os.flush();
+ }
+ return true;
+ }
+
if (sm != null) {
Serializer s = sm.getSerializer();
MediaType mediaType = res.getMediaType();
@@ -218,4 +246,16 @@ public class DefaultHandler implements ResponseHandler {
req.getHeaders().getString("Accept", ""),
g.getSupportedMediaTypes()
);
}
-}
+
+ private Iterable<?> iterate(Object o) {
+ if (o == null)
+ return Collections.emptyList();
+ if (o instanceof Map)
+ return ((Map<?,?>)o).entrySet();
+ if (o.getClass().isArray())
+ return Arrays.asList(o);
+ if (o instanceof Collection)
+ return (Collection<?>)o;
+ throw new InternalServerError("Could not iterate over Headers
of type ''{0}''", o.getClass().getName());
+ }
+ }