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