/**
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.synapse.message.store.impl.rabbitmq;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.MessageProperties;
import com.rabbitmq.client.impl.AMQBasicProperties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.MessageContext;
import org.apache.synapse.message.MessageProducer;
import org.apache.synapse.message.store.impl.commons.MessageConverter;
import org.apache.synapse.message.store.impl.commons.StorableMessage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
public class RabbitMQProducer implements MessageProducer {
private static final Log logger = LogFactory.getLog(RabbitMQProducer.class.getName());
private static final int DEFAULT_PRIORITY = 0;
/**
* Connection to the RabbitMQ broker. Passed reference from Store *
*/
private Connection connection;
/**
* Reference of the store *
*/
private RabbitMQStore store;
/**
* Message storing queue name *
*/
private String queueName;
/**
* Message exchange *
*/
private String exchangeName;
private boolean isInitialized = false;
private boolean isConnectionError = false;
/**
* ID of the MessageProducer *
*/
private String idString;
public RabbitMQProducer(RabbitMQStore store) {
if (store == null) {
logger.error("Cannot initialize.");
return;
}
this.store = store;
isInitialized = true;
}
public void setQueueName(String queueName) {
this.queueName = queueName;
}
public void setExchangeName(String exchangeName) {
this.exchangeName = exchangeName;
}
public void setConnection(Connection connection) {
this.connection = connection;
}
public void setId(int id) {
idString = "[" + store.getName() + "-P-" + id + "]";
}
public boolean storeMessage(MessageContext synCtx) {
if (synCtx == null) {
return false;
}
if (connection == null) {
if (logger.isDebugEnabled()) {
logger.error(getId() + " cannot proceed. RabbitMQ Connection is null.");
}
logger.warn(getId() + ". Ignored MessageID : " + synCtx.getMessageID());
return false;
}
StorableMessage message = MessageConverter.toStorableMessage(synCtx);
boolean error = false;
Throwable throwable = null;
Channel channel = null;
try {
//Serializing message
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutput objOut = new ObjectOutputStream(os);
objOut.writeObject(message);
byte[] byteForm = os.toByteArray();
objOut.close();
os.close();
//building AMQP message
AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties().builder();
builder.messageId(synCtx.getMessageID());
builder.deliveryMode(MessageProperties.MINIMAL_PERSISTENT_BASIC.getDeliveryMode());
builder.priority(message.getPriority(DEFAULT_PRIORITY));
channel = connection.createChannel();
if (exchangeName == null) {
channel.basicPublish("", queueName, builder.build(), byteForm);
} else {
channel.basicPublish(exchangeName, queueName, builder.build(), byteForm);
}
} catch (IOException e) {
throwable = e;
error = true;
isConnectionError = true;
} catch (Throwable t) {
throwable = t;
error = true;
} finally {
if (channel != null && channel.isOpen())
try {
channel.close();
} catch (IOException e) {
logger.error(
"Error when closing connection" + synCtx.getMessageID() + ". " + e);
}
}
if (error) {
String errorMsg = getId() + ". Ignored MessageID : " + synCtx.getMessageID()
+ ". Could not store message to store ["
+ store.getName() + "]. Error:" + throwable.getLocalizedMessage();
logger.error(errorMsg, throwable);
store.closeProducerConnection();
connection = null;
if (logger.isDebugEnabled()) {
logger.debug(getId() + ". Ignored MessageID : " + synCtx.getMessageID());
}
return false;
}
if (logger.isDebugEnabled()) {
logger.debug(getId() + ". Stored MessageID : " + synCtx.getMessageID());
}
store.enqueued();
return true;
}
/**
* Used to close the channel opened in this object instance.
* This should be called after the end of each call on storeMessage method
* But instead of this, finally block is used in storeMethod to close the channels
*/
public boolean cleanup() {
return store.cleanup(null, false);
}
public boolean isInitialized() {
return isInitialized;
}
public String getId() {
return idString;
}
}