yegor256/rehttp

View on GitHub
src/main/java/net/rehttp/base/DyBase.java

Summary

Maintainability
A
1 hr
Test Coverage
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017-2024 Yegor Bugayenko
 *
 * Permission is hereby granted, free of charge,  to any person obtaining
 * a copy  of  this  software  and  associated  documentation files  (the
 * "Software"),  to deal in the Software  without restriction,  including
 * without limitation the rights to use,  copy,  modify,  merge, publish,
 * distribute,  sublicense,  and/or sell  copies of the Software,  and to
 * permit persons to whom the Software is furnished to do so,  subject to
 * the  following  conditions:   the  above  copyright  notice  and  this
 * permission notice  shall  be  included  in  all copies or  substantial
 * portions of the Software.  The software is provided  "as is",  without
 * warranty of any kind, express or implied, including but not limited to
 * the warranties  of merchantability,  fitness for  a particular purpose
 * and non-infringement.  In  no  event shall  the  authors  or copyright
 * holders be liable for any claim,  damages or other liability,  whether
 * in an action of contract,  tort or otherwise,  arising from, out of or
 * in connection with the software or  the  use  or other dealings in the
 * software.
 */
package net.rehttp.base;

import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.amazonaws.services.dynamodbv2.model.Select;
import com.jcabi.dynamo.Attributes;
import com.jcabi.dynamo.Conditions;
import com.jcabi.dynamo.Item;
import com.jcabi.dynamo.QueryValve;
import com.jcabi.dynamo.Region;
import com.jcabi.dynamo.Table;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import org.cactoos.iterable.Mapped;
import org.takes.Take;

/**
 * Base in DynamoDB.
 *
 * @since 1.0
 * @checkstyle MultipleStringLiteralsCheck (500 lines)
 * @checkstyle ClassDataAbstractionCouplingCheck (500 lines)
 */
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
public final class DyBase implements Base {

    /**
     * The region to work with.
     */
    private final transient Region region;

    /**
     * Delay in msecs between attempts.
     */
    private final transient long delay;

    /**
     * Ctor.
     * @param reg Region
     */
    public DyBase(final Region reg) {
        this(reg, TimeUnit.HOURS.toMillis(1L));
    }

    /**
     * Ctor.
     * @param reg Region
     * @param msec Delay in msecs between attempts
     */
    public DyBase(final Region reg, final long msec) {
        this.region = reg;
        this.delay = msec;
    }

    @Override
    public Take target(final URL url, final long time) throws IOException {
        final Collection<Item> items = this.table()
            .frame()
            .through(
                new QueryValve()
                    .withSelect(Select.ALL_ATTRIBUTES)
                    .withLimit(1)
            )
            .where("url", Conditions.equalTo(url))
            .where("time", Conditions.equalTo(time));
        final Item item;
        if (items.isEmpty()) {
            item = this.table().put(
                new Attributes()
                    .with("url", url)
                    .with("time", time)
                    .with("code", 0)
                    .with("attempts", 0)
                    .with("when", System.currentTimeMillis())
                    .with(
                        "ttl",
                        (System.currentTimeMillis()
                            + TimeUnit.DAYS.toMillis(1L))
                            / TimeUnit.SECONDS.toMillis(1L)
                    )
            );
        } else {
            item = items.iterator().next();
        }
        return new DyTake(item, this.delay);
    }

    @Override
    public Iterable<Take> expired() {
        return new Mapped<>(
            item -> new DyTake(item, this.delay),
            this.table()
                .frame()
                .through(
                    new QueryValve()
                        .withIndexName("expired")
                        .withConsistentRead(false)
                        .withSelect(Select.ALL_ATTRIBUTES)
                )
                .where("success", Conditions.equalTo(Boolean.toString(false)))
                .where(
                    "when",
                    new Condition()
                        .withComparisonOperator(ComparisonOperator.LT)
                        .withAttributeValueList(
                            new AttributeValue().withN(
                                Long.toString(System.currentTimeMillis())
                            )
                        )
                )
        );
    }

    @Override
    public Status status(final URL url) {
        return new DyStatus(this.region, url);
    }

    /**
     * Table to work with.
     * @return Table
     */
    private Table table() {
        return this.region.table("targets");
    }

}