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