001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.hadoop.lib.wsrs; 020 021import com.google.common.collect.Lists; 022import com.sun.jersey.api.core.HttpContext; 023import com.sun.jersey.core.spi.component.ComponentContext; 024import com.sun.jersey.core.spi.component.ComponentScope; 025import com.sun.jersey.server.impl.inject.AbstractHttpContextInjectable; 026import com.sun.jersey.spi.inject.Injectable; 027import com.sun.jersey.spi.inject.InjectableProvider; 028import org.apache.hadoop.classification.InterfaceAudience; 029import org.apache.hadoop.util.StringUtils; 030 031import javax.ws.rs.core.Context; 032import javax.ws.rs.core.MultivaluedMap; 033import java.lang.reflect.Type; 034import java.text.MessageFormat; 035import java.util.HashMap; 036import java.util.List; 037import java.util.Map; 038 039/** 040 * Jersey provider that parses the request parameters based on the 041 * given parameter definition. 042 */ 043@InterfaceAudience.Private 044public class ParametersProvider 045 extends AbstractHttpContextInjectable<Parameters> 046 implements InjectableProvider<Context, Type> { 047 048 private String driverParam; 049 private Class<? extends Enum> enumClass; 050 private Map<Enum, Class<Param<?>>[]> paramsDef; 051 052 public ParametersProvider(String driverParam, Class<? extends Enum> enumClass, 053 Map<Enum, Class<Param<?>>[]> paramsDef) { 054 this.driverParam = driverParam; 055 this.enumClass = enumClass; 056 this.paramsDef = paramsDef; 057 } 058 059 @Override 060 @SuppressWarnings("unchecked") 061 public Parameters getValue(HttpContext httpContext) { 062 Map<String, List<Param<?>>> map = new HashMap<String, List<Param<?>>>(); 063 Map<String, List<String>> queryString = 064 httpContext.getRequest().getQueryParameters(); 065 String str = ((MultivaluedMap<String, String>) queryString). 066 getFirst(driverParam); 067 if (str == null) { 068 throw new IllegalArgumentException( 069 MessageFormat.format("Missing Operation parameter [{0}]", 070 driverParam)); 071 } 072 Enum op; 073 try { 074 op = Enum.valueOf(enumClass, StringUtils.toUpperCase(str)); 075 } catch (IllegalArgumentException ex) { 076 throw new IllegalArgumentException( 077 MessageFormat.format("Invalid Operation [{0}]", str)); 078 } 079 if (!paramsDef.containsKey(op)) { 080 throw new IllegalArgumentException( 081 MessageFormat.format("Unsupported Operation [{0}]", op)); 082 } 083 for (Class<Param<?>> paramClass : paramsDef.get(op)) { 084 Param<?> param = newParam(paramClass); 085 List<Param<?>> paramList = Lists.newArrayList(); 086 List<String> ps = queryString.get(param.getName()); 087 if (ps != null) { 088 for (String p : ps) { 089 try { 090 param.parseParam(p); 091 } 092 catch (Exception ex) { 093 throw new IllegalArgumentException(ex.toString(), ex); 094 } 095 paramList.add(param); 096 param = newParam(paramClass); 097 } 098 } else { 099 paramList.add(param); 100 } 101 102 map.put(param.getName(), paramList); 103 } 104 return new Parameters(map); 105 } 106 107 private Param<?> newParam(Class<Param<?>> paramClass) { 108 try { 109 return paramClass.newInstance(); 110 } catch (Exception ex) { 111 throw new UnsupportedOperationException( 112 MessageFormat.format( 113 "Param class [{0}] does not have default constructor", 114 paramClass.getName())); 115 } 116 } 117 118 @Override 119 public ComponentScope getScope() { 120 return ComponentScope.PerRequest; 121 } 122 123 @Override 124 public Injectable getInjectable(ComponentContext componentContext, Context context, Type type) { 125 return (type.equals(Parameters.class)) ? this : null; 126 } 127}