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    package org.apache.hadoop.hdfs.web.resources;
019    
020    import java.io.UnsupportedEncodingException;
021    import java.net.URLEncoder;
022    import java.util.Arrays;
023    import java.util.Comparator;
024    
025    
026    /** Base class of parameters. */
027    public 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).append(
051                  URLEncoder.encode(p.getName(), "UTF-8")
052                  + "="
053                  + 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    }