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; 019 020import javax.servlet.http.HttpServletResponse; 021import javax.xml.bind.annotation.XmlAccessType; 022import javax.xml.bind.annotation.XmlAccessorType; 023import javax.xml.bind.annotation.XmlAttribute; 024import javax.xml.bind.annotation.XmlElement; 025import javax.xml.bind.annotation.XmlElementRef; 026import javax.xml.bind.annotation.XmlEnum; 027import javax.xml.bind.annotation.XmlRootElement; 028 029import org.apache.log4j.Logger; 030 031import core.tut.pori.utils.XMLFormatter; 032 033 034/** 035 * Basic HTTP response, which prints the given ResponseData as an xml. 036 * 037 * By default, the status of the response is 200 OK 038 */ 039@XmlRootElement(name=Definitions.ELEMENT_RESPONSE) 040@XmlAccessorType(XmlAccessType.NONE) 041public class Response { 042 private static final Logger LOGGER = Logger.getLogger(Response.class); 043 @XmlElementRef 044 private ResponseData _responseData = null; 045 @XmlAttribute(name=Definitions.ATTRIBUTE_METHOD) 046 private String _method = null; 047 @XmlElement(name=Definitions.ELEMENT_MESSAGE) 048 private String _message = null; 049 @XmlAttribute(name=Definitions.ATTRIBUTE_SERVICE) 050 private String _service = null; 051 @XmlElement(name=Definitions.ELEMENT_STATUS) 052 private Status _status = Status.OK; 053 054 055 /** 056 * HTTP Status code enumerations. 057 * 058 * As defined by http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 059 */ 060 @XmlEnum 061 public enum Status{ 062 /** 200 OK response */ 063 OK(200), 064 /** 204 No Content */ 065 NO_CONTENT(204), 066 /** 400 Bad Request response */ 067 BAD_REQUEST(400), 068 /** 401 Unauthorized response */ 069 UNAUTHORIZED(401), 070 /** 403 Forbidden response */ 071 FORBIDDEN(403), 072 /** 404 Not Found response */ 073 NOT_FOUND(404), 074 /** 440 Login Timeout response, Microsoft/Outlook extension. In this case used more liberally for all login timeout cases. */ 075 LOGIN_TIMEOUT(440), 076 /** 500 Internal Server Error response */ 077 INTERNAL_SERVER_ERROR(500), 078 /** 503 Service Unavailable response */ 079 SERVICE_UNAVAILABLE(503); 080 081 private int _code; 082 083 /** 084 * 085 * @param code 086 */ 087 private Status(int code){ 088 _code = code; 089 } 090 091 /** 092 * convert to HTTP status code 093 * @return the status as HTTP status code 094 */ 095 public int toStatusCode(){ 096 return _code; 097 } 098 099 /** 100 * 101 * @param code 102 * @return status code from the given integer code, returns INTERNAL_SERVER_ERROR on unknown error code 103 */ 104 public static Status fromStatusCode(int code){ 105 for(Status s : Status.values()){ 106 if(s._code == code){ 107 return s; 108 } 109 } 110 return INTERNAL_SERVER_ERROR; 111 } 112 } // enum Status 113 114 /** 115 * for serialization 116 */ 117 public Response(){ 118 // nothing needed 119 } 120 121 /** 122 * 123 * @param status 124 */ 125 public Response(Status status){ 126 _status = status; 127 } 128 129 /** 130 * 131 * @param status 132 * @param message 133 */ 134 public Response(Status status, String message){ 135 _status = status; 136 _message = message; 137 } 138 139 /** 140 * 141 * @param data 142 */ 143 public Response(ResponseData data){ 144 _responseData = data; 145 } 146 147 /** 148 * Write this response to the given response object. 149 * 150 * This method can be overridden to provide custom responses. 151 * 152 * By default this method writes this object to the stream as XML based on JAXB annotations 153 * and sets the encoding ({@value core.tut.pori.http.Definitions#ENCODING_UTF8}) and content type ({@value core.tut.pori.http.Definitions#CONTENT_TYPE_XML}) to appropriate values. 154 * These to parameters should be changed for the response if format is changed in the overriding method. 155 * 156 * Additionally this method sets the HTTP basic authentication header if the status is set {@link core.tut.pori.http.Response.Status#UNAUTHORIZED}. 157 * 158 * @param response 159 * @see #setDefaultAuthenticationHeader(HttpServletResponse) 160 * @see #setStatus(core.tut.pori.http.Response.Status) 161 */ 162 public void writeTo(HttpServletResponse response){ 163 try { 164 response.setContentType(Definitions.CONTENT_TYPE_XML); 165 response.setCharacterEncoding(Definitions.ENCODING_UTF8); 166 response.getWriter().write((new XMLFormatter()).toString(this)); 167 } catch (IOException ex) { 168 LOGGER.error(ex, ex); 169 _status = Status.INTERNAL_SERVER_ERROR; 170 } 171 172 if(_status != Status.OK){ // don't change defaults if there is OK status 173 response.setStatus(_status.toStatusCode()); 174 if(_status == Status.UNAUTHORIZED){ 175 setDefaultAuthenticationHeader(response); 176 } 177 } 178 } 179 180 /** 181 * Set the default HTTP authentication header in the response. 182 * 183 * <a href="http://tools.ietf.org/html/rfc2617#section-2">HTTP Basic Authentication</a> 184 * 185 * @param response 186 */ 187 public static void setDefaultAuthenticationHeader(HttpServletResponse response){ 188 response.setHeader(Definitions.HEADER_AUTHENTICATE, Definitions.HEADER_AUTHENTICATE_VALUE); 189 } 190 191 /** 192 * @return the status 193 */ 194 public Status getStatus() { 195 return _status; 196 } 197 198 /** 199 * @param status the status to set 200 */ 201 public void setStatus(Status status) { 202 _status = status; 203 } 204 205 /** 206 * @return the method 207 */ 208 public String getMethod() { 209 return _method; 210 } 211 212 /** 213 * @param method the method to set 214 */ 215 public void setMethod(String method) { 216 _method = method; 217 } 218 219 /** 220 * @return the service 221 */ 222 public String getService() { 223 return _service; 224 } 225 226 /** 227 * @param service the service to set 228 */ 229 public void setService(String service) { 230 _service = service; 231 } 232 233 /** 234 * @return the data 235 */ 236 public ResponseData getResponseData() { 237 return _responseData; 238 } 239 240 /** 241 * @param data the data to set 242 */ 243 public void setResponseData(ResponseData data) { 244 _responseData = data; 245 } 246 247 /** 248 * 249 * @return response message 250 */ 251 public String getMessage() { 252 return _message; 253 } 254 255 /** 256 * Set an optional message to be shown with the response 257 * 258 * @param message 259 */ 260 public void setMessage(String message) { 261 _message = message; 262 } 263}