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: 42401 $
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    }