View Javadoc

1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.handler.codec.http;
17  
18  import java.io.UnsupportedEncodingException;
19  import java.net.URI;
20  import java.net.URISyntaxException;
21  import java.net.URLEncoder;
22  import java.nio.charset.Charset;
23  import java.nio.charset.UnsupportedCharsetException;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  /**
28   * Creates an URL-encoded URI from a path string and key-value parameter pairs.
29   * This encoder is for one time use only.  Create a new instance for each URI.
30   *
31   * <pre>
32   * {@link QueryStringEncoder} encoder = new {@link QueryStringEncoder}("/hello");
33   * encoder.addParam("recipient", "world");
34   * assert encoder.toString().equals("/hello?recipient=world");
35   * </pre>
36   * @see QueryStringDecoder
37   *
38   * @apiviz.stereotype utility
39   * @apiviz.has        org.jboss.netty.handler.codec.http.HttpRequest oneway - - encodes
40   */
41  public class QueryStringEncoder {
42  
43      private final Charset charset;
44      private final String uri;
45      private final List<Param> params = new ArrayList<Param>();
46  
47      /**
48       * Creates a new encoder that encodes a URI that starts with the specified
49       * path string.  The encoder will encode the URI in UTF-8.
50       */
51      public QueryStringEncoder(String uri) {
52          this(uri, HttpConstants.DEFAULT_CHARSET);
53      }
54  
55      /**
56       * Creates a new encoder that encodes a URI that starts with the specified
57       * path string in the specified charset.
58       */
59      public QueryStringEncoder(String uri, Charset charset) {
60          if (uri == null) {
61              throw new NullPointerException("uri");
62          }
63          if (charset == null) {
64              throw new NullPointerException("charset");
65          }
66  
67          this.uri = uri;
68          this.charset = charset;
69      }
70  
71      /**
72       * @deprecated Use {@link #QueryStringEncoder(String, Charset)} instead.
73       */
74      @Deprecated
75      public QueryStringEncoder(String uri, String charset) {
76          this(uri, Charset.forName(charset));
77      }
78  
79      /**
80       * Adds a parameter with the specified name and value to this encoder.
81       */
82      public void addParam(String name, String value) {
83          if (name == null) {
84              throw new NullPointerException("name");
85          }
86          if (value == null) {
87              throw new NullPointerException("value");
88          }
89          params.add(new Param(name, value));
90      }
91  
92      /**
93       * Returns the URL-encoded URI object which was created from the path string
94       * specified in the constructor and the parameters added by
95       * {@link #addParam(String, String)} method.
96       */
97      public URI toUri() throws URISyntaxException {
98          return new URI(toString());
99      }
100 
101     /**
102      * Returns the URL-encoded URI which was created from the path string
103      * specified in the constructor and the parameters added by
104      * {@link #addParam(String, String)} method.
105      */
106     @Override
107     public String toString() {
108         if (params.isEmpty()) {
109             return uri;
110         } else {
111             StringBuilder sb = new StringBuilder(uri).append('?');
112             for (int i = 0; i < params.size(); i++) {
113                 Param param = params.get(i);
114                 sb.append(encodeComponent(param.name, charset));
115                 sb.append('=');
116                 sb.append(encodeComponent(param.value, charset));
117                 if (i != params.size() - 1) {
118                     sb.append('&');
119                 }
120             }
121             return sb.toString();
122         }
123     }
124 
125     private static String encodeComponent(String s, Charset charset) {
126         try {
127             return URLEncoder.encode(s, charset.name()).replaceAll("\\+", "%20");
128         } catch (UnsupportedEncodingException e) {
129             throw new UnsupportedCharsetException(charset.name());
130         }
131     }
132 
133     private static final class Param {
134 
135         final String name;
136         final String value;
137 
138         Param(String name, String value) {
139             this.value = value;
140             this.name = name;
141         }
142     }
143 }