View Javadoc

    1   /***
    2    *
    3    * Copyright 2004 Protique Ltd
    4    *
    5    * Licensed under the Apache License, Version 2.0 (the "License");
    6    * you may not use this file except in compliance with the License.
    7    * You may obtain a copy of the License at
    8    *
    9    * http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   **/
    18  package org.codehaus.activemq.broker.impl;
    19
    20  import org.apache.commons.logging.Log;
    21  import org.apache.commons.logging.LogFactory;
    22  import org.codehaus.activemq.broker.BrokerClient;
    23  import org.codehaus.activemq.broker.BrokerConnector;
    24  import org.codehaus.activemq.broker.BrokerContainer;
    25  import org.codehaus.activemq.message.*;
    26  import org.codehaus.activemq.transport.TransportChannel;
    27  import org.codehaus.activemq.transport.TransportChannelListener;
    28  import org.codehaus.activemq.transport.TransportServerChannel;
    29  import org.codehaus.activemq.transport.TransportServerChannelProvider;
    30
    31  import javax.jms.JMSException;
    32  import javax.jms.JMSSecurityException;
    33  import javax.transaction.xa.XAException;
    34  import java.net.URI;
    35  import java.net.URISyntaxException;
    36  import java.util.Collections;
    37  import java.util.HashMap;
    38  import java.util.Map;
    39
    40  /***
    41   * An implementation of the broker (the JMS server)
    42   *
    43   * @version $Revision: 1.8 $
    44   */
    45  public class BrokerConnectorImpl implements BrokerConnector, TransportChannelListener {
    46      private BrokerInfo brokerInfo;
    47
    48      private TransportServerChannel serverChannel;
    49      private Log log;
    50      private BrokerContainer container;
    51      private Map clients = Collections.synchronizedMap(new HashMap());
    52
    53      /***
    54       * Helper constructor for TCP protocol with the given bind address
    55       *
    56       * @param container
    57       * @param bindAddress
    58       * @throws JMSException
    59       */
    60      public BrokerConnectorImpl(BrokerContainer container, String bindAddress, WireFormat wireFormat) throws JMSException {
    61          this(container, createTransportServerChannel(wireFormat, bindAddress));
    62      }
    63
    64      /***
    65       * @param container
    66       * @param serverChannel
    67       */
    68      public BrokerConnectorImpl(BrokerContainer container, TransportServerChannel serverChannel) {
    69          assert container != null;
    70          this.brokerInfo = new BrokerInfo();
    71          this.brokerInfo.setBrokerName(container.getBroker().getBrokerName());
    72          this.log = LogFactory.getLog(getClass().getName());
    73          this.serverChannel = serverChannel;
    74          this.container = container;
    75          this.container.addConnector(this);
    76          serverChannel.setTransportChannelListener(this);
    77      }
    78
    79      /***
    80       * @return infomation about the Broker
    81       */
    82      public BrokerInfo getBrokerInfo() {
    83          return brokerInfo;
    84      }
    85
    86      /***
    87       * Get a hint about the broker capacity for more messages
    88       *
    89       * @return percentage value (0-100) about how much capacity the
    90       *         broker has
    91       */
    92      public int getBrokerCapacity() {
    93          return container.getBroker().getRoundedCapacity();
    94      }
    95
    96      /***
    97       * @return Get the server channel
    98       */
    99      public TransportServerChannel getServerChannel() {
    100         return serverChannel;
    101     }
    102
    103     /***
    104      * start the Broker
    105      *
    106      * @throws JMSException
    107      */
    108     public void start() throws JMSException {
    109         this.serverChannel.start();
    110         log.info("ActiveMQ connector started: " + this);
    111     }
    112
    113     /***
    114      * Stop the Broker
    115      *
    116      * @throws JMSException
    117      */
    118     public void stop() throws JMSException {
    119         this.serverChannel.stop();
    120         this.container.removeConnector(this);
    121         log.info("ActiveMQ connector stopped: " + this);
    122     }
    123
    124     /***
    125      * Register a Broker Client
    126      *
    127      * @param client
    128      * @param info   contains infomation about the Connection this Client represents
    129      * @throws JMSException
    130      * @throws javax.jms.InvalidClientIDException
    131      *                              if the JMS client specifies an invalid or duplicate client ID.
    132      * @throws JMSSecurityException if client authentication fails due to an invalid user name or password.
    133      */
    134     public void registerClient(BrokerClient client, ConnectionInfo info) throws JMSException {
    135         this.container.registerConnection(client, info);
    136     }
    137
    138     /***
    139      * Deregister a Broker Client
    140      *
    141      * @param client
    142      * @param info
    143      * @throws JMSException if some internal error occurs
    144      */
    145     public void deregisterClient(BrokerClient client, ConnectionInfo info) throws JMSException {
    146         this.container.deregisterConnection(client, info);
    147     }
    148
    149     /***
    150      * Registers a MessageConsumer
    151      *
    152      * @param client
    153      * @param info
    154      * @throws JMSException
    155      * @throws JMSSecurityException if client authentication fails for the Destination the Consumer applies for
    156      */
    157     public void registerMessageConsumer(BrokerClient client, ConsumerInfo info) throws JMSException {
    158         if (info.getDestination() == null) {
    159             throw new JMSException("No Destination specified on consumerInfo for client: " + client + " info: " + info);
    160         }
    161         this.container.registerMessageConsumer(client, info);
    162
    163     }
    164
    165     /***
    166      * De-register a MessageConsumer from the Broker
    167      *
    168      * @param client
    169      * @param info
    170      * @throws JMSException
    171      */
    172     public void deregisterMessageConsumer(BrokerClient client, ConsumerInfo info) throws JMSException {
    173         this.container.deregisterMessageConsumer(client, info);
    174     }
    175
    176     /***
    177      * Registers a MessageProducer
    178      *
    179      * @param client
    180      * @param info
    181      * @throws JMSException
    182      * @throws JMSSecurityException if client authentication fails for the Destination the Consumer applies for
    183      */
    184     public void registerMessageProducer(BrokerClient client, ProducerInfo info) throws JMSException {
    185         this.container.registerMessageProducer(client, info);
    186     }
    187
    188     /***
    189      * De-register a MessageProducer from the Broker
    190      *
    191      * @param client
    192      * @param info
    193      * @throws JMSException
    194      */
    195     public void deregisterMessageProducer(BrokerClient client, ProducerInfo info) throws JMSException {
    196         this.container.deregisterMessageProducer(client, info);
    197     }
    198
    199     /***
    200      * Register a client-side Session (used for Monitoring)
    201      *
    202      * @param client
    203      * @param info
    204      * @throws JMSException
    205      */
    206     public void registerSession(BrokerClient client, SessionInfo info) throws JMSException {
    207         this.container.registerSession(client, info);
    208     }
    209
    210     /***
    211      * De-register a client-side Session from the Broker (used for monitoring)
    212      *
    213      * @param client
    214      * @param info
    215      * @throws JMSException
    216      */
    217     public void deregisterSession(BrokerClient client, SessionInfo info) throws JMSException {
    218         this.container.deregisterSession(client, info);
    219     }
    220
    221     /***
    222      * Start a transaction from the Client session
    223      *
    224      * @param client
    225      * @param transactionId
    226      * @throws JMSException
    227      */
    228     public void startTransaction(BrokerClient client, String transactionId) throws JMSException {
    229         this.container.startTransaction(client, transactionId);
    230     }
    231
    232     /***
    233      * Rollback a transacton
    234      *
    235      * @param client
    236      * @param transactionId
    237      * @throws JMSException
    238      */
    239     public void rollbackTransaction(BrokerClient client, String transactionId) throws JMSException {
    240         this.container.rollbackTransaction(client, transactionId);
    241     }
    242
    243     /***
    244      * Commit a transaction
    245      *
    246      * @param client
    247      * @param transactionId
    248      * @throws JMSException
    249      */
    250     public void commitTransaction(BrokerClient client, String transactionId) throws JMSException {
    251         this.container.commitTransaction(client, transactionId);
    252     }
    253
    254     /***
    255      * send message with a transaction context
    256      *
    257      * @param client
    258      * @param transactionId
    259      * @param message
    260      * @throws JMSException
    261      */
    262     public void sendTransactedMessage(BrokerClient client, String transactionId, ActiveMQMessage message)
    263             throws JMSException {
    264         this.container.sendTransactedMessage(client, transactionId, message);
    265     }
    266
    267     /***
    268      * Acknowledge receipt of a message within a transaction context
    269      *
    270      * @param client
    271      * @param transactionId
    272      * @param ack
    273      * @throws JMSException
    274      */
    275     public void acknowledgeTransactedMessage(BrokerClient client, String transactionId, MessageAck ack)
    276             throws JMSException {
    277         this.container.acknowledgeTransactedMessage(client, transactionId, ack);
    278     }
    279
    280     /***
    281      * Send a non-transacted message to the Broker
    282      *
    283      * @param client
    284      * @param message
    285      * @throws JMSException
    286      */
    287     public void sendMessage(BrokerClient client, ActiveMQMessage message) throws JMSException {
    288         this.container.sendMessage(client, message);
    289     }
    290
    291     /***
    292      * Acknowledge reciept of a message
    293      *
    294      * @param client
    295      * @param ack
    296      * @throws JMSException
    297      */
    298     public void acknowledgeMessage(BrokerClient client, MessageAck ack) throws JMSException {
    299         this.container.acknowledgeMessage(client, ack);
    300     }
    301
    302     /***
    303      * Command to delete a durable topic subscription
    304      *
    305      * @param client
    306      * @param ds
    307      * @throws JMSException
    308      */
    309     public void durableUnsubscribe(BrokerClient client, DurableUnsubscribe ds) throws JMSException {
    310         this.container.durableUnsubscribe(client, ds);
    311     }
    312
    313
    314     /***
    315      * @param channel - client to add
    316      */
    317     public void addClient(TransportChannel channel) {
    318         try {
    319             BrokerClient client = new BrokerClientImpl();
    320             client.initialize(this, channel);
    321             if (log.isDebugEnabled()) {
    322                 log.debug("Starting new client: " + client);
    323             }
    324             channel.start();
    325             clients.put(channel, client);
    326         }
    327         catch (JMSException e) {
    328             log.error("Failed to add client due to: " + e, e);
    329         }
    330     }
    331
    332     /***
    333      * @param channel - client to remove
    334      */
    335     public void removeClient(TransportChannel channel) {
    336         BrokerClient client = (BrokerClient) clients.remove(channel);
    337         if (client != null) {
    338             if (log.isDebugEnabled()) {
    339                 log.debug("Client leaving client: " + client);
    340             }
    341
    342             // we may have already been closed, if not then lets simulate a normal shutdown
    343             client.cleanUp();
    344         }
    345         else {
    346             // might have got a duplicate callback
    347             log.warn("No such client for channel: " + channel);
    348         }
    349     }
    350
    351     /***
    352      * @return the BrokerContainer for this Connector
    353      */
    354     public BrokerContainer getBrokerContainer() {
    355         return this.container;
    356     }
    357
    358
    359     // Implementation methods
    360     //-------------------------------------------------------------------------
    361     /***
    362      * Factory method ot create a transport channel
    363      *
    364      * @param bindAddress
    365      * @return @throws JMSException
    366      * @throws JMSException
    367      */
    368     protected static TransportServerChannel createTransportServerChannel(WireFormat wireFormat, String bindAddress) throws JMSException {
    369         URI url;
    370         try {
    371             url = new URI(bindAddress);
    372         }
    373         catch (URISyntaxException e) {
    374             JMSException jmsEx = new JMSException("Badly formated bindAddress: " + e.getMessage());
    375             jmsEx.setLinkedException(e);
    376             throw jmsEx;
    377         }
    378         return TransportServerChannelProvider.create(wireFormat, url);
    379     }
    380
    381     /***
    382      * Start an XA transaction.
    383      *
    384      * @see org.codehaus.activemq.broker.BrokerConnector#startTransaction(org.codehaus.activemq.broker.BrokerClient, org.codehaus.activemq.message.ActiveMQXid)
    385      */
    386     public void startTransaction(BrokerClient client, ActiveMQXid xid) throws XAException {
    387         this.container.startTransaction(client, xid);
    388     }
    389
    390     /***
    391      * Gets the prepared XA transactions.
    392      *
    393      * @see org.codehaus.activemq.broker.BrokerConnector#getPreparedTransactions(org.codehaus.activemq.broker.BrokerClient)
    394      */
    395     public ActiveMQXid[] getPreparedTransactions(BrokerClient client) throws XAException {
    396         return this.container.getPreparedTransactions(client);
    397     }
    398
    399     /***
    400      * Prepare an XA transaction.
    401      *
    402      * @see org.codehaus.activemq.broker.BrokerConnector#prepareTransaction(org.codehaus.activemq.broker.BrokerClient, org.codehaus.activemq.message.ActiveMQXid)
    403      */
    404     public int prepareTransaction(BrokerClient client, ActiveMQXid xid) throws XAException {
    405         return this.container.prepareTransaction(client, xid);
    406     }
    407
    408     /***
    409      * Rollback an XA transaction.
    410      *
    411      * @see org.codehaus.activemq.broker.BrokerConnector#rollbackTransaction(org.codehaus.activemq.broker.BrokerClient, org.codehaus.activemq.message.ActiveMQXid)
    412      */
    413     public void rollbackTransaction(BrokerClient client, ActiveMQXid xid) throws XAException {
    414         this.container.rollbackTransaction(client, xid);
    415     }
    416
    417     /***
    418      * Commit an XA transaction.
    419      *
    420      * @see org.codehaus.activemq.broker.BrokerConnector#commitTransaction(org.codehaus.activemq.broker.BrokerClient, org.codehaus.activemq.message.ActiveMQXid, boolean)
    421      */
    422     public void commitTransaction(BrokerClient client, ActiveMQXid xid, boolean onePhase) throws XAException {
    423         this.container.commitTransaction(client, xid, onePhase);
    424     }
    425
    426     /***
    427      * @see org.codehaus.activemq.broker.BrokerConnector#getResourceManagerId(org.codehaus.activemq.broker.BrokerClient)
    428      */
    429     public String getResourceManagerId(BrokerClient client) {
    430         // TODO: I think we need to return a better (more unique) RM id.
    431         return getBrokerInfo().getBrokerName();
    432     }
    433
    434 }