-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add SDK functionality to make it easier to deserialize/consume EventG…
…rid events (#2426) * Adding support for deserialize/conusme (custom) eventgrid events * Tests for deserialize/conusme (custom) eventgrid events utility (EventGridSubscriber) * Adding beta annotation for EventGridSubscriber and associated types, rename mappingExists -> containsMappingFor * Simplifying code using canonicalizeEventType(String), improved custom mapping lookup methods, adding method to return all custom mapping and adding new IoT & resource events * Adding tests for new IoT [Connected|Disconnected] & resource [Action*] events * Rename getAllCustomEventMapping() -> getAllCustomEventMappings(), adding tests for custom mapping operations
- Loading branch information
Showing
39 changed files
with
1,820 additions
and
0 deletions.
There are no files selected for viewing
185 changes: 185 additions & 0 deletions
185
...-plane/src/main/java/com/microsoft/azure/eventgrid/customization/EventGridSubscriber.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
/** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for | ||
* license information. | ||
*/ | ||
package com.microsoft.azure.eventgrid.customization; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.microsoft.azure.eventgrid.models.EventGridEvent; | ||
import com.microsoft.azure.management.apigeneration.Beta; | ||
import com.microsoft.azure.serializer.AzureJacksonAdapter; | ||
import com.microsoft.rest.protocol.SerializerAdapter; | ||
|
||
import java.io.IOException; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Type; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
/** | ||
* The type that can be used to de-serialize eventgrid events. | ||
*/ | ||
@Beta | ||
public class EventGridSubscriber { | ||
/** | ||
* The default adapter to be used for de-serializing the events. | ||
*/ | ||
private final AzureJacksonAdapter defaultSerializerAdapter; | ||
/** | ||
* The map containing user defined mapping of eventType to Java model type. | ||
*/ | ||
private Map<String, Type> eventTypeToEventDataMapping; | ||
|
||
/** | ||
* Creates EventGridSubscriber with default de-serializer. | ||
*/ | ||
@Beta | ||
public EventGridSubscriber() { | ||
this.defaultSerializerAdapter = new AzureJacksonAdapter(); | ||
this.eventTypeToEventDataMapping = new HashMap<>(); | ||
} | ||
|
||
/** | ||
* Add a custom event mapping. If a mapping with same eventType exists then the old eventDataType is replaced by | ||
* the specified eventDataType. | ||
* | ||
* @param eventType the event type name. | ||
* @param eventDataType type of the Java model that the event type name mapped to. | ||
*/ | ||
@Beta | ||
public void putCustomEventMapping(final String eventType, final Type eventDataType) { | ||
if (eventType == null || eventType.isEmpty()) { | ||
throw new IllegalArgumentException("eventType parameter is required and cannot be null or empty"); | ||
} | ||
if (eventDataType == null) { | ||
throw new IllegalArgumentException("eventDataType parameter is required and cannot be null"); | ||
} | ||
this.eventTypeToEventDataMapping.put(canonicalizeEventType(eventType), eventDataType); | ||
} | ||
|
||
/** | ||
* Get type of the Java model that is mapped to the given eventType. | ||
* | ||
* @param eventType the event type name. | ||
* @return type of the Java model if mapping exists, null otherwise. | ||
*/ | ||
@Beta | ||
public Type getCustomEventMapping(final String eventType) { | ||
if (!containsCustomEventMappingFor(eventType)) { | ||
return null; | ||
} else { | ||
return this.eventTypeToEventDataMapping.get(canonicalizeEventType(eventType)); | ||
} | ||
} | ||
|
||
/** | ||
* @return get all registered custom event mappings. | ||
*/ | ||
@Beta | ||
public Set<Map.Entry<String, Type>> getAllCustomEventMappings() { | ||
return Collections.unmodifiableSet(this.eventTypeToEventDataMapping.entrySet()); | ||
} | ||
|
||
/** | ||
* Removes the mapping with the given eventType. | ||
* | ||
* @param eventType the event type name. | ||
* @return true if the mapping exists and removed, false if mapping does not exists. | ||
*/ | ||
@Beta | ||
public boolean removeCustomEventMapping(final String eventType) { | ||
if (!containsCustomEventMappingFor(eventType)) { | ||
return false; | ||
} else { | ||
this.eventTypeToEventDataMapping.remove(canonicalizeEventType(eventType)); | ||
return true; | ||
} | ||
} | ||
|
||
/** | ||
* Checks if an event mapping with the given eventType exists. | ||
* | ||
* @param eventType the event type name. | ||
* @return true if the mapping exists, false otherwise. | ||
*/ | ||
@Beta | ||
public boolean containsCustomEventMappingFor(final String eventType) { | ||
if (eventType == null || eventType.isEmpty()) { | ||
return false; | ||
} else { | ||
return this.eventTypeToEventDataMapping.containsKey(canonicalizeEventType(eventType)); | ||
} | ||
} | ||
|
||
/** | ||
* De-serialize the events in the given requested content using default de-serializer. | ||
* | ||
* @param requestContent the request content in string format. | ||
* @return De-serialized events. | ||
* | ||
* @throws IOException | ||
*/ | ||
@Beta | ||
public EventGridEvent[] deserializeEventGridEvents(final String requestContent) throws IOException { | ||
return this.deserializeEventGridEvents(requestContent, this.defaultSerializerAdapter); | ||
} | ||
|
||
/** | ||
* De-serialize the events in the given requested content using the provided de-serializer. | ||
* | ||
* @param requestContent the request content as string. | ||
* @param serializerAdapter the de-serializer. | ||
* @return de-serialized events. | ||
* @throws IOException | ||
*/ | ||
@Beta | ||
public EventGridEvent[] deserializeEventGridEvents(final String requestContent, final SerializerAdapter<ObjectMapper> serializerAdapter) throws IOException { | ||
EventGridEvent[] eventGridEvents = serializerAdapter.<EventGridEvent[]>deserialize(requestContent, EventGridEvent[].class); | ||
for (EventGridEvent receivedEvent : eventGridEvents) { | ||
if (receivedEvent.data() == null) { | ||
continue; | ||
} else { | ||
final String eventType = receivedEvent.eventType(); | ||
final Type eventDataType; | ||
if (SystemEventTypeMappings.containsMappingFor(eventType)) { | ||
eventDataType = SystemEventTypeMappings.getMapping(eventType); | ||
} else if (containsCustomEventMappingFor(eventType)) { | ||
eventDataType = getCustomEventMapping(eventType); | ||
} else { | ||
eventDataType = null; | ||
} | ||
if (eventDataType != null) { | ||
final String eventDataAsString = serializerAdapter.serializeRaw(receivedEvent.data()); | ||
final Object eventData = serializerAdapter.<Object>deserialize(eventDataAsString, eventDataType); | ||
setEventData(receivedEvent, eventData); | ||
} | ||
} | ||
} | ||
return eventGridEvents; | ||
} | ||
|
||
private static void setEventData(EventGridEvent event, final Object data) { | ||
// This reflection based way to set the data field needs to be removed once | ||
// we expose a wither in EventGridEvent to set the data. (Check swagger + codegen) | ||
try { | ||
Field dataField = event.getClass().getDeclaredField("data"); | ||
dataField.setAccessible(true); | ||
dataField.set(event, data); | ||
} catch (NoSuchFieldException nsfe) { | ||
throw new RuntimeException(nsfe); | ||
} catch (IllegalAccessException iae) { | ||
throw new RuntimeException(iae); | ||
} | ||
} | ||
|
||
private static String canonicalizeEventType(final String eventType) { | ||
if (eventType == null) { | ||
return null; | ||
} else { | ||
return eventType.toLowerCase(); | ||
} | ||
} | ||
} |
127 changes: 127 additions & 0 deletions
127
...ne/src/main/java/com/microsoft/azure/eventgrid/customization/SystemEventTypeMappings.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for | ||
* license information. | ||
*/ | ||
package com.microsoft.azure.eventgrid.customization; | ||
|
||
import com.microsoft.azure.eventgrid.models.ContainerRegistryImageDeletedEventData; | ||
import com.microsoft.azure.eventgrid.models.ContainerRegistryImagePushedEventData; | ||
import com.microsoft.azure.eventgrid.models.EventHubCaptureFileCreatedEventData; | ||
import com.microsoft.azure.eventgrid.models.IotHubDeviceConnectedEventData; | ||
import com.microsoft.azure.eventgrid.models.IotHubDeviceCreatedEventData; | ||
import com.microsoft.azure.eventgrid.models.IotHubDeviceDeletedEventData; | ||
import com.microsoft.azure.eventgrid.models.IotHubDeviceDisconnectedEventData; | ||
import com.microsoft.azure.eventgrid.models.MediaJobStateChangeEventData; | ||
import com.microsoft.azure.eventgrid.models.ResourceActionCancelData; | ||
import com.microsoft.azure.eventgrid.models.ResourceActionFailureData; | ||
import com.microsoft.azure.eventgrid.models.ResourceActionSuccessData; | ||
import com.microsoft.azure.eventgrid.models.ResourceDeleteCancelData; | ||
import com.microsoft.azure.eventgrid.models.ResourceDeleteFailureData; | ||
import com.microsoft.azure.eventgrid.models.ResourceDeleteSuccessData; | ||
import com.microsoft.azure.eventgrid.models.ResourceWriteCancelData; | ||
import com.microsoft.azure.eventgrid.models.ResourceWriteFailureData; | ||
import com.microsoft.azure.eventgrid.models.ResourceWriteSuccessData; | ||
import com.microsoft.azure.eventgrid.models.ServiceBusActiveMessagesAvailableWithNoListenersEventData; | ||
import com.microsoft.azure.eventgrid.models.ServiceBusDeadletterMessagesAvailableWithNoListenersEventData; | ||
import com.microsoft.azure.eventgrid.models.StorageBlobCreatedEventData; | ||
import com.microsoft.azure.eventgrid.models.StorageBlobDeletedEventData; | ||
import com.microsoft.azure.eventgrid.models.SubscriptionDeletedEventData; | ||
import com.microsoft.azure.eventgrid.models.SubscriptionValidationEventData; | ||
import com.microsoft.azure.management.apigeneration.Beta; | ||
|
||
import java.lang.reflect.Type; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
/** | ||
* Mapping of system event type name to corresponding type of the Java model. | ||
*/ | ||
@Beta | ||
final class SystemEventTypeMappings { | ||
/** | ||
* The map containing system eventType to Java model type mapping. | ||
*/ | ||
private static Map<String, Type> systemEventMappings; | ||
|
||
static { | ||
systemEventMappings = new HashMap<>(); // key: eventType, Value:eventDataType | ||
// | ||
// ContainerRegistry events. | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.CONTAINER_REGISTRY_IMAGE_PUSHED_EVENT), ContainerRegistryImagePushedEventData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.CONTAINER_REGISTRY_IMAGE_DELETED_EVENT), ContainerRegistryImageDeletedEventData.class); | ||
// | ||
// Device events. | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.IOT_HUB_DEVICE_CREATED_EVENT), IotHubDeviceCreatedEventData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.IOT_HUB_DEVICE_DELETED_EVENT), IotHubDeviceDeletedEventData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.IOT_HUB_DEVICE_CONNECTED_EVENT), IotHubDeviceConnectedEventData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.IOT_HUB_DEVICE_DISCONNECTED_EVENT), IotHubDeviceDisconnectedEventData.class); | ||
// | ||
// EventGrid events. | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.EVENT_GRID_SUBSCRIPTION_VALIDATION_EVENT), SubscriptionValidationEventData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.EVENT_GRID_SUBSCRIPTION_DELETED_EVENT), SubscriptionDeletedEventData.class); | ||
// | ||
// Event Hub Events. | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.EVENT_HUB_CAPTURE_FILE_CREATED_EVENT), EventHubCaptureFileCreatedEventData.class); | ||
// | ||
// Media Services events. | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.MEDIA_JOB_STATE_CHANGE_EVENT), MediaJobStateChangeEventData.class); | ||
// | ||
// Resource Manager (Azure Subscription/Resource Group) events. | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.RESOURCE_WRITE_SUCCESS_EVENT), ResourceWriteSuccessData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.RESOURCE_WRITE_FAILURE_EVENT), ResourceWriteFailureData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.RESOURCE_WRITE_CANCEL_EVENT), ResourceWriteCancelData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.RESOURCE_DELETE_SUCCESS_EVENT), ResourceDeleteSuccessData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.RESOURCE_DELETE_FAILURE_EVENT), ResourceDeleteFailureData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.RESOURCE_DELETE_CANCEL_EVENT), ResourceDeleteCancelData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.RESOURCE_ACTION_SUCCESS_EVENT), ResourceActionSuccessData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.RESOURCE_ACTION_FAILURE_EVENT), ResourceActionFailureData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.RESOURCE_ACTION_CANCEL_EVENT), ResourceActionCancelData.class); | ||
// | ||
// ServiceBus events. | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.SERVICE_BUS_ACTIVE_MESSAGES_AVAILABLE_WITH_NO_LISTENERS_EVENT), ServiceBusActiveMessagesAvailableWithNoListenersEventData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.SERVICE_BUS_DEADLETTER_MESSAGES_AVAILABLE_WITH_NO_LISTENER_EVENT), ServiceBusDeadletterMessagesAvailableWithNoListenersEventData.class); | ||
// | ||
// Storage events. | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.STORAGE_BLOB_CREATED_EVENT), StorageBlobCreatedEventData.class); | ||
systemEventMappings.put(canonicalizeEventType(SystemEventTypes.STORAGE_BLOB_DELETED_EVENT), StorageBlobDeletedEventData.class); | ||
} | ||
|
||
/** | ||
* Checks if a mapping exists for the given type. | ||
* | ||
* @param eventType the event type. | ||
* @return true if mapping exists, false otherwise. | ||
*/ | ||
@Beta | ||
public static boolean containsMappingFor(final String eventType) { | ||
if (eventType == null || eventType.isEmpty()) { | ||
return false; | ||
} else { | ||
return systemEventMappings.containsKey(canonicalizeEventType(eventType)); | ||
} | ||
} | ||
|
||
/** | ||
* Get Java model type for the given event type. | ||
* | ||
* @param eventType the event type. | ||
* @return the Java model type if mapping exists, null otherwise. | ||
*/ | ||
@Beta | ||
public static Type getMapping(final String eventType) { | ||
if (!containsMappingFor(eventType)) { | ||
return null; | ||
} else { | ||
return systemEventMappings.get(canonicalizeEventType(eventType)); | ||
} | ||
} | ||
|
||
private static String canonicalizeEventType(final String eventType) { | ||
if (eventType == null) { | ||
return null; | ||
} else { | ||
return eventType.toLowerCase(); | ||
} | ||
} | ||
} |
Oops, something went wrong.