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