/**
* 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.jooby.servlet;
import static java.util.Objects.requireNonNull;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.jooby.Cookie;
import org.jooby.MediaType;
import org.jooby.spi.NativeRequest;
import org.jooby.spi.NativeUpload;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
public class ServletServletRequest implements NativeRequest {
private HttpServletRequest req;
private String tmpdir;
private boolean multipart;
private String path;
private ServletUpgrade upgrade = noupgrade();
public ServletServletRequest(final HttpServletRequest req, final String tmpdir,
final boolean multipart) throws IOException {
this.req = requireNonNull(req, "HTTP req is required.");
this.tmpdir = requireNonNull(tmpdir, "A tmpdir is required.");
this.multipart = multipart;
String pathInfo = req.getPathInfo();
if (pathInfo == null) {
pathInfo = "/";
}
this.path = req.getContextPath() + URLDecoder.decode(pathInfo, "UTF-8");
}
public HttpServletRequest servletRequest() {
return req;
}
public ServletServletRequest(final HttpServletRequest req, final String tmpdir)
throws IOException {
this(req, tmpdir, multipart(req));
}
public ServletServletRequest with(final ServletUpgrade upgrade) {
this.upgrade = requireNonNull(upgrade, "An upgrade provider is required.");
return this;
}
@Override
public String method() {
return req.getMethod();
}
@Override
public Optional<String> queryString() {
return Optional.ofNullable(Strings.emptyToNull(req.getQueryString()));
}
@Override
public String path() {
return path;
}
@Override
public String rawPath() {
return req.getRequestURI();
}
@Override
public List<String> paramNames() {
return toList(req.getParameterNames());
}
private <T> List<T> toList(final Enumeration<T> enumeration) {
Builder<T> result = ImmutableList.builder();
while (enumeration.hasMoreElements()) {
result.add(enumeration.nextElement());
}
return result.build();
}
@Override
public List<String> params(final String name) throws Exception {
String[] values = req.getParameterValues(name);
if (values == null) {
return Collections.emptyList();
}
return Arrays.asList(values);
}
@Override
public Map<String, Object> attributes() {
final Enumeration<String> attributeNames = req.getAttributeNames();
if (!attributeNames.hasMoreElements()) {
return Collections.emptyMap();
}
return Collections.list(attributeNames).stream()
.collect(Collectors.toMap(Function.identity(), req::getAttribute));
}
@Override
public List<String> headers(final String name) {
return toList(req.getHeaders(name));
}
@Override
public Optional<String> header(final String name) {
return Optional.ofNullable(req.getHeader(name));
}
@Override
public List<String> headerNames() {
return toList(req.getHeaderNames());
}
@Override
public List<Cookie> cookies() {
javax.servlet.http.Cookie[] cookies = req.getCookies();
if (cookies == null) {
return ImmutableList.of();
}
return Arrays.stream(cookies)
.map(c -> {
Cookie.Definition cookie = new Cookie.Definition(c.getName(), c.getValue());
Optional.ofNullable(c.getComment()).ifPresent(cookie::comment);
Optional.ofNullable(c.getDomain()).ifPresent(cookie::domain);
Optional.ofNullable(c.getPath()).ifPresent(cookie::path);
return cookie.toCookie();
})
.collect(Collectors.toList());
}
@Override
public List<NativeUpload> files(final String name) throws IOException {
try {
if (multipart) {
return req.getParts().stream()
.filter(part -> part.getSubmittedFileName() != null && part.getName().equals(name))
.map(part -> new ServletUpload(part, tmpdir))
.collect(Collectors.toList());
}
return Collections.emptyList();
} catch (ServletException ex) {
throw new IOException("File not found: " + name, ex);
}
}
@Override
public InputStream in() throws IOException {
return req.getInputStream();
}
@Override
public String ip() {
return req.getRemoteAddr();
}
@Override
public String protocol() {
return req.getProtocol();
}
@Override
public boolean secure() {
return req.isSecure();
}
@Override
public <T> T upgrade(final Class<T> type) throws Exception {
return upgrade.upgrade(type);
}
@Override
public void startAsync(final Executor executor, final Runnable runnable) {
req.startAsync();
executor.execute(runnable);
}
private static boolean multipart(final HttpServletRequest req) {
String contentType = req.getContentType();
return contentType != null && contentType.toLowerCase().startsWith(MediaType.multipart.name());
}
private static ServletUpgrade noupgrade() {
return new ServletUpgrade() {
@Override
public <T> T upgrade(final Class<T> type) throws Exception {
throw new UnsupportedOperationException("");
}
};
}
}