Drizzled Public API Documentation

rabbitmq_handler.cc
00001 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2010 Marcus Eriksson
00005  *
00006  *  Authors:
00007  *
00008  *  Marcus Eriksson <krummas@gmail.com>
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00023  */
00024 
00025 #include <config.h>
00026 
00027 #include <drizzled/gettext.h>
00028 
00029 #include "rabbitmq_handler.h"
00030 
00031 using namespace std;
00032 
00033 namespace drizzle_plugin
00034 {
00035 
00036 RabbitMQHandler::RabbitMQHandler(const std::string &rabbitMQHost, 
00037                                  const in_port_t rabbitMQPort, 
00038                                  const std::string &rabbitMQUsername, 
00039                                  const std::string &rabbitMQPassword, 
00040                                  const std::string &rabbitMQVirtualhost, 
00041          const std::string &rabbitMQExchange, 
00042          const std::string &rabbitMQRoutingKey) 
00043   throw(rabbitmq_handler_exception) :
00044     rabbitmqConnection(amqp_new_connection()),
00045     hostname(rabbitMQHost),
00046     port(rabbitMQPort),
00047     username(rabbitMQUsername),
00048     password(rabbitMQPassword),
00049     virtualhost(rabbitMQVirtualhost),
00050     exchange(rabbitMQExchange), 
00051     routingKey(rabbitMQRoutingKey)
00052 {
00053   pthread_mutex_init(&publishLock, NULL);
00054   connect();
00055 }
00056 
00057 RabbitMQHandler::~RabbitMQHandler()
00058 {
00059   pthread_mutex_destroy(&publishLock);
00060   disconnect();
00061 }
00062 
00063 void RabbitMQHandler::publish(void *message, 
00064                               const int length)
00065 throw(rabbitmq_handler_exception)
00066 {
00067   pthread_mutex_lock(&publishLock);
00068   amqp_bytes_t b;
00069   b.bytes= message;
00070   b.len= length;
00071   
00072   if (amqp_basic_publish(rabbitmqConnection,
00073                          1,
00074                          amqp_cstring_bytes(exchange.c_str()),
00075                          amqp_cstring_bytes(routingKey.c_str()),
00076                          0,
00077                          0,
00078                          NULL,
00079                          b) < 0)
00080   {
00081     pthread_mutex_unlock(&publishLock);
00082     throw rabbitmq_handler_exception("Could not publish message");
00083   }
00084   pthread_mutex_unlock(&publishLock);
00085 
00086 }
00087 
00088 void RabbitMQHandler::reconnect() throw(rabbitmq_handler_exception)
00089 {
00090   disconnect();
00091   connect();
00092 }
00093 
00094 void RabbitMQHandler::disconnect() throw(rabbitmq_handler_exception) 
00095 {
00096   try
00097   {
00098     handleAMQPError(amqp_channel_close(rabbitmqConnection, 
00099                1, 
00100                AMQP_REPLY_SUCCESS),
00101         "close channel");
00102     handleAMQPError(amqp_connection_close(rabbitmqConnection, 
00103             AMQP_REPLY_SUCCESS),
00104         "close connection");
00105     amqp_destroy_connection(rabbitmqConnection);
00106   }
00107   catch(exception& e) {} // do not throw in destructorn 
00108   close(sockfd);
00109 }
00110 
00111 void RabbitMQHandler::connect() throw(rabbitmq_handler_exception) {
00112   sockfd = amqp_open_socket(hostname.c_str(), port);
00113   if(sockfd < 0) 
00114   {
00115     throw rabbitmq_handler_exception(_("Could not open socket, is rabbitmq running?"));
00116   }
00117   amqp_set_sockfd(rabbitmqConnection, sockfd);
00118   /* login to rabbitmq, handleAMQPError throws exception if there is a problem */
00119   handleAMQPError(amqp_login(rabbitmqConnection, 
00120                              virtualhost.c_str(), 
00121                              0, 
00122                              131072, 
00123                              0, 
00124                              AMQP_SASL_METHOD_PLAIN, 
00125                              username.c_str(), 
00126                              password.c_str()), 
00127                   "rabbitmq login");
00128   /* open the channel */
00129   amqp_channel_open(rabbitmqConnection, 1);
00130   handleAMQPError(amqp_get_rpc_reply(rabbitmqConnection), "RPC Reply");
00131   amqp_table_t empty_table = { 0, NULL }; // for users of old librabbitmq users - amqp_empty_table did not exist
00132   amqp_exchange_declare(rabbitmqConnection, 1, amqp_cstring_bytes(exchange.c_str()), amqp_cstring_bytes("fanout"), 0, 0, empty_table);
00133   handleAMQPError(amqp_get_rpc_reply(rabbitmqConnection), "RPC Reply");
00134 }
00135 
00136 void RabbitMQHandler::handleAMQPError(amqp_rpc_reply_t x, string context) throw(rabbitmq_handler_exception)
00137 {
00138   string errorMessage("");
00139   switch (x.reply_type) {
00140   case AMQP_RESPONSE_NORMAL:
00141     break;
00142   case AMQP_RESPONSE_NONE:
00143     errorMessage.assign("No response in ");
00144     errorMessage.append(context);
00145     throw rabbitmq_handler_exception(errorMessage);
00146   case AMQP_RESPONSE_LIBRARY_EXCEPTION:
00147   case AMQP_RESPONSE_SERVER_EXCEPTION:
00148     switch (x.reply.id) {      
00149     case AMQP_CONNECTION_CLOSE_METHOD:
00150       errorMessage.assign("Connection closed in ");
00151       errorMessage.append(context);
00152       throw rabbitmq_handler_exception(errorMessage);
00153     case AMQP_CHANNEL_CLOSE_METHOD:
00154       errorMessage.assign("Channel closed in ");
00155       errorMessage.append(context);
00156       throw rabbitmq_handler_exception(errorMessage);
00157     default:
00158       errorMessage.assign("Unknown error in ");
00159       errorMessage.append(context);
00160       throw rabbitmq_handler_exception(errorMessage);
00161     }
00162   }
00163 }
00164 
00165 } /* namespace drizzle_plugin */