All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratorRegistry Maven / Gradle / Ivy

Go to download

The AWS Java SDK for Amazon DynamoDB module holds the client classes that are used for communicating with Amazon DynamoDB Service

There is a newer version: 1.9.11
Show newest version
/*
 * Copyright 2010-2016 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.dynamodbv2.datamodeling;

import java.math.BigInteger;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.UUID;

import com.amazonaws.annotation.SdkInternalApi;

/**
 * Helper for auto-generating attribute values.
 */
@SdkInternalApi
final class DynamoDBAutoGeneratorRegistry {

    /**
     * Gets the generator given an annotations definition.
     * @param generatedType The generated type class.
     * @param annotations The annotations.
     * @return The generator.
     */
    final Generator generatorOf(final Class generatedType, final DynamoDBAnnotationRegistry.AnnotationMap annotations) {
        if (annotations.isAutoGeneratedKey()) {
            return keyGeneratorOf(generatedType);
        } else if (annotations.isVersion()) {
            return versionGeneratorOf(generatedType);
        } else if (annotations.isAutoGeneratedTimestamp()) {
            return timestampGeneratorOf(generatedType, annotations.getAutoGenerateStrategy());
        } else {
            return neverGeneratorOf(generatedType);
        }
    }

    /**
     * Gets the never generator given the annotation and generatedType.
     * @param generatedType The generated type class.
     * @return The generator.
     */
    final Generator neverGeneratorOf(final Class generatedType) {
        final Generator generator = new NeverGenerator(generatedType);
        return (Generator)generator;
    }

    /**
     * Gets the key generator given the annotation and generatedType.
     * @param generatedType The generated type class.
     * @return The generator.
     */
    final Generator keyGeneratorOf(final Class generatedType) {
        final Generator generator;
        if (String.class.isAssignableFrom(generatedType)) {
            generator = new UuidStringKeyGenerator();
        } else {
            generator = new NeverKeyGenerator(generatedType);
        }
        return (Generator)generator;
    }

    /**
     * Gets the version generator given the annotation and generatedType.
     * @param generatedType The generated type class.
     * @return The generator.
     */
    final Generator versionGeneratorOf(final Class generatedType) {
        final Generator generator;
        if (BigInteger.class.isAssignableFrom(generatedType)) {
            generator = new BigIntegerVersionGenerator();
        } else if (Byte.class.isAssignableFrom(generatedType) || byte.class.isAssignableFrom(generatedType)) {
            generator = new ByteVersionGenerator();
        } else if (Integer.class.isAssignableFrom(generatedType) || int.class.isAssignableFrom(generatedType)) {
            generator = new IntegerVersionGenerator();
        } else if (Long.class.isAssignableFrom(generatedType) || long.class.isAssignableFrom(generatedType)) {
            generator = new LongVersionGenerator();
        } else if (Short.class.isAssignableFrom(generatedType) || short.class.isAssignableFrom(generatedType)) {
            generator = new ShortVersionGenerator();
        } else {
            generator = new NeverVersionGenerator(generatedType);
        }
        return (Generator)generator;
    }

    /**
     * Gets the timestamp generator given the annotation and generatedType.
     * @param generatedType The generated type class.
     * @param strategy The auto-generation strategy.
     * @return The generator.
     */
    final Generator timestampGeneratorOf(final Class generatedType, final DynamoDBAutoGenerateStrategy strategy) {
        final Generator generator;
        if (Calendar.class.isAssignableFrom(generatedType)) {
            generator = new CalendarTimestampGenerator(strategy);
        } else if (Date.class.isAssignableFrom(generatedType)) {
            generator = new DateTimestampGenerator(strategy);
        } else if (Long.class.isAssignableFrom(generatedType)) {
            generator = new LongTimestampGenerator(strategy);
        } else {
            generator = new NeverTimestampGenerator(generatedType, strategy);
        }
        return (Generator)generator;
    }

    /**
     * Generator for auto-generating attribute values.
     */
    static interface Generatable {
        /**
         * Determines if the value can be auto-generated for the object.
         * @param currentValue The current attribute value.
         * @return True if can be auto generated, false otherwise.
         */
        abstract public boolean canGenerate(T currentValue);
    }

    /**
     * Default logic for never generatable.
     */
    static final class NeverGeneratable implements Generatable {
        private static final Generatable INSTANCE = new NeverGeneratable();

        @SuppressWarnings("unchecked")
        private static final  Generatable instance() {
            return (Generatable)INSTANCE;
        }

        @Override
        public final boolean canGenerate(final T currentValue) {
            return false;
        }
    }

    /**
     * Default logic for always generatable.
     */
    static final class AlwaysGeneratable implements Generatable {
        private static final Generatable INSTANCE = new AlwaysGeneratable();

        @SuppressWarnings("unchecked")
        private static final  Generatable instance() {
            return (Generatable)INSTANCE;
        }

        @Override
        public final boolean canGenerate(final T currentValue) {
            return true;
        }
    }

    /**
     * Default logic for generatable on create only.
     */
    static final class CreateGeneratable implements Generatable {
        private static final Generatable INSTANCE = new CreateGeneratable();

        @SuppressWarnings("unchecked")
        private static final  Generatable instance() {
            return (Generatable)INSTANCE;
        }

        @Override
        public final boolean canGenerate(final T currentValue) {
            return (currentValue == null);
        }
    }

    /**
     * Generator for auto-generating attribute values.
     */
    static interface Generator extends Generatable {
        /**
         * Generates a new attribute value for the target object.
         * @param currentValue The current attribute value.
         * @return The new attribute value.
         */
        abstract public T generate(T currentValue);
    }

    /**
     * Abstract generator, does not generate.
     */
    private static abstract class AbstractGenerator implements Generator {
        private final Class generatedType;
        private final Generatable generatable;

        private AbstractGenerator(final Class generatedType, final Generatable generatable) {
            this.generatedType = generatedType;
            this.generatable = generatable;
        }

        private AbstractGenerator(final Class generatedType, final DynamoDBAutoGenerateStrategy strategy) {
            this(generatedType, (DynamoDBAutoGenerateStrategy.CREATE == strategy) ? CreateGeneratable.instance() : AlwaysGeneratable.instance());
        }

        private final Class getGeneratedType() {
            return this.generatedType;
        }

        private final Generatable getGeneratable() {
            return this.generatable;
        }

        @Override
        public boolean canGenerate(final T currentValue) {
            return getGeneratable().canGenerate(currentValue);
        }

        @Override
        public T generate(final T currentValue) {
            throw new DynamoDBMappingException("Generate not supported for " + getGeneratedType());
        }
    }

    /**
     * Never generator for key.
     */
    static class NeverGenerator extends AbstractGenerator {
        private NeverGenerator(final Class generatedType) {
            super(generatedType, NeverGeneratable.instance());
        }
    }

    /**
     * Never generator for key.
     */
    static class NeverKeyGenerator extends AbstractGenerator {
        private NeverKeyGenerator(final Class generatedType) {
            super(generatedType, CreateGeneratable.instance());
        }

        @Override
        public T generate(final T currentValue) {
            throw new DynamoDBMappingException("Unsupported type for @DynamoDBAutoGeneratedKey; only String allowed");
        }
    }

    /**
     * Key generator for UUID strings.
     */
    static final class UuidStringKeyGenerator extends NeverKeyGenerator {
        private UuidStringKeyGenerator() {
            super(String.class);
        }

        @Override
        public final String generate(final String currentValue) {
            return UUID.randomUUID().toString();
        }
    }

    /**
     * Never generator for version.
     */
    static class NeverVersionGenerator extends AbstractGenerator {
        private NeverVersionGenerator(final Class generatedType) {
            super(generatedType, AlwaysGeneratable.instance());
        }

        @Override
        public T generate(final T currentValue) {
            throw new DynamoDBMappingException("Unsupported type for @DynamoDBVersionAttribute; only BigInteger, Byte, Integer or Long allowed");
        }
    }

    /**
     * Version generator for {@code BigInteger} types.
     */
    static final class BigIntegerVersionGenerator extends NeverVersionGenerator {
        private BigIntegerVersionGenerator() {
            super(BigInteger.class);
        }

        @Override
        public final BigInteger generate(final BigInteger currentValue) {
            if (currentValue == null) {
                return BigInteger.ONE;
            }
            return currentValue.add(BigInteger.ONE);
        }
    }

    /**
     * Version generator for {@code Byte} types.
     */
    static final class ByteVersionGenerator extends NeverVersionGenerator {
        private ByteVersionGenerator() {
            super(Byte.class);
        }

        @Override
        public final Byte generate(final Byte currentValue) {
            if (currentValue == null) {
                return Byte.valueOf((byte)1);
            }
            // Mod MAX_VALUE since that's what the DynamoDBReflector used to do.
            return (byte)((currentValue + 1) % Byte.MAX_VALUE);
        }
    }

    /**
     * Version generator for {@code Integer} types.
     */
    static final class IntegerVersionGenerator extends NeverVersionGenerator {
        private IntegerVersionGenerator() {
            super(Integer.class);
        }

        @Override
        public final Integer generate(final Integer currentValue) {
            if (currentValue == null) {
                return Integer.valueOf(1);
            }
            return (int)(currentValue + 1);
        }
    }

    /**
     * Version generator for {@code Long} types.
     */
    static final class LongVersionGenerator extends NeverVersionGenerator {
        private LongVersionGenerator() {
            super(Long.class);
        }

        @Override
        public final Long generate(final Long currentValue) {
            if (currentValue == null) {
                return Long.valueOf(1L);
            }
            return (long)(currentValue + 1L);
        }
    }

    /**
     * Version generator for {@code Short} types.
     */
    static final class ShortVersionGenerator extends NeverVersionGenerator {
        private ShortVersionGenerator() {
            super(Short.class);
        }

        @Override
        public final Short generate(final Short currentValue) {
            if (currentValue == null) {
                return Short.valueOf((short)1);
            }
            return (short)(currentValue + 1);
        }
    }

    /**
     * Never generator for timestamp.
     */
    static class NeverTimestampGenerator extends AbstractGenerator {
        private NeverTimestampGenerator(final Class generatedType, final DynamoDBAutoGenerateStrategy strategy) {
            super(generatedType, strategy);
        }

        @Override
        public T generate(final T currentValue) {
            throw new DynamoDBMappingException("Unsupported type for @DynamoDBAutoGeneratedTimestamp; only Calendar, Date, or Long allowed");
        }
    }

    /**
     * Timestamp generator for {@code Calendar} types.
     */
    static final class CalendarTimestampGenerator extends NeverTimestampGenerator {
        private CalendarTimestampGenerator(final DynamoDBAutoGenerateStrategy strategy) {
            super(Calendar.class, strategy);
        }

        @Override
        public final Calendar generate(final Calendar currentValue) {
            return Calendar.getInstance();
        }
    }

    /**
     * Timestamp generator for {@code Date} types.
     */
    static final class DateTimestampGenerator extends NeverTimestampGenerator {
        private DateTimestampGenerator(final DynamoDBAutoGenerateStrategy strategy) {
            super(Date.class, strategy);
        }

        @Override
        public final Date generate(final Date currentValue) {
            return Calendar.getInstance().getTime();
        }
    }

    /**
     * Timestamp generator for {@code Long} types; milliseconds from epoch in UTC.
     */
    static final class LongTimestampGenerator extends NeverTimestampGenerator {
        private static final TimeZone UTC = TimeZone.getTimeZone("UTC");

        private LongTimestampGenerator(final DynamoDBAutoGenerateStrategy strategy) {
            super(Long.class, strategy);
        }

        @Override
        public final Long generate(final Long currentValue) {
            return Calendar.getInstance(UTC).getTime().getTime();
        }
    }

}