/*
* Copyright (c) 2017, 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.wso2.carbon.transport.jms.receiver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.carbon.messaging.CarbonMessageProcessor;
import org.wso2.carbon.transport.jms.exception.JMSConnectorException;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Session;
/**
* Message receiver for receiving JMS messages synchronously.
*/
public class JMSMessageReceiver implements Runnable, Thread.UncaughtExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(JMSMessageReceiver.class);
private MessageConsumer messageConsumer;
private JMSMessageHandler messageHandler;
private boolean running = true;
/**
* The message receive wait timeout.
*/
private long timeout = -1;
/**
* Initializes the message receiver with consumer and session details.
*
* @param messageProcessor The message processor which is going to process the received messages
* @param serviceId Id of the service that is interested in particular destination
* @param session The session that is used to create the consumer
* @param messageConsumer The {@link MessageConsumer} to use to receive messages
* @throws JMSConnectorException Throws if message handler cannot be initialized
*/
JMSMessageReceiver(CarbonMessageProcessor messageProcessor, String serviceId, Session session,
MessageConsumer messageConsumer) throws JMSConnectorException {
this.messageConsumer = messageConsumer;
messageHandler = new JMSMessageHandler(messageProcessor, serviceId, session);
}
/**
* The runnable implementation which is invoked when message receiving is started.
*/
@Override
public void run() {
while (running) {
try {
Message message;
if (timeout < 0) {
message = messageConsumer.receive();
} else {
message = messageConsumer.receive(timeout);
}
if (message != null) {
messageHandler.handle(message);
} else {
logger.warn("Timeout expired or message consumer is concurrently closed");
}
} catch (JMSException e) {
throw new RuntimeException("Error receiving messages", e);
} catch (JMSConnectorException e) {
// We're only logging the error here since we do not want to stop message receiving due to this
logger.error("Error handling the received message", e);
}
}
}
/**
* Start message receiving via message consumer.
*/
public void receive() {
startReceiverThread();
}
/**
* Start receiving messages with a wait timeout.
*
* @param timeout Message receive wait timeout
*/
public void receive(long timeout) {
this.timeout = timeout;
startReceiverThread();
}
/**
* Start message receiving thread.
*/
private void startReceiverThread() {
Thread thread = new Thread(this, "JMSMessageReceiverThread");
thread.setUncaughtExceptionHandler(this);
thread.start();
}
/**
* Any exception that was thrown when receiving messages from the receiver thread will be reported here.
*
* @param thread The thread which produced the error
* @param error The error
*/
@Override
public void uncaughtException(Thread thread, Throwable error) {
running = false;
logger.error("Unexpected error occurred while receiving messages", error);
}
}