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 SDK for Java with support for OSGi. The AWS SDK for Java provides Java APIs for building software on AWS' cost-effective, scalable, and reliable infrastructure products. The AWS Java SDK allows developers to code against APIs for all of Amazon's infrastructure web services (Amazon S3, Amazon EC2, Amazon SQS, Amazon Relational Database Service, Amazon AutoScaling, etc).

There is a newer version: 1.11.60
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();
        }
    }

}