/**
* Copyright (C) 2003-2008 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.etk.core.rest.impl.method;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyReader;
import org.etk.common.logging.Logger;
import org.etk.core.rest.FilterDescriptor;
import org.etk.core.rest.impl.ApplicationContext;
import org.etk.core.rest.impl.InternalException;
import org.etk.core.rest.impl.ObjectFactory;
import org.etk.core.rest.method.MethodInvoker;
import org.etk.core.rest.method.MethodInvokerFilter;
import org.etk.core.rest.resource.GenericMethodResource;
/**
* Invoker for Resource Method, Sub-Resource Method and SubResource Locator.
*
* @author <a href="mailto:andrew00x@gmail.com">Andrey Parfonov</a>
* @version $Id: $
*/
public final class DefaultMethodInvoker implements MethodInvoker {
/**
* Logger.
*/
private static final Logger LOG = Logger.getLogger(DefaultMethodInvoker.class.getName());
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public Object invokeMethod(Object resource,
GenericMethodResource methodResource,
ApplicationContext context) {
for (ObjectFactory<FilterDescriptor> factory : context.getProviders()
.getMethodInvokerFilters(context.getPath())) {
MethodInvokerFilter f = (MethodInvokerFilter) factory.getInstance(context);
f.accept(methodResource);
}
Object[] p = new Object[methodResource.getMethodParameters().size()];
int i = 0;
for (org.etk.core.rest.method.MethodParameter mp : methodResource.getMethodParameters()) {
Annotation a = mp.getAnnotation();
if (a != null) {
ParameterResolver<?> pr = ParameterResolverFactory.createParameterResolver(a);
try {
p[i++] = pr.resolve(mp, context);
} catch (Exception e) {
if (LOG.isDebugEnabled())
e.printStackTrace();
Class<?> ac = a.annotationType();
if (ac == MatrixParam.class || ac == QueryParam.class || ac == PathParam.class)
throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).build());
}
} else {
InputStream entityStream = context.getContainerRequest().getEntityStream();
if (entityStream == null)
p[i++] = null;
else {
MediaType contentType = context.getContainerRequest().getMediaType();
MultivaluedMap<String, String> headers = context.getContainerRequest()
.getRequestHeaders();
MessageBodyReader entityReader = context.getProviders()
.getMessageBodyReader(mp.getParameterClass(),
mp.getGenericType(),
mp.getAnnotations(),
contentType);
if (entityReader == null) {
if (LOG.isDebugEnabled())
LOG.warn("Unsupported media type. ");
throw new WebApplicationException(Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE)
.build());
}
try {
p[i++] = entityReader.readFrom(mp.getParameterClass(),
mp.getGenericType(),
mp.getAnnotations(),
contentType,
headers,
entityStream);
} catch (IOException e) {
if (LOG.isDebugEnabled())
e.printStackTrace();
throw new InternalException(e);
}
}
}
}
try {
return methodResource.getMethod().invoke(resource, p);
} catch (IllegalArgumentException argExc) {
// should not be thrown
throw new InternalException(argExc);
} catch (IllegalAccessException accessExc) {
// should not be thrown
throw new InternalException(accessExc);
} catch (InvocationTargetException invExc) {
if (LOG.isDebugEnabled())
invExc.printStackTrace();
// get cause of exception that method produces
Throwable cause = invExc.getCause();
// if WebApplicationException than it may contain response
if (WebApplicationException.class == cause.getClass())
throw (WebApplicationException) cause;
throw new InternalException(cause);
}
}
}