AMQBrokerDetails.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  *
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  *
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.client;
022 
023 import java.net.URI;
024 import java.net.URISyntaxException;
025 import java.util.HashMap;
026 import java.util.Map;
027 
028 import org.apache.qpid.jms.BrokerDetails;
029 import org.apache.qpid.jms.ConnectionURL;
030 import org.apache.qpid.url.URLHelper;
031 import org.apache.qpid.url.URLSyntaxException;
032 
033 public class AMQBrokerDetails implements BrokerDetails
034 {
035     private String _host;
036     private int _port;
037     private String _transport;
038 
039     private Map<String, String> _options = new HashMap<String, String>();
040 
041     private SSLConfiguration _sslConfiguration;
042 
043     public AMQBrokerDetails(){}
044     
045     public AMQBrokerDetails(String urlthrows URLSyntaxException
046     {        
047       
048         // URL should be of format tcp://host:port?option='value',option='value'
049         try
050         {
051             URI connection = new URI(url);
052 
053             String transport = connection.getScheme();
054 
055             // Handles some defaults to minimise changes to existing broker URLS e.g. localhost
056             if (transport != null)
057             {
058                 //todo this list of valid transports should be enumerated somewhere
059                 if ((!(transport.equalsIgnoreCase(BrokerDetails.VM||
060                        transport.equalsIgnoreCase(BrokerDetails.TCP||
061                        transport.equalsIgnoreCase(BrokerDetails.SOCKET))))
062                 {
063                     if (transport.equalsIgnoreCase("localhost"))
064                     {
065                         connection = new URI(DEFAULT_TRANSPORT + "://" + url);
066                         transport = connection.getScheme();
067                     }
068                     else
069                     {
070                         if (url.charAt(transport.length()) == ':' && url.charAt(transport.length() 1!= '/')
071                         {
072                             //Then most likely we have a host:port value
073                             connection = new URI(DEFAULT_TRANSPORT + "://" + url);
074                             transport = connection.getScheme();
075                         }
076                         else
077                         {
078                             throw URLHelper.parseError(0, transport.length()"Unknown transport", url);
079                         }
080                     }
081                 }
082                 else if (url.indexOf("//"== -1)
083                 {
084                     throw new URLSyntaxException(url, "Missing '//' after the transport In broker URL",transport.length()+1,1);
085                 }
086             }
087             else
088             {
089                 //Default the transport
090                 connection = new URI(DEFAULT_TRANSPORT + "://" + url);
091                 transport = connection.getScheme();
092             }
093 
094             if (transport == null)
095             {
096                 throw URLHelper.parseError(-1"Unknown transport:'" + transport + "'" +
097                                          " In broker URL:'" + url + "' Format: " + URL_FORMAT_EXAMPLE, "");
098             }
099 
100             setTransport(transport);
101 
102             String host = connection.getHost();
103 
104             // Fix for Java 1.5
105             if (host == null)
106             {
107                 host = "";
108             }
109 
110             setHost(host);
111 
112             int port = connection.getPort();
113 
114             if (port == -1)
115             {
116                 // Fix for when there is port data but it is not automatically parseable by getPort().
117                 String auth = connection.getAuthority();
118 
119                 if (auth != null && auth.contains(":"))
120                 {
121                     int start = auth.indexOf(":"1;
122                     int end = start;
123                     boolean looking = true;
124                     boolean found = false;
125                     // Throw an URL exception if the port number is not specified
126                     if (start == auth.length())
127                     {
128                         throw URLHelper.parseError(connection.toString().indexOf(auth+ end - 1,
129                                 connection.toString().indexOf(auth+ end, "Port number must be specified",
130                                 connection.toString());
131                     }
132                     //Walk the authority looking for a port value.
133                     while (looking)
134                     {
135                         try
136                         {
137                             end++;
138                             Integer.parseInt(auth.substring(start, end));
139 
140                             if (end >= auth.length())
141                             {
142                                 looking = false;
143                                 found = true;
144                             }
145                         }
146                         catch (NumberFormatException nfe)
147                         {
148                             looking = false;
149                         }
150 
151                     }
152                     if (found)
153                     {
154                         setPort(Integer.parseInt(auth.substring(start, end)));
155                     }
156                     else
157                     {
158                         throw URLHelper.parseError(connection.toString().indexOf(connection.getAuthority()) + end - 1,
159                                              "Illegal character in port number", connection.toString());
160                     }
161 
162                 }
163                 else
164                 {
165                     setPort(DEFAULT_PORT);
166                 }
167             }
168             else
169             {
170                 if (!_transport.equalsIgnoreCase(SOCKET))
171                 {
172                     setPort(port);
173                 }
174             }
175 
176             String queryString = connection.getQuery();
177 
178             URLHelper.parseOptions(_options, queryString);
179 
180             //Fragment is #string (not used)
181         }
182         catch (URISyntaxException uris)
183         {
184             if (uris instanceof URLSyntaxException)
185             {
186                 throw(URLSyntaxExceptionuris;
187             }
188 
189             throw URLHelper.parseError(uris.getIndex(), uris.getReason(), uris.getInput());
190         }
191     }
192 
193     public AMQBrokerDetails(String host, int port, SSLConfiguration sslConfiguration)
194     {
195         _host = host;
196         _port = port;
197         _sslConfiguration = sslConfiguration;
198     }
199 
200     public String getHost()
201     {
202         return _host;
203     }
204 
205     public void setHost(String _host)
206     {
207         this._host = _host;
208     }
209 
210     public int getPort()
211     {
212         return _port;
213     }
214 
215     public void setPort(int _port)
216     {
217         this._port = _port;
218     }
219 
220     public String getTransport()
221     {
222         return _transport;
223     }
224 
225     public void setTransport(String _transport)
226     {
227         this._transport = _transport;
228     }
229 
230 
231     public String getProperty(String key)
232     {
233         return _options.get(key);
234     }
235 
236     public void setProperty(String key, String value)
237     {
238         _options.put(key, value);
239     }
240 
241     public long getTimeout()
242     {
243         if (_options.containsKey(OPTIONS_CONNECT_TIMEOUT))
244         {
245             try
246             {
247                 return Long.parseLong(_options.get(OPTIONS_CONNECT_TIMEOUT));
248             }
249             catch (NumberFormatException nfe)
250             {
251                 //Do nothing as we will use the default below.
252             }
253         }
254 
255         return BrokerDetails.DEFAULT_CONNECT_TIMEOUT;
256     }
257     
258     public boolean useSSL()
259     {
260         if (_options.containsKey(ConnectionURL.OPTIONS_SSL))
261         {
262             return Boolean.parseBoolean(_options.get(ConnectionURL.OPTIONS_SSL));
263         }
264 
265         return false;
266     }    
267 
268     public void setTimeout(long timeout)
269     {
270         setProperty(OPTIONS_CONNECT_TIMEOUT, Long.toString(timeout));
271     }
272 
273     public SSLConfiguration getSSLConfiguration()
274     {
275         return _sslConfiguration;
276     }
277 
278     public void setSSLConfiguration(SSLConfiguration sslConfig)
279     {
280         _sslConfiguration = sslConfig;
281     }
282 
283     public String toString()
284     {
285         StringBuffer sb = new StringBuffer();
286 
287         sb.append(_transport);
288         sb.append("://");
289 
290         if (!(_transport.equalsIgnoreCase(VM)))
291         {
292             sb.append(_host);
293         }
294 
295         if (!(_transport.equalsIgnoreCase(SOCKET)))
296         {
297             sb.append(':');
298             sb.append(_port);
299         }
300 
301         sb.append(printOptionsURL());
302 
303         return sb.toString();
304     }
305 
306     public boolean equals(Object o)
307     {
308         if (!(instanceof BrokerDetails))
309         {
310             return false;
311         }
312 
313         BrokerDetails bd = (BrokerDetailso;
314 
315         return _host.equalsIgnoreCase(bd.getHost()) &&
316                (_port == bd.getPort()) &&
317                _transport.equalsIgnoreCase(bd.getTransport()) &&
318                compareSSLConfigurations(bd.getSSLConfiguration());
319         //todo do we need to compare all the options as well?
320     }
321 
322     private String printOptionsURL()
323     {
324         StringBuffer optionsURL = new StringBuffer();
325 
326         optionsURL.append('?');
327 
328         if (!(_options.isEmpty()))
329         {
330 
331             for (String key : _options.keySet())
332             {
333                 optionsURL.append(key);
334 
335                 optionsURL.append("='");
336 
337                 optionsURL.append(_options.get(key));
338 
339                 optionsURL.append("'");
340 
341                 optionsURL.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
342             }
343         }
344 
345         //removeKey the extra DEFAULT_OPTION_SEPERATOR or the '?' if there are no options
346         optionsURL.deleteCharAt(optionsURL.length() 1);
347 
348         return optionsURL.toString();
349     }
350 
351     // Do we need to do a more in-depth comparison?
352     private boolean compareSSLConfigurations(SSLConfiguration other)
353     {
354         boolean retval = false;
355         if (_sslConfiguration == null &&
356                 other == null)
357         {
358             retval = true;
359         }
360         else if (_sslConfiguration != null &&
361                 other != null)
362         {
363             retval = true;
364         }
365 
366         return retval;
367     }
368 
369     public static String checkTransport(String broker)
370     {
371         if ((!broker.contains("://")))
372         {
373             return "tcp://" + broker;
374         }
375         else
376         {
377             return broker;
378         }
379     }
380 
381     public Map<String, String> getProperties()
382     {
383         return _options;
384     }
385 
386     public void setProperties(Map<String, String> props)
387     {
388         _options = props;
389     }
390 }