This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch SLING-10871
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-api.git
The following commit(s) were added to refs/heads/SLING-10871 by this push:
new 860ca8b SLING-10871 : Add builder API for request/resource objects
860ca8b is described below
commit 860ca8bb40c2bf236c25ad74ae1c3ee13b9aaef9
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Sat Oct 16 10:01:53 2021 +0200
SLING-10871 : Add builder API for request/resource objects
---
.../apache/sling/api/request/builder/Builders.java | 45 ++
.../builder/SlingHttpServletRequestBuilder.java | 140 ++++
.../builder/SlingHttpServletResponseBuilder.java | 39 +
.../builder/SlingHttpServletResponseResult.java | 78 ++
.../api/request/builder/impl/HeaderSupport.java | 122 +++
.../api/request/builder/impl/HttpSessionImpl.java | 154 ++++
.../request/builder/impl/RequestParameterImpl.java | 92 +++
.../builder/impl/RequestParameterMapImpl.java | 56 ++
.../request/builder/impl/RequestPathInfoImpl.java | 80 ++
.../builder/impl/RequestProgressTrackerImpl.java | 71 ++
.../request/builder/impl/ServletContextImpl.java | 306 +++++++
.../builder/impl/SlingHttpServletRequestImpl.java | 892 +++++++++++++++++++++
.../builder/impl/SlingHttpServletResponseImpl.java | 387 +++++++++
.../sling/api/request/builder/package-info.java | 20 +
.../sling/api/request/builder/BuildersTest.java | 66 ++
.../request/builder/impl/HeaderSupportTest.java | 116 +++
.../request/builder/impl/HttpSessionImplTest.java | 104 +++
.../builder/impl/RequestParameterImplTest.java | 47 ++
.../builder/impl/RequestParameterMapImplTest.java | 49 ++
.../builder/impl/RequestPathInfoImplTest.java | 103 +++
.../impl/RequestProgressTrackerImplTest.java | 42 +
.../builder/impl/ServletContextImplTest.java | 263 ++++++
.../impl/SlingHttpServletRequestImplTest.java | 520 ++++++++++++
.../impl/SlingHttpServletResponseImplTest.java | 248 ++++++
24 files changed, 4040 insertions(+)
diff --git a/src/main/java/org/apache/sling/api/request/builder/Builders.java
b/src/main/java/org/apache/sling/api/request/builder/Builders.java
new file mode 100644
index 0000000..7e5e5d2
--- /dev/null
+++ b/src/main/java/org/apache/sling/api/request/builder/Builders.java
@@ -0,0 +1,45 @@
+/*
+ * 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.sling.api.request.builder;
+
+import org.apache.sling.api.request.builder.impl.SlingHttpServletRequestImpl;
+import org.apache.sling.api.request.builder.impl.SlingHttpServletResponseImpl;
+import org.apache.sling.api.resource.Resource;
+import org.jetbrains.annotations.NotNull;
+
+public class Builders {
+
+ /**
+ * Create a new request builder
+ * @param resource The resource
+ * @return A builder
+ * @throws IllegalArgumentException If resource is {@code null}
+ */
+ public static @NotNull SlingHttpServletRequestBuilder
newRequestBuilder(@NotNull final Resource resource) {
+ return new SlingHttpServletRequestImpl(resource);
+ }
+
+ /**
+ * Create a new response builder
+ * @return A builder
+ */
+ public static @NotNull SlingHttpServletResponseBuilder
newResponseBuilder() {
+ return new SlingHttpServletResponseImpl();
+ }
+}
\ No newline at end of file
diff --git
a/src/main/java/org/apache/sling/api/request/builder/SlingHttpServletRequestBuilder.java
b/src/main/java/org/apache/sling/api/request/builder/SlingHttpServletRequestBuilder.java
new file mode 100644
index 0000000..9f661a8
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/SlingHttpServletRequestBuilder.java
@@ -0,0 +1,140 @@
+/*
+ * 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.sling.api.request.builder;
+
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * Fluent helper for building a request.
+ *
+ * Instances of this interface are not thread-safe.
+ */
+@ProviderType
+public interface SlingHttpServletRequestBuilder {
+
+ /**
+ * Set the HTTP request method to use - defaults to GET
+ * @param method The HTTP method
+ * @return this object
+ * @throws IllegalArgumentException If method is {@code null}
+ */
+ @NotNull SlingHttpServletRequestBuilder withRequestMethod(@NotNull String
method);
+
+ /**
+ * Set the HTTP request's Content-Type
+ * @param content type
+ * @return this object
+ */
+ @NotNull SlingHttpServletRequestBuilder withContentType(String
contentType);
+
+ /**
+ * Use the supplied content as the request's body content
+ * @param content the content
+ * @return this object
+ */
+ @NotNull SlingHttpServletRequestBuilder withBody(String content);
+
+ /**
+ * Sets the optional selectors of the internal request, which influence
+ * the Servlet/Script resolution.
+ * @param selectors The selectors
+ * @return this object
+ */
+ @NotNull SlingHttpServletRequestBuilder withSelectors(String ...
selectors);
+
+ /**
+ * Sets the optional extension of the internal request, which influence
+ * the Servlet/Script resolution.
+ * @param extension The extension
+ * @return this object
+ */
+ @NotNull SlingHttpServletRequestBuilder withExtension(String extension);
+
+ /**
+ * Set a request parameter
+ * @param key The name of the parameter
+ * @param value The value of the parameter
+ * @return this object
+ * @throws IllegalArgumentException If key or value is {@code null}
+ */
+ @NotNull SlingHttpServletRequestBuilder withParameter(@NotNull String key,
@NotNull String value);
+
+ /**
+ * Set a request parameter
+ * @param key The name of the parameter
+ * @param values The values of the parameter
+ * @return this object
+ * @throws IllegalArgumentException If key or values is {@code null}
+ */
+ @NotNull SlingHttpServletRequestBuilder withParameter(@NotNull String key,
@NotNull String[] values);
+
+ /**
+ * Add the supplied request parameters to the current ones.
+ * @param parameters Additional parameters
+ * @return this object
+ * @throws IllegalArgumentException If parameters is {@code null}
+ */
+ @NotNull SlingHttpServletRequestBuilder withParameters(@NotNull
Map<String, String[]> parameters);
+
+ /**
+ * Use the request dispatcher from the provided request.
+ * @param request The request
+ * @return this object
+ * @throws IllegalArgumentException If request is {@code null}
+ */
+ @NotNull SlingHttpServletRequestBuilder useRequestDispatcherFrom(@NotNull
SlingHttpServletRequest request);
+
+ /**
+ * If a session is used, use the session from the provided request
+ * @param request The request
+ * @return this object
+ * @throws IllegalArgumentException If request is {@code null}
+ */
+ @NotNull SlingHttpServletRequestBuilder useSessionFrom(@NotNull
HttpServletRequest request);
+
+ /**
+ * Use the attributes backed by the provided request
+ * @param request The request
+ * @return this object
+ * @throws IllegalArgumentException If request is {@code null}
+ */
+ @NotNull SlingHttpServletRequestBuilder useAttributesFrom(@NotNull
HttpServletRequest request);
+
+ /**
+ * Use the servlet context from the provided request
+ * @param request The request
+ * @return this object
+ * @throws IllegalArgumentException If request is {@code null}
+ */
+ @NotNull SlingHttpServletRequestBuilder useServletContextFrom(@NotNull
HttpServletRequest request);
+
+ /**
+ * Build the request.
+ * Once this method has been called, the builder must not be used anymore.
A new builder
+ * needs to be created, to create a new request.
+ * @return A request object
+ */
+ @NotNull SlingHttpServletRequest build();
+}
\ No newline at end of file
diff --git
a/src/main/java/org/apache/sling/api/request/builder/SlingHttpServletResponseBuilder.java
b/src/main/java/org/apache/sling/api/request/builder/SlingHttpServletResponseBuilder.java
new file mode 100644
index 0000000..23f4752
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/SlingHttpServletResponseBuilder.java
@@ -0,0 +1,39 @@
+/*
+ * 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.sling.api.request.builder;
+
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * Fluent helper for building a response.
+ *
+ * Instances of this interface are not thread-safe.
+ */
+@ProviderType
+public interface SlingHttpServletResponseBuilder {
+
+ /**
+ * Build the response.
+ * Once this method has been called, the builder must not be used anymore.
A new builder
+ * needs to be created, to create a new response.
+ * @return A response object
+ */
+ @NotNull SlingHttpServletResponseResult build();
+}
\ No newline at end of file
diff --git
a/src/main/java/org/apache/sling/api/request/builder/SlingHttpServletResponseResult.java
b/src/main/java/org/apache/sling/api/request/builder/SlingHttpServletResponseResult.java
new file mode 100644
index 0000000..823c7d9
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/SlingHttpServletResponseResult.java
@@ -0,0 +1,78 @@
+/*
+ * 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.sling.api.request.builder;
+
+import javax.servlet.http.Cookie;
+
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * This is an extension of a {@link SlingHttpServletResponse} to get
+ * the result from a processing.
+ *
+ * Instances of this interface are not thread-safe.
+ */
+@ProviderType
+public interface SlingHttpServletResponseResult extends
SlingHttpServletResponse {
+
+ /**
+ * Build the response.
+ * Once this method has been called, the builder must not be used anymore.
A new builder
+ * needs to be created, to create a new response.
+ * @return A response object
+ */
+ @NotNull SlingHttpServletResponse build();
+
+ /**
+ * Get the content length
+ * @return The content length or {@code -1} if not set
+ */
+ long getContentLength();
+
+ /**
+ * Get the status message
+ * @return The status message or {@code null}.
+ */
+ String getStatusMessage();
+
+ /**
+ * Get the named cookie
+ * @param name The name of the cookie
+ * @return The cookie or {@code null} if no cookie with that name exists.
+ */
+ public Cookie getCookie(String name);
+
+ /**
+ * Get all cookies
+ * @return The array of cookies or {@code null} if no cookies are set.
+ */
+ Cookie[] getCookies();
+
+ /**
+ * Get the output as a byte array
+ */
+ byte [] getOutput();
+
+ /**
+ * Get the output as a string
+ */
+ String getOutputAsString();
+}
\ No newline at end of file
diff --git
a/src/main/java/org/apache/sling/api/request/builder/impl/HeaderSupport.java
b/src/main/java/org/apache/sling/api/request/builder/impl/HeaderSupport.java
new file mode 100644
index 0000000..f0f8793
--- /dev/null
+++ b/src/main/java/org/apache/sling/api/request/builder/impl/HeaderSupport.java
@@ -0,0 +1,122 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Manage HTTP headers for request and response.
+ */
+public class HeaderSupport {
+
+ private static final DateTimeFormatter RFC_1123_DATE_TIME =
DateTimeFormatter.RFC_1123_DATE_TIME;
+
+ private final Map<String, List<String>> headers = new LinkedHashMap<>();
+
+ public void addHeader(final String name, final String value) {
+ this.headers.computeIfAbsent(name, key -> new
ArrayList<>()).add(value);
+ }
+
+ public void addIntHeader(final String name, final int value) {
+ this.addHeader(name, Integer.toString(value));
+ }
+
+ public void addDateHeader(final String name, final long date) {
+ final Date d = new Date(date);
+ this.addHeader(name,
RFC_1123_DATE_TIME.format(d.toInstant().atOffset(ZoneOffset.UTC)));
+ }
+
+ public void setHeader(final String name, final String value) {
+ removeHeaders(name);
+ addHeader(name, value);
+ }
+
+ public void setIntHeader(final String name, final int value) {
+ removeHeaders(name);
+ addIntHeader(name, value);
+ }
+
+ public void setDateHeader(final String name, final long date) {
+ removeHeaders(name);
+ addDateHeader(name, date);
+ }
+
+ private void removeHeaders(final String name) {
+ this.headers.remove(name);
+ }
+
+ public boolean containsHeader(final String name) {
+ return this.headers.get(name) != null;
+ }
+
+ public String getHeader(final String name) {
+ final List<String> values = this.headers.get(name);
+ if ( values == null ) {
+ return null;
+ }
+ return values.get(0);
+ }
+
+ public int getIntHeader(String name) {
+ final String value = getHeader(name);
+ if ( value != null ) {
+ return Integer.valueOf(value);
+ }
+ return -1;
+ }
+
+ public long getDateHeader(final String name) {
+ final String value = getHeader(name);
+ if ( value != null ) {
+ try {
+ final Date date = Date.from(ZonedDateTime.parse(value,
RFC_1123_DATE_TIME).toInstant());
+ return date.getTime();
+ } catch (final DateTimeParseException ex) {
+ throw new IllegalArgumentException("Invalid date value: " +
value, ex);
+ }
+ }
+ return -1L;
+ }
+
+ public Collection<String> getHeaders(final String name) {
+ final List<String> values = new ArrayList<String>();
+ final List<String> headers = this.headers.get(name);
+ if ( headers != null ) {
+ values.addAll(headers);
+ }
+ return values;
+ }
+
+ public Collection<String> getHeaderNames() {
+ return this.headers.keySet();
+ }
+
+ public void reset() {
+ this.headers.clear();
+ }
+}
diff --git
a/src/main/java/org/apache/sling/api/request/builder/impl/HttpSessionImpl.java
b/src/main/java/org/apache/sling/api/request/builder/impl/HttpSessionImpl.java
new file mode 100644
index 0000000..19db6a2
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/impl/HttpSessionImpl.java
@@ -0,0 +1,154 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Internal {@link HttpSession} implementation.
+ */
+public class HttpSessionImpl implements HttpSession {
+
+ private final ServletContext servletContext;
+ private final Map<String, Object> attributeMap = new HashMap<String,
Object>();
+ private final String sessionID = UUID.randomUUID().toString();
+ private final long creationTime = System.currentTimeMillis();
+ private boolean invalidated = false;
+ private int maxActiveInterval = 1800;
+
+ public HttpSessionImpl(final ServletContext context) {
+ this.servletContext = context;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return this.servletContext;
+ }
+
+ @Override
+ public Object getAttribute(final String name) {
+ checkInvalidatedState();
+ return this.attributeMap.get(name);
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ checkInvalidatedState();
+ return Collections.enumeration(this.attributeMap.keySet());
+ }
+
+ @Override
+ public String getId() {
+ return this.sessionID;
+ }
+
+ @Override
+ public long getCreationTime() {
+ checkInvalidatedState();
+ return this.creationTime;
+ }
+
+ @Override
+ public Object getValue(final String name) {
+ checkInvalidatedState();
+ return getAttribute(name);
+ }
+
+ @Override
+ public String[] getValueNames() {
+ checkInvalidatedState();
+ return this.attributeMap.keySet().toArray(new
String[this.attributeMap.keySet().size()]);
+ }
+
+ @Override
+ public void putValue(final String name, final Object value) {
+ checkInvalidatedState();
+ setAttribute(name, value);
+ }
+
+ @Override
+ public void removeAttribute(final String name) {
+ checkInvalidatedState();
+ this.attributeMap.remove(name);
+ }
+
+ @Override
+ public void removeValue(final String name) {
+ checkInvalidatedState();
+ this.attributeMap.remove(name);
+ }
+
+ @Override
+ public void setAttribute(final String name, final Object value) {
+ checkInvalidatedState();
+ this.attributeMap.put(name, value);
+ }
+
+ @Override
+ public void invalidate() {
+ checkInvalidatedState();
+ this.invalidated = true;
+ }
+
+ private void checkInvalidatedState() {
+ if (invalidated) {
+ throw new IllegalStateException("Session is already invalidated.");
+ }
+ }
+
+ public boolean isInvalidated() {
+ return invalidated;
+ }
+
+ @Override
+ public boolean isNew() {
+ checkInvalidatedState();
+ return true;
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ checkInvalidatedState();
+ return creationTime;
+ }
+
+ @Override
+ public int getMaxInactiveInterval() {
+ return maxActiveInterval;
+ }
+
+ @Override
+ public void setMaxInactiveInterval(final int interval) {
+ this.maxActiveInterval = interval;
+ }
+
+ // --- unsupported operations ---
+ @Override
+ @SuppressWarnings("deprecation")
+ public javax.servlet.http.HttpSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git
a/src/main/java/org/apache/sling/api/request/builder/impl/RequestParameterImpl.java
b/src/main/java/org/apache/sling/api/request/builder/impl/RequestParameterImpl.java
new file mode 100644
index 0000000..4d99a60
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/impl/RequestParameterImpl.java
@@ -0,0 +1,92 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.sling.api.request.RequestParameter;
+
+/**
+ * Implementation of {@link RequestParameter}.
+ */
+public class RequestParameterImpl implements RequestParameter {
+
+ private static final String CONTENT_TYPE = "text/plain";
+
+ private final String name;
+ private final String value;
+
+ public RequestParameterImpl(final String name, final String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public byte[] get() {
+ return this.value.getBytes(StandardCharsets.UTF_8);
+ }
+
+ @Override
+ public String getContentType() {
+ return CONTENT_TYPE;
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ return new ByteArrayInputStream(this.get());
+ }
+
+ @Override
+ public String getFileName() {
+ return null;
+ }
+
+ @Override
+ public long getSize() {
+ return this.get().length;
+ }
+
+ @Override
+ public String getString() {
+ return this.value;
+ }
+
+ @Override
+ public String getString(final String encoding) throws
UnsupportedEncodingException {
+ return new String(this.get(), encoding);
+ }
+
+ @Override
+ public boolean isFormField() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return this.getString();
+ }
+}
diff --git
a/src/main/java/org/apache/sling/api/request/builder/impl/RequestParameterMapImpl.java
b/src/main/java/org/apache/sling/api/request/builder/impl/RequestParameterMapImpl.java
new file mode 100644
index 0000000..32a3887
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/impl/RequestParameterMapImpl.java
@@ -0,0 +1,56 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.sling.api.request.RequestParameter;
+import org.apache.sling.api.request.RequestParameterMap;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Implementation of {@link RequestParameterMap}.
+ */
+public class RequestParameterMapImpl extends LinkedHashMap<String,
RequestParameter[]>
+ implements RequestParameterMap {
+
+ public RequestParameterMapImpl(@NotNull final Map<String, String[]>
params) {
+ for(final Map.Entry<String, String[]> entry : params.entrySet()) {
+ final RequestParameter[] values = new
RequestParameter[entry.getValue().length];
+ int index = 0;
+ for(final String v : entry.getValue()) {
+ values[index] = new RequestParameterImpl(entry.getKey(), v);
+ index++;
+ }
+ this.put(entry.getKey(), values);
+ }
+ }
+
+ @Override
+ public RequestParameter getValue(final String name) {
+ RequestParameter[] params = getValues(name);
+ return (params != null && params.length > 0) ? params[0] : null;
+ }
+
+ @Override
+ public RequestParameter[] getValues(final String name) {
+ return this.get(name);
+ }
+}
diff --git
a/src/main/java/org/apache/sling/api/request/builder/impl/RequestPathInfoImpl.java
b/src/main/java/org/apache/sling/api/request/builder/impl/RequestPathInfoImpl.java
new file mode 100644
index 0000000..1181696
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/impl/RequestPathInfoImpl.java
@@ -0,0 +1,80 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import org.apache.sling.api.request.RequestPathInfo;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+
+/**
+ * {@link RequestPathInfo} implementation.
+ */
+public class RequestPathInfoImpl implements RequestPathInfo {
+
+ private final String extension;
+ private final String resourcePath;
+ private final String[] selectors;
+ private final String suffix;
+
+ private final ResourceResolver resourceResolver;
+
+ public RequestPathInfoImpl(final Resource resource,
+ final String[] selectors,
+ final String extension,
+ final String suffix) {
+ this.resourceResolver = resource.getResourceResolver();
+ this.resourcePath = resource.getPath();
+ this.selectors = selectors == null ? new String[0] : selectors;
+ this.extension = extension;
+ this.suffix = suffix;
+ }
+
+ @Override
+ public String getExtension() {
+ return this.extension;
+ }
+
+ @Override
+ public String getResourcePath() {
+ return this.resourcePath;
+ }
+
+ @Override
+ public String[] getSelectors() {
+ return this.selectors;
+ }
+
+ @Override
+ public String getSelectorString() {
+ return this.selectors.length == 0 ? null : String.join(".",
this.selectors);
+ }
+
+ @Override
+ public String getSuffix() {
+ return this.suffix;
+ }
+
+ @Override
+ public Resource getSuffixResource() {
+ if (suffix == null) {
+ return null;
+ }
+ return this.resourceResolver.getResource(suffix);
+ }
+}
diff --git
a/src/main/java/org/apache/sling/api/request/builder/impl/RequestProgressTrackerImpl.java
b/src/main/java/org/apache/sling/api/request/builder/impl/RequestProgressTrackerImpl.java
new file mode 100644
index 0000000..a0d7836
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/impl/RequestProgressTrackerImpl.java
@@ -0,0 +1,71 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.sling.api.request.RequestProgressTracker;
+
+/**
+ * Internal {@link RequestProgressTracker} implementation.
+ */
+public class RequestProgressTrackerImpl implements RequestProgressTracker {
+
+ @Override
+ public void log(String message) {
+ // does nothing in this mock class
+ }
+
+ @Override
+ public void log(String format, Object... args) {
+ // does nothing in this mock class
+ }
+
+ @Override
+ public void startTimer(String timerName) {
+ // does nothing in this mock class
+ }
+
+ @Override
+ public void logTimer(String timerName) {
+ // does nothing in this mock class
+ }
+
+ @Override
+ public void logTimer(String timerName, String format, Object... args) {
+ // does nothing in this mock class
+ }
+
+ @Override
+ public Iterator<String> getMessages() {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ // does nothing in this mock class
+ }
+
+ @Override
+ public void done() {
+ // does nothing in this mock class
+ }
+}
diff --git
a/src/main/java/org/apache/sling/api/request/builder/impl/ServletContextImpl.java
b/src/main/java/org/apache/sling/api/request/builder/impl/ServletContextImpl.java
new file mode 100644
index 0000000..7c4731b
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/impl/ServletContextImpl.java
@@ -0,0 +1,306 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRegistration.Dynamic;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspConfigDescriptor;
+
+/**
+ * Internal {@link ServletContext} implementation.
+ */
+public class ServletContextImpl implements ServletContext {
+
+ @Override
+ public String getMimeType(final String file) {
+ return "application/octet-stream";
+ }
+
+ // --- unsupported operations ---
+ @Override
+ public Object getAttribute(final String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ServletContext getContext(final String uriPath) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getContextPath() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getInitParameter(final String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getMajorVersion() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getMinorVersion() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RequestDispatcher getNamedDispatcher(final String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getRealPath(final String pPath) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(final String path) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public URL getResource(final String pPath) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public InputStream getResourceAsStream(final String path) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> getResourcePaths(final String path) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getServerInfo() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Servlet getServlet(final String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getServletContextName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Enumeration<String> getServletNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Enumeration<Servlet> getServlets() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void log(final String msg) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void log(final Exception exception, final String msg) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void log(final String msg, final Throwable throwable) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeAttribute(final String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setAttribute(final String name, final Object object) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getEffectiveMajorVersion() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getEffectiveMinorVersion() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean setInitParameter(final String name, final String value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Dynamic addServlet(final String servletName, final String
className) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Dynamic addServlet(final String servletName, final Servlet servlet)
{
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Dynamic addServlet(final String servletName, final Class<? extends
Servlet> servletClass) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends Servlet> T createServlet(final Class<T> clazz) throws
ServletException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ServletRegistration getServletRegistration(final String
servletName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, ? extends ServletRegistration>
getServletRegistrations() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FilterRegistration.Dynamic addFilter(final String filterName, final
String className) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FilterRegistration.Dynamic addFilter(final String filterName, final
Filter filter) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FilterRegistration.Dynamic addFilter(final String filterName, final
Class<? extends Filter> filterClass) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends Filter> T createFilter(final Class<T> clazz) throws
ServletException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FilterRegistration getFilterRegistration(final String filterName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SessionCookieConfig getSessionCookieConfig() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setSessionTrackingModes(final Set<SessionTrackingMode>
sessionTrackingModes) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addListener(final String pClassName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends EventListener> void addListener(final T listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addListener(final Class<? extends EventListener>
listenerClass) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends EventListener> T createListener(final Class<T> clazz) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public JspConfigDescriptor getJspConfigDescriptor() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void declareRoles(final String... roleNames) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getVirtualServerName() {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git
a/src/main/java/org/apache/sling/api/request/builder/impl/SlingHttpServletRequestImpl.java
b/src/main/java/org/apache/sling/api/request/builder/impl/SlingHttpServletRequestImpl.java
new file mode 100644
index 0000000..9ca89dd
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/impl/SlingHttpServletRequestImpl.java
@@ -0,0 +1,892 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.ListResourceBundle;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.ReadListener;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpUpgradeHandler;
+import javax.servlet.http.Part;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.adapter.SlingAdaptable;
+import org.apache.sling.api.request.RequestDispatcherOptions;
+import org.apache.sling.api.request.RequestParameter;
+import org.apache.sling.api.request.RequestParameterMap;
+import org.apache.sling.api.request.RequestPathInfo;
+import org.apache.sling.api.request.RequestProgressTracker;
+import org.apache.sling.api.request.builder.SlingHttpServletRequestBuilder;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Internal {@link SlingHttpServletRequest} implementation.
+ */
+public class SlingHttpServletRequestImpl extends SlingAdaptable
+ implements SlingHttpServletRequest, SlingHttpServletRequestBuilder {
+
+ /** Default http method */
+ private static final String DEFAULT_METHOD = "GET";
+
+ /** Protocol */
+ private static final String SECURE_PROTOCOL = "https";
+ private static final String HTTP_PROTOCOL = "http";
+
+ static final String CHARSET_SEPARATOR = ";charset=";
+
+ private static final ResourceBundle EMPTY_RESOURCE_BUNDLE = new
ListResourceBundle() {
+ @Override
+ protected Object[][] getContents() {
+ return new Object[0][0];
+ }
+ };
+
+ /** Required resource */
+ private final Resource resource;
+
+ /** Optional selectors */
+ private String[] selectors;
+
+ /** Optional extension */
+ private String extension;
+
+ /** HTTP method */
+ private String requestMethod = DEFAULT_METHOD;
+
+ /** Optional content type / character encoding */
+ private String contentType;
+ private String characterEncoding;
+
+ /** Optional body */
+ private String body;
+
+ /** Is the builder locked? */
+ private boolean locked = false;
+
+ /** Parameters map */
+ private final Map<String, String[]> parameters = new LinkedHashMap<>();
+
+ /** Request path info */
+ private RequestPathInfoImpl requestPathInfo;
+
+ /** Optional query string */
+ private String queryString;
+
+ /** The path info, calculated based on the provided resource */
+ private String pathInfo;
+
+ /** Attributes */
+ private final Dictionary<String, Object> attributeMap = new Hashtable<>();
+
+ /** On demand session */
+ private HttpSession session;
+
+ /** On demand request parameter map */
+ private RequestParameterMap requestParameterMap;
+
+ /** Headers */
+ private final HeaderSupport headerSupport = new HeaderSupport();
+
+ /** Cookies */
+ private final Map<String, Cookie> cookies = new LinkedHashMap<>();
+
+ /** Request progress tracker */
+ private final RequestProgressTracker progressTracker = new
RequestProgressTrackerImpl();
+
+ private HttpServletRequest sessionProvider;
+
+ private HttpServletRequest attributesProvider;
+
+ private ServletContext servletContext;
+
+ private SlingHttpServletRequest requestDispatcherProvider;
+
+ private boolean getInputStreamCalled;
+ private boolean getReaderCalled;
+
+ // the following fields are not settable atm
+ private final Locale locale = Locale.US;
+ private final String contextPath = "";
+ private final String scheme = HTTP_PROTOCOL;
+ private final String serverName = "localhost";
+ private final int serverPort = 80;
+ private String authType;
+ private String remoteUser;
+ private String remoteAddr;
+ private String remoteHost;
+ private int remotePort;
+ private String servletPath = "";
+ private String responseContentType;
+
+ /**
+ * Create a new request builder with the minimal information
+ * @param resource The resource
+ */
+ public SlingHttpServletRequestImpl(final @NotNull Resource resource) {
+ checkNotNull("resource", resource);
+ this.resource = resource;
+ }
+
+ private void checkLocked() {
+ if ( locked ) {
+ throw new IllegalStateException("The builder can't be reused.
Create a new builder instead.");
+ }
+ }
+
+ private void checkNotNull(final String info, final Object candidate) {
+ if (candidate == null) {
+ throw new IllegalArgumentException(info.concat(" is null"));
+ }
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder withRequestMethod(@NotNull
String method) {
+ this.checkLocked();
+ this.checkNotNull("method", method);
+ this.requestMethod = method.toUpperCase();
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder withContentType(final
String type) {
+ this.checkLocked();
+ final int pos =
type.indexOf(SlingHttpServletRequestImpl.CHARSET_SEPARATOR);
+ if ( pos != -1 ) {
+ this.contentType = type.substring(0, pos);
+ this.characterEncoding = type.substring(pos +
SlingHttpServletRequestImpl.CHARSET_SEPARATOR.length());
+ } else {
+ this.contentType = type;
+ }
+
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder withBody(final String
content) {
+ this.checkLocked();
+ this.body = content;
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder withSelectors(final String
... selectors) {
+ this.checkLocked();
+ this.selectors = selectors;
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder withExtension(final String
extension) {
+ this.checkLocked();
+ this.extension = extension;
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder withParameter(final
@NotNull String key, final @NotNull String value) {
+ this.checkLocked();
+ this.checkNotNull("key", key);
+ this.checkNotNull("value", value);
+ this.parameters.put(key, new String[] {value});
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder withParameter(final
@NotNull String key, final @NotNull String[] values) {
+ this.checkLocked();
+ this.checkNotNull("key", key);
+ this.checkNotNull("values", values);
+ this.parameters.put(key, values);
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder withParameters(final
@NotNull Map<String, String[]> parameters) {
+ this.checkLocked();
+ this.checkNotNull("parameters", parameters);
+ this.parameters.putAll(parameters);
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder useAttributesFrom(@NotNull
HttpServletRequest request) {
+ this.checkLocked();
+ this.checkNotNull("request", request);
+ this.attributesProvider = request;
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder
useServletContextFrom(@NotNull HttpServletRequest request) {
+ this.checkLocked();
+ this.checkNotNull("request", request);
+ this.servletContext = request.getServletContext();
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder useSessionFrom(@NotNull
HttpServletRequest request) {
+ this.checkLocked();
+ this.checkNotNull("request", request);
+ this.sessionProvider = request;
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequestBuilder
useRequestDispatcherFrom(@NotNull SlingHttpServletRequest request) {
+ this.checkLocked();
+ this.checkNotNull("request", request);
+ this.requestDispatcherProvider = request;
+ return this;
+ }
+
+ @Override
+ public @NotNull SlingHttpServletRequest build() {
+ this.checkLocked();
+ this.locked = true;
+
+ this.requestPathInfo = new RequestPathInfoImpl(this.resource,
this.selectors, this.extension, null);
+ this.queryString = this.formatQueryString();
+ this.pathInfo = this.buildPathInfo();
+
+ if ( this.servletContext == null ) {
+ this.servletContext = new ServletContextImpl();
+ }
+ if (this.body == null ) {
+ this.body = "";
+ }
+ return this;
+ }
+
+ private String buildPathInfo() {
+ final StringBuilder builder = new StringBuilder();
+
+ builder.append(this.requestPathInfo.getResourcePath());
+ if ( this.requestPathInfo.getSelectorString() != null ) {
+ builder.append('.');
+ builder.append(this.requestPathInfo.getSelectorString());
+ }
+
+ if ( this.requestPathInfo.getExtension() != null ) {
+ builder.append('.');
+ builder.append(this.requestPathInfo.getExtension());
+ }
+
+ if ( this.requestPathInfo.getSuffix() != null ) {
+ builder.append(this.requestPathInfo.getSuffix());
+ }
+
+ return builder.toString();
+ }
+
+ private String formatQueryString() {
+ final StringBuilder builder = new StringBuilder();
+ for (Map.Entry<String, String[]> entry :
this.getParameterMap().entrySet()) {
+ if (entry.getValue() != null) {
+ formatQueryStringParameter(builder, entry);
+ }
+ }
+ return builder.length() > 0 ? builder.toString() : null;
+ }
+
+ private static String encode(final String v) {
+ try {
+ return URLEncoder.encode(v, StandardCharsets.UTF_8.name());
+ } catch (final UnsupportedEncodingException uee) {
+ // UTF-8 is always supported, we return the string as-is to make
the compiler happy
+ return v;
+ }
+ }
+
+ private static void formatQueryStringParameter(final StringBuilder
builder, final Map.Entry<String, String[]> entry) {
+ for (String value : entry.getValue()) {
+ if (builder.length() != 0) {
+ builder.append('&');
+ }
+ builder.append(encode(entry.getKey()));
+ builder.append('=');
+ if (value != null) {
+ builder.append(encode(value));
+ }
+ }
+ }
+
+ @Override
+ public Resource getResource() {
+ return this.resource;
+ }
+
+ @Override
+ public ResourceResolver getResourceResolver() {
+ return this.getResource().getResourceResolver();
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return getSession(true);
+ }
+
+ @Override
+ public HttpSession getSession(final boolean create) {
+ if (this.session == null && create) {
+ if ( this.sessionProvider != null ) {
+ this.session = this.sessionProvider.getSession(create);
+ } else {
+ this.session = new HttpSessionImpl(this.servletContext);
+ }
+ }
+ return this.session;
+ }
+
+ @Override
+ public RequestPathInfo getRequestPathInfo() {
+ return this.requestPathInfo;
+ }
+
+ @Override
+ public Object getAttribute(final String name) {
+ if ( this.attributesProvider != null ) {
+ return this.attributesProvider.getAttribute(name);
+ }
+ return this.attributeMap.get(name);
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ if ( this.attributesProvider != null ) {
+ return this.attributesProvider.getAttributeNames();
+ }
+ return this.attributeMap.keys();
+ }
+
+ @Override
+ public void removeAttribute(final String name) {
+ if ( this.attributesProvider != null ) {
+ this.attributesProvider.removeAttribute(name);
+ } else {
+ this.attributeMap.remove(name);
+ }
+ }
+
+ @Override
+ public void setAttribute(final String name, final Object object) {
+ if ( this.attributesProvider != null ) {
+ this.attributesProvider.setAttribute(name, object);
+ } else {
+ this.attributeMap.put(name, object);
+ }
+ }
+
+ @Override
+ public String getParameter(final String name) {
+ final String[] values = this.parameters.get(name);
+ if (values != null && values.length > 0) {
+ return values[0];
+ }
+ return null;
+ }
+
+ @Override
+ public Map<String, String[]> getParameterMap() {
+ return Collections.unmodifiableMap(this.parameters);
+ }
+
+ @Override
+ public Enumeration<String> getParameterNames() {
+ return Collections.enumeration(this.parameters.keySet());
+ }
+
+ @Override
+ public String[] getParameterValues(final String name) {
+ return this.parameters.get(name);
+ }
+
+ @Override
+ public RequestParameter getRequestParameter(final String name) {
+ return this.getRequestParameterMap().getValue(name);
+ }
+
+ @Override
+ public RequestParameterMap getRequestParameterMap() {
+ if ( this.requestParameterMap == null ) {
+ this.requestParameterMap = new
RequestParameterMapImpl(this.parameters);
+ }
+ return this.requestParameterMap;
+ }
+
+ @Override
+ public RequestParameter[] getRequestParameters(final String name) {
+ return this.getRequestParameterMap().get(name);
+ }
+
+ @Override
+ public List<RequestParameter> getRequestParameterList() {
+ final List<RequestParameter> params = new
ArrayList<RequestParameter>();
+ for (final RequestParameter[] requestParameters :
getRequestParameterMap().values()) {
+ params.addAll(Arrays.asList(requestParameters));
+ }
+ return params;
+ }
+
+ @Override
+ public Collection<Part> getParts() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Part getPart(final String name) {
+ return null;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return this.locale;
+ }
+
+ @Override
+ public Enumeration<Locale> getLocales() {
+ return Collections.enumeration(Collections.singleton(getLocale()));
+ }
+
+ @Override
+ public String getContextPath() {
+ return this.contextPath;
+ }
+
+ @Override
+ public String getQueryString() {
+ return this.queryString;
+ }
+
+ @Override
+ public String getScheme() {
+ return this.scheme;
+ }
+
+ @Override
+ public String getServerName() {
+ return this.serverName;
+ }
+
+ @Override
+ public int getServerPort() {
+ return this.serverPort;
+ }
+
+ @Override
+ public boolean isSecure() {
+ return SECURE_PROTOCOL.equals(this.scheme);
+ }
+
+ @Override
+ public String getMethod() {
+ return this.requestMethod;
+ }
+
+ @Override
+ public long getDateHeader(final String name) {
+ return headerSupport.getDateHeader(name);
+ }
+
+ @Override
+ public String getHeader(final String name) {
+ return headerSupport.getHeader(name);
+ }
+
+ @Override
+ public Enumeration<String> getHeaderNames() {
+ return Collections.enumeration(headerSupport.getHeaderNames());
+ }
+
+ @Override
+ public Enumeration<String> getHeaders(final String name) {
+ return Collections.enumeration(headerSupport.getHeaders(name));
+ }
+
+ @Override
+ public int getIntHeader(final String name) {
+ return headerSupport.getIntHeader(name);
+ }
+
+ @Override
+ public Cookie getCookie(final String name) {
+ return this.cookies.get(name);
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ if ( this.cookies.isEmpty() ) {
+ return null;
+ }
+ return cookies.values().toArray(new Cookie[cookies.size()]);
+ }
+
+ @Override
+ public ResourceBundle getResourceBundle(final Locale locale) {
+ return getResourceBundle(null, locale);
+ }
+
+ @Override
+ public ResourceBundle getResourceBundle(final String baseName, final
Locale locale) {
+ return EMPTY_RESOURCE_BUNDLE;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return this.characterEncoding;
+ }
+
+ @Override
+ public void setCharacterEncoding(final String encoding) throws
UnsupportedEncodingException {
+ this.characterEncoding = encoding;
+ }
+
+ @Override
+ public String getContentType() {
+ if (this.contentType == null) {
+ return null;
+ } else if ( this.characterEncoding == null ) {
+ return this.contentType;
+ }
+ return
this.contentType.concat(CHARSET_SEPARATOR).concat(this.characterEncoding);
+ }
+
+ @Override
+ public ServletInputStream getInputStream() {
+ if (getReaderCalled) {
+ throw new IllegalStateException();
+ }
+ getInputStreamCalled = true;
+ return new ServletInputStream() {
+ private final InputStream is = new
ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
+
+ @Override
+ public int read() throws IOException {
+ return is.read();
+ }
+
+ @Override
+ public boolean isReady() {
+ return true;
+ }
+
+ @Override
+ public boolean isFinished() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setReadListener(ReadListener readListener) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public BufferedReader getReader() {
+ if (getInputStreamCalled) {
+ throw new IllegalStateException();
+ }
+ getReaderCalled = true;
+ return new BufferedReader(new StringReader(this.body));
+ }
+
+ @Override
+ public int getContentLength() {
+ return this.body.length();
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ return this.getContentLength();
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(final String path) {
+ if ( this.requestDispatcherProvider != null ) {
+ return this.requestDispatcherProvider.getRequestDispatcher(path);
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(final String path, final
RequestDispatcherOptions options) {
+ if ( this.requestDispatcherProvider != null ) {
+ return this.requestDispatcherProvider.getRequestDispatcher(path,
options);
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(final Resource resource) {
+ if ( this.requestDispatcherProvider != null ) {
+ return
this.requestDispatcherProvider.getRequestDispatcher(resource);
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(final Resource resource,
final RequestDispatcherOptions options) {
+ if ( this.requestDispatcherProvider != null ) {
+ return
this.requestDispatcherProvider.getRequestDispatcher(resource, options);
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return remoteUser;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return remoteAddr;
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return remoteHost;
+ }
+
+ @Override
+ public int getRemotePort() {
+ return remotePort;
+ }
+
+ @Override
+ public String getServletPath() {
+ return this.servletPath;
+ }
+
+ @Override
+ public String getPathInfo() {
+ return this.pathInfo;
+ }
+
+ @Override
+ public String getRequestURI() {
+ final StringBuilder requestUri = new StringBuilder();
+ requestUri.append(this.contextPath);
+ requestUri.append(this.servletPath);
+ requestUri.append(this.pathInfo);
+ return requestUri.toString();
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ final StringBuffer requestUrl = new StringBuffer();
+
+ requestUrl.append(this.scheme);
+ requestUrl.append("://");
+ requestUrl.append(this.serverName);
+ boolean includePort = true;
+ if ( (HTTP_PROTOCOL.equals(this.scheme) && this.serverPort == 80 )
+ || (SECURE_PROTOCOL.equals(this.scheme) && this.serverPort ==
443) ) {
+ includePort = false;
+ }
+ if ( includePort ) {
+ requestUrl.append(':');
+ requestUrl.append(this.serverPort);
+ }
+ requestUrl.append(getRequestURI());
+
+ return requestUrl;
+ }
+
+ @Override
+ public String getAuthType() {
+ return this.authType;
+ }
+
+ @Override
+ public String getResponseContentType() {
+ return responseContentType;
+ }
+
+ @Override
+ public Enumeration<String> getResponseContentTypes() {
+ return
Collections.enumeration(Collections.singleton(responseContentType));
+ }
+
+ @Override
+ public RequestProgressTracker getRequestProgressTracker() {
+ return this.progressTracker;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return this.servletContext;
+ }
+
+ // --- unsupported operations ---
+
+ @Override
+ public String getPathTranslated() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromUrl() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isUserInRole(String role) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getLocalAddr() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getLocalName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getLocalPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean authenticate(HttpServletResponse response) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void login(String pUsername, String password) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void logout() throws ServletException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public AsyncContext startAsync() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest,
ServletResponse servletResponse) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isAsyncStarted() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String changeSessionId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass)
throws IOException, ServletException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git
a/src/main/java/org/apache/sling/api/request/builder/impl/SlingHttpServletResponseImpl.java
b/src/main/java/org/apache/sling/api/request/builder/impl/SlingHttpServletResponseImpl.java
new file mode 100644
index 0000000..5ebeec6
--- /dev/null
+++
b/src/main/java/org/apache/sling/api/request/builder/impl/SlingHttpServletResponseImpl.java
@@ -0,0 +1,387 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.WriteListener;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.adapter.SlingAdaptable;
+import org.apache.sling.api.request.builder.SlingHttpServletResponseBuilder;
+import org.apache.sling.api.request.builder.SlingHttpServletResponseResult;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Internal {@link SlingHttpServletResponse} implementation.
+ */
+public class SlingHttpServletResponseImpl
+ extends SlingAdaptable
+ implements SlingHttpServletResponseResult, SlingHttpServletResponseBuilder
{
+
+ /** Headers */
+ private final HeaderSupport headerSupport = new HeaderSupport();
+
+ /** Cookies */
+ private final Map<String, Cookie> cookies = new LinkedHashMap<>();
+
+ private String contentType;
+
+ private String characterEncoding;
+
+ private Locale locale = Locale.US;
+
+ private long contentLength;
+
+ private int status;
+
+ private boolean isCommitted;
+
+ private String statusMessage;
+
+ private int bufferSize = 8192;
+
+ private ByteArrayOutputStream outputStream;
+
+ private ServletOutputStream servletOutputStream;
+
+ private PrintWriter printWriter;
+
+ /** Is the builder locked? */
+ private boolean locked = false;
+
+ private void checkLocked() {
+ if ( locked ) {
+ throw new IllegalStateException("The builder can't be reused.
Create a new builder instead.");
+ }
+ }
+
+ @Override
+ public @NotNull SlingHttpServletResponseResult build() {
+ this.checkLocked();
+ this.locked = true;
+ this.reset();
+ return this;
+ }
+
+ private void checkCommitted() {
+ if (isCommitted()) {
+ throw new IllegalStateException("Response already committed.");
+ }
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return this.characterEncoding;
+ }
+
+ @Override
+ public void setCharacterEncoding(final String encoding) {
+ this.characterEncoding = encoding;
+ }
+
+ @Override
+ public String getContentType() {
+ if (this.contentType == null) {
+ return null;
+ } else if ( this.characterEncoding == null ) {
+ return this.contentType;
+ }
+ return
this.contentType.concat(SlingHttpServletRequestImpl.CHARSET_SEPARATOR).concat(this.characterEncoding);
+ }
+
+ @Override
+ public void setContentType(final String type) {
+ final int pos =
type.indexOf(SlingHttpServletRequestImpl.CHARSET_SEPARATOR);
+ if ( pos != -1 ) {
+ this.contentType = type.substring(0, pos);
+ this.characterEncoding = type.substring(pos +
SlingHttpServletRequestImpl.CHARSET_SEPARATOR.length());
+ } else {
+ this.contentType = type;
+ }
+ }
+
+ @Override
+ public void setContentLength(final int len) {
+ this.contentLength = len;
+ }
+
+ @Override
+ public void setContentLengthLong(final long len) {
+ this.contentLength = len;
+ }
+
+ @Override
+ public void setStatus(final int sc, final String message) {
+ setStatus(sc);
+ this.statusMessage = message;
+ }
+
+ @Override
+ public void setStatus(final int sc) {
+ this.status = sc;
+ }
+
+ @Override
+ public int getStatus() {
+ return this.status;
+ }
+
+ @Override
+ public void sendError(final int sc, final String msg) {
+ this.setStatus(sc);
+ this.statusMessage = msg;
+ this.isCommitted = true;
+ }
+
+ @Override
+ public void sendError(final int sc) {
+ this.setStatus(sc);
+ this.statusMessage = null;
+ this.isCommitted = true;
+ }
+
+ @Override
+ public void sendRedirect(final String location) {
+ this.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ this.statusMessage = null;
+ this.setHeader("Location", location);
+ this.isCommitted = true;
+ }
+
+ @Override
+ public void addHeader(final String name, final String value) {
+ this.headerSupport.addHeader(name, value);
+ }
+
+ @Override
+ public void addIntHeader(final String name, final int value) {
+ this.headerSupport.addIntHeader(name, value);
+ }
+
+ @Override
+ public void addDateHeader(final String name, final long date) {
+ this.headerSupport.addDateHeader(name, date);
+ }
+
+ @Override
+ public void setHeader(final String name, final String value) {
+ this.headerSupport.setHeader(name, value);
+ }
+
+ @Override
+ public void setIntHeader(final String name, final int value) {
+ this.headerSupport.setIntHeader(name, value);
+ }
+
+ @Override
+ public void setDateHeader(final String name, final long date) {
+ this.headerSupport.setDateHeader(name, date);
+ }
+
+ @Override
+ public boolean containsHeader(final String name) {
+ return this.headerSupport.containsHeader(name);
+ }
+
+ @Override
+ public String getHeader(final String name) {
+ return this.headerSupport.getHeader(name);
+ }
+
+ @Override
+ public Collection<String> getHeaders(final String name) {
+ return this.headerSupport.getHeaders(name);
+ }
+
+ @Override
+ public Collection<String> getHeaderNames() {
+ return this.headerSupport.getHeaderNames();
+ }
+
+ private Charset getCharset() {
+ if ( this.characterEncoding == null ) {
+ return StandardCharsets.UTF_8;
+ }
+ return Charset.forName(this.characterEncoding);
+ }
+
+ @Override
+ public PrintWriter getWriter() {
+ if (this.printWriter == null) {
+ this.printWriter = new PrintWriter(new
OutputStreamWriter(getOutputStream(), getCharset()));
+ }
+ return this.printWriter;
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() {
+ if (this.servletOutputStream == null) {
+ this.servletOutputStream = new ServletOutputStream() {
+ @Override
+ public void write(int b) throws IOException {
+ outputStream.write(b);
+ }
+
+ @Override
+ public boolean isReady() {
+ return true;
+ }
+
+ @Override
+ public void setWriteListener(final WriteListener
writeListener) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ return this.servletOutputStream;
+ }
+
+ @Override
+ public void reset() {
+ this.checkCommitted();
+ this.cookies.clear();
+ this.headerSupport.reset();
+ this.status = HttpServletResponse.SC_OK;
+ this.contentLength = -1L;
+ this.statusMessage = null;
+ this.resetBuffer();
+ }
+
+ @Override
+ public void resetBuffer() {
+ this.checkCommitted();
+ this.outputStream = new ByteArrayOutputStream();
+ this.servletOutputStream = null;
+ this.printWriter = null;
+ }
+
+ @Override
+ public int getBufferSize() {
+ return this.bufferSize;
+ }
+
+ @Override
+ public void setBufferSize(final int size) {
+ this.bufferSize = size;
+ }
+
+ @Override
+ public void flushBuffer() {
+ this.isCommitted = true;
+ }
+
+ @Override
+ public boolean isCommitted() {
+ return isCommitted;
+ }
+
+ @Override
+ public void addCookie(final Cookie cookie) {
+ this.cookies.put(cookie.getName(), cookie);
+ }
+
+ @Override
+ public Locale getLocale() {
+ return locale;
+ }
+
+ @Override
+ public void setLocale(final Locale loc) {
+ this.locale = loc;
+ }
+
+ @Override
+ public long getContentLength() {
+ return this.contentLength;
+ }
+
+ @Override
+ public String getStatusMessage() {
+ return this.statusMessage;
+ }
+
+ @Override
+ public Cookie getCookie(final String name) {
+ return this.cookies.get(name);
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ if ( this.cookies.isEmpty() ) {
+ return null;
+ }
+ return cookies.values().toArray(new Cookie[cookies.size()]);
+ }
+
+ @Override
+ public byte[] getOutput() {
+ this.isCommitted = true;
+ if (printWriter != null) {
+ printWriter.flush();
+ }
+ if (servletOutputStream != null) {
+ try {
+ servletOutputStream.flush();
+ } catch (IOException ex) {
+ // ignore
+ }
+ }
+ return outputStream.toByteArray();
+ }
+
+ @Override
+ public String getOutputAsString() {
+ this.isCommitted = true;
+ return new String(getOutput(), this.getCharset());
+ }
+
+ // --- unsupported operations ---
+ @Override
+ public String encodeRedirectUrl(String url) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String encodeRedirectURL(String url) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String encodeUrl(String url) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String encodeURL(String url) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git
a/src/main/java/org/apache/sling/api/request/builder/package-info.java
b/src/main/java/org/apache/sling/api/request/builder/package-info.java
new file mode 100644
index 0000000..11251e6
--- /dev/null
+++ b/src/main/java/org/apache/sling/api/request/builder/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
[email protected]("1.0")
+package org.apache.sling.api.request.builder;
diff --git
a/src/test/java/org/apache/sling/api/request/builder/BuildersTest.java
b/src/test/java/org/apache/sling/api/request/builder/BuildersTest.java
new file mode 100644
index 0000000..35c0571
--- /dev/null
+++ b/src/test/java/org/apache/sling/api/request/builder/BuildersTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.sling.api.request.builder;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class BuildersTest {
+
+ @Test(expected = IllegalArgumentException.class)
+ public void createRequestBuilderNullResource() {
+ Builders.newRequestBuilder(null);
+ }
+
+ @Test
+ public void createRequestBuilder() {
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+ final Resource resource = Mockito.mock(Resource.class);
+ Mockito.when(resource.getPath()).thenReturn("/content/page");
+ Mockito.when(resource.getResourceResolver()).thenReturn(resolver);
+
+ final SlingHttpServletRequestBuilder builder =
Builders.newRequestBuilder(resource);
+ builder.withExtension("html").withSelectors("tidy", "json");
+
+ final SlingHttpServletRequest req = builder.build();
+ assertEquals(resource, req.getResource());
+ assertEquals(resolver, req.getResourceResolver());
+ assertEquals("html", req.getRequestPathInfo().getExtension());
+ assertEquals("/content/page",
req.getRequestPathInfo().getResourcePath());
+ assertEquals("tidy.json",
req.getRequestPathInfo().getSelectorString());
+ assertArrayEquals(new String[] {"tidy", "json"},
req.getRequestPathInfo().getSelectors());
+ assertNull(req.getRequestPathInfo().getSuffix());
+ assertNull(req.getRequestPathInfo().getSuffixResource());
+ }
+
+ @Test
+ public void createResponseBuilder() {
+ final SlingHttpServletResponseBuilder builder =
Builders.newResponseBuilder();
+ final SlingHttpServletResponseResult result = builder.build();
+ assertNotNull(result);
+ }
+}
diff --git
a/src/test/java/org/apache/sling/api/request/builder/impl/HeaderSupportTest.java
b/src/test/java/org/apache/sling/api/request/builder/impl/HeaderSupportTest.java
new file mode 100644
index 0000000..1bc7071
--- /dev/null
+++
b/src/test/java/org/apache/sling/api/request/builder/impl/HeaderSupportTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+public class HeaderSupportTest {
+
+ @Test public void testDateHeaders() {
+ final HeaderSupport support = new HeaderSupport();
+ // no header set, return -1
+ assertEquals(-1L, support.getDateHeader("date"));
+ // set/get date header as long
+ final long now = System.currentTimeMillis();
+ support.addDateHeader("date", now);
+ // precision is second (not millisecond)
+ assertEquals(now - (now % 1000), support.getDateHeader("date"));
+ assertNotNull(support.getHeader("date"));
+ // no need to test exact output of JDK formatter
+ assertTrue(support.getHeader("date").endsWith(" GMT"));
+ // wrong format
+ support.addHeader("nodate", "foo");
+ try {
+ support.getDateHeader("nodate");
+ fail();
+ } catch ( final IllegalArgumentException iae) {
+ // expected
+ }
+ }
+
+ @Test public void testIntDateHeaders() {
+ final HeaderSupport support = new HeaderSupport();
+ // no header set, return -1
+ assertEquals(-1L, support.getIntHeader("number"));
+ // set/get int header
+ support.addIntHeader("number", 5);
+ assertEquals(5, support.getIntHeader("number"));
+ assertEquals("5", support.getHeader("number"));
+ // wrong format
+ support.addHeader("nonumber", "foo");
+ try {
+ support.getIntHeader("nonumber");
+ fail();
+ } catch ( final NumberFormatException nfe) {
+ // expected
+ }
+ }
+
+ @Test public void testAddSetHeaders() {
+ final HeaderSupport support = new HeaderSupport();
+ support.addHeader("string", "a");
+ support.addHeader("string", "b");
+
+ support.addIntHeader("number", 3);
+ support.addIntHeader("number", 1);
+
+ support.addDateHeader("date", 300000000);
+ support.addDateHeader("date", 100000000);
+
+ assertEquals("a", support.getHeader("string"));
+ assertEquals(Arrays.asList("a", "b"), support.getHeaders("string"));
+
+ assertEquals("3", support.getHeader("number"));
+ assertEquals(Arrays.asList("3", "1"), support.getHeaders("number"));
+
+ assertEquals(300000000, support.getDateHeader("date"));
+ assertEquals(2, support.getHeaders("date").size());
+
+ support.setHeader("string", "c");
+ assertEquals("c", support.getHeader("string"));
+ assertEquals(Arrays.asList("c"), support.getHeaders("string"));
+
+ support.setIntHeader("number", 9);
+ assertEquals("9", support.getHeader("number"));
+ assertEquals(Arrays.asList("9"), support.getHeaders("number"));
+
+ support.setDateHeader("date", 900000000);
+ assertEquals(900000000, support.getDateHeader("date"));
+ assertEquals(1, support.getHeaders("date").size());
+
+ assertTrue(support.containsHeader("date"));
+ assertFalse(support.containsHeader("foo"));
+
+ assertTrue(support.getHeaders("foo").isEmpty());
+
+ assertEquals(Arrays.asList("string", "number", "date"), new
ArrayList<>(support.getHeaderNames()));
+
+ support.reset();
+ assertTrue(support.getHeaderNames().isEmpty());
+ }
+}
diff --git
a/src/test/java/org/apache/sling/api/request/builder/impl/HttpSessionImplTest.java
b/src/test/java/org/apache/sling/api/request/builder/impl/HttpSessionImplTest.java
new file mode 100644
index 0000000..667860f
--- /dev/null
+++
b/src/test/java/org/apache/sling/api/request/builder/impl/HttpSessionImplTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class HttpSessionImplTest {
+
+ @Test
+ public void testServletContext() {
+ HttpSessionImpl httpSession = new HttpSessionImpl(null);
+ assertNull(httpSession.getServletContext());
+ httpSession = new HttpSessionImpl(new ServletContextImpl());
+ assertNotNull(httpSession.getServletContext());
+ }
+
+ @Test
+ public void testId() {
+ HttpSessionImpl httpSession = new HttpSessionImpl(new
ServletContextImpl());
+ assertNotNull(httpSession.getId());
+ }
+
+ @Test
+ public void testCreationTime() {
+ HttpSessionImpl httpSession = new HttpSessionImpl(new
ServletContextImpl());
+ assertNotNull(httpSession.getCreationTime());
+ }
+
+ @Test
+ public void testAttributes() {
+ HttpSessionImpl httpSession = new HttpSessionImpl(new
ServletContextImpl());
+ httpSession.setAttribute("attr1", "value1");
+ assertTrue(httpSession.getAttributeNames().hasMoreElements());
+ assertEquals("value1", httpSession.getAttribute("attr1"));
+ httpSession.removeAttribute("attr1");
+ assertFalse(httpSession.getAttributeNames().hasMoreElements());
+ }
+
+ @Test
+ public void testValues() {
+ HttpSessionImpl httpSession = new HttpSessionImpl(new
ServletContextImpl());
+ httpSession.putValue("attr1", "value1");
+ assertEquals(1, httpSession.getValueNames().length);
+ assertEquals("value1", httpSession.getValue("attr1"));
+ httpSession.removeValue("attr1");
+ assertEquals(0, httpSession.getValueNames().length);
+ }
+
+ @Test
+ public void testInvalidate() {
+ HttpSessionImpl httpSession = new HttpSessionImpl(new
ServletContextImpl());
+ httpSession.invalidate();
+ assertTrue(httpSession.isInvalidated());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testInvalidateStateCheck() {
+ HttpSessionImpl httpSession = new HttpSessionImpl(new
ServletContextImpl());
+ httpSession.invalidate();
+ httpSession.getAttribute("attr1");
+ }
+
+ @Test
+ public void testIsNew() {
+ HttpSessionImpl httpSession = new HttpSessionImpl(new
ServletContextImpl());
+ assertTrue(httpSession.isNew());
+ }
+
+ @Test
+ public void testGetLastAccessedTime() {
+ HttpSessionImpl httpSession = new HttpSessionImpl(new
ServletContextImpl());
+ assertNotNull(httpSession.getLastAccessedTime());
+ }
+
+ @Test
+ public void testGetMaxInactiveInterval() {
+ HttpSessionImpl httpSession = new HttpSessionImpl(new
ServletContextImpl());
+ assertTrue(httpSession.getMaxInactiveInterval() > 0);
+ httpSession.setMaxInactiveInterval(123);
+ assertEquals(123, httpSession.getMaxInactiveInterval());
+ }
+}
diff --git
a/src/test/java/org/apache/sling/api/request/builder/impl/RequestParameterImplTest.java
b/src/test/java/org/apache/sling/api/request/builder/impl/RequestParameterImplTest.java
new file mode 100644
index 0000000..43d4feb
--- /dev/null
+++
b/src/test/java/org/apache/sling/api/request/builder/impl/RequestParameterImplTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Test;
+
+public class RequestParameterImplTest {
+
+ @Test public void testParameter() throws UnsupportedEncodingException {
+ final RequestParameterImpl param = new RequestParameterImpl("foo",
"bar");
+ assertEquals("foo", param.getName());
+ assertEquals("bar", param.getString());
+ assertArrayEquals("bar".getBytes(StandardCharsets.UTF_8), param.get());
+ assertEquals("text/plain", param.getContentType());
+ assertNotNull(param.getInputStream());
+ assertNull(param.getFileName());
+ assertEquals(3L, param.getSize());
+ assertEquals("bar", param.getString("UTF-8"));
+ assertTrue(param.isFormField());
+ assertEquals(param.getString(), param.toString());
+ }
+}
diff --git
a/src/test/java/org/apache/sling/api/request/builder/impl/RequestParameterMapImplTest.java
b/src/test/java/org/apache/sling/api/request/builder/impl/RequestParameterMapImplTest.java
new file mode 100644
index 0000000..366906e
--- /dev/null
+++
b/src/test/java/org/apache/sling/api/request/builder/impl/RequestParameterMapImplTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+public class RequestParameterMapImplTest {
+
+ @Test public void testMap() {
+ final Map<String, String[]> initial = new HashMap<>();
+ initial.put("foo", new String[] {"bar"});
+ initial.put("a", new String[] {"b", "c"});
+
+ final RequestParameterMapImpl map = new
RequestParameterMapImpl(initial);
+ assertEquals(2, map.size());
+ assertTrue(map.containsKey("foo"));
+ assertTrue(map.containsKey("a"));
+
+ assertEquals("bar", map.getValue("foo").getString());
+ assertEquals("b", map.getValue("a").getString());
+ assertNull(map.getValue("unknown"));
+ assertEquals(2, map.getValues("a").length);
+ assertEquals("b", map.getValues("a")[0].getString());
+ assertEquals("c", map.getValues("a")[1].getString());
+ }
+}
diff --git
a/src/test/java/org/apache/sling/api/request/builder/impl/RequestPathInfoImplTest.java
b/src/test/java/org/apache/sling/api/request/builder/impl/RequestPathInfoImplTest.java
new file mode 100644
index 0000000..3450f0c
--- /dev/null
+++
b/src/test/java/org/apache/sling/api/request/builder/impl/RequestPathInfoImplTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import org.apache.sling.api.request.RequestPathInfo;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class RequestPathInfoImplTest {
+
+ @Test
+ public void testExtension() {
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+ final Resource resource = Mockito.mock(Resource.class);
+ Mockito.when(resource.getPath()).thenReturn("/content/page");
+ Mockito.when(resource.getResourceResolver()).thenReturn(resolver);
+
+ RequestPathInfo requestPathInfo = new RequestPathInfoImpl(resource,
null, null, null);
+ assertNull(requestPathInfo.getExtension());
+ requestPathInfo = new RequestPathInfoImpl(resource, null, "ext", null);
+ assertEquals("ext", requestPathInfo.getExtension());
+ }
+
+ @Test
+ public void testResourcePath() {
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+ final Resource resource = Mockito.mock(Resource.class);
+ Mockito.when(resource.getPath()).thenReturn("/content/page");
+ Mockito.when(resource.getResourceResolver()).thenReturn(resolver);
+
+ RequestPathInfo requestPathInfo = new RequestPathInfoImpl(resource,
null, null, null);
+ assertEquals("/content/page", requestPathInfo.getResourcePath());
+ }
+
+ @Test
+ public void testSelector() {
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+ final Resource resource = Mockito.mock(Resource.class);
+ Mockito.when(resource.getPath()).thenReturn("/content/page");
+ Mockito.when(resource.getResourceResolver()).thenReturn(resolver);
+
+ RequestPathInfo requestPathInfo = new RequestPathInfoImpl(resource,
null, null, null);
+ assertNull(requestPathInfo.getSelectorString());
+ assertEquals(0, requestPathInfo.getSelectors().length);
+
+ requestPathInfo = new RequestPathInfoImpl(resource, new String[]
{"aa", "bb"}, null, null);
+ assertEquals("aa.bb", requestPathInfo.getSelectorString());
+ assertArrayEquals(new String[] { "aa", "bb" },
requestPathInfo.getSelectors());
+ }
+
+ @Test
+ public void testSuffix() {
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+ final Resource resource = Mockito.mock(Resource.class);
+ Mockito.when(resource.getPath()).thenReturn("/content/page");
+ Mockito.when(resource.getResourceResolver()).thenReturn(resolver);
+
+ RequestPathInfo requestPathInfo = new RequestPathInfoImpl(resource,
null, null, null);
+ assertNull(requestPathInfo.getSuffix());
+
+ requestPathInfo = new RequestPathInfoImpl(resource, null, null,
"/suffix");
+ assertEquals("/suffix", requestPathInfo.getSuffix());
+ }
+
+ @Test
+ public void testGetSuffixResource() {
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+ final Resource resource = Mockito.mock(Resource.class);
+ Mockito.when(resource.getPath()).thenReturn("/content/page");
+ Mockito.when(resource.getResourceResolver()).thenReturn(resolver);
+ final Resource suffixResource = Mockito.mock(Resource.class);
+
Mockito.when(resolver.getResource("/suffix")).thenReturn(suffixResource);
+
+ RequestPathInfo requestPathInfo = new RequestPathInfoImpl(resource,
null, null, null);
+ assertNull(requestPathInfo.getSuffixResource());
+
+ requestPathInfo = new RequestPathInfoImpl(resource, null, null,
"/suffix");
+ assertSame(suffixResource, requestPathInfo.getSuffixResource());
+ }
+}
diff --git
a/src/test/java/org/apache/sling/api/request/builder/impl/RequestProgressTrackerImplTest.java
b/src/test/java/org/apache/sling/api/request/builder/impl/RequestProgressTrackerImplTest.java
new file mode 100644
index 0000000..c757ba2
--- /dev/null
+++
b/src/test/java/org/apache/sling/api/request/builder/impl/RequestProgressTrackerImplTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import static org.junit.Assert.assertFalse;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.junit.Test;
+
+public class RequestProgressTrackerImplTest {
+
+ @Test public void testTracker() {
+ final RequestProgressTrackerImpl tracker = new
RequestProgressTrackerImpl();
+ // this test basically checks that all methods are callable
+ tracker.log("message");
+ tracker.log("%s", "message");
+ tracker.startTimer("foo");
+ tracker.logTimer("foo");
+ tracker.logTimer("foo", "%s", "msg");
+ assertFalse(tracker.getMessages().hasNext());
+ tracker.dump(new PrintWriter(new StringWriter()));
+ tracker.done();
+ }
+}
diff --git
a/src/test/java/org/apache/sling/api/request/builder/impl/ServletContextImplTest.java
b/src/test/java/org/apache/sling/api/request/builder/impl/ServletContextImplTest.java
new file mode 100644
index 0000000..a256627
--- /dev/null
+++
b/src/test/java/org/apache/sling/api/request/builder/impl/ServletContextImplTest.java
@@ -0,0 +1,263 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.EventListener;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
+
+import org.junit.Test;
+
+public class ServletContextImplTest {
+
+ @Test public void testContext() throws ServletException {
+ final ServletContextImpl context = new ServletContextImpl();
+ // the context is very useless, it throws an exception for most methods
+ assertEquals("application/octet-stream", context.getMimeType("file"));
+ try {
+ context.getAttribute("name");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getAttributeNames();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getContext("path");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getContextPath();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getInitParameter("name");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getInitParameterNames();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getMajorVersion();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getMinorVersion();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getNamedDispatcher("name");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getRealPath("path");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getRequestDispatcher("path");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getResource("path");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getResourceAsStream("path");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getResourcePaths("path");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getServerInfo();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getServlet("path");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getServletContextName();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getServletNames();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getServlets();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.log("msg");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.log("msg", new Exception());
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.log(new Exception(), "msg");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.removeAttribute("name");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.setAttribute("name", "value");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getEffectiveMajorVersion();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getEffectiveMinorVersion();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.setInitParameter("name", "value");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.addServlet("name", "classname");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.addServlet("name", new HttpServlet(){
+
+ });
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.addServlet("name", HttpServlet.class);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.addFilter("name", "classname");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.addFilter("name", new Filter(){
+
+ @Override
+ public void init(FilterConfig filterConfig) throws
ServletException {
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse
response, FilterChain chain)
+ throws IOException, ServletException {
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ });
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.addFilter("name", Filter.class);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.createServlet(HttpServlet.class);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getServletRegistration("name");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getServletRegistrations();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.createFilter(Filter.class);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getFilterRegistration("name");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getFilterRegistrations();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getSessionCookieConfig();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.setSessionTrackingModes(null);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getDefaultSessionTrackingModes();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getEffectiveSessionTrackingModes();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.addListener(new EventListener(){
+
+ });
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.addListener(EventListener.class);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.createListener(EventListener.class);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getJspConfigDescriptor();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getClassLoader();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.declareRoles("a");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ context.getVirtualServerName();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ }
+}
diff --git
a/src/test/java/org/apache/sling/api/request/builder/impl/SlingHttpServletRequestImplTest.java
b/src/test/java/org/apache/sling/api/request/builder/impl/SlingHttpServletRequestImplTest.java
new file mode 100644
index 0000000..49c3a37
--- /dev/null
+++
b/src/test/java/org/apache/sling/api/request/builder/impl/SlingHttpServletRequestImplTest.java
@@ -0,0 +1,520 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpSession;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.request.RequestDispatcherOptions;
+import org.apache.sling.api.request.RequestParameter;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class SlingHttpServletRequestImplTest {
+
+ private SlingHttpServletRequestImpl req;
+
+ private Resource resource;
+
+ @Before
+ public void setup() {
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+ this.resource = Mockito.mock(Resource.class);
+ Mockito.when(resource.getPath()).thenReturn("/content/page");
+ Mockito.when(resource.getResourceResolver()).thenReturn(resolver);
+
+ this.req = new SlingHttpServletRequestImpl(resource);
+ }
+
+ @Test(expected = IllegalStateException.class) public void
testCheckLocked() {
+ req.build();
+ req.withExtension("foo");
+ }
+
+ @Test public void testGetResource() {
+ req.build();
+ assertEquals(resource, req.getResource());
+ assertEquals(resource.getResourceResolver(),
req.getResourceResolver());
+ }
+
+ @Test public void testGetRequestPathInfo() {
+ req.withExtension("html").withSelectors("tidy", "json");
+ req.build();
+ assertEquals("html", req.getRequestPathInfo().getExtension());
+ assertEquals("/content/page",
req.getRequestPathInfo().getResourcePath());
+ assertEquals("tidy.json",
req.getRequestPathInfo().getSelectorString());
+ assertArrayEquals(new String[] {"tidy", "json"},
req.getRequestPathInfo().getSelectors());
+ assertNull(req.getRequestPathInfo().getSuffix());
+ assertNull(req.getRequestPathInfo().getSuffixResource());
+ }
+
+ @Test public void testInternalSession() {
+ req.build();
+ assertNull(req.getSession(false));
+ final HttpSession s = req.getSession();
+ assertNotNull(s);
+ assertSame(s, req.getSession(true));
+ assertTrue(s instanceof HttpSessionImpl);
+ }
+
+ @Test public void testProvidedSession() {
+ final SlingHttpServletRequest outer =
Mockito.mock(SlingHttpServletRequest.class);
+ final HttpSession outerSession = Mockito.mock(HttpSession.class);
+ Mockito.when(outer.getSession()).thenReturn(outerSession);
+ Mockito.when(outer.getSession(true)).thenReturn(outerSession);
+ Mockito.when(outerSession.getId()).thenReturn("provided");
+
+ req.useSessionFrom(outer).build();
+ assertNull(req.getSession(false));
+ final HttpSession s = req.getSession();
+ assertNotNull(s);
+ assertSame(s, req.getSession(true));
+ assertEquals("provided", s.getId());
+ }
+
+ @Test public void testInternalAttributes() {
+ req.build();
+ assertFalse(req.getAttributeNames().hasMoreElements());
+ req.setAttribute("a", "b");
+ assertEquals("b", req.getAttribute("a"));
+ assertEquals("a", req.getAttributeNames().nextElement());
+ req.removeAttribute("a");
+ assertFalse(req.getAttributeNames().hasMoreElements());
+ assertNull(req.getAttribute("a"));
+ }
+
+ @Test public void testProvidedAttributes() {
+ final SlingHttpServletRequest outer =
Mockito.mock(SlingHttpServletRequest.class);
+
+ req.useAttributesFrom(outer).build();
+ req.getAttributeNames();
+ Mockito.verify(outer, Mockito.atLeastOnce()).getAttributeNames();
+ req.getAttribute("foo");
+ Mockito.verify(outer, Mockito.atLeastOnce()).getAttribute("foo");
+ req.removeAttribute("foo");
+ Mockito.verify(outer, Mockito.atLeastOnce()).removeAttribute("foo");
+ req.setAttribute("foo", "bar");
+ Mockito.verify(outer, Mockito.atLeastOnce()).setAttribute("foo",
"bar");
+ }
+
+ @Test public void testParameters() {
+ req.withParameter("a", "b");
+ req.withParameter("c", new String[] {"d", "e"});
+ req.withParameters(Collections.singletonMap("f", new String[] {"g"}));
+ req.build();
+
+ assertEquals("b", req.getParameter("a"));
+ assertEquals("d", req.getParameter("c"));
+ assertEquals("g", req.getParameter("f"));
+ assertNull(req.getParameter("g"));
+
+ final Map<String, String[]> params = req.getParameterMap();
+ assertEquals(3, params.size());
+ assertArrayEquals(new String[] {"b"}, params.get("a"));
+ assertArrayEquals(new String[] {"d", "e"}, params.get("c"));
+ assertArrayEquals(new String[] {"g"}, params.get("f"));
+
+ assertNotNull(req.getRequestParameter("a"));
+ assertNotNull(req.getRequestParameter("c"));
+ assertNotNull(req.getRequestParameter("f"));
+ assertNull(req.getRequestParameter("g"));
+
+ assertEquals(1, req.getRequestParameters("a").length);
+ assertEquals(2, req.getRequestParameters("c").length);
+ assertEquals(1, req.getRequestParameters("f").length);
+ assertNull(req.getRequestParameters("g"));
+
+ final List<RequestParameter> list = req.getRequestParameterList();
+ assertEquals(4, list.size());
+
+ assertTrue(req.getParts().isEmpty());
+ assertNull(req.getPart("a"));
+ }
+
+ @Test public void testNoQueryString() {
+ req.build();
+ assertNull(req.getQueryString());
+ }
+
+ @Test public void testQueryString() {
+ req.withParameter("a", "b");
+ req.withParameter("c", new String[] {"d", "e"});
+ req.withParameters(Collections.singletonMap("f", new String[] {"g"}));
+ req.build();
+
+ assertEquals("a=b&c=d&c=e&f=g", req.getQueryString());
+ }
+
+ @Test public void testLocale() {
+ req.build();
+ assertEquals(Locale.US, req.getLocale());
+ assertEquals(Collections.singletonList(Locale.US),
Collections.list(req.getLocales()));
+ }
+
+ @Test public void testGetContextPath() {
+ req.build();
+ assertEquals("", req.getContextPath());
+ }
+
+ @Test public void testGetScheme() {
+ req.build();
+ assertEquals("http", req.getScheme());
+ }
+
+ @Test public void testGetServerName() {
+ req.build();
+ assertEquals("localhost", req.getServerName());
+ }
+
+ @Test public void testGetServerPort() {
+ req.build();
+ assertEquals(80, req.getServerPort());
+ }
+
+ @Test public void testIsSecure() {
+ req.build();
+ assertFalse(req.isSecure());
+ }
+
+ @Test public void testDefaultGetMethod() {
+ req.build();
+ assertEquals("GET", req.getMethod());
+ }
+
+ @Test public void testGetMethod() {
+ req.withRequestMethod("POST").build();
+ assertEquals("POST", req.getMethod());
+ }
+
+ @Test public void testHeaders() {
+ req.build();
+ assertFalse(req.getHeaderNames().hasMoreElements());
+ assertEquals(-1, req.getDateHeader("foo"));
+ assertEquals(-1, req.getIntHeader("foo"));
+ assertNull(req.getHeader("foo"));
+ assertFalse(req.getHeaders("foo").hasMoreElements());
+ }
+
+ @Test public void testCookies() {
+ req.build();
+ assertNull(req.getCookies());
+ assertNull(req.getCookie("name"));
+ }
+
+ @Test public void testGetResourceBundle() {
+ req.build();
+ assertNotNull(req.getResourceBundle(req.getLocale()));
+ assertNotNull(req.getResourceBundle("base", req.getLocale()));
+ }
+
+ @Test public void testGetCharacterEncoding() throws
UnsupportedEncodingException {
+ req.build();
+ assertNull(req.getCharacterEncoding());
+ req.setCharacterEncoding("UTF-8");
+ assertEquals("UTF-8", req.getCharacterEncoding());
+ }
+
+ @Test public void testDefaultContentType() throws
UnsupportedEncodingException {
+ req.build();
+ assertNull(req.getContentType());
+ }
+
+ @Test public void testContentType() throws UnsupportedEncodingException {
+ req.withContentType("text/text").build();
+ assertEquals("text/text", req.getContentType());
+ assertNull(req.getCharacterEncoding());
+ req.setCharacterEncoding("UTF-8");
+ assertEquals("UTF-8", req.getCharacterEncoding());
+ assertEquals("text/text;charset=UTF-8", req.getContentType());
+ }
+
+ @Test public void testContentTypeAndCharset() throws
UnsupportedEncodingException {
+ req.withContentType("text/text;charset=UTF-16").build();
+ assertEquals("text/text;charset=UTF-16", req.getContentType());
+ assertEquals("UTF-16", req.getCharacterEncoding());
+ req.setCharacterEncoding("UTF-8");
+ assertEquals("UTF-8", req.getCharacterEncoding());
+ assertEquals("text/text;charset=UTF-8", req.getContentType());
+ }
+
+ @Test public void testNoBody() {
+ req.build();
+ assertEquals(0, req.getContentLength());
+ assertEquals(0L, req.getContentLengthLong());
+ }
+
+ @Test public void testBodyReader() throws IOException {
+ req.withBody("body").build();
+ assertEquals(4, req.getContentLength());
+ assertEquals(4L, req.getContentLengthLong());
+ final Reader r = req.getReader();
+ try {
+ req.getInputStream();
+ fail();
+ } catch ( final IllegalStateException iae) {}
+ final char[] cbuf = new char[96];
+ final int l = r.read(cbuf);
+ assertEquals("body", new String(cbuf, 0, l));
+ }
+
+ @Test public void testBodyInputStream() throws IOException {
+ req.withBody("body").build();
+ assertEquals(4, req.getContentLength());
+ assertEquals(4L, req.getContentLengthLong());
+ final InputStream in = req.getInputStream();
+ try {
+ req.getReader();
+ fail();
+ } catch ( final IllegalStateException iae) {}
+ final byte[] buf = new byte[96];
+ final int l = in.read(buf);
+ assertEquals("body", new String(buf, 0, l));
+ }
+
+ @Test public void testDefaultRequestDispatcher() {
+ final Resource rsrc = Mockito.mock(Resource.class);
+ req.build();
+ try {
+ req.getRequestDispatcher("/path");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getRequestDispatcher("/path", new RequestDispatcherOptions());
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getRequestDispatcher(rsrc);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getRequestDispatcher(rsrc, new RequestDispatcherOptions());
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ }
+
+ @Test public void testProvidedRequestDispatcher() {
+ final Resource rsrc = Mockito.mock(Resource.class);
+ final RequestDispatcherOptions opts = new RequestDispatcherOptions();
+ final SlingHttpServletRequest outer =
Mockito.mock(SlingHttpServletRequest.class);
+ req.useRequestDispatcherFrom(outer).build();
+
+ req.getRequestDispatcher("/path");
+ Mockito.verify(outer, Mockito.times(1)).getRequestDispatcher("/path");
+ req.getRequestDispatcher("/path", opts);
+ Mockito.verify(outer, Mockito.times(1)).getRequestDispatcher("/path",
opts);
+ req.getRequestDispatcher(rsrc);
+ Mockito.verify(outer, Mockito.times(1)).getRequestDispatcher(rsrc);
+ req.getRequestDispatcher(rsrc, opts);
+ Mockito.verify(outer, Mockito.times(1)).getRequestDispatcher(rsrc,
opts);
+ }
+
+ @Test public void testGetRemoteUser() {
+ req.build();
+ assertNull(req.getRemoteUser());
+ }
+
+ @Test public void testGetRemoteAddr() {
+ req.build();
+ assertNull(req.getRemoteAddr());
+ }
+
+ @Test public void testGetRemoteHost() {
+ req.build();
+ assertNull(req.getRemoteHost());
+ }
+
+ @Test public void testGetRemotePort() {
+ req.build();
+ assertEquals(0, req.getRemotePort());
+ }
+
+ @Test public void testGetServletPath() {
+ req.build();
+ assertEquals("", req.getServletPath());
+ }
+
+ @Test public void testGetPathInfo() {
+ req.build();
+ assertEquals("/content/page", req.getPathInfo());
+ }
+
+ @Test public void testGetRequestURI() {
+ req.build();
+ assertEquals("/content/page", req.getRequestURI());
+ }
+
+ @Test public void testGetRequestURL() {
+ req.build();
+ assertEquals("http://localhost/content/page",
req.getRequestURL().toString());
+ }
+
+ @Test public void testGetAuthType() {
+ req.build();
+ assertNull(req.getAuthType());
+ }
+
+ @Test public void getResponseContentType() {
+ req.build();
+ assertNull(req.getResponseContentType());
+ assertEquals(Collections.singletonList(null),
Collections.list(req.getResponseContentTypes()));
+ }
+
+ @Test public void testGetRequestProgressTracker() {
+ req.build();
+ assertNotNull(req.getRequestProgressTracker());
+ }
+
+ @Test public void testDefaultServletContext() {
+ req.build();
+ final ServletContext ctx = req.getServletContext();
+ assertNotNull(ctx);
+ assertTrue(ctx instanceof ServletContextImpl);
+ }
+
+ @Test public void testProvidedServletContext() {
+ final SlingHttpServletRequest outer =
Mockito.mock(SlingHttpServletRequest.class);
+ final ServletContext outerCtx = Mockito.mock(ServletContext.class);
+ Mockito.when(outer.getServletContext()).thenReturn(outerCtx);
+
+ req.useServletContextFrom(outer).build();
+ final ServletContext ctx = req.getServletContext();
+ assertNotNull(ctx);
+ Mockito.verify(outer, Mockito.times(1)).getServletContext();
+ assertFalse(ctx instanceof ServletContextImpl);
+ }
+
+ @Test public void testUnsupportedMethods() throws ServletException,
IOException {
+ req.build();
+ try {
+ req.getPathTranslated();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getRequestedSessionId();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getUserPrincipal();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.isRequestedSessionIdFromCookie();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.isRequestedSessionIdFromURL();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.isRequestedSessionIdFromUrl();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.isRequestedSessionIdValid();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.isUserInRole("foo");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getLocalAddr();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getLocalName();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getLocalPort();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getRealPath("path");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.authenticate(null);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.login("u", "p");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.logout();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.startAsync();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.startAsync(null, null);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.isAsyncStarted();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.isAsyncSupported();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getAsyncContext();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.getDispatcherType();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.changeSessionId();
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ req.upgrade(null);
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ }
+}
diff --git
a/src/test/java/org/apache/sling/api/request/builder/impl/SlingHttpServletResponseImplTest.java
b/src/test/java/org/apache/sling/api/request/builder/impl/SlingHttpServletResponseImplTest.java
new file mode 100644
index 0000000..8543788
--- /dev/null
+++
b/src/test/java/org/apache/sling/api/request/builder/impl/SlingHttpServletResponseImplTest.java
@@ -0,0 +1,248 @@
+/*
+ * 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.sling.api.request.builder.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.util.Locale;
+
+import javax.servlet.http.Cookie;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SlingHttpServletResponseImplTest {
+
+ private SlingHttpServletResponseImpl res;
+
+ @Before
+ public void setup() {
+ this.res = new SlingHttpServletResponseImpl();
+ }
+
+ @Test(expected = IllegalStateException.class) public void
testCheckLocked() {
+ try {
+ res.build();
+ } catch ( final IllegalStateException error) {
+ fail();
+ }
+ res.build();
+ }
+
+
+ @Test public void testGetCharacterEncoding() throws
UnsupportedEncodingException {
+ res.build();
+ assertNull(res.getCharacterEncoding());
+ res.setCharacterEncoding("UTF-8");
+ assertEquals("UTF-8", res.getCharacterEncoding());
+ }
+
+ @Test public void testDefaultContentType() throws
UnsupportedEncodingException {
+ res.build();
+ assertNull(res.getContentType());
+ }
+
+ @Test public void testContentType() throws UnsupportedEncodingException {
+ res.build();
+ res.setContentType("text/text");
+ assertEquals("text/text", res.getContentType());
+ assertNull(res.getCharacterEncoding());
+ res.setCharacterEncoding("UTF-8");
+ assertEquals("UTF-8", res.getCharacterEncoding());
+ assertEquals("text/text;charset=UTF-8", res.getContentType());
+ }
+
+ @Test public void testContentTypeAndCharset() throws
UnsupportedEncodingException {
+ res.build();
+ res.setContentType("text/text;charset=UTF-16");
+ assertEquals("text/text;charset=UTF-16", res.getContentType());
+ assertEquals("UTF-16", res.getCharacterEncoding());
+ res.setCharacterEncoding("UTF-8");
+ assertEquals("UTF-8", res.getCharacterEncoding());
+ assertEquals("text/text;charset=UTF-8", res.getContentType());
+ }
+
+ @Test public void testContentLength() {
+ res.build();
+ assertEquals(-1L, res.getContentLength());
+ res.setContentLength(500);
+ assertEquals(500L, res.getContentLength());
+ res.setContentLengthLong(5000L);
+ assertEquals(5000L, res.getContentLength());
+ }
+
+ @Test public void testSetStatus() {
+ res.build();
+ assertEquals(200, res.getStatus());
+ assertNull(res.getStatusMessage());
+
+ res.setStatus(201);
+ assertEquals(201, res.getStatus());
+ assertNull(res.getStatusMessage());
+
+ res.setStatus(202, "msg");
+ assertEquals(202, res.getStatus());
+ assertEquals("msg", res.getStatusMessage());
+
+ assertFalse(res.isCommitted());
+ }
+
+ @Test public void testSendError() {
+ res.build();
+ res.sendError(500);
+ assertEquals(500, res.getStatus());
+ assertNull(res.getStatusMessage());
+ assertTrue(res.isCommitted());
+ }
+
+ @Test public void testSendErrorWithMessage() {
+ res.build();
+ res.sendError(500, "msg");
+ assertEquals(500, res.getStatus());
+ assertEquals("msg", res.getStatusMessage());
+ assertTrue(res.isCommitted());
+ }
+
+ @Test public void testSendRedirect() {
+ res.build();
+ res.sendRedirect("/redirect");
+ assertEquals(302, res.getStatus());
+ assertNull(res.getStatusMessage());
+ assertTrue(res.isCommitted());
+ assertEquals("/redirect", res.getHeader("Location"));
+ }
+
+ @Test public void testHeaders() {
+ res.build();
+ assertTrue(res.getHeaderNames().isEmpty());
+ res.addDateHeader("date", 50000);
+ res.addIntHeader("number", 5);
+ res.addHeader("name", "value");
+ res.setDateHeader("adate", 100000);
+ res.setIntHeader("anumber", 10);
+ res.setHeader("aname", "something");
+
+ assertEquals(6, res.getHeaderNames().size());
+ assertEquals("Thu, 1 Jan 1970 00:00:50 GMT", res.getHeader("date"));
+ assertEquals("5", res.getHeader("number"));
+ assertEquals("value", res.getHeader("name"));
+ assertEquals("Thu, 1 Jan 1970 00:01:40 GMT", res.getHeader("adate"));
+ assertEquals("10", res.getHeader("anumber"));
+ assertEquals("something", res.getHeader("aname"));
+
+ assertTrue(res.containsHeader("name"));
+ assertFalse(res.containsHeader("foo"));
+
+ assertEquals(1, res.getHeaders("name").size());
+ }
+
+ @Test public void testGetWriter() {
+ res.build();
+ final PrintWriter writer = res.getWriter();
+ writer.write("body");
+ assertEquals("body", res.getOutputAsString());
+ assertEquals("body", new String(res.getOutput(),
StandardCharsets.UTF_8));
+ }
+
+ @Test public void testGetOutputStream() throws IOException {
+ res.build();
+ final OutputStream out = res.getOutputStream();
+ out.write("body".getBytes(StandardCharsets.UTF_8));
+ assertEquals("body", res.getOutputAsString());
+ assertEquals("body", new String(res.getOutput(),
StandardCharsets.UTF_8));
+ }
+
+ @Test public void testReset() {
+ res.build();
+ res.setStatus(201);
+ res.setContentLength(500);
+ res.reset();
+ assertEquals(200, res.getStatus());
+ assertEquals(-1L, res.getContentLength());
+ }
+
+ @Test public void testResetBuffer() {
+ res.build();
+ res.setStatus(201);
+ res.setContentLength(500);
+ res.resetBuffer();
+ assertEquals(201, res.getStatus());
+ assertEquals(500L, res.getContentLength());
+ }
+
+ @Test public void testBufferSize() {
+ res.build();
+ assertEquals(8192, res.getBufferSize());
+ res.setBufferSize(16384);
+ assertEquals(16384, res.getBufferSize());
+ }
+
+ @Test public void testFlushBuffer() {
+ res.build();
+ assertFalse(res.isCommitted());
+ res.flushBuffer();
+ assertTrue(res.isCommitted());
+ }
+
+ @Test public void testCookies() {
+ res.build();
+ assertNull(res.getCookies());
+ res.addCookie(new Cookie("name", "value"));
+ assertEquals(1, res.getCookies().length);
+ assertEquals("name", res.getCookies()[0].getName());
+ assertNotNull(res.getCookie("name"));
+ }
+
+ @Test public void testLocale() {
+ res.build();
+ assertEquals(Locale.US, res.getLocale());
+ res.setLocale(Locale.CANADA);
+ assertEquals(Locale.CANADA, res.getLocale());
+ }
+
+ @Test public void testUnsupportedMethods() {
+ res.build();
+ try {
+ res.encodeRedirectURL("/url");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ res.encodeRedirectUrl("/url");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ res.encodeURL("/url");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ try {
+ res.encodeUrl("/url");
+ fail();
+ } catch ( final UnsupportedOperationException expected) {}
+ }
+}