public String getEncodedLocalName() { return Codec.encode(localName); }
public PersistentMessageFinder(String topicName, ManagedCursor cursor) { this.topicName = topicName; this.cursor = cursor; this.subName = Codec.decode(cursor.getName()); }
private CompletableFuture<? extends Subscription> getDurableSubscription(String subscriptionName) { CompletableFuture<Subscription> subscriptionFuture = new CompletableFuture<>(); ledger.asyncOpenCursor(Codec.encode(subscriptionName), new OpenCursorCallback() { @Override public void openCursorComplete(ManagedCursor cursor, Object ctx) { if (log.isDebugEnabled()) { log.debug("[{}][{}] Opened cursor", topic, subscriptionName); } subscriptionFuture.complete(subscriptions.computeIfAbsent(subscriptionName, name -> new PersistentSubscription(PersistentTopic.this, subscriptionName, cursor))); } @Override public void openCursorFailed(ManagedLedgerException exception, Object ctx) { log.warn("[{}] Failed to create subscription for {}", topic, subscriptionName); USAGE_COUNT_UPDATER.decrementAndGet(PersistentTopic.this); subscriptionFuture.completeExceptionally(new PersistenceException(exception)); } }, null); return subscriptionFuture; }
@POST @Path("/{property}/{cluster}/{namespace}/{destination}/subscription/{subName}/expireMessages/{expireTimeInSeconds}") @ApiOperation(value = "Expire messages on a topic subscription.") @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), @ApiResponse(code = 404, message = "Topic or subscription does not exist") }) public void expireTopicMessages(@PathParam("property") String property, @PathParam("cluster") String cluster, @PathParam("namespace") String namespace, @PathParam("destination") @Encoded String destination, @PathParam("subName") String subName, @PathParam("expireTimeInSeconds") int expireTimeInSeconds, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { destination = decode(destination); expireMessages(property, cluster, namespace, destination, subName, expireTimeInSeconds, authoritative); }
@Override public CompletableFuture<Void> skipMessagesAsync(String destination, String subName, long numMessages) { DestinationName ds = validateTopic(destination); String encodedSubName = Codec.encode(subName); return asyncPostRequest( persistentTopics.path(ds.getNamespace()).path(ds.getEncodedLocalName()).path("subscription") .path(encodedSubName).path("skip").path(String.valueOf(numMessages)), Entity.entity("", MediaType.APPLICATION_JSON)); }
@GET @Path("/{property}/{cluster}/{namespace}/{destination}/partitions") @ApiOperation(value = "Get partitioned topic metadata.") @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) public PartitionedTopicMetadata getPartitionedMetadata(@PathParam("property") String property, @PathParam("cluster") String cluster, @PathParam("namespace") String namespace, @PathParam("destination") @Encoded String destination, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { destination = decode(destination); return getPartitionedTopicMetadata(property, cluster, namespace, destination, authoritative); }
@Override public CompletableFuture<Void> expireMessagesAsync(String destination, String subName, long expireTimeInSeconds) { DestinationName ds = validateTopic(destination); String encodedSubName = Codec.encode(subName); return asyncPostRequest( persistentTopics.path(ds.getNamespace()).path(ds.getEncodedLocalName()).path("subscription") .path(encodedSubName).path("expireMessages").path(String.valueOf(expireTimeInSeconds)), Entity.entity("", MediaType.APPLICATION_JSON)); }
public List<String> getListOfDestinations(String property, String cluster, String namespace) throws Exception { List<String> destinations = Lists.newArrayList(); // For every topic there will be a managed ledger created. try { String path = String.format("/managed-ledgers/%s/%s/%s/persistent", property, cluster, namespace); LOG.debug("Getting children from managed-ledgers now: {}", path); for (String destination : pulsar.getLocalZkCacheService().managedLedgerListCache().get(path)) { destinations.add(String.format("persistent://%s/%s/%s/%s", property, cluster, namespace, Codec.decode(destination))); } } catch (KeeperException.NoNodeException e) { // NoNode means there are no persistent topics for this namespace } destinations.sort(null); return destinations; }
@Override public CompletableFuture<Void> resetCursorAsync(String destination, String subName, long timestamp) { DestinationName ds = validateTopic(destination); String encodedSubName = Codec.encode(subName); return asyncPostRequest( persistentTopics.path(ds.getNamespace()).path(ds.getEncodedLocalName()).path("subscription") .path(encodedSubName).path("resetcursor").path(String.valueOf(timestamp)), Entity.entity("", MediaType.APPLICATION_JSON)); }
@GET @Path("{property}/{cluster}/{namespace}/{destination}/stats") @ApiOperation(value = "Get the stats for the topic.") @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), @ApiResponse(code = 404, message = "Topic does not exist") }) public PersistentTopicStats getStats(@PathParam("property") String property, @PathParam("cluster") String cluster, @PathParam("namespace") String namespace, @PathParam("destination") @Encoded String destination, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { destination = decode(destination); DestinationName dn = DestinationName.get(domain(), property, cluster, namespace, destination); validateAdminAndClientPermission(dn); validateDestinationOwnership(dn, authoritative); PersistentTopic topic = getTopicReference(dn); return topic.getStats(); }
@Override public void resetCursor(String destination, String subName, long timestamp) throws PulsarAdminException { try { DestinationName ds = validateTopic(destination); String encodedSubName = Codec.encode(subName); request( persistentTopics.path(ds.getNamespace()).path(ds.getEncodedLocalName()).path("subscription") .path(encodedSubName).path("resetcursor").path(String.valueOf(timestamp))).post( Entity.entity("", MediaType.APPLICATION_JSON), ErrorData.class); } catch (Exception e) { throw getApiException(e); } }
@GET @Path("{property}/{cluster}/{namespace}/{destination}/internalStats") @ApiOperation(value = "Get the internal stats for the topic.") @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), @ApiResponse(code = 404, message = "Topic does not exist") }) public PersistentTopicInternalStats getInternalStats(@PathParam("property") String property, @PathParam("cluster") String cluster, @PathParam("namespace") String namespace, @PathParam("destination") @Encoded String destination, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { destination = decode(destination); DestinationName dn = DestinationName.get(domain(), property, cluster, namespace, destination); validateAdminAndClientPermission(dn); validateDestinationOwnership(dn, authoritative); PersistentTopic topic = getTopicReference(dn); return topic.getInternalStats(); }
@Override public CompletableFuture<Void> skipAllMessagesAsync(String destination, String subName) { DestinationName ds = validateTopic(destination); String encodedSubName = Codec.encode(subName); return asyncPostRequest( persistentTopics.path(ds.getNamespace()).path(ds.getEncodedLocalName()).path("subscription") .path(encodedSubName).path("skip_all"), Entity.entity("", MediaType.APPLICATION_JSON)); }
@PathParam("destination") @Encoded String destination) { destination = decode(destination); validateAdminAccessOnProperty(property);
CompletableFuture<Void> unsubscribeFuture = new CompletableFuture<>(); ledger.asyncDeleteCursor(Codec.encode(subscriptionName), new DeleteCursorCallback() { @Override public void deleteCursorComplete(Object ctx) {
@POST @Path("/{property}/{cluster}/{namespace}/{destination}/terminate") @ApiOperation(value = "Terminate a topic. A topic that is terminated will not accept any more " + "messages to be published and will let consumer to drain existing messages in backlog") @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), @ApiResponse(code = 404, message = "Topic does not exist") }) public MessageId terminate(@PathParam("property") String property, @PathParam("cluster") String cluster, @PathParam("namespace") String namespace, @PathParam("destination") @Encoded String destination, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { destination = decode(destination); DestinationName dn = DestinationName.get(domain(), property, cluster, namespace, destination); PartitionedTopicMetadata partitionMetadata = getPartitionedTopicMetadata(property, cluster, namespace, destination, authoritative); if (partitionMetadata.partitions > 0) { throw new RestException(Status.METHOD_NOT_ALLOWED, "Termination of a partitioned topic is not allowed"); } validateAdminOperationOnDestination(dn, authoritative); PersistentTopic topic = getTopicReference(dn); try { return topic.terminate().get(); } catch (Exception exception) { log.error("[{}] Failed to terminated topic {}", clientAppId(), dn, exception); throw new RestException(exception); } }
@Override public CompletableFuture<Void> deleteSubscriptionAsync(String destination, String subName) { DestinationName ds = validateTopic(destination); String encodedSubName = Codec.encode(subName); return asyncDeleteRequest(persistentTopics.path(ds.getNamespace()).path(ds.getEncodedLocalName()) .path("subscription").path(encodedSubName)); }
@PathParam("namespace") String namespace, @PathParam("destination") @Encoded String destination, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { destination = decode(destination); DestinationName dn = DestinationName.get(domain(), property, cluster, namespace, destination); validateAdminOperationOnDestination(dn, authoritative);
private CompletableFuture<Message> peekNthMessage(String destination, String subName, int messagePosition) { DestinationName ds = validateTopic(destination); String encodedSubName = Codec.encode(subName); final CompletableFuture<Message> future = new CompletableFuture<Message>(); asyncGetRequest(persistentTopics.path(ds.getNamespace()).path(ds.getEncodedLocalName()).path("subscription") .path(encodedSubName).path("position").path(String.valueOf(messagePosition)), new InvocationCallback<Response>() { @Override public void completed(Response response) { try { Message msg = getMessageFromHttpResponse(response); future.complete(msg); } catch (Exception e) { future.completeExceptionally(getApiException(e)); } } @Override public void failed(Throwable throwable) { future.completeExceptionally(getApiException(throwable.getCause())); } }); return future; }
String partitionedTopicPath = path(PARTITIONED_TOPIC_PATH_ZNODE, property, cluster, namespace, domain()); List<String> destinations = globalZk().getChildren(partitionedTopicPath, false); partitionedTopics = destinations.stream().map(s -> String.format("persistent://%s/%s/%s/%s", property, cluster, namespace, decode(s))).collect( Collectors.toList()); } catch (KeeperException.NoNodeException e) {