| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| using System; |
| using System.Collections; |
| using System.Net; |
| using System.Text; |
| using System.Text.RegularExpressions; |
| using log4net; |
| using Apache.Qpid.Client.Qms; |
| |
| namespace Apache.Qpid.Client |
| { |
| |
| public class URLHelper |
| { |
| public static char DEFAULT_OPTION_SEPERATOR = '&'; |
| public static char ALTERNATIVE_OPTION_SEPARATOR = ','; |
| public static char BROKER_SEPARATOR = ';'; |
| |
| /// <summary> |
| /// |
| /// </summary> |
| /// <param name="optionMap"></param> |
| /// <param name="options"></param> |
| public static void parseOptions(IDictionary optionMap, string options) |
| { |
| //options looks like this |
| //brokerlist='tcp://host:port?option='value',option='value';vm://:3/virtualpath?option='value'',failover='method?option='value',option='value'' |
| |
| if (options == null || options.IndexOf('=') == -1) |
| { |
| return; |
| } |
| |
| int optionIndex = options.IndexOf('='); |
| |
| String option = options.Substring(0, optionIndex); |
| |
| int length = options.Length; |
| |
| int nestedQuotes = 0; |
| |
| // to store index of final "'" |
| int valueIndex = optionIndex; |
| |
| //Walk remainder of url. |
| while (nestedQuotes > 0 || valueIndex < length) |
| { |
| valueIndex++; |
| |
| if (valueIndex >= length) |
| { |
| break; |
| } |
| |
| if (options[valueIndex] == '\'') |
| { |
| if (valueIndex + 1 < options.Length) |
| { |
| if (options[valueIndex + 1] == DEFAULT_OPTION_SEPERATOR || |
| options[valueIndex + 1] == ALTERNATIVE_OPTION_SEPARATOR || |
| options[valueIndex + 1] == BROKER_SEPARATOR || |
| options[valueIndex + 1] == '\'') |
| { |
| nestedQuotes--; |
| // System.out.println( |
| // options + "\n" + "-" + nestedQuotes + ":" + getPositionString(valueIndex - 2, 1)); |
| if (nestedQuotes == 0) |
| { |
| //We've found the value of an option |
| break; |
| } |
| } |
| else |
| { |
| nestedQuotes++; |
| // System.out.println( |
| // options + "\n" + "+" + nestedQuotes + ":" + getPositionString(valueIndex - 2, 1)); |
| } |
| } |
| else |
| { |
| // We are at the end of the string |
| // Check to see if we are corectly closing quotes |
| if (options[valueIndex] == '\'') |
| { |
| nestedQuotes--; |
| } |
| |
| break; |
| } |
| } |
| } |
| |
| if (nestedQuotes != 0 || valueIndex < (optionIndex + 2)) |
| { |
| int sepIndex = 0; |
| |
| //Try and identify illegal separator character |
| if (nestedQuotes > 1) |
| { |
| for (int i = 0; i < nestedQuotes; i++) |
| { |
| sepIndex = options.IndexOf('\'', sepIndex); |
| sepIndex++; |
| } |
| } |
| |
| if (sepIndex >= options.Length || sepIndex == 0) |
| { |
| parseError(valueIndex, "Unterminated option", options); |
| } |
| else |
| { |
| parseError(sepIndex, "Unterminated option. Possible illegal option separator:'" + |
| options[sepIndex] + "'", options); |
| } |
| } |
| |
| // optionIndex +2 to skip "='" |
| int sublen = valueIndex - (optionIndex + 2); |
| String value = options.Substring(optionIndex + 2, sublen); |
| |
| optionMap.Add(option, value); |
| |
| if (valueIndex < (options.Length - 1)) |
| { |
| //Recurse to get remaining options |
| parseOptions(optionMap, options.Substring(valueIndex + 2)); |
| } |
| } |
| |
| |
| public static void parseError(int index, String error, String url) |
| { |
| parseError(index, 1, error, url); |
| } |
| |
| public static void parseError(int index, int length, String error, String url) |
| { |
| throw new UrlSyntaxException(url, error, index, length); |
| } |
| |
| public static String printOptions(Hashtable options) |
| { |
| if (options.Count == 0) |
| { |
| return ""; |
| } |
| else |
| { |
| StringBuilder sb = new StringBuilder(); |
| sb.Append('?'); |
| foreach (String key in options.Keys) |
| { |
| sb.AppendFormat("{0}='{1}'{2}", key, options[key], DEFAULT_OPTION_SEPERATOR); |
| } |
| |
| sb.Remove(sb.Length - 1, 1); |
| return sb.ToString(); |
| } |
| } |
| |
| } |
| |
| public class QpidConnectionUrl |
| { |
| internal static IConnectionInfo FromUrl(string fullURL) |
| { |
| //_url = fullURL; |
| IConnectionInfo connectionInfo = new QpidConnectionInfo(); |
| |
| |
| // _options = new HashMap<String, String>(); |
| // _brokers = new LinkedList(); |
| // _failoverOptions = new HashMap<String, String>(); |
| |
| // Connection URL format |
| //amqp://[user:pass@][clientid]/virtualhost?brokerlist='tcp://host:port?option=\'value\',option=\'value\';vm://:3/virtualpath?option=\'value\'',failover='method?option=\'value\',option='value''" |
| // Options are of course optional except for requiring a single broker in the broker list. |
| try |
| { |
| Uri connection = new Uri(fullURL); |
| |
| if (connection.Scheme == null || !(connection.Scheme.Equals(ConnectionUrlConstants.AMQ_PROTOCOL))) |
| { |
| throw new UrlSyntaxException(fullURL, "Not an AMQP URL"); |
| } |
| |
| if (connection.Host != null && connection.Host.Length > 0 && !connection.Host.Equals("default")) |
| { |
| connectionInfo.ClientName = connection.Host; |
| } |
| |
| String userInfo = connection.UserInfo; |
| if (userInfo == null || userInfo.Length == 0) |
| { |
| URLHelper.parseError(ConnectionUrlConstants.AMQ_PROTOCOL.Length + 3, |
| "User information not found on url", fullURL); |
| } |
| else |
| { |
| parseUserInfo(userInfo, fullURL, connectionInfo); |
| } |
| String virtualHost = connection.AbsolutePath; // XXX: is AbsolutePath corrrect? |
| |
| if (virtualHost != null && virtualHost.Length > 0) |
| { |
| connectionInfo.VirtualHost = virtualHost; |
| } |
| else |
| { |
| int authLength = connection.Authority.Length; |
| int start = ConnectionUrlConstants.AMQ_PROTOCOL.Length + 3; |
| int testIndex = start + authLength; |
| if (testIndex < fullURL.Length && fullURL[testIndex] == '?') |
| { |
| URLHelper.parseError(start, testIndex - start, "Virtual host found", fullURL); |
| } |
| else |
| { |
| URLHelper.parseError(-1, "Virtual host not specified", fullURL); |
| } |
| |
| } |
| |
| QpidConnectionInfo qci = (QpidConnectionInfo)connectionInfo; |
| string query = connection.Query; |
| if (query[0] == '?') query = query.Substring(1); |
| URLHelper.parseOptions(qci.GetOptions(), query); |
| |
| processOptions(connectionInfo); |
| |
| //Fragment is #string (not used) |
| //System.out.println(connection.getFragment()); |
| return connectionInfo; |
| } |
| catch (UriFormatException uris) |
| { |
| throw uris; |
| // if (uris is UrlSyntaxException) |
| // { |
| // throw uris; |
| // } |
| // |
| // int slash = fullURL.IndexOf("\\"); |
| // |
| // if (slash == -1) |
| // { |
| // URLHelper.parseError(uris.GetIndex(), uris.getReason(), uris.getInput()); |
| // } |
| // else |
| // { |
| // if (slash != 0 && fullURL.charAt(slash - 1) == ':') |
| // { |
| // URLHelper.parseError(slash - 2, fullURL.indexOf('?') - slash + 2, "Virtual host looks like a windows path, forward slash not allowed in URL", fullURL); |
| // } |
| // else |
| // { |
| // URLHelper.parseError(slash, "Forward slash not allowed in URL", fullURL); |
| // } |
| // } |
| } |
| } |
| |
| private static void parseUserInfo(String userinfo, string fullUrl, IConnectionInfo connectionInfo) |
| { |
| //user info = user:pass |
| |
| int colonIndex = userinfo.IndexOf(':'); |
| |
| if (colonIndex == -1) |
| { |
| URLHelper.parseError(ConnectionUrlConstants.AMQ_PROTOCOL.Length + 3, |
| userinfo.Length, "Null password in user information not allowed.", fullUrl); |
| } |
| else |
| { |
| connectionInfo.Username = userinfo.Substring(0, colonIndex); |
| connectionInfo.Password = userinfo.Substring(colonIndex + 1); |
| } |
| } |
| |
| private static void processOptions(IConnectionInfo connectionInfo) |
| { |
| string brokerlist = connectionInfo.GetOption(ConnectionUrlConstants.OPTIONS_BROKERLIST); |
| if (brokerlist != null) |
| { |
| //brokerlist tcp://host:port?option='value',option='value';vm://:3/virtualpath?option='value' |
| Regex splitter = new Regex("" + URLHelper.BROKER_SEPARATOR); |
| |
| foreach (string broker in splitter.Split(brokerlist)) |
| { |
| connectionInfo.AddBrokerInfo(new AmqBrokerInfo(broker)); |
| } |
| |
| connectionInfo.SetOption(ConnectionUrlConstants.OPTIONS_BROKERLIST, null); |
| // _options.remove(OPTIONS_BROKERLIST); |
| } |
| |
| string failover = connectionInfo.GetOption(ConnectionUrlConstants.OPTIONS_FAILOVER); |
| if (failover != null) |
| { |
| // failover='method?option='value',option='value'' |
| |
| int methodIndex = failover.IndexOf('?'); |
| |
| if (methodIndex > -1) |
| { |
| connectionInfo.FailoverMethod = failover.Substring(0, methodIndex); |
| QpidConnectionInfo qpidConnectionInfo = (QpidConnectionInfo)connectionInfo; |
| URLHelper.parseOptions(qpidConnectionInfo.GetFailoverOptions(), |
| failover.Substring(methodIndex + 1)); |
| } |
| else |
| { |
| connectionInfo.FailoverMethod = failover; |
| } |
| |
| connectionInfo.SetOption(ConnectionUrlConstants.OPTIONS_FAILOVER, null); |
| // _options.remove(OPTIONS_FAILOVER); |
| } |
| } |
| |
| internal static IConnectionInfo FromUri(Uri uri) |
| { |
| return null; // FIXME |
| |
| } |
| } |
| |
| public class QpidConnectionInfo : IConnectionInfo |
| { |
| const string DEFAULT_VHOST = "/"; |
| string _username = "guest"; |
| string _password = "guest"; |
| string _virtualHost = DEFAULT_VHOST; |
| |
| string _failoverMethod = null; |
| IDictionary _failoverOptions = new Hashtable(); |
| IDictionary _options = new Hashtable(); |
| IList _brokerInfos = new ArrayList(); // List<BrokerInfo> |
| string _clientName = String.Format("{0}{1:G}", Dns.GetHostName(), DateTime.Now.Ticks); |
| |
| public IDictionary GetFailoverOptions() |
| { |
| return _failoverOptions; |
| } |
| |
| public IDictionary GetOptions() |
| { |
| return _options; |
| } |
| |
| public static IConnectionInfo FromUrl(String url) |
| { |
| return QpidConnectionUrl.FromUrl(url); |
| } |
| |
| public string AsUrl() |
| { |
| StringBuilder sb = new StringBuilder(); |
| sb.AppendFormat("{0}://", ConnectionUrlConstants.AMQ_PROTOCOL); |
| |
| if (_username != null) |
| { |
| sb.Append(_username); |
| if (_password != null) |
| { |
| sb.AppendFormat(":{0}", _password); |
| } |
| sb.Append("@"); |
| } |
| |
| sb.Append(_clientName); |
| sb.Append(_virtualHost); |
| sb.Append(OptionsToString()); |
| |
| return sb.ToString(); |
| } |
| |
| private String OptionsToString() |
| { |
| StringBuilder sb = new StringBuilder(); |
| sb.AppendFormat("?{0}='", ConnectionUrlConstants.OPTIONS_BROKERLIST); |
| |
| foreach (IBrokerInfo broker in _brokerInfos) |
| { |
| sb.AppendFormat("{0};", broker); |
| } |
| |
| sb.Remove(sb.Length - 1, 1); |
| sb.Append("'"); |
| |
| if (_failoverMethod != null) |
| { |
| sb.AppendFormat("{0}{1}='{2}{3}'", URLHelper.DEFAULT_OPTION_SEPERATOR, |
| ConnectionUrlConstants.OPTIONS_FAILOVER, |
| _failoverMethod, |
| URLHelper.printOptions((Hashtable)_failoverOptions)); |
| } |
| |
| return sb.ToString(); |
| } |
| |
| |
| public string FailoverMethod |
| { |
| get { return _failoverMethod; } |
| set { _failoverMethod = value; } |
| } |
| |
| public string GetFailoverOption(string key) |
| { |
| return (string)_failoverOptions[key]; |
| } |
| |
| public int BrokerCount |
| { |
| get { return _brokerInfos.Count; } |
| } |
| |
| public IBrokerInfo GetBrokerInfo(int index) |
| { |
| return (IBrokerInfo)_brokerInfos[index]; |
| } |
| |
| public void AddBrokerInfo(IBrokerInfo brokerInfo) |
| { |
| if (!_brokerInfos.Contains(brokerInfo)) |
| { |
| _brokerInfos.Add(brokerInfo); |
| } |
| } |
| |
| public IList GetAllBrokerInfos() |
| { |
| return _brokerInfos; |
| } |
| |
| public string ClientName |
| { |
| get { return _clientName; } |
| set { _clientName = value; } |
| } |
| |
| public string Username |
| { |
| get { return _username; } |
| set { _username = value; } |
| } |
| |
| public string Password |
| { |
| get { return _password; } |
| set { _password = value; } |
| } |
| |
| public string VirtualHost |
| { |
| get { return _virtualHost; } |
| set { |
| _virtualHost = value; |
| if ( _virtualHost == null || _virtualHost.Length == 0 ) |
| _virtualHost = DEFAULT_VHOST; |
| if ( _virtualHost[0] != '/' ) |
| _virtualHost = '/' + _virtualHost; |
| } |
| } |
| |
| public string GetOption(string key) |
| { |
| return (string)_options[key]; |
| } |
| |
| public void SetOption(string key, string value) |
| { |
| _options[key] = value; |
| } |
| |
| public override string ToString() |
| { |
| return AsUrl(); |
| } |
| } |
| } |