001 package org.apache.tapestry.pageload; 002 003 import org.apache.hivemind.ApplicationRuntimeException; 004 import org.apache.hivemind.PoolManageable; 005 import org.apache.tapestry.IComponent; 006 import org.apache.tapestry.IForm; 007 import org.apache.tapestry.IPage; 008 import org.apache.tapestry.IRender; 009 import org.apache.tapestry.form.IFormComponent; 010 import org.apache.tapestry.internal.Component; 011 import org.apache.tapestry.internal.event.ComponentEventProperty; 012 import org.apache.tapestry.internal.event.EventBoundListener; 013 import org.apache.tapestry.internal.event.IComponentEventInvoker; 014 import org.apache.tapestry.spec.IComponentSpecification; 015 016 import java.util.*; 017 018 /** 019 * Handles connecting up components and forms targeted with the EventListener annotation. 020 */ 021 public class EventConnectionVisitor implements IComponentVisitor, PoolManageable { 022 023 IComponentEventInvoker _invoker; 024 025 IPage _currentPage = null; 026 List _forms = new ArrayList(); 027 028 public void visitComponent(IComponent component) 029 { 030 checkComponentPage(component); 031 032 Map events = component.getSpecification().getComponentEvents(); 033 Set keySet = events.keySet(); 034 String[] compIds = (String[]) keySet.toArray(new String[keySet.size()]); 035 036 for (int i=0; i < compIds.length; i++) 037 { 038 String compId = compIds[i]; 039 040 // find the targeted component, first search component children 041 // and then page children if not contained by component 042 043 IComponent comp = findComponent(compId, component); 044 045 if (comp == null && !IPage.class.isInstance(component)) 046 { 047 comp = findComponent(compId, component.getPage()); 048 } 049 050 if (comp == null) 051 continue; 052 053 if (Component.class.isInstance(comp)) 054 ((Component)comp).setHasEvents(true); 055 056 // wire up with idPath 057 058 String idPath = comp.getExtendedId(); 059 060 component.getSpecification().rewireComponentId(compId, idPath, component.getIdPath()); 061 062 _invoker.addEventListener(idPath, component.getSpecification()); 063 wireFormEvents(comp, component.getSpecification()); 064 } 065 066 // find form element targets for re-mapping with proper idpath && IEventInvoker connection 067 068 events = component.getSpecification().getElementEvents(); 069 Iterator it = events.keySet().iterator(); 070 071 // for efficiency later in ComponentEventConnectionWorker 072 073 if (events.size() > 0 && Component.class.isInstance(component)) 074 { 075 ((Component)component).setHasEvents(true); 076 } 077 078 while (it.hasNext()) 079 { 080 String elementId = (String) it.next(); 081 ComponentEventProperty property = (ComponentEventProperty) events.get(elementId); 082 083 Iterator bindingIt = property.getFormEvents().iterator(); 084 while (bindingIt.hasNext()) 085 { 086 String key = (String) bindingIt.next(); 087 List listeners = property.getFormEventListeners(key); 088 089 for (int i=0; i < listeners.size(); i++) 090 { 091 EventBoundListener listener = (EventBoundListener) listeners.get(i); 092 wireElementFormEvents(listener, component, component.getSpecification()); 093 } 094 } 095 } 096 } 097 098 void wireElementFormEvents(EventBoundListener listener, IComponent component, IComponentSpecification spec) 099 { 100 if (listener.getFormId() == null) 101 return; 102 103 if (_forms.size() < 1) 104 discoverPageForms(component.getPage()); 105 106 IForm form = null; 107 for (int i=0; i < _forms.size(); i++) 108 { 109 IForm f = (IForm) _forms.get(i); 110 if (listener.getFormId().equals(f.getExtendedId()) || listener.getFormId().equals(f.getId())) 111 { 112 form = f; 113 break; 114 } 115 } 116 117 // couldn't find the form they specified 118 119 if (form == null) 120 throw new ApplicationRuntimeException(PageloadMessages.componentNotFound(listener.getFormId()), 121 component, component.getLocation(), null); 122 123 String idPath = form.getExtendedId(); 124 125 listener.setFormId(idPath); 126 _invoker.addFormEventListener(idPath, spec); 127 } 128 129 void wireFormEvents(IComponent component, IComponentSpecification listener) 130 { 131 if (!IFormComponent.class.isInstance(component)) 132 return; 133 134 IFormComponent fcomp = (IFormComponent) component; 135 136 if (_forms.size() < 1) 137 discoverPageForms(fcomp.getPage()); 138 139 IForm form = findComponentForm(fcomp); 140 if (form == null) 141 return; 142 143 listener.connectAutoSubmitEvents(component, form); 144 _invoker.addFormEventListener(form.getExtendedId(), listener); 145 } 146 147 IComponent findComponent(String id, IComponent target) 148 { 149 Map components = target.getComponents(); 150 if (components == null) 151 return null; 152 153 IComponent comp = (IComponent) components.get(id); 154 if (comp != null) 155 return comp; 156 157 Iterator children = components.values().iterator(); 158 159 while (children.hasNext()) 160 { 161 IComponent child = (IComponent) children.next(); 162 163 comp = findComponent(id, child); 164 if (comp != null) 165 return comp; 166 } 167 168 return null; 169 } 170 171 void discoverPageForms(IComponent parent) 172 { 173 if (IForm.class.isInstance(parent)) 174 _forms.add(parent); 175 176 Iterator it = parent.getComponents().values().iterator(); 177 while (it.hasNext()) 178 { 179 IComponent comp = (IComponent)it.next(); 180 181 discoverPageForms(comp); 182 } 183 } 184 185 IForm findComponentForm(IFormComponent child) 186 { 187 for (int i = 0; i < _forms.size(); i++) 188 { 189 IForm form = (IForm) _forms.get(i); 190 191 IComponent match = findContainedComponent(child.getExtendedId(), (Component)form); 192 if (match != null) 193 return form; 194 } 195 196 return null; 197 } 198 199 IComponent findContainedComponent(String idPath, Component container) 200 { 201 IComponent comp = (IComponent) container; 202 203 if (idPath.equals(comp.getExtendedId())) 204 return comp; 205 206 IRender[] children = container.getContainedRenderers(); 207 if (children == null) 208 return null; 209 210 for (int i=0; i < children.length; i++) 211 { 212 if (children[i] == null) 213 return null; 214 215 if (!Component.class.isInstance(children[i])) 216 continue; 217 218 IComponent found = findContainedComponent(idPath, (Component)children[i]); 219 if (found != null) 220 return found; 221 } 222 223 return null; 224 } 225 226 void checkComponentPage(IComponent component) 227 { 228 if (_currentPage == null) 229 { 230 _currentPage = component.getPage(); 231 _forms.clear(); 232 } else if (component.getPage() != _currentPage) 233 { 234 _currentPage = component.getPage(); 235 _forms.clear(); 236 } 237 } 238 239 public void activateService() 240 { 241 _currentPage = null; 242 _forms.clear(); 243 } 244 245 public void passivateService() 246 { 247 _currentPage = null; 248 _forms.clear(); 249 } 250 251 // injected 252 public void setEventInvoker(IComponentEventInvoker invoker) 253 { 254 _invoker = invoker; 255 } 256 }