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.servicemix.jbi.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.List;
029    import java.util.Map;
030    
031    /**
032     * @version $Revision$
033     */
034    public class URISupport {
035    
036        public static class CompositeData {
037            String scheme;
038    
039            String path;
040    
041            URI components[];
042    
043            Map parameters;
044    
045            String fragment;
046    
047            String host;
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 (int i = 0; i < parameters.length; i++) {
115                        int p = parameters[i].indexOf("=");
116                        if (p >= 0) {
117                            String name = URLDecoder.decode(parameters[i].substring(0, p), "UTF-8");
118                            String value = URLDecoder.decode(parameters[i].substring(p + 1), "UTF-8");
119                            rc.put(name, value);
120                        } else {
121                            rc.put(parameters[i], 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 parseParamters(URI uri) throws URISyntaxException {
132            return uri.getQuery() == null ? Collections.EMPTY_MAP : parseQuery(stripPrefix(uri.getQuery(), "?"));
133        }
134    
135        /**
136         * Removes any URI query from the given uri
137         */
138        public static URI removeQuery(URI uri) throws URISyntaxException {
139            return createURIWithQuery(uri, null);
140        }
141    
142        /**
143         * Creates a URI with the given query
144         */
145        public static URI createURIWithQuery(URI uri, String query) throws URISyntaxException {
146            return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath(), query, uri.getFragment());
147        }
148    
149        public static CompositeData parseComposite(URI uri) throws URISyntaxException {
150    
151            CompositeData rc = new CompositeData();
152            rc.scheme = uri.getScheme();
153            String ssp = stripPrefix(uri.getSchemeSpecificPart().trim(), "//").trim();
154    
155            parseComposite(uri, rc, ssp);
156    
157            rc.fragment = uri.getFragment();
158            return rc;
159        }
160    
161        /**
162         * @param uri
163         * @param rc
164         * @param ssp
165         * @param p
166         * @throws URISyntaxException
167         */
168        private static void parseComposite(URI uri, CompositeData rc, String ssp) throws URISyntaxException {
169            String componentString;
170            String params;
171    
172            if (!checkParenthesis(ssp)) {
173                throw new URISyntaxException(uri.toString(), "Not a matching number of '(' and ')' parenthesis");
174            }
175    
176            int p;
177            int intialParen = ssp.indexOf("(");
178            if (intialParen == 0) {
179                rc.host = ssp.substring(0, intialParen);
180                p = rc.host.indexOf("/");
181                if (p >= 0) {
182                    rc.path = rc.host.substring(p);
183                    rc.host = rc.host.substring(0, p);
184                }
185                p = ssp.lastIndexOf(")");
186                componentString = ssp.substring(intialParen + 1, p);
187                params = ssp.substring(p + 1).trim();
188    
189            } else {
190                componentString = ssp;
191                params = "";
192            }
193    
194            String components[] = splitComponents(componentString);
195            rc.components = new URI[components.length];
196            for (int i = 0; i < components.length; i++) {
197                rc.components[i] = new URI(components[i].trim());
198            }
199    
200            p = params.indexOf("?");
201            if (p >= 0) {
202                if (p > 0) {
203                    rc.path = stripPrefix(params.substring(0, p), "/");
204                }
205                rc.parameters = parseQuery(params.substring(p + 1));
206            } else {
207                if (params.length() > 0) {
208                    rc.path = stripPrefix(params, "/");
209                }
210                rc.parameters = Collections.EMPTY_MAP;
211            }
212        }
213    
214        /**
215         * @param componentString
216         * @return
217         */
218        private static String[] splitComponents(String str) {
219            List<String> l = new ArrayList<String>();
220    
221            int last = 0;
222            int depth = 0;
223            char chars[] = str.toCharArray();
224            for (int i = 0; i < chars.length; i++) {
225                switch (chars[i]) {
226                case '(':
227                    depth++;
228                    break;
229                case ')':
230                    depth--;
231                    break;
232                case ',':
233                    if (depth == 0) {
234                        String s = str.substring(last, i);
235                        l.add(s);
236                        last = i + 1;
237                    }
238                    break;
239                default:
240                    break;
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                        String key = (String) iter.next();
277                        String value = (String) options.get(key);
278                        rc.append(URLEncoder.encode(key, "UTF-8"));
279                        rc.append("=");
280                        rc.append(URLEncoder.encode(value, "UTF-8"));
281                    }
282                    return rc.toString();
283                } else {
284                    return "";
285                }
286            } catch (UnsupportedEncodingException e) {
287                throw (URISyntaxException) new URISyntaxException(e.toString(), "Invalid encoding").initCause(e);
288            }
289        }
290    
291        /**
292         * Creates a URI from the original URI and the remaining paramaters
293         * 
294         * @throws URISyntaxException
295         */
296        public static URI createRemainingURI(URI originalURI, Map params) throws URISyntaxException {
297            String s = createQueryString(params);
298            if (s.length() == 0) {
299                s = null;
300            }
301            return createURIWithQuery(originalURI, s);
302        }
303    
304        public static URI changeScheme(URI bindAddr, String scheme) throws URISyntaxException {
305            return new URI(scheme, bindAddr.getUserInfo(), bindAddr.getHost(), bindAddr.getPort(), 
306                           bindAddr.getPath(), bindAddr.getQuery(), bindAddr.getFragment());
307        }
308    
309        public static boolean checkParenthesis(String str) {
310            boolean result = true;
311            if (str != null) {
312                int open = 0;
313                int closed = 0;
314    
315                int i = str.indexOf('(');
316                while (i >= 0) {
317                    open++;
318                    i = str.indexOf('(', i + 1);
319                }
320                i = str.indexOf(')');
321                while (i >= 0) {
322                    closed++;
323                    i = str.indexOf(')', i + 1);
324                }
325                result = open == closed;
326            }
327            return result;
328        }
329    
330        public int indexOfParenthesisMatch(String str) {
331            int result = -1;
332    
333            return result;
334        }
335    
336    }