001    /**
002     *
003     * Licensed to the Apache Software Foundation (ASF) under one or more
004     * contributor license agreements.  See the NOTICE file distributed with
005     * this work for additional information regarding copyright ownership.
006     * The ASF licenses this file to You under the Apache License, Version 2.0
007     * (the "License"); you may not use this file except in compliance with
008     * the License.  You may obtain a copy of the License at
009     *
010     * http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.camel.util;
019    
020    import java.io.UnsupportedEncodingException;
021    import java.net.URI;
022    import java.net.URISyntaxException;
023    import java.net.URLDecoder;
024    import java.net.URLEncoder;
025    import java.util.ArrayList;
026    import java.util.Collections;
027    import java.util.HashMap;
028    import java.util.Iterator;
029    import java.util.Map;
030    
031    /**
032     * @version $Revision$
033     */
034    public class URISupport {
035        public static class CompositeData {
036            String scheme;
037            String path;
038            URI components[];
039            Map parameters;
040            String fragment;
041            public String host;
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                }
077                else {
078                    sb.append('(');
079                    for (int i = 0; i < components.length; i++) {
080                        if (i != 0) {
081                            sb.append(',');
082                        }
083                        sb.append(components[i].toString());
084                    }
085                    sb.append(')');
086                }
087    
088                if (path != null) {
089                    sb.append('/');
090                    sb.append(path);
091                }
092                if (!parameters.isEmpty()) {
093                    sb.append("?");
094                    sb.append(createQueryString(parameters));
095                }
096                if (fragment != null) {
097                    sb.append("#");
098                    sb.append(fragment);
099                }
100                return new URI(sb.toString());
101            }
102        }
103    
104        public static Map parseQuery(String uri) throws URISyntaxException {
105            try {
106                Map rc = new HashMap();
107                if (uri != null) {
108                    String[] parameters = uri.split("&");
109                    for (int i = 0; i < parameters.length; i++) {
110                        int p = parameters[i].indexOf("=");
111                        if (p >= 0) {
112                            String name = URLDecoder.decode(parameters[i].substring(0, p), "UTF-8");
113                            String value = URLDecoder.decode(parameters[i].substring(p + 1), "UTF-8");
114                            rc.put(name, value);
115                        }
116                        else {
117                            rc.put(parameters[i], null);
118                        }
119                    }
120                }
121                return rc;
122            }
123            catch (UnsupportedEncodingException e) {
124                throw (URISyntaxException) new URISyntaxException(e.toString(), "Invalid encoding").initCause(e);
125            }
126        }
127    
128        public static Map parseParamters(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                }
136                else {
137                    query = schemeSpecificPart.substring(idx + 1);
138                }
139            }
140            else {
141                query = stripPrefix(query, "?");
142            }
143            return parseQuery(query);
144        }
145    
146        /**
147         * Removes any URI query from the given uri
148         */
149        public static URI removeQuery(URI uri) throws URISyntaxException {
150            return createURIWithQuery(uri, null);
151        }
152    
153        /**
154         * Creates a URI with the given query
155         */
156        public static URI createURIWithQuery(URI uri, String query) throws URISyntaxException {
157            return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath(), query, uri.getFragment());
158        }
159    
160        public static CompositeData parseComposite(URI uri) throws URISyntaxException {
161    
162            CompositeData rc = new CompositeData();
163            rc.scheme = uri.getScheme();
164            String ssp = stripPrefix(uri.getSchemeSpecificPart().trim(), "//").trim();
165    
166            parseComposite(uri, rc, ssp);
167    
168            rc.fragment = uri.getFragment();
169            return rc;
170        }
171    
172        /**
173         * @param uri
174         * @param rc
175         * @param ssp
176         * @throws URISyntaxException
177         */
178        private static void parseComposite(URI uri, CompositeData rc, String ssp) throws URISyntaxException {
179            String componentString;
180            String params;
181    
182            if (!checkParenthesis(ssp)) {
183                throw new URISyntaxException(uri.toString(), "Not a matching number of '(' and ')' parenthesis");
184            }
185    
186            int p;
187            int intialParen = ssp.indexOf("(");
188            if (intialParen == 0) {
189                rc.host = ssp.substring(0, intialParen);
190                p = rc.host.indexOf("/");
191                if (p >= 0) {
192                    rc.path = rc.host.substring(p);
193                    rc.host = rc.host.substring(0, p);
194                }
195                p = ssp.lastIndexOf(")");
196                componentString = ssp.substring(intialParen + 1, p);
197                params = ssp.substring(p + 1).trim();
198            }
199            else {
200                componentString = ssp;
201                params = "";
202            }
203    
204            String components[] = splitComponents(componentString);
205            rc.components = new URI[components.length];
206            for (int i = 0; i < components.length; i++) {
207                rc.components[i] = new URI(components[i].trim());
208            }
209    
210            p = params.indexOf("?");
211            if (p >= 0) {
212                if (p > 0) {
213                    rc.path = stripPrefix(params.substring(0, p), "/");
214                }
215                rc.parameters = parseQuery(params.substring(p + 1));
216            }
217            else {
218                if (params.length() > 0) {
219                    rc.path = stripPrefix(params, "/");
220                }
221                rc.parameters = Collections.EMPTY_MAP;
222            }
223        }
224    
225        /**
226         * @param str
227         * @return
228         */
229        private static String[] splitComponents(String str) {
230            ArrayList l = new ArrayList();
231    
232            int last = 0;
233            int depth = 0;
234            char chars[] = str.toCharArray();
235            for (int i = 0; i < chars.length; i++) {
236                switch (chars[i]) {
237                    case '(':
238                        depth++;
239                        break;
240                    case ')':
241                        depth--;
242                        break;
243                    case ',':
244                        if (depth == 0) {
245                            String s = str.substring(last, i);
246                            l.add(s);
247                            last = i + 1;
248                        }
249                }
250            }
251    
252            String s = str.substring(last);
253            if (s.length() != 0) {
254                l.add(s);
255            }
256    
257            String rc[] = new String[l.size()];
258            l.toArray(rc);
259            return rc;
260        }
261    
262        public static String stripPrefix(String value, String prefix) {
263            if (value.startsWith(prefix)) {
264                return value.substring(prefix.length());
265            }
266            return value;
267        }
268    
269        public static URI stripScheme(URI uri) throws URISyntaxException {
270            return new URI(stripPrefix(uri.getSchemeSpecificPart().trim(), "//"));
271        }
272    
273        public static String createQueryString(Map options) throws URISyntaxException {
274            try {
275                if (options.size() > 0) {
276                    StringBuffer rc = new StringBuffer();
277                    boolean first = true;
278                    for (Iterator iter = options.keySet().iterator(); iter.hasNext();) {
279                        if (first) {
280                            first = false;
281                        }
282                        else {
283                            rc.append("&");
284                        }
285    
286                        String key = (String) iter.next();
287                        String value = (String) options.get(key);
288                        rc.append(URLEncoder.encode(key, "UTF-8"));
289                        rc.append("=");
290                        rc.append(URLEncoder.encode(value, "UTF-8"));
291                    }
292                    return rc.toString();
293                }
294                else {
295                    return "";
296                }
297            }
298            catch (UnsupportedEncodingException e) {
299                throw (URISyntaxException) new URISyntaxException(e.toString(), "Invalid encoding").initCause(e);
300            }
301        }
302    
303        /**
304         * Creates a URI from the original URI and the remaining paramaters
305         *
306         * @throws URISyntaxException
307         */
308        public static URI createRemainingURI(URI originalURI, Map params) throws URISyntaxException {
309            String s = createQueryString(params);
310            if (s.length() == 0) {
311                s = null;
312            }
313            return createURIWithQuery(originalURI, s);
314        }
315    
316        static public URI changeScheme(URI bindAddr, String scheme) throws URISyntaxException {
317            return new URI(scheme, bindAddr.getUserInfo(), bindAddr.getHost(), bindAddr.getPort(), bindAddr.getPath(), bindAddr.getQuery(), bindAddr.getFragment());
318        }
319    
320        public static boolean checkParenthesis(String str) {
321            boolean result = true;
322            if (str != null) {
323                int open = 0;
324                int closed = 0;
325    
326                int i = 0;
327                while ((i = str.indexOf('(', i)) >= 0) {
328                    i++;
329                    open++;
330                }
331                i = 0;
332                while ((i = str.indexOf(')', i)) >= 0) {
333                    i++;
334                    closed++;
335                }
336                result = open == closed;
337            }
338            return result;
339        }
340    
341        public int indexOfParenthesisMatch(String str) {
342            int result = -1;
343    
344            return result;
345        }
346    }