/*
* Copyright 2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springmodules.xt.ajax;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.log4j.Logger;
import org.springmodules.xt.ajax.support.EventHandlingException;
import org.springmodules.xt.ajax.support.UnsupportedEventException;
/**
* Abstract {@link AjaxHandler} with the {@link #handle(AjaxEvent)} method implemented as a <i>dynamic template method</i>
* with automatic dispatching of different requests depending on the {@link AjaxEvent} id.<br>
* For handling different requests, hence different events, you have to simply implement a method named after the AjaxEvent id, with the following signature:
* <br><br>
* <code>public {@link AjaxResponse} eventId(<i>{@link AjaxEvent}</i> )</code>
* <br><br>
* The <i>AjaxEvent</i> in the signature above must be the effective subinterface of the {@link AjaxEvent} actually handled.<br>
* Given an ajax event with id <i>countrySelection</i>, the handling method will be:
* <br><br>
* <code>public {@link AjaxResponse} countrySelection({@link AjaxEvent} )</code>
* <br><br>
* The already implemented {@link #handle(AjaxEvent )} will do the appropriate dispatching.
* <br><br>
* NOTE: Implementors are required to be thread-safe.
*
* @author Sergio Bossa
*/
public abstract class AbstractAjaxHandler implements AjaxHandler {
private static final Logger logger = Logger.getLogger(AbstractAjaxHandler.class);
/**
* Dynamic template method for handling ajax requests depending on the event id.
* <br><br>
* @see AjaxHandler#handle(AjaxEvent )
*/
public AjaxResponse handle(AjaxEvent event) {
if (event == null || event.getEventId() == null) {
logger.error("Event and event id cannot be null.");
throw new IllegalArgumentException("Event and event id cannot be null.");
}
String id = event.getEventId();
AjaxResponse response = null;
try {
Method m = this.getMatchingMethod(event);
if (m != null) {
logger.info(new StringBuilder("Invoking method: ").append(m));
response = (AjaxResponse) m.invoke(this, new Object[]{event});
}
else {
logger.error("You need to call the supports() method first!");
throw new UnsupportedEventException("You need to call the supports() method first!");
}
}
catch(IllegalAccessException ex) {
logger.error(ex.getMessage(), ex);
logger.error("Cannot handle the given event with id: " + id);
throw new UnsupportedEventException("Cannot handle the given event with id: " + id, ex);
}
catch(InvocationTargetException ex) {
logger.error(ex.getMessage(), ex);
logger.error("Exception while handling the given event with id: " + id);
throw new EventHandlingException("Exception while handling the given event with id: " + id, ex);
}
return response;
}
/**
* Supports the given event if the concrete class implements a method for handling it, that is, a method
* with the following signature:
* <br><br>
* <i>public {@link AjaxResponse} eventId({@link AjaxEvent} )</i>
* <br><br>
* @see AjaxHandler#supports(AjaxEvent )
*/
public boolean supports(AjaxEvent event) {
String id = event.getEventId();
if (id == null) {
logger.error("Event id cannot be null.");
throw new IllegalArgumentException("Event id cannot be null.");
}
Method m = this.getMatchingMethod(event);
if (m != null) {
logger.debug(new StringBuilder("Event supported by method: ").append(m));
return true;
}
else {
return false;
}
}
/**
* FIXME: Cache reflection results!
*/
private Method getMatchingMethod(AjaxEvent event) {
Class eventType = this.getEventType(event);
Method[] methods = this.getClass().getMethods();
Method ret = null;
for (Method method : methods) {
if (method.getName().equals(event.getEventId()) && method.getParameterTypes()[0].isAssignableFrom(eventType)) {
ret = method;
break;
}
}
return ret;
}
/**
* FIXME: Cache reflection results!
*/
private Class getEventType(AjaxEvent event) {
Class[] interfaces = event.getClass().getInterfaces();
Class ret = event.getClass();
for (Class intf : interfaces) {
if (AjaxEvent.class.isAssignableFrom(intf)) {
ret = intf;
break;
}
}
return ret;
}
}