001/* 002 * Copyright 2009 Red Hat, Inc. 003 * Red Hat licenses this file to you under the Apache License, version 004 * 2.0 (the "License"); you may not use this file except in compliance 005 * with the License. You may obtain a copy of the License at 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * Unless required by applicable law or agreed to in writing, software 008 * distributed under the License is distributed on an "AS IS" BASIS, 009 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 010 * implied. See the License for the specific language governing 011 * permissions and limitations under the License. 012 */ 013package org.hornetq.api.core; 014 015import java.io.Serializable; 016import java.util.HashMap; 017import java.util.Map; 018 019import org.hornetq.utils.UUIDGenerator; 020 021/** 022 * A TransportConfiguration is used by a client to specify a connections to a server and its backup if one exists.<br><br> 023 * <p/> 024 * Typically the constructors take the class name and parameters for needed to create the connection. These will be 025 * different dependent on which connector is being used, i.e. Netty or InVM etc. For example:<br><br> 026 * <p/> 027 * <code> 028 * HashMap<String, Object> map = new HashMap<String, Object>();<br> 029 * map.put("host", "localhost");<br> 030 * map.put("port", 5445);<br> 031 * TransportConfiguration config = new TransportConfiguration(InVMConnectorFactory.class.getName(), map); <br> 032 * ClientSessionFactory sf = new ClientSessionFactoryImpl(config); <br> 033 * </code><br><br> 034 * 035 * @author <a href="mailto:tim.fox@jboss.com">Tim Fox</a> 036 */ 037public class TransportConfiguration implements Serializable 038{ 039 private static final long serialVersionUID = -3994528421527392679L; 040 041 private String name; 042 043 private String factoryClassName; 044 045 private Map<String, Object> params; 046 047 private static final byte TYPE_BOOLEAN = 0; 048 049 private static final byte TYPE_INT = 1; 050 051 private static final byte TYPE_LONG = 2; 052 053 private static final byte TYPE_STRING = 3; 054 055 /** 056 * Utility method for splitting a comma separated list of hosts 057 * 058 * @param commaSeparatedHosts the comma separated host string 059 * @return the hosts 060 */ 061 public static String[] splitHosts(final String commaSeparatedHosts) 062 { 063 if (commaSeparatedHosts == null) 064 { 065 return new String[0]; 066 } 067 String[] hosts = commaSeparatedHosts.split(","); 068 069 for (int i = 0; i < hosts.length; i++) 070 { 071 hosts[i] = hosts[i].trim(); 072 } 073 return hosts; 074 } 075 076 /** 077 * Creates a default TransportConfiguration with no configured transport. 078 */ 079 public TransportConfiguration() 080 { 081 } 082 083 /** 084 * Creates a TransportConfiguration with a specific name providing the class name of the {@link org.hornetq.spi.core.remoting.ConnectorFactory} 085 * and any parameters needed. 086 * 087 * @param className The class name of the ConnectorFactory 088 * @param params The parameters needed by the ConnectorFactory 089 * @param name The name of this TransportConfiguration 090 */ 091 public TransportConfiguration(final String className, final Map<String, Object> params, final String name) 092 { 093 factoryClassName = className; 094 095 this.params = params; 096 097 this.name = name; 098 } 099 100 /** 101 * Creates a TransportConfiguration providing the class name of the {@link org.hornetq.spi.core.remoting.ConnectorFactory} 102 * and any parameters needed. 103 * 104 * @param className The class name of the ConnectorFactory 105 * @param params The parameters needed by the ConnectorFactory 106 */ 107 public TransportConfiguration(final String className, final Map<String, Object> params) 108 { 109 this(className, params, UUIDGenerator.getInstance().generateStringUUID()); 110 } 111 112 /** 113 * Creates a TransportConfiguration providing the class name of the {@link org.hornetq.spi.core.remoting.ConnectorFactory} 114 * 115 * @param className The class name of the ConnectorFactory 116 */ 117 public TransportConfiguration(final String className) 118 { 119 this(className, new HashMap<String, Object>(), UUIDGenerator.getInstance().generateStringUUID()); 120 } 121 122 /** 123 * Returns the name of this TransportConfiguration. 124 * 125 * @return the name 126 */ 127 public String getName() 128 { 129 return name; 130 } 131 132 /** 133 * Returns the class name of ConnectorFactory being used by this TransportConfiguration 134 * 135 * @return The factory's class name 136 */ 137 public String getFactoryClassName() 138 { 139 return factoryClassName; 140 } 141 142 /** 143 * Returns any parameters set for this TransportConfiguration 144 * 145 * @return the parameters 146 */ 147 public Map<String, Object> getParams() 148 { 149 return params; 150 } 151 152 @Override 153 public int hashCode() 154 { 155 return factoryClassName.hashCode(); 156 } 157 158 @Override 159 public boolean equals(final Object other) 160 { 161 if (other instanceof TransportConfiguration == false) 162 { 163 return false; 164 } 165 166 TransportConfiguration kother = (TransportConfiguration) other; 167 168 if (factoryClassName.equals(kother.factoryClassName)) 169 { 170 if (params == null || params.isEmpty()) 171 { 172 return kother.params == null || kother.params.isEmpty(); 173 } 174 else 175 { 176 if (kother.params == null || kother.params.isEmpty()) 177 { 178 return false; 179 } 180 else if (params.size() == kother.params.size()) 181 { 182 for (Map.Entry<String, Object> entry : params.entrySet()) 183 { 184 Object thisVal = entry.getValue(); 185 186 Object otherVal = kother.params.get(entry.getKey()); 187 188 if (otherVal == null || !otherVal.equals(thisVal)) 189 { 190 return false; 191 } 192 } 193 return true; 194 } 195 else 196 { 197 return false; 198 } 199 } 200 } 201 else 202 { 203 return false; 204 } 205 } 206 207 @Override 208 public String toString() 209 { 210 StringBuilder str = new StringBuilder(replaceWildcardChars(factoryClassName)); 211 212 if (params != null) 213 { 214 if (!params.isEmpty()) 215 { 216 str.append("?"); 217 } 218 219 boolean first = true; 220 for (Map.Entry<String, Object> entry : params.entrySet()) 221 { 222 if (!first) 223 { 224 str.append("&"); 225 } 226 String encodedKey = replaceWildcardChars(entry.getKey()); 227 228 String val = entry.getValue().toString(); 229 String encodedVal = replaceWildcardChars(val); 230 231 str.append(encodedKey).append('=').append(encodedVal); 232 233 first = false; 234 } 235 } 236 237 return str.toString(); 238 } 239 240 /** 241 * Encodes this TransportConfiguration into a buffer. 242 * <p/> 243 * Note that this is only used internally HornetQ. 244 * 245 * @param buffer the buffer to encode into 246 */ 247 public void encode(final HornetQBuffer buffer) 248 { 249 buffer.writeString(name); 250 buffer.writeString(factoryClassName); 251 252 buffer.writeInt(params == null ? 0 : params.size()); 253 254 if (params != null) 255 { 256 for (Map.Entry<String, Object> entry : params.entrySet()) 257 { 258 buffer.writeString(entry.getKey()); 259 260 Object val = entry.getValue(); 261 262 if (val instanceof Boolean) 263 { 264 buffer.writeByte(TransportConfiguration.TYPE_BOOLEAN); 265 buffer.writeBoolean((Boolean) val); 266 } 267 else if (val instanceof Integer) 268 { 269 buffer.writeByte(TransportConfiguration.TYPE_INT); 270 buffer.writeInt((Integer) val); 271 } 272 else if (val instanceof Long) 273 { 274 buffer.writeByte(TransportConfiguration.TYPE_LONG); 275 buffer.writeLong((Long) val); 276 } 277 else if (val instanceof String) 278 { 279 buffer.writeByte(TransportConfiguration.TYPE_STRING); 280 buffer.writeString((String) val); 281 } 282 else 283 { 284 throw new IllegalArgumentException("Invalid type " + val); 285 } 286 } 287 } 288 } 289 290 /** 291 * Decodes this TransportConfiguration from a buffer. 292 * <p/> 293 * Note this is only used internally by HornetQ 294 * 295 * @param buffer the buffer to decode from 296 */ 297 public void decode(final HornetQBuffer buffer) 298 { 299 name = buffer.readString(); 300 factoryClassName = buffer.readString(); 301 302 int num = buffer.readInt(); 303 304 if (params == null) 305 { 306 if (num > 0) 307 { 308 params = new HashMap<String, Object>(); 309 } 310 } 311 else 312 { 313 params.clear(); 314 } 315 316 for (int i = 0; i < num; i++) 317 { 318 String key = buffer.readString(); 319 320 byte type = buffer.readByte(); 321 322 Object val; 323 324 switch (type) 325 { 326 case TYPE_BOOLEAN: 327 { 328 val = buffer.readBoolean(); 329 330 break; 331 } 332 case TYPE_INT: 333 { 334 val = buffer.readInt(); 335 336 break; 337 } 338 case TYPE_LONG: 339 { 340 val = buffer.readLong(); 341 342 break; 343 } 344 case TYPE_STRING: 345 { 346 val = buffer.readString(); 347 348 break; 349 } 350 default: 351 { 352 throw new IllegalArgumentException("Invalid type " + type); 353 } 354 } 355 356 params.put(key, val); 357 } 358 } 359 360 private String replaceWildcardChars(final String str) 361 { 362 return str.replace('.', '-'); 363 } 364}