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 url) throws 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(URLSyntaxException) uris;
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 (!(o instanceof BrokerDetails))
309 {
310 return false;
311 }
312
313 BrokerDetails bd = (BrokerDetails) o;
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 }
|