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.Iterator;
028 import java.util.List;
029 import java.util.Map;
030
031 /**
032 *
033 */
034 public 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 }