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