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