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