├── asto-core └── src │ ├── test │ ├── resources │ │ ├── folder │ │ │ ├── one.txt │ │ │ └── two.txt │ │ ├── test.txt │ │ └── log4j.properties │ └── java │ │ └── com │ │ ├── artipie │ │ └── asto │ │ │ ├── misc │ │ │ ├── package-info.java │ │ │ ├── UncheckedScalarTest.java │ │ │ ├── UncheckedSupplierTest.java │ │ │ ├── UncheckedFuncTest.java │ │ │ └── UncheckedConsumerTest.java │ │ │ ├── fs │ │ │ ├── package-info.java │ │ │ └── FileMetaTest.java │ │ │ ├── key │ │ │ ├── package-info.java │ │ │ ├── KeyExcludeAllTest.java │ │ │ ├── KeyExcludeByIndexTest.java │ │ │ ├── KeyInsertTest.java │ │ │ ├── KeyExcludeLastTest.java │ │ │ └── KeyExcludeFirstTest.java │ │ │ ├── package-info.java │ │ │ ├── cache │ │ │ ├── package-info.java │ │ │ ├── CacheControlTest.java │ │ │ ├── RemoteWithErrorHandlingTest.java │ │ │ └── DigestVerificationTest.java │ │ │ ├── ext │ │ │ ├── package-info.java │ │ │ ├── KeyLastPartTest.java │ │ │ ├── ContentDigestTest.java │ │ │ ├── ContentAsTest.java │ │ │ ├── PublisherAsTest.java │ │ │ └── DigestsTest.java │ │ │ ├── lock │ │ │ ├── package-info.java │ │ │ └── storage │ │ │ │ └── package-info.java │ │ │ ├── test │ │ │ └── package-info.java │ │ │ ├── blocking │ │ │ └── package-info.java │ │ │ ├── factory │ │ │ └── package-info.java │ │ │ ├── streams │ │ │ ├── package-info.java │ │ │ ├── ContentAsStreamTest.java │ │ │ ├── PublishingOutputStreamTest.java │ │ │ └── ContentAsInputStreamTest.java │ │ │ ├── rx │ │ │ └── package-info.java │ │ │ ├── memory │ │ │ ├── package-info.java │ │ │ ├── InMemoryStorageTest.java │ │ │ ├── BenchmarkStorageExistsTest.java │ │ │ ├── BenchmarkStorageDeleteTest.java │ │ │ └── BenchmarkStorageSizeTest.java │ │ │ ├── InMemoryStorageVerificationTest.java │ │ │ ├── RemainingTest.java │ │ │ ├── OneTimePublisherTest.java │ │ │ ├── MetaCommonTest.java │ │ │ ├── BenchmarkStorageVerificationTest.java │ │ │ ├── ContentTest.java │ │ │ ├── FileStorageWhiteboxVerificationTest.java │ │ │ ├── OneTimePublisherVerificationTest.java │ │ │ ├── SplittingTest.java │ │ │ └── CopyTest.java │ │ └── third │ │ └── party │ │ └── factory │ │ ├── first │ │ ├── package-info.java │ │ └── TestFirstStorageFactory.java │ │ ├── first2 │ │ ├── package-info.java │ │ └── TestFirst2StorageFactory.java │ │ └── second │ │ ├── package-info.java │ │ └── TestSecondStorageFactory.java │ └── main │ └── java │ └── com │ └── artipie │ ├── package-info.java │ ├── asto │ ├── misc │ │ ├── package-info.java │ │ ├── Scalar.java │ │ ├── Cleanable.java │ │ ├── UncheckedIOConsumer.java │ │ ├── UncheckedIOFunc.java │ │ ├── UncheckedIOSupplier.java │ │ ├── UncheckedIOScalar.java │ │ ├── UncheckedScalar.java │ │ ├── UncheckedConsumer.java │ │ ├── UncheckedFunc.java │ │ ├── UncheckedSupplier.java │ │ └── UncheckedRunnable.java │ ├── package-info.java │ ├── cache │ │ ├── package-info.java │ │ ├── Cache.java │ │ ├── DigestVerification.java │ │ ├── FromRemoteCache.java │ │ ├── FromStorageCache.java │ │ └── Remote.java │ ├── rx │ │ ├── package-info.java │ │ ├── RxStorage.java │ │ └── RxStorageWrapper.java │ ├── factory │ │ ├── package-info.java │ │ ├── ArtipieStorageFactory.java │ │ ├── StorageNotFoundException.java │ │ ├── StorageFactory.java │ │ └── StoragesLoader.java │ ├── fs │ │ ├── package-info.java │ │ ├── FileStorageFactory.java │ │ └── FileMeta.java │ ├── blocking │ │ └── package-info.java │ ├── ext │ │ ├── package-info.java │ │ ├── KeyLastPart.java │ │ ├── CompletableFutureSupport.java │ │ ├── ContentAs.java │ │ ├── Digests.java │ │ └── PublisherAs.java │ ├── key │ │ ├── package-info.java │ │ ├── KeyExcludeAll.java │ │ ├── KeyInsert.java │ │ ├── KeyExcludeByIndex.java │ │ ├── KeyExcludeFirst.java │ │ └── KeyExcludeLast.java │ ├── streams │ │ ├── package-info.java │ │ └── ContentAsStream.java │ ├── memory │ │ └── package-info.java │ ├── lock │ │ ├── package-info.java │ │ ├── storage │ │ │ └── package-info.java │ │ ├── Lock.java │ │ ├── RxLock.java │ │ └── RetryLock.java │ ├── test │ │ ├── package-info.java │ │ └── ContentIs.java │ ├── MetaCommon.java │ ├── ValueNotFoundException.java │ ├── Remaining.java │ ├── Concatenation.java │ ├── OneTimePublisher.java │ ├── Splitting.java │ ├── ArtipieIOException.java │ ├── UnderLockOperation.java │ ├── ByteArray.java │ └── Copy.java │ └── ArtipieException.java ├── .0pdd.yml ├── .gitignore ├── LICENSE.header ├── .gitattributes ├── asto-s3 └── src │ ├── test │ └── java │ │ └── com │ │ └── artipie │ │ └── asto │ │ ├── package-info.java │ │ ├── s3 │ │ ├── package-info.java │ │ ├── S3HeadMetaTest.java │ │ ├── EstimatedContentTest.java │ │ └── InternalExceptionHandleTest.java │ │ ├── S3StorageWhiteboxVerificationTest.java │ │ └── S3StorageFactoryTest.java │ └── main │ └── java │ └── com │ └── artipie │ └── asto │ └── s3 │ ├── package-info.java │ ├── S3HeadMeta.java │ ├── InternalExceptionHandle.java │ └── Bucket.java ├── asto-artipie ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── artipie │ │ │ └── asto │ │ │ └── package-info.java │ └── test │ │ └── java │ │ └── com │ │ └── artipie │ │ └── asto │ │ └── package-info.java └── pom.xml ├── asto-etcd ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── artipie │ │ │ └── asto │ │ │ └── etcd │ │ │ ├── package-info.java │ │ │ ├── EtcdMeta.java │ │ │ └── EtcdStorageFactory.java │ └── test │ │ └── java │ │ └── com │ │ └── artipie │ │ └── asto │ │ └── etcd │ │ ├── package-info.java │ │ ├── EtcdStorageFactoryTest.java │ │ └── EtcdStorageVerificationTest.java └── pom.xml ├── asto-redis ├── src │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── artipie │ │ │ └── asto │ │ │ └── redis │ │ │ ├── package-info.java │ │ │ └── RedisStorageWhiteboxVerificationTest.java │ └── main │ │ └── java │ │ └── com │ │ └── artipie │ │ └── asto │ │ └── redis │ │ ├── package-info.java │ │ └── RedisStorageFactory.java └── pom.xml ├── .github ├── workflows │ ├── pdd.yml │ ├── xcop.yml │ ├── update-copyright-years.yml │ ├── maven.yml │ ├── deploy-snapshot.yml │ └── release.yml └── dependabot.yml ├── asto-vertx-file ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── artipie │ │ │ └── asto │ │ │ └── fs │ │ │ ├── package-info.java │ │ │ └── VertxFileStorageFactory.java │ └── test │ │ └── java │ │ └── com │ │ └── artipie │ │ └── asto │ │ ├── package-info.java │ │ ├── VertxFileStorageFactoryTest.java │ │ └── VertxFileStorageVerificationTest.java └── pom.xml ├── .rultor.yml └── LICENSE.txt /asto-core/src/test/resources/folder/one.txt: -------------------------------------------------------------------------------- 1 | one -------------------------------------------------------------------------------- /asto-core/src/test/resources/folder/two.txt: -------------------------------------------------------------------------------- 1 | two -------------------------------------------------------------------------------- /asto-core/src/test/resources/test.txt: -------------------------------------------------------------------------------- 1 | hello world -------------------------------------------------------------------------------- /.0pdd.yml: -------------------------------------------------------------------------------- 1 | format: 2 | - short-title 3 | - title-length=100 4 | tags: 5 | - tech-debt 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ 3 | *.iml 4 | .DS_Store 5 | .classpath 6 | .project 7 | .settings/** 8 | -------------------------------------------------------------------------------- /LICENSE.header: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 2 | https://github.com/artipie/asto/LICENSE.txt 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Check out all text files in UNIX format, with LF as end of line 2 | # Don't change this file. If you have any ideas about it, please 3 | # submit a separate issue about it and we'll discuss. 4 | 5 | * text=auto eol=lf 6 | *.java ident 7 | *.xml ident 8 | *.png binary 9 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Abstract base package. 8 | * 9 | * @since 1.0 10 | */ 11 | package com.artipie; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Misc tools. 8 | * 9 | * @since 1.2 10 | */ 11 | package com.artipie.asto.misc; 12 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Abstract Storage. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto; 12 | 13 | -------------------------------------------------------------------------------- /asto-s3/src/test/java/com/artipie/asto/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * S3 storage tests. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto; 12 | 13 | -------------------------------------------------------------------------------- /asto-artipie/src/main/java/com/artipie/asto/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Artipie Storage. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/misc/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Misc tools tests. 8 | * 9 | * @since 1.1 10 | */ 11 | package com.artipie.asto.misc; 12 | -------------------------------------------------------------------------------- /asto-etcd/src/main/java/com/artipie/asto/etcd/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Etcd based storage. 8 | * @since 0.1 9 | */ 10 | package com.artipie.asto.etcd; 11 | 12 | -------------------------------------------------------------------------------- /asto-artipie/src/test/java/com/artipie/asto/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Artipie Storage tests. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/cache/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Caching objects. 8 | * 9 | * @since 0.24 10 | */ 11 | package com.artipie.asto.cache; 12 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/rx/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * RxJava version of asto. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto.rx; 12 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/fs/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for FS objects. 8 | * 9 | * @since 1.9 10 | */ 11 | package com.artipie.asto.fs; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/key/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for Key. 8 | * 9 | * @since 1.8.1 10 | */ 11 | package com.artipie.asto.key; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Abstract storage, tests. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/cache/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for cache. 8 | * 9 | * @since 0.24 10 | */ 11 | package com.artipie.asto.cache; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/ext/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for extensions. 8 | * 9 | * @since 0.6 10 | */ 11 | package com.artipie.asto.ext; 12 | 13 | -------------------------------------------------------------------------------- /asto-etcd/src/test/java/com/artipie/asto/etcd/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * EtcdStorage tests. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto.etcd; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/factory/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Storage factory. 8 | * 9 | * @since 1.13.0 10 | */ 11 | package com.artipie.asto.factory; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/fs/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * File system implementation of asto. 8 | * 9 | * @since 0.10 10 | */ 11 | package com.artipie.asto.fs; 12 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/lock/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for lock related classes. 8 | * 9 | * @since 0.24 10 | */ 11 | package com.artipie.asto.lock; 12 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/test/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for classes for tests. 8 | * 9 | * @since 0.24 10 | */ 11 | package com.artipie.asto.test; 12 | -------------------------------------------------------------------------------- /asto-core/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=WARN, CONSOLE 2 | 3 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 4 | log4j.appender.CONSOLE.layout=com.jcabi.log.MulticolorLayout 5 | log4j.appender.CONSOLE.layout.ConversionPattern=[%color{%p}] %t %c: %m%n 6 | 7 | log4j.logger.com.artipie.asto=DEBUG -------------------------------------------------------------------------------- /asto-redis/src/test/java/com/artipie/asto/redis/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for redis storage. 8 | * 9 | * @since 1.12.0 10 | */ 11 | package com.artipie.asto.redis; 12 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/blocking/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Blocking version of asto. 8 | * 9 | * @since 0.10 10 | */ 11 | package com.artipie.asto.blocking; 12 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/ext/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Storage and content extensions. 8 | * 9 | * @since 0.6 10 | */ 11 | package com.artipie.asto.ext; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/key/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Implementations of storage key. 8 | * 9 | * @since 1.8.1 10 | */ 11 | package com.artipie.asto.key; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/streams/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Storage items as IO streams. 8 | * 9 | * @since 1.4 10 | */ 11 | package com.artipie.asto.streams; 12 | -------------------------------------------------------------------------------- /asto-redis/src/main/java/com/artipie/asto/redis/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Redis implementation of Storage. 8 | * 9 | * @since 1.12.0 10 | */ 11 | package com.artipie.asto.redis; 12 | -------------------------------------------------------------------------------- /asto-s3/src/test/java/com/artipie/asto/s3/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for S3 storage related classes. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto.s3; 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/pdd.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: PDD linter 3 | "on": 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | brranches: 9 | - master 10 | jobs: 11 | pdd-lint: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: g4s8/pdd-action@master 16 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/memory/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * In memory implementation of Storage. 8 | * 9 | * @since 0.14 10 | */ 11 | package com.artipie.asto.memory; 12 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/blocking/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for BlockingStorage. 8 | * 9 | * @since 0.24 10 | */ 11 | package com.artipie.asto.blocking; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/factory/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests fo Storage factory classes. 8 | * 9 | * @since 1.13.0 10 | */ 11 | package com.artipie.asto.factory; 12 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/streams/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Storage items as IO streams tests. 8 | * 9 | * @since 1.4 10 | */ 11 | package com.artipie.asto.streams; 12 | -------------------------------------------------------------------------------- /asto-s3/src/main/java/com/artipie/asto/s3/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Implementation of storage that holds data in S3. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto.s3; 12 | -------------------------------------------------------------------------------- /asto-vertx-file/src/main/java/com/artipie/asto/fs/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Vertx file system implementation of asto. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto.fs; 12 | -------------------------------------------------------------------------------- /.github/workflows/xcop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: XCOP linter 3 | "on": 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | brranches: 9 | - master 10 | jobs: 11 | xcop-lint: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: g4s8/xcop-action@master 16 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/rx/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for {@link com.artipie.asto.rx.RxStorage}. 8 | * 9 | * @since 1.11 10 | */ 11 | package com.artipie.asto.rx; 12 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/lock/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Locks for controlling access to shared resources. 8 | * 9 | * @since 0.24 10 | */ 11 | package com.artipie.asto.lock; 12 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/third/party/factory/first/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Storage factory classes for tests. 8 | * 9 | * @since 1.13.0 10 | */ 11 | package com.third.party.factory.first; 12 | -------------------------------------------------------------------------------- /asto-vertx-file/src/test/java/com/artipie/asto/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Vertx file system implementation of asto tests. 8 | * 9 | * @since 0.1 10 | */ 11 | package com.artipie.asto; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/memory/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for in memory storage related classes. 8 | * 9 | * @since 0.15 10 | */ 11 | package com.artipie.asto.memory; 12 | 13 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/third/party/factory/first2/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Storage factory classes for tests. 8 | * 9 | * @since 1.13.0 10 | */ 11 | package com.third.party.factory.first2; 12 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/third/party/factory/second/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Storage factory classes for tests. 8 | * 9 | * @since 1.13.0 10 | */ 11 | package com.third.party.factory.second; 12 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/test/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Classes for tests, do not use this package in the main code. 8 | * 9 | * @since 0.24 10 | */ 11 | package com.artipie.asto.test; 12 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/lock/storage/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Tests for storage lock implementation classes. 8 | * 9 | * @since 0.24 10 | */ 11 | package com.artipie.asto.lock.storage; 12 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/lock/storage/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | /** 7 | * Storage implementation for {@link com.artipie.asto.lock.Lock}. 8 | * 9 | * @since 0.24 10 | */ 11 | package com.artipie.asto.lock.storage; 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: "maven" 7 | directory: "/" 8 | labels: 9 | - "dependencies" 10 | - "bot" 11 | schedule: 12 | interval: "daily" 13 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/Scalar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | /** 8 | * Scalar. 9 | * Originally introduced in cactoos. 10 | * @param Result value type 11 | * @since 1.3 12 | */ 13 | @FunctionalInterface 14 | public interface Scalar { 15 | 16 | /** 17 | * Convert it to the value. 18 | * @return The value 19 | * @throws Exception If fails 20 | */ 21 | T value() throws Exception; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/Cleanable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | /** 8 | * Cleanable interface to represent objects that can be cleaned/invalidated. 9 | * @param The key type. 10 | * @since 1.16 11 | */ 12 | public interface Cleanable { 13 | 14 | /** 15 | * Invalidate object by the specified key. 16 | * @param key The key 17 | */ 18 | void invalidate(T key); 19 | 20 | /** 21 | * Invalidate all. 22 | */ 23 | void invalidateAll(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/factory/ArtipieStorageFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.factory; 6 | 7 | import java.lang.annotation.ElementType; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | 12 | /** 13 | * Annotation to mark StorageFactory implementation. 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.TYPE) 17 | public @interface ArtipieStorageFactory { 18 | /** 19 | * Storage type. 20 | * 21 | * @return Supported storage type. 22 | */ 23 | String value(); 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/update-copyright-years.yml: -------------------------------------------------------------------------------- 1 | name: Update copyright year 2 | 3 | on: 4 | schedule: 5 | - cron: '0 1 22 * *' # Runs at 01:00 UTC on the 22nd of every month 6 | 7 | jobs: 8 | license: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | with: 13 | fetch-depth: 0 14 | - uses: FantasticFiasco/action-update-license-year@v2 15 | with: 16 | token: ${{ secrets.LICENSE_SECRET }} 17 | path: | # Add new path with glob pattern https://www.npmjs.com/package/glob 18 | **/LICENSE* 19 | **/*.java 20 | **/*.rb 21 | **/*.py 22 | **/*.xml 23 | .release/* 24 | commitTitle: "chore: update license year" 25 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/lock/Lock.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.lock; 6 | 7 | import java.util.concurrent.CompletionStage; 8 | 9 | /** 10 | * Asynchronous lock that might be successfully obtained by one thread only at a time. 11 | * 12 | * @since 0.24 13 | */ 14 | public interface Lock { 15 | 16 | /** 17 | * Acquire the lock. 18 | * 19 | * @return Completion of lock acquire operation. 20 | */ 21 | CompletionStage acquire(); 22 | 23 | /** 24 | * Release the lock. 25 | * 26 | * @return Completion of lock release operation. 27 | */ 28 | CompletionStage release(); 29 | } 30 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/factory/StorageNotFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.factory; 6 | 7 | import com.artipie.ArtipieException; 8 | 9 | /** 10 | * Exception indicating that {@link StorageFactory} cannot be found. 11 | * 12 | * @since 1.13.0 13 | */ 14 | public class StorageNotFoundException extends ArtipieException { 15 | 16 | private static final long serialVersionUID = 0L; 17 | 18 | /** 19 | * Ctor. 20 | * 21 | * @param type Storage type 22 | */ 23 | public StorageNotFoundException(final String type) { 24 | super(String.format("Storage with type '%s' is not found.", type)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/InMemoryStorageVerificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.artipie.asto.memory.InMemoryStorage; 8 | import com.artipie.asto.test.StorageWhiteboxVerification; 9 | 10 | /** 11 | * In memory storage verification test. 12 | * 13 | * @checkstyle ProtectedMethodInFinalClassCheck (500 lines) 14 | * @since 1.14.0 15 | */ 16 | @SuppressWarnings("PMD.TestClassWithoutTestCases") 17 | public final class InMemoryStorageVerificationTest extends StorageWhiteboxVerification { 18 | 19 | @Override 20 | protected Storage newStorage() throws Exception { 21 | return new InMemoryStorage(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/third/party/factory/first/TestFirstStorageFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.third.party.factory.first; 6 | 7 | import com.artipie.asto.Storage; 8 | import com.artipie.asto.factory.ArtipieStorageFactory; 9 | import com.artipie.asto.factory.Config; 10 | import com.artipie.asto.factory.StorageFactory; 11 | import com.artipie.asto.memory.InMemoryStorage; 12 | 13 | /** 14 | * Test storage factory. 15 | * 16 | * @since 1.13.0 17 | */ 18 | @ArtipieStorageFactory("test-first") 19 | public final class TestFirstStorageFactory implements StorageFactory { 20 | @Override 21 | public Storage newStorage(final Config cfg) { 22 | return new InMemoryStorage(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/third/party/factory/first2/TestFirst2StorageFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.third.party.factory.first2; 6 | 7 | import com.artipie.asto.Storage; 8 | import com.artipie.asto.factory.ArtipieStorageFactory; 9 | import com.artipie.asto.factory.Config; 10 | import com.artipie.asto.factory.StorageFactory; 11 | import com.artipie.asto.memory.InMemoryStorage; 12 | 13 | /** 14 | * Test storage factory. 15 | * 16 | * @since 1.13.0 17 | */ 18 | @ArtipieStorageFactory("test-first") 19 | public final class TestFirst2StorageFactory implements StorageFactory { 20 | @Override 21 | public Storage newStorage(final Config cfg) { 22 | return new InMemoryStorage(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/third/party/factory/second/TestSecondStorageFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.third.party.factory.second; 6 | 7 | import com.artipie.asto.Storage; 8 | import com.artipie.asto.factory.ArtipieStorageFactory; 9 | import com.artipie.asto.factory.Config; 10 | import com.artipie.asto.factory.StorageFactory; 11 | import com.artipie.asto.memory.InMemoryStorage; 12 | 13 | /** 14 | * Test storage factory. 15 | * 16 | * @since 1.13.0 17 | */ 18 | @ArtipieStorageFactory("test-second") 19 | public final class TestSecondStorageFactory implements StorageFactory { 20 | @Override 21 | public Storage newStorage(final Config cfg) { 22 | return new InMemoryStorage(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/fs/FileStorageFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.fs; 6 | 7 | import com.artipie.asto.Storage; 8 | import com.artipie.asto.factory.ArtipieStorageFactory; 9 | import com.artipie.asto.factory.Config; 10 | import com.artipie.asto.factory.StorageFactory; 11 | import java.nio.file.Paths; 12 | 13 | /** 14 | * File storage factory. 15 | * 16 | * @since 1.13.0 17 | */ 18 | @ArtipieStorageFactory("fs") 19 | public final class FileStorageFactory implements StorageFactory { 20 | @Override 21 | public Storage newStorage(final Config cfg) { 22 | return new FileStorage( 23 | Paths.get(new Config.StrictStorageConfig(cfg).string("path")) 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Maven Build 3 | "on": 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | jobs: 11 | maven-build: 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | os: [windows-latest, ubuntu-latest] 16 | java: [1.8, 11, 13] 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up JDK 20 | uses: actions/setup-java@v1 21 | with: 22 | java-version: ${{ matrix.java }} 23 | - uses: actions/cache@v1 24 | with: 25 | path: ~/.m2/repository 26 | key: ${{ runner.os }}-jdk-${{ matrix.java }}-mvn-${{ hashFiles('**/pom.xml') }} 27 | restore-keys: | 28 | ${{ runner.os }}-jdk-${{ matrix.java }}-mvn- 29 | - name: Build it with Maven 30 | run: mvn clean verify -B -Pqulice 31 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/MetaCommon.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.artipie.ArtipieException; 8 | 9 | /** 10 | * Helper object to read common metadata from {@link Meta}. 11 | * @since 1.11 12 | */ 13 | public final class MetaCommon { 14 | 15 | /** 16 | * Metadata. 17 | */ 18 | private final Meta meta; 19 | 20 | /** 21 | * Ctor. 22 | * @param meta Metadata 23 | */ 24 | public MetaCommon(final Meta meta) { 25 | this.meta = meta; 26 | } 27 | 28 | /** 29 | * Size. 30 | * @return Size 31 | */ 32 | public long size() { 33 | return this.meta.read(Meta.OP_SIZE).orElseThrow( 34 | () -> new ArtipieException("SIZE couldn't be read") 35 | ).longValue(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/ext/KeyLastPart.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.ext; 6 | 7 | import com.artipie.asto.Key; 8 | 9 | /** 10 | * Last part of the storage {@link com.artipie.asto.Key}. 11 | * @since 0.24 12 | */ 13 | public final class KeyLastPart { 14 | 15 | /** 16 | * Origin key. 17 | */ 18 | private final Key origin; 19 | 20 | /** 21 | * Ctor. 22 | * @param origin Key 23 | */ 24 | public KeyLastPart(final Key origin) { 25 | this.origin = origin; 26 | } 27 | 28 | /** 29 | * Get last part of the key. 30 | * @return Key last part as string 31 | */ 32 | public String get() { 33 | final String[] parts = this.origin.string().replaceAll("/$", "").split("/"); 34 | return parts[parts.length - 1]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/factory/StorageFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.factory; 6 | 7 | import com.amihaiemil.eoyaml.YamlMapping; 8 | import com.artipie.asto.Storage; 9 | 10 | /** 11 | * Storage factory interface. 12 | * 13 | * @since 1.13.0 14 | */ 15 | public interface StorageFactory { 16 | 17 | /** 18 | * Create new storage. 19 | * 20 | * @param cfg Storage configuration. 21 | * @return Storage 22 | */ 23 | Storage newStorage(Config cfg); 24 | 25 | /** 26 | * Create new storage. 27 | * 28 | * @param cfg Storage configuration. 29 | * @return Storage 30 | */ 31 | default Storage newStorage(YamlMapping cfg) { 32 | return this.newStorage( 33 | new Config.YamlStorageConfig(cfg) 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /asto-vertx-file/src/main/java/com/artipie/asto/fs/VertxFileStorageFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.fs; 6 | 7 | import com.artipie.asto.Storage; 8 | import com.artipie.asto.factory.ArtipieStorageFactory; 9 | import com.artipie.asto.factory.Config; 10 | import com.artipie.asto.factory.StorageFactory; 11 | import io.vertx.reactivex.core.Vertx; 12 | import java.nio.file.Paths; 13 | 14 | /** 15 | * File storage factory. 16 | * 17 | * @since 0.1 18 | */ 19 | @ArtipieStorageFactory("vertx-file") 20 | public final class VertxFileStorageFactory implements StorageFactory { 21 | @Override 22 | public Storage newStorage(final Config cfg) { 23 | return new VertxFileStorage( 24 | Paths.get(new Config.StrictStorageConfig(cfg).string("path")), 25 | Vertx.vertx() 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/key/KeyExcludeAll.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | package com.artipie.asto.key; 7 | 8 | import com.artipie.asto.Key; 9 | import java.util.stream.Collectors; 10 | 11 | /** 12 | * Key that excludes all occurrences of a part. 13 | * @implNote If part to exclude was not found, the class can return the origin key. 14 | * @since 1.8.1 15 | */ 16 | public final class KeyExcludeAll extends Key.Wrap { 17 | 18 | /** 19 | * Ctor. 20 | * @param key Key 21 | * @param part Part to exclude 22 | */ 23 | public KeyExcludeAll(final Key key, final String part) { 24 | super( 25 | new Key.From( 26 | key.parts().stream() 27 | .filter(p -> !p.equals(part)) 28 | .collect(Collectors.toList()) 29 | ) 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/RemainingTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | package com.artipie.asto; 7 | 8 | import java.nio.ByteBuffer; 9 | import org.hamcrest.MatcherAssert; 10 | import org.hamcrest.core.IsEqual; 11 | import org.junit.jupiter.api.Test; 12 | 13 | /** 14 | * Test case for {@link Remaining}. 15 | * @since 0.32 16 | */ 17 | public final class RemainingTest { 18 | 19 | @Test 20 | public void readTwiceWithRestoreStrategy() throws Exception { 21 | final ByteBuffer buf = ByteBuffer.allocate(32); 22 | final byte[] array = new byte[]{1, 2, 3, 4}; 23 | buf.put(array); 24 | buf.flip(); 25 | MatcherAssert.assertThat( 26 | new Remaining(buf, true).bytes(), new IsEqual<>(array) 27 | ); 28 | MatcherAssert.assertThat( 29 | new Remaining(buf, true).bytes(), new IsEqual<>(array) 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/ext/KeyLastPartTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.ext; 6 | 7 | import com.artipie.asto.Key; 8 | import org.hamcrest.MatcherAssert; 9 | import org.hamcrest.core.IsEqual; 10 | import org.junit.jupiter.params.ParameterizedTest; 11 | import org.junit.jupiter.params.provider.CsvSource; 12 | 13 | /** 14 | * Test for {@link KeyLastPart}. 15 | * @since 0.24 16 | */ 17 | class KeyLastPartTest { 18 | 19 | @ParameterizedTest 20 | @CsvSource({ 21 | "abc/def/some_file.txt,some_file.txt", 22 | "a/b/c/e/c,c", 23 | "one,one", 24 | "four/,four", 25 | "'',''" 26 | }) 27 | void normalisesNames(final String key, final String expected) { 28 | MatcherAssert.assertThat( 29 | new KeyLastPart(new Key.From(key)).get(), 30 | new IsEqual<>(expected) 31 | ); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/key/KeyExcludeAllTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.key; 6 | 7 | import com.artipie.asto.Key; 8 | import org.hamcrest.MatcherAssert; 9 | import org.hamcrest.core.IsEqual; 10 | import org.junit.jupiter.api.Test; 11 | 12 | /** 13 | * Test case for {@link KeyExcludeAll}. 14 | * 15 | * @since 1.8.1 16 | */ 17 | final class KeyExcludeAllTest { 18 | 19 | @Test 20 | void excludesAllPart() { 21 | final Key key = new Key.From("1", "2", "1"); 22 | MatcherAssert.assertThat( 23 | new KeyExcludeAll(key, "1").string(), 24 | new IsEqual<>("2") 25 | ); 26 | } 27 | 28 | @Test 29 | void excludesNonExistingPart() { 30 | final Key key = new Key.From("1", "2"); 31 | MatcherAssert.assertThat( 32 | new KeyExcludeAll(key, "3").string(), 33 | new IsEqual<>("1/2") 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/key/KeyExcludeByIndexTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.key; 6 | 7 | import com.artipie.asto.Key; 8 | import org.hamcrest.MatcherAssert; 9 | import org.hamcrest.core.IsEqual; 10 | import org.junit.jupiter.api.Test; 11 | 12 | /** 13 | * Test case for {@link KeyExcludeByIndex}. 14 | * 15 | * @since 1.9.1 16 | */ 17 | final class KeyExcludeByIndexTest { 18 | 19 | @Test 20 | void excludesPart() { 21 | final Key key = new Key.From("1", "2", "1"); 22 | MatcherAssert.assertThat( 23 | new KeyExcludeByIndex(key, 0).string(), 24 | new IsEqual<>("2/1") 25 | ); 26 | } 27 | 28 | @Test 29 | void excludesNonExistingPart() { 30 | final Key key = new Key.From("1", "2"); 31 | MatcherAssert.assertThat( 32 | new KeyExcludeByIndex(key, -1).string(), 33 | new IsEqual<>("1/2") 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/key/KeyInsertTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.key; 6 | 7 | import com.artipie.asto.Key; 8 | import org.hamcrest.MatcherAssert; 9 | import org.hamcrest.core.IsEqual; 10 | import org.junit.jupiter.api.Assertions; 11 | import org.junit.jupiter.api.Test; 12 | 13 | /** 14 | * Test case for {@link KeyInsert}. 15 | * 16 | * @since 1.9.1 17 | */ 18 | final class KeyInsertTest { 19 | 20 | @Test 21 | void insertsPart() { 22 | final Key key = new Key.From("1", "2", "4"); 23 | MatcherAssert.assertThat( 24 | new KeyInsert(key, "3", 2).string(), 25 | new IsEqual<>("1/2/3/4") 26 | ); 27 | } 28 | 29 | @Test 30 | void insertsIndexOutOfBounds() { 31 | final Key key = new Key.From("1", "2"); 32 | Assertions.assertThrows( 33 | IndexOutOfBoundsException.class, 34 | () -> new KeyInsert(key, "3", -1) 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/OneTimePublisherTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import io.reactivex.Flowable; 8 | import org.hamcrest.MatcherAssert; 9 | import org.hamcrest.core.IsEqual; 10 | import org.junit.jupiter.api.Assertions; 11 | import org.junit.jupiter.api.Test; 12 | 13 | /** 14 | * Test case for {@link OneTimePublisher}. 15 | * @since 0.23 16 | */ 17 | public final class OneTimePublisherTest { 18 | 19 | @Test 20 | public void secondAttemptLeadToFail() { 21 | final int one = 1; 22 | final Flowable pub = Flowable.fromPublisher( 23 | new OneTimePublisher<>(Flowable.fromArray(one)) 24 | ); 25 | final Integer last = pub.lastOrError().blockingGet(); 26 | MatcherAssert.assertThat(last, new IsEqual<>(one)); 27 | Assertions.assertThrows( 28 | ArtipieIOException.class, 29 | () -> pub.firstOrError().blockingGet() 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/deploy-snapshot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Deploy snapshot 3 | "on": 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | deploy-snapshot: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Set up JDK 13 | uses: actions/setup-java@v1 14 | with: 15 | java-version: 1.8 16 | - uses: actions/cache@v1 17 | with: 18 | path: ~/.m2/repository 19 | key: ${{ runner.os }}-jdk-1.8-mvn-${{ hashFiles('**/pom.xml') }} 20 | restore-keys: | 21 | ${{ runner.os }}-jdk-1.8-mvn- 22 | - name: Create settings.xml 23 | uses: whelk-io/maven-settings-xml-action@v15 24 | with: 25 | servers: | 26 | [ 27 | { 28 | "id": "artipie-central", 29 | "username": "${{ secrets.ARTIPIE_CENTRAL_USERNAME }}", 30 | "password": "${{ secrets.ARTIPIE_CENTRAL_PASSWORD }}" 31 | } 32 | ] 33 | - name: Deploy snapshot to Artipie central 34 | run: mvn clean deploy -B 35 | -------------------------------------------------------------------------------- /.rultor.yml: -------------------------------------------------------------------------------- 1 | docker: 2 | image: g4s8/rultor:alpine3.10 3 | assets: 4 | settings.xml: "yegor256/artipie-keys#settings.xml" 5 | pubring.gpg: "yegor256/artipie-keys#pubring.gpg" 6 | secring.gpg: "yegor256/artipie-keys#secring.gpg" 7 | install: | 8 | export LC_ALL=en_US.UTF-8 9 | export LANG=en_US.UTF-8 10 | export LANGUAGE=en_US.UTF-8 11 | merge: 12 | script: | 13 | echo We don't merge via Rultor 14 | exit 1 15 | deploy: 16 | script: | 17 | echo There is nothing to deploy 18 | exit 1 19 | release: 20 | sensitive: 21 | - settings.xml 22 | script: |- 23 | pdd -f /dev/null 24 | gpg --import /home/r/pubring.gpg 25 | gpg --allow-secret-key-import --no-tty --batch --import /home/r/secring.gpg 26 | mvn versions:set "-DnewVersion=${tag}" --settings ../settings.xml 27 | git commit -am "${tag}" 28 | mvn clean deploy -Partipie,publish,sonatype,qulice,gpg-sign --errors --settings ../settings.xml 29 | architect: 30 | - g4s8 31 | - yegor256 32 | - Sammers21 33 | - olegmoz 34 | - brastak 35 | - olenagerasimova 36 | - artemlazarev 37 | - IlyaMoskva 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/MetaCommonTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.artipie.asto.memory.InMemoryStorage; 8 | import java.nio.charset.StandardCharsets; 9 | import org.hamcrest.MatcherAssert; 10 | import org.hamcrest.core.IsEqual; 11 | import org.junit.jupiter.api.Test; 12 | 13 | /** 14 | * Test case for {@link MetaCommon}. 15 | * @since 1.11 16 | */ 17 | final class MetaCommonTest { 18 | 19 | @Test 20 | void readsSize() { 21 | final Storage storage = new InMemoryStorage(); 22 | final Key key = new Key.From("key"); 23 | final String data = "012004407"; 24 | storage.save( 25 | key, 26 | new Content.From(data.getBytes(StandardCharsets.UTF_8)) 27 | ); 28 | MatcherAssert.assertThat( 29 | "Gets value size from metadata", 30 | new MetaCommon(storage.metadata(key).join()).size(), 31 | new IsEqual<>(Long.valueOf(data.length())) 32 | ); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/BenchmarkStorageVerificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.artipie.asto.memory.BenchmarkStorage; 8 | import com.artipie.asto.memory.InMemoryStorage; 9 | import com.artipie.asto.test.StorageWhiteboxVerification; 10 | import java.util.Optional; 11 | 12 | /** 13 | * Benchmark storage verification test. 14 | * 15 | * @checkstyle ProtectedMethodInFinalClassCheck (500 lines) 16 | * @since 1.14.0 17 | */ 18 | @SuppressWarnings("PMD.TestClassWithoutTestCases") 19 | public final class BenchmarkStorageVerificationTest extends StorageWhiteboxVerification { 20 | 21 | @Override 22 | protected Storage newStorage() { 23 | return new BenchmarkStorage(new InMemoryStorage()); 24 | } 25 | 26 | @Override 27 | protected Optional newBaseForRootSubStorage() { 28 | return Optional.empty(); 29 | } 30 | 31 | @Override 32 | protected Optional newBaseForSubStorage() { 33 | return Optional.empty(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020-2023 artipie.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/ext/ContentDigestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.ext; 6 | 7 | import com.artipie.asto.Content; 8 | import org.hamcrest.MatcherAssert; 9 | import org.hamcrest.core.IsEqual; 10 | import org.junit.jupiter.api.Test; 11 | 12 | /** 13 | * Test case for {@link ContentDigest}. 14 | * 15 | * @since 0.22 16 | */ 17 | final class ContentDigestTest { 18 | 19 | @Test 20 | void calculatesHex() throws Exception { 21 | MatcherAssert.assertThat( 22 | new ContentDigest( 23 | new Content.OneTime( 24 | new Content.From( 25 | // @checkstyle MagicNumberCheck (1 line) 26 | new byte[]{(byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe} 27 | ) 28 | ), 29 | Digests.SHA256 30 | ).hex().toCompletableFuture().get(), 31 | new IsEqual<>("65ab12a8ff3263fbc257e5ddf0aa563c64573d0bab1f1115b9b107834cfa6971") 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/ContentTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import hu.akarnokd.rxjava2.interop.MaybeInterop; 8 | import io.reactivex.Flowable; 9 | import java.util.Optional; 10 | import org.hamcrest.MatcherAssert; 11 | import org.hamcrest.core.IsEqual; 12 | import org.hamcrest.core.IsNull; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Test cases for {@link Content}. 17 | * 18 | * @since 0.24 19 | */ 20 | final class ContentTest { 21 | 22 | @Test 23 | void emptyHasNoChunks() { 24 | MatcherAssert.assertThat( 25 | Flowable.fromPublisher(Content.EMPTY) 26 | .singleElement() 27 | .to(MaybeInterop.get()) 28 | .toCompletableFuture() 29 | .join(), 30 | new IsNull<>() 31 | ); 32 | } 33 | 34 | @Test 35 | void emptyHasZeroSize() { 36 | MatcherAssert.assertThat( 37 | Content.EMPTY.size(), 38 | new IsEqual<>(Optional.of(0L)) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/streams/ContentAsStreamTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.streams; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.misc.UncheckedIOFunc; 9 | import java.nio.charset.Charset; 10 | import java.nio.charset.StandardCharsets; 11 | import java.util.List; 12 | import org.apache.commons.io.IOUtils; 13 | import org.hamcrest.MatcherAssert; 14 | import org.hamcrest.Matchers; 15 | import org.junit.jupiter.api.Test; 16 | 17 | /** 18 | * Test for {@link ContentAsStream}. 19 | * @since 1.4 20 | */ 21 | class ContentAsStreamTest { 22 | 23 | @Test 24 | void processesItem() { 25 | final Charset charset = StandardCharsets.UTF_8; 26 | MatcherAssert.assertThat( 27 | new ContentAsStream>(new Content.From("one\ntwo\nthree".getBytes(charset))) 28 | .process(new UncheckedIOFunc<>(input -> IOUtils.readLines(input, charset))) 29 | .toCompletableFuture().join(), 30 | Matchers.contains("one", "two", "three") 31 | ); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /asto-etcd/src/main/java/com/artipie/asto/etcd/EtcdMeta.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.etcd; 6 | 7 | import com.artipie.asto.Meta; 8 | import io.etcd.jetcd.KeyValue; 9 | import java.time.Instant; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | /** 14 | * Metadata from Etcd key value. 15 | * @since 0.1 16 | */ 17 | final class EtcdMeta implements Meta { 18 | 19 | /** 20 | * Key value. 21 | */ 22 | private final KeyValue kvs; 23 | 24 | /** 25 | * New metadata. 26 | * @param kvs Key value 27 | */ 28 | EtcdMeta(final KeyValue kvs) { 29 | this.kvs = kvs; 30 | } 31 | 32 | @Override 33 | public T read(final ReadOperator opr) { 34 | final Map raw = new HashMap<>(); 35 | Meta.OP_SIZE.put(raw, Long.valueOf(this.kvs.getValue().size())); 36 | Meta.OP_CREATED_AT.put(raw, Instant.ofEpochMilli(this.kvs.getCreateRevision())); 37 | Meta.OP_UPDATED_AT.put(raw, Instant.ofEpochMilli(this.kvs.getModRevision())); 38 | return opr.take(raw); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /asto-vertx-file/src/test/java/com/artipie/asto/VertxFileStorageFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.amihaiemil.eoyaml.Yaml; 8 | import com.artipie.asto.factory.Config; 9 | import com.artipie.asto.factory.StoragesLoader; 10 | import com.artipie.asto.fs.VertxFileStorage; 11 | import org.hamcrest.MatcherAssert; 12 | import org.hamcrest.core.IsInstanceOf; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Test for Storages. 17 | * 18 | * @since 0.1 19 | */ 20 | @SuppressWarnings("PMD.AvoidDuplicateLiterals") 21 | public final class VertxFileStorageFactoryTest { 22 | 23 | @Test 24 | void shouldCreateVertxFileStorage() { 25 | MatcherAssert.assertThat( 26 | new StoragesLoader() 27 | .newObject( 28 | "vertx-file", 29 | new Config.YamlStorageConfig( 30 | Yaml.createYamlMappingBuilder().add("path", "").build() 31 | ) 32 | ), 33 | new IsInstanceOf(VertxFileStorage.class) 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/cache/Cache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.cache; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.Key; 9 | import java.util.Optional; 10 | import java.util.concurrent.CompletionStage; 11 | 12 | /** 13 | * Generic reactive cache which returns cached content by key of exist or loads from remote and 14 | * cache if doesn't exit. 15 | * 16 | * @since 0.24 17 | */ 18 | public interface Cache { 19 | 20 | /** 21 | * No cache, just load remote resource. 22 | */ 23 | Cache NOP = (key, remote, ctl) -> remote.get(); 24 | 25 | /** 26 | * Try to load content from cache or fallback to remote publisher if cached key doesn't exist. 27 | * When loading remote item, the cache may save its content to the cache storage. 28 | * @param key Cached item key 29 | * @param remote Remote source 30 | * @param control Cache control 31 | * @return Content for key 32 | */ 33 | CompletionStage> load( 34 | Key key, Remote remote, CacheControl control 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/key/KeyInsert.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.key; 6 | 7 | import com.artipie.asto.Key; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | 11 | /** 12 | * Key that inserts a part. 13 | * 14 | * @since 1.9.1 15 | */ 16 | public final class KeyInsert extends Key.Wrap { 17 | 18 | /** 19 | * Ctor. 20 | * @param key Key 21 | * @param part Part to insert 22 | * @param index Index of insertion 23 | */ 24 | public KeyInsert(final Key key, final String part, final int index) { 25 | super( 26 | new From(KeyInsert.insert(key, part, index)) 27 | ); 28 | } 29 | 30 | /** 31 | * Inserts part. 32 | * @param key Key 33 | * @param part Part to insert 34 | * @param index Index of insertion 35 | * @return List of parts 36 | */ 37 | private static List insert(final Key key, final String part, final int index) { 38 | final List parts = new LinkedList<>(key.parts()); 39 | parts.add(index, part); 40 | return parts; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/UncheckedIOConsumer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.asto.ArtipieIOException; 8 | import java.io.IOException; 9 | import java.util.function.Consumer; 10 | 11 | /** 12 | * Unchecked IO {@link Consumer}. 13 | * @param Consumer type 14 | * @since 1.1 15 | * @checkstyle AbbreviationAsWordInNameCheck (200 lines) 16 | */ 17 | public final class UncheckedIOConsumer implements Consumer { 18 | 19 | /** 20 | * Checked version. 21 | */ 22 | private final UncheckedConsumer.Checked checked; 23 | 24 | /** 25 | * Ctor. 26 | * @param checked Checked func 27 | */ 28 | public UncheckedIOConsumer(final UncheckedConsumer.Checked checked) { 29 | this.checked = checked; 30 | } 31 | 32 | @Override 33 | public void accept(final T val) { 34 | try { 35 | this.checked.accept(val); 36 | } catch (final IOException err) { 37 | throw new ArtipieIOException(err); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /asto-s3/src/main/java/com/artipie/asto/s3/S3HeadMeta.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.s3; 6 | 7 | import com.artipie.asto.Meta; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import software.amazon.awssdk.services.s3.model.HeadObjectResponse; 11 | 12 | /** 13 | * Metadata from S3 object. 14 | * @since 0.1 15 | */ 16 | final class S3HeadMeta implements Meta { 17 | 18 | /** 19 | * S3 head object response. 20 | */ 21 | private final HeadObjectResponse rsp; 22 | 23 | /** 24 | * New metadata. 25 | * @param rsp Head response 26 | */ 27 | S3HeadMeta(final HeadObjectResponse rsp) { 28 | this.rsp = rsp; 29 | } 30 | 31 | @Override 32 | public T read(final ReadOperator opr) { 33 | final Map raw = new HashMap<>(); 34 | Meta.OP_SIZE.put(raw, this.rsp.contentLength()); 35 | // @checkstyle MethodBodyCommentsCheck (1 line) 36 | // ETag is a quoted MD5 of blob content according to S3 docs 37 | Meta.OP_MD5.put(raw, this.rsp.eTag().replaceAll("\"", "")); 38 | return opr.take(raw); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/fs/FileMeta.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.fs; 6 | 7 | import com.artipie.asto.Meta; 8 | import java.nio.file.attribute.BasicFileAttributes; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * Metadata for file. 14 | * @since 1.9 15 | */ 16 | final class FileMeta implements Meta { 17 | 18 | /** 19 | * File attributes. 20 | */ 21 | private final BasicFileAttributes attr; 22 | 23 | /** 24 | * New metadata. 25 | * @param attr File attributes 26 | */ 27 | FileMeta(final BasicFileAttributes attr) { 28 | this.attr = attr; 29 | } 30 | 31 | @Override 32 | public T read(final ReadOperator opr) { 33 | final Map raw = new HashMap<>(); 34 | Meta.OP_SIZE.put(raw, this.attr.size()); 35 | Meta.OP_ACCESSED_AT.put(raw, this.attr.lastAccessTime().toInstant()); 36 | Meta.OP_CREATED_AT.put(raw, this.attr.creationTime().toInstant()); 37 | Meta.OP_UPDATED_AT.put(raw, this.attr.lastModifiedTime().toInstant()); 38 | return opr.take(raw); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/lock/RxLock.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.lock; 6 | 7 | import hu.akarnokd.rxjava2.interop.CompletableInterop; 8 | import io.reactivex.Completable; 9 | 10 | /** 11 | * Reactive adapter for {@link Lock}. 12 | * 13 | * @since 0.27 14 | */ 15 | public final class RxLock { 16 | 17 | /** 18 | * Origin. 19 | */ 20 | private final Lock origin; 21 | 22 | /** 23 | * Ctor. 24 | * 25 | * @param origin Origin. 26 | */ 27 | public RxLock(final Lock origin) { 28 | this.origin = origin; 29 | } 30 | 31 | /** 32 | * Acquire the lock. 33 | * 34 | * @return Completion of lock acquire operation. 35 | */ 36 | public Completable acquire() { 37 | return Completable.defer(() -> CompletableInterop.fromFuture(this.origin.acquire())); 38 | } 39 | 40 | /** 41 | * Release the lock. 42 | * 43 | * @return Completion of lock release operation. 44 | */ 45 | public Completable release() { 46 | return Completable.defer(() -> CompletableInterop.fromFuture(this.origin.release())); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/UncheckedIOFunc.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.asto.ArtipieIOException; 8 | import java.io.IOException; 9 | import java.util.function.Function; 10 | 11 | /** 12 | * Unchecked IO {@link Function}. 13 | * @param Function type 14 | * @param Function return type 15 | * @since 1.1 16 | * @checkstyle AbbreviationAsWordInNameCheck (200 lines) 17 | */ 18 | public final class UncheckedIOFunc implements Function { 19 | 20 | /** 21 | * Checked version. 22 | */ 23 | private final UncheckedFunc.Checked checked; 24 | 25 | /** 26 | * Ctor. 27 | * @param checked Checked func 28 | */ 29 | public UncheckedIOFunc(final UncheckedFunc.Checked checked) { 30 | this.checked = checked; 31 | } 32 | 33 | @Override 34 | public R apply(final T val) { 35 | try { 36 | return this.checked.apply(val); 37 | } catch (final IOException err) { 38 | throw new ArtipieIOException(err); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/ValueNotFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * Exception indicating that value cannot be found in storage. 11 | * 12 | * @since 0.28 13 | */ 14 | @SuppressWarnings("serial") 15 | public class ValueNotFoundException extends ArtipieIOException { 16 | 17 | /** 18 | * Ctor. 19 | * 20 | * @param key Key that was not found. 21 | */ 22 | public ValueNotFoundException(final Key key) { 23 | super(message(key)); 24 | } 25 | 26 | /** 27 | * Ctor. 28 | * 29 | * @param key Key that was not found. 30 | * @param cause Original cause for exception. 31 | */ 32 | public ValueNotFoundException(final Key key, final Throwable cause) { 33 | super(new IOException(message(key), cause)); 34 | } 35 | 36 | /** 37 | * Build exception message for given key. 38 | * 39 | * @param key Key that was not found. 40 | * @return Message string. 41 | */ 42 | private static String message(final Key key) { 43 | return String.format("No value for key: %s", key.string()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/UncheckedIOSupplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.asto.ArtipieIOException; 8 | import java.io.IOException; 9 | import java.util.function.Supplier; 10 | 11 | /** 12 | * Unchecked IO {@link Supplier}. 13 | * @param Supplier type 14 | * @since 1.8 15 | * @checkstyle AbbreviationAsWordInNameCheck (200 lines) 16 | */ 17 | public final class UncheckedIOSupplier implements Supplier { 18 | 19 | /** 20 | * Checked version. 21 | */ 22 | private final UncheckedSupplier.CheckedSupplier checked; 23 | 24 | /** 25 | * Ctor. 26 | * @param checked Checked func 27 | */ 28 | public UncheckedIOSupplier( 29 | final UncheckedSupplier.CheckedSupplier checked 30 | ) { 31 | this.checked = checked; 32 | } 33 | 34 | @Override 35 | @SuppressWarnings("PMD.AvoidCatchingGenericException") 36 | public T get() { 37 | try { 38 | return this.checked.get(); 39 | } catch (final IOException err) { 40 | throw new ArtipieIOException(err); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/ArtipieException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie; 6 | 7 | /** 8 | * Base Artipie exception. 9 | *

It should be used as a base exception for all Artipie public APIs 10 | * as a contract instead of others.

11 | * 12 | * @since 1.0 13 | * @implNote ArtipieException is unchecked exception, but it's a good 14 | * practice to document it via {@code throws} tag in JavaDocs. 15 | */ 16 | public class ArtipieException extends RuntimeException { 17 | 18 | private static final long serialVersionUID = 1L; 19 | 20 | /** 21 | * New exception with message and base cause. 22 | * @param msg Message 23 | * @param cause Cause 24 | */ 25 | public ArtipieException(final String msg, final Throwable cause) { 26 | super(msg, cause); 27 | } 28 | 29 | /** 30 | * New exception with base cause. 31 | * @param cause Cause 32 | */ 33 | public ArtipieException(final Throwable cause) { 34 | super(cause); 35 | } 36 | 37 | /** 38 | * New exception with message. 39 | * @param msg Message 40 | */ 41 | public ArtipieException(final String msg) { 42 | super(msg); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/key/KeyExcludeByIndex.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | package com.artipie.asto.key; 7 | 8 | import com.artipie.asto.Key; 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | 12 | /** 13 | * Key that excludes a part by its index. 14 | * @implNote If index is out of bounds, the class can return the origin key. 15 | * @since 1.9.1 16 | */ 17 | public final class KeyExcludeByIndex extends Key.Wrap { 18 | 19 | /** 20 | * Ctor. 21 | * @param key Key 22 | * @param index Index of part 23 | */ 24 | public KeyExcludeByIndex(final Key key, final int index) { 25 | super( 26 | new From(KeyExcludeByIndex.exclude(key, index)) 27 | ); 28 | } 29 | 30 | /** 31 | * Excludes part by its index. 32 | * @param key Key 33 | * @param index Index of part to exclude 34 | * @return List of parts 35 | */ 36 | private static List exclude(final Key key, final int index) { 37 | final List parts = new LinkedList<>(key.parts()); 38 | if (index >= 0 && index < parts.size()) { 39 | parts.remove(index); 40 | } 41 | return parts; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/UncheckedIOScalar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.ArtipieException; 8 | import com.artipie.asto.ArtipieIOException; 9 | import java.io.IOException; 10 | 11 | /** 12 | * Scalar that throws {@link ArtipieException} on error. 13 | * @param Return value type 14 | * @since 1.3 15 | * @checkstyle AbbreviationAsWordInNameCheck (200 lines) 16 | */ 17 | public final class UncheckedIOScalar implements Scalar { 18 | 19 | /** 20 | * Original origin. 21 | */ 22 | private final UncheckedScalar.Checked origin; 23 | 24 | /** 25 | * Ctor. 26 | * @param origin Encapsulated origin 27 | */ 28 | public UncheckedIOScalar(final UncheckedScalar.Checked origin) { 29 | this.origin = origin; 30 | } 31 | 32 | @Override 33 | @SuppressWarnings("PMD.AvoidCatchingGenericException") 34 | public T value() { 35 | try { 36 | return this.origin.value(); 37 | // @checkstyle IllegalCatchCheck (1 line) 38 | } catch (final IOException ex) { 39 | throw new ArtipieIOException(ex); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /asto-etcd/src/main/java/com/artipie/asto/etcd/EtcdStorageFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.etcd; 6 | 7 | import com.artipie.asto.Storage; 8 | import com.artipie.asto.factory.ArtipieStorageFactory; 9 | import com.artipie.asto.factory.Config; 10 | import com.artipie.asto.factory.StorageFactory; 11 | import io.etcd.jetcd.Client; 12 | import io.etcd.jetcd.ClientBuilder; 13 | import java.time.Duration; 14 | import java.util.Arrays; 15 | 16 | /** 17 | * Etcd storage factory. 18 | * @since 0.1 19 | */ 20 | @ArtipieStorageFactory("etcd") 21 | public final class EtcdStorageFactory implements StorageFactory { 22 | @Override 23 | public Storage newStorage(final Config cfg) { 24 | final Config connection = new Config.StrictStorageConfig(cfg) 25 | .config("connection"); 26 | final String[] endpoints = connection.sequence("endpoints").toArray(new String[0]); 27 | final ClientBuilder builder = Client.builder().endpoints(endpoints); 28 | final String sto = connection.string("timeout"); 29 | if (sto != null) { 30 | builder.connectTimeout(Duration.ofMillis(Integer.parseInt(sto))); 31 | } 32 | return new EtcdStorage(builder.build(), Arrays.toString(endpoints)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/FileStorageWhiteboxVerificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.artipie.asto.fs.FileStorage; 8 | import com.artipie.asto.test.StorageWhiteboxVerification; 9 | import java.nio.file.Path; 10 | import java.util.Optional; 11 | import org.junit.jupiter.api.io.TempDir; 12 | 13 | /** 14 | * File storage verification test. 15 | * 16 | * @checkstyle ProtectedMethodInFinalClassCheck (500 lines) 17 | * @since 1.14.0 18 | */ 19 | @SuppressWarnings("PMD.TestClassWithoutTestCases") 20 | public final class FileStorageWhiteboxVerificationTest extends StorageWhiteboxVerification { 21 | 22 | /** 23 | * Temp test dir. 24 | */ 25 | @TempDir 26 | private Path temp; 27 | 28 | @Override 29 | protected Storage newStorage() { 30 | return new FileStorage(this.temp.resolve("base")); 31 | } 32 | 33 | @Override 34 | protected Optional newBaseForRootSubStorage() { 35 | return Optional.of(new FileStorage(this.temp.resolve("root-sub-storage"))); 36 | } 37 | 38 | @Override 39 | protected Optional newBaseForSubStorage() throws Exception { 40 | return Optional.of(new FileStorage(this.temp.resolve("sub-storage"))); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/OneTimePublisherVerificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import io.reactivex.Flowable; 8 | import org.reactivestreams.Publisher; 9 | import org.reactivestreams.tck.PublisherVerification; 10 | import org.reactivestreams.tck.TestEnvironment; 11 | 12 | /** 13 | * Reactive streams-tck verification suit for {@link OneTimePublisher}. 14 | * @since 0.23 15 | */ 16 | @SuppressWarnings("PMD.TestClassWithoutTestCases") 17 | public final class OneTimePublisherVerificationTest extends PublisherVerification { 18 | 19 | /** 20 | * Ctor. 21 | */ 22 | public OneTimePublisherVerificationTest() { 23 | super(new TestEnvironment()); 24 | } 25 | 26 | @Override 27 | public Publisher createPublisher(final long elements) { 28 | return Flowable.empty(); 29 | } 30 | 31 | @Override 32 | public Publisher createFailedPublisher() { 33 | final OneTimePublisher publisher = new OneTimePublisher<>(Flowable.fromArray(1)); 34 | Flowable.fromPublisher(publisher).toList().blockingGet(); 35 | return publisher; 36 | } 37 | 38 | @Override 39 | public long maxElementsFromPublisher() { 40 | return 0; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/streams/PublishingOutputStreamTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.streams; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.ext.ContentAs; 9 | import io.reactivex.Single; 10 | import java.nio.charset.StandardCharsets; 11 | import org.hamcrest.MatcherAssert; 12 | import org.hamcrest.core.IsEqual; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Tests for {@link StorageValuePipeline.PublishingOutputStream}. 17 | * 18 | * @since 1.12 19 | */ 20 | public final class PublishingOutputStreamTest { 21 | @Test 22 | void shouldPublishContentWhenDataIsWroteToOutputStream() throws Exception { 23 | final Content content; 24 | try (StorageValuePipeline.PublishingOutputStream output = 25 | new StorageValuePipeline.PublishingOutputStream()) { 26 | content = new Content.From(output.publisher()); 27 | output.write("test data".getBytes(StandardCharsets.UTF_8)); 28 | output.write(" test data 2".getBytes(StandardCharsets.UTF_8)); 29 | } 30 | MatcherAssert.assertThat( 31 | ContentAs.STRING.apply(Single.just(content)).toFuture().get(), 32 | new IsEqual<>("test data test data 2") 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/key/KeyExcludeLastTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.key; 6 | 7 | import com.artipie.asto.Key; 8 | import org.hamcrest.MatcherAssert; 9 | import org.hamcrest.core.IsEqual; 10 | import org.junit.jupiter.api.Test; 11 | 12 | /** 13 | * Test case for {@link KeyExcludeLast}. 14 | * 15 | * @since 1.9.1 16 | */ 17 | @SuppressWarnings("PMD.AvoidDuplicateLiterals") 18 | final class KeyExcludeLastTest { 19 | 20 | @Test 21 | void excludesLastPart() { 22 | final Key key = new Key.From("1", "2", "1"); 23 | MatcherAssert.assertThat( 24 | new KeyExcludeLast(key, "1").string(), 25 | new IsEqual<>("1/2") 26 | ); 27 | } 28 | 29 | @Test 30 | void excludesWhenPartIsNotAtEnd() { 31 | final Key key = new Key.From("one", "two", "three"); 32 | MatcherAssert.assertThat( 33 | new KeyExcludeLast(key, "two").string(), 34 | new IsEqual<>("one/three") 35 | ); 36 | } 37 | 38 | @Test 39 | void excludesNonExistingPart() { 40 | final Key key = new Key.From("3", "4"); 41 | MatcherAssert.assertThat( 42 | new KeyExcludeLast(key, "5").string(), 43 | new IsEqual<>("3/4") 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/key/KeyExcludeFirstTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.key; 6 | 7 | import com.artipie.asto.Key; 8 | import org.hamcrest.MatcherAssert; 9 | import org.hamcrest.core.IsEqual; 10 | import org.junit.jupiter.api.Test; 11 | 12 | /** 13 | * Test case for {@link KeyExcludeFirst}. 14 | * 15 | * @since 1.8.1 16 | */ 17 | @SuppressWarnings("PMD.AvoidDuplicateLiterals") 18 | final class KeyExcludeFirstTest { 19 | 20 | @Test 21 | void excludesFirstPart() { 22 | final Key key = new Key.From("1", "2", "1"); 23 | MatcherAssert.assertThat( 24 | new KeyExcludeFirst(key, "1").string(), 25 | new IsEqual<>("2/1") 26 | ); 27 | } 28 | 29 | @Test 30 | void excludesWhenPartIsNotAtBeginning() { 31 | final Key key = new Key.From("one", "two", "three"); 32 | MatcherAssert.assertThat( 33 | new KeyExcludeFirst(key, "two").string(), 34 | new IsEqual<>("one/three") 35 | ); 36 | } 37 | 38 | @Test 39 | void excludesNonExistingPart() { 40 | final Key key = new Key.From("1", "2"); 41 | MatcherAssert.assertThat( 42 | new KeyExcludeFirst(key, "3").string(), 43 | new IsEqual<>("1/2") 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /asto-s3/src/test/java/com/artipie/asto/s3/S3HeadMetaTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.s3; 6 | 7 | import com.artipie.asto.Meta; 8 | import org.hamcrest.MatcherAssert; 9 | import org.hamcrest.core.IsEqual; 10 | import org.junit.jupiter.api.Test; 11 | import software.amazon.awssdk.services.s3.model.HeadObjectResponse; 12 | 13 | /** 14 | * Test case for {@link S3HeadMeta}. 15 | * @since 0.1 16 | */ 17 | final class S3HeadMetaTest { 18 | 19 | @Test 20 | void readSize() { 21 | final long len = 1024; 22 | MatcherAssert.assertThat( 23 | new S3HeadMeta( 24 | HeadObjectResponse.builder() 25 | .contentLength(len) 26 | .eTag("empty") 27 | .build() 28 | ).read(Meta.OP_SIZE).orElseThrow(IllegalStateException::new), 29 | new IsEqual<>(len) 30 | ); 31 | } 32 | 33 | @Test 34 | void readHash() { 35 | final String hash = "abc"; 36 | MatcherAssert.assertThat( 37 | new S3HeadMeta( 38 | HeadObjectResponse.builder() 39 | .contentLength(0L) 40 | .eTag(hash) 41 | .build() 42 | ).read(Meta.OP_MD5).orElseThrow(IllegalStateException::new), 43 | new IsEqual<>(hash) 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/memory/InMemoryStorageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.memory; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.Key; 9 | import java.util.concurrent.TimeUnit; 10 | import org.hamcrest.MatcherAssert; 11 | import org.hamcrest.core.IsEqual; 12 | import org.junit.jupiter.api.BeforeEach; 13 | import org.junit.jupiter.api.Test; 14 | import org.junit.jupiter.api.Timeout; 15 | 16 | /** 17 | * Tests for {@link InMemoryStorage}. 18 | * 19 | * @since 0.18 20 | */ 21 | class InMemoryStorageTest { 22 | 23 | /** 24 | * Storage being tested. 25 | */ 26 | private InMemoryStorage storage; 27 | 28 | @BeforeEach 29 | void setUp() { 30 | this.storage = new InMemoryStorage(); 31 | } 32 | 33 | @Test 34 | @Timeout(1) 35 | void shouldNotBeBlockedByEndlessContent() throws Exception { 36 | final Key.From key = new Key.From("data"); 37 | this.storage.save( 38 | key, 39 | new Content.From( 40 | ignored -> { 41 | } 42 | ) 43 | ); 44 | // @checkstyle MagicNumberCheck (1 line) 45 | Thread.sleep(100); 46 | MatcherAssert.assertThat( 47 | this.storage.exists(key).get(1, TimeUnit.SECONDS), 48 | new IsEqual<>(false) 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/key/KeyExcludeFirst.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | package com.artipie.asto.key; 7 | 8 | import com.artipie.asto.Key; 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | 12 | /** 13 | * Key that excludes the first occurrence of a part. 14 | * @implNote If part to exclude was not found, the class can return the origin key. 15 | * @since 1.8.1 16 | */ 17 | public final class KeyExcludeFirst extends Key.Wrap { 18 | 19 | /** 20 | * Ctor. 21 | * @param key Key 22 | * @param part Part to exclude 23 | */ 24 | public KeyExcludeFirst(final Key key, final String part) { 25 | super( 26 | new Key.From(KeyExcludeFirst.exclude(key, part)) 27 | ); 28 | } 29 | 30 | /** 31 | * Excludes first occurrence of part. 32 | * @param key Key 33 | * @param part Part to exclude 34 | * @return List of parts 35 | */ 36 | private static List exclude(final Key key, final String part) { 37 | final List parts = new LinkedList<>(); 38 | boolean isfound = false; 39 | for (final String prt : key.parts()) { 40 | if (prt.equals(part) && !isfound) { 41 | isfound = true; 42 | continue; 43 | } 44 | parts.add(prt); 45 | } 46 | return parts; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/ext/ContentAsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.ext; 6 | 7 | import com.artipie.asto.Content; 8 | import io.reactivex.Single; 9 | import org.hamcrest.MatcherAssert; 10 | import org.hamcrest.core.IsEqual; 11 | import org.junit.jupiter.api.Test; 12 | 13 | /** 14 | * Test for {@link ContentAs}. 15 | * @since 0.33 16 | */ 17 | class ContentAsTest { 18 | 19 | @Test 20 | void transformsToString() throws Exception { 21 | final String str = "abc012"; 22 | MatcherAssert.assertThat( 23 | ContentAs.STRING.apply(Single.just(new Content.From(str.getBytes()))).toFuture().get(), 24 | new IsEqual<>(str) 25 | ); 26 | } 27 | 28 | @Test 29 | void transformsToBytes() throws Exception { 30 | final byte[] bytes = "876hgf".getBytes(); 31 | MatcherAssert.assertThat( 32 | ContentAs.BYTES.apply(Single.just(new Content.From(bytes))).toFuture().get(), 33 | new IsEqual<>(bytes) 34 | ); 35 | } 36 | 37 | @Test 38 | void transformsToLong() throws Exception { 39 | final long number = 12_087L; 40 | MatcherAssert.assertThat( 41 | ContentAs.LONG.apply( 42 | Single.just(new Content.From(String.valueOf(number).getBytes())) 43 | ).toFuture().get(), 44 | new IsEqual<>(number) 45 | ); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/cache/CacheControlTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.cache; 6 | 7 | import com.artipie.asto.Key; 8 | import org.hamcrest.MatcherAssert; 9 | import org.hamcrest.Matchers; 10 | import org.junit.jupiter.params.ParameterizedTest; 11 | import org.junit.jupiter.params.provider.MethodSource; 12 | 13 | /** 14 | * Test case for {@link CacheControl}. 15 | * 16 | * @since 0.25 17 | */ 18 | final class CacheControlTest { 19 | 20 | static Object[][] verifyAllItemsParams() { 21 | return new Object[][]{ 22 | new Object[]{CacheControl.Standard.ALWAYS, CacheControl.Standard.ALWAYS, true}, 23 | new Object[]{CacheControl.Standard.ALWAYS, CacheControl.Standard.NO_CACHE, false}, 24 | new Object[]{CacheControl.Standard.NO_CACHE, CacheControl.Standard.ALWAYS, false}, 25 | new Object[]{CacheControl.Standard.NO_CACHE, CacheControl.Standard.NO_CACHE, false}, 26 | }; 27 | } 28 | 29 | @ParameterizedTest 30 | @MethodSource("verifyAllItemsParams") 31 | void verifyAllItems(final CacheControl first, final CacheControl second, 32 | final boolean expects) throws Exception { 33 | MatcherAssert.assertThat( 34 | new CacheControl.All(first, second) 35 | .validate(Key.ROOT, Remote.EMPTY) 36 | .toCompletableFuture().get(), 37 | Matchers.is(expects) 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/ext/PublisherAsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.ext; 6 | 7 | import com.artipie.asto.Content; 8 | import java.nio.charset.StandardCharsets; 9 | import org.hamcrest.MatcherAssert; 10 | import org.hamcrest.core.IsEqual; 11 | import org.junit.jupiter.api.Test; 12 | 13 | /** 14 | * Test for {@link PublisherAs}. 15 | * @since 0.24 16 | */ 17 | class PublisherAsTest { 18 | 19 | @Test 20 | void readsBytes() { 21 | final byte[] buf = "abc".getBytes(); 22 | MatcherAssert.assertThat( 23 | new PublisherAs(new Content.From(buf)).bytes().toCompletableFuture().join(), 24 | new IsEqual<>(buf) 25 | ); 26 | } 27 | 28 | @Test 29 | void readsAsciiString() { 30 | final byte[] buf = "абв".getBytes(StandardCharsets.US_ASCII); 31 | MatcherAssert.assertThat( 32 | new PublisherAs(new Content.From(buf)).asciiString().toCompletableFuture().join(), 33 | new IsEqual<>(new String(buf, StandardCharsets.US_ASCII)) 34 | ); 35 | } 36 | 37 | @Test 38 | void readsString() { 39 | final byte[] buf = "фыв".getBytes(StandardCharsets.UTF_8); 40 | MatcherAssert.assertThat( 41 | new PublisherAs(new Content.From(buf)).string(StandardCharsets.UTF_8) 42 | .toCompletableFuture().join(), 43 | new IsEqual<>(new String(buf, StandardCharsets.UTF_8)) 44 | ); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/Remaining.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import java.nio.ByteBuffer; 8 | 9 | /** 10 | * Remaining bytes in a byte buffer. 11 | * @since 0.13 12 | */ 13 | public final class Remaining { 14 | 15 | /** 16 | * The buffer. 17 | */ 18 | private final ByteBuffer buf; 19 | 20 | /** 21 | * Restore buffer position. 22 | */ 23 | private final boolean restore; 24 | 25 | /** 26 | * Ctor. 27 | * @param buf The byte buffer. 28 | */ 29 | public Remaining(final ByteBuffer buf) { 30 | this(buf, false); 31 | } 32 | 33 | /** 34 | * Ctor. 35 | * @param buf The byte buffer. 36 | * @param restore Restore position. 37 | */ 38 | public Remaining(final ByteBuffer buf, final boolean restore) { 39 | this.buf = buf; 40 | this.restore = restore; 41 | } 42 | 43 | /** 44 | * Obtain remaining bytes. 45 | *

46 | * Read all remaining bytes from the buffer and reset position back after 47 | * reading. 48 | *

49 | * @return Remaining bytes. 50 | */ 51 | public byte[] bytes() { 52 | final byte[] bytes = new byte[this.buf.remaining()]; 53 | if (this.restore) { 54 | this.buf.mark(); 55 | } 56 | this.buf.get(bytes); 57 | if (this.restore) { 58 | this.buf.reset(); 59 | } 60 | return bytes; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/UncheckedScalar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.ArtipieException; 8 | 9 | /** 10 | * Scalar that throws {@link com.artipie.ArtipieException} on error. 11 | * @param Return value type 12 | * @param Error type 13 | * @since 1.3 14 | */ 15 | public final class UncheckedScalar implements Scalar { 16 | 17 | /** 18 | * Original origin. 19 | */ 20 | private final Checked origin; 21 | 22 | /** 23 | * Ctor. 24 | * @param origin Encapsulated origin 25 | */ 26 | public UncheckedScalar(final Checked origin) { 27 | this.origin = origin; 28 | } 29 | 30 | @Override 31 | @SuppressWarnings("PMD.AvoidCatchingGenericException") 32 | public T value() { 33 | try { 34 | return this.origin.value(); 35 | // @checkstyle IllegalCatchCheck (1 line) 36 | } catch (final Exception ex) { 37 | throw new ArtipieException(ex); 38 | } 39 | } 40 | 41 | /** 42 | * Checked version of scalar. 43 | * @param Return type 44 | * @param Error type 45 | * @since 1.1 46 | */ 47 | @FunctionalInterface 48 | public interface Checked { 49 | 50 | /** 51 | * Return value. 52 | * @return Result 53 | * @throws E On error 54 | */ 55 | R value() throws E; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /asto-redis/src/main/java/com/artipie/asto/redis/RedisStorageFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.redis; 6 | 7 | import com.artipie.asto.ArtipieIOException; 8 | import com.artipie.asto.Storage; 9 | import com.artipie.asto.factory.ArtipieStorageFactory; 10 | import com.artipie.asto.factory.Config; 11 | import com.artipie.asto.factory.StorageFactory; 12 | import java.io.IOException; 13 | import org.redisson.Redisson; 14 | import org.redisson.api.RedissonClient; 15 | 16 | /** 17 | * Redis storage factory. 18 | * 19 | * @since 0.1 20 | */ 21 | @ArtipieStorageFactory("redis") 22 | public final class RedisStorageFactory implements StorageFactory { 23 | /** 24 | * Default redis object name. 25 | */ 26 | public static final String DEF_OBJ_NAME = "artipie-redis"; 27 | 28 | @Override 29 | public Storage newStorage(final Config cfg) { 30 | try { 31 | String name = cfg.string("name"); 32 | if (name == null) { 33 | name = RedisStorageFactory.DEF_OBJ_NAME; 34 | } 35 | final RedissonClient redisson = Redisson.create( 36 | org.redisson.config.Config.fromYAML( 37 | new Config.StrictStorageConfig(cfg) 38 | .string("config") 39 | ) 40 | ); 41 | return new RedisStorage(redisson.getMap(name), redisson.getId()); 42 | } catch (final IOException err) { 43 | throw new ArtipieIOException(err); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/UncheckedConsumer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.ArtipieException; 8 | import java.util.function.Consumer; 9 | 10 | /** 11 | * Unchecked {@link Consumer}. 12 | * @param Consumer type 13 | * @param Error type 14 | * @since 1.1 15 | */ 16 | public final class UncheckedConsumer implements Consumer { 17 | 18 | /** 19 | * Checked version. 20 | */ 21 | private final Checked checked; 22 | 23 | /** 24 | * Ctor. 25 | * @param checked Checked func 26 | */ 27 | public UncheckedConsumer(final Checked checked) { 28 | this.checked = checked; 29 | } 30 | 31 | @Override 32 | @SuppressWarnings("PMD.AvoidCatchingGenericException") 33 | public void accept(final T val) { 34 | try { 35 | this.checked.accept(val); 36 | // @checkstyle IllegalCatchCheck (1 line) 37 | } catch (final Exception err) { 38 | throw new ArtipieException(err); 39 | } 40 | } 41 | 42 | /** 43 | * Checked version of consumer. 44 | * @param Consumer type 45 | * @param Error type 46 | * @since 1.1 47 | */ 48 | @FunctionalInterface 49 | public interface Checked { 50 | 51 | /** 52 | * Accept value. 53 | * @param value Value to accept 54 | * @throws E On error 55 | */ 56 | void accept(T value) throws E; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/ext/DigestsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.ext; 6 | 7 | import org.hamcrest.MatcherAssert; 8 | import org.hamcrest.core.IsEqual; 9 | import org.junit.jupiter.api.Assertions; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.params.ParameterizedTest; 12 | import org.junit.jupiter.params.provider.CsvSource; 13 | 14 | /** 15 | * Test for {@link Digests}. 16 | * @since 0.24 17 | */ 18 | class DigestsTest { 19 | 20 | @ParameterizedTest 21 | @CsvSource({ 22 | "MD5,MD5", 23 | "SHA1,SHA-1", 24 | "SHA256,SHA-256", 25 | "SHA512,SHA-512" 26 | }) 27 | void providesCorrectMessageDigestAlgorithm(final Digests item, final String expected) { 28 | MatcherAssert.assertThat( 29 | item.get().getAlgorithm(), 30 | new IsEqual<>(expected) 31 | ); 32 | } 33 | 34 | @ParameterizedTest 35 | @CsvSource({ 36 | "md5,MD5", 37 | "SHA-1,SHA1", 38 | "sha-256,SHA256", 39 | "SHa-512,SHA512" 40 | }) 41 | void returnsCorrectDigestItem(final String from, final Digests item) { 42 | MatcherAssert.assertThat( 43 | new Digests.FromString(from).get(), 44 | new IsEqual<>(item) 45 | ); 46 | } 47 | 48 | @Test 49 | void throwsExceptionOnUnknownAlgorithm() { 50 | Assertions.assertThrows( 51 | IllegalArgumentException.class, 52 | () -> new Digests.FromString("123").get() 53 | ); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /asto-etcd/src/test/java/com/artipie/asto/etcd/EtcdStorageFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.etcd; 6 | 7 | import com.amihaiemil.eoyaml.Yaml; 8 | import com.artipie.asto.factory.Config; 9 | import com.artipie.asto.factory.StoragesLoader; 10 | import org.hamcrest.MatcherAssert; 11 | import org.hamcrest.core.IsInstanceOf; 12 | import org.junit.jupiter.api.Test; 13 | 14 | /** 15 | * Test for EtcdStorageFactory. 16 | * 17 | * @since 0.1 18 | */ 19 | @SuppressWarnings("PMD.AvoidDuplicateLiterals") 20 | public final class EtcdStorageFactoryTest { 21 | @Test 22 | void shouldCreateEtcdStorage() { 23 | MatcherAssert.assertThat( 24 | new StoragesLoader() 25 | .newObject( 26 | "etcd", 27 | new Config.YamlStorageConfig( 28 | Yaml.createYamlMappingBuilder().add( 29 | "connection", 30 | Yaml.createYamlMappingBuilder() 31 | .add( 32 | "endpoints", 33 | Yaml.createYamlSequenceBuilder() 34 | .add("http://localhost") 35 | .build() 36 | ) 37 | .build() 38 | ) 39 | .build() 40 | ) 41 | ), 42 | new IsInstanceOf(EtcdStorage.class) 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/misc/UncheckedScalarTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.ArtipieException; 8 | import com.artipie.asto.ArtipieIOException; 9 | import java.io.IOException; 10 | import org.hamcrest.MatcherAssert; 11 | import org.hamcrest.core.IsEqual; 12 | import org.junit.jupiter.api.Assertions; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Test for {@link UncheckedScalar} and {@link UncheckedIOScalar}. 17 | * @since 1.3 18 | * @checkstyle LeftCurlyCheck (200 lines) 19 | * @checkstyle AbbreviationAsWordInNameCheck (200 lines) 20 | */ 21 | class UncheckedScalarTest { 22 | 23 | @Test 24 | void throwsArtipieException() { 25 | final Exception error = new Exception("Error"); 26 | final Exception res = Assertions.assertThrows( 27 | ArtipieException.class, 28 | () -> new UncheckedScalar<>(() -> { throw error; }).value() 29 | ); 30 | MatcherAssert.assertThat( 31 | res.getCause(), 32 | new IsEqual<>(error) 33 | ); 34 | } 35 | 36 | @Test 37 | void throwsArtipieIOException() { 38 | final IOException error = new IOException("IO error"); 39 | final Exception res = Assertions.assertThrows( 40 | ArtipieIOException.class, 41 | () -> new UncheckedIOScalar<>(() -> { throw error; }).value() 42 | ); 43 | MatcherAssert.assertThat( 44 | res.getCause(), 45 | new IsEqual<>(error) 46 | ); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/cache/DigestVerification.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.cache; 6 | 7 | import com.artipie.asto.Key; 8 | import com.artipie.asto.ext.ContentDigest; 9 | import java.security.MessageDigest; 10 | import java.util.Arrays; 11 | import java.util.concurrent.CompletableFuture; 12 | import java.util.concurrent.CompletionStage; 13 | import java.util.function.Supplier; 14 | 15 | /** 16 | * By digest verification. 17 | * @since 0.25 18 | */ 19 | public final class DigestVerification implements CacheControl { 20 | 21 | /** 22 | * Message digest. 23 | */ 24 | private final Supplier digest; 25 | 26 | /** 27 | * Expected digest. 28 | */ 29 | private final byte[] expected; 30 | 31 | /** 32 | * New digest verification. 33 | * @param digest Message digest has func 34 | * @param expected Expected digest bytes 35 | */ 36 | @SuppressWarnings("PMD.ArrayIsStoredDirectly") 37 | public DigestVerification(final Supplier digest, final byte[] expected) { 38 | this.digest = digest; 39 | this.expected = expected; 40 | } 41 | 42 | @Override 43 | public CompletionStage validate(final Key item, final Remote content) { 44 | return content.get().thenCompose( 45 | val -> val.map(pub -> new ContentDigest(pub, this.digest).bytes()) 46 | .orElse(CompletableFuture.completedFuture(new byte[]{})) 47 | ).thenApply(actual -> Arrays.equals(this.expected, actual)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/cache/RemoteWithErrorHandlingTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.cache; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.FailedCompletionStage; 9 | import com.artipie.asto.ext.PublisherAs; 10 | import java.net.ConnectException; 11 | import java.util.Optional; 12 | import java.util.concurrent.CompletableFuture; 13 | import org.hamcrest.MatcherAssert; 14 | import org.hamcrest.core.IsEqual; 15 | import org.junit.jupiter.api.Test; 16 | 17 | /** 18 | * Test for {@link Remote.WithErrorHandling}. 19 | * @since 0.32 20 | */ 21 | class RemoteWithErrorHandlingTest { 22 | 23 | @Test 24 | void returnsContentFromOrigin() { 25 | final byte[] bytes = "123".getBytes(); 26 | MatcherAssert.assertThat( 27 | new PublisherAs( 28 | new Remote.WithErrorHandling( 29 | () -> CompletableFuture.completedFuture( 30 | Optional.of(new Content.From(bytes)) 31 | ) 32 | ).get().toCompletableFuture().join().get() 33 | ).bytes().toCompletableFuture().join(), 34 | new IsEqual<>(bytes) 35 | ); 36 | } 37 | 38 | @Test 39 | void returnsEmptyOnError() { 40 | MatcherAssert.assertThat( 41 | new Remote.WithErrorHandling( 42 | () -> new FailedCompletionStage<>(new ConnectException("Connection error")) 43 | ).get().toCompletableFuture().join().isPresent(), 44 | new IsEqual<>(false) 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/misc/UncheckedSupplierTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.ArtipieException; 8 | import com.artipie.asto.ArtipieIOException; 9 | import java.io.IOException; 10 | import org.hamcrest.MatcherAssert; 11 | import org.hamcrest.core.IsEqual; 12 | import org.junit.jupiter.api.Assertions; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Test for {@link UncheckedSupplier} and {@link UncheckedIOSupplier}. 17 | * @since 1.8 18 | * @checkstyle LeftCurlyCheck (200 lines) 19 | * @checkstyle AbbreviationAsWordInNameCheck (200 lines) 20 | */ 21 | class UncheckedSupplierTest { 22 | 23 | @Test 24 | void throwsArtipieException() { 25 | final Exception error = new Exception("Error"); 26 | final Exception res = Assertions.assertThrows( 27 | ArtipieException.class, 28 | () -> new UncheckedSupplier<>(() -> { throw error; }).get() 29 | ); 30 | MatcherAssert.assertThat( 31 | res.getCause(), 32 | new IsEqual<>(error) 33 | ); 34 | } 35 | 36 | @Test 37 | void throwsArtipieIOException() { 38 | final IOException error = new IOException("IO error"); 39 | final Exception res = Assertions.assertThrows( 40 | ArtipieIOException.class, 41 | () -> new UncheckedIOSupplier<>(() -> { throw error; }).get() 42 | ); 43 | MatcherAssert.assertThat( 44 | res.getCause(), 45 | new IsEqual<>(error) 46 | ); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/misc/UncheckedFuncTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.ArtipieException; 8 | import com.artipie.asto.ArtipieIOException; 9 | import java.io.IOException; 10 | import org.hamcrest.MatcherAssert; 11 | import org.hamcrest.core.IsEqual; 12 | import org.junit.jupiter.api.Assertions; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Test for {@link UncheckedFunc} and {@link UncheckedIOFunc}. 17 | * @since 1.1 18 | * @checkstyle LeftCurlyCheck (200 lines) 19 | * @checkstyle AbbreviationAsWordInNameCheck (200 lines) 20 | */ 21 | class UncheckedFuncTest { 22 | 23 | @Test 24 | void throwsArtipieException() { 25 | final Exception error = new Exception("Error"); 26 | final Exception res = Assertions.assertThrows( 27 | ArtipieException.class, 28 | () -> new UncheckedFunc<>(ignored -> { throw error; }).apply("ignored") 29 | ); 30 | MatcherAssert.assertThat( 31 | res.getCause(), 32 | new IsEqual<>(error) 33 | ); 34 | } 35 | 36 | @Test 37 | void throwsArtipieIOException() { 38 | final IOException error = new IOException("IO error"); 39 | final Exception res = Assertions.assertThrows( 40 | ArtipieIOException.class, 41 | () -> new UncheckedIOFunc<>(ignored -> { throw error; }).apply("nothing") 42 | ); 43 | MatcherAssert.assertThat( 44 | res.getCause(), 45 | new IsEqual<>(error) 46 | ); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/ext/CompletableFutureSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | package com.artipie.asto.ext; 7 | 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.function.Supplier; 10 | 11 | /** 12 | * Support of new {@link CompletableFuture} API for JDK 1.8. 13 | * @param Future type 14 | * @since 0.33 15 | */ 16 | public abstract class CompletableFutureSupport implements Supplier> { 17 | 18 | /** 19 | * Supplier wrap. 20 | */ 21 | private final Supplier> wrap; 22 | 23 | /** 24 | * New wrapped future supplier. 25 | * @param wrap Supplier to wrap 26 | */ 27 | protected CompletableFutureSupport(final Supplier> wrap) { 28 | this.wrap = wrap; 29 | } 30 | 31 | @Override 32 | public final CompletableFuture get() { 33 | return this.wrap.get(); 34 | } 35 | 36 | /** 37 | * Failed completable future supplier. 38 | * @param Future type 39 | * @since 0.33 40 | */ 41 | public static final class Failed extends CompletableFutureSupport { 42 | /** 43 | * New failed future. 44 | * @param err Failure exception 45 | */ 46 | public Failed(final Exception err) { 47 | super(() -> { 48 | final CompletableFuture future = new CompletableFuture<>(); 49 | future.completeExceptionally(err); 50 | return future; 51 | }); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/misc/UncheckedConsumerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.ArtipieException; 8 | import com.artipie.asto.ArtipieIOException; 9 | import java.io.IOException; 10 | import org.hamcrest.MatcherAssert; 11 | import org.hamcrest.core.IsEqual; 12 | import org.junit.jupiter.api.Assertions; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Test for {@link UncheckedConsumer} and {@link UncheckedIOConsumer}. 17 | * @since 1.1 18 | * @checkstyle LeftCurlyCheck (200 lines) 19 | * @checkstyle AbbreviationAsWordInNameCheck (200 lines) 20 | */ 21 | class UncheckedConsumerTest { 22 | 23 | @Test 24 | void throwsArtipieException() { 25 | final Exception error = new Exception("Error"); 26 | final Exception res = Assertions.assertThrows( 27 | ArtipieException.class, 28 | () -> new UncheckedConsumer<>(ignored -> { throw error; }).accept("ignored") 29 | ); 30 | MatcherAssert.assertThat( 31 | res.getCause(), 32 | new IsEqual<>(error) 33 | ); 34 | } 35 | 36 | @Test 37 | void throwsArtipieIOException() { 38 | final IOException error = new IOException("IO error"); 39 | final Exception res = Assertions.assertThrows( 40 | ArtipieIOException.class, 41 | () -> new UncheckedIOConsumer<>(ignored -> { throw error; }).accept("nothing") 42 | ); 43 | MatcherAssert.assertThat( 44 | res.getCause(), 45 | new IsEqual<>(error) 46 | ); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/key/KeyExcludeLast.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | 6 | package com.artipie.asto.key; 7 | 8 | import com.artipie.asto.Key; 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | 12 | /** 13 | * Key that excludes the last occurrence of a part. 14 | * @implNote If part to exclude was not found, the class can return the origin key. 15 | * @since 1.9.1 16 | */ 17 | public final class KeyExcludeLast extends Key.Wrap { 18 | 19 | /** 20 | * Ctor. 21 | * @param key Key 22 | * @param part Part to exclude 23 | */ 24 | public KeyExcludeLast(final Key key, final String part) { 25 | super( 26 | new From(KeyExcludeLast.exclude(key, part)) 27 | ); 28 | } 29 | 30 | /** 31 | * Excludes last occurrence of part. 32 | * @param key Key 33 | * @param part Part to exclude 34 | * @return List of parts 35 | */ 36 | private static List exclude(final Key key, final String part) { 37 | final List allparts = key.parts(); 38 | int ifound = -1; 39 | for (int ind = allparts.size() - 1; ind >= 0; ind = ind - 1) { 40 | final String prt = allparts.get(ind); 41 | if (prt.equals(part)) { 42 | ifound = ind; 43 | break; 44 | } 45 | } 46 | final List parts = new LinkedList<>(); 47 | for (int ind = 0; ind < allparts.size(); ind = ind + 1) { 48 | if (ind != ifound) { 49 | parts.add(allparts.get(ind)); 50 | } 51 | } 52 | return parts; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/UncheckedFunc.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.ArtipieException; 8 | import java.util.function.Function; 9 | 10 | /** 11 | * Unchecked {@link Function}. 12 | * @param Function type 13 | * @param Function return type 14 | * @param Error type 15 | * @since 1.1 16 | */ 17 | public final class UncheckedFunc implements Function { 18 | 19 | /** 20 | * Checked version. 21 | */ 22 | private final Checked checked; 23 | 24 | /** 25 | * Ctor. 26 | * @param checked Checked func 27 | */ 28 | public UncheckedFunc(final Checked checked) { 29 | this.checked = checked; 30 | } 31 | 32 | @Override 33 | @SuppressWarnings("PMD.AvoidCatchingGenericException") 34 | public R apply(final T val) { 35 | try { 36 | return this.checked.apply(val); 37 | // @checkstyle IllegalCatchCheck (1 line) 38 | } catch (final Exception err) { 39 | throw new ArtipieException(err); 40 | } 41 | } 42 | 43 | /** 44 | * Checked version of consumer. 45 | * @param Consumer type 46 | * @param Return type 47 | * @param Error type 48 | * @since 1.1 49 | */ 50 | @FunctionalInterface 51 | public interface Checked { 52 | 53 | /** 54 | * Apply value. 55 | * @param value Value to accept 56 | * @return Result 57 | * @throws E On error 58 | */ 59 | R apply(T value) throws E; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/UncheckedSupplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.ArtipieException; 8 | import java.util.function.Supplier; 9 | 10 | /** 11 | * Supplier to wrap checked supplier throwing checked exception 12 | * with unchecked one. 13 | * @param Supplier type 14 | * @since 1.8 15 | */ 16 | public final class UncheckedSupplier implements Supplier { 17 | 18 | /** 19 | * Supplier which throws checked exceptions. 20 | */ 21 | private final CheckedSupplier checked; 22 | 23 | /** 24 | * Wrap checked supplier with unchecked. 25 | * @param checked Checked supplier 26 | */ 27 | public UncheckedSupplier(final CheckedSupplier checked) { 28 | this.checked = checked; 29 | } 30 | 31 | @Override 32 | @SuppressWarnings("PMD.AvoidCatchingGenericException") 33 | public T get() { 34 | try { 35 | return this.checked.get(); 36 | // @checkstyle IllegalCatchCheck (1 line) 37 | } catch (final Exception err) { 38 | throw new ArtipieException(err); 39 | } 40 | } 41 | 42 | /** 43 | * Checked supplier which throws exception. 44 | * @param Supplier type 45 | * @param Exception type 46 | * @since 1.0 47 | */ 48 | @FunctionalInterface 49 | public interface CheckedSupplier { 50 | 51 | /** 52 | * Get value or throw exception. 53 | * @return Value 54 | * @throws Exception of type E 55 | */ 56 | T get() throws E; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /asto-s3/src/test/java/com/artipie/asto/s3/EstimatedContentTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.s3; 6 | 7 | import com.artipie.asto.Content; 8 | import java.nio.charset.StandardCharsets; 9 | import java.util.Optional; 10 | import java.util.concurrent.ExecutionException; 11 | import org.hamcrest.MatcherAssert; 12 | import org.hamcrest.core.IsEqual; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Test for {@link EstimatedContentCompliment}. 17 | * 18 | * @since 0.1 19 | */ 20 | final class EstimatedContentTest { 21 | @Test 22 | void shouldReadUntilLimit() throws ExecutionException, InterruptedException { 23 | final byte[] data = "xxx".getBytes(StandardCharsets.UTF_8); 24 | final Content content = new EstimatedContentCompliment( 25 | new Content.From( 26 | Optional.empty(), 27 | new Content.From(data) 28 | ), 29 | 1 30 | ).estimate().toCompletableFuture().get(); 31 | MatcherAssert.assertThat( 32 | content.size(), new IsEqual<>(Optional.empty()) 33 | ); 34 | } 35 | 36 | @Test 37 | void shouldEvaluateSize() throws ExecutionException, InterruptedException { 38 | final byte[] data = "yyy".getBytes(StandardCharsets.UTF_8); 39 | final Content content = new EstimatedContentCompliment( 40 | new Content.From( 41 | Optional.empty(), 42 | new Content.From(data) 43 | ) 44 | ).estimate().toCompletableFuture().get(); 45 | MatcherAssert.assertThat( 46 | content.size(), new IsEqual<>(Optional.of((long) data.length)) 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/Concatenation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import io.reactivex.Flowable; 8 | import io.reactivex.Single; 9 | import java.nio.ByteBuffer; 10 | import org.reactivestreams.Publisher; 11 | 12 | /** 13 | * Concatenation of {@link ByteBuffer} instances. 14 | * 15 | * @since 0.17 16 | */ 17 | public class Concatenation { 18 | 19 | /** 20 | * Source of byte buffers. 21 | */ 22 | private final Publisher source; 23 | 24 | /** 25 | * Ctor. 26 | * 27 | * @param source Source of byte buffers. 28 | */ 29 | public Concatenation(final Publisher source) { 30 | this.source = source; 31 | } 32 | 33 | /** 34 | * Concatenates all buffers into single one. 35 | * 36 | * @return Single buffer. 37 | */ 38 | public Single single() { 39 | return Flowable.fromPublisher(this.source).reduce( 40 | ByteBuffer.allocate(0), 41 | (left, right) -> { 42 | right.mark(); 43 | final ByteBuffer result; 44 | if (left.capacity() - left.limit() >= right.limit()) { 45 | left.position(left.limit()); 46 | left.limit(left.limit() + right.limit()); 47 | result = left.put(right); 48 | } else { 49 | result = ByteBuffer.allocate( 50 | 2 * Math.max(left.capacity(), right.capacity()) 51 | ).put(left).put(right); 52 | } 53 | right.reset(); 54 | result.flip(); 55 | return result; 56 | } 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/ext/ContentAs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.ext; 6 | 7 | import io.reactivex.Single; 8 | import io.reactivex.functions.Function; 9 | import java.nio.ByteBuffer; 10 | import java.nio.charset.StandardCharsets; 11 | import org.reactivestreams.Publisher; 12 | 13 | /** 14 | * Rx publisher transformer to single. 15 | * @param Single type 16 | * @since 0.33 17 | */ 18 | public final class ContentAs 19 | implements Function>, Single> { 20 | 21 | /** 22 | * Content as string. 23 | */ 24 | public static final ContentAs STRING = new ContentAs<>( 25 | bytes -> new String(bytes, StandardCharsets.UTF_8) 26 | ); 27 | 28 | /** 29 | * Content as {@code long} number. 30 | */ 31 | public static final ContentAs LONG = new ContentAs<>( 32 | bytes -> Long.valueOf(new String(bytes, StandardCharsets.US_ASCII)) 33 | ); 34 | 35 | /** 36 | * Content as {@code bytes}. 37 | */ 38 | public static final ContentAs BYTES = new ContentAs<>(bytes -> bytes); 39 | 40 | /** 41 | * Transform function. 42 | */ 43 | private final Function transform; 44 | 45 | /** 46 | * Ctor. 47 | * @param transform Transform function 48 | */ 49 | public ContentAs(final Function transform) { 50 | this.transform = transform; 51 | } 52 | 53 | @Override 54 | public Single apply( 55 | final Single> content 56 | ) { 57 | return content.flatMap( 58 | pub -> Single.fromFuture(new PublisherAs(pub).bytes().toCompletableFuture()) 59 | ).map(this.transform); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/OneTimePublisher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | import org.reactivestreams.Publisher; 9 | import org.reactivestreams.Subscriber; 10 | import org.reactivestreams.Subscription; 11 | 12 | /** 13 | * A publish which can be consumed only once. 14 | * @param The type of publisher elements. 15 | * @since 0.23 16 | */ 17 | @SuppressWarnings("PMD.UncommentedEmptyMethodBody") 18 | public final class OneTimePublisher implements Publisher { 19 | 20 | /** 21 | * The original publisher. 22 | */ 23 | private final Publisher original; 24 | 25 | /** 26 | * The amount of subscribers. 27 | */ 28 | private final AtomicInteger subscribers; 29 | 30 | /** 31 | * Wrap a publish in a way it can be used only once. 32 | * @param original The original publisher. 33 | */ 34 | public OneTimePublisher(final Publisher original) { 35 | this.original = original; 36 | this.subscribers = new AtomicInteger(0); 37 | } 38 | 39 | @Override 40 | public void subscribe(final Subscriber sub) { 41 | final int subs = this.subscribers.incrementAndGet(); 42 | if (subs == 1) { 43 | this.original.subscribe(sub); 44 | } else { 45 | final String msg = 46 | "The subscriber could not be consumed more than once. Failed on #%d attempt"; 47 | sub.onSubscribe( 48 | new Subscription() { 49 | @Override 50 | public void request(final long cnt) { 51 | } 52 | 53 | @Override 54 | public void cancel() { 55 | } 56 | } 57 | ); 58 | sub.onError(new ArtipieIOException(String.format(msg, subs))); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/misc/UncheckedRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.misc; 6 | 7 | import com.artipie.asto.ArtipieIOException; 8 | import java.io.IOException; 9 | 10 | /** 11 | * Unchecked {@link Runnable}. 12 | * 13 | * @since 1.12 14 | */ 15 | public final class UncheckedRunnable implements Runnable { 16 | /** 17 | * Original runnable. 18 | */ 19 | private final CheckedRunnable original; 20 | 21 | /** 22 | * Ctor. 23 | * 24 | * @param original Original runnable. 25 | */ 26 | public UncheckedRunnable(final CheckedRunnable original) { 27 | this.original = original; 28 | } 29 | 30 | /** 31 | * New {@code UncheckedRunnable}. 32 | * 33 | * @param original Runnable, that can throw {@code IOException} 34 | * @param An error 35 | * @return UncheckedRunnable 36 | */ 37 | @SuppressWarnings("PMD.ProhibitPublicStaticMethods") 38 | public static UncheckedRunnable newIoRunnable( 39 | final CheckedRunnable original 40 | ) { 41 | return new UncheckedRunnable(original); 42 | } 43 | 44 | @Override 45 | @SuppressWarnings("PMD.AvoidCatchingGenericException") 46 | public void run() { 47 | try { 48 | this.original.run(); 49 | // @checkstyle IllegalCatchCheck (1 line) 50 | } catch (final Exception err) { 51 | throw new ArtipieIOException(err); 52 | } 53 | } 54 | 55 | /** 56 | * Checked version of runnable. 57 | * 58 | * @param Checked exception. 59 | * @since 1.12 60 | */ 61 | @FunctionalInterface 62 | public interface CheckedRunnable { 63 | /** 64 | * Run action. 65 | * 66 | * @throws E An error. 67 | */ 68 | void run() throws E; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /asto-vertx-file/src/test/java/com/artipie/asto/VertxFileStorageVerificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.artipie.asto.fs.VertxFileStorage; 8 | import com.artipie.asto.test.StorageWhiteboxVerification; 9 | import io.vertx.reactivex.core.Vertx; 10 | import java.nio.file.Path; 11 | import java.util.Optional; 12 | import org.junit.jupiter.api.AfterAll; 13 | import org.junit.jupiter.api.io.TempDir; 14 | 15 | /** 16 | * Vertx file storage verification test. 17 | * 18 | * @checkstyle ProtectedMethodInFinalClassCheck (500 lines) 19 | * @since 0.1 20 | */ 21 | @SuppressWarnings("PMD.TestClassWithoutTestCases") 22 | public final class VertxFileStorageVerificationTest extends StorageWhiteboxVerification { 23 | 24 | /** 25 | * Vert.x file System. 26 | */ 27 | private static final Vertx VERTX = Vertx.vertx(); 28 | 29 | /** 30 | * Temp dir. 31 | */ 32 | @TempDir 33 | private Path temp; 34 | 35 | @Override 36 | protected Storage newStorage() throws Exception { 37 | return new VertxFileStorage( 38 | this.temp.resolve("base"), 39 | VertxFileStorageVerificationTest.VERTX 40 | ); 41 | } 42 | 43 | @Override 44 | protected Optional newBaseForRootSubStorage() { 45 | return Optional.of( 46 | new VertxFileStorage( 47 | this.temp.resolve("root-sub-storage"), VertxFileStorageVerificationTest.VERTX 48 | ) 49 | ); 50 | } 51 | 52 | @Override 53 | protected Optional newBaseForSubStorage() { 54 | return Optional.of( 55 | new VertxFileStorage( 56 | this.temp.resolve("sub-storage"), VertxFileStorageVerificationTest.VERTX 57 | ) 58 | ); 59 | } 60 | 61 | @AfterAll 62 | static void tearDown() throws Exception { 63 | VertxFileStorageVerificationTest.VERTX.close(); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/fs/FileMetaTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.fs; 6 | 7 | import com.artipie.asto.Meta; 8 | import java.nio.file.attribute.BasicFileAttributes; 9 | import java.nio.file.attribute.FileTime; 10 | import java.time.Instant; 11 | import org.hamcrest.MatcherAssert; 12 | import org.hamcrest.core.IsEqual; 13 | import org.junit.jupiter.api.Test; 14 | import org.mockito.Mockito; 15 | 16 | /** 17 | * Test case for {@link FileMeta}. 18 | * @since 1.9 19 | */ 20 | final class FileMetaTest { 21 | 22 | @Test 23 | void readAttrs() { 24 | final long len = 4; 25 | final Instant creation = Instant.ofEpochMilli(1); 26 | final Instant modified = Instant.ofEpochMilli(2); 27 | final Instant access = Instant.ofEpochMilli(3); 28 | final BasicFileAttributes attrs = Mockito.mock(BasicFileAttributes.class); 29 | Mockito.when(attrs.size()).thenReturn(len); 30 | Mockito.when(attrs.creationTime()).thenReturn(FileTime.from(creation)); 31 | Mockito.when(attrs.lastModifiedTime()).thenReturn(FileTime.from(modified)); 32 | Mockito.when(attrs.lastAccessTime()).thenReturn(FileTime.from(access)); 33 | MatcherAssert.assertThat( 34 | "size", 35 | new FileMeta(attrs).read(Meta.OP_SIZE).get(), 36 | new IsEqual<>(len) 37 | ); 38 | MatcherAssert.assertThat( 39 | "created at", 40 | new FileMeta(attrs).read(Meta.OP_CREATED_AT).get(), 41 | new IsEqual<>(creation) 42 | ); 43 | MatcherAssert.assertThat( 44 | "updated at", 45 | new FileMeta(attrs).read(Meta.OP_UPDATED_AT).get(), 46 | new IsEqual<>(modified) 47 | ); 48 | MatcherAssert.assertThat( 49 | "accessed at", 50 | new FileMeta(attrs).read(Meta.OP_ACCESSED_AT).get(), 51 | new IsEqual<>(access) 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /asto-etcd/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | asto 28 | com.artipie 29 | 1.0-SNAPSHOT 30 | 31 | 4.0.0 32 | asto-etcd 33 | 34 | 35 | com.artipie 36 | asto-core 37 | 1.0-SNAPSHOT 38 | compile 39 | 40 | 41 | 42 | io.etcd 43 | jetcd-core 44 | 0.7.1 45 | true 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/streams/ContentAsInputStreamTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.streams; 6 | 7 | import com.artipie.asto.Content; 8 | import io.reactivex.Flowable; 9 | import java.io.BufferedReader; 10 | import java.io.InputStream; 11 | import java.io.InputStreamReader; 12 | import java.nio.ByteBuffer; 13 | import java.nio.charset.StandardCharsets; 14 | import org.hamcrest.MatcherAssert; 15 | import org.hamcrest.core.IsEqual; 16 | import org.junit.jupiter.api.Test; 17 | 18 | /** 19 | * Tests for {@link StorageValuePipeline.PublishingOutputStream}. 20 | * 21 | * @since 1.12 22 | * @checkstyle MagicNumberCheck (500 lines) 23 | */ 24 | public final class ContentAsInputStreamTest { 25 | 26 | @Test 27 | void shouldGetContentDataFromInputStream() throws Exception { 28 | final StorageValuePipeline.ContentAsInputStream cnt = 29 | new StorageValuePipeline.ContentAsInputStream( 30 | new Content.From( 31 | Flowable.fromArray( 32 | ByteBuffer.wrap("test data".getBytes(StandardCharsets.UTF_8)), 33 | ByteBuffer.wrap(" test data2".getBytes(StandardCharsets.UTF_8)) 34 | ) 35 | ) 36 | ); 37 | try (BufferedReader in = new BufferedReader(new InputStreamReader(cnt.inputStream()))) { 38 | MatcherAssert.assertThat( 39 | in.readLine(), 40 | new IsEqual<>("test data test data2") 41 | ); 42 | } 43 | } 44 | 45 | @Test 46 | void shouldEndOfStreamWhenContentIsEmpty() throws Exception { 47 | final StorageValuePipeline.ContentAsInputStream cnt = 48 | new StorageValuePipeline.ContentAsInputStream(Content.EMPTY); 49 | try (InputStream stream = cnt.inputStream()) { 50 | final byte[] buf = new byte[8]; 51 | MatcherAssert.assertThat( 52 | stream.read(buf), 53 | new IsEqual<>(-1) 54 | ); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/Splitting.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import io.reactivex.Flowable; 8 | import java.nio.ByteBuffer; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import org.reactivestreams.Publisher; 12 | 13 | /** 14 | * Splits the original ByteBuffer to several ones 15 | * with size less or equals defined max size. 16 | * 17 | * @since 1.12.0 18 | */ 19 | public class Splitting { 20 | 21 | /** 22 | * Source byte buffer. 23 | */ 24 | private final ByteBuffer source; 25 | 26 | /** 27 | * Max size of split byte buffer. 28 | */ 29 | private final int size; 30 | 31 | /** 32 | * Ctor. 33 | * 34 | * @param source Source byte buffer. 35 | * @param size Max size of split byte buffer. 36 | */ 37 | public Splitting(final ByteBuffer source, final int size) { 38 | this.source = source; 39 | this.size = size; 40 | } 41 | 42 | /** 43 | * Splits the original ByteBuffer to ones with size less 44 | * or equals defined max {@code size}. 45 | * 46 | * @return Publisher of ByteBuffers. 47 | */ 48 | public Publisher publisher() { 49 | final Publisher res; 50 | int remaining = this.source.remaining(); 51 | if (remaining > this.size) { 52 | final List parts = new ArrayList<>(remaining / this.size + 1); 53 | while (remaining > 0) { 54 | final byte[] bytes; 55 | if (remaining > this.size) { 56 | bytes = new byte[this.size]; 57 | } else { 58 | bytes = new byte[remaining]; 59 | } 60 | this.source.get(bytes); 61 | parts.add(ByteBuffer.wrap(bytes)); 62 | remaining = this.source.remaining(); 63 | } 64 | res = Flowable.fromIterable(parts); 65 | } else { 66 | res = Flowable.just(this.source); 67 | } 68 | return res; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /asto-etcd/src/test/java/com/artipie/asto/etcd/EtcdStorageVerificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.etcd; 6 | 7 | import com.artipie.asto.Storage; 8 | import com.artipie.asto.test.StorageWhiteboxVerification; 9 | import io.etcd.jetcd.Client; 10 | import io.etcd.jetcd.test.EtcdClusterExtension; 11 | import java.net.URI; 12 | import java.util.List; 13 | import java.util.Optional; 14 | import java.util.stream.Collectors; 15 | import org.junit.jupiter.api.AfterAll; 16 | import org.junit.jupiter.api.BeforeAll; 17 | import org.junit.jupiter.api.condition.DisabledOnOs; 18 | import org.junit.jupiter.api.condition.OS; 19 | 20 | /** 21 | * ETCD storage verification test. 22 | * 23 | * @checkstyle ProtectedMethodInFinalClassCheck (500 lines) 24 | * @since 0.1 25 | */ 26 | @SuppressWarnings("PMD.TestClassWithoutTestCases") 27 | @DisabledOnOs(OS.WINDOWS) 28 | public final class EtcdStorageVerificationTest extends StorageWhiteboxVerification { 29 | /** 30 | * Etcd cluster. 31 | */ 32 | private static EtcdClusterExtension etcd; 33 | 34 | @Override 35 | protected Storage newStorage() { 36 | final List endpoints = EtcdStorageVerificationTest.etcd.getClientEndpoints(); 37 | return new EtcdStorage( 38 | Client.builder().endpoints(endpoints).build(), 39 | endpoints.stream().map(URI::toString).collect(Collectors.joining()) 40 | ); 41 | } 42 | 43 | @Override 44 | protected Optional newBaseForRootSubStorage() { 45 | return Optional.empty(); 46 | } 47 | 48 | @BeforeAll 49 | static void beforeClass() throws Exception { 50 | EtcdStorageVerificationTest.etcd = new EtcdClusterExtension( 51 | "test-etcd", 52 | 1, 53 | false, 54 | "--data-dir", 55 | "/data.etcd0" 56 | ); 57 | EtcdStorageVerificationTest.etcd.beforeAll(null); 58 | } 59 | 60 | @AfterAll 61 | static void afterClass() throws Exception { 62 | EtcdStorageVerificationTest.etcd.afterAll(null); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/memory/BenchmarkStorageExistsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.memory; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.Key; 9 | import java.util.NavigableMap; 10 | import java.util.TreeMap; 11 | import org.hamcrest.MatcherAssert; 12 | import org.hamcrest.core.IsEqual; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Tests for {@link BenchmarkStorage#exists(Key)}. 17 | * @since 1.2.0 18 | */ 19 | @SuppressWarnings("PMD.AvoidDuplicateLiterals") 20 | final class BenchmarkStorageExistsTest { 21 | @Test 22 | void existsWhenPresentInLocalAndNotDeleted() { 23 | final InMemoryStorage memory = new InMemoryStorage(); 24 | final BenchmarkStorage bench = new BenchmarkStorage(memory); 25 | final Key key = new Key.From("somekey"); 26 | bench.save(key, Content.EMPTY).join(); 27 | MatcherAssert.assertThat( 28 | bench.exists(key).join(), 29 | new IsEqual<>(true) 30 | ); 31 | } 32 | 33 | @Test 34 | void existsWhenPresentInBackendAndNotDeleted() { 35 | final Key key = new Key.From("somekey"); 36 | final NavigableMap backdata = new TreeMap<>(); 37 | backdata.put(key.string(), "shouldExist".getBytes()); 38 | final InMemoryStorage memory = new InMemoryStorage(backdata); 39 | final BenchmarkStorage bench = new BenchmarkStorage(memory); 40 | MatcherAssert.assertThat( 41 | bench.exists(key).join(), 42 | new IsEqual<>(true) 43 | ); 44 | } 45 | 46 | @Test 47 | void notExistsIfKeyWasDeleted() { 48 | final InMemoryStorage memory = new InMemoryStorage(); 49 | final BenchmarkStorage bench = new BenchmarkStorage(memory); 50 | final Key key = new Key.From("somekey"); 51 | bench.save(key, new Content.From("any data".getBytes())).join(); 52 | bench.delete(key).join(); 53 | MatcherAssert.assertThat( 54 | bench.exists(key).join(), 55 | new IsEqual<>(false) 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Create Maven release 2 | on: 3 | push: 4 | tags: 5 | - 'v*' 6 | jobs: 7 | build: 8 | name: Build release 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2.3.3 12 | - uses: actions/setup-java@v2 13 | with: 14 | java-version: 8 15 | distribution: adopt 16 | - uses: actions/cache@v2 17 | with: 18 | path: ~/.m2/repository 19 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 20 | restore-keys: | 21 | ${{ runner.os }}-maven- 22 | - name: Import GPG key 23 | uses: crazy-max/ghaction-import-gpg@v3 24 | with: 25 | gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} 26 | passphrase: ${{ secrets.GPG_PASSPHRASE }} 27 | - name: Set env 28 | run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV 29 | - name: Set version 30 | run: mvn -B versions:set -DnewVersion=${{ env.TAG }} versions:commit 31 | - name: Create settings.xml 32 | uses: whelk-io/maven-settings-xml-action@v15 33 | with: 34 | servers: | 35 | [ 36 | { 37 | "id": "oss.sonatype.org", 38 | "username": "${{ secrets.SONATYPE_USER }}", 39 | "password": "${{ secrets.SONATYPE_PASSWORD }}" 40 | } 41 | ] 42 | profiles: | 43 | [ 44 | { 45 | "id": "artipie", 46 | "properties": { 47 | "gpg.keyname": "${{ secrets.GPG_KEYNAME }}", 48 | "gpg.passphrase": "${{ secrets.GPG_PASSPHRASE }}" 49 | } 50 | } 51 | ] 52 | - name: Deploy artifacts 53 | run: mvn deploy -Partipie,publish,sonatype,gpg-sign -DskipITs --errors 54 | - name: Create Github Release 55 | id: create_release 56 | uses: actions/create-release@v1 57 | env: 58 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 59 | with: 60 | tag_name: ${{ github.ref }} 61 | release_name: Release ${{ env.TAG }} 62 | draft: false 63 | prerelease: false 64 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/test/ContentIs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.test; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.ext.PublisherAs; 9 | import com.google.common.util.concurrent.Uninterruptibles; 10 | import java.nio.charset.Charset; 11 | import java.util.concurrent.ExecutionException; 12 | import org.hamcrest.Description; 13 | import org.hamcrest.Matcher; 14 | import org.hamcrest.Matchers; 15 | import org.hamcrest.TypeSafeMatcher; 16 | 17 | /** 18 | * Matcher for {@link Content}. 19 | * @since 0.24 20 | */ 21 | public final class ContentIs extends TypeSafeMatcher { 22 | 23 | /** 24 | * Byte array matcher. 25 | */ 26 | private final Matcher matcher; 27 | 28 | /** 29 | * Content is a string with encoding. 30 | * @param expected String 31 | * @param enc Encoding charset 32 | */ 33 | public ContentIs(final String expected, final Charset enc) { 34 | this(expected.getBytes(enc)); 35 | } 36 | 37 | /** 38 | * Content is a byte array. 39 | * @param expected Byte array 40 | */ 41 | public ContentIs(final byte[] expected) { 42 | this(Matchers.equalTo(expected)); 43 | } 44 | 45 | /** 46 | * Content matches for byte array matcher. 47 | * @param matcher Byte array matcher 48 | */ 49 | public ContentIs(final Matcher matcher) { 50 | this.matcher = matcher; 51 | } 52 | 53 | @Override 54 | public void describeTo(final Description description) { 55 | description.appendText("has bytes ").appendValue(this.matcher); 56 | } 57 | 58 | @Override 59 | public boolean matchesSafely(final Content item) { 60 | try { 61 | return this.matcher.matches( 62 | Uninterruptibles.getUninterruptibly( 63 | new PublisherAs(item).bytes().toCompletableFuture() 64 | ) 65 | ); 66 | } catch (final ExecutionException err) { 67 | throw new IllegalStateException("Failed to read content", err); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /asto-artipie/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | asto 28 | com.artipie 29 | 1.0-SNAPSHOT 30 | 31 | 4.0.0 32 | asto-artipie 33 | 34 | 35 | com.artipie 36 | asto-core 37 | 1.0-SNAPSHOT 38 | compile 39 | 40 | 41 | com.artipie 42 | http-client 43 | 0.3.9 44 | 45 | 46 | com.artipie 47 | asto-core 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/ext/Digests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.ext; 6 | 7 | import java.security.MessageDigest; 8 | import java.security.NoSuchAlgorithmException; 9 | import java.util.function.Supplier; 10 | import java.util.stream.Stream; 11 | 12 | /** 13 | * Common digests. 14 | * @since 0.22 15 | */ 16 | public enum Digests implements Supplier { 17 | /** 18 | * Common digest algorithms. 19 | */ 20 | SHA256("SHA-256"), SHA1("SHA-1"), MD5("MD5"), SHA512("SHA-512"); 21 | 22 | /** 23 | * Digest name. 24 | */ 25 | private final String name; 26 | 27 | /** 28 | * New digest for name. 29 | * @param name Digest name 30 | */ 31 | Digests(final String name) { 32 | this.name = name; 33 | } 34 | 35 | @Override 36 | public MessageDigest get() { 37 | try { 38 | return MessageDigest.getInstance(this.name); 39 | } catch (final NoSuchAlgorithmException err) { 40 | throw new IllegalStateException(String.format("No algorithm '%s'", this.name), err); 41 | } 42 | } 43 | 44 | /** 45 | * Digest enum item from string digest algorithm, case insensitive. 46 | * @since 0.24 47 | */ 48 | public static final class FromString { 49 | 50 | /** 51 | * Algorithm string representation. 52 | */ 53 | private final String from; 54 | 55 | /** 56 | * Ctor. 57 | * @param from Algorithm string representation 58 | */ 59 | public FromString(final String from) { 60 | this.from = from; 61 | } 62 | 63 | /** 64 | * Returns {@link Digests} enum item. 65 | * @return Digest 66 | */ 67 | public Digests get() { 68 | return Stream.of(Digests.values()).filter( 69 | digest -> digest.name.equalsIgnoreCase(this.from) 70 | ).findFirst().orElseThrow( 71 | () -> new IllegalArgumentException( 72 | String.format("Unsupported digest algorithm %s", this.from) 73 | ) 74 | ); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/cache/DigestVerificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.cache; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.Key; 9 | import com.artipie.asto.ext.Digests; 10 | import java.util.Optional; 11 | import java.util.concurrent.CompletableFuture; 12 | import org.apache.commons.codec.binary.Hex; 13 | import org.hamcrest.MatcherAssert; 14 | import org.hamcrest.Matchers; 15 | import org.junit.jupiter.api.Test; 16 | 17 | /** 18 | * Test case for {@link DigestVerification}. 19 | * 20 | * @since 0.25 21 | * @checkstyle MagicNumberCheck (500 lines) 22 | */ 23 | final class DigestVerificationTest { 24 | 25 | @Test 26 | void validatesCorrectDigest() throws Exception { 27 | final boolean result = new DigestVerification( 28 | Digests.MD5, 29 | Hex.decodeHex("5289df737df57326fcdd22597afb1fac") 30 | ).validate( 31 | new Key.From("any"), 32 | () -> CompletableFuture.supplyAsync( 33 | () -> Optional.of(new Content.From(new byte[]{1, 2, 3})) 34 | ) 35 | ).toCompletableFuture().get(); 36 | MatcherAssert.assertThat(result, Matchers.is(true)); 37 | } 38 | 39 | @Test 40 | void doesntValidatesIncorrectDigest() throws Exception { 41 | final boolean result = new DigestVerification( 42 | Digests.MD5, new byte[16] 43 | ).validate( 44 | new Key.From("other"), 45 | () -> CompletableFuture.supplyAsync( 46 | () -> Optional.of(new Content.From(new byte[]{1, 2, 3})) 47 | ) 48 | ).toCompletableFuture().get(); 49 | MatcherAssert.assertThat(result, Matchers.is(false)); 50 | } 51 | 52 | @Test 53 | void doesntValidateAbsentContent() throws Exception { 54 | MatcherAssert.assertThat( 55 | new DigestVerification( 56 | Digests.MD5, new byte[16] 57 | ).validate( 58 | new Key.From("something"), 59 | () -> CompletableFuture.supplyAsync(Optional::empty) 60 | ).toCompletableFuture().get(), 61 | Matchers.is(false) 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/cache/FromRemoteCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.cache; 6 | 7 | import com.artipie.asto.ArtipieIOException; 8 | import com.artipie.asto.Content; 9 | import com.artipie.asto.Key; 10 | import com.artipie.asto.Storage; 11 | import java.util.Optional; 12 | import java.util.concurrent.CompletionStage; 13 | import java.util.function.Function; 14 | 15 | /** 16 | * This cache implementation loads all the items from remote and caches it to storage. Content 17 | * is loaded from cache only if remote failed to return requested item. 18 | * @since 0.30 19 | */ 20 | public final class FromRemoteCache implements Cache { 21 | 22 | /** 23 | * Back-end storage. 24 | */ 25 | private final Storage storage; 26 | 27 | /** 28 | * New remote cache. 29 | * @param storage Back-end storage for cache 30 | */ 31 | public FromRemoteCache(final Storage storage) { 32 | this.storage = storage; 33 | } 34 | 35 | @Override 36 | public CompletionStage> load( 37 | final Key key, final Remote remote, final CacheControl control 38 | ) { 39 | return remote.get().handle( 40 | (content, throwable) -> { 41 | final CompletionStage> res; 42 | if (throwable == null && content.isPresent()) { 43 | res = this.storage.save( 44 | key, new Content.From(content.get().size(), content.get()) 45 | ).thenCompose(nothing -> this.storage.value(key)) 46 | .thenApply(Optional::of); 47 | } else { 48 | final Throwable error; 49 | if (throwable == null) { 50 | error = new ArtipieIOException("Failed to load content from remote"); 51 | } else { 52 | error = throwable; 53 | } 54 | res = new FromStorageCache(this.storage) 55 | .load(key, new Remote.Failed(error), control); 56 | } 57 | return res; 58 | } 59 | ).thenCompose(Function.identity()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/ext/PublisherAs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.ext; 6 | 7 | import com.artipie.asto.Concatenation; 8 | import com.artipie.asto.Content; 9 | import com.artipie.asto.Remaining; 10 | import hu.akarnokd.rxjava2.interop.SingleInterop; 11 | import java.nio.ByteBuffer; 12 | import java.nio.charset.Charset; 13 | import java.nio.charset.StandardCharsets; 14 | import java.util.concurrent.CompletionStage; 15 | import org.reactivestreams.Publisher; 16 | 17 | /** 18 | * Read bytes from content to memory. 19 | * Using this class keep in mind that it reads ByteBuffer from publisher into memory and is not 20 | * suitable for large content. 21 | * @since 0.24 22 | */ 23 | public final class PublisherAs { 24 | 25 | /** 26 | * Content to read bytes from. 27 | */ 28 | private final Content content; 29 | 30 | /** 31 | * Ctor. 32 | * @param content Content 33 | */ 34 | public PublisherAs(final Content content) { 35 | this.content = content; 36 | } 37 | 38 | /** 39 | * Ctor. 40 | * @param content Content 41 | */ 42 | public PublisherAs(final Publisher content) { 43 | this(new Content.From(content)); 44 | } 45 | 46 | /** 47 | * Reads bytes from content into memory. 48 | * @return Byte array as CompletionStage 49 | */ 50 | public CompletionStage bytes() { 51 | return new Concatenation(this.content) 52 | .single() 53 | .map(buf -> new Remaining(buf, true)) 54 | .map(Remaining::bytes) 55 | .to(SingleInterop.get()); 56 | } 57 | 58 | /** 59 | * Reads bytes from content as string. 60 | * @param charset Charset to read string 61 | * @return String as CompletionStage 62 | */ 63 | public CompletionStage string(final Charset charset) { 64 | return this.bytes().thenApply(bytes -> new String(bytes, charset)); 65 | } 66 | 67 | /** 68 | * Reads bytes from content as {@link StandardCharsets#US_ASCII} string. 69 | * @return String as CompletionStage 70 | */ 71 | public CompletionStage asciiString() { 72 | return this.string(StandardCharsets.US_ASCII); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/streams/ContentAsStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.streams; 6 | 7 | import com.artipie.asto.ArtipieIOException; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.PipedInputStream; 11 | import java.io.PipedOutputStream; 12 | import java.nio.ByteBuffer; 13 | import java.util.concurrent.CompletableFuture; 14 | import java.util.concurrent.CompletionStage; 15 | import java.util.function.Function; 16 | import org.cqfn.rio.WriteGreed; 17 | import org.cqfn.rio.stream.ReactiveOutputStream; 18 | import org.reactivestreams.Publisher; 19 | 20 | /** 21 | * Process content as input stream. 22 | * This class allows to treat storage item as input stream and 23 | * perform some action with this stream (read/uncompress/parse etc). 24 | * @param Result type 25 | * @since 1.4 26 | */ 27 | public final class ContentAsStream { 28 | 29 | /** 30 | * Publisher to process. 31 | */ 32 | private final Publisher content; 33 | 34 | /** 35 | * Ctor. 36 | * @param content Content 37 | */ 38 | public ContentAsStream(final Publisher content) { 39 | this.content = content; 40 | } 41 | 42 | /** 43 | * Process storage item as input stream by performing provided action on it. 44 | * @param action Action to perform 45 | * @return Completion action with the result 46 | */ 47 | public CompletionStage process(final Function action) { 48 | return CompletableFuture.supplyAsync( 49 | () -> { 50 | try ( 51 | PipedInputStream in = new PipedInputStream(); 52 | PipedOutputStream out = new PipedOutputStream(in) 53 | ) { 54 | final CompletionStage ros = 55 | new ReactiveOutputStream(out).write(this.content, WriteGreed.SYSTEM); 56 | final T result = action.apply(in); 57 | return ros.thenApply(nothing -> result); 58 | } catch (final IOException err) { 59 | throw new ArtipieIOException(err); 60 | } 61 | } 62 | ).thenCompose(Function.identity()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/ArtipieIOException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.artipie.ArtipieException; 8 | import java.io.IOException; 9 | import java.io.UncheckedIOException; 10 | 11 | /** 12 | * Artipie input-output exception. 13 | * @since 1.0 14 | * @checkstyle AbbreviationAsWordInNameCheck (10 lines) 15 | */ 16 | public class ArtipieIOException extends ArtipieException { 17 | 18 | private static final long serialVersionUID = 862160427262047490L; 19 | 20 | /** 21 | * New IO excption. 22 | * @param cause IO exception 23 | */ 24 | public ArtipieIOException(final IOException cause) { 25 | super(cause); 26 | } 27 | 28 | /** 29 | * New IO excption with message. 30 | * @param msg Message 31 | * @param cause IO exception 32 | */ 33 | public ArtipieIOException(final String msg, final IOException cause) { 34 | super(msg, cause); 35 | } 36 | 37 | /** 38 | * New IO exception. 39 | * @param cause Unkown exception 40 | */ 41 | public ArtipieIOException(final Throwable cause) { 42 | this(ArtipieIOException.unwrap(cause)); 43 | } 44 | 45 | /** 46 | * New IO exception. 47 | * @param msg Exception message 48 | * @param cause Unkown exception 49 | */ 50 | public ArtipieIOException(final String msg, final Throwable cause) { 51 | this(msg, ArtipieIOException.unwrap(cause)); 52 | } 53 | 54 | /** 55 | * New IO exception with message. 56 | * @param msg Exception message 57 | */ 58 | public ArtipieIOException(final String msg) { 59 | this(new IOException(msg)); 60 | } 61 | 62 | /** 63 | * Resolve unkown exception to IO exception. 64 | * @param cause Unkown exception 65 | * @return IO exception 66 | */ 67 | private static IOException unwrap(final Throwable cause) { 68 | final IOException iex; 69 | if (cause instanceof UncheckedIOException) { 70 | iex = ((UncheckedIOException) cause).getCause(); 71 | } else if (cause instanceof IOException) { 72 | iex = (IOException) cause; 73 | } else { 74 | iex = new IOException(cause); 75 | } 76 | return iex; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /asto-s3/src/main/java/com/artipie/asto/s3/InternalExceptionHandle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.s3; 6 | 7 | import com.artipie.asto.ArtipieIOException; 8 | import com.artipie.asto.FailedCompletionStage; 9 | import java.util.concurrent.CompletableFuture; 10 | import java.util.concurrent.CompletionException; 11 | import java.util.concurrent.CompletionStage; 12 | import java.util.function.BiFunction; 13 | import java.util.function.Function; 14 | 15 | /** 16 | * Translate an exception happened inside future. 17 | * 18 | * @param Future result type. 19 | * @since 0.1 20 | */ 21 | final class InternalExceptionHandle implements BiFunction> { 22 | 23 | /** 24 | * Type of exception to handle. 25 | */ 26 | private final Class from; 27 | 28 | /** 29 | * Converter to a new exception. 30 | */ 31 | private final Function convert; 32 | 33 | /** 34 | * Ctor. 35 | * 36 | * @param from Internal type of exception. 37 | * @param convert Converter to a external type. 38 | */ 39 | InternalExceptionHandle( 40 | final Class from, 41 | final Function convert 42 | ) { 43 | this.from = from; 44 | this.convert = convert; 45 | } 46 | 47 | @Override 48 | public CompletionStage apply(final T content, final Throwable throwable) { 49 | final CompletionStage result; 50 | if (throwable == null) { 51 | result = CompletableFuture.completedFuture(content); 52 | } else { 53 | if ( 54 | throwable instanceof CompletionException 55 | && this.from.isInstance(throwable.getCause()) 56 | ) { 57 | result = new FailedCompletionStage<>( 58 | this.convert.apply(throwable.getCause()) 59 | ); 60 | } else if (throwable instanceof CompletionException) { 61 | result = new FailedCompletionStage<>(new ArtipieIOException(throwable.getCause())); 62 | } else { 63 | result = new FailedCompletionStage<>(new ArtipieIOException(throwable)); 64 | } 65 | } 66 | return result; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/SplittingTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import io.reactivex.Flowable; 8 | import java.nio.ByteBuffer; 9 | import java.util.List; 10 | import java.util.Random; 11 | import org.hamcrest.MatcherAssert; 12 | import org.hamcrest.Matchers; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Tests for {@link Splitting}. 17 | * 18 | * @since 1.12.0 19 | * @checkstyle MagicNumberCheck (500 lines) 20 | */ 21 | public class SplittingTest { 22 | 23 | @Test 24 | void shouldReturnOneByteBufferWhenOriginalLessSize() { 25 | final byte[] data = new byte[12]; 26 | new Random().nextBytes(data); 27 | final List buffers = Flowable.fromPublisher( 28 | new Splitting(ByteBuffer.wrap(data), 24).publisher() 29 | ).toList().blockingGet(); 30 | MatcherAssert.assertThat(buffers.size(), Matchers.equalTo(1)); 31 | MatcherAssert.assertThat( 32 | new Remaining(buffers.get(0)).bytes(), Matchers.equalTo(data) 33 | ); 34 | } 35 | 36 | @Test 37 | void shouldReturnOneByteBufferWhenOriginalEqualsSize() { 38 | final byte[] data = new byte[24]; 39 | new Random().nextBytes(data); 40 | final List buffers = Flowable.fromPublisher( 41 | new Splitting(ByteBuffer.wrap(data), 24).publisher() 42 | ).toList().blockingGet(); 43 | MatcherAssert.assertThat(buffers.size(), Matchers.equalTo(1)); 44 | MatcherAssert.assertThat( 45 | new Remaining(buffers.get(0)).bytes(), Matchers.equalTo(data) 46 | ); 47 | } 48 | 49 | @Test 50 | void shouldReturnSeveralByteBuffersWhenOriginalMoreSize() { 51 | final byte[] data = new byte[2 * 24 + 8]; 52 | new Random().nextBytes(data); 53 | final List buffers = Flowable.fromPublisher( 54 | new Splitting(ByteBuffer.wrap(data), 24).publisher() 55 | ).toList().blockingGet(); 56 | MatcherAssert.assertThat(buffers.size(), Matchers.equalTo(3)); 57 | MatcherAssert.assertThat( 58 | new Remaining( 59 | new Concatenation( 60 | Flowable.fromIterable(buffers) 61 | ).single().blockingGet() 62 | ).bytes(), Matchers.equalTo(data) 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/memory/BenchmarkStorageDeleteTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.memory; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.Key; 9 | import com.artipie.asto.ValueNotFoundException; 10 | import com.artipie.asto.ext.PublisherAs; 11 | import java.util.NavigableMap; 12 | import java.util.TreeMap; 13 | import java.util.concurrent.CompletionException; 14 | import org.hamcrest.MatcherAssert; 15 | import org.hamcrest.core.IsEqual; 16 | import org.hamcrest.core.IsInstanceOf; 17 | import org.junit.jupiter.api.Assertions; 18 | import org.junit.jupiter.api.Test; 19 | 20 | /** 21 | * Tests for {@link BenchmarkStorage#delete(Key)}. 22 | * @since 1.2.0 23 | */ 24 | @SuppressWarnings("PMD.AvoidDuplicateLiterals") 25 | final class BenchmarkStorageDeleteTest { 26 | @Test 27 | void obtainsValueWhichWasAddedBySameKeyAfterDeletionToVerifyDeletedWasReset() { 28 | final InMemoryStorage memory = new InMemoryStorage(); 29 | final BenchmarkStorage bench = new BenchmarkStorage(memory); 30 | final Key key = new Key.From("somekey"); 31 | bench.save(key, new Content.From("old data".getBytes())).join(); 32 | bench.delete(key).join(); 33 | final byte[] upd = "updated data".getBytes(); 34 | bench.save(key, new Content.From(upd)).join(); 35 | MatcherAssert.assertThat( 36 | new PublisherAs(bench.value(key).join()) 37 | .bytes() 38 | .toCompletableFuture().join(), 39 | new IsEqual<>(upd) 40 | ); 41 | } 42 | 43 | @Test 44 | void returnsNotFoundIfValueWasDeletedButPresentInBackend() { 45 | final Key key = new Key.From("somekey"); 46 | final NavigableMap backdata = new TreeMap<>(); 47 | backdata.put(key.string(), "shouldBeObtained".getBytes()); 48 | final InMemoryStorage memory = new InMemoryStorage(backdata); 49 | final BenchmarkStorage bench = new BenchmarkStorage(memory); 50 | bench.delete(key).join(); 51 | final Throwable thr = Assertions.assertThrows( 52 | CompletionException.class, 53 | () -> bench.value(key).join() 54 | ); 55 | MatcherAssert.assertThat( 56 | thr.getCause(), 57 | new IsInstanceOf(ValueNotFoundException.class) 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /asto-redis/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | asto 28 | com.artipie 29 | 1.0-SNAPSHOT 30 | 31 | 4.0.0 32 | asto-redis 33 | 34 | 35 | com.artipie 36 | asto-core 37 | 1.0-SNAPSHOT 38 | compile 39 | 40 | 41 | org.redisson 42 | redisson 43 | 3.17.4 44 | 45 | 46 | 47 | 48 | 49 | 50 | maven-surefire-plugin 51 | 52 | false 53 | false 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /asto-s3/src/test/java/com/artipie/asto/S3StorageWhiteboxVerificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.adobe.testing.s3mock.junit5.S3MockExtension; 8 | import com.artipie.asto.s3.S3Storage; 9 | import com.artipie.asto.test.StorageWhiteboxVerification; 10 | import java.net.URI; 11 | import java.util.UUID; 12 | import org.junit.jupiter.api.AfterAll; 13 | import org.junit.jupiter.api.BeforeAll; 14 | import org.junit.jupiter.api.condition.DisabledOnOs; 15 | import org.junit.jupiter.api.condition.OS; 16 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; 17 | import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; 18 | import software.amazon.awssdk.regions.Region; 19 | import software.amazon.awssdk.services.s3.S3AsyncClient; 20 | import software.amazon.awssdk.services.s3.model.CreateBucketRequest; 21 | 22 | /** 23 | * S3 storage verification test. 24 | * 25 | * @checkstyle ProtectedMethodInFinalClassCheck (500 lines) 26 | * @since 0.1 27 | */ 28 | @SuppressWarnings("PMD.TestClassWithoutTestCases") 29 | @DisabledOnOs(OS.WINDOWS) 30 | public final class S3StorageWhiteboxVerificationTest extends StorageWhiteboxVerification { 31 | 32 | /** 33 | * S3 mock server extension. 34 | */ 35 | private static final S3MockExtension MOCK = S3MockExtension.builder() 36 | .withSecureConnection(false).build(); 37 | 38 | @Override 39 | protected Storage newStorage() { 40 | final String endpoint = String.format("http://localhost:%d", MOCK.getHttpPort()); 41 | final S3AsyncClient client = S3AsyncClient.builder() 42 | .region(Region.of("us-east-1")) 43 | .credentialsProvider( 44 | StaticCredentialsProvider.create( 45 | AwsBasicCredentials.create("foo", "bar") 46 | ) 47 | ) 48 | .endpointOverride(URI.create(endpoint)) 49 | .build(); 50 | final String bucket = UUID.randomUUID().toString(); 51 | client.createBucket(CreateBucketRequest.builder().bucket(bucket).build()).join(); 52 | return new S3Storage(client, bucket, endpoint); 53 | } 54 | 55 | @BeforeAll 56 | static void setUp() throws Exception { 57 | S3StorageWhiteboxVerificationTest.MOCK.beforeAll(null); 58 | } 59 | 60 | @AfterAll 61 | static void tearDown() { 62 | S3StorageWhiteboxVerificationTest.MOCK.afterAll(null); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/UnderLockOperation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.artipie.asto.lock.Lock; 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.concurrent.CompletionStage; 10 | import java.util.function.Function; 11 | 12 | /** 13 | * Operation performed under lock. 14 | * 15 | * @param Operation result type. 16 | * @since 0.27 17 | */ 18 | public final class UnderLockOperation { 19 | 20 | /** 21 | * Lock. 22 | */ 23 | private final Lock lock; 24 | 25 | /** 26 | * Operation. 27 | */ 28 | private final Function> operation; 29 | 30 | /** 31 | * Ctor. 32 | * 33 | * @param lock Lock. 34 | * @param operation Operation. 35 | */ 36 | public UnderLockOperation( 37 | final Lock lock, 38 | final Function> operation 39 | ) { 40 | this.lock = lock; 41 | this.operation = operation; 42 | } 43 | 44 | /** 45 | * Perform operation under lock on storage. 46 | * 47 | * @param storage Storage. 48 | * @return Operation result. 49 | * @checkstyle IllegalCatchCheck (10 lines) 50 | */ 51 | @SuppressWarnings("PMD.AvoidCatchingThrowable") 52 | public CompletionStage perform(final Storage storage) { 53 | return this.lock.acquire().thenCompose( 54 | nothing -> { 55 | CompletionStage result; 56 | try { 57 | result = this.operation.apply(storage); 58 | } catch (final Throwable throwable) { 59 | result = new FailedCompletionStage<>(throwable); 60 | } 61 | return result.handle( 62 | (value, throwable) -> this.lock.release().thenCompose( 63 | released -> { 64 | final CompletableFuture future = new CompletableFuture<>(); 65 | if (throwable == null) { 66 | future.complete(value); 67 | } else { 68 | future.completeExceptionally(throwable); 69 | } 70 | return future; 71 | } 72 | ) 73 | ).thenCompose(Function.identity()); 74 | } 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/ByteArray.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Byte array wrapper with ability to transform it to 11 | * boxed and primitive array. 12 | * 13 | * @since 0.7 14 | */ 15 | public final class ByteArray { 16 | 17 | /** 18 | * Bytes. 19 | */ 20 | private final Byte[] bytes; 21 | 22 | /** 23 | * Ctor for a list of byes. 24 | * 25 | * @param bytes The list of bytes 26 | */ 27 | public ByteArray(final List bytes) { 28 | this(fromList(bytes)); 29 | } 30 | 31 | /** 32 | * Ctor for a primitive array. 33 | * 34 | * @param bytes The primitive bytes 35 | */ 36 | public ByteArray(final byte[] bytes) { 37 | this(boxed(bytes)); 38 | } 39 | 40 | /** 41 | * Ctor. 42 | * 43 | * @param bytes The bytes. 44 | */ 45 | @SuppressWarnings("PMD.ArrayIsStoredDirectly") 46 | public ByteArray(final Byte[] bytes) { 47 | this.bytes = bytes; 48 | } 49 | 50 | /** 51 | * Return primitive byte array. 52 | * 53 | * @return Primitive byte array 54 | */ 55 | public byte[] primitiveBytes() { 56 | final byte[] result = new byte[this.bytes.length]; 57 | for (int itr = 0; itr < this.bytes.length; itr += 1) { 58 | result[itr] = this.bytes[itr]; 59 | } 60 | return result; 61 | } 62 | 63 | /** 64 | * Return primitive byte array. 65 | * 66 | * @return Primitive byte array 67 | */ 68 | @SuppressWarnings("PMD.MethodReturnsInternalArray") 69 | public Byte[] boxedBytes() { 70 | return this.bytes; 71 | } 72 | 73 | /** 74 | * Convert primitive to boxed array. 75 | * @param primitive Primitive byte array 76 | * @return Boxed byte array 77 | */ 78 | @SuppressWarnings("PMD.AvoidArrayLoops") 79 | private static Byte[] boxed(final byte[] primitive) { 80 | final Byte[] res = new Byte[primitive.length]; 81 | for (int itr = 0; itr < primitive.length; itr += 1) { 82 | res[itr] = primitive[itr]; 83 | } 84 | return res; 85 | } 86 | 87 | /** 88 | * Convert list of bytes to byte array. 89 | * @param list The list of bytes. 90 | * @return Boxed byte array 91 | */ 92 | private static Byte[] fromList(final List list) { 93 | return list.toArray(new Byte[0]); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/factory/StoragesLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.factory; 6 | 7 | import com.artipie.ArtipieException; 8 | import com.artipie.asto.Storage; 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | /** 15 | * Storages to get instance of storage. 16 | * 17 | * @since 1.13.0 18 | */ 19 | public final class StoragesLoader 20 | extends FactoryLoader { 21 | 22 | /** 23 | * Environment parameter to define packages to find storage factories. 24 | * Package names should be separated by semicolon ';'. 25 | */ 26 | public static final String SCAN_PACK = "STORAGE_FACTORY_SCAN_PACKAGES"; 27 | 28 | /** 29 | * Ctor. 30 | */ 31 | public StoragesLoader() { 32 | this(System.getenv()); 33 | } 34 | 35 | /** 36 | * Ctor. 37 | * 38 | * @param env Environment parameters. 39 | */ 40 | public StoragesLoader(final Map env) { 41 | super(ArtipieStorageFactory.class, env); 42 | } 43 | 44 | @Override 45 | public Storage newObject(final String type, final Config cfg) { 46 | final StorageFactory factory = super.factories.get(type); 47 | if (factory == null) { 48 | throw new StorageNotFoundException(type); 49 | } 50 | return factory.newStorage(cfg); 51 | } 52 | 53 | /** 54 | * Known storage types. 55 | * 56 | * @return Set of storage types. 57 | */ 58 | public Set types() { 59 | return this.factories.keySet(); 60 | } 61 | 62 | @Override 63 | public Set defPackages() { 64 | return Collections.singleton("com.artipie.asto"); 65 | } 66 | 67 | @Override 68 | public String scanPackagesEnv() { 69 | return StoragesLoader.SCAN_PACK; 70 | } 71 | 72 | @Override 73 | public String getFactoryName(final Class element) { 74 | return Arrays.stream(element.getAnnotations()) 75 | .filter(ArtipieStorageFactory.class::isInstance) 76 | .map(a -> ((ArtipieStorageFactory) a).value()) 77 | .findFirst() 78 | .orElseThrow( 79 | // @checkstyle LineLengthCheck (3 lines) 80 | () -> new ArtipieException("Annotation 'ArtipieStorageFactory' should have a not empty value") 81 | ); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/rx/RxStorage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.rx; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.Key; 9 | import io.reactivex.Completable; 10 | import io.reactivex.Single; 11 | import java.util.Collection; 12 | import java.util.function.Function; 13 | 14 | /** 15 | * A reactive version of {@link com.artipie.asto.Storage}. 16 | * 17 | * @since 0.10 18 | */ 19 | public interface RxStorage { 20 | 21 | /** 22 | * This file exists? 23 | * 24 | * @param key The key (file name) 25 | * @return TRUE if exists, FALSE otherwise 26 | */ 27 | Single exists(Key key); 28 | 29 | /** 30 | * Return the list of keys that start with this prefix, for 31 | * example "foo/bar/". 32 | * 33 | * @param prefix The prefix. 34 | * @return Collection of relative keys. 35 | */ 36 | Single> list(Key prefix); 37 | 38 | /** 39 | * Saves the bytes to the specified key. 40 | * 41 | * @param key The key 42 | * @param content Bytes to save 43 | * @return Completion or error signal. 44 | */ 45 | Completable save(Key key, Content content); 46 | 47 | /** 48 | * Moves value from one location to another. 49 | * 50 | * @param source Source key. 51 | * @param destination Destination key. 52 | * @return Completion or error signal. 53 | */ 54 | Completable move(Key source, Key destination); 55 | 56 | /** 57 | * Get value size. 58 | * 59 | * @param key The key of value. 60 | * @return Size of value in bytes. 61 | */ 62 | Single size(Key key); 63 | 64 | /** 65 | * Obtain bytes by key. 66 | * 67 | * @param key The key 68 | * @return Bytes. 69 | */ 70 | Single value(Key key); 71 | 72 | /** 73 | * Removes value from storage. Fails if value does not exist. 74 | * 75 | * @param key Key for value to be deleted. 76 | * @return Completion or error signal. 77 | */ 78 | Completable delete(Key key); 79 | 80 | /** 81 | * Runs operation exclusively for specified key. 82 | * 83 | * @param key Key which is scope of operation. 84 | * @param operation Operation to be performed exclusively. 85 | * @param Operation result type. 86 | * @return Result of operation. 87 | */ 88 | Single exclusively( 89 | Key key, 90 | Function> operation 91 | ); 92 | } 93 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/memory/BenchmarkStorageSizeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.memory; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.Key; 9 | import com.artipie.asto.ValueNotFoundException; 10 | import java.util.NavigableMap; 11 | import java.util.TreeMap; 12 | import java.util.concurrent.CompletionException; 13 | import org.hamcrest.MatcherAssert; 14 | import org.hamcrest.core.IsEqual; 15 | import org.hamcrest.core.IsInstanceOf; 16 | import org.junit.jupiter.api.Assertions; 17 | import org.junit.jupiter.api.Test; 18 | 19 | /** 20 | * Tests for {@link BenchmarkStorage#size(Key)}. 21 | * @since 1.2.0 22 | */ 23 | @SuppressWarnings("deprecation") 24 | final class BenchmarkStorageSizeTest { 25 | @Test 26 | void returnsSizeWhenPresentInLocalAndNotDeleted() { 27 | final byte[] data = "example data".getBytes(); 28 | final InMemoryStorage memory = new InMemoryStorage(); 29 | final BenchmarkStorage bench = new BenchmarkStorage(memory); 30 | final Key key = new Key.From("someLocalKey"); 31 | bench.save(key, new Content.From(data)).join(); 32 | MatcherAssert.assertThat( 33 | bench.size(key).join(), 34 | new IsEqual<>((long) data.length) 35 | ); 36 | } 37 | 38 | @Test 39 | void returnsSizeWhenPresentInBackendAndNotDeleted() { 40 | final byte[] data = "super data".getBytes(); 41 | final Key key = new Key.From("someBackendKey"); 42 | final NavigableMap backdata = new TreeMap<>(); 43 | backdata.put(key.string(), data); 44 | final InMemoryStorage memory = new InMemoryStorage(backdata); 45 | final BenchmarkStorage bench = new BenchmarkStorage(memory); 46 | MatcherAssert.assertThat( 47 | bench.size(key).join(), 48 | new IsEqual<>((long) data.length) 49 | ); 50 | } 51 | 52 | @Test 53 | void throwsIfKeyWasDeleted() { 54 | final InMemoryStorage memory = new InMemoryStorage(); 55 | final BenchmarkStorage bench = new BenchmarkStorage(memory); 56 | final Key key = new Key.From("somekey"); 57 | bench.save(key, new Content.From("will be deleted".getBytes())).join(); 58 | bench.delete(key).join(); 59 | final Throwable thr = Assertions.assertThrows( 60 | CompletionException.class, 61 | () -> bench.size(key).join() 62 | ); 63 | MatcherAssert.assertThat( 64 | thr.getCause(), 65 | new IsInstanceOf(ValueNotFoundException.class) 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/lock/RetryLock.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.lock; 6 | 7 | import io.github.resilience4j.core.IntervalFunction; 8 | import io.github.resilience4j.retry.RetryConfig; 9 | import io.github.resilience4j.retry.internal.InMemoryRetryRegistry; 10 | import java.util.concurrent.CompletionStage; 11 | import java.util.concurrent.ScheduledExecutorService; 12 | 13 | /** 14 | * Lock that tries to obtain origin {@link Lock} with retries. 15 | * 16 | * @since 0.24 17 | */ 18 | public final class RetryLock implements Lock { 19 | 20 | /** 21 | * Max number of attempts by default. 22 | */ 23 | private static final int MAX_ATTEMPTS = 3; 24 | 25 | /** 26 | * Scheduler to use for retry triggering. 27 | */ 28 | private final ScheduledExecutorService scheduler; 29 | 30 | /** 31 | * Origin lock. 32 | */ 33 | private final Lock origin; 34 | 35 | /** 36 | * Retry registry to store retries state. 37 | */ 38 | private final InMemoryRetryRegistry registry; 39 | 40 | /** 41 | * Ctor. 42 | * 43 | * @param scheduler Scheduler to use for retry triggering. 44 | * @param origin Origin lock. 45 | */ 46 | public RetryLock(final ScheduledExecutorService scheduler, final Lock origin) { 47 | this( 48 | scheduler, 49 | origin, 50 | new RetryConfig.Builder<>() 51 | .maxAttempts(RetryLock.MAX_ATTEMPTS) 52 | .intervalFunction(IntervalFunction.ofExponentialBackoff()) 53 | .build() 54 | ); 55 | } 56 | 57 | /** 58 | * Ctor. 59 | * 60 | * @param scheduler Scheduler to use for retry triggering. 61 | * @param origin Origin lock. 62 | * @param config Retry strategy. 63 | */ 64 | public RetryLock( 65 | final ScheduledExecutorService scheduler, 66 | final Lock origin, 67 | final RetryConfig config 68 | ) { 69 | this.scheduler = scheduler; 70 | this.origin = origin; 71 | this.registry = new InMemoryRetryRegistry(config); 72 | } 73 | 74 | @Override 75 | public CompletionStage acquire() { 76 | return this.registry.retry("lock-acquire").executeCompletionStage( 77 | this.scheduler, 78 | this.origin::acquire 79 | ); 80 | } 81 | 82 | @Override 83 | public CompletionStage release() { 84 | return this.registry.retry("lock-release").executeCompletionStage( 85 | this.scheduler, 86 | this.origin::release 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /asto-s3/src/test/java/com/artipie/asto/S3StorageFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.amihaiemil.eoyaml.Yaml; 8 | import com.artipie.asto.factory.Config; 9 | import com.artipie.asto.factory.StoragesLoader; 10 | import com.artipie.asto.s3.S3Storage; 11 | import org.hamcrest.MatcherAssert; 12 | import org.hamcrest.core.IsInstanceOf; 13 | import org.junit.jupiter.api.Test; 14 | 15 | /** 16 | * Test for Storages. 17 | * 18 | * @since 0.1 19 | */ 20 | @SuppressWarnings("PMD.AvoidDuplicateLiterals") 21 | public final class S3StorageFactoryTest { 22 | 23 | /** 24 | * Test for S3 storage factory. 25 | * 26 | * @checkstyle MethodNameCheck (3 lines) 27 | */ 28 | @Test 29 | void shouldCreateS3StorageConfigHasCredentials() { 30 | MatcherAssert.assertThat( 31 | new StoragesLoader() 32 | .newObject( 33 | "s3", 34 | new Config.YamlStorageConfig( 35 | Yaml.createYamlMappingBuilder() 36 | .add("region", "us-east-1") 37 | .add("bucket", "aaa") 38 | .add("endpoint", "http://localhost") 39 | .add( 40 | "credentials", 41 | Yaml.createYamlMappingBuilder() 42 | .add("type", "basic") 43 | .add("accessKeyId", "foo") 44 | .add("secretAccessKey", "bar") 45 | .build() 46 | ) 47 | .build() 48 | ) 49 | ), 50 | new IsInstanceOf(S3Storage.class) 51 | ); 52 | } 53 | 54 | /** 55 | * Test for S3 storage factory. 56 | * 57 | * @checkstyle MethodNameCheck (3 lines) 58 | */ 59 | @Test 60 | void shouldCreateS3StorageConfigDoesNotHaveCredentials() { 61 | MatcherAssert.assertThat( 62 | new StoragesLoader() 63 | .newObject( 64 | "s3", 65 | new Config.YamlStorageConfig( 66 | Yaml.createYamlMappingBuilder() 67 | .add("region", "us-east-1") 68 | .add("bucket", "aaa") 69 | .add("endpoint", "http://localhost") 70 | .build() 71 | ) 72 | ), 73 | new IsInstanceOf(S3Storage.class) 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/Copy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.artipie.asto.rx.RxStorageWrapper; 8 | import hu.akarnokd.rxjava2.interop.CompletableInterop; 9 | import io.reactivex.Observable; 10 | import java.util.Collection; 11 | import java.util.HashSet; 12 | import java.util.Set; 13 | import java.util.concurrent.CompletableFuture; 14 | import java.util.function.Predicate; 15 | import java.util.stream.Collectors; 16 | 17 | /** 18 | * Storage synchronization. 19 | * @since 0.19 20 | */ 21 | public class Copy { 22 | 23 | /** 24 | * The storage to copy from. 25 | */ 26 | private final Storage from; 27 | 28 | /** 29 | * Predicate condition to copy keys. 30 | */ 31 | private final Predicate predicate; 32 | 33 | /** 34 | * Ctor. 35 | * 36 | * @param from The storage to copy to. 37 | */ 38 | public Copy(final Storage from) { 39 | this(from, item -> true); 40 | } 41 | 42 | /** 43 | * Ctor. 44 | * @param from The storage to copy to 45 | * @param keys The keys to copy 46 | */ 47 | public Copy(final Storage from, final Collection keys) { 48 | this(from, new HashSet<>(keys)); 49 | } 50 | 51 | /** 52 | * Ctor. 53 | * @param from The storage to copy to 54 | * @param keys The keys to copy 55 | */ 56 | public Copy(final Storage from, final Set keys) { 57 | this(from, keys::contains); 58 | } 59 | 60 | /** 61 | * Ctor. 62 | * 63 | * @param from The storage to copy to 64 | * @param predicate Predicate to copy items 65 | */ 66 | public Copy(final Storage from, final Predicate predicate) { 67 | this.from = from; 68 | this.predicate = predicate; 69 | } 70 | 71 | /** 72 | * Copy keys to the specified storage. 73 | * @param dest Destination storage 74 | * @return When copy operation completes 75 | */ 76 | public CompletableFuture copy(final Storage dest) { 77 | final RxStorageWrapper rxdst = new RxStorageWrapper(dest); 78 | final RxStorageWrapper rxsrc = new RxStorageWrapper(this.from); 79 | return rxsrc.list(Key.ROOT) 80 | .map(lst -> lst.stream().filter(this.predicate).collect(Collectors.toList())) 81 | .flatMapObservable(Observable::fromIterable) 82 | .flatMapCompletable( 83 | key -> rxsrc.value(key).flatMapCompletable(content -> rxdst.save(key, content)) 84 | ) 85 | .to(CompletableInterop.await()) 86 | .thenApply(ignore -> (Void) null) 87 | .toCompletableFuture(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/cache/FromStorageCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.cache; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.Key; 9 | import com.artipie.asto.Storage; 10 | import com.artipie.asto.rx.RxStorageWrapper; 11 | import com.jcabi.log.Logger; 12 | import hu.akarnokd.rxjava2.interop.SingleInterop; 13 | import io.reactivex.Single; 14 | import java.util.Optional; 15 | import java.util.concurrent.CompletionStage; 16 | 17 | /** 18 | * Cache implementation that tries to obtain items from storage cache, 19 | * validates it and returns if valid. If item is not present in storage or is not valid, 20 | * it is loaded from remote. 21 | * @since 0.24 22 | */ 23 | public final class FromStorageCache implements Cache { 24 | 25 | /** 26 | * Back-end storage. 27 | */ 28 | private final Storage storage; 29 | 30 | /** 31 | * New storage cache. 32 | * @param storage Back-end storage for cache 33 | */ 34 | public FromStorageCache(final Storage storage) { 35 | this.storage = storage; 36 | } 37 | 38 | @Override 39 | public CompletionStage> load(final Key key, final Remote remote, 40 | final CacheControl control) { 41 | final RxStorageWrapper rxsto = new RxStorageWrapper(this.storage); 42 | return rxsto.exists(key) 43 | .filter(exists -> exists) 44 | .flatMapSingleElement( 45 | exists -> SingleInterop.fromFuture( 46 | control.validate(key, () -> this.storage.value(key).thenApply(Optional::of)) 47 | ) 48 | ) 49 | .filter(valid -> valid) 50 | .>flatMapSingleElement( 51 | ignore -> rxsto.value(key).map(Optional::of) 52 | ) 53 | .doOnError(err -> Logger.warn(this, "Failed to read cached item: %[exception]s", err)) 54 | .onErrorComplete() 55 | .switchIfEmpty( 56 | SingleInterop.fromFuture(remote.get()).flatMap( 57 | content -> { 58 | final Single> res; 59 | if (content.isPresent()) { 60 | res = rxsto.save( 61 | key, new Content.From(content.get().size(), content.get()) 62 | ).andThen(rxsto.value(key)).map(Optional::of); 63 | } else { 64 | res = Single.fromCallable(Optional::empty); 65 | } 66 | return res; 67 | } 68 | ) 69 | ).to(SingleInterop.get()); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /asto-redis/src/test/java/com/artipie/asto/redis/RedisStorageWhiteboxVerificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.redis; 6 | 7 | import com.amihaiemil.eoyaml.Yaml; 8 | import com.artipie.asto.Storage; 9 | import com.artipie.asto.factory.Config; 10 | import com.artipie.asto.factory.StoragesLoader; 11 | import com.artipie.asto.test.StorageWhiteboxVerification; 12 | import org.junit.jupiter.api.AfterAll; 13 | import org.junit.jupiter.api.BeforeAll; 14 | import org.junit.jupiter.api.condition.DisabledOnOs; 15 | import org.junit.jupiter.api.condition.OS; 16 | import org.testcontainers.containers.GenericContainer; 17 | 18 | /** 19 | * Redis storage verification test. 20 | * 21 | * @checkstyle ProtectedMethodInFinalClassCheck (500 lines) 22 | * @since 0.1 23 | */ 24 | @SuppressWarnings({"PMD.TestClassWithoutTestCases", "PMD.AvoidDuplicateLiterals"}) 25 | @DisabledOnOs(OS.WINDOWS) 26 | public final class RedisStorageWhiteboxVerificationTest extends StorageWhiteboxVerification { 27 | 28 | /** 29 | * Default redis port. 30 | */ 31 | private static final int DEF_PORT = 6379; 32 | 33 | /** 34 | * Redis test container. 35 | */ 36 | private static GenericContainer redis; 37 | 38 | /** 39 | * Redis storage. 40 | */ 41 | private static Storage storage; 42 | 43 | @Override 44 | protected Storage newStorage() { 45 | return RedisStorageWhiteboxVerificationTest.storage; 46 | } 47 | 48 | @BeforeAll 49 | static void setUp() { 50 | RedisStorageWhiteboxVerificationTest.redis = new GenericContainer<>("redis:3-alpine") 51 | .withExposedPorts(RedisStorageWhiteboxVerificationTest.DEF_PORT); 52 | RedisStorageWhiteboxVerificationTest.redis.start(); 53 | RedisStorageWhiteboxVerificationTest.storage = new StoragesLoader().newObject( 54 | "redis", config(RedisStorageWhiteboxVerificationTest.redis.getFirstMappedPort()) 55 | ); 56 | } 57 | 58 | @AfterAll 59 | static void tearDown() { 60 | RedisStorageWhiteboxVerificationTest.redis.stop(); 61 | } 62 | 63 | private static Config config(final Integer port) { 64 | return new Config.YamlStorageConfig( 65 | Yaml.createYamlMappingBuilder() 66 | .add("type", "redis") 67 | .add( 68 | "config", 69 | Yaml.createYamlMappingBuilder() 70 | .add( 71 | "singleServerConfig", 72 | Yaml.createYamlMappingBuilder() 73 | .add( 74 | "address", 75 | String.format("redis://127.0.0.1:%d", port) 76 | ).build() 77 | ).build() 78 | ).build() 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/cache/Remote.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.cache; 6 | 7 | import com.artipie.asto.Content; 8 | import com.jcabi.log.Logger; 9 | import java.util.Optional; 10 | import java.util.concurrent.CompletableFuture; 11 | import java.util.concurrent.CompletionStage; 12 | import java.util.function.Supplier; 13 | 14 | /** 15 | * Async {@link java.util.function.Supplier} of {@link java.util.concurrent.CompletionStage} 16 | * with {@link Optional} of {@link Content}. It's a {@link FunctionalInterface}. 17 | * 18 | * @since 0.32 19 | */ 20 | @FunctionalInterface 21 | public interface Remote extends Supplier>> { 22 | 23 | /** 24 | * Empty remote. 25 | */ 26 | Remote EMPTY = () -> CompletableFuture.completedFuture(Optional.empty()); 27 | 28 | @Override 29 | CompletionStage> get(); 30 | 31 | /** 32 | * Implementation of {@link Remote} that handle all possible errors and returns 33 | * empty {@link Optional} if any exception happened. 34 | * @since 0.32 35 | */ 36 | class WithErrorHandling implements Remote { 37 | 38 | /** 39 | * Origin. 40 | */ 41 | private final Remote origin; 42 | 43 | /** 44 | * Ctor. 45 | * @param origin Origin 46 | */ 47 | public WithErrorHandling(final Remote origin) { 48 | this.origin = origin; 49 | } 50 | 51 | @Override 52 | public CompletionStage> get() { 53 | return this.origin.get().handle( 54 | (content, throwable) -> { 55 | final Optional res; 56 | if (throwable == null) { 57 | res = content; 58 | } else { 59 | Logger.error(this.origin.getClass(), throwable.getMessage()); 60 | res = Optional.empty(); 61 | } 62 | return res; 63 | } 64 | ); 65 | } 66 | } 67 | 68 | /** 69 | * Failed remote. 70 | * @since 0.32 71 | */ 72 | final class Failed implements Remote { 73 | 74 | /** 75 | * Failure cause. 76 | */ 77 | private final Throwable reason; 78 | 79 | /** 80 | * Ctor. 81 | * @param reason Failure cause 82 | */ 83 | public Failed(final Throwable reason) { 84 | this.reason = reason; 85 | } 86 | 87 | @Override 88 | public CompletionStage> get() { 89 | final CompletableFuture> res = new CompletableFuture<>(); 90 | res.completeExceptionally(this.reason); 91 | return res; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /asto-core/src/main/java/com/artipie/asto/rx/RxStorageWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.rx; 6 | 7 | import com.artipie.asto.Content; 8 | import com.artipie.asto.Key; 9 | import com.artipie.asto.Storage; 10 | import hu.akarnokd.rxjava2.interop.CompletableInterop; 11 | import hu.akarnokd.rxjava2.interop.SingleInterop; 12 | import io.reactivex.Completable; 13 | import io.reactivex.Single; 14 | import java.util.Collection; 15 | import java.util.function.Function; 16 | 17 | /** 18 | * Reactive wrapper over {@code Storage}. 19 | * 20 | * @since 0.9 21 | */ 22 | public final class RxStorageWrapper implements RxStorage { 23 | 24 | /** 25 | * Wrapped storage. 26 | */ 27 | private final Storage storage; 28 | 29 | /** 30 | * Ctor. 31 | * 32 | * @param storage The storage 33 | */ 34 | public RxStorageWrapper(final Storage storage) { 35 | this.storage = storage; 36 | } 37 | 38 | @Override 39 | public Single exists(final Key key) { 40 | return Single.defer(() -> SingleInterop.fromFuture(this.storage.exists(key))); 41 | } 42 | 43 | @Override 44 | public Single> list(final Key prefix) { 45 | return Single.defer(() -> SingleInterop.fromFuture(this.storage.list(prefix))); 46 | } 47 | 48 | @Override 49 | public Completable save(final Key key, final Content content) { 50 | return Completable.defer( 51 | () -> CompletableInterop.fromFuture(this.storage.save(key, content)) 52 | ); 53 | } 54 | 55 | @Override 56 | public Completable move(final Key source, final Key destination) { 57 | return Completable.defer( 58 | () -> CompletableInterop.fromFuture(this.storage.move(source, destination)) 59 | ); 60 | } 61 | 62 | // @checkstyle MissingDeprecatedCheck (5 lines) 63 | @Override 64 | @Deprecated 65 | public Single size(final Key key) { 66 | return Single.defer(() -> SingleInterop.fromFuture(this.storage.size(key))); 67 | } 68 | 69 | @Override 70 | public Single value(final Key key) { 71 | return Single.defer(() -> SingleInterop.fromFuture(this.storage.value(key))); 72 | } 73 | 74 | @Override 75 | public Completable delete(final Key key) { 76 | return Completable.defer(() -> CompletableInterop.fromFuture(this.storage.delete(key))); 77 | } 78 | 79 | @Override 80 | public Single exclusively( 81 | final Key key, 82 | final Function> operation 83 | ) { 84 | return Single.defer( 85 | () -> SingleInterop.fromFuture( 86 | this.storage.exclusively( 87 | key, 88 | st -> operation.apply(new RxStorageWrapper(st)).to(SingleInterop.get()) 89 | ) 90 | ) 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /asto-core/src/test/java/com/artipie/asto/CopyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto; 6 | 7 | import com.artipie.asto.blocking.BlockingStorage; 8 | import com.artipie.asto.memory.InMemoryStorage; 9 | import java.util.Arrays; 10 | import java.util.concurrent.ExecutionException; 11 | import org.hamcrest.MatcherAssert; 12 | import org.hamcrest.Matchers; 13 | import org.hamcrest.core.IsEqual; 14 | import org.junit.jupiter.api.Test; 15 | 16 | /** 17 | * A test for {@link Copy}. 18 | * @since 0.19 19 | * @checkstyle LocalFinalVariableNameCheck (500 lines) 20 | */ 21 | public class CopyTest { 22 | 23 | @Test 24 | public void copyTwoFilesFromOneStorageToAnotherWorksFine() 25 | throws ExecutionException, InterruptedException { 26 | final Storage from = new InMemoryStorage(); 27 | final Storage to = new InMemoryStorage(); 28 | final Key akey = new Key.From("a.txt"); 29 | final Key bkey = new Key.From("b.txt"); 30 | final BlockingStorage bfrom = new BlockingStorage(from); 31 | bfrom.save(akey, "Hello world A".getBytes()); 32 | bfrom.save(bkey, "Hello world B".getBytes()); 33 | new Copy(from, Arrays.asList(akey, bkey)).copy(to).get(); 34 | for (final Key key : new BlockingStorage(from).list(Key.ROOT)) { 35 | MatcherAssert.assertThat( 36 | Arrays.equals( 37 | bfrom.value(key), 38 | new BlockingStorage(to).value(key) 39 | ), 40 | Matchers.is(true) 41 | ); 42 | } 43 | } 44 | 45 | @Test 46 | public void copyEverythingFromOneStorageToAnotherWorksFine() { 47 | final Storage from = new InMemoryStorage(); 48 | final Storage to = new InMemoryStorage(); 49 | final Key akey = new Key.From("a/b/c"); 50 | final Key bkey = new Key.From("foo.bar"); 51 | final BlockingStorage bfrom = new BlockingStorage(from); 52 | bfrom.save(akey, "one".getBytes()); 53 | bfrom.save(bkey, "two".getBytes()); 54 | new Copy(from).copy(to).join(); 55 | for (final Key key : bfrom.list(Key.ROOT)) { 56 | MatcherAssert.assertThat( 57 | new BlockingStorage(to).value(key), 58 | new IsEqual<>(bfrom.value(key)) 59 | ); 60 | } 61 | } 62 | 63 | @Test 64 | public void copyPredicate() { 65 | final Storage src = new InMemoryStorage(); 66 | final Storage dst = new InMemoryStorage(); 67 | final Key foo = new Key.From("foo"); 68 | new BlockingStorage(src).save(foo, new byte[]{0x00}); 69 | new BlockingStorage(src).save(new Key.From("bar/baz"), new byte[]{0x00}); 70 | new Copy(src, key -> key.string().contains("oo")).copy(dst).join(); 71 | MatcherAssert.assertThat( 72 | new BlockingStorage(dst).list(Key.ROOT), 73 | Matchers.contains(foo) 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /asto-s3/src/test/java/com/artipie/asto/s3/InternalExceptionHandleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.s3; 6 | 7 | import com.artipie.asto.ArtipieIOException; 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.concurrent.ExecutionException; 10 | import java.util.function.Function; 11 | import org.hamcrest.MatcherAssert; 12 | import org.hamcrest.Matchers; 13 | import org.junit.jupiter.api.Assertions; 14 | import org.junit.jupiter.api.Test; 15 | 16 | /** 17 | * Test for {@link InternalExceptionHandle}. 18 | * 19 | * @since 0.1 20 | */ 21 | @SuppressWarnings("PMD.AvoidDuplicateLiterals") 22 | final class InternalExceptionHandleTest { 23 | 24 | @Test 25 | void translatesException() { 26 | final CompletableFuture future = CompletableFuture.runAsync(Assertions::fail); 27 | MatcherAssert.assertThat( 28 | Assertions.assertThrows( 29 | ExecutionException.class, 30 | future.handle( 31 | new InternalExceptionHandle<>( 32 | AssertionError.class, 33 | IllegalStateException::new 34 | ) 35 | ) 36 | .thenCompose(Function.identity()) 37 | .toCompletableFuture() 38 | ::get 39 | ), 40 | Matchers.hasProperty("cause", Matchers.isA(IllegalStateException.class)) 41 | ); 42 | } 43 | 44 | @Test 45 | void wrapsWithArtipieExceptionIfUnmatched() { 46 | final CompletableFuture future = CompletableFuture.runAsync(Assertions::fail); 47 | MatcherAssert.assertThat( 48 | Assertions.assertThrows( 49 | ExecutionException.class, 50 | future.handle( 51 | new InternalExceptionHandle<>( 52 | NullPointerException.class, 53 | IllegalStateException::new 54 | ) 55 | ) 56 | .thenCompose(Function.identity()) 57 | .toCompletableFuture() 58 | ::get 59 | ), 60 | Matchers.hasProperty("cause", Matchers.isA(ArtipieIOException.class)) 61 | ); 62 | } 63 | 64 | @Test 65 | void returnsValueIfNoErrorOccurs() throws ExecutionException, InterruptedException { 66 | final CompletableFuture future = CompletableFuture.supplyAsync( 67 | Object::new 68 | ); 69 | MatcherAssert.assertThat( 70 | future 71 | .handle( 72 | new InternalExceptionHandle<>( 73 | AssertionError.class, 74 | IllegalStateException::new 75 | ) 76 | ) 77 | .thenCompose(Function.identity()) 78 | .toCompletableFuture() 79 | .get(), 80 | Matchers.notNullValue() 81 | ); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /asto-vertx-file/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | asto 28 | com.artipie 29 | 1.0-SNAPSHOT 30 | 31 | 4.0.0 32 | asto-vertx-file 33 | 34 | 4.3.3 35 | 36 | 37 | 38 | com.artipie 39 | asto-core 40 | 1.0-SNAPSHOT 41 | compile 42 | 43 | 44 | 45 | io.vertx 46 | vertx-reactive-streams 47 | ${vertx.version} 48 | true 49 | 50 | 51 | io.vertx 52 | vertx-rx-java2 53 | ${vertx.version} 54 | true 55 | 56 | 57 | com.fasterxml.jackson.core 58 | jackson-databind 59 | 60 | 61 | 62 | 63 | io.vertx 64 | vertx-core 65 | ${vertx.version} 66 | true 67 | 68 | 69 | com.fasterxml.jackson.core 70 | jackson-databind 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /asto-s3/src/main/java/com/artipie/asto/s3/Bucket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2020-2023 artipie.com 3 | * https://github.com/artipie/asto/LICENSE.txt 4 | */ 5 | package com.artipie.asto.s3; 6 | 7 | import java.util.concurrent.CompletableFuture; 8 | import software.amazon.awssdk.core.async.AsyncRequestBody; 9 | import software.amazon.awssdk.services.s3.S3AsyncClient; 10 | import software.amazon.awssdk.services.s3.model.AbortMultipartUploadRequest; 11 | import software.amazon.awssdk.services.s3.model.AbortMultipartUploadResponse; 12 | import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest; 13 | import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadResponse; 14 | import software.amazon.awssdk.services.s3.model.UploadPartRequest; 15 | import software.amazon.awssdk.services.s3.model.UploadPartResponse; 16 | 17 | /** 18 | * S3 client targeted at specific bucket. 19 | * 20 | * @since 0.1 21 | */ 22 | final class Bucket { 23 | 24 | /** 25 | * S3 client. 26 | */ 27 | private final S3AsyncClient client; 28 | 29 | /** 30 | * Bucket name. 31 | */ 32 | private final String name; 33 | 34 | /** 35 | * Ctor. 36 | * 37 | * @param client S3 client. 38 | * @param name Bucket name. 39 | */ 40 | Bucket(final S3AsyncClient client, final String name) { 41 | this.client = client; 42 | this.name = name; 43 | } 44 | 45 | /** 46 | * Handles {@link UploadPartResponse}. 47 | * See {@link S3AsyncClient#uploadPart(UploadPartRequest, AsyncRequestBody)} 48 | * 49 | * @param request Request to bucket. 50 | * @param body Part body to upload. 51 | * @return Response to request. 52 | */ 53 | public CompletableFuture uploadPart( 54 | final UploadPartRequest request, 55 | final AsyncRequestBody body) { 56 | return this.client.uploadPart(request.copy(original -> original.bucket(this.name)), body); 57 | } 58 | 59 | /** 60 | * Handles {@link CompleteMultipartUploadRequest}. 61 | * See {@link S3AsyncClient#completeMultipartUpload(CompleteMultipartUploadRequest)} 62 | * 63 | * @param request Request to bucket. 64 | * @return Response to request. 65 | */ 66 | public CompletableFuture completeMultipartUpload( 67 | final CompleteMultipartUploadRequest request) { 68 | return this.client.completeMultipartUpload( 69 | request.copy(original -> original.bucket(this.name)) 70 | ); 71 | } 72 | 73 | /** 74 | * Handles {@link AbortMultipartUploadRequest}. 75 | * See {@link S3AsyncClient#abortMultipartUpload(AbortMultipartUploadRequest)} 76 | * 77 | * @param request Request to bucket. 78 | * @return Response to request. 79 | */ 80 | public CompletableFuture abortMultipartUpload( 81 | final AbortMultipartUploadRequest request) { 82 | return this.client.abortMultipartUpload( 83 | request.copy(original -> original.bucket(this.name)) 84 | ); 85 | } 86 | } 87 | --------------------------------------------------------------------------------