/*
* Copyright 2013 Simon Taddiken
*
* This file is part of Polly HTTP API.
*
* Polly HTTP API is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Polly HTTP API is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with Polly HTTP API. If not, see http://www.gnu.org/licenses/.
*/
package de.skuzzle.polly.http.internal;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import de.skuzzle.polly.http.api.Controller;
import de.skuzzle.polly.http.api.HttpEvent;
import de.skuzzle.polly.http.api.HttpEvent.RequestMode;
import de.skuzzle.polly.http.api.handler.HttpEventHandler;
import de.skuzzle.polly.http.api.HttpException;
import de.skuzzle.polly.http.annotations.Param;
import de.skuzzle.polly.http.api.ParameterHandler;
import de.skuzzle.polly.http.api.answers.HttpAnswer;
class ReflectionHttpHandler implements HttpEventHandler {
private final String uri;
private final Method handler;
private final RequestMode mode;
private final Controller carrier;
private final HttpServletServerImpl parent;
private final boolean matchExactly;
public ReflectionHttpHandler(RequestMode mode, String uri, Controller carrier,
Method handler, HttpServletServerImpl parent, boolean matchExactly) {
this.matchExactly = matchExactly;
this.mode = mode;
this.carrier = carrier;
this.uri = uri;
this.handler = handler;
this.parent = parent;
}
@Override
public HttpAnswer handleHttpEvent(String registered, HttpEvent e,
HttpEventHandler next) throws HttpException {
if (e.getMode() != this.mode ||
this.matchExactly && !e.getPlainUri().equals(this.uri)) {
return next.handleHttpEvent(registered, e, next);
}
// extract actual parameters from the request
final Object[] params = new Object[this.handler.getParameterTypes().length];
for (int i = 0; i < this.handler.getParameterTypes().length; ++i) {
final Annotation[] an = this.handler.getParameterAnnotations()[i];
// extract parameter name from annotated method parameter
// INVARIANT: every parameter is annotated!
Param key = null;
for (Annotation a : an) {
if (a instanceof Param) {
key = (Param) a;
break;
}
}
// value associated with that key in the current request
String sValue = e.parameterMap(this.mode).get(key.value());
if (sValue == null) {
if (key.optional()) {
sValue = key.defaultValue();
} else {
// this handler does not match, try the next one
return next.handleHttpEvent(registered, e, next);
}
}
final Class<?> type = this.handler.getParameterTypes()[i];
final ParameterHandler ph = this.parent.findHandler(type, key.typeHint());
// INVARIANT: ph can not be null
assert ph != null;
params[i] = ph.parse(sValue);
}
// execute the function
try {
final Controller copy = this.carrier.bind(registered, e);
return (HttpAnswer) this.handler.invoke(copy, params);
} catch (InvocationTargetException e1) {
if (e1.getTargetException() instanceof HttpException) {
throw (HttpException) e1.getTargetException();
}
throw new HttpException(e1.getTargetException());
} catch (Exception e1) {
throw new HttpException(e1);
}
}
}