@Path("auto-ack/{subscription-id}") @DELETE public void deleteSubscription( @Context UriInfo uriInfo, @PathParam("subscription-id") String consumerId) { ActiveMQRestLogger.LOGGER.debug("Handling DELETE request for \"" + uriInfo.getPath() + "\""); internalDeleteSubscription(consumerId); }
@Path("acknowledged/{consumer-id}") @HEAD public Response headAcknowledgedConsumer( @PathParam("consumer-id") String consumerId, @Context UriInfo uriInfo) throws Exception { ActiveMQRestLogger.LOGGER.debug("Handling HEAD request for \"" + uriInfo.getPath() + "\""); return internalHeadAcknowledgedConsumer(uriInfo, consumerId); }
@Path("auto-ack/{consumer-id}") @GET public Response getAutoAckSubscription( @PathParam("consumer-id") String consumerId, @Context UriInfo uriInfo) throws Exception { ActiveMQRestLogger.LOGGER.debug("Handling GET request for \"" + uriInfo.getPath() + "\""); return internalHeadAutoAckSubscription(uriInfo, consumerId); }
@Override public boolean testTimeout(String target, boolean autoShutdown) { QueueConsumer consumer = queueConsumers.get(target); Subscription subscription = (Subscription) consumer; if (consumer == null) return false; if (System.currentTimeMillis() - consumer.getLastPingTime() > subscription.getTimeout()) { ActiveMQRestLogger.LOGGER.shutdownRestSubscription(consumer.getId()); if (autoShutdown) { shutdown(consumer); } return true; } else { return false; } }
@POST public Response createSubscription( @FormParam("durable") @DefaultValue("false") boolean durable, @FormParam("autoAck") @DefaultValue("true") boolean autoAck, @FormParam("name") String subscriptionName, @FormParam("selector") String selector, @FormParam("delete-when-idle") Boolean destroyWhenIdle, @FormParam("idle-timeout") Long timeout, @Context UriInfo uriInfo) { ActiveMQRestLogger.LOGGER.debug("Handling POST request for \"" + uriInfo.getPath() + "\""); if (timeout == null) timeout = Long.valueOf(consumerTimeoutSeconds * 1000); boolean deleteWhenIdle = !durable; // default is true if non-durable if (destroyWhenIdle != null) deleteWhenIdle = destroyWhenIdle.booleanValue(); if (subscriptionName != null) { // see if this is a reconnect QueueConsumer consumer = queueConsumers.get(subscriptionName); if (consumer != null) { boolean acked = consumer instanceof AcknowledgedSubscriptionResource; acked = !acked; if (acked != autoAck) { throw new WebApplicationException( Response.status(412) .entity("Consumer already exists and ack-modes don't match.") .type("text/plain") .build()); } Subscription sub = (Subscription) consumer; if (sub.isDurable() != durable) { throw new WebApplicationException( Response.status(412) .entity("Consumer already exists and durability doesn't match.") .type("text/plain") .build()); } Response.ResponseBuilder builder = Response.noContent(); String pathToPullSubscriptions = uriInfo.getMatchedURIs().get(0); if (autoAck) { headAutoAckSubscriptionResponse(uriInfo, consumer, builder, pathToPullSubscriptions); consumer.setSessionLink( builder, uriInfo, pathToPullSubscriptions + "/auto-ack/" + consumer.getId()); } else { headAcknowledgedConsumerResponse(uriInfo, (AcknowledgedQueueConsumer) consumer, builder); consumer.setSessionLink( builder, uriInfo, pathToPullSubscriptions + "/acknowledged/" + consumer.getId()); } return builder.build(); } } else { subscriptionName = generateSubscriptionName(); } ClientSession session = null; try { // if this is not a reconnect, create the subscription queue if (!subscriptionExists(subscriptionName)) { session = sessionFactory.createSession(); if (durable) { session.createQueue(destination, subscriptionName, true); } else { session.createTemporaryQueue(destination, subscriptionName); } } QueueConsumer consumer = createConsumer(durable, autoAck, subscriptionName, selector, timeout, deleteWhenIdle); queueConsumers.put(consumer.getId(), consumer); serviceManager.getTimeoutTask().add(this, consumer.getId()); UriBuilder location = uriInfo.getAbsolutePathBuilder(); if (autoAck) location.path("auto-ack"); else location.path("acknowledged"); location.path(consumer.getId()); Response.ResponseBuilder builder = Response.created(location.build()); if (autoAck) { QueueConsumer.setConsumeNextLink( serviceManager.getLinkStrategy(), builder, uriInfo, uriInfo.getMatchedURIs().get(0) + "/auto-ack/" + consumer.getId(), "-1"); } else { AcknowledgedQueueConsumer.setAcknowledgeNextLink( serviceManager.getLinkStrategy(), builder, uriInfo, uriInfo.getMatchedURIs().get(0) + "/acknowledged/" + consumer.getId(), "-1"); } return builder.build(); } catch (ActiveMQException e) { throw new RuntimeException(e); } finally { if (session != null) { try { session.close(); } catch (ActiveMQException e) { } } } }
@Override public boolean push(ClientMessage message) { ActiveMQRestLogger.LOGGER.debug("Pushing " + message); String uri = createUri(message); for (int i = 0; i < registration.getMaxRetries(); i++) { long wait = registration.getRetryWaitMillis(); System.out.println("Creating request from " + uri); ClientRequest request = executor.createRequest(uri); request.followRedirects(false); ActiveMQRestLogger.LOGGER.debug("Created request " + request); for (XmlHttpHeader header : registration.getHeaders()) { ActiveMQRestLogger.LOGGER.debug( "Setting XmlHttpHeader: " + header.getName() + "=" + header.getValue()); request.header(header.getName(), header.getValue()); } HttpMessageHelper.buildMessage(message, request, contentType, jmsOptions); ClientResponse<?> res = null; try { ActiveMQRestLogger.LOGGER.debug(method + " " + uri); res = request.httpMethod(method); int status = res.getStatus(); ActiveMQRestLogger.LOGGER.debug("Status of push: " + status); if (status == 503) { String retryAfter = res.getStringHeaders().getFirst("Retry-After"); if (retryAfter != null) { wait = Long.parseLong(retryAfter) * 1000; } } else if (status == 307) { uri = res.getLocation().toString(); wait = 0; } else if ((status >= 200 && status < 299) || status == 303 || status == 304) { ActiveMQRestLogger.LOGGER.debug("Success"); return true; } else if (status >= 400) { switch (status) { case 400: // these usually mean the message you are trying to send is crap, let dead // letter logic take over case 411: case 412: case 413: case 414: case 415: case 416: throw new RuntimeException( "Something is wrong with the message, status returned: " + status + " for push registration of URI: " + uri); case 401: // might as well consider these critical failures and abort. Immediately // signal to disable push registration depending on config case 402: case 403: case 405: case 406: case 407: case 417: case 505: return false; case 404: // request timeout, gone, and not found treat as a retry case 408: case 409: case 410: break; default: // all 50x requests just retry (except 505) break; } } } catch (Exception e) { ActiveMQRestLogger.LOGGER.debug("failed to push message to " + uri, e); e.printStackTrace(); return false; } finally { if (res != null) res.releaseConnection(); } try { if (wait > 0) Thread.sleep(wait); } catch (InterruptedException e) { throw new RuntimeException("Interrupted"); } } return false; }