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 */ 018package org.apache.hadoop.hdfs.web.resources; 019 020import java.io.UnsupportedEncodingException; 021import java.net.URLEncoder; 022import java.util.Arrays; 023import java.util.Comparator; 024 025 026/** Base class of parameters. */ 027public abstract class Param<T, D extends Param.Domain<T>> { 028 static final String NULL = "null"; 029 030 static final Comparator<Param<?,?>> NAME_CMP = new Comparator<Param<?,?>>() { 031 @Override 032 public int compare(Param<?, ?> left, Param<?, ?> right) { 033 return left.getName().compareTo(right.getName()); 034 } 035 }; 036 037 /** Convert the parameters to a sorted String. 038 * 039 * @param separator URI parameter separator character 040 * @param parameters parameters to encode into a string 041 * @return the encoded URI string 042 */ 043 public static String toSortedString(final String separator, 044 final Param<?, ?>... parameters) { 045 Arrays.sort(parameters, NAME_CMP); 046 final StringBuilder b = new StringBuilder(); 047 try { 048 for(Param<?, ?> p : parameters) { 049 if (p.getValue() != null) { 050 b.append(separator) 051 .append(URLEncoder.encode(p.getName(), "UTF-8")) 052 .append("=") 053 .append(URLEncoder.encode(p.getValueString(), "UTF-8")); 054 } 055 } 056 } catch (UnsupportedEncodingException e) { 057 // Sane systems know about UTF-8, so this should never happen. 058 throw new RuntimeException(e); 059 } 060 return b.toString(); 061 } 062 063 /** The domain of the parameter. */ 064 final D domain; 065 /** The actual parameter value. */ 066 final T value; 067 068 Param(final D domain, final T value) { 069 this.domain = domain; 070 this.value = value; 071 } 072 073 /** @return the parameter value. */ 074 public final T getValue() { 075 return value; 076 } 077 078 /** @return the parameter value as a string */ 079 public abstract String getValueString(); 080 081 /** @return the parameter name. */ 082 public abstract String getName(); 083 084 @Override 085 public String toString() { 086 return getName() + "=" + value; 087 } 088 089 /** Base class of parameter domains. */ 090 static abstract class Domain<T> { 091 /** Parameter name. */ 092 final String paramName; 093 094 Domain(final String paramName) { 095 this.paramName = paramName; 096 } 097 098 /** @return the parameter name. */ 099 public final String getParamName() { 100 return paramName; 101 } 102 103 /** @return a string description of the domain of the parameter. */ 104 public abstract String getDomain(); 105 106 /** @return the parameter value represented by the string. */ 107 abstract T parse(String str); 108 109 /** Parse the given string. 110 * @return the parameter value represented by the string. 111 */ 112 public final T parse(final String varName, final String str) { 113 try { 114 return str != null && str.trim().length() > 0 ? parse(str) : null; 115 } catch(Exception e) { 116 throw new IllegalArgumentException("Failed to parse \"" + str 117 + "\" for the parameter " + varName 118 + ". The value must be in the domain " + getDomain(), e); 119 } 120 } 121 } 122}