/* * Copyright 2012-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ package com.amazonaws.services.sns.message; import com.amazonaws.util.DateUtils; import com.fasterxml.jackson.databind.JsonNode; import java.util.Date; import org.apache.http.client.HttpClient; /** * Unmarshalls the JSON of an SNS message into the appropriate subclass of {@link SnsMessage}. */ final class SnsMessageUnmarshaller { // SNS message field names private static final String TYPE = "Type"; private static final String MESSAGE_ID = "MessageId"; private static final String TOPIC_ARN = "TopicArn"; private static final String SUBJECT = "Subject"; private static final String MESSAGE = "Message"; private static final String TIMESTAMP = "Timestamp"; private static final String SUBSCRIBE_URL = "SubscribeURL"; private static final String UNSUBSCRIBE_URL = "UnsubscribeURL"; private static final String TOKEN = "Token"; // SNS message types private static final String TYPE_NOTIFICATION = "Notification"; private static final String TYPE_SUBSCRIPTION_CONFIRMATION = "SubscriptionConfirmation"; private static final String TYPE_UNSUBSCRIBE_CONFIRMATION = "UnsubscribeConfirmation"; private final HttpClient client; SnsMessageUnmarshaller(HttpClient client) { this.client = client; } /** * Unmarshalls the given {@link JsonNode} into the appropriate sub type based on the {@link #TYPE}. * * @param rawMessage JSON message. * @return Unmarshalled message. */ public SnsMessage unmarshall(JsonNode rawMessage) { SnsJsonNode message = new SnsJsonNode(rawMessage); return unmarshallBase(createSubMessage(message), message).build(); } private SnsMessage.Builder<? extends SnsMessage.Builder> createSubMessage(SnsJsonNode message) { String type = message.getString(TYPE); if (TYPE_NOTIFICATION.equals(type)) { return unmarshallNotification(message); } else if (TYPE_SUBSCRIPTION_CONFIRMATION.equals(type)) { return unmarshallSubscriptionConfirmation(message); } else if (TYPE_UNSUBSCRIBE_CONFIRMATION.equals(type)) { return unmarshallUnsubscribeConfirmation(message); } else { return SnsUnknownMessage.builder(); } } /** * Unmarshall into a {@link SnsUnsubscribeConfirmation} object. * * @param message JSON message. * @return Builder with sub properties filled in. Base properties are added by * {@link #unmarshallBase(SnsMessage.Builder, SnsJsonNode)}. */ private SnsMessage.Builder<? extends SnsMessage.Builder> unmarshallUnsubscribeConfirmation(SnsJsonNode message) { return SnsUnsubscribeConfirmation.builder(client) .withMessage(message.getString(MESSAGE)) .withSubscribeUrl(message.getString(SUBSCRIBE_URL)) .withToken(message.getString(TOKEN)); } /** * Unmarshall into a {@link SnsSubscriptionConfirmation} object. * * @param message JSON message. * @return Builder with sub properties filled in. Base properties are added by * {@link #unmarshallBase(SnsMessage.Builder, SnsJsonNode)}. */ private SnsMessage.Builder<? extends SnsMessage.Builder> unmarshallSubscriptionConfirmation(SnsJsonNode message) { return SnsSubscriptionConfirmation.builder(client) .withSubscribeUrl(message.getString(SUBSCRIBE_URL)) .withToken(message.getString(TOKEN)) .withMessage(message.getString(MESSAGE)); } /** * Unmarshall into a {@link SnsNotification} object. * * @param message JSON message. * @return Builder with sub properties filled in. Base properties are added by * {@link #unmarshallBase(SnsMessage.Builder, SnsJsonNode)}. */ private SnsMessage.Builder<? extends SnsMessage.Builder> unmarshallNotification(SnsJsonNode message) { return SnsNotification.builder(client) .withMessage(message.getString(MESSAGE)) .withSubject(message.getString(SUBJECT)) .withUnsubscribeUrl(message.getString(UNSUBSCRIBE_URL)); } /** * Unmarshall the base properties of {@link SnsMessage}. * * @param builder Builder subclass to add base properties to. * @param message JSON message. * @return Modified builder with base properties added. */ public SnsMessage.Builder<?> unmarshallBase(SnsMessage.Builder<?> builder, SnsJsonNode message) { return builder .withMessageId(message.getString(MESSAGE_ID)) .withTopicArn(message.getString(TOPIC_ARN)) .withTimestamp(message.getIso8601Date(TIMESTAMP)); } /** * Small wrapper to provide convenient access to a {@link JsonNode} and some simple conversions. */ private static final class SnsJsonNode { private final JsonNode source; private SnsJsonNode(JsonNode source) { this.source = source; } /** * Gets a ISO8601 date value from the JSON. * * @param fieldName Name of field to get. * @return Date object or null if not present. */ private Date getIso8601Date(String fieldName) { String dateString = getString(fieldName); return dateString != null ? DateUtils.parseISO8601Date(dateString) : null; } /** * Get a string field from the JSON. * * @param fieldName Name of field to get. * @return String value or null if not present. */ private String getString(String fieldName) { return source.has(fieldName) ? source.get(fieldName).asText() : null; } } }