/* * Copyright 2005 John R. Fallows * * 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 net.java.dev.weblets.impl.servlets; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Calendar; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import net.java.dev.weblets.WebletResponse; import net.java.dev.weblets.impl.WebletResponseBase; import net.java.dev.weblets.impl.misc.ReflectUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Weblets Response impl object implementation of the internal weblets response object <p/> TODO check out how to enable all the header params in portlet * environments which do not provide the needed methods but follow the pure ri interfaces */ public class WebletResponseImpl extends WebletResponseBase { public WebletResponseImpl(String contentTypeDefault, ServletResponse httpResponse) { super(contentTypeDefault); // new GZIPResponseWrapper( _httpResponse = httpResponse; } public void setContentLength(int length) { _httpResponse.setContentLength(length); } public OutputStream getOutputStream() throws IOException { // return _httpResponse.getOutputStream(); return ReflectUtils.getOutputStream(getHttpResponse()); } public void setStatus(int statusCode) { switch (statusCode) { case WebletResponse.SC_ACCEPTED: setResponseStatus(HttpServletResponse.SC_ACCEPTED); break; case WebletResponse.SC_NOT_FOUND: setResponseStatus(HttpServletResponse.SC_NOT_FOUND); break; case WebletResponse.SC_NOT_MODIFIED: setResponseStatus(HttpServletResponse.SC_NOT_MODIFIED); break; default: throw new IllegalArgumentException(); } } public ServletResponse getHttpResponse() { return _httpResponse; } protected void setContentTypeImpl(String contentType) { if(contentType != null) { //needed to avoid npes in was! _httpResponse.setContentType(contentType); } } protected void setLastModifiedImpl(long lastModified) { if(_y2038_bug) { lastModified = y2038k_fix(lastModified); } try { setDateHeader(WebletResponse.HTTP_LAST_MODIFIED, lastModified); } catch (IndexOutOfBoundsException ex) { // websphere 6.1 has a y2038k bug _y2038_bug = true; lastModified = y2038k_fix(lastModified); setDateHeader(WebletResponse.HTTP_EXPIRES, lastModified); } } protected void setContentLength(long length) { ((HttpServletResponse)_httpResponse).addHeader("Conten-Length", Long.toString(length)); } protected void setContentVersionImpl(String contentVersion, long timeout) { if(_y2038_bug) { timeout = y2038k_fix(timeout); } try { setDateHeader(WebletResponse.HTTP_EXPIRES, timeout); //Cache-Control: max-age=3600, must-revalidate //pre-check=9000,post-check=9000, ((HttpServletResponse)_httpResponse).addHeader("Cache-Control", "pre-check=9000,post-check=9000,max-age="+((timeout-System.currentTimeMillis())/ 1000 )); } catch (IndexOutOfBoundsException ex) { // websphere 6.1 has a y2038k bug _y2038_bug = true; timeout = y2038k_fix(timeout); setDateHeader(WebletResponse.HTTP_EXPIRES, timeout); } } /** * y2038k fix for certain servers (aka WAS 6.1) * * @param timeout the incoming time value to be fixed * @return */ private long y2038k_fix(long timeout) { java.util.Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(timeout); if(cal.get(Calendar.YEAR) >= Y2038_BOUNDARY) { cal.set(Calendar.YEAR, Y0238_VALIDYEAR); } return cal.getTimeInMillis(); } /** * we fallback to various introspection methods to support portlet environments as well * * @param entry * @param lastModified */ private void setDateHeader(String entry, long lastModified) { /*we can cover a simple httpservletresponse*/ /*we do it that way to improve speed*/ if(_httpResponse instanceof HttpServletResponse) { ((HttpServletResponse)_httpResponse).addDateHeader(entry, lastModified); return; } /*with others we give introspection a try*/ Method[] supportedMethods = _httpResponse.getClass().getMethods(); // fetch the date header method Method m = null; try { m = _httpResponse.getClass().getMethod(SETDATEHEADER, new Class[] { String.class, long.class }); } catch (NoSuchMethodException e) { if (!_dateheader_warn) { _dateheader_warn = true; // we do not want to flood warnings one is enough Log log = LogFactory.getLog(getClass()); log.warn(ERR_NODATEHEADERSET); log.warn(e); return; } } try { Object[] params = new Object[2]; params[0] = entry; params[1] = new Long( lastModified ); m.invoke(_httpResponse, params); } catch (IllegalAccessException e) { Log log = LogFactory.getLog(getClass()); log.error(e); } catch (InvocationTargetException e) { Log log = LogFactory.getLog(getClass()); log.error(e); } return; } /** * locking singleton to prevent too many warnings in certain portlet environments which dont have the needed methods implemented (which follow the pure ri) */ static boolean responsestatus_warn = false; private void setResponseStatus(int status) { if(_httpResponse instanceof HttpServletResponse) { ((HttpServletResponse)_httpResponse).setStatus(status); return; } Method[] supportedMethods = _httpResponse.getClass().getMethods(); // fetch the date header method Method m = null; try { m = _httpResponse.getClass().getMethod("setStatus", new Class[] { int.class }); } catch (NoSuchMethodException e) { if (!responsestatus_warn) { responsestatus_warn = true; Log log = LogFactory.getLog(getClass()); log.warn("No satus setting possible reason: "); log.warn(e); return; } } try { Object[] params = new Object[1]; params[0] = new Integer(status); m.invoke(_httpResponse, params); } catch (IllegalAccessException e) { Log log = LogFactory.getLog(getClass()); log.error(e); } catch (InvocationTargetException e) { Log log = LogFactory.getLog(getClass()); log.error(e); } return; } private static final int Y0238_VALIDYEAR = 2037; private static final int Y2038_BOUNDARY = 2038; private static final String ERR_NODATEHEADERSET = "No date header setting possible reason: "; private static final String SETDATEHEADER = "setDateHeader"; /** * locking singleton to prevent too many warnings in certain portlet environments which dont have the needed methods implemented (which follow the pure ri) */ static boolean _dateheader_warn = false; static boolean _y2038_bug = false; /*y2038 bug affected system, aka WAS <=6.1+*/ ServletResponse _httpResponse = null; }