/*
* $Id$
*
* 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.apache.struts2.rest;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import static javax.servlet.http.HttpServletResponse.SC_CREATED;
import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
import static javax.servlet.http.HttpServletResponse.SC_OK;
/**
* Default implementation of rest info that uses fluent-style construction
*/
public class DefaultHttpHeaders implements HttpHeaders {
private static final Logger LOG = LoggerFactory.getLogger(DefaultHttpHeaders.class);
private static final String IF_MODIFIED_SINCE_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
private static final SimpleDateFormat IF_MODIFIED_SINCE_FORMAT = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
private String resultCode;
private int status = SC_OK;
private Object etag;
private Object locationId;
private String location;
private boolean disableCaching;
private boolean noETag = false;
private Date lastModified;
public DefaultHttpHeaders() {
}
public DefaultHttpHeaders(String result) {
resultCode = result;
}
public DefaultHttpHeaders renderResult(String code) {
this.resultCode = code;
return this;
}
public DefaultHttpHeaders withStatus(int code) {
this.status = code;
return this;
}
public DefaultHttpHeaders withETag(Object etag) {
this.etag = etag;
return this;
}
public DefaultHttpHeaders withNoETag() {
this.noETag = true;
return this;
}
public DefaultHttpHeaders setLocationId(Object id) {
this.locationId = id;
return this;
}
public DefaultHttpHeaders setLocation(String loc) {
this.location = loc;
return this;
}
public DefaultHttpHeaders lastModified(Date date) {
this.lastModified = date;
return this;
}
public DefaultHttpHeaders disableCaching() {
this.disableCaching = true;
return this;
}
/* (non-Javadoc)
* @see org.apache.struts2.rest.HttpHeaders#apply(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
*/
public String apply(HttpServletRequest request, HttpServletResponse response, Object target) {
if (disableCaching) {
response.setHeader("Cache-Control", "no-cache");
}
if (lastModified != null) {
response.setDateHeader("Last-Modified", lastModified.getTime());
}
if (etag == null && !noETag && target != null) {
etag = String.valueOf(target.hashCode());
}
if (etag != null) {
response.setHeader("ETag", etag.toString());
}
if (locationId != null) {
String url = request.getRequestURL().toString();
int lastSlash = url.lastIndexOf("/");
int lastDot = url.lastIndexOf(".");
if (lastDot > lastSlash && lastDot > -1) {
url = url.substring(0, lastDot) + "/" + locationId + url.substring(lastDot);
} else {
url += "/" + locationId;
}
response.setHeader("Location", url);
status = SC_CREATED;
} else if (location != null) {
response.setHeader("Location", location);
status = SC_CREATED;
}
if (status == SC_OK && !disableCaching) {
boolean etagNotChanged = false;
boolean lastModifiedNotChanged = false;
String reqETag = request.getHeader("If-None-Match");
if (etag != null) {
if (etag.equals(reqETag)) {
etagNotChanged = true;
}
}
String reqLastModified = request.getHeader("If-Modified-Since");
if (lastModified != null && reqLastModified != null) {
lastModifiedNotChanged = compareIfModifiedSince(reqLastModified);
}
if ((etagNotChanged && lastModifiedNotChanged) ||
(etagNotChanged && reqLastModified == null) ||
(lastModifiedNotChanged && reqETag == null)) {
status = SC_NOT_MODIFIED;
}
}
response.setStatus(status);
return resultCode;
}
private boolean compareIfModifiedSince(String reqLastModified) {
try {
if (lastModified.compareTo(IF_MODIFIED_SINCE_FORMAT.parse(reqLastModified)) >= 0) {
return true;
}
} catch (ParseException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Got error parsing If-Modified-Since header value [#0] as [#1]!", e, reqLastModified, IF_MODIFIED_SINCE_DATE_FORMAT);
}
return false;
}
return false;
}
public int getStatus() {
return status;
}
public void setStatus(int s) {
status = s;
}
public String getResultCode() {
return resultCode;
}
}