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 */
013 package org.hornetq.api.core;
014
015 import java.io.Serializable;
016 import java.util.HashMap;
017 import java.util.Map;
018
019 import 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 */
037 public 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 }