    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    }