use of co.cask.cdap.api.messaging.TopicNotFoundException in project cdap by caskdata.
the class LevelDBMetadataTable method getMetadata.
@Override
public TopicMetadata getMetadata(TopicId topicId) throws IOException, TopicNotFoundException {
try {
byte[] value = levelDB.get(MessagingUtils.toMetadataRowKey(topicId));
if (value == null) {
throw new TopicNotFoundException(topicId.getNamespace(), topicId.getTopic());
}
Map<String, String> properties = GSON.fromJson(Bytes.toString(value), MAP_TYPE);
TopicMetadata topicMetadata = new TopicMetadata(topicId, properties);
if (!topicMetadata.exists()) {
throw new TopicNotFoundException(topicId.getNamespace(), topicId.getTopic());
}
return topicMetadata;
} catch (DBException e) {
// DBException is a RuntimeException. Turn it to IOException so that it forces caller to handle it.
throw new IOException(e);
}
}
use of co.cask.cdap.api.messaging.TopicNotFoundException in project cdap by caskdata.
the class LevelDBMetadataTable method updateTopic.
@Override
public void updateTopic(TopicMetadata topicMetadata) throws TopicNotFoundException, IOException {
try {
TopicId topicId = topicMetadata.getTopicId();
byte[] key = MessagingUtils.toMetadataRowKey(topicId);
synchronized (this) {
byte[] tableValue = levelDB.get(key);
if (tableValue == null) {
throw new TopicNotFoundException(topicId.getNamespace(), topicId.getTopic());
}
Map<String, String> oldProperties = GSON.fromJson(Bytes.toString(tableValue), MAP_TYPE);
TopicMetadata oldMetadata = new TopicMetadata(topicId, oldProperties);
if (!oldMetadata.exists()) {
throw new TopicNotFoundException(topicId.getNamespace(), topicId.getTopic());
}
TreeMap<String, String> newProperties = new TreeMap<>(topicMetadata.getProperties());
newProperties.put(TopicMetadata.GENERATION_KEY, Integer.toString(oldMetadata.getGeneration()));
levelDB.put(key, Bytes.toBytes(GSON.toJson(newProperties, MAP_TYPE)), WRITE_OPTIONS);
}
} catch (DBException e) {
throw new IOException(e);
}
}
use of co.cask.cdap.api.messaging.TopicNotFoundException in project cdap by caskdata.
the class MessagingHttpServiceTest method testBasicPubSub.
@Test
public void testBasicPubSub() throws Exception {
TopicId topicId = new NamespaceId("ns1").topic("testBasicPubSub");
// Publish to a non-existing topic should get not found exception
try {
client.publish(StoreRequestBuilder.of(topicId).addPayloads("a").build());
Assert.fail("Expected TopicNotFoundException");
} catch (TopicNotFoundException e) {
// Expected
}
// Consume from a non-existing topic should get not found exception
try {
client.prepareFetch(topicId).fetch();
Assert.fail("Expected TopicNotFoundException");
} catch (TopicNotFoundException e) {
// Expected
}
client.createTopic(new TopicMetadata(topicId));
// Publish a non-transactional message with empty payload should result in failure
try {
client.publish(StoreRequestBuilder.of(topicId).build());
Assert.fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// Expected
}
// Publish a non-tx message, no RollbackDetail is returned
Assert.assertNull(client.publish(StoreRequestBuilder.of(topicId).addPayloads("m0", "m1").build()));
// Publish a transactional message, a RollbackDetail should be returned
RollbackDetail rollbackDetail = client.publish(StoreRequestBuilder.of(topicId).addPayloads("m2").setTransaction(1L).build());
Assert.assertNotNull(rollbackDetail);
// Rollback the published message
client.rollback(topicId, rollbackDetail);
// Fetch messages non-transactionally (should be able to read all the messages since rolled back messages
// are still visible until ttl kicks in)
List<RawMessage> messages = new ArrayList<>();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).fetch()) {
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(3, messages.size());
for (int i = 0; i < 3; i++) {
Assert.assertEquals("m" + i, Bytes.toString(messages.get(i).getPayload()));
}
// Consume transactionally. It should get only m0 and m1 since m2 has been rolled back
List<RawMessage> txMessages = new ArrayList<>();
Transaction transaction = new Transaction(3L, 3L, new long[0], new long[] { 2L }, 2L);
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartTime(0).setTransaction(transaction).fetch()) {
Iterators.addAll(txMessages, iterator);
}
Assert.assertEquals(2, txMessages.size());
for (int i = 0; i < 2; i++) {
Assert.assertEquals("m" + i, Bytes.toString(messages.get(i).getPayload()));
}
// Fetch again from a given message offset exclusively.
// Expects one message to be fetched
byte[] startMessageId = messages.get(1).getId();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).fetch()) {
// It should have only one message (m2)
Assert.assertTrue(iterator.hasNext());
RawMessage msg = iterator.next();
Assert.assertEquals("m2", Bytes.toString(msg.getPayload()));
}
// Fetch again from the last message offset exclusively
// Expects no message to be fetched
startMessageId = messages.get(2).getId();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).fetch()) {
Assert.assertFalse(iterator.hasNext());
}
// Fetch with start time. It should get both m0 and m1 since they are published in the same request, hence
// having the same publish time
startMessageId = messages.get(1).getId();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartTime(new MessageId(startMessageId).getPublishTimestamp()).setLimit(2).fetch()) {
messages.clear();
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(2, messages.size());
for (int i = 0; i < 2; i++) {
Assert.assertEquals("m" + i, Bytes.toString(messages.get(i).getPayload()));
}
// Publish 2 messages, one transactionally, one without transaction
client.publish(StoreRequestBuilder.of(topicId).addPayloads("m3").setTransaction(2L).build());
client.publish(StoreRequestBuilder.of(topicId).addPayloads("m4").build());
// Consume without transactional, it should see m2, m3 and m4
startMessageId = messages.get(1).getId();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).fetch()) {
messages.clear();
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(3, messages.size());
for (int i = 0; i < 3; i++) {
Assert.assertEquals("m" + (i + 2), Bytes.toString(messages.get(i).getPayload()));
}
// Consume using a transaction that doesn't have tx = 2L visible. It should get no message as it should block on m3
transaction = new Transaction(3L, 3L, new long[0], new long[] { 2L }, 2L);
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).setTransaction(transaction).fetch()) {
Assert.assertFalse(iterator.hasNext());
}
// Consume using a transaction that has tx = 2L in the invalid list. It should skip m3 and got m4
transaction = new Transaction(3L, 3L, new long[] { 2L }, new long[0], 0L);
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).setTransaction(transaction).fetch()) {
messages.clear();
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(1, messages.size());
Assert.assertEquals("m4", Bytes.toString(messages.get(0).getPayload()));
// Consume using a transaction that has tx = 2L committed. It should get m3 and m4
transaction = new Transaction(3L, 3L, new long[0], new long[0], 0L);
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).setTransaction(transaction).fetch()) {
messages.clear();
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(2, messages.size());
for (int i = 0; i < 2; i++) {
Assert.assertEquals("m" + (i + 3), Bytes.toString(messages.get(i).getPayload()));
}
client.deleteTopic(topicId);
}
use of co.cask.cdap.api.messaging.TopicNotFoundException in project cdap by caskdata.
the class MessagingHttpServiceTest method testMetadataEndpoints.
@Test
public void testMetadataEndpoints() throws Exception {
NamespaceId nsId = new NamespaceId("metadata");
TopicId topic1 = nsId.topic("t1");
TopicId topic2 = nsId.topic("t2");
// Get a non exist topic should fail
try {
client.getTopic(topic1);
Assert.fail("Expected TopicNotFoundException");
} catch (TopicNotFoundException e) {
// Expected
}
// Create the topic t1
client.createTopic(new TopicMetadata(topic1));
// Create an existing topic should fail
try {
client.createTopic(new TopicMetadata(topic1));
Assert.fail("Expect TopicAlreadyExistsException");
} catch (TopicAlreadyExistsException e) {
// Expected
}
// Get the topic properties. Verify TTL is the same as the default one
Assert.assertEquals(cConf.getInt(Constants.MessagingSystem.TOPIC_DEFAULT_TTL_SECONDS), client.getTopic(topic1).getTTL());
// Update the topic t1 with new TTL
client.updateTopic(new TopicMetadata(topic1, "ttl", "5"));
// Get the topic t1 properties. Verify TTL is updated
Assert.assertEquals(5, client.getTopic(topic1).getTTL());
// Try to add another topic t2 with invalid ttl, it should fail
try {
client.createTopic(new TopicMetadata(topic2, "ttl", "xyz"));
Assert.fail("Expect BadRequestException");
} catch (IllegalArgumentException e) {
// Expected
}
// Add topic t2 with valid ttl
client.createTopic(new TopicMetadata(topic2, "ttl", "5"));
// Get the topic t2 properties. It should have TTL set based on what provided
Assert.assertEquals(5, client.getTopic(topic2).getTTL());
// Listing topics under namespace ns1
List<TopicId> topics = client.listTopics(nsId);
Assert.assertEquals(Arrays.asList(topic1, topic2), topics);
// Delete both topics
client.deleteTopic(topic1);
client.deleteTopic(topic2);
// Delete a non exist topic should fail
try {
client.deleteTopic(topic1);
Assert.fail("Expect TopicNotFoundException");
} catch (TopicNotFoundException e) {
// Expected
}
// Update a non exist topic should fail
try {
client.updateTopic(new TopicMetadata(topic1));
Assert.fail("Expect TopicNotFoundException");
} catch (TopicNotFoundException e) {
// Expected
}
// Listing topics under namespace ns1 again, it should be empty
Assert.assertTrue(client.listTopics(nsId).isEmpty());
}
use of co.cask.cdap.api.messaging.TopicNotFoundException in project cdap by caskdata.
the class ClientMessagingService method rollback.
@Override
public void rollback(TopicId topicId, RollbackDetail rollbackDetail) throws TopicNotFoundException, IOException {
ByteBuffer requestBody = (rollbackDetail instanceof ClientRollbackDetail) ? ByteBuffer.wrap(((ClientRollbackDetail) rollbackDetail).getEncoded()) : encodeRollbackDetail(rollbackDetail);
HttpRequest httpRequest = remoteClient.requestBuilder(HttpMethod.POST, createTopicPath(topicId) + "/rollback").addHeader(HttpHeaders.CONTENT_TYPE, "avro/binary").withBody(requestBody).build();
HttpResponse response = remoteClient.execute(httpRequest);
if (response.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
throw new TopicNotFoundException(topicId.getNamespace(), topicId.getTopic());
}
handleError(response, "Failed to rollback message in topic " + topicId + " with rollback detail " + rollbackDetail);
}
Aggregations