1 /* 2 * Copyright (c) 2003 The Visigoth Software Society. All rights 3 * reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * 3. The end-user documentation included with the redistribution, if 18 * any, must include the following acknowledgement: 19 * "This product includes software developed by the 20 * Visigoth Software Society (http://www.visigoths.org/)." 21 * Alternately, this acknowledgement may appear in the software itself, 22 * if and wherever such third-party acknowledgements normally appear. 23 * 24 * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the 25 * project contributors may be used to endorse or promote products derived 26 * from this software without prior written permission. For written 27 * permission, please contact visigoths@visigoths.org. 28 * 29 * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" 30 * nor may "FreeMarker" or "Visigoth" appear in their names 31 * without prior written permission of the Visigoth Software Society. 32 * 33 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 34 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 35 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 36 * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR 37 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 38 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 39 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 40 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 41 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 42 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 43 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 * ==================================================================== 46 * 47 * This software consists of voluntary contributions made by many 48 * individuals on behalf of the Visigoth Software Society. For more 49 * information on the Visigoth Software Society, please see 50 * http://www.visigoths.org/ 51 */ 52 53 54 package freemarker.ext.jsp; 55 56 import java.io.IOException; 57 import java.util.ArrayList; 58 import java.util.Collections; 59 import java.util.Enumeration; 60 import java.util.List; 61 import java.util.ListIterator; 62 63 import javax.servlet.GenericServlet; 64 import javax.servlet.Servlet; 65 import javax.servlet.ServletConfig; 66 import javax.servlet.ServletContext; 67 import javax.servlet.ServletException; 68 import javax.servlet.ServletRequest; 69 import javax.servlet.ServletResponse; 70 import javax.servlet.http.HttpServletRequest; 71 import javax.servlet.http.HttpServletResponse; 72 import javax.servlet.http.HttpSession; 73 import javax.servlet.jsp.JspWriter; 74 import javax.servlet.jsp.PageContext; 75 import javax.servlet.jsp.tagext.BodyContent; 76 77 import freemarker.core.Environment; 78 import freemarker.ext.servlet.FreemarkerServlet; 79 import freemarker.ext.servlet.HttpRequestHashModel; 80 import freemarker.ext.servlet.ServletContextHashModel; 81 import freemarker.ext.util.WrapperTemplateModel; 82 import freemarker.template.AdapterTemplateModel; 83 import freemarker.template.ObjectWrapper; 84 import freemarker.template.TemplateBooleanModel; 85 import freemarker.template.TemplateHashModelEx; 86 import freemarker.template.TemplateModel; 87 import freemarker.template.TemplateModelException; 88 import freemarker.template.TemplateModelIterator; 89 import freemarker.template.TemplateNumberModel; 90 import freemarker.template.TemplateScalarModel; 91 import freemarker.template.utility.UndeclaredThrowableException; 92 93 /** 94 * @version $Id: FreeMarkerPageContext.java,v 1.26.2.2 2006/07/08 14:45:34 ddekany Exp $ 95 * @author Attila Szegedi 96 */ 97 abstract class FreeMarkerPageContext extends PageContext implements TemplateModel 98 { 99 private static final Class OBJECT_CLASS = Object.class; 100 101 private final Environment environment; 102 private List tags = new ArrayList(); 103 private List outs = new ArrayList(); 104 private final GenericServlet servlet; 105 private HttpSession session; 106 private final HttpServletRequest request; 107 private final HttpServletResponse response; 108 private final ObjectWrapper wrapper; 109 private JspWriter jspOut; 110 111 protected FreeMarkerPageContext() throws TemplateModelException 112 { 113 environment = Environment.getCurrentEnvironment(); 114 115 TemplateModel appModel = environment.getGlobalVariable( 116 FreemarkerServlet.KEY_APPLICATION_PRIVATE); 117 if(!(appModel instanceof ServletContextHashModel)) { 118 appModel = environment.getGlobalVariable( 119 FreemarkerServlet.KEY_APPLICATION); 120 } 121 if(appModel instanceof ServletContextHashModel) { 122 this.servlet = ((ServletContextHashModel)appModel).getServlet(); 123 } 124 else { 125 throw new TemplateModelException("Could not find an instance of " + 126 ServletContextHashModel.class.getName() + 127 " in the data model under either the name " + 128 FreemarkerServlet.KEY_APPLICATION_PRIVATE + " or " + 129 FreemarkerServlet.KEY_APPLICATION); 130 } 131 132 TemplateModel requestModel = 133 environment.getGlobalVariable(FreemarkerServlet.KEY_REQUEST_PRIVATE); 134 if(!(requestModel instanceof HttpRequestHashModel)) { 135 requestModel = environment.getGlobalVariable( 136 FreemarkerServlet.KEY_REQUEST); 137 } 138 if(requestModel instanceof HttpRequestHashModel) { 139 HttpRequestHashModel reqHash = (HttpRequestHashModel)requestModel; 140 this.request = reqHash.getRequest(); 141 this.session = request.getSession(false); 142 this.response = reqHash.getResponse(); 143 this.wrapper = reqHash.getObjectWrapper(); 144 } 145 else { 146 throw new TemplateModelException("Could not find an instance of " + 147 HttpRequestHashModel.class.getName() + 148 " in the data model under either the name " + 149 FreemarkerServlet.KEY_REQUEST_PRIVATE + " or " + 150 FreemarkerServlet.KEY_REQUEST); 151 } 152 153 // Register page attributes as per spec 154 setAttribute(REQUEST, request); 155 setAttribute(RESPONSE, response); 156 if (session != null) 157 setAttribute(SESSION, session); 158 setAttribute(PAGE, servlet); 159 setAttribute(CONFIG, servlet.getServletConfig()); 160 setAttribute(PAGECONTEXT, this); 161 setAttribute(APPLICATION, servlet.getServletContext()); 162 } 163 164 ObjectWrapper getObjectWrapper() { 165 return wrapper; 166 } 167 168 public void initialize( 169 Servlet servlet, ServletRequest request, ServletResponse response, 170 String errorPageURL, boolean needsSession, int bufferSize, 171 boolean autoFlush) 172 { 173 throw new UnsupportedOperationException(); 174 } 175 176 public void release() { 177 } 178 179 public void setAttribute(String name, Object value) { 180 setAttribute(name, value, PAGE_SCOPE); 181 } 182 183 public void setAttribute(String name, Object value, int scope) { 184 switch(scope) { 185 case PAGE_SCOPE: { 186 try { 187 environment.setGlobalVariable(name, wrapper.wrap(value)); 188 break; 189 } 190 catch(TemplateModelException e) { 191 throw new UndeclaredThrowableException(e); 192 } 193 } 194 case REQUEST_SCOPE: { 195 getRequest().setAttribute(name, value); 196 break; 197 } 198 case SESSION_SCOPE: { 199 getSession(true).setAttribute(name, value); 200 break; 201 } 202 case APPLICATION_SCOPE: { 203 getServletContext().setAttribute(name, value); 204 break; 205 } 206 default: { 207 throw new IllegalArgumentException("Invalid scope " + scope); 208 } 209 } 210 } 211 212 public Object getAttribute(String name) 213 { 214 return getAttribute(name, PAGE_SCOPE); 215 } 216 217 public Object getAttribute(String name, int scope) 218 { 219 switch (scope) { 220 case PAGE_SCOPE: { 221 try { 222 TemplateModel m = environment.getGlobalNamespace().get(name); 223 if (m instanceof AdapterTemplateModel) { 224 return ((AdapterTemplateModel) m).getAdaptedObject(OBJECT_CLASS); 225 } 226 if (m instanceof WrapperTemplateModel) { 227 return ((WrapperTemplateModel)m).getWrappedObject(); 228 } 229 if (m instanceof TemplateScalarModel) { 230 return ((TemplateScalarModel) m).getAsString(); 231 } 232 if (m instanceof TemplateNumberModel) { 233 return ((TemplateNumberModel) m).getAsNumber(); 234 } 235 if (m instanceof TemplateBooleanModel) { 236 return ((TemplateBooleanModel) m).getAsBoolean() ? Boolean.TRUE : Boolean.FALSE; 237 } 238 return m; 239 } 240 catch (TemplateModelException e) { 241 throw new UndeclaredThrowableException(e); 242 } 243 } 244 case REQUEST_SCOPE: { 245 return getRequest().getAttribute(name); 246 } 247 case SESSION_SCOPE: { 248 HttpSession session = getSession(false); 249 if(session == null) { 250 return null; 251 } 252 return session.getAttribute(name); 253 } 254 case APPLICATION_SCOPE: { 255 return getServletContext().getAttribute(name); 256 } 257 default: { 258 throw new IllegalArgumentException("Invalid scope " + scope); 259 } 260 } 261 } 262 263 public Object findAttribute(String name) 264 { 265 Object retval = getAttribute(name, PAGE_SCOPE); 266 if(retval != null) return retval; 267 retval = getAttribute(name, REQUEST_SCOPE); 268 if(retval != null) return retval; 269 retval = getAttribute(name, SESSION_SCOPE); 270 if(retval != null) return retval; 271 return getAttribute(name, APPLICATION_SCOPE); 272 } 273 274 public void removeAttribute(String name) { 275 removeAttribute(name, PAGE_SCOPE); 276 removeAttribute(name, REQUEST_SCOPE); 277 removeAttribute(name, SESSION_SCOPE); 278 removeAttribute(name, APPLICATION_SCOPE); 279 } 280 281 public void removeAttribute(String name, int scope) { 282 switch(scope) { 283 case PAGE_SCOPE: { 284 environment.getGlobalNamespace().remove(name); 285 break; 286 } 287 case REQUEST_SCOPE: { 288 getRequest().removeAttribute(name); 289 break; 290 } 291 case SESSION_SCOPE: { 292 HttpSession session = getSession(false); 293 if(session != null) { 294 session.removeAttribute(name); 295 } 296 break; 297 } 298 case APPLICATION_SCOPE: { 299 getServletContext().removeAttribute(name); 300 break; 301 } 302 default: { 303 throw new IllegalArgumentException("Invalid scope: " + scope); 304 } 305 } 306 } 307 308 public int getAttributesScope(String name) { 309 if(getAttribute(name, PAGE_SCOPE) != null) return PAGE_SCOPE; 310 if(getAttribute(name, REQUEST_SCOPE) != null) return REQUEST_SCOPE; 311 if(getAttribute(name, SESSION_SCOPE) != null) return SESSION_SCOPE; 312 if(getAttribute(name, APPLICATION_SCOPE) != null) return APPLICATION_SCOPE; 313 return 0; 314 } 315 316 public Enumeration getAttributeNamesInScope(int scope) { 317 switch(scope) { 318 case PAGE_SCOPE: { 319 try { 320 return 321 new TemplateHashModelExEnumeration(environment.getGlobalNamespace()); 322 } 323 catch(TemplateModelException e) { 324 throw new UndeclaredThrowableException(e); 325 } 326 } 327 case REQUEST_SCOPE: { 328 return getRequest().getAttributeNames(); 329 } 330 case SESSION_SCOPE: { 331 HttpSession session = getSession(false); 332 if(session != null) { 333 return session.getAttributeNames(); 334 } 335 return Collections.enumeration(Collections.EMPTY_SET); 336 } 337 case APPLICATION_SCOPE: { 338 return getServletContext().getAttributeNames(); 339 } 340 default: { 341 throw new IllegalArgumentException("Invalid scope " + scope); 342 } 343 } 344 } 345 346 public JspWriter getOut() { 347 return jspOut; 348 } 349 350 private HttpSession getSession(boolean create) { 351 if(session == null) { 352 session = request.getSession(create); 353 if(session != null) { 354 setAttribute(SESSION, session); 355 } 356 } 357 return session; 358 } 359 360 public HttpSession getSession() { 361 return getSession(false); 362 } 363 364 public Object getPage() { 365 return servlet; 366 } 367 368 public ServletRequest getRequest() { 369 return request; 370 } 371 372 public ServletResponse getResponse() { 373 return response; 374 } 375 376 public Exception getException() { 377 throw new UnsupportedOperationException(); 378 } 379 380 public ServletConfig getServletConfig() { 381 return servlet.getServletConfig(); 382 } 383 384 public ServletContext getServletContext() { 385 return servlet.getServletContext(); 386 } 387 388 public void forward(String url) throws ServletException, IOException { 389 //TODO: make sure this is 100% correct by looking at Jasper output 390 request.getRequestDispatcher(url).forward(request, response); 391 } 392 393 public void include(String url) throws ServletException, IOException { 394 //TODO: make sure this is 100% correct by looking at Jasper output 395 request.getRequestDispatcher(url).include(request, response); 396 } 397 398 public void include(String url, boolean flush) throws ServletException, IOException { 399 //TODO: make sure this is 100% correct by looking at Jasper output 400 request.getRequestDispatcher(url).include(request, response); 401 } 402 403 public void handlePageException(Exception e) { 404 throw new UnsupportedOperationException(); 405 } 406 407 public void handlePageException(Throwable e) { 408 throw new UnsupportedOperationException(); 409 } 410 411 public BodyContent pushBody() { 412 BodyContent bc = new TagTransformModel.BodyContentImpl(getOut(), true); 413 pushWriter(bc); 414 return bc; 415 } 416 417 public JspWriter popBody() { 418 popWriter(); 419 return (JspWriter) getAttribute(OUT); 420 } 421 422 Object peekTopTag(Class tagClass) { 423 for (ListIterator iter = tags.listIterator(tags.size()); iter.hasPrevious();) 424 { 425 Object tag = iter.previous(); 426 if(tagClass.isInstance(tag)) { 427 return tag; 428 } 429 } 430 return null; 431 } 432 433 void popTopTag() { 434 tags.remove(tags.size() - 1); 435 } 436 437 void popWriter() { 438 jspOut = (JspWriter)outs.remove(outs.size() - 1); 439 setAttribute(OUT, jspOut); 440 } 441 442 void pushTopTag(Object tag) { 443 tags.add(tag); 444 } 445 446 void pushWriter(JspWriter out) { 447 outs.add(jspOut); 448 jspOut = out; 449 setAttribute(OUT, jspOut); 450 } 451 452 private static class TemplateHashModelExEnumeration implements Enumeration { 453 private final TemplateModelIterator it; 454 455 private TemplateHashModelExEnumeration(TemplateHashModelEx hashEx) throws TemplateModelException { 456 it = hashEx.keys().iterator(); 457 } 458 459 public boolean hasMoreElements() { 460 try { 461 return it.hasNext(); 462 } catch (TemplateModelException tme) { 463 throw new UndeclaredThrowableException(tme); 464 } 465 } 466 467 public Object nextElement() { 468 try { 469 return ((TemplateScalarModel) it.next()).getAsString(); 470 } catch (TemplateModelException tme) { 471 throw new UndeclaredThrowableException(tme); 472 } 473 } 474 } 475 }