/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.solder.servlet.http;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.inject.Inject;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jboss.solder.core.Requires;
/**
* @author <a href="http://community.jboss.org/people/dan.j.allen">Dan Allen</a>
*/
// todo support switching to https/http
@Requires("javax.servlet.Servlet")
public class RedirectBuilderImpl implements RedirectBuilder {
@Inject
private HttpServletRequest request;
@Inject
private HttpServletResponse response;
private String path = null;
private String fragment = null;
private Map<String, String[]> paramMap = new LinkedHashMap<String, String[]>();
private Map<String, String[]> headerMap = new LinkedHashMap<String, String[]>();
private List<Cookie> cookies = new ArrayList<Cookie>();
private int status = HttpServletResponse.SC_MOVED_TEMPORARILY;
private boolean encode = false;
public RedirectBuilder mirror() {
paramMap = new LinkedHashMap<String, String[]>(request.getParameterMap());
headerMap = new LinkedHashMap<String, String[]>();
for (Enumeration<String> names = request.getHeaderNames(); names.hasMoreElements();) {
String name = names.nextElement();
List<String> v = new ArrayList<String>();
for (Enumeration<String> values = request.getHeaders(name); values.hasMoreElements();) {
v.add(values.nextElement());
}
headerMap.put(name, v.toArray(new String[0]));
}
path = request.getRequestURI();
if (path.indexOf("#") >= 0) {
fragment = path.substring(path.indexOf("#") + 1);
}
return this;
}
public RedirectBuilder header(String name, Object... values) {
return header(true, name, values);
}
public RedirectBuilder header(boolean replace, String name, Object... values) {
List<String> stringValues = new ArrayList<String>(values.length);
if (!replace && headerMap.containsKey(name)) {
for (String existing : headerMap.get(name)) {
stringValues.add(existing);
}
}
for (Object value : values) {
if (value != null) {
stringValues.add(value.toString());
}
}
headerMap.put(name, stringValues.toArray(new String[0]));
return this;
}
public RedirectBuilder param(String name, Object... values) {
return param(true, name, values);
}
public RedirectBuilder param(boolean replace, String name, Object... values) {
List<String> stringValues = new ArrayList<String>(values.length);
if (!replace && paramMap.containsKey(name)) {
for (String existing : paramMap.get(name)) {
stringValues.add(existing);
}
}
for (Object value : values) {
if (value != null) {
stringValues.add(value.toString());
}
}
paramMap.put(name, stringValues.toArray(new String[0]));
return this;
}
public RedirectBuilder cookie(Cookie... cookies) {
for (Cookie c : cookies) {
this.cookies.add(c);
}
return this;
}
public RedirectBuilder fragment(String fragment) {
this.fragment = fragment;
return this;
}
public RedirectBuilder seeOther(String path) {
status = HttpServletResponse.SC_SEE_OTHER;
this.path = path;
return this;
}
public RedirectBuilder temporaryRedirect(String path) {
status = HttpServletResponse.SC_TEMPORARY_REDIRECT;
this.path = path;
return this;
}
public RedirectBuilder redirect() {
return redirect(null);
}
// TODO respect query string on path
public RedirectBuilder redirect(String path) {
status = HttpServletResponse.SC_MOVED_TEMPORARILY;
this.path = path;
return this;
}
public RedirectBuilder encodeSessionId() {
encode = true;
return this;
}
public void send() {
if (response.isCommitted()) {
throw new RuntimeException("Cannot issue redirect. Response already committed.");
}
String location = path;
if (location == null) {
location = request.getRequestURI();
} else if (!location.startsWith("/")) {
location = request.getContextPath() + location;
}
for (Entry<String, String[]> headers : headerMap.entrySet()) {
String name = headers.getKey();
for (String value : headers.getValue()) {
response.addHeader(name, value);
}
}
for (Cookie c : cookies) {
response.addCookie(c);
}
String query = "";
for (Entry<String, String[]> params : paramMap.entrySet()) {
String name = params.getKey();
for (String value : params.getValue()) {
// FIXME naive
query += (query.length() == 0 ? "?" : "&") + name + "=" + value;
}
}
location += query;
if (fragment != null) {
location += "#" + fragment;
}
try {
response.resetBuffer();
if (encode) {
location = response.encodeRedirectURL(location);
}
response.setHeader("Location", location);
response.setStatus(status);
response.getWriter().flush();
// more flexible to do it ourselves
// response.sendRedirect(response.encodeRedirectURL(location));
} catch (IOException e) {
throw new RuntimeException("Failed to issue redirect. " + e.getMessage());
}
}
}