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