org.apache.activemq.artemis.rest.queue.QueueConsumer Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.activemq.artemis.rest.queue;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
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.apache.activemq.artemis.api.core.client.ClientSession;
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
import org.apache.activemq.artemis.jms.client.ConnectionFactoryOptions;
import org.apache.activemq.artemis.rest.ActiveMQRestLogger;
import org.apache.activemq.artemis.rest.util.Constants;
import org.apache.activemq.artemis.rest.util.LinkStrategy;
import org.apache.activemq.artemis.utils.SelectorTranslator;
/**
* Auto-acknowledged consumer
*/
public class QueueConsumer {
protected ClientSessionFactory factory;
protected ClientSession session;
protected ClientConsumer consumer;
protected String destination;
protected boolean closed;
protected String id;
protected long lastPing = System.currentTimeMillis();
protected DestinationServiceManager serviceManager;
protected boolean autoAck = true;
protected String selector;
/**
* token used to create consume-next links
*/
protected long previousIndex = -1;
protected ConsumedMessage lastConsumed;
public long getConsumeIndex() {
if (lastConsumed == null)
return -1;
return lastConsumed.getMessageID();
}
public DestinationServiceManager getServiceManager() {
return serviceManager;
}
public void setServiceManager(DestinationServiceManager serviceManager) {
this.serviceManager = serviceManager;
}
public long getLastPingTime() {
return lastPing;
}
protected void ping(long offsetSecs) {
lastPing = System.currentTimeMillis() + (offsetSecs * 1000);
}
public QueueConsumer(ClientSessionFactory factory,
String destination,
String id,
DestinationServiceManager serviceManager,
String selector) throws ActiveMQException {
this.factory = factory;
this.destination = destination;
this.id = id;
this.serviceManager = serviceManager;
this.selector = selector;
createSession();
}
public String getId() {
return id;
}
public boolean isClosed() {
return closed;
}
public synchronized void shutdown() {
if (closed)
return;
closed = true;
lastConsumed = null;
previousIndex = -2;
try {
consumer.close();
ActiveMQRestLogger.LOGGER.debug("Closed consumer: " + consumer);
} catch (Exception e) {
}
try {
session.close();
ActiveMQRestLogger.LOGGER.debug("Closed session: " + session);
} catch (Exception e) {
}
session = null;
consumer = null;
}
@Path("consume-next{index}")
@POST
public synchronized Response poll(@HeaderParam(Constants.WAIT_HEADER) @DefaultValue("0") long wait,
@PathParam("index") long index,
@Context UriInfo info) {
ActiveMQRestLogger.LOGGER.debug("Handling POST request for \"" + info.getRequestUri() + "\"");
if (closed) {
UriBuilder builder = info.getBaseUriBuilder();
builder.path(info.getMatchedURIs().get(1)).path("consume-next");
String uri = builder.build().toString();
// redirect to another consume-next
return Response.status(307).location(URI.create(uri)).build();
}
return checkIndexAndPoll(wait, info, info.getMatchedURIs().get(1), index);
}
protected Response checkIndexAndPoll(long wait, UriInfo info, String basePath, long index) {
ping(wait);
if (lastConsumed == null && index > 0) {
return Response.status(412).entity("You are using an old consume-next link and are out of sync with the JMS session on the server").type("text/plain").build();
}
if (lastConsumed != null) {
if (index == previousIndex) {
String token = Long.toString(lastConsumed.getMessageID());
return getMessageResponse(lastConsumed, info, basePath, token).build();
}
if (index != lastConsumed.getMessageID()) {
return Response.status(412).entity("You are using an old consume-next link and are out of sync with the JMS session on the server").type("text/plain").build();
}
}
try {
return pollWithIndex(wait, info, basePath, index);
} finally {
ping(0); // ping again as we don't want wait time included in timeout.
}
}
protected Response pollWithIndex(long wait, UriInfo info, String basePath, long index) {
try {
ClientMessage message = receive(wait);
if (message == null) {
Response.ResponseBuilder builder = Response.status(503).entity("Timed out waiting for message receive.").type("text/plain");
setPollTimeoutLinks(info, basePath, builder, Long.toString(index));
return builder.build();
}
previousIndex = index;
lastConsumed = ConsumedMessage.createConsumedMessage(message, this.getJmsOptions());
String token = Long.toString(lastConsumed.getMessageID());
Response response = getMessageResponse(lastConsumed, info, basePath, token).build();
if (autoAck)
message.acknowledge();
return response;
} catch (Exception e) {
Response errorResponse = Response.serverError().entity(e.getMessage()).status(Response.Status.INTERNAL_SERVER_ERROR).build();
return errorResponse;
}
}
protected void createSession() throws ActiveMQException {
session = factory.createSession(true, true, 0);
ActiveMQRestLogger.LOGGER.debug("Created session: " + session);
if (selector == null) {
consumer = session.createConsumer(destination);
} else {
consumer = session.createConsumer(destination, SelectorTranslator.convertToActiveMQFilterString(selector));
}
ActiveMQRestLogger.LOGGER.debug("Created consumer: " + consumer);
session.start();
}
protected ClientMessage receiveFromConsumer(long timeoutSecs) throws Exception {
ClientMessage m = null;
if (timeoutSecs <= 0) {
m = consumer.receive(1);
} else {
m = consumer.receive(timeoutSecs * 1000);
}
ActiveMQRestLogger.LOGGER.debug("Returning message " + m + " from consumer: " + consumer);
return m;
}
protected ClientMessage receive(long timeoutSecs) throws Exception {
return receiveFromConsumer(timeoutSecs);
}
protected void setPollTimeoutLinks(UriInfo info, String basePath, Response.ResponseBuilder builder, String index) {
setSessionLink(builder, info, basePath);
setConsumeNextLink(serviceManager.getLinkStrategy(), builder, info, basePath, index);
}
protected Response.ResponseBuilder getMessageResponse(ConsumedMessage msg,
UriInfo info,
String basePath,
String index) {
Response.ResponseBuilder responseBuilder = Response.ok();
setMessageResponseLinks(info, basePath, responseBuilder, index);
msg.build(responseBuilder);
return responseBuilder;
}
protected void setMessageResponseLinks(UriInfo info,
String basePath,
Response.ResponseBuilder responseBuilder,
String index) {
setConsumeNextLink(serviceManager.getLinkStrategy(), responseBuilder, info, basePath, index);
setSessionLink(responseBuilder, info, basePath);
}
public static void setConsumeNextLink(LinkStrategy linkStrategy,
Response.ResponseBuilder response,
UriInfo info,
String basePath,
String index) {
if (index == null)
throw new IllegalArgumentException("index cannot be null");
UriBuilder builder = info.getBaseUriBuilder();
builder.path(basePath).path("consume-next" + index);
String uri = builder.build().toString();
linkStrategy.setLinkHeader(response, "consume-next", "consume-next", uri, MediaType.APPLICATION_FORM_URLENCODED);
}
public void setSessionLink(Response.ResponseBuilder response, UriInfo info, String basePath) {
UriBuilder builder = info.getBaseUriBuilder();
builder.path(basePath);
String uri = builder.build().toString();
serviceManager.getLinkStrategy().setLinkHeader(response, "consumer", "consumer", uri, MediaType.APPLICATION_XML);
}
public ConnectionFactoryOptions getJmsOptions() {
return serviceManager.getJmsOptions();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy