/*
* Copyright (c) 2016 Red Hat, Inc. and/or its affiliates.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cheng Fang - Initial API and implementation
*/
package org.jberet.support.io;
import java.io.Serializable;
import javax.batch.api.BatchProperty;
import javax.batch.api.chunk.ItemReader;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
import org.apache.activemq.artemis.api.core.client.ClientMessage;
import org.jberet.support._private.SupportLogger;
/**
* An implementation of {@code javax.batch.api.chunk.ItemReader} that reads data items from a Artemis address.
* It handles the following types of Artemis messages:
* <p>
* <ul>
* <li>if {@link #beanType} is set to {@code org.apache.activemq.artemis.api.core.client.ClientMessage}, the incoming message
* is immediately returned as is from {@link #readItem()}
* <li>if the message type is {@code org.apache.activemq.artemis.api.core.client.ClientMessage#TEXT_TYPE}, the string text is
* returned from {@link #readItem()};
* <li>otherwise, a byte array is retrieved from the message body buffer, deserialize to an object, and returned
* from {@link #readItem()}
* </ul>
* <p>
* This reader ends when either of the following occurs:
* <p>
* <ul>
* <li>{@link #receiveTimeout} (in milliseconds) has elapsed when trying to receive a message from the destination;
* <li>the size of the incoming message body is 0;
* </ul>
* <p>
*
* @see ArtemisItemWriter
* @see ArtemisItemReaderWriterBase
* @see JmsItemReader
* @since 1.3.0
*/
@Named
@Dependent
public class ArtemisItemReader extends ArtemisItemReaderWriterBase implements ItemReader {
/**
* The number of milliseconds a Artemis {@code ClientConsumer} blocks until a message arrives. Optional property, and
* defaults to 0, which means it blocks indefinitely.
*/
@Inject
@BatchProperty
protected long receiveTimeout;
/**
* The fully-qualified class name of the data item to be returned from {@link #readItem()} method. Optional
* property and defaults to null. If it is specified, its valid value is:
* <p>
* <ul>
* <li>{@code org.apache.activemq.artemis.api.core.client.ClientMessage}: an incoming Artemis message is returned as is.
* </ul>
* <p>
* When this property is not specified, {@link #readItem()} method returns an object whose actual type is
* determined by the incoming Artemis message type.
*/
@Inject
@BatchProperty
protected Class beanType;
protected ClientConsumer consumer;
@Override
public void open(final Serializable checkpoint) throws Exception {
super.open(checkpoint);
consumer = session.createConsumer(queueName);
session.start();
}
@Override
public Object readItem() throws Exception {
final Object result;
final ClientMessage message = consumer.receive(receiveTimeout);
if (message == null) { //no more messages after receiveTimeout
return null;
}
final int bodySize = message.getBodySize();
if (bodySize == 0) {
return null;
}
if (beanType == ClientMessage.class) {
return message;
}
final byte messageType = message.getType();
final byte[] bytes = new byte[bodySize];
message.getBodyBuffer().readBytes(bytes);
if (messageType == ClientMessage.TEXT_TYPE) {
result = new String(bytes);
} else {
result = bytesToSerializableObject(bytes);
if (!skipBeanValidation) {
ItemReaderWriterBase.validate(result);
}
}
return result;
}
@Override
public void close() {
super.close();
if (consumer != null) {
try {
consumer.close();
} catch (final ActiveMQException e) {
SupportLogger.LOGGER.tracef(e, "Failed to close Artemis consumer %s%n", consumer);
}
consumer = null;
}
}
}