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}