blob: 16a5fb9a358b99a83a13e2facf493665f70e69b3 [file] [log] [blame]
package org.apache.tapestry.pageload;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.PoolManageable;
import org.apache.tapestry.IComponent;
import org.apache.tapestry.IForm;
import org.apache.tapestry.IPage;
import org.apache.tapestry.IRender;
import org.apache.tapestry.form.IFormComponent;
import org.apache.tapestry.internal.Component;
import org.apache.tapestry.internal.event.ComponentEventProperty;
import org.apache.tapestry.internal.event.EventBoundListener;
import org.apache.tapestry.internal.event.IComponentEventInvoker;
import org.apache.tapestry.spec.IComponentSpecification;
import java.util.*;
/**
* Handles connecting up components and forms targeted with the EventListener annotation.
*/
public class EventConnectionVisitor implements IComponentVisitor, PoolManageable {
IComponentEventInvoker _invoker;
IPage _currentPage = null;
List _forms = new ArrayList();
public void visitComponent(IComponent component)
{
checkComponentPage(component);
Map events = component.getSpecification().getComponentEvents();
Set keySet = events.keySet();
String[] compIds = (String[]) keySet.toArray(new String[keySet.size()]);
for (int i=0; i < compIds.length; i++)
{
String compId = compIds[i];
ComponentEventProperty property = (ComponentEventProperty) events.get(compId);
// find the targeted component
IComponent comp = findComponent(compId, component.getPage());
if (comp == null)
continue;
if (Component.class.isInstance(comp))
((Component)comp).setHasEvents(true);
// wire up with idPath
String idPath = comp.getExtendedId();
component.getSpecification().rewireComponentId(compId, idPath);
_invoker.addEventListener(idPath, component.getSpecification());
wireFormEvents(comp, component.getSpecification());
}
// find form element targets for re-mapping with proper idpath && IEventInvoker connection
events = component.getSpecification().getElementEvents();
Iterator it = events.keySet().iterator();
// for efficiency later in ComponentEventConnectionWorker
if (events.size() > 0 && Component.class.isInstance(component)) {
((Component)component).setHasEvents(true);
}
while (it.hasNext())
{
String elementId = (String) it.next();
ComponentEventProperty property = (ComponentEventProperty) events.get(elementId);
Iterator bindingIt = property.getFormEvents().iterator();
while (bindingIt.hasNext())
{
String key = (String) bindingIt.next();
List listeners = property.getFormEventListeners(key);
for (int i=0; i < listeners.size(); i++) {
EventBoundListener listener = (EventBoundListener) listeners.get(i);
wireElementFormEvents(listener, component, component.getSpecification());
}
}
}
}
void wireElementFormEvents(EventBoundListener listener, IComponent component, IComponentSpecification spec)
{
if (listener.getFormId() == null)
return;
if (_forms.size() < 1)
discoverPageForms(component.getPage());
IForm form = null;
for (int i=0; i < _forms.size(); i++)
{
IForm f = (IForm) _forms.get(i);
if (listener.getFormId().equals(f.getExtendedId()) || listener.getFormId().equals(f.getId()))
{
form = f;
break;
}
}
// couldn't find the form they specified
if (form == null)
throw new ApplicationRuntimeException(PageloadMessages.componentNotFound(listener.getFormId()),
component, component.getLocation(), null);
String idPath = form.getExtendedId();
listener.setFormId(idPath);
_invoker.addFormEventListener(idPath, spec);
}
void wireFormEvents(IComponent component, IComponentSpecification listener)
{
if (!IFormComponent.class.isInstance(component))
return;
IFormComponent fcomp = (IFormComponent) component;
if (_forms.size() < 1)
discoverPageForms(fcomp.getPage());
IForm form = findComponentForm(fcomp);
if (form == null)
return;
listener.connectAutoSubmitEvents(component, form);
_invoker.addFormEventListener(form.getExtendedId(), listener);
}
IComponent findComponent(String id, IComponent target)
{
Map components = target.getComponents();
if (components == null)
return null;
IComponent comp = (IComponent) components.get(id);
if (comp != null)
return comp;
Iterator children = components.values().iterator();
while (children.hasNext())
{
IComponent child = (IComponent) children.next();
comp = findComponent(id, child);
if (comp != null)
return comp;
}
return null;
}
void discoverPageForms(IComponent parent)
{
if (IForm.class.isInstance(parent))
_forms.add(parent);
Iterator it = parent.getComponents().values().iterator();
while (it.hasNext())
{
IComponent comp = (IComponent)it.next();
discoverPageForms(comp);
}
}
IForm findComponentForm(IFormComponent child)
{
for (int i = 0; i < _forms.size(); i++) {
IForm form = (IForm) _forms.get(i);
IComponent match = findContainedComponent(child.getExtendedId(), (Component)form);
if (match != null)
return form;
}
return null;
}
IComponent findContainedComponent(String idPath, Component container)
{
IComponent comp = (IComponent) container;
if (idPath.equals(comp.getExtendedId()))
return comp;
IRender[] children = container.getContainedRenderers();
if (children == null)
return null;
for (int i=0; i < children.length; i++) {
if (children[i] == null)
return null;
if (!Component.class.isInstance(children[i]))
continue;
IComponent found = findContainedComponent(idPath, (Component)children[i]);
if (found != null)
return found;
}
return null;
}
void checkComponentPage(IComponent component)
{
if (_currentPage == null) {
_currentPage = component.getPage();
_forms.clear();
} else if (component.getPage() != _currentPage) {
_currentPage = component.getPage();
_forms.clear();
}
}
public void activateService()
{
_currentPage = null;
_forms.clear();
}
public void passivateService()
{
_currentPage = null;
_forms.clear();
}
// injected
public void setEventInvoker(IComponentEventInvoker invoker)
{
_invoker = invoker;
}
}