View Javadoc
1 /* 2 * Angkor Web Framework 3 * 4 * Distributable under LGPL license. 5 * See terms of license at gnu.org. 6 */ 7 package com.tirsen.angkor; 8 9 import com.tirsen.angkor.jsp.PrerenderValve; 10 import com.tirsen.angkor.process.DefaultPipeline; 11 import com.tirsen.angkor.process.ErrorValve; 12 import com.tirsen.angkor.process.EventValve; 13 import com.tirsen.angkor.process.ExecuteContext; 14 import com.tirsen.angkor.process.ParseValve; 15 import com.tirsen.angkor.process.Pipeline; 16 import com.tirsen.angkor.process.RedirectValve; 17 import com.tirsen.angkor.process.SingleViewFactoryRenderValve; 18 import org.apache.commons.logging.Log; 19 import org.apache.commons.logging.LogFactory; 20 21 import javax.servlet.http.HttpSessionBindingEvent; 22 import javax.servlet.http.HttpSessionBindingListener; 23 import javax.servlet.http.HttpServletRequest; 24 import javax.servlet.http.HttpServletResponse; 25 import java.beans.PropertyEditorManager; 26 import java.io.IOException; 27 import java.io.Serializable; 28 import java.util.ArrayList; 29 import java.util.Collection; 30 import java.util.Collections; 31 import java.util.HashMap; 32 import java.util.Iterator; 33 import java.util.LinkedList; 34 import java.util.Map; 35 import java.util.WeakHashMap; 36 37 /*** 38 * The main controller of an application, typically first class extended when implementing 39 * an application in Angkor. 40 * 41 * There is one instance of this for each session. 42 * 43 * Responsibilities include: 44 * <li> maintaining conversational state. 45 * <li> implementing core functionality shared by the entire application. 46 * <li> maintaining the flow of application. 47 * <li> maintaing a register of named components and their respective ViewFactory. 48 * 49 * which is to be used if using JSP in Angkor. Includes window-title. 50 * 51 * <!-- $Id: Application.java,v 1.7 2002/10/13 19:59:22 tirsen Exp $ --> 52 * 53 * @author $Author: tirsen $ 54 * @version $Revision: 1.7 $ 55 */ 56 public class Application implements Serializable, HttpSessionBindingListener 57 { 58 private static final Log logger = LogFactory.getLog(Application.class); 59 60 private Map components = new HashMap(); 61 private Throwable error; 62 private Map viewToID = new WeakHashMap(); 63 private Collection parsingComponents; 64 private long currentId = 0; 65 66 public Throwable getError() 67 { 68 return error; 69 } 70 71 public void handleError(Throwable e) 72 { 73 error = e; 74 logger.error(e); 75 } 76 77 public ViewFactory getComponent(String name) 78 { 79 Object component = components.get(name); 80 if (component == null) throw new IllegalArgumentException("No such component in this application: " + name); 81 ViewFactory factory; 82 if (component instanceof ViewLink) 83 { 84 factory = ((ViewLink) component).getTarget(); 85 } 86 else 87 { 88 factory = (ViewFactory) component; 89 } 90 return factory; 91 } 92 93 /*** 94 * Registers a <em>new</em> component. 95 * @throws IllegalStateException if that component has already been registered. 96 */ 97 public void registerComponent(String name, ViewFactory factory) 98 { 99 if (components.containsKey(name)) throw new IllegalStateException(name + " has already been registered."); 100 components.put(name, factory); 101 } 102 103 /*** 104 * Registers a <em>new</em> component. 105 * @throws IllegalStateException if that component has already been registered. 106 */ 107 public void registerPrerenderComponent(String name, View component) 108 { 109 if (components.containsKey(name)) throw new IllegalStateException(name + " has already been registered."); 110 components.put(name, component); 111 } 112 113 public void registerLink(String name, ViewFactory originalBinding) 114 { 115 registerComponent(name, new ViewLink(originalBinding)); 116 } 117 118 /*** 119 * Relinks a link. 120 */ 121 public void relink(String name, ViewFactory target) 122 { 123 ViewLink link = (ViewLink) components.get(name); 124 if (link == null) throw new IllegalArgumentException("No such link " + name); 125 link.relink(target); 126 } 127 128 /*** 129 * Relinks a link to a named view. 130 */ 131 public void relink(String name, String target) 132 { 133 relink(name, getComponent(target)); 134 } 135 136 /*** 137 * Overriding method needs to call this method. 138 */ 139 public void init() 140 { 141 initDefaultPropertyEditors(); 142 initPrerenderedComponents(); 143 } 144 145 public void destroy() 146 { 147 // do nothing by default 148 } 149 150 public void valueBound(HttpSessionBindingEvent event) 151 { 152 init(); 153 } 154 155 public void valueUnbound(HttpSessionBindingEvent event) 156 { 157 destroy(); 158 } 159 160 protected void initPrerenderedComponents() 161 { 162 // none by default 163 } 164 165 protected void initDefaultPropertyEditors() 166 { 167 // set up some obvious editors which should have been setup by the JDK but are not 168 PropertyEditorManager.registerEditor(Integer.class, PropertyEditorManager.findEditor(Integer.TYPE).getClass()); 169 PropertyEditorManager.registerEditor(Double.class, PropertyEditorManager.findEditor(Double.TYPE).getClass()); 170 } 171 172 public void beforeRequest(RenderContext context) 173 throws IOException 174 { 175 } 176 177 public void afterRequest(RenderContext context) 178 throws IOException 179 { 180 error = null; 181 } 182 183 /*** 184 * Creates the default processing pipeline. This will probably be refactored a lot. 185 * Which factory to use to produce the view to render needs to be determined beforehand. 186 */ 187 public Pipeline createRenderPipeline(ViewFactory factory) 188 { 189 Pipeline process = createBasicPipeline(); 190 process.addValve(new SingleViewFactoryRenderValve(factory)); 191 return process; 192 } 193 194 /*** 195 * Creates a pipeline that prerenders all currently registered components. 196 * These prerendered components can be used in for example JSP. 197 */ 198 public Pipeline createPrerenderPipeline() 199 { 200 Pipeline pipeline = createBasicPipeline(); 201 pipeline.addValve(new PrerenderValve()); 202 return pipeline; 203 } 204 205 /*** 206 * Creates the basic pipeline with the exception of a render valve. 207 */ 208 public Pipeline createBasicPipeline() 209 { 210 Pipeline process = createDefaultPipeline(); 211 process.addValve(new ParseValve()); 212 process.addValve(new EventValve()); 213 process.addValve(new RedirectValve()); 214 return process; 215 } 216 217 protected Pipeline createDefaultPipeline() 218 { 219 DefaultPipeline pipeline = new DefaultPipeline(); 220 pipeline.addValve(new ErrorValve()); 221 return pipeline; 222 } 223 224 public void resetParsingComponents() 225 { 226 parsingComponents = null; 227 } 228 229 /*** 230 * Returns a tread-safe iterator of the parsing components. Parsing components can be registered 231 * while using the returned iterator, the components registered after this iterator has been created 232 * will not be iterated by this iterator. 233 */ 234 public Iterator iterateParsingComponents() 235 { 236 return parsingComponents == null ? Collections.EMPTY_LIST.iterator() : new ArrayList(parsingComponents).iterator(); 237 } 238 239 /*** 240 * Public for unit tests only, maybe it's time to move to JUnitX soon. 241 * TODO move this to the ExecuteContext. 242 */ 243 public Collection getParsingComponents() 244 { 245 return parsingComponents; 246 } 247 248 public void registerParsingComponent(View view) 249 { 250 if (parsingComponents == null) parsingComponents = new LinkedList(); 251 parsingComponents.add(view); 252 } 253 254 public String nextUniqueID() 255 { 256 currentId++; 257 return String.valueOf(currentId); 258 } 259 260 public void allocateUniqueID(String id, View view) 261 { 262 // check uniqueness of id 263 if (viewToID.containsValue(id) && !id.equals(viewToID.get(view))) 264 { 265 throw new IllegalArgumentException("ID already allocated: " + id); 266 } 267 else 268 viewToID.put(view, id); 269 } 270 271 /*** 272 * This is used by the {@link PrerenderValve} and is not part of the public API. 273 * @return a <code>String</code> -> <code>ViewFactory</code> map containing the components to prerender. 274 */ 275 public Map getComponentsToPrerender() throws Exception 276 { 277 return components; 278 } 279 280 /*** 281 * Returns the application of the currently executing pipeline. 282 */ 283 public static Application getApplication() 284 { 285 return (Application) Pipeline.getCurrentExecuteContext().getAttribute(ExecuteContext.ApplicationAttribute); 286 } 287 288 /*** 289 * Override to provide a title rendered by the angkor:header-tag. 290 */ 291 public String getWindowTitle() 292 { 293 return null; 294 } 295 296 public void registerPage(String name, Page page) 297 { 298 if (components.containsKey(name) && components.get(name) != page) 299 { 300 throw new IllegalStateException(name + " has already been registered."); 301 } 302 if(page.getApplication() != null && page.getApplication() != this) 303 { 304 throw new IllegalArgumentException("Page can only be registered with one application."); 305 } 306 page.setApplication(this); 307 components.put(name, page); 308 } 309 310 public void process(HttpServletRequest request, HttpServletResponse response) throws Exception 311 { 312 RenderContext renderContext = new RenderContext(request, response); 313 314 beforeRequest(renderContext); 315 316 String pageName = extractPageName(request); 317 Page page = getPage(pageName); 318 319 Pipeline pipeline = page.createProcessPipeline(); 320 pipeline.execute(renderContext); 321 322 afterRequest(renderContext); 323 } 324 325 public Page getPage(String pageName) 326 { 327 Page page = (Page) components.get(pageName); 328 if(page == null) 329 { 330 throw new IllegalArgumentException("No such page " + pageName + " exists."); 331 } 332 return page; 333 } 334 335 private String extractPageName(HttpServletRequest request) 336 { 337 String requestURI = request.getRequestURI(); 338 return requestURI.substring(requestURI.lastIndexOf('/') + 1); 339 } 340 }

This page was automatically generated by Maven