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     * @version $Revision$
032     */
033    public class URISupport {
034        public static class CompositeData {
035            public String host;
036    
037            String scheme;
038            String path;
039            URI components[];
040            Map parameters;
041            String fragment;
042    
043            public URI[] getComponents() {
044                return components;
045            }
046    
047            public String getFragment() {
048                return fragment;
049            }
050    
051            public Map 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 parseQuery(String uri) throws URISyntaxException {
104            try {
105                Map rc = new HashMap();
106                if (uri != null) {
107                    String[] parameters = uri.split("&");
108                    for (int i = 0; i < parameters.length; i++) {
109                        int p = parameters[i].indexOf("=");
110                        if (p >= 0) {
111                            String name = URLDecoder.decode(parameters[i].substring(0, p), "UTF-8");
112                            String value = URLDecoder.decode(parameters[i].substring(p + 1), "UTF-8");
113                            rc.put(name, value);
114                        } else {
115                            rc.put(parameters[i], null);
116                        }
117                    }
118                }
119                return rc;
120            } catch (UnsupportedEncodingException e) {
121                throw (URISyntaxException)new URISyntaxException(e.toString(), "Invalid encoding").initCause(e);
122            }
123        }
124    
125        public static Map parseParamters(URI uri) throws URISyntaxException {
126            String query = uri.getQuery();
127            if (query == null) {
128                String schemeSpecificPart = uri.getSchemeSpecificPart();
129                int idx = schemeSpecificPart.lastIndexOf('?');
130                if (idx < 0) {
131                    return Collections.EMPTY_MAP;
132                } else {
133                    query = schemeSpecificPart.substring(idx + 1);
134                }
135            } else {
136                query = stripPrefix(query, "?");
137            }
138            return parseQuery(query);
139        }
140    
141        /**
142         * Removes any URI query from the given uri
143         */
144        public static URI removeQuery(URI uri) throws URISyntaxException {
145            return createURIWithQuery(uri, null);
146        }
147    
148        /**
149         * Creates a URI with the given query
150         */
151        public static URI createURIWithQuery(URI uri, String query) throws URISyntaxException {
152            return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath(),
153                           query, uri.getFragment());
154        }
155    
156        public static CompositeData parseComposite(URI uri) throws URISyntaxException {
157    
158            CompositeData rc = new CompositeData();
159            rc.scheme = uri.getScheme();
160            String ssp = stripPrefix(uri.getSchemeSpecificPart().trim(), "//").trim();
161    
162            parseComposite(uri, rc, ssp);
163    
164            rc.fragment = uri.getFragment();
165            return rc;
166        }
167    
168        /**
169         * @param uri
170         * @param rc
171         * @param ssp
172         * @throws URISyntaxException
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        /**
220         * @param str
221         * @return
222         */
223        private static String[] splitComponents(String str) {
224            ArrayList l = new ArrayList();
225    
226            int last = 0;
227            int depth = 0;
228            char chars[] = str.toCharArray();
229            for (int i = 0; i < chars.length; i++) {
230                switch (chars[i]) {
231                case '(':
232                    depth++;
233                    break;
234                case ')':
235                    depth--;
236                    break;
237                case ',':
238                    if (depth == 0) {
239                        String s = str.substring(last, i);
240                        l.add(s);
241                        last = i + 1;
242                    }
243                    break;
244                default:
245                }
246            }
247    
248            String s = str.substring(last);
249            if (s.length() != 0) {
250                l.add(s);
251            }
252    
253            String rc[] = new String[l.size()];
254            l.toArray(rc);
255            return rc;
256        }
257    
258        public static String stripPrefix(String value, String prefix) {
259            if (value.startsWith(prefix)) {
260                return value.substring(prefix.length());
261            }
262            return value;
263        }
264    
265        public static URI stripScheme(URI uri) throws URISyntaxException {
266            return new URI(stripPrefix(uri.getSchemeSpecificPart().trim(), "//"));
267        }
268    
269        public static String createQueryString(Map options) throws URISyntaxException {
270            try {
271                if (options.size() > 0) {
272                    StringBuffer rc = new StringBuffer();
273                    boolean first = true;
274                    for (Iterator iter = options.keySet().iterator(); iter.hasNext();) {
275                        if (first) {
276                            first = false;
277                        } else {
278                            rc.append("&");
279                        }
280    
281                        String key = (String)iter.next();
282                        String value = (String)options.get(key);
283                        rc.append(URLEncoder.encode(key, "UTF-8"));
284                        rc.append("=");
285                        rc.append(URLEncoder.encode(value, "UTF-8"));
286                    }
287                    return rc.toString();
288                } else {
289                    return "";
290                }
291            } catch (UnsupportedEncodingException e) {
292                throw (URISyntaxException)new URISyntaxException(e.toString(), "Invalid encoding").initCause(e);
293            }
294        }
295    
296        /**
297         * Creates a URI from the original URI and the remaining paramaters
298         * 
299         * @throws URISyntaxException
300         */
301        public static URI createRemainingURI(URI originalURI, Map params) throws URISyntaxException {
302            String s = createQueryString(params);
303            if (s.length() == 0) {
304                s = null;
305            }
306            return createURIWithQuery(originalURI, s);
307        }
308    
309        public static URI changeScheme(URI bindAddr, String scheme) throws URISyntaxException {
310            return new URI(scheme, bindAddr.getUserInfo(), bindAddr.getHost(), bindAddr.getPort(), bindAddr
311                .getPath(), bindAddr.getQuery(), bindAddr.getFragment());
312        }
313    
314        public static boolean checkParenthesis(String str) {
315            boolean result = true;
316            if (str != null) {
317                int open = 0;
318                int closed = 0;
319    
320                int i = 0;
321                while ((i = str.indexOf('(', i)) >= 0) {
322                    i++;
323                    open++;
324                }
325                i = 0;
326                while ((i = str.indexOf(')', i)) >= 0) {
327                    i++;
328                    closed++;
329                }
330                result = open == closed;
331            }
332            return result;
333        }
334    
335        public int indexOfParenthesisMatch(String str) {
336            int result = -1;
337    
338            return result;
339        }
340    }