/** * Copyright 2014 Opower, Inc. * 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 com.opower.rest.client.generator.extractors; import com.google.common.base.Throwables; import com.opower.rest.client.generator.core.BaseClientResponse; import com.opower.rest.client.generator.core.ClientResponse; import com.opower.rest.client.generator.core.ClientResponseFailure; import com.opower.rest.client.generator.util.Types; import javax.ws.rs.core.Response; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import static com.google.common.base.Preconditions.checkNotNull; /** * @author Solomon.Duskis */ @SuppressWarnings("unchecked") public class DefaultEntityExtractorFactory implements EntityExtractorFactory { public static final EntityExtractor clientResponseExtractor = new EntityExtractor<ClientResponse>() { public ClientResponse extractEntity(ClientRequestContext context, Object... args) { context.getClientResponse().setReturnType(Response.class); return context.getClientResponse(); } }; public static EntityExtractor<Response.Status> createStatusExtractor(final boolean release) { return new EntityExtractor<Response.Status>() { public Response.Status extractEntity(ClientRequestContext context, Object... args) { if (release) context.getClientResponse().releaseConnection(); return context.getClientResponse().getResponseStatus(); } }; } public static final EntityExtractor createVoidExtractor(final Method method, final boolean release) { checkNotNull(method); return new EntityExtractor() { public Object extractEntity(ClientRequestContext context, Object... args) { handleResponseErrors(method, context); if (release) { context.getClientResponse().releaseConnection(); } return null; } }; } public EntityExtractor createExtractor(final Method method) { checkNotNull(method); final Class returnType = method.getReturnType(); if (isVoidReturnType(returnType)) { return createVoidExtractor(method, true); } if (returnType.equals(Response.Status.class)) { return createStatusExtractor(true); } if (Response.class.isAssignableFrom(returnType) || returnType.getCanonicalName().equals("javax.ws.rs.core.Response")) { return createResponseTypeEntityExtractor(method); } // We are not a ClientResponse type so we need to unmarshall and narrow it // to right type. If we are unable to unmarshall, or encounter any kind of // Exception, give the ClientErrorHandlers a chance to handle the // ClientResponse manually. return new BodyEntityExtractor(method); } protected EntityExtractor createResponseTypeEntityExtractor(final Method method) { final Type methodGenericReturnType = method.getGenericReturnType(); if (methodGenericReturnType instanceof ParameterizedType) { final ParameterizedType zType = (ParameterizedType) methodGenericReturnType; final Type genericReturnType = zType.getActualTypeArguments()[0]; final Class<?> responseReturnType = Types.getRawType(genericReturnType); return new EntityExtractor() { public Object extractEntity(ClientRequestContext context, Object... args) { handleResponseErrors(method, context); context.getClientResponse().setReturnType(responseReturnType); context.getClientResponse().setGenericReturnType(genericReturnType); return context.getClientResponse(); } }; } else { return clientResponseExtractor; } } protected static void handleResponseErrors(Method method, ClientRequestContext context) { checkNotNull(method); final BaseClientResponse response = context.getClientResponse(); try { response.checkFailureStatus(); } catch (ClientResponseFailure ce) { // If ClientResponseFailure do a copy of the response and then release the connection, // we need to use the copy here and not the original response context.getErrorHandler().clientErrorHandling(method, (BaseClientResponse) ce.getResponse(), ce); } catch (RuntimeException e) { context.getErrorHandler().clientErrorHandling(method, response, e); } } public static final boolean isVoidReturnType(Class<?> returnType) { return returnType == null || void.class.equals(returnType) || Void.class.equals(returnType); } }