Java tutorial
/** * JBoss, Home of Professional Open Source * Copyright Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * 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.jboss.aerogear.controller.util; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.activation.MimeType; import javax.activation.MimeTypeParseException; import javax.servlet.http.Cookie; import org.jboss.aerogear.controller.log.AeroGearLogger; import org.jboss.aerogear.controller.log.ExceptionBundle; import org.jboss.aerogear.controller.router.Consumer; import org.jboss.aerogear.controller.router.RouteContext; import org.jboss.aerogear.controller.router.parameter.ConstantParameter; import org.jboss.aerogear.controller.router.parameter.Parameter; import org.jboss.aerogear.controller.router.parameter.ReplacementParameter; import org.jboss.aerogear.controller.router.parameter.RequestParameter; import org.jboss.aerogear.controller.router.rest.pagination.PaginationInfo; import br.com.caelum.iogi.Iogi; import br.com.caelum.iogi.reflection.Target; import br.com.caelum.iogi.util.DefaultLocaleProvider; import br.com.caelum.iogi.util.NullDependencyProvider; import com.google.common.base.Optional; public class ParameterExtractor { private static final Iogi IOGI = new Iogi(new NullDependencyProvider(), new DefaultLocaleProvider()); /** * Extracts the arguments from the current request for the target route. * * @param routeContext the {@link org.jboss.aerogear.controller.router.RouteContext}. * @param consumers the {@link Consumer}s that will be used to try to unmarshall the request body. * @return {@code Map<String, Object} containing parameter name -> value mapping. */ public static Map<String, Object> extractArguments(final RouteContext routeContext, final Map<String, Consumer> consumers) throws Exception { final Map<String, Object> argsMap = new LinkedHashMap<String, Object>(); final List<Parameter<?>> parameters = routeContext.getRoute().getParameters(); final int size = parameters.size(); for (int i = 0; i < size; i++) { final Parameter<?> parameter = parameters.get(i); switch (parameter.getParameterType()) { case ENTITY: if (PaginationInfo.class.isAssignableFrom(parameter.getType())) { break; } if (!addIfPresent(extractIogiParam(routeContext), "entityParam", argsMap)) { argsMap.put("entityParam", extractBody(routeContext, parameter, getConsumer(routeContext, consumers, parameter))); } break; case REQUEST: final RequestParameter<?> rp = (RequestParameter<?>) parameter; extractRequestParam(rp.getName(), rp.getType(), rp.getDefaultValue(), argsMap, routeContext); break; case CONSTANT: final ConstantParameter<?> cp = (ConstantParameter<?>) parameter; argsMap.put("constantParam-" + i, cp.getValue()); break; case REPLACEMENT: final ReplacementParameter<?> replacementParam = (ReplacementParameter<?>) parameter; final Map<String, Object> paramsMap = extractRequestParams(replacementParam, routeContext); argsMap.put("replacementParam-" + i, RequestUtils.injectParamValues(replacementParam.getString(), paramsMap)); break; } } return argsMap; } private static Map<String, Object> extractRequestParam(final String paramName, final Class<?> type, final Optional<?> defaultValue, final Map<String, Object> map, final RouteContext routeContext) throws Exception { if (addIfPresent(extractParam(routeContext, paramName, type), paramName, map)) { return map; } if (addIfPresent(extractHeaderParam(routeContext, paramName), paramName, map)) { return map; } if (addIfPresent(extractCookieParam(routeContext, paramName, type), paramName, map)) { return map; } if (addIfPresent(extractDefaultParam(type, defaultValue), paramName, map)) { return map; } if (addIfPresent(extractPathParam(routeContext, paramName, type), paramName, map)) { return map; } else { throw ExceptionBundle.MESSAGES.missingParameterInRequest(paramName); } } private static Map<String, Object> extractRequestParams(final ReplacementParameter<?> replacementParam, final RouteContext routeContext) throws Exception { final Map<String, Object> map = new HashMap<String, Object>(); for (String paramName : replacementParam.getParamNames()) { extractRequestParam(paramName, String.class, Optional.absent(), map, routeContext); } return map; } private static Optional<?> extractDefaultParam(final Class<?> type, final Optional<?> defaultValue) throws Exception { if (defaultValue.isPresent()) { return Optional.of(createInstance(type, defaultValue.get().toString())); } return Optional.absent(); } private static Object extractBody(final RouteContext routeContext, final Parameter<?> parameter, final Consumer consumer) { return consumer.unmarshall(routeContext.getRequest(), parameter.getType()); } private static Consumer getConsumer(final RouteContext routeContext, final Map<String, Consumer> consumers, final Parameter<?> parameter) { final Set<String> mediaTypes = routeContext.getRoute().consumes(); final Optional<String> contentType = extractContentType(routeContext); if (contentType.isPresent()) { final Consumer consumer = consumers.get(contentType.get()); if (consumer != null) { return consumer; } } else { for (String mediaType : mediaTypes) { final Consumer consumer = consumers.get(mediaType); if (consumer != null) { return consumer; } } } throw ExceptionBundle.MESSAGES.noConsumerForMediaType(parameter, consumers.values(), mediaTypes); } private static Optional<String> extractContentType(final RouteContext routeContext) { final String contentType = routeContext.getRequest().getContentType(); if (contentType != null) { try { MimeType mimeType = new MimeType(contentType); return Optional.of(mimeType.getBaseType()); } catch (MimeTypeParseException e) { throw new RuntimeException("Error parsing content-type " + contentType, e); } } return Optional.absent(); } public static Optional<?> extractPathParam(final RouteContext routeContext, final RequestParameter<?> param) throws Exception { return extractPathParam(routeContext, param.getName(), param.getType()); } /** * Extracts a path parameter from the passed in request path. * * @param routeContext the {@link org.jboss.aerogear.controller.router.RouteContext} to extract a path parameter from. * @param paramName the name of the parameter to be extracted. * @param type the parameter type. * @return {@code Optional<String>} containing the extracted path param if present in the request path. */ public static Optional<?> extractPathParam(final RouteContext routeContext, final String paramName, final Class<?> type) throws Exception { final String requestPath = routeContext.getRequestPath(); final Map<String, String> pathParams = RequestUtils.mapPathParams(requestPath, routeContext.getRoute().getPath()); if (pathParams.containsKey(paramName)) { final String value = pathParams.get(paramName); if (value != null) { return Optional.of(createInstance(type, pathParams.get(paramName))); } } return Optional.absent(); } /** * Returns an instance of the type used in the parameter names using Iogi. </p> For example, having form parameters named * 'car.color', 'car.brand', this method would try to use those values to instantiate a new Car instance. * * @return {@link com.google.common.base.Optional} may contain the instantiated instance, else isPresent will return false. */ public static Optional<?> extractIogiParam(final RouteContext routeContext) { final LinkedList<br.com.caelum.iogi.parameters.Parameter> parameters = new LinkedList<br.com.caelum.iogi.parameters.Parameter>(); for (Map.Entry<String, String[]> entry : routeContext.getRequest().getParameterMap().entrySet()) { final String[] value = entry.getValue(); if (value.length == 1) { parameters.add(new br.com.caelum.iogi.parameters.Parameter(entry.getKey(), value[0])); } else { AeroGearLogger.LOGGER.multivaluedParamsUnsupported(); } } if (!parameters.isEmpty()) { final Class<?>[] parameterTypes = routeContext.getRoute().getTargetMethod().getParameterTypes(); final Class<?> parameterType = parameterTypes[0]; final Target<?> target = Target.create(parameterType, StringUtils.downCaseFirst(parameterType.getSimpleName())); return Optional.fromNullable(IOGI.instantiate(target, parameters.toArray(new br.com.caelum.iogi.parameters.Parameter[parameters.size()]))); } return Optional.absent(); } private static boolean addIfPresent(final Optional<?> op, final String paramName, final Map<String, Object> args) { if (op.isPresent()) { args.put(paramName, op.get()); return true; } return false; } private static Optional<?> extractHeaderParam(final RouteContext routeContext, final String paramName) { return Optional.fromNullable(routeContext.getRequest().getHeader(paramName)); } private static Optional<?> extractCookieParam(final RouteContext routeContext, final String paramName, final Class<?> type) throws Exception { final Cookie[] cookies = routeContext.getRequest().getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals(paramName)) { return Optional.fromNullable(createInstance(type, cookie.getValue())); } } } return Optional.absent(); } private static Optional<?> extractParam(final RouteContext routeContext, final String name, final Class<?> type) throws Exception { final String[] values = routeContext.getRequest().getParameterMap().get(name); if (values != null) { if (values.length == 1) { return Optional.of(createInstance(type, values[0])); } else { throw ExceptionBundle.MESSAGES.multivaluedParamsUnsupported(name); } } return Optional.absent(); } private static Object createInstance(Class<?> type, String arg) throws Exception { final Constructor<?> constructor = type.getDeclaredConstructor(String.class); return constructor.newInstance(arg); } }