001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest;
014
015import static org.apache.juneau.internal.StringUtils.*;
016
017import java.lang.reflect.*;
018import java.util.*;
019
020import org.apache.juneau.*;
021import org.apache.juneau.httppart.*;
022import org.apache.juneau.parser.*;
023
024/**
025 * @deprecated Unused.
026 */
027@Deprecated
028@SuppressWarnings("unchecked")
029public class RequestPathMatch extends TreeMap<String,String> {
030   private static final long serialVersionUID = 1L;
031
032   private HttpPartParser parser;
033   private BeanSession beanSession;
034   private String remainder, pattern;
035
036   RequestPathMatch() {
037      super(String.CASE_INSENSITIVE_ORDER);
038   }
039
040   RequestPathMatch parser(HttpPartParser parser) {
041      this.parser = parser;
042      return this;
043   }
044
045   RequestPathMatch beanSession(BeanSession beanSession) {
046      this.beanSession = beanSession;
047      return this;
048   }
049
050   RequestPathMatch remainder(String remainder) {
051      this.remainder = remainder;
052      return this;
053   }
054
055   RequestPathMatch pattern(String pattern) {
056      this.pattern = pattern;
057      return this;
058   }
059
060   /**
061    * Sets a request query parameter value.
062    *
063    * @param name The parameter name.
064    * @param value The parameter value.
065    */
066   public void put(String name, Object value) {
067      super.put(name, value.toString());
068   }
069
070   /**
071    * Returns the specified path parameter converted to a String.
072    *
073    * @param name The path variable name.
074    * @return The parameter value.
075    * @throws ParseException
076    */
077   public String getString(String name) throws ParseException {
078      return parse(parser, name, beanSession.string());
079   }
080
081   /**
082    * Returns the specified path parameter converted to an integer.
083    *
084    * @param name The path variable name.
085    * @return The parameter value.
086    * @throws ParseException
087    */
088   public int getInt(String name) throws ParseException {
089      return parse(parser, name, beanSession.getClassMeta(int.class));
090   }
091
092   /**
093    * Returns the specified path parameter converted to a boolean.
094    *
095    * @param name The path variable name.
096    * @return The parameter value.
097    * @throws ParseException
098    */
099   public boolean getBoolean(String name) throws ParseException {
100      return parse(parser, name, beanSession.getClassMeta(boolean.class));
101   }
102
103   /**
104    * Returns the specified path parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
105    *
106    * <h5 class='section'>Examples:</h5>
107    * <p class='bcode'>
108    *    <jc>// Parse into an integer.</jc>
109    *    <jk>int</jk> myparam = path.get(<js>"myparam"</js>, <jk>int</jk>.<jk>class</jk>);
110    *
111    *    <jc>// Parse into an int array.</jc>
112    *    <jk>int</jk>[] myparam = path.get(<js>"myparam"</js>, <jk>int</jk>[].<jk>class</jk>);
113
114    *    <jc>// Parse into a bean.</jc>
115    *    MyBean myparam = path.get(<js>"myparam"</js>, MyBean.<jk>class</jk>);
116    *
117    *    <jc>// Parse into a linked-list of objects.</jc>
118    *    List myparam = path.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>);
119    *
120    *    <jc>// Parse into a map of object keys/values.</jc>
121    *    Map myparam = path.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>);
122    * </p>
123    *
124    * <h5 class='section'>See Also:</h5>
125    * <ul>
126    *    <li class='jf'>{@link RestContext#REST_partParser}
127    * </ul>
128    *
129    * @param name The attribute name.
130    * @param type The class type to convert the attribute value to.
131    * @param <T> The class type to convert the attribute value to.
132    * @return The attribute value converted to the specified class type.
133    * @throws ParseException
134    */
135   public <T> T get(String name, Class<T> type) throws ParseException {
136      return get(parser, name, type);
137   }
138
139   /**
140    * Same as {@link #get(String, Class)} but allows you to override the part parser.
141    *
142    * @param parser
143    *    The parser to use for parsing the string value.
144    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
145    * @param name The attribute name.
146    * @param type The class type to convert the attribute value to.
147    * @param <T> The class type to convert the attribute value to.
148    * @return The attribute value converted to the specified class type.
149    * @throws ParseException
150    */
151   public <T> T get(HttpPartParser parser, String name, Class<T> type) throws ParseException {
152      return parse(parser, name, beanSession.getClassMeta(type));
153   }
154
155   /**
156    * Returns the specified query parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
157    *
158    * <p>
159    * Similar to {@link #get(String,Class)} but allows for complex collections of POJOs to be created.
160    *
161    * <p>
162    * Use this method if you want to parse into a parameterized <code>Map</code>/<code>Collection</code> object.
163    *
164    * <h5 class='section'>Examples:</h5>
165    * <p class='bcode'>
166    *    <jc>// Parse into a linked-list of strings.</jc>
167    *    List&lt;String&gt; myparam = req.getPathParameter(<js>"myparam"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
168    *
169    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
170    *    List&lt;List&lt;String&gt;&gt; myparam = req.getPathParameter(<js>"myparam"</js>, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
171    *
172    *    <jc>// Parse into a map of string keys/values.</jc>
173    *    Map&lt;String,String&gt; myparam = req.getPathParameter(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
174    *
175    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
176    *    Map&lt;String,List&lt;MyBean&gt;&gt; myparam = req.getPathParameter(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
177    * </p>
178    *
179    * <h5 class='section'>Notes:</h5>
180    * <ul class='spaced-list'>
181    *    <li>
182    *       <code>Collections</code> must be followed by zero or one parameter representing the value type.
183    *    <li>
184    *       <code>Maps</code> must be followed by zero or two parameters representing the key and value types.
185    * </ul>
186    *
187    * <h5 class='section'>See Also:</h5>
188    * <ul>
189    *    <li class='jf'>{@link RestContext#REST_partParser}
190    * </ul>
191    *
192    * @param name The attribute name.
193    * @param type
194    *    The type of object to create.
195    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
196    * @param args
197    *    The type arguments of the class if it's a collection or map.
198    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
199    *    <br>Ignored if the main type is not a map or collection.
200    * @param <T> The class type to convert the attribute value to.
201    * @return The attribute value converted to the specified class type.
202    * @throws ParseException
203    */
204   public <T> T get(String name, Type type, Type...args) throws ParseException {
205      return get(parser, name, type, args);
206   }
207
208   /**
209    * Same as {@link #get(String, Type, Type...)} but allows you to override the part parser.
210    *
211    * @param parser
212    *    The parser to use for parsing the string value.
213    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
214    * @param name The attribute name.
215    * @param type
216    *    The type of object to create.
217    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
218    * @param args
219    *    The type arguments of the class if it's a collection or map.
220    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
221    *    <br>Ignored if the main type is not a map or collection.
222    * @param <T> The class type to convert the attribute value to.
223    * @return The attribute value converted to the specified class type.
224    * @throws ParseException
225    */
226   public <T> T get(HttpPartParser parser, String name, Type type, Type...args) throws ParseException {
227      return (T)parse(parser, name, beanSession.getClassMeta(type, args));
228   }
229
230
231   /* Workhorse method */
232   <T> T parse(HttpPartParser parser, String name, ClassMeta<T> cm) throws ParseException {
233      if (parser == null)
234         parser = this.parser;
235      Object attr = get(name);
236      T t = null;
237      if (attr != null)
238         t = parser.parse(HttpPartType.PATH, attr.toString(), cm);
239      if (t == null && cm.isPrimitive())
240         return cm.getPrimitiveDefault();
241      return t;
242   }
243
244   /**
245    * Returns the decoded remainder of the URL following any path pattern matches.
246    *
247    * <p>
248    * The behavior of path remainder is shown below given the path pattern "/foo/*":
249    * <table class='styled'>
250    *    <tr>
251    *       <th>URL</th>
252    *       <th>Path Remainder</th>
253    *    </tr>
254    *    <tr>
255    *       <td><code>/foo</code></td>
256    *       <td><jk>null</jk></td>
257    *    </tr>
258    *    <tr>
259    *       <td><code>/foo/</code></td>
260    *       <td><js>""</js></td>
261    *    </tr>
262    *    <tr>
263    *       <td><code>/foo//</code></td>
264    *       <td><js>"/"</js></td>
265    *    </tr>
266    *    <tr>
267    *       <td><code>/foo///</code></td>
268    *       <td><js>"//"</js></td>
269    *    </tr>
270    *    <tr>
271    *       <td><code>/foo/a/b</code></td>
272    *       <td><js>"a/b"</js></td>
273    *    </tr>
274    *    <tr>
275    *       <td><code>/foo//a/b/</code></td>
276    *       <td><js>"/a/b/"</js></td>
277    *    </tr>
278    *    <tr>
279    *       <td><code>/foo/a%2Fb</code></td>
280    *       <td><js>"a/b"</js></td>
281    *    </tr>
282    * </table>
283    *
284    * <h5 class='section'>Example:</h5>
285    * <p class='bcode'>
286    *    <jc>// REST method</jc>
287    *    <ja>@RestMethod</ja>(name=<jsf>GET</jsf>,path=<js>"/foo/{bar}/*"</js>)
288    *    <jk>public</jk> String doGetById(RequestPathMatch path, <jk>int</jk> bar) {
289    *       <jk>return</jk> path.getRemainder();
290    *    }
291    * </p>
292    *
293    * @return The path remainder string.
294    */
295   public String getRemainder() {
296      return urlDecode(remainder);
297   }
298
299   /**
300    * Same as {@link #getRemainder()} but doesn't decode characters.
301    *
302    * @return The un-decoded path remainder.
303    */
304   public String getRemainderUndecoded() {
305      return remainder;
306   }
307
308   /**
309    * Returns the path pattern that matched this request.
310    *
311    * @return The path pattern that matched this request.
312    */
313   public String getPattern() {
314      return pattern;
315   }
316}