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 019 package org.apache.hadoop.lib.wsrs; 020 021 import com.google.common.collect.Lists; 022 import com.sun.jersey.api.core.HttpContext; 023 import com.sun.jersey.core.spi.component.ComponentContext; 024 import com.sun.jersey.core.spi.component.ComponentScope; 025 import com.sun.jersey.server.impl.inject.AbstractHttpContextInjectable; 026 import com.sun.jersey.spi.inject.Injectable; 027 import com.sun.jersey.spi.inject.InjectableProvider; 028 import org.apache.hadoop.classification.InterfaceAudience; 029 030 import javax.ws.rs.core.Context; 031 import javax.ws.rs.core.MultivaluedMap; 032 import java.lang.reflect.Type; 033 import java.text.MessageFormat; 034 import java.util.HashMap; 035 import java.util.List; 036 import java.util.Map; 037 038 /** 039 * Jersey provider that parses the request parameters based on the 040 * given parameter definition. 041 */ 042 @InterfaceAudience.Private 043 public class ParametersProvider 044 extends AbstractHttpContextInjectable<Parameters> 045 implements InjectableProvider<Context, Type> { 046 047 private String driverParam; 048 private Class<? extends Enum> enumClass; 049 private Map<Enum, Class<Param<?>>[]> paramsDef; 050 051 public ParametersProvider(String driverParam, Class<? extends Enum> enumClass, 052 Map<Enum, Class<Param<?>>[]> paramsDef) { 053 this.driverParam = driverParam; 054 this.enumClass = enumClass; 055 this.paramsDef = paramsDef; 056 } 057 058 @Override 059 @SuppressWarnings("unchecked") 060 public Parameters getValue(HttpContext httpContext) { 061 Map<String, List<Param<?>>> map = new HashMap<String, List<Param<?>>>(); 062 Map<String, List<String>> queryString = 063 httpContext.getRequest().getQueryParameters(); 064 String str = ((MultivaluedMap<String, String>) queryString). 065 getFirst(driverParam); 066 if (str == null) { 067 throw new IllegalArgumentException( 068 MessageFormat.format("Missing Operation parameter [{0}]", 069 driverParam)); 070 } 071 Enum op; 072 try { 073 op = Enum.valueOf(enumClass, str.toUpperCase()); 074 } catch (IllegalArgumentException ex) { 075 throw new IllegalArgumentException( 076 MessageFormat.format("Invalid Operation [{0}]", str)); 077 } 078 if (!paramsDef.containsKey(op)) { 079 throw new IllegalArgumentException( 080 MessageFormat.format("Unsupported Operation [{0}]", op)); 081 } 082 for (Class<Param<?>> paramClass : paramsDef.get(op)) { 083 Param<?> param = newParam(paramClass); 084 List<Param<?>> paramList = Lists.newArrayList(); 085 List<String> ps = queryString.get(param.getName()); 086 if (ps != null) { 087 for (String p : ps) { 088 try { 089 param.parseParam(p); 090 } 091 catch (Exception ex) { 092 throw new IllegalArgumentException(ex.toString(), ex); 093 } 094 paramList.add(param); 095 param = newParam(paramClass); 096 } 097 } else { 098 paramList.add(param); 099 } 100 101 map.put(param.getName(), paramList); 102 } 103 return new Parameters(map); 104 } 105 106 private Param<?> newParam(Class<Param<?>> paramClass) { 107 try { 108 return paramClass.newInstance(); 109 } catch (Exception ex) { 110 throw new UnsupportedOperationException( 111 MessageFormat.format( 112 "Param class [{0}] does not have default constructor", 113 paramClass.getName())); 114 } 115 } 116 117 @Override 118 public ComponentScope getScope() { 119 return ComponentScope.PerRequest; 120 } 121 122 @Override 123 public Injectable getInjectable(ComponentContext componentContext, Context context, Type type) { 124 return (type.equals(Parameters.class)) ? this : null; 125 } 126 }