Coverage Report - org.apache.tapestry.internal.event.impl.ComponentEventInvoker
 
Classes in this File Line Coverage Branch Coverage Complexity
ComponentEventInvoker
86% 
97% 
3.857
 
 1  
 // Copyright 2004, 2005 The Apache Software Foundation
 2  
 //
 3  
 // Licensed under the Apache License, Version 2.0 (the "License");
 4  
 // you may not use this file except in compliance with the License.
 5  
 // You may obtain a copy of the License at
 6  
 //
 7  
 //     http://www.apache.org/licenses/LICENSE-2.0
 8  
 //
 9  
 // Unless required by applicable law or agreed to in writing, software
 10  
 // distributed under the License is distributed on an "AS IS" BASIS,
 11  
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
 // See the License for the specific language governing permissions and
 13  
 // limitations under the License.
 14  
 package org.apache.tapestry.internal.event.impl;
 15  
 
 16  
 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
 17  
 import org.apache.hivemind.util.Defense;
 18  
 import org.apache.tapestry.IActionListener;
 19  
 import org.apache.tapestry.IComponent;
 20  
 import org.apache.tapestry.IForm;
 21  
 import org.apache.tapestry.IRequestCycle;
 22  
 import org.apache.tapestry.event.BrowserEvent;
 23  
 import org.apache.tapestry.event.ResetEventListener;
 24  
 import org.apache.tapestry.form.FormSupport;
 25  
 import org.apache.tapestry.internal.event.ComponentEventProperty;
 26  
 import org.apache.tapestry.internal.event.EventBoundListener;
 27  
 import org.apache.tapestry.internal.event.IComponentEventInvoker;
 28  
 import org.apache.tapestry.listener.ListenerInvoker;
 29  
 import org.apache.tapestry.spec.IComponentSpecification;
 30  
 import org.apache.tapestry.spec.IEventListener;
 31  
 
 32  
 import java.util.*;
 33  
 
 34  
 
 35  
 /**
 36  
  * Implementation of {@link IComponentEventInvoker}.
 37  
  */
 38  13
 public class ComponentEventInvoker implements IComponentEventInvoker, ResetEventListener
 39  
 {
 40  1
     static final ComponentEventProperty[] EMPTY_PROPERTIES = new ComponentEventProperty[0];
 41  
 
 42  
     // Mapped component id path -> List of IEventListeners
 43  13
     private Map _components = new ConcurrentHashMap();
 44  
     // Mapped form id path -> List of IEventListeners
 45  13
     private Map _formComponents = new ConcurrentHashMap();
 46  
     // Used to invoke actual listener methods
 47  
     private ListenerInvoker _invoker;
 48  
 
 49  
     // Cached set of ComponentEventProperty[] arrays mapped to specific components
 50  13
     private Map _propertyCache = new ConcurrentHashMap();
 51  
 
 52  
     /**
 53  
      * {@inheritDoc}
 54  
      */
 55  
     public void invokeListeners(IComponent component, IRequestCycle cycle, BrowserEvent event)
 56  
     {
 57  2
         Defense.notNull(component, "component");
 58  2
         Defense.notNull(cycle, "cycle");
 59  2
         Defense.notNull(event, "event");
 60  
 
 61  2
         invokeComponentListeners(component, cycle, event);
 62  
 
 63  2
         invokeElementListeners(component, cycle, event);
 64  2
     }
 65  
 
 66  
     /**
 67  
      * {@inheritDoc}
 68  
      */
 69  
     public void invokeFormListeners(FormSupport formSupport, final IRequestCycle cycle, final BrowserEvent event)
 70  
     {
 71  4
         Defense.notNull(formSupport, "formSupport");
 72  4
         Defense.notNull(cycle, "cycle");
 73  4
         Defense.notNull(event, "event");
 74  
 
 75  4
         IForm form = formSupport.getForm();
 76  4
         String formIdPath = form.getExtendedId();
 77  
 
 78  4
         String targetId = (String)event.getTarget().get("id");
 79  4
         String componentId = event.getComponentId();
 80  
 
 81  4
         if (targetId == null || componentId == null)
 82  1
             return;
 83  
 
 84  3
         List comps = getFormEventListeners(formIdPath);
 85  3
         if (comps == null)
 86  1
             return;
 87  
 
 88  2
         boolean disableFocus = false;
 89  
 
 90  4
         for (int i=0; i < comps.size(); i++)
 91  
         {
 92  2
             IComponentSpecification spec = (IComponentSpecification)comps.get(i);
 93  2
             EventBoundListener[] listeners = spec.getFormEvents(formIdPath, event);
 94  
 
 95  2
             IComponent target = null;
 96  2
             if (spec.isPageSpecification())
 97  
             {
 98  0
                 target = form.getPage();
 99  
             } else {
 100  2
                 target = findComponent(form.getPage().getComponents().values(), spec);
 101  
             }
 102  
 
 103  4
             for (int e=0; e < listeners.length; e++)
 104  
             {
 105  
                 // ensure ~only~ the method that targeted this event gets called!
 106  
 
 107  2
                 if (!listeners[e].getComponentId().endsWith(componentId))
 108  0
                     continue;
 109  
 
 110  
                 // clear validation errors but not input if async validation is
 111  
                 // disabled
 112  
 
 113  2
                 if (!listeners[e].isValidateForm())
 114  
                 {
 115  2
                     form.getDelegate().clearErrors();
 116  
                 }
 117  
 
 118  
                 // handle disabling focus
 119  2
                 if (!disableFocus && !listeners[e].shouldFocusForm())
 120  1
                     disableFocus = true;
 121  
 
 122  
                 // defer execution until after form is done rewinding
 123  
 
 124  2
                 form.addDeferredRunnable(
 125  
                   new FormRunnable(target.getListeners().getListener(listeners[e].getMethodName()),
 126  
                                    target,
 127  
                                    cycle));
 128  
             }
 129  
         }
 130  
 
 131  
         // Form uses cycle attributes to test whether or not to focus .
 132  
         // The attribute existing at all is enough to bypass focusing.
 133  
         
 134  2
         if (disableFocus)
 135  
         {
 136  1
             cycle.disableFocus();
 137  
         }
 138  2
     }
 139  
 
 140  
     void invokeComponentListeners(IComponent component, IRequestCycle cycle, BrowserEvent event)
 141  
     {
 142  2
         String idPath = component.getExtendedId();
 143  2
         List listeners = getEventListeners(idPath);
 144  2
         if (listeners == null)
 145  0
             return;
 146  
 
 147  4
         for (int i = 0; i < listeners.size(); i++)
 148  
         {
 149  2
             IComponentSpecification listener = (IComponentSpecification)listeners.get(i);
 150  
 
 151  
             IComponent target;
 152  
             ComponentEventProperty props;
 153  
 
 154  2
             if (listener.isPageSpecification())
 155  
             {
 156  0
                 target = component.getPage();
 157  0
                 props = listener.getComponentEvents(idPath);
 158  
             } else
 159  
             {
 160  2
                 target = findComponent(component.getPage().getComponents().values(), listener);
 161  2
                 props = target.getSpecification().getComponentEvents(idPath);
 162  
             }
 163  
             
 164  2
             if (props == null)
 165  1
                 continue;
 166  
 
 167  1
             List clisteners = props.getEventListeners(event.getName());
 168  2
             for (int e=0; e < clisteners.size(); e++)
 169  
             {
 170  1
                 EventBoundListener eventListener = (EventBoundListener)clisteners.get(e);
 171  
 
 172  1
                 _invoker.invokeListener(target.getListeners().getListener(eventListener.getMethodName()), target, cycle);
 173  
             }
 174  
 
 175  
         }
 176  2
     }
 177  
 
 178  
     void invokeElementListeners(IComponent component, IRequestCycle cycle, BrowserEvent event)
 179  
     {
 180  2
         String targetId = (String)event.getTarget().get("id");
 181  2
         if (targetId == null)
 182  0
             return;
 183  
 
 184  2
         ComponentEventProperty prop = component.getSpecification().getElementEvents(targetId);
 185  2
         if (prop == null)
 186  1
             return;
 187  
 
 188  1
         List listeners = prop.getEventListeners(event.getName());
 189  
 
 190  2
         for (int i=0; i < listeners.size(); i++)
 191  
         {
 192  1
             EventBoundListener listener = (EventBoundListener)listeners.get(i);
 193  
 
 194  1
             _invoker.invokeListener(component.getListeners().getListener(listener.getMethodName()), component, cycle);
 195  
         }
 196  1
     }
 197  
 
 198  
     IComponent findComponent(Collection comps, IComponentSpecification spec)
 199  
     {
 200  4
         IComponent ret = null;
 201  
 
 202  4
         Iterator it = comps.iterator();
 203  
 
 204  4
         while (it.hasNext())
 205  
         {
 206  4
             IComponent comp = (IComponent)it.next();
 207  
 
 208  4
             if (comp.getSpecification().equals(spec))
 209  
             {
 210  4
                 ret = comp;
 211  4
                 break;
 212  
             }
 213  
 
 214  0
             ret = findComponent(comp.getComponents().values(), spec);
 215  0
             if (ret != null)
 216  0
                 break;
 217  0
         }
 218  
 
 219  4
         return ret;
 220  
     }
 221  
 
 222  
     /** Local runnable for deferred form connections. */
 223  13
     class FormRunnable implements Runnable {
 224  
 
 225  
         private IActionListener _listener;
 226  
         private IComponent _component;
 227  
         private IRequestCycle _cycle;
 228  
 
 229  
         public FormRunnable(IActionListener listener, IComponent comp, IRequestCycle cycle)
 230  2
         {
 231  2
             _listener = listener;
 232  2
             _component = comp;
 233  2
             _cycle = cycle;
 234  2
         }
 235  
 
 236  
         public void run()
 237  
         {
 238  0
             _invoker.invokeListener(_listener, _component, _cycle);
 239  0
         }
 240  
     }
 241  
 
 242  
     /**
 243  
      * {@inheritDoc}
 244  
      */
 245  
     public void addEventListener(String componentId, IComponentSpecification listener)
 246  
     {
 247  11
         List listeners = (List)_components.get(componentId);
 248  
 
 249  11
         if (listeners == null)
 250  
         {
 251  10
             listeners = new ArrayList();
 252  10
             _components.put(componentId, listeners);
 253  
         }
 254  
 
 255  11
         if (!listeners.contains(listener))
 256  
         {
 257  11
             listeners.add(listener);
 258  
         }
 259  
 
 260  11
         _propertyCache.remove(componentId);
 261  11
     }
 262  
 
 263  
     /**
 264  
      * {@inheritDoc}
 265  
      */
 266  
     public List getEventListeners(String componentId)
 267  
     {
 268  13
         if (componentId == null)
 269  0
             return null;
 270  
 
 271  13
         return (List)_components.get(componentId);
 272  
     }
 273  
 
 274  
     public ComponentEventProperty[] getEventPropertyListeners(String componentIdPath)
 275  
     {
 276  15
         if (componentIdPath == null)
 277  0
             return EMPTY_PROPERTIES;
 278  
 
 279  15
         ComponentEventProperty[] ret = (ComponentEventProperty[])_propertyCache.get(componentIdPath);
 280  15
         if (ret != null)
 281  4
             return ret;
 282  
 
 283  11
         List listeners = getEventListeners(componentIdPath);
 284  11
         if (listeners == null || listeners.size() < 1)
 285  4
             return EMPTY_PROPERTIES;
 286  
 
 287  7
         List props = new ArrayList();
 288  15
         for (int i=0; i < listeners.size(); i++)
 289  
         {
 290  8
             IEventListener listener = (IEventListener)listeners.get(i);
 291  
 
 292  8
             props.add(listener.getComponentEvents(componentIdPath));
 293  
         }
 294  
 
 295  7
         ret = (ComponentEventProperty[])props.toArray(new ComponentEventProperty[props.size()]);
 296  
 
 297  7
         _propertyCache.put(componentIdPath, ret);
 298  
 
 299  7
         return ret;
 300  
     }
 301  
 
 302  
     /**
 303  
      * {@inheritDoc}
 304  
      */
 305  
     public void addFormEventListener(String formId, IComponentSpecification listener)
 306  
     {
 307  6
         List listeners = (List)_formComponents.get(formId);
 308  
 
 309  6
         if (listeners == null)
 310  
         {
 311  4
             listeners = new ArrayList();
 312  4
             _formComponents.put(formId, listeners);
 313  
         }
 314  
 
 315  6
         if (!listeners.contains(listener))
 316  
         {
 317  4
             listeners.add(listener);
 318  
         }
 319  6
     }
 320  
 
 321  
     /**
 322  
      * {@inheritDoc}
 323  
      */
 324  
     public List getFormEventListeners(String formId)
 325  
     {
 326  3
         if (formId == null)
 327  0
             return null;
 328  
 
 329  3
         return (List)_formComponents.get(formId);
 330  
     }
 331  
 
 332  
     /**
 333  
      * {@inheritDoc}
 334  
      */
 335  
     public void resetEventDidOccur()
 336  
     {
 337  0
         _components.clear();
 338  0
         _formComponents.clear();
 339  0
         _propertyCache.clear();
 340  0
     }
 341  
 
 342  
     /** Injected. */
 343  
     public void setInvoker(ListenerInvoker invoker)
 344  
     {
 345  5
         _invoker = invoker;
 346  5
     }
 347  
 }