org.apache.activemq.artemis.rest.queue.AcknowledgedQueueConsumer 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.FormParam;
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.rest.ActiveMQRestLogger;
import org.apache.activemq.artemis.rest.util.Constants;
import org.apache.activemq.artemis.rest.util.LinkStrategy;
public class AcknowledgedQueueConsumer extends QueueConsumer {
protected long counter;
protected String startup = Long.toString(System.currentTimeMillis());
protected volatile Acknowledgement ack;
public AcknowledgedQueueConsumer(ClientSessionFactory factory,
String destination,
String id,
DestinationServiceManager serviceManager,
String selector) throws ActiveMQException {
super(factory, destination, id, serviceManager, selector);
autoAck = false;
}
public synchronized Acknowledgement getAck() {
return ack;
}
@Override
@Path("acknowledge-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.getPath() + "\"");
if (closed) {
UriBuilder builder = info.getBaseUriBuilder();
String path = info.getMatchedURIs().get(1);
builder.path(path).path("acknowledge-next");
String uri = builder.build().toString();
// redirect to another acknowledge-next
return Response.status(307).location(URI.create(uri)).build();
}
return checkIndexAndPoll(wait, info, info.getMatchedURIs().get(1), index);
}
@Override
public synchronized void shutdown() {
super.shutdown();
if (ack != null) {
ack = null;
}
}
@Path("acknowledgement/{ackToken}")
@POST
public synchronized Response acknowledge(@PathParam("ackToken") String ackToken,
@FormParam("acknowledge") boolean doAcknowledge,
@Context UriInfo uriInfo) {
ActiveMQRestLogger.LOGGER.debug("Handling POST request for \"" + uriInfo.getPath() + "\"");
ping(0);
String basePath = uriInfo.getMatchedURIs().get(1);
if (closed) {
Response.ResponseBuilder builder = Response.status(Response.Status.PRECONDITION_FAILED).entity("Could not acknowledge message, it was probably requeued from a timeout").type("text/plain");
setAcknowledgeLinks(uriInfo, basePath, builder, "-1");
return builder.build();
}
if (ack == null || !ack.getAckToken().equals(ackToken)) {
Response.ResponseBuilder builder = Response.status(Response.Status.PRECONDITION_FAILED).entity("Could not acknowledge message, it was probably requeued from a timeout or you have an old link").type("text/plain");
setAcknowledgeLinks(uriInfo, basePath, builder, "-1");
return builder.build();
}
// clear indexes as we know the client got the message and won't send a duplicate ack-next
previousIndex = -2;
lastConsumed = null;
if (ack.wasSet() && doAcknowledge != ack.isAcknowledged()) {
StringBuilder msg = new StringBuilder("Could not ");
if (doAcknowledge == false)
msg.append("un");
msg.append("acknowledge message because it has already been ");
if (doAcknowledge == true)
msg.append("un");
msg.append("acknowledged");
Response.ResponseBuilder builder = Response.status(Response.Status.PRECONDITION_FAILED).entity(msg.toString()).type("text/plain");
setAcknowledgeLinks(uriInfo, basePath, builder, "-1");
return builder.build();
}
if (ack.wasSet() && doAcknowledge == ack.isAcknowledged()) {
Response.ResponseBuilder builder = Response.noContent();
setAcknowledgeLinks(uriInfo, basePath, builder, "-1");
return builder.build();
}
if (doAcknowledge) {
try {
ack.acknowledge();
//System.out.println("Acknowledge message: " + ack.getMessage());
ack.getMessage().acknowledge();
} catch (ActiveMQException e) {
throw new RuntimeException(e);
}
} else {
ack.unacknowledge();
unacknowledge();
}
Response.ResponseBuilder builder = Response.noContent();
setAcknowledgeLinks(uriInfo, basePath, builder, "-1");
return builder.build();
}
@Override
protected ClientMessage receive(long timeoutSecs) throws Exception {
ClientMessage msg = super.receive(timeoutSecs);
return msg;
}
@Override
protected ClientMessage receiveFromConsumer(long timeoutSecs) throws Exception {
ClientMessage message = super.receiveFromConsumer(timeoutSecs);
if (message != null) {
ack = new Acknowledgement((counter++) + startup, message);
//System.out.println("---> Setting ack: " + ack.getAckToken());
}
return message;
}
protected String getAckToken() {
return ack.getAckToken();
}
protected void unacknowledge() {
// we close current session so that message is redelivered
// for temporary queues/topics, create a new session before closing old so we don't lose the temporary topic/queue
ClientConsumer old = consumer;
ClientSession oldSession = session;
try {
createSession();
} catch (Exception e) {
shutdown();
throw new RuntimeException(e);
} finally {
try {
old.close();
} catch (ActiveMQException e) {
}
try {
oldSession.close();
} catch (ActiveMQException e) {
}
}
}
protected void setAcknowledgeLinks(UriInfo uriInfo,
String basePath,
Response.ResponseBuilder builder,
String index) {
setAcknowledgeNextLink(serviceManager.getLinkStrategy(), builder, uriInfo, basePath, index);
setSessionLink(builder, uriInfo, basePath);
}
@Override
protected void setMessageResponseLinks(UriInfo info,
String basePath,
Response.ResponseBuilder builder,
String index) {
setAcknowledgementLink(builder, info, basePath);
setSessionLink(builder, info, basePath);
}
@Override
protected void setPollTimeoutLinks(UriInfo info, String basePath, Response.ResponseBuilder builder, String index) {
setAcknowledgeNextLink(serviceManager.getLinkStrategy(), builder, info, basePath, index);
setSessionLink(builder, info, basePath);
}
public void setAcknowledgementLink(Response.ResponseBuilder response, UriInfo info, String basePath) {
UriBuilder builder = info.getBaseUriBuilder();
builder.path(basePath).path("acknowledgement").path(getAckToken());
String uri = builder.build().toString();
serviceManager.getLinkStrategy().setLinkHeader(response, "acknowledgement", "acknowledgement", uri, MediaType.APPLICATION_FORM_URLENCODED);
}
public static void setAcknowledgeNextLink(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("acknowledge-next" + index);
String uri = builder.build().toString();
linkStrategy.setLinkHeader(response, "acknowledge-next", "acknowledge-next", uri, MediaType.APPLICATION_FORM_URLENCODED);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy