001/**
002 * Copyright 2014 Tampere University of Technology, Pori Department
003 * 
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * 
008 *   http://www.apache.org/licenses/LICENSE-2.0
009 * 
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package core.tut.pori.http;
017
018import java.io.IOException;
019import java.io.InputStream;
020import java.util.List;
021import java.util.Map;
022
023import javax.servlet.http.HttpServletRequest;
024import javax.servlet.http.HttpSession;
025
026import org.apache.commons.collections4.map.CaseInsensitiveMap;
027import org.apache.commons.lang3.StringUtils;
028import org.apache.log4j.Logger;
029
030import core.tut.pori.users.UserIdentity;
031import core.tut.pori.utils.HTTPParameterUtil;
032
033/**
034 * A service request definitions, which can be passed to ServiceHandler for service invocation.
035 *
036 */
037public class ServiceRequest {
038  private static final Logger LOGGER = Logger.getLogger(ServiceRequest.class);
039  private UserIdentity _authenticatedUser = null;
040  private boolean _bodyRequested = false;
041  private CaseInsensitiveMap<String, String> _headers = null;
042  private String _httpMethod = null; // e.g. GET, POST
043  private String _methodName = null;
044  private Map<String, List<String>> _rawParameters = null;  // the list of raw, URL decoded parameters
045  private HttpServletRequest _request = null;
046  private String _serviceName = null;
047  
048  /**
049   * 
050   */
051  public ServiceRequest(){
052    // nothing needed
053  }
054  
055  /**
056   * this is only for sub-classing, use the static
057   * 
058   * @return true if service name, method name and http method are given
059   */
060  protected boolean isValid(){
061    if(_serviceName == null || _methodName == null || _httpMethod == null){
062      return false;
063    }else{
064      return true;
065    }
066  }
067  
068  /**
069   * 
070   * @param request
071   * @return true if the given request was valid and != null
072   */
073  public static boolean isValid(ServiceRequest request){
074    if(request == null){
075      return false;
076    }else{
077      return request.isValid();
078    }
079  }
080  
081  /**
082   * 
083   * @param authenticatedUser
084   * @param httpServletRequest
085   * @return new request or null on failure
086   */
087  public static ServiceRequest createRequest(UserIdentity authenticatedUser, HttpServletRequest httpServletRequest){
088    String path[] = StringUtils.split(httpServletRequest.getPathInfo(), Definitions.SEPARATOR_URI_PATH, 2); // get service and "the rest of the string"
089    ServiceRequest r = null;
090    if(path != null && path.length == 2){
091      r = new ServiceRequest();
092      r._serviceName = path[0];
093      r._methodName = (path[1].endsWith(Definitions.SEPARATOR_URI_PATH) ? path[1].substring(0, path[1].length()-1) : path[1]);
094      r._request = httpServletRequest;
095      r._authenticatedUser = authenticatedUser;
096      r._httpMethod = httpServletRequest.getMethod();
097    }else{
098      LOGGER.debug("Method name is missing.");
099    }
100    return r;
101  }
102  
103  /**
104   * Note: you can only read the body once. Further attempts will return null
105   * 
106   * @return body or null if none available
107   */
108  public InputStream getBody(){
109    if(_bodyRequested){
110      LOGGER.warn("Tried to read HTTP body, but it has already been read.");
111    }else if(_request != null){
112      _bodyRequested = true;
113      try {
114        return _request.getInputStream();
115      } catch (IOException ex) {
116        LOGGER.error(ex, ex);
117      }
118    }
119    return null;
120  }
121
122  /**
123   * @return the serviceName
124   */
125  public String getServiceName() {
126    return _serviceName;
127  }
128  
129  /**
130   * 
131   * @return the http session for this request. A new session will be created if one does not already exist. Returns null if no HttpRequest is associated with this request.
132   */
133  public HttpSession getSession(){
134    if(_request == null){
135      LOGGER.warn("No request object.");
136      return null;
137    }else{
138      return _request.getSession();
139    }
140  }
141
142  /**
143   * @param serviceName the serviceName to set
144   */
145  public void setServiceName(String serviceName) {
146    _serviceName = serviceName;
147  }
148
149  /**
150   * @return the methodName
151   */
152  public String getMethodName() {
153    return _methodName;
154  }
155
156  /**
157   * @param methodName the methodName to set
158   */
159  public void setMethodName(String methodName) {
160    _methodName = methodName;
161  }
162
163  /**
164   * @return the raw URL encoded parameters
165   */
166  public Map<String, List<String>> getRawParameters() {
167    if(_rawParameters == null){
168      _rawParameters = HTTPParameterUtil.getParameterMap(_request, false);
169    }
170    return _rawParameters;
171  }
172
173  /**
174   * @return the authenticatedUser
175   */
176  public UserIdentity getAuthenticatedUser() {
177    return _authenticatedUser;
178  }
179
180  /**
181   * @param authenticatedUser the authenticatedUser to set
182   */
183  public void setAuthenticatedUser(UserIdentity authenticatedUser) {
184    _authenticatedUser = authenticatedUser;
185  }
186
187  /**
188   * @return the bodyRequested
189   */
190  public boolean isBodyRequested() {
191    return _bodyRequested;
192  }
193
194  /**
195   * @return the method, e.g. GET, POST
196   */
197  public String getHttpMethod() {
198    return _httpMethod;
199  }
200
201  /**
202   * @param method the method to set, e.g. GET, POST
203   */
204  public void setHttpMethod(String method) {
205    _httpMethod = method;
206  }
207
208  /**
209   * Set/override the previously set headers. 
210   * 
211   * Note that HTTP headers are case insensitive and thus duplicate header names with only difference being the case will be removed.
212   * 
213   * 
214   * @param headers the map of header names/values, note that the passed list will NOT be used, and an internal copy of the map will be made.
215   */
216  public void setHeaders(Map<String, String> headers) {
217    _headers = (headers == null || headers.isEmpty() ? null : new CaseInsensitiveMap<>(headers));
218  }
219  
220  /**
221   * 
222   * @param headerName
223   * @return the value of header or null if the header does not exist
224   */
225  public String getHeaderValue(String headerName) {
226    if(_headers != null){ // use the set map if available
227      return _headers.get(headerName);
228    }else if(_request != null){
229      return _request.getHeader(headerName);
230    }else{
231      return null;
232    }
233  }
234
235  /**
236   * @return the request
237   */
238  public HttpServletRequest getRequest() {
239    return _request;
240  }
241}