Clover coverage report - angkor - 0.4
Coverage timestamp: ti okt 15 2002 22:32:48 CEST
file stats: LOC: 341   Methods: 33
NCLOC: 223   Classes: 1
Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover.
 
 Source file Conditionals Statements Methods TOTAL
Application.java 80% 83,1% 84,8% 83,1%
 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  97
     public Throwable getError()
 67   
     {
 68  97
         return error;
 69   
     }
 70   
 
 71  1
     public void handleError(Throwable e)
 72   
     {
 73  1
         error = e;
 74  1
         logger.error(e);
 75   
     }
 76   
 
 77  5
     public ViewFactory getComponent(String name)
 78   
     {
 79  5
         Object component = components.get(name);
 80  1
         if (component == null) throw new IllegalArgumentException("No such component in this application: " + name);
 81  4
         ViewFactory factory;
 82  4
         if (component instanceof ViewLink)
 83   
         {
 84  2
             factory = ((ViewLink) component).getTarget();
 85   
         }
 86   
         else
 87   
         {
 88  2
             factory = (ViewFactory) component;
 89   
         }
 90  4
         return factory;
 91   
     }
 92   
 
 93   
     /**
 94   
      * Registers a <em>new</em> component.
 95   
      * @throws IllegalStateException if that component has already been registered.
 96   
      */
 97  7
     public void registerComponent(String name, ViewFactory factory)
 98   
     {
 99  1
         if (components.containsKey(name)) throw new IllegalStateException(name + " has already been registered.");
 100  6
         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  0
     public void registerPrerenderComponent(String name, View component)
 108   
     {
 109  0
         if (components.containsKey(name)) throw new IllegalStateException(name + " has already been registered.");
 110  0
         components.put(name, component);
 111   
     }
 112   
 
 113  1
     public void registerLink(String name, ViewFactory originalBinding)
 114   
     {
 115  1
         registerComponent(name, new ViewLink(originalBinding));
 116   
     }
 117   
 
 118   
     /**
 119   
      * Relinks a link.
 120   
      */
 121  1
     public void relink(String name, ViewFactory target)
 122   
     {
 123  1
         ViewLink link = (ViewLink) components.get(name);
 124  0
         if (link == null) throw new IllegalArgumentException("No such link " + name);
 125  1
         link.relink(target);
 126   
     }
 127   
 
 128   
     /**
 129   
      * Relinks a link to a named view.
 130   
      */
 131  0
     public void relink(String name, String target)
 132   
     {
 133  0
         relink(name, getComponent(target));
 134   
     }
 135   
 
 136   
     /**
 137   
      * Overriding method needs to call this method.
 138   
      */
 139  6
     public void init()
 140   
     {
 141  6
         initDefaultPropertyEditors();
 142  6
         initPrerenderedComponents();
 143   
     }
 144   
 
 145  1
     public void destroy()
 146   
     {
 147   
         // do nothing by default
 148   
     }
 149   
 
 150  3
     public void valueBound(HttpSessionBindingEvent event)
 151   
     {
 152  3
         init();
 153   
     }
 154   
 
 155  1
     public void valueUnbound(HttpSessionBindingEvent event)
 156   
     {
 157  1
         destroy();
 158   
     }
 159   
 
 160  6
     protected void initPrerenderedComponents()
 161   
     {
 162   
         // none by default
 163   
     }
 164   
 
 165  6
     protected void initDefaultPropertyEditors()
 166   
     {
 167   
         // set up some obvious editors which should have been setup by the JDK but are not
 168  6
         PropertyEditorManager.registerEditor(Integer.class, PropertyEditorManager.findEditor(Integer.TYPE).getClass());
 169  6
         PropertyEditorManager.registerEditor(Double.class, PropertyEditorManager.findEditor(Double.TYPE).getClass());
 170   
     }
 171   
 
 172  3
     public void beforeRequest(RenderContext context)
 173   
             throws IOException
 174   
     {
 175   
     }
 176   
 
 177  9
     public void afterRequest(RenderContext context)
 178   
             throws IOException
 179   
     {
 180  9
         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  7
     public Pipeline createRenderPipeline(ViewFactory factory)
 188   
     {
 189  7
         Pipeline process = createBasicPipeline();
 190  7
         process.addValve(new SingleViewFactoryRenderValve(factory));
 191  7
         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  0
     public Pipeline createPrerenderPipeline()
 199   
     {
 200  0
         Pipeline pipeline = createBasicPipeline();
 201  0
         pipeline.addValve(new PrerenderValve());
 202  0
         return pipeline;
 203   
     }
 204   
 
 205   
     /**
 206   
      * Creates the basic pipeline with the exception of a render valve.
 207   
      */
 208  8
     public Pipeline createBasicPipeline()
 209   
     {
 210  8
         Pipeline process = createDefaultPipeline();
 211  8
         process.addValve(new ParseValve());
 212  8
         process.addValve(new EventValve());
 213  8
         process.addValve(new RedirectValve());
 214  8
         return process;
 215   
     }
 216   
 
 217  0
     protected Pipeline createDefaultPipeline()
 218   
     {
 219  0
         DefaultPipeline pipeline = new DefaultPipeline();
 220  0
         pipeline.addValve(new ErrorValve());
 221  0
         return pipeline;
 222   
     }
 223   
 
 224  11
     public void resetParsingComponents()
 225   
     {
 226  11
         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  11
     public Iterator iterateParsingComponents()
 235   
     {
 236  11
         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  1
     public Collection getParsingComponents()
 244   
     {
 245  1
         return parsingComponents;
 246   
     }
 247   
 
 248  10
     public void registerParsingComponent(View view)
 249   
     {
 250  9
         if (parsingComponents == null) parsingComponents = new LinkedList();
 251  10
         parsingComponents.add(view);
 252   
     }
 253   
 
 254  10
     public String nextUniqueID()
 255   
     {
 256  10
         currentId++;
 257  10
         return String.valueOf(currentId);
 258   
     }
 259   
 
 260  13
     public void allocateUniqueID(String id, View view)
 261   
     {
 262   
         // check uniqueness of id
 263  13
         if (viewToID.containsValue(id) && !id.equals(viewToID.get(view)))
 264   
         {
 265  1
             throw new IllegalArgumentException("ID already allocated: " + id);
 266   
         }
 267   
         else
 268  12
             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  0
     public Map getComponentsToPrerender() throws Exception
 276   
     {
 277  0
         return components;
 278   
     }
 279   
 
 280   
     /**
 281   
      * Returns the application of the currently executing pipeline.
 282   
      */
 283  50
     public static Application getApplication()
 284   
     {
 285  50
         return (Application) Pipeline.getCurrentExecuteContext().getAttribute(ExecuteContext.ApplicationAttribute);
 286   
     }
 287   
 
 288   
     /**
 289   
      * Override to provide a title rendered by the angkor:header-tag.
 290   
      */
 291  1
     public String getWindowTitle()
 292   
     {
 293  1
         return null;
 294   
     }
 295   
 
 296  7
     public void registerPage(String name, Page page)
 297   
     {
 298  7
         if (components.containsKey(name) && components.get(name) != page)
 299   
         {
 300  0
             throw new IllegalStateException(name + " has already been registered.");
 301   
         }
 302  7
         if(page.getApplication() != null && page.getApplication() != this)
 303   
         {
 304  1
             throw new IllegalArgumentException("Page can only be registered with one application.");
 305   
         }
 306  6
         page.setApplication(this);
 307  6
         components.put(name, page);
 308   
     }
 309   
 
 310  1
     public void process(HttpServletRequest request, HttpServletResponse response) throws Exception
 311   
     {
 312  1
         RenderContext renderContext = new RenderContext(request, response);
 313   
 
 314  1
         beforeRequest(renderContext);
 315   
 
 316  1
         String pageName = extractPageName(request);
 317  1
         Page page = getPage(pageName);
 318   
 
 319  1
         Pipeline pipeline = page.createProcessPipeline();
 320  1
         pipeline.execute(renderContext);
 321   
 
 322  1
         afterRequest(renderContext);
 323   
     }
 324   
 
 325  3
     public Page getPage(String pageName)
 326   
     {
 327  3
         Page page = (Page) components.get(pageName);
 328  3
         if(page == null)
 329   
         {
 330  1
             throw new IllegalArgumentException("No such page " + pageName + " exists.");
 331   
         }
 332  2
         return page;
 333   
     }
 334   
 
 335  1
     private String extractPageName(HttpServletRequest request)
 336   
     {
 337  1
         String requestURI = request.getRequestURI();
 338  1
         return requestURI.substring(requestURI.lastIndexOf('/') + 1);
 339   
     }
 340   
 }
 341