001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.util; 018 019import java.io.UnsupportedEncodingException; 020import java.net.URI; 021import java.net.URISyntaxException; 022import java.net.URLDecoder; 023import java.net.URLEncoder; 024import java.util.ArrayList; 025import java.util.Collections; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029 030/** 031 * Utility class that provides methods for parsing URI's 032 */ 033public class URISupport { 034 035 public static class CompositeData { 036 private String host; 037 private String scheme; 038 private String path; 039 private URI components[]; 040 private Map<String, String> parameters; 041 private String fragment; 042 043 public URI[] getComponents() { 044 return components; 045 } 046 047 public String getFragment() { 048 return fragment; 049 } 050 051 public Map<String, String> getParameters() { 052 return parameters; 053 } 054 055 public String getScheme() { 056 return scheme; 057 } 058 059 public String getPath() { 060 return path; 061 } 062 063 public String getHost() { 064 return host; 065 } 066 067 public URI toURI() throws URISyntaxException { 068 StringBuffer sb = new StringBuffer(); 069 if (scheme != null) { 070 sb.append(scheme); 071 sb.append(':'); 072 } 073 074 if (host != null && host.length() != 0) { 075 sb.append(host); 076 } else { 077 sb.append('('); 078 for (int i = 0; i < components.length; i++) { 079 if (i != 0) { 080 sb.append(','); 081 } 082 sb.append(components[i].toString()); 083 } 084 sb.append(')'); 085 } 086 087 if (path != null) { 088 sb.append('/'); 089 sb.append(path); 090 } 091 if (!parameters.isEmpty()) { 092 sb.append("?"); 093 sb.append(createQueryString(parameters)); 094 } 095 if (fragment != null) { 096 sb.append("#"); 097 sb.append(fragment); 098 } 099 return new URI(sb.toString()); 100 } 101 } 102 103 public static Map<String, String> parseQuery(String uri) throws URISyntaxException { 104 try { 105 uri = uri.substring(uri.lastIndexOf("?") + 1); // get only the relevant part of the query 106 Map<String, String> rc = new HashMap<String, String>(); 107 if (uri != null && !uri.isEmpty()) { 108 String[] parameters = uri.split("&"); 109 for (int i = 0; i < parameters.length; i++) { 110 int p = parameters[i].indexOf("="); 111 if (p >= 0) { 112 String name = URLDecoder.decode(parameters[i].substring(0, p), "UTF-8"); 113 String value = URLDecoder.decode(parameters[i].substring(p + 1), "UTF-8"); 114 rc.put(name, value); 115 } else { 116 rc.put(parameters[i], null); 117 } 118 } 119 } 120 return rc; 121 } catch (UnsupportedEncodingException e) { 122 throw (URISyntaxException)new URISyntaxException(e.toString(), "Invalid encoding").initCause(e); 123 } 124 } 125 126 public static Map<String, String> parseParameters(URI uri) throws URISyntaxException { 127 if (!isCompositeURI(uri)) { 128 return uri.getQuery() == null ? emptyMap() : parseQuery(stripPrefix(uri.getQuery(), "?")); 129 } else { 130 CompositeData data = URISupport.parseComposite(uri); 131 Map<String, String> parameters = new HashMap<String, String>(); 132 parameters.putAll(data.getParameters()); 133 if (parameters.isEmpty()) { 134 parameters = emptyMap(); 135 } 136 137 return parameters; 138 } 139 } 140 141 public static URI applyParameters(URI uri, Map<String, String> queryParameters) throws URISyntaxException { 142 return applyParameters(uri, queryParameters, ""); 143 } 144 145 public static URI applyParameters(URI uri, Map<String, String> queryParameters, String optionPrefix) throws URISyntaxException { 146 if (queryParameters != null && !queryParameters.isEmpty()) { 147 StringBuffer newQuery = uri.getRawQuery() != null ? new StringBuffer(uri.getRawQuery()) : new StringBuffer() ; 148 for ( Map.Entry<String, String> param: queryParameters.entrySet()) { 149 if (param.getKey().startsWith(optionPrefix)) { 150 if (newQuery.length()!=0) { 151 newQuery.append('&'); 152 } 153 final String key = param.getKey().substring(optionPrefix.length()); 154 newQuery.append(key).append('=').append(param.getValue()); 155 } 156 } 157 uri = createURIWithQuery(uri, newQuery.toString()); 158 } 159 return uri; 160 } 161 162 @SuppressWarnings("unchecked") 163 private static Map<String, String> emptyMap() { 164 return Collections.EMPTY_MAP; 165 } 166 167 /** 168 * Removes any URI query from the given uri 169 */ 170 public static URI removeQuery(URI uri) throws URISyntaxException { 171 return createURIWithQuery(uri, null); 172 } 173 174 /** 175 * Creates a URI with the given query 176 */ 177 public static URI createURIWithQuery(URI uri, String query) throws URISyntaxException { 178 String schemeSpecificPart = uri.getRawSchemeSpecificPart(); 179 // strip existing query if any 180 int questionMark = schemeSpecificPart.lastIndexOf("?"); 181 // make sure question mark is not within parentheses 182 if (questionMark < schemeSpecificPart.lastIndexOf(")")) { 183 questionMark = -1; 184 } 185 if (questionMark > 0) { 186 schemeSpecificPart = schemeSpecificPart.substring(0, questionMark); 187 } 188 if (query != null && query.length() > 0) { 189 schemeSpecificPart += "?" + query; 190 } 191 return new URI(uri.getScheme(), schemeSpecificPart, uri.getFragment()); 192 } 193 194 public static CompositeData parseComposite(URI uri) throws URISyntaxException { 195 196 CompositeData rc = new CompositeData(); 197 rc.scheme = uri.getScheme(); 198 String ssp = stripPrefix(uri.getRawSchemeSpecificPart().trim(), "//").trim(); 199 200 201 parseComposite(uri, rc, ssp); 202 203 rc.fragment = uri.getFragment(); 204 return rc; 205 } 206 207 public static boolean isCompositeURI(URI uri) { 208 if (uri.getQuery() != null) { 209 return false; 210 } else { 211 String ssp = stripPrefix(uri.getRawSchemeSpecificPart().trim(), "(").trim(); 212 ssp = stripPrefix(ssp, "//").trim(); 213 try { 214 new URI(ssp); 215 } catch (URISyntaxException e) { 216 return false; 217 } 218 return true; 219 } 220 } 221 222 /** 223 * @param uri 224 * @param rc 225 * @param ssp 226 * @throws URISyntaxException 227 */ 228 private static void parseComposite(URI uri, CompositeData rc, String ssp) throws URISyntaxException { 229 String componentString; 230 String params; 231 232 if (!checkParenthesis(ssp)) { 233 throw new URISyntaxException(uri.toString(), "Not a matching number of '(' and ')' parenthesis"); 234 } 235 236 int p; 237 int intialParen = ssp.indexOf("("); 238 if (intialParen == 0) { 239 rc.host = ssp.substring(0, intialParen); 240 p = rc.host.indexOf("/"); 241 if (p >= 0) { 242 rc.path = rc.host.substring(p); 243 rc.host = rc.host.substring(0, p); 244 } 245 p = ssp.lastIndexOf(")"); 246 componentString = ssp.substring(intialParen + 1, p); 247 params = ssp.substring(p + 1).trim(); 248 249 } else { 250 componentString = ssp; 251 params = ""; 252 } 253 254 String components[] = splitComponents(componentString); 255 rc.components = new URI[components.length]; 256 for (int i = 0; i < components.length; i++) { 257 rc.components[i] = new URI(components[i].trim()); 258 } 259 260 p = params.indexOf("?"); 261 if (p >= 0) { 262 if (p > 0) { 263 rc.path = stripPrefix(params.substring(0, p), "/"); 264 } 265 rc.parameters = parseQuery(params.substring(p + 1)); 266 } else { 267 if (params.length() > 0) { 268 rc.path = stripPrefix(params, "/"); 269 } 270 rc.parameters = emptyMap(); 271 } 272 } 273 274 /** 275 * @param str 276 * @return 277 */ 278 private static String[] splitComponents(String str) { 279 List<String> l = new ArrayList<String>(); 280 281 int last = 0; 282 int depth = 0; 283 char chars[] = str.toCharArray(); 284 for (int i = 0; i < chars.length; i++) { 285 switch (chars[i]) { 286 case '(': 287 depth++; 288 break; 289 case ')': 290 depth--; 291 break; 292 case ',': 293 if (depth == 0) { 294 String s = str.substring(last, i); 295 l.add(s); 296 last = i + 1; 297 } 298 break; 299 default: 300 } 301 } 302 303 String s = str.substring(last); 304 if (s.length() != 0) { 305 l.add(s); 306 } 307 308 String rc[] = new String[l.size()]; 309 l.toArray(rc); 310 return rc; 311 } 312 313 public static String stripPrefix(String value, String prefix) { 314 if (value.startsWith(prefix)) { 315 return value.substring(prefix.length()); 316 } 317 return value; 318 } 319 320 public static URI stripScheme(URI uri) throws URISyntaxException { 321 return new URI(stripPrefix(uri.getSchemeSpecificPart().trim(), "//")); 322 } 323 324 public static String createQueryString(Map<String, String> options) throws URISyntaxException { 325 try { 326 if (options.size() > 0) { 327 StringBuffer rc = new StringBuffer(); 328 boolean first = true; 329 for (String key : options.keySet()) { 330 if (first) { 331 first = false; 332 } else { 333 rc.append("&"); 334 } 335 String value = (String)options.get(key); 336 rc.append(URLEncoder.encode(key, "UTF-8")); 337 rc.append("="); 338 rc.append(URLEncoder.encode(value, "UTF-8")); 339 } 340 return rc.toString(); 341 } else { 342 return ""; 343 } 344 } catch (UnsupportedEncodingException e) { 345 throw (URISyntaxException)new URISyntaxException(e.toString(), "Invalid encoding").initCause(e); 346 } 347 } 348 349 /** 350 * Creates a URI from the original URI and the remaining paramaters 351 * 352 * @throws URISyntaxException 353 */ 354 public static URI createRemainingURI(URI originalURI, Map<String, String> params) throws URISyntaxException { 355 String s = createQueryString(params); 356 if (s.length() == 0) { 357 s = null; 358 } 359 return createURIWithQuery(originalURI, s); 360 } 361 362 public static URI changeScheme(URI bindAddr, String scheme) throws URISyntaxException { 363 return new URI(scheme, bindAddr.getUserInfo(), bindAddr.getHost(), bindAddr.getPort(), bindAddr 364 .getPath(), bindAddr.getQuery(), bindAddr.getFragment()); 365 } 366 367 public static boolean checkParenthesis(String str) { 368 boolean result = true; 369 if (str != null) { 370 int open = 0; 371 int closed = 0; 372 373 int i = 0; 374 while ((i = str.indexOf('(', i)) >= 0) { 375 i++; 376 open++; 377 } 378 i = 0; 379 while ((i = str.indexOf(')', i)) >= 0) { 380 i++; 381 closed++; 382 } 383 result = open == closed; 384 } 385 return result; 386 } 387 388 public int indexOfParenthesisMatch(String str) { 389 int result = -1; 390 391 return result; 392 } 393 394}