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 */
017 package org.apache.activemq.util;
018
019 import java.io.UnsupportedEncodingException;
020 import java.net.URI;
021 import java.net.URISyntaxException;
022 import java.net.URLDecoder;
023 import java.net.URLEncoder;
024 import java.util.ArrayList;
025 import java.util.Collections;
026 import java.util.HashMap;
027 import java.util.List;
028 import java.util.Map;
029
030 /**
031 * Utility class that provides methods for parsing URI's
032 */
033 public 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 }