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