/**
* Copyright (C) 2012 BonitaSoft S.A.
* BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.web.toolkit.server;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.io.IOUtils;
import org.bonitasoft.web.toolkit.client.common.exception.http.ServerException;
import org.bonitasoft.web.toolkit.client.common.json.JSonSerializer;
import org.bonitasoft.web.toolkit.server.utils.LocaleUtils;
/**
* @author Séverin Moussel
* @author Baptiste Mesta
* @author Fabio Lombardi
*
*/
public abstract class ServletCall {
private String inputStream = null;
/**
* The parameters of the URL.<br />
* Result of the parsing of the query string : "?a=b&c=d&..."
*/
protected Map<String, String[]> parameters = new HashMap<String, String[]>();
/**
* The request made to access this servletCall.
*/
private final HttpServletRequest request;
/**
* The response to return.
*/
private final HttpServletResponse response;
/**
* Default constructor.
*
* @param request
* The request made to access this servletCall.
* @param response
* The response to return.
*/
public ServletCall(final HttpServletRequest request, final HttpServletResponse response) {
super();
this.request = request;
this.response = response;
parseRequest(request, response);
}
/**
* Constructor for tests
*/
public ServletCall(){
request = null;
response = null;
}
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PARAMETERS
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Get the current call's HttpSession
*
* @return This method returns the session from the current call.
*/
public HttpSession getHttpSession() {
return request.getSession();
}
/**
* @see javax.servlet.http.HttpServletRequest#getQueryString()
*/
public String getQueryString() {
return request.getQueryString();
}
/**
* Reconstruct the URL the client used to make the request.
* The returned URL contains a protocol, server name, port
* number, and server path, but it does not include query
* string parameters.
*
* @return This method returns the reconstructed URL
*/
public String getRequestURL() {
return request.getRequestURL().toString();
}
/**
* Read the input stream and set it in a String
*/
public String getInputStream() {
if (inputStream == null) {
BufferedReader reader = null;
try {
// BS-8474 - use custom reader instead of request reader to avoid JBoss5.1 bug
// see https://issues.jboss.org/browse/JBAS-7817
final ServletInputStream stream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
final StringBuilder sb = new StringBuilder();
String line = reader.readLine();
while (line != null) {
sb.append(line + "\n");
line = reader.readLine();
}
inputStream = sb.toString();
} catch (final IOException e) {
throw new RuntimeException("Can't read input Stream.", e);
} finally {
closeQuietly(reader);
}
}
return inputStream;
}
private void closeQuietly(final BufferedReader reader) {
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
// do nothing / close quietly
}
}
}
/**
* Count the number of parameters passed in the URL
*
* @return This method returns the number of parameters in the URL
*/
public int countParameters() {
return parameters.size();
}
/**
* Get a parameter values by its name
*
* @param name
* The name of the parameter (case sensitive)
* @return This method returns the values of a parameter as a list of String or null if the parameter isn't defined
*/
public List<String> getParameterAsList(final String name) {
return getParameterAsList(name, (String) null);
}
/**
* Get a parameter values by its name
*
* @param name
* The name of the parameter (case sensitive)
* @param defaultValue
* The value to return if the parameter isn't define
* @return This method returns the values of a parameter as a list of String
*/
public List<String> getParameterAsList(final String name, final String defaultValue) {
if (parameters.containsKey(name)) {
return Arrays.asList(parameters.get(name));
}
if (defaultValue != null) {
final List<String> results = new ArrayList<String>();
results.add(defaultValue);
return results;
}
return null;
}
/**
* Get a parameter first value by its name
*
* @param name
* The name of the parameter (case sensitive)
* @return This method returns the first value of a parameter as a String or null if the parameter isn't define
*/
public String getParameter(final String name) {
return getParameter(name, (String) null);
}
/**
* Get a parameter first value by its name
*
* @param name
* The name of the parameter (case sensitive)
* @param defaultValue
* The value to return if the parameter isn't define
* @return This method returns the first value of a parameter as a String
*/
public String getParameter(final String name, final String defaultValue) {
if (parameters.containsKey(name)) {
final String[] result = parameters.get(name);
if (result.length > 0) {
return result[0];
}
}
return defaultValue;
}
/**
* Get all the parameters
*
* @return This method returns all the parameters as a Map of array of String
*/
public Map<String, String[]> getParameters() {
return parameters;
}
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GENERATE RESPONSES
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Write into the output header.
*
* @param name
* The name of the header to write.
* @param value
* The value of the header to write.
*/
protected void head(final String name, final String value) {
response.addHeader(name, value);
}
/**
* Output a file
*
* @param file
* The file to output
*/
protected void output(final File file) {
try(InputStream stream = new FileInputStream(file)) {
output(stream);
} catch (final FileNotFoundException e) {
throw new ServerException(e);
} catch (IOException e) {
throw new ServerException(e);
}
}
/**
* Output a stream as a file
*
* @param stream
* The stream to output
* @param filename
* The name of the file to retrieve with the stream.
*/
protected void output(final InputStream stream, final String filename) {
response.addHeader("Content-Disposition", "attachment; filename=" + filename + ";");
output(stream);
}
/**
* Output a stream as a file
*
* @param stream
* The stream to output
*/
protected void output(final InputStream stream) {
response.setContentType("application/octet-stream");
try {
IOUtils.copy(stream, response.getOutputStream());
} catch (final IOException e) {
throw new ServerException(e);
}
}
/**
* Write into the output
*
* @param string
* The string to output
*/
protected void output(final String string) {
final PrintWriter outputWriter = getOutputWriter();
outputWriter.print(string);
outputWriter.flush();
}
/**
* Write into the output
*
* @param object
* An object that will be transform into JSon
*/
protected void output(final Object object) {
final PrintWriter outputWriter = getOutputWriter();
outputWriter.print(JSonSerializer.serialize(object));
outputWriter.flush();
}
/**
* The outputWriter in which to write the response String.
*/
private PrintWriter outputWriter = null;
/**
* Prepare the output
*
* @param response
*/
private PrintWriter getOutputWriter() {
if (outputWriter == null) {
response.setContentType("application/json;charset=UTF-8");
try {
outputWriter = response.getWriter();
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
return outputWriter;
}
/**
* Read elements form the request
* <ul>
* <li>API tokens</li>
* <li>item id (if defined)</li>
* <li>parameters</li>
* </ul>
*
* @param request
* @param response
*/
@SuppressWarnings("unchecked")
protected void parseRequest(final HttpServletRequest request, final HttpServletResponse response) {
// Create a new HashMap and copy all the elements in the new one
parameters.putAll(this.request.getParameterMap());
}
public String getLocale() {
return LocaleUtils.getUserLocale(request);
}
public HttpServletRequest getRequest() {
return request;
}
public HttpServletResponse getResponse() {
return response;
}
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// REQUEST ENTRY POINTS
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Entry point for GET and SEARCH
*/
public abstract void doGet();
/**
* Entry point for CREATE
*/
public abstract void doPost();
/**
* Entry point for UPDATE
*/
public abstract void doPut();
/**
* Entry point for DELETE
*/
public abstract void doDelete();
}