feat: Add Official Microsoft & Gemini Skills (845+ Total)
🚀 Impact Significantly expands the capabilities of **Antigravity Awesome Skills** by integrating official skill collections from **Microsoft** and **Google Gemini**. This update increases the total skill count to **845+**, making the library even more comprehensive for AI coding assistants. ✨ Key Changes 1. New Official Skills - **Microsoft Skills**: Added a massive collection of official skills from [microsoft/skills](https://github.com/microsoft/skills). - Includes Azure, .NET, Python, TypeScript, and Semantic Kernel skills. - Preserves the original directory structure under `skills/official/microsoft/`. - Includes plugin skills from the `.github/plugins` directory. - **Gemini Skills**: Added official Gemini API development skills under `skills/gemini-api-dev/`. 2. New Scripts & Tooling - **`scripts/sync_microsoft_skills.py`**: A robust synchronization script that: - Clones the official Microsoft repository. - Preserves the original directory heirarchy. - Handles symlinks and plugin locations. - Generates attribution metadata. - **`scripts/tests/inspect_microsoft_repo.py`**: Debug tool to inspect the remote repository structure. - **`scripts/tests/test_comprehensive_coverage.py`**: Verification script to ensure 100% of skills are captured during sync. 3. Core Improvements - **`scripts/generate_index.py`**: Enhanced frontmatter parsing to safely handle unquoted values containing `@` symbols and commas (fixing issues with some Microsoft skill descriptions). - **`package.json`**: Added `sync:microsoft` and `sync:all-official` scripts for easy maintenance. 4. Documentation - Updated `README.md` to reflect the new skill counts (845+) and added Microsoft/Gemini to the provider list. - Updated `CATALOG.md` and `skills_index.json` with the new skills. 🧪 Verification - Ran `scripts/tests/test_comprehensive_coverage.py` to verify all Microsoft skills are detected. - Validated `generate_index.py` fixes by successfully indexing the new skills.
This commit is contained in:
305
skills/official/microsoft/java/messaging/eventgrid/SKILL.md
Normal file
305
skills/official/microsoft/java/messaging/eventgrid/SKILL.md
Normal file
@@ -0,0 +1,305 @@
|
||||
---
|
||||
name: azure-eventgrid-java
|
||||
description: Build event-driven applications with Azure Event Grid SDK for Java. Use when publishing events, implementing pub/sub patterns, or integrating with Azure services via events.
|
||||
package: com.azure:azure-messaging-eventgrid
|
||||
---
|
||||
|
||||
# Azure Event Grid SDK for Java
|
||||
|
||||
Build event-driven applications using the Azure Event Grid SDK for Java.
|
||||
|
||||
## Installation
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-messaging-eventgrid</artifactId>
|
||||
<version>4.27.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Client Creation
|
||||
|
||||
### EventGridPublisherClient
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventgrid.EventGridPublisherClient;
|
||||
import com.azure.messaging.eventgrid.EventGridPublisherClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
|
||||
// With API Key
|
||||
EventGridPublisherClient<EventGridEvent> client = new EventGridPublisherClientBuilder()
|
||||
.endpoint("<topic-endpoint>")
|
||||
.credential(new AzureKeyCredential("<access-key>"))
|
||||
.buildEventGridEventPublisherClient();
|
||||
|
||||
// For CloudEvents
|
||||
EventGridPublisherClient<CloudEvent> cloudClient = new EventGridPublisherClientBuilder()
|
||||
.endpoint("<topic-endpoint>")
|
||||
.credential(new AzureKeyCredential("<access-key>"))
|
||||
.buildCloudEventPublisherClient();
|
||||
```
|
||||
|
||||
### With DefaultAzureCredential
|
||||
|
||||
```java
|
||||
import com.azure.identity.DefaultAzureCredentialBuilder;
|
||||
|
||||
EventGridPublisherClient<EventGridEvent> client = new EventGridPublisherClientBuilder()
|
||||
.endpoint("<topic-endpoint>")
|
||||
.credential(new DefaultAzureCredentialBuilder().build())
|
||||
.buildEventGridEventPublisherClient();
|
||||
```
|
||||
|
||||
### Async Client
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventgrid.EventGridPublisherAsyncClient;
|
||||
|
||||
EventGridPublisherAsyncClient<EventGridEvent> asyncClient = new EventGridPublisherClientBuilder()
|
||||
.endpoint("<topic-endpoint>")
|
||||
.credential(new AzureKeyCredential("<access-key>"))
|
||||
.buildEventGridEventPublisherAsyncClient();
|
||||
```
|
||||
|
||||
## Event Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `EventGridEvent` | Azure Event Grid native schema |
|
||||
| `CloudEvent` | CNCF CloudEvents 1.0 specification |
|
||||
| `BinaryData` | Custom schema events |
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Publish EventGridEvent
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventgrid.EventGridEvent;
|
||||
import com.azure.core.util.BinaryData;
|
||||
|
||||
EventGridEvent event = new EventGridEvent(
|
||||
"resource/path", // subject
|
||||
"MyApp.Events.OrderCreated", // eventType
|
||||
BinaryData.fromObject(new OrderData("order-123", 99.99)), // data
|
||||
"1.0" // dataVersion
|
||||
);
|
||||
|
||||
client.sendEvent(event);
|
||||
```
|
||||
|
||||
### Publish Multiple Events
|
||||
|
||||
```java
|
||||
List<EventGridEvent> events = Arrays.asList(
|
||||
new EventGridEvent("orders/1", "Order.Created",
|
||||
BinaryData.fromObject(order1), "1.0"),
|
||||
new EventGridEvent("orders/2", "Order.Created",
|
||||
BinaryData.fromObject(order2), "1.0")
|
||||
);
|
||||
|
||||
client.sendEvents(events);
|
||||
```
|
||||
|
||||
### Publish CloudEvent
|
||||
|
||||
```java
|
||||
import com.azure.core.models.CloudEvent;
|
||||
import com.azure.core.models.CloudEventDataFormat;
|
||||
|
||||
CloudEvent cloudEvent = new CloudEvent(
|
||||
"/myapp/orders", // source
|
||||
"order.created", // type
|
||||
BinaryData.fromObject(orderData), // data
|
||||
CloudEventDataFormat.JSON // dataFormat
|
||||
);
|
||||
cloudEvent.setSubject("orders/12345");
|
||||
cloudEvent.setId(UUID.randomUUID().toString());
|
||||
|
||||
cloudClient.sendEvent(cloudEvent);
|
||||
```
|
||||
|
||||
### Publish CloudEvents Batch
|
||||
|
||||
```java
|
||||
List<CloudEvent> cloudEvents = Arrays.asList(
|
||||
new CloudEvent("/app", "event.type1", BinaryData.fromString("data1"), CloudEventDataFormat.JSON),
|
||||
new CloudEvent("/app", "event.type2", BinaryData.fromString("data2"), CloudEventDataFormat.JSON)
|
||||
);
|
||||
|
||||
cloudClient.sendEvents(cloudEvents);
|
||||
```
|
||||
|
||||
### Async Publishing
|
||||
|
||||
```java
|
||||
asyncClient.sendEvent(event)
|
||||
.subscribe(
|
||||
unused -> System.out.println("Event sent successfully"),
|
||||
error -> System.err.println("Error: " + error.getMessage())
|
||||
);
|
||||
|
||||
// With multiple events
|
||||
asyncClient.sendEvents(events)
|
||||
.doOnSuccess(unused -> System.out.println("All events sent"))
|
||||
.doOnError(error -> System.err.println("Failed: " + error))
|
||||
.block(); // Block if needed
|
||||
```
|
||||
|
||||
### Custom Event Data Class
|
||||
|
||||
```java
|
||||
public class OrderData {
|
||||
private String orderId;
|
||||
private double amount;
|
||||
private String customerId;
|
||||
|
||||
public OrderData(String orderId, double amount) {
|
||||
this.orderId = orderId;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
}
|
||||
|
||||
// Usage
|
||||
OrderData order = new OrderData("ORD-123", 150.00);
|
||||
EventGridEvent event = new EventGridEvent(
|
||||
"orders/" + order.getOrderId(),
|
||||
"MyApp.Order.Created",
|
||||
BinaryData.fromObject(order),
|
||||
"1.0"
|
||||
);
|
||||
```
|
||||
|
||||
## Receiving Events
|
||||
|
||||
### Parse EventGridEvent
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventgrid.EventGridEvent;
|
||||
|
||||
// From JSON string (e.g., webhook payload)
|
||||
String jsonPayload = "[{\"id\": \"...\", ...}]";
|
||||
List<EventGridEvent> events = EventGridEvent.fromString(jsonPayload);
|
||||
|
||||
for (EventGridEvent event : events) {
|
||||
System.out.println("Event Type: " + event.getEventType());
|
||||
System.out.println("Subject: " + event.getSubject());
|
||||
System.out.println("Event Time: " + event.getEventTime());
|
||||
|
||||
// Get data
|
||||
BinaryData data = event.getData();
|
||||
OrderData orderData = data.toObject(OrderData.class);
|
||||
}
|
||||
```
|
||||
|
||||
### Parse CloudEvent
|
||||
|
||||
```java
|
||||
import com.azure.core.models.CloudEvent;
|
||||
|
||||
String cloudEventJson = "[{\"specversion\": \"1.0\", ...}]";
|
||||
List<CloudEvent> cloudEvents = CloudEvent.fromString(cloudEventJson);
|
||||
|
||||
for (CloudEvent event : cloudEvents) {
|
||||
System.out.println("Type: " + event.getType());
|
||||
System.out.println("Source: " + event.getSource());
|
||||
System.out.println("ID: " + event.getId());
|
||||
|
||||
MyEventData data = event.getData().toObject(MyEventData.class);
|
||||
}
|
||||
```
|
||||
|
||||
### Handle System Events
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventgrid.systemevents.*;
|
||||
|
||||
for (EventGridEvent event : events) {
|
||||
if (event.getEventType().equals("Microsoft.Storage.BlobCreated")) {
|
||||
StorageBlobCreatedEventData blobData =
|
||||
event.getData().toObject(StorageBlobCreatedEventData.class);
|
||||
System.out.println("Blob URL: " + blobData.getUrl());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Event Grid Namespaces (MQTT/Pull)
|
||||
|
||||
### Receive from Namespace Topic
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventgrid.namespaces.EventGridReceiverClient;
|
||||
import com.azure.messaging.eventgrid.namespaces.EventGridReceiverClientBuilder;
|
||||
import com.azure.messaging.eventgrid.namespaces.models.*;
|
||||
|
||||
EventGridReceiverClient receiverClient = new EventGridReceiverClientBuilder()
|
||||
.endpoint("<namespace-endpoint>")
|
||||
.credential(new AzureKeyCredential("<key>"))
|
||||
.topicName("my-topic")
|
||||
.subscriptionName("my-subscription")
|
||||
.buildClient();
|
||||
|
||||
// Receive events
|
||||
ReceiveResult result = receiverClient.receive(10, Duration.ofSeconds(30));
|
||||
|
||||
for (ReceiveDetails detail : result.getValue()) {
|
||||
CloudEvent event = detail.getEvent();
|
||||
System.out.println("Event: " + event.getType());
|
||||
|
||||
// Acknowledge the event
|
||||
receiverClient.acknowledge(Arrays.asList(detail.getBrokerProperties().getLockToken()));
|
||||
}
|
||||
```
|
||||
|
||||
### Reject or Release Events
|
||||
|
||||
```java
|
||||
// Reject (don't retry)
|
||||
receiverClient.reject(Arrays.asList(lockToken));
|
||||
|
||||
// Release (retry later)
|
||||
receiverClient.release(Arrays.asList(lockToken));
|
||||
|
||||
// Release with delay
|
||||
receiverClient.release(Arrays.asList(lockToken),
|
||||
new ReleaseOptions().setDelay(ReleaseDelay.BY_60_SECONDS));
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```java
|
||||
import com.azure.core.exception.HttpResponseException;
|
||||
|
||||
try {
|
||||
client.sendEvent(event);
|
||||
} catch (HttpResponseException e) {
|
||||
System.out.println("Status: " + e.getResponse().getStatusCode());
|
||||
System.out.println("Error: " + e.getMessage());
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
EVENT_GRID_TOPIC_ENDPOINT=https://<topic-name>.<region>.eventgrid.azure.net/api/events
|
||||
EVENT_GRID_ACCESS_KEY=<your-access-key>
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Batch Events**: Send multiple events in one call when possible
|
||||
2. **Idempotency**: Include unique event IDs for deduplication
|
||||
3. **Schema Validation**: Use strongly-typed event data classes
|
||||
4. **Retry Logic**: Built-in, but consider dead-letter for failures
|
||||
5. **Event Size**: Keep events under 1MB (64KB for basic tier)
|
||||
|
||||
## Trigger Phrases
|
||||
|
||||
- "Event Grid Java"
|
||||
- "publish events Azure"
|
||||
- "CloudEvent SDK"
|
||||
- "event-driven messaging"
|
||||
- "pub/sub Azure"
|
||||
- "webhook events"
|
||||
356
skills/official/microsoft/java/messaging/eventhubs/SKILL.md
Normal file
356
skills/official/microsoft/java/messaging/eventhubs/SKILL.md
Normal file
@@ -0,0 +1,356 @@
|
||||
---
|
||||
name: azure-eventhub-java
|
||||
description: Build real-time streaming applications with Azure Event Hubs SDK for Java. Use when implementing event streaming, high-throughput data ingestion, or building event-driven architectures.
|
||||
package: com.azure:azure-messaging-eventhubs
|
||||
---
|
||||
|
||||
# Azure Event Hubs SDK for Java
|
||||
|
||||
Build real-time streaming applications using the Azure Event Hubs SDK for Java.
|
||||
|
||||
## Installation
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-messaging-eventhubs</artifactId>
|
||||
<version>5.19.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- For checkpoint store (production) -->
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-messaging-eventhubs-checkpointstore-blob</artifactId>
|
||||
<version>1.20.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Client Creation
|
||||
|
||||
### EventHubProducerClient
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventhubs.EventHubProducerClient;
|
||||
import com.azure.messaging.eventhubs.EventHubClientBuilder;
|
||||
|
||||
// With connection string
|
||||
EventHubProducerClient producer = new EventHubClientBuilder()
|
||||
.connectionString("<connection-string>", "<event-hub-name>")
|
||||
.buildProducerClient();
|
||||
|
||||
// Full connection string with EntityPath
|
||||
EventHubProducerClient producer = new EventHubClientBuilder()
|
||||
.connectionString("<connection-string-with-entity-path>")
|
||||
.buildProducerClient();
|
||||
```
|
||||
|
||||
### With DefaultAzureCredential
|
||||
|
||||
```java
|
||||
import com.azure.identity.DefaultAzureCredentialBuilder;
|
||||
|
||||
EventHubProducerClient producer = new EventHubClientBuilder()
|
||||
.fullyQualifiedNamespace("<namespace>.servicebus.windows.net")
|
||||
.eventHubName("<event-hub-name>")
|
||||
.credential(new DefaultAzureCredentialBuilder().build())
|
||||
.buildProducerClient();
|
||||
```
|
||||
|
||||
### EventHubConsumerClient
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventhubs.EventHubConsumerClient;
|
||||
|
||||
EventHubConsumerClient consumer = new EventHubClientBuilder()
|
||||
.connectionString("<connection-string>", "<event-hub-name>")
|
||||
.consumerGroup(EventHubClientBuilder.DEFAULT_CONSUMER_GROUP_NAME)
|
||||
.buildConsumerClient();
|
||||
```
|
||||
|
||||
### Async Clients
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventhubs.EventHubProducerAsyncClient;
|
||||
import com.azure.messaging.eventhubs.EventHubConsumerAsyncClient;
|
||||
|
||||
EventHubProducerAsyncClient asyncProducer = new EventHubClientBuilder()
|
||||
.connectionString("<connection-string>", "<event-hub-name>")
|
||||
.buildAsyncProducerClient();
|
||||
|
||||
EventHubConsumerAsyncClient asyncConsumer = new EventHubClientBuilder()
|
||||
.connectionString("<connection-string>", "<event-hub-name>")
|
||||
.consumerGroup("$Default")
|
||||
.buildAsyncConsumerClient();
|
||||
```
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Send Single Event
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventhubs.EventData;
|
||||
|
||||
EventData eventData = new EventData("Hello, Event Hubs!");
|
||||
producer.send(Collections.singletonList(eventData));
|
||||
```
|
||||
|
||||
### Send Event Batch
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventhubs.EventDataBatch;
|
||||
import com.azure.messaging.eventhubs.models.CreateBatchOptions;
|
||||
|
||||
// Create batch
|
||||
EventDataBatch batch = producer.createBatch();
|
||||
|
||||
// Add events (returns false if batch is full)
|
||||
for (int i = 0; i < 100; i++) {
|
||||
EventData event = new EventData("Event " + i);
|
||||
if (!batch.tryAdd(event)) {
|
||||
// Batch is full, send and create new batch
|
||||
producer.send(batch);
|
||||
batch = producer.createBatch();
|
||||
batch.tryAdd(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Send remaining events
|
||||
if (batch.getCount() > 0) {
|
||||
producer.send(batch);
|
||||
}
|
||||
```
|
||||
|
||||
### Send to Specific Partition
|
||||
|
||||
```java
|
||||
CreateBatchOptions options = new CreateBatchOptions()
|
||||
.setPartitionId("0");
|
||||
|
||||
EventDataBatch batch = producer.createBatch(options);
|
||||
batch.tryAdd(new EventData("Partition 0 event"));
|
||||
producer.send(batch);
|
||||
```
|
||||
|
||||
### Send with Partition Key
|
||||
|
||||
```java
|
||||
CreateBatchOptions options = new CreateBatchOptions()
|
||||
.setPartitionKey("customer-123");
|
||||
|
||||
EventDataBatch batch = producer.createBatch(options);
|
||||
batch.tryAdd(new EventData("Customer event"));
|
||||
producer.send(batch);
|
||||
```
|
||||
|
||||
### Event with Properties
|
||||
|
||||
```java
|
||||
EventData event = new EventData("Order created");
|
||||
event.getProperties().put("orderId", "ORD-123");
|
||||
event.getProperties().put("customerId", "CUST-456");
|
||||
event.getProperties().put("priority", 1);
|
||||
|
||||
producer.send(Collections.singletonList(event));
|
||||
```
|
||||
|
||||
### Receive Events (Simple)
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventhubs.models.EventPosition;
|
||||
import com.azure.messaging.eventhubs.models.PartitionEvent;
|
||||
|
||||
// Receive from specific partition
|
||||
Iterable<PartitionEvent> events = consumer.receiveFromPartition(
|
||||
"0", // partitionId
|
||||
10, // maxEvents
|
||||
EventPosition.earliest(), // startingPosition
|
||||
Duration.ofSeconds(30) // timeout
|
||||
);
|
||||
|
||||
for (PartitionEvent partitionEvent : events) {
|
||||
EventData event = partitionEvent.getData();
|
||||
System.out.println("Body: " + event.getBodyAsString());
|
||||
System.out.println("Sequence: " + event.getSequenceNumber());
|
||||
System.out.println("Offset: " + event.getOffset());
|
||||
}
|
||||
```
|
||||
|
||||
### EventProcessorClient (Production)
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventhubs.EventProcessorClient;
|
||||
import com.azure.messaging.eventhubs.EventProcessorClientBuilder;
|
||||
import com.azure.messaging.eventhubs.checkpointstore.blob.BlobCheckpointStore;
|
||||
import com.azure.storage.blob.BlobContainerAsyncClient;
|
||||
import com.azure.storage.blob.BlobContainerClientBuilder;
|
||||
|
||||
// Create checkpoint store
|
||||
BlobContainerAsyncClient blobClient = new BlobContainerClientBuilder()
|
||||
.connectionString("<storage-connection-string>")
|
||||
.containerName("checkpoints")
|
||||
.buildAsyncClient();
|
||||
|
||||
// Create processor
|
||||
EventProcessorClient processor = new EventProcessorClientBuilder()
|
||||
.connectionString("<eventhub-connection-string>", "<event-hub-name>")
|
||||
.consumerGroup("$Default")
|
||||
.checkpointStore(new BlobCheckpointStore(blobClient))
|
||||
.processEvent(eventContext -> {
|
||||
EventData event = eventContext.getEventData();
|
||||
System.out.println("Processing: " + event.getBodyAsString());
|
||||
|
||||
// Checkpoint after processing
|
||||
eventContext.updateCheckpoint();
|
||||
})
|
||||
.processError(errorContext -> {
|
||||
System.err.println("Error: " + errorContext.getThrowable().getMessage());
|
||||
System.err.println("Partition: " + errorContext.getPartitionContext().getPartitionId());
|
||||
})
|
||||
.buildEventProcessorClient();
|
||||
|
||||
// Start processing
|
||||
processor.start();
|
||||
|
||||
// Keep running...
|
||||
Thread.sleep(Duration.ofMinutes(5).toMillis());
|
||||
|
||||
// Stop gracefully
|
||||
processor.stop();
|
||||
```
|
||||
|
||||
### Batch Processing
|
||||
|
||||
```java
|
||||
EventProcessorClient processor = new EventProcessorClientBuilder()
|
||||
.connectionString("<connection-string>", "<event-hub-name>")
|
||||
.consumerGroup("$Default")
|
||||
.checkpointStore(new BlobCheckpointStore(blobClient))
|
||||
.processEventBatch(eventBatchContext -> {
|
||||
List<EventData> events = eventBatchContext.getEvents();
|
||||
System.out.printf("Received %d events%n", events.size());
|
||||
|
||||
for (EventData event : events) {
|
||||
// Process each event
|
||||
System.out.println(event.getBodyAsString());
|
||||
}
|
||||
|
||||
// Checkpoint after batch
|
||||
eventBatchContext.updateCheckpoint();
|
||||
}, 50) // maxBatchSize
|
||||
.processError(errorContext -> {
|
||||
System.err.println("Error: " + errorContext.getThrowable());
|
||||
})
|
||||
.buildEventProcessorClient();
|
||||
```
|
||||
|
||||
### Async Receiving
|
||||
|
||||
```java
|
||||
asyncConsumer.receiveFromPartition("0", EventPosition.latest())
|
||||
.subscribe(
|
||||
partitionEvent -> {
|
||||
EventData event = partitionEvent.getData();
|
||||
System.out.println("Received: " + event.getBodyAsString());
|
||||
},
|
||||
error -> System.err.println("Error: " + error),
|
||||
() -> System.out.println("Complete")
|
||||
);
|
||||
```
|
||||
|
||||
### Get Event Hub Properties
|
||||
|
||||
```java
|
||||
// Get hub info
|
||||
EventHubProperties hubProps = producer.getEventHubProperties();
|
||||
System.out.println("Hub: " + hubProps.getName());
|
||||
System.out.println("Partitions: " + hubProps.getPartitionIds());
|
||||
|
||||
// Get partition info
|
||||
PartitionProperties partitionProps = producer.getPartitionProperties("0");
|
||||
System.out.println("Begin sequence: " + partitionProps.getBeginningSequenceNumber());
|
||||
System.out.println("Last sequence: " + partitionProps.getLastEnqueuedSequenceNumber());
|
||||
System.out.println("Last offset: " + partitionProps.getLastEnqueuedOffset());
|
||||
```
|
||||
|
||||
## Event Positions
|
||||
|
||||
```java
|
||||
// Start from beginning
|
||||
EventPosition.earliest()
|
||||
|
||||
// Start from end (new events only)
|
||||
EventPosition.latest()
|
||||
|
||||
// From specific offset
|
||||
EventPosition.fromOffset(12345L)
|
||||
|
||||
// From specific sequence number
|
||||
EventPosition.fromSequenceNumber(100L)
|
||||
|
||||
// From specific time
|
||||
EventPosition.fromEnqueuedTime(Instant.now().minus(Duration.ofHours(1)))
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```java
|
||||
import com.azure.messaging.eventhubs.models.ErrorContext;
|
||||
|
||||
.processError(errorContext -> {
|
||||
Throwable error = errorContext.getThrowable();
|
||||
String partitionId = errorContext.getPartitionContext().getPartitionId();
|
||||
|
||||
if (error instanceof AmqpException) {
|
||||
AmqpException amqpError = (AmqpException) error;
|
||||
if (amqpError.isTransient()) {
|
||||
System.out.println("Transient error, will retry");
|
||||
}
|
||||
}
|
||||
|
||||
System.err.printf("Error on partition %s: %s%n", partitionId, error.getMessage());
|
||||
})
|
||||
```
|
||||
|
||||
## Resource Cleanup
|
||||
|
||||
```java
|
||||
// Always close clients
|
||||
try {
|
||||
producer.send(batch);
|
||||
} finally {
|
||||
producer.close();
|
||||
}
|
||||
|
||||
// Or use try-with-resources
|
||||
try (EventHubProducerClient producer = new EventHubClientBuilder()
|
||||
.connectionString(connectionString, eventHubName)
|
||||
.buildProducerClient()) {
|
||||
producer.send(events);
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
EVENT_HUBS_CONNECTION_STRING=Endpoint=sb://<namespace>.servicebus.windows.net/;SharedAccessKeyName=...
|
||||
EVENT_HUBS_NAME=<event-hub-name>
|
||||
STORAGE_CONNECTION_STRING=<for-checkpointing>
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use EventProcessorClient**: For production, provides load balancing and checkpointing
|
||||
2. **Batch Events**: Use `EventDataBatch` for efficient sending
|
||||
3. **Partition Keys**: Use for ordering guarantees within a partition
|
||||
4. **Checkpointing**: Checkpoint after processing to avoid reprocessing
|
||||
5. **Error Handling**: Handle transient errors with retries
|
||||
6. **Close Clients**: Always close producer/consumer when done
|
||||
|
||||
## Trigger Phrases
|
||||
|
||||
- "Event Hubs Java"
|
||||
- "event streaming Azure"
|
||||
- "real-time data ingestion"
|
||||
- "EventProcessorClient"
|
||||
- "event hub producer consumer"
|
||||
- "partition processing"
|
||||
302
skills/official/microsoft/java/messaging/webpubsub/SKILL.md
Normal file
302
skills/official/microsoft/java/messaging/webpubsub/SKILL.md
Normal file
@@ -0,0 +1,302 @@
|
||||
---
|
||||
name: azure-messaging-webpubsub-java
|
||||
description: Build real-time web applications with Azure Web PubSub SDK for Java. Use when implementing WebSocket-based messaging, live updates, chat applications, or server-to-client push notifications.
|
||||
package: com.azure:azure-messaging-webpubsub
|
||||
---
|
||||
|
||||
# Azure Web PubSub SDK for Java
|
||||
|
||||
Build real-time web applications using the Azure Web PubSub SDK for Java.
|
||||
|
||||
## Installation
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-messaging-webpubsub</artifactId>
|
||||
<version>1.5.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Client Creation
|
||||
|
||||
### With Connection String
|
||||
|
||||
```java
|
||||
import com.azure.messaging.webpubsub.WebPubSubServiceClient;
|
||||
import com.azure.messaging.webpubsub.WebPubSubServiceClientBuilder;
|
||||
|
||||
WebPubSubServiceClient client = new WebPubSubServiceClientBuilder()
|
||||
.connectionString("<connection-string>")
|
||||
.hub("chat")
|
||||
.buildClient();
|
||||
```
|
||||
|
||||
### With Access Key
|
||||
|
||||
```java
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
|
||||
WebPubSubServiceClient client = new WebPubSubServiceClientBuilder()
|
||||
.credential(new AzureKeyCredential("<access-key>"))
|
||||
.endpoint("<endpoint>")
|
||||
.hub("chat")
|
||||
.buildClient();
|
||||
```
|
||||
|
||||
### With DefaultAzureCredential
|
||||
|
||||
```java
|
||||
import com.azure.identity.DefaultAzureCredentialBuilder;
|
||||
|
||||
WebPubSubServiceClient client = new WebPubSubServiceClientBuilder()
|
||||
.credential(new DefaultAzureCredentialBuilder().build())
|
||||
.endpoint("<endpoint>")
|
||||
.hub("chat")
|
||||
.buildClient();
|
||||
```
|
||||
|
||||
### Async Client
|
||||
|
||||
```java
|
||||
import com.azure.messaging.webpubsub.WebPubSubServiceAsyncClient;
|
||||
|
||||
WebPubSubServiceAsyncClient asyncClient = new WebPubSubServiceClientBuilder()
|
||||
.connectionString("<connection-string>")
|
||||
.hub("chat")
|
||||
.buildAsyncClient();
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Hub**: Logical isolation unit for connections
|
||||
- **Group**: Subset of connections within a hub
|
||||
- **Connection**: Individual WebSocket client connection
|
||||
- **User**: Entity that can have multiple connections
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Send to All Connections
|
||||
|
||||
```java
|
||||
import com.azure.messaging.webpubsub.models.WebPubSubContentType;
|
||||
|
||||
// Send text message
|
||||
client.sendToAll("Hello everyone!", WebPubSubContentType.TEXT_PLAIN);
|
||||
|
||||
// Send JSON
|
||||
String jsonMessage = "{\"type\": \"notification\", \"message\": \"New update!\"}";
|
||||
client.sendToAll(jsonMessage, WebPubSubContentType.APPLICATION_JSON);
|
||||
```
|
||||
|
||||
### Send to All with Filter
|
||||
|
||||
```java
|
||||
import com.azure.core.http.rest.RequestOptions;
|
||||
import com.azure.core.util.BinaryData;
|
||||
|
||||
BinaryData message = BinaryData.fromString("Hello filtered users!");
|
||||
|
||||
// Filter by userId
|
||||
client.sendToAllWithResponse(
|
||||
message,
|
||||
WebPubSubContentType.TEXT_PLAIN,
|
||||
message.getLength(),
|
||||
new RequestOptions().addQueryParam("filter", "userId ne 'user1'"));
|
||||
|
||||
// Filter by groups
|
||||
client.sendToAllWithResponse(
|
||||
message,
|
||||
WebPubSubContentType.TEXT_PLAIN,
|
||||
message.getLength(),
|
||||
new RequestOptions().addQueryParam("filter", "'GroupA' in groups and not('GroupB' in groups)"));
|
||||
```
|
||||
|
||||
### Send to Group
|
||||
|
||||
```java
|
||||
// Send to all connections in a group
|
||||
client.sendToGroup("java-developers", "Hello Java devs!", WebPubSubContentType.TEXT_PLAIN);
|
||||
|
||||
// Send JSON to group
|
||||
String json = "{\"event\": \"update\", \"data\": {\"version\": \"2.0\"}}";
|
||||
client.sendToGroup("subscribers", json, WebPubSubContentType.APPLICATION_JSON);
|
||||
```
|
||||
|
||||
### Send to Specific Connection
|
||||
|
||||
```java
|
||||
// Send to a specific connection by ID
|
||||
client.sendToConnection("connectionId123", "Private message", WebPubSubContentType.TEXT_PLAIN);
|
||||
```
|
||||
|
||||
### Send to User
|
||||
|
||||
```java
|
||||
// Send to all connections for a specific user
|
||||
client.sendToUser("andy", "Hello Andy!", WebPubSubContentType.TEXT_PLAIN);
|
||||
```
|
||||
|
||||
### Manage Groups
|
||||
|
||||
```java
|
||||
// Add connection to group
|
||||
client.addConnectionToGroup("premium-users", "connectionId123");
|
||||
|
||||
// Remove connection from group
|
||||
client.removeConnectionFromGroup("premium-users", "connectionId123");
|
||||
|
||||
// Add user to group (all their connections)
|
||||
client.addUserToGroup("admin-group", "userId456");
|
||||
|
||||
// Remove user from group
|
||||
client.removeUserFromGroup("admin-group", "userId456");
|
||||
|
||||
// Check if user is in group
|
||||
boolean exists = client.userExistsInGroup("admin-group", "userId456");
|
||||
```
|
||||
|
||||
### Manage Connections
|
||||
|
||||
```java
|
||||
// Check if connection exists
|
||||
boolean connected = client.connectionExists("connectionId123");
|
||||
|
||||
// Close a connection
|
||||
client.closeConnection("connectionId123");
|
||||
|
||||
// Close with reason
|
||||
client.closeConnection("connectionId123", "Session expired");
|
||||
|
||||
// Check if user exists (has any connections)
|
||||
boolean userOnline = client.userExists("userId456");
|
||||
|
||||
// Close all connections for a user
|
||||
client.closeUserConnections("userId456");
|
||||
|
||||
// Close all connections in a group
|
||||
client.closeGroupConnections("inactive-group");
|
||||
```
|
||||
|
||||
### Generate Client Access Token
|
||||
|
||||
```java
|
||||
import com.azure.messaging.webpubsub.models.GetClientAccessTokenOptions;
|
||||
import com.azure.messaging.webpubsub.models.WebPubSubClientAccessToken;
|
||||
|
||||
// Basic token
|
||||
WebPubSubClientAccessToken token = client.getClientAccessToken(
|
||||
new GetClientAccessTokenOptions());
|
||||
System.out.println("URL: " + token.getUrl());
|
||||
|
||||
// With user ID
|
||||
WebPubSubClientAccessToken userToken = client.getClientAccessToken(
|
||||
new GetClientAccessTokenOptions().setUserId("user123"));
|
||||
|
||||
// With roles (permissions)
|
||||
WebPubSubClientAccessToken roleToken = client.getClientAccessToken(
|
||||
new GetClientAccessTokenOptions()
|
||||
.setUserId("user123")
|
||||
.addRole("webpubsub.joinLeaveGroup")
|
||||
.addRole("webpubsub.sendToGroup"));
|
||||
|
||||
// With groups to join on connect
|
||||
WebPubSubClientAccessToken groupToken = client.getClientAccessToken(
|
||||
new GetClientAccessTokenOptions()
|
||||
.setUserId("user123")
|
||||
.addGroup("announcements")
|
||||
.addGroup("updates"));
|
||||
|
||||
// With custom expiration
|
||||
WebPubSubClientAccessToken expToken = client.getClientAccessToken(
|
||||
new GetClientAccessTokenOptions()
|
||||
.setUserId("user123")
|
||||
.setExpiresAfter(Duration.ofHours(2)));
|
||||
```
|
||||
|
||||
### Grant/Revoke Permissions
|
||||
|
||||
```java
|
||||
import com.azure.messaging.webpubsub.models.WebPubSubPermission;
|
||||
|
||||
// Grant permission to send to a group
|
||||
client.grantPermission(
|
||||
WebPubSubPermission.SEND_TO_GROUP,
|
||||
"connectionId123",
|
||||
new RequestOptions().addQueryParam("targetName", "chat-room"));
|
||||
|
||||
// Revoke permission
|
||||
client.revokePermission(
|
||||
WebPubSubPermission.SEND_TO_GROUP,
|
||||
"connectionId123",
|
||||
new RequestOptions().addQueryParam("targetName", "chat-room"));
|
||||
|
||||
// Check permission
|
||||
boolean hasPermission = client.checkPermission(
|
||||
WebPubSubPermission.SEND_TO_GROUP,
|
||||
"connectionId123",
|
||||
new RequestOptions().addQueryParam("targetName", "chat-room"));
|
||||
```
|
||||
|
||||
### Async Operations
|
||||
|
||||
```java
|
||||
asyncClient.sendToAll("Async message!", WebPubSubContentType.TEXT_PLAIN)
|
||||
.subscribe(
|
||||
unused -> System.out.println("Message sent"),
|
||||
error -> System.err.println("Error: " + error.getMessage())
|
||||
);
|
||||
|
||||
asyncClient.sendToGroup("developers", "Group message", WebPubSubContentType.TEXT_PLAIN)
|
||||
.doOnSuccess(v -> System.out.println("Sent to group"))
|
||||
.doOnError(e -> System.err.println("Failed: " + e))
|
||||
.subscribe();
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```java
|
||||
import com.azure.core.exception.HttpResponseException;
|
||||
|
||||
try {
|
||||
client.sendToConnection("invalid-id", "test", WebPubSubContentType.TEXT_PLAIN);
|
||||
} catch (HttpResponseException e) {
|
||||
System.out.println("Status: " + e.getResponse().getStatusCode());
|
||||
System.out.println("Error: " + e.getMessage());
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
WEB_PUBSUB_CONNECTION_STRING=Endpoint=https://<resource>.webpubsub.azure.com;AccessKey=...
|
||||
WEB_PUBSUB_ENDPOINT=https://<resource>.webpubsub.azure.com
|
||||
WEB_PUBSUB_ACCESS_KEY=<your-access-key>
|
||||
```
|
||||
|
||||
## Client Roles
|
||||
|
||||
| Role | Permission |
|
||||
|------|------------|
|
||||
| `webpubsub.joinLeaveGroup` | Join/leave any group |
|
||||
| `webpubsub.sendToGroup` | Send to any group |
|
||||
| `webpubsub.joinLeaveGroup.<group>` | Join/leave specific group |
|
||||
| `webpubsub.sendToGroup.<group>` | Send to specific group |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use Groups**: Organize connections into groups for targeted messaging
|
||||
2. **User IDs**: Associate connections with user IDs for user-level messaging
|
||||
3. **Token Expiration**: Set appropriate token expiration for security
|
||||
4. **Roles**: Grant minimal required permissions via roles
|
||||
5. **Hub Isolation**: Use separate hubs for different application features
|
||||
6. **Connection Management**: Clean up inactive connections
|
||||
|
||||
## Trigger Phrases
|
||||
|
||||
- "Web PubSub Java"
|
||||
- "WebSocket messaging Azure"
|
||||
- "real-time push notifications"
|
||||
- "server-sent events"
|
||||
- "chat application backend"
|
||||
- "live updates broadcasting"
|
||||
Reference in New Issue
Block a user