From c4ed4b378cd8f0586af0cec4dca03b9ce961ede2 Mon Sep 17 00:00:00 2001 From: catbref Date: Fri, 21 Dec 2018 11:14:16 +0000 Subject: [PATCH] Refactoring, new translations, cleaning up warnings. Refactored to standard Maven layout: src/main/java src/main/resources src/test/java etc. New translation code that uses locale-specific ResourceBundles to load translations on demand. Reworked API error/exceptions code to a shorter, simpler @ApiErrors annotation. Processing of @ApiErrors annotations produces an example for each possible API error and includes API error string in HTTP response code, e.g. 400 INVALID_SIGNATURE Missing API error cases added to each API call. Translation of openAPI.json removed (for now). block-explorer.html and BIP39 wordlists now read as resources instead of direct from disk. Java compile warnings fixed. Some runtime warnings remain: WARNING: A provider api.resource.ApiDefinition registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. WARNING: A provider api.resource.AnnotationPostProcessor registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. WARN org.reflections.Reflections - given scan urls are empty. set urls in the configuration --- .classpath | 26 +- .settings/org.eclipse.core.resources.prefs | 4 +- .settings/org.eclipse.jdt.core.prefs | 1 + NOTES.md | 37 -- globalization/Api.de.xml | 104 ---- globalization/Api.en.xml | 108 ---- pom.xml | 11 +- src/api/AnnotationPostProcessor.java | 239 --------- src/api/ApiClient.java | 340 ------------- src/api/ApiErrorFactory.java | 200 -------- src/api/BlockExplorerResource.java | 35 -- src/globalization/BIP39WordList.java | 55 -- src/globalization/ContextPaths.java | 33 -- src/globalization/TranslationEntry.java | 32 -- .../TranslationXmlStreamReader.java | 252 ---------- src/globalization/Translations.xsd | 33 -- src/globalization/Translator.java | 176 ------- src/{ => main/java}/api/ApiError.java | 48 +- src/{ => main/java}/api/ApiErrorMessage.java | 9 +- src/main/java/api/ApiErrors.java | 18 + src/{ => main/java}/api/ApiException.java | 10 +- src/main/java/api/ApiExceptionFactory.java | 20 + src/{ => main/java}/api/ApiService.java | 32 +- .../java}/api/Base58TypeAdapter.java | 0 .../java}/api/BigDecimalTypeAdapter.java | 0 src/{ => main/java}/api/Constants.java | 0 src/{ => main/java}/api/Security.java | 4 +- .../java}/api/TransactionClassExtractor.java | 0 .../java}/api/TranslatableProperty.java | 0 .../java}/api/models/AssetWithHolders.java | 0 .../api/models/BlockWithTransactions.java | 0 .../java}/api/models/OrderWithTrades.java | 0 .../models/SimpleTransactionSignRequest.java | 0 .../java}/api/models/TradeWithOrderInfo.java | 0 .../java/api/resource}/AddressesResource.java | 216 ++------ .../java/api/resource}/AdminResource.java | 39 +- .../api/resource/AnnotationPostProcessor.java | 114 +++++ .../java/api/resource}/ApiDefinition.java | 5 +- .../java/api/resource}/AssetsResource.java | 43 +- .../api/resource/BlockExplorerResource.java | 37 ++ .../java/api/resource}/BlocksResource.java | 475 +++--------------- .../java/api/resource}/NamesResource.java | 20 +- .../java/api/resource}/PaymentsResource.java | 20 +- .../api/resource}/TransactionsResource.java | 171 ++----- .../java/api/resource}/UtilsResource.java | 27 +- src/{ => main/java}/blockgenerator.java | 0 src/{ => main/java}/brokenmd160.java | 0 .../java}/controller/Controller.java | 0 src/{ => main/java}/crosschain/BTC.java | 2 +- src/{ => main/java}/data/PaymentData.java | 0 .../data/account/AccountBalanceData.java | 0 .../java}/data/account/AccountData.java | 0 .../java}/data/assets/AssetData.java | 0 .../java}/data/assets/OrderData.java | 0 .../java}/data/assets/TradeData.java | 0 src/{ => main/java}/data/at/ATData.java | 0 src/{ => main/java}/data/at/ATStateData.java | 0 src/{ => main/java}/data/block/BlockData.java | 0 .../data/block/BlockTransactionData.java | 0 src/{ => main/java}/data/naming/NameData.java | 0 src/{ => main/java}/data/package-info.java | 0 .../data/transaction/ATTransactionData.java | 0 .../transaction/ArbitraryTransactionData.java | 0 .../transaction/BuyNameTransactionData.java | 0 .../CancelOrderTransactionData.java | 0 .../CancelSellNameTransactionData.java | 0 .../CreateOrderTransactionData.java | 0 .../CreatePollTransactionData.java | 0 .../transaction/DeployATTransactionData.java | 0 .../transaction/GenesisTransactionData.java | 0 .../IssueAssetTransactionData.java | 0 .../transaction/MessageTransactionData.java | 0 .../MultiPaymentTransactionData.java | 0 .../transaction/PaymentTransactionData.java | 0 .../RegisterNameTransactionData.java | 0 .../transaction/SellNameTransactionData.java | 0 .../data/transaction/TransactionData.java | 0 .../TransferAssetTransactionData.java | 0 .../UpdateNameTransactionData.java | 0 .../VoteOnPollTransactionData.java | 0 src/{ => main/java}/data/voting/PollData.java | 0 .../java}/data/voting/PollOptionData.java | 0 .../java}/data/voting/VoteOnPollData.java | 0 .../java}/database/NoDataFoundException.java | 0 .../java/globalization/BIP39WordList.java | 52 ++ src/main/java/globalization/Translator.java | 52 ++ .../curve25519/java/Arrays.java | 0 .../curve25519/java/Sha512.java | 0 .../curve25519/java/crypto_verify_32.java | 0 .../curve25519/java/curve_sigs.java | 0 .../whispersystems/curve25519/java/fe_0.java | 0 .../whispersystems/curve25519/java/fe_1.java | 0 .../curve25519/java/fe_add.java | 0 .../curve25519/java/fe_cmov.java | 0 .../curve25519/java/fe_copy.java | 0 .../curve25519/java/fe_cswap.java | 0 .../curve25519/java/fe_frombytes.java | 0 .../curve25519/java/fe_invert.java | 0 .../curve25519/java/fe_isnegative.java | 0 .../curve25519/java/fe_isnonzero.java | 0 .../curve25519/java/fe_mul.java | 0 .../curve25519/java/fe_mul121666.java | 0 .../curve25519/java/fe_neg.java | 0 .../curve25519/java/fe_pow22523.java | 0 .../whispersystems/curve25519/java/fe_sq.java | 0 .../curve25519/java/fe_sq2.java | 0 .../curve25519/java/fe_sub.java | 0 .../curve25519/java/fe_tobytes.java | 0 .../curve25519/java/ge_add.java | 0 .../curve25519/java/ge_cached.java | 0 .../curve25519/java/ge_double_scalarmult.java | 0 .../curve25519/java/ge_frombytes.java | 0 .../curve25519/java/ge_madd.java | 0 .../curve25519/java/ge_msub.java | 0 .../curve25519/java/ge_p1p1.java | 0 .../curve25519/java/ge_p1p1_to_p2.java | 0 .../curve25519/java/ge_p1p1_to_p3.java | 0 .../whispersystems/curve25519/java/ge_p2.java | 0 .../curve25519/java/ge_p2_0.java | 0 .../curve25519/java/ge_p2_dbl.java | 0 .../whispersystems/curve25519/java/ge_p3.java | 0 .../curve25519/java/ge_p3_0.java | 0 .../curve25519/java/ge_p3_dbl.java | 0 .../curve25519/java/ge_p3_to_cached.java | 0 .../curve25519/java/ge_p3_to_p2.java | 0 .../curve25519/java/ge_p3_tobytes.java | 0 .../curve25519/java/ge_precomp.java | 0 .../curve25519/java/ge_precomp_0.java | 0 .../curve25519/java/ge_precomp_base_0_7.java | 0 .../java/ge_precomp_base_16_23.java | 0 .../java/ge_precomp_base_24_31.java | 0 .../curve25519/java/ge_precomp_base_8_15.java | 0 .../curve25519/java/ge_scalarmult_base.java | 0 .../curve25519/java/ge_sub.java | 0 .../curve25519/java/ge_tobytes.java | 0 .../whispersystems/curve25519/java/open.java | 0 .../curve25519/java/sc_muladd.java | 0 .../curve25519/java/sc_reduce.java | 0 .../curve25519/java/scalarmult.java | 0 .../curve25519/java/sign_modified.java | 0 src/{ => main/java}/orphan.java | 0 src/{ => main/java}/qora/account/Account.java | 0 .../java}/qora/account/GenesisAccount.java | 0 .../java}/qora/account/PrivateKeyAccount.java | 0 .../java}/qora/account/PublicKeyAccount.java | 0 src/{ => main/java}/qora/assets/Asset.java | 0 src/{ => main/java}/qora/assets/Order.java | 0 src/{ => main/java}/qora/assets/Trade.java | 0 src/{ => main/java}/qora/at/AT.java | 0 .../java}/qora/at/BlockchainAPI.java | 0 src/{ => main/java}/qora/at/QoraATAPI.java | 0 src/{ => main/java}/qora/at/QoraATLogger.java | 0 .../java}/qora/at/QoraFunctionCode.java | 0 src/{ => main/java}/qora/block/Block.java | 0 .../java}/qora/block/BlockChain.java | 0 .../java}/qora/block/BlockGenerator.java | 0 .../java}/qora/block/GenesisBlock.java | 0 .../java}/qora/crypto/BrokenMD160.java | 0 src/{ => main/java}/qora/crypto/Crypto.java | 0 .../java}/qora/crypto/CryptoBytes.java | 0 src/{ => main/java}/qora/crypto/Ed25519.java | 0 src/{ => main/java}/qora/naming/Name.java | 0 src/{ => main/java}/qora/payment/Payment.java | 0 .../java}/qora/transaction/ATTransaction.java | 0 .../transaction/ArbitraryTransaction.java | 0 .../qora/transaction/BuyNameTransaction.java | 0 .../transaction/CancelOrderTransaction.java | 0 .../CancelSellNameTransaction.java | 0 .../transaction/CreateOrderTransaction.java | 0 .../transaction/CreatePollTransaction.java | 0 .../qora/transaction/DeployATTransaction.java | 0 .../qora/transaction/GenesisTransaction.java | 0 .../transaction/IssueAssetTransaction.java | 0 .../qora/transaction/MessageTransaction.java | 0 .../transaction/MultiPaymentTransaction.java | 0 .../qora/transaction/PaymentTransaction.java | 0 .../transaction/RegisterNameTransaction.java | 0 .../qora/transaction/SellNameTransaction.java | 0 .../java}/qora/transaction/Transaction.java | 0 .../transaction/TransferAssetTransaction.java | 0 .../transaction/UpdateNameTransaction.java | 0 .../transaction/VoteOnPollTransaction.java | 0 src/{ => main/java}/qora/voting/Poll.java | 0 .../java}/repository/ATRepository.java | 0 .../java}/repository/AccountRepository.java | 0 .../java}/repository/AssetRepository.java | 0 .../java}/repository/BlockRepository.java | 0 .../java}/repository/DataException.java | 0 .../java}/repository/NameRepository.java | 0 .../java}/repository/Repository.java | 0 .../java}/repository/RepositoryFactory.java | 0 .../java}/repository/RepositoryManager.java | 0 .../repository/TransactionRepository.java | 0 .../java}/repository/VotingRepository.java | 0 .../repository/hsqldb/HSQLDBATRepository.java | 0 .../hsqldb/HSQLDBAccountRepository.java | 0 .../hsqldb/HSQLDBAssetRepository.java | 0 .../hsqldb/HSQLDBBlockRepository.java | 0 .../hsqldb/HSQLDBDatabaseUpdates.java | 0 .../hsqldb/HSQLDBNameRepository.java | 0 .../repository/hsqldb/HSQLDBRepository.java | 0 .../hsqldb/HSQLDBRepositoryFactory.java | 0 .../java}/repository/hsqldb/HSQLDBSaver.java | 0 .../hsqldb/HSQLDBVotingRepository.java | 0 .../HSQLDBATTransactionRepository.java | 0 .../HSQLDBArbitraryTransactionRepository.java | 0 .../HSQLDBBuyNameTransactionRepository.java | 0 ...SQLDBCancelOrderTransactionRepository.java | 0 ...DBCancelSellNameTransactionRepository.java | 0 ...SQLDBCreateOrderTransactionRepository.java | 0 ...HSQLDBCreatePollTransactionRepository.java | 0 .../HSQLDBDeployATTransactionRepository.java | 0 .../HSQLDBGenesisTransactionRepository.java | 0 ...HSQLDBIssueAssetTransactionRepository.java | 0 .../HSQLDBMessageTransactionRepository.java | 0 ...QLDBMultiPaymentTransactionRepository.java | 0 .../HSQLDBPaymentTransactionRepository.java | 0 ...QLDBRegisterNameTransactionRepository.java | 0 .../HSQLDBSellNameTransactionRepository.java | 0 .../HSQLDBTransactionRepository.java | 0 ...LDBTransferAssetTransactionRepository.java | 0 ...HSQLDBUpdateNameTransactionRepository.java | 0 ...HSQLDBVoteOnPollTransactionRepository.java | 0 src/{ => main/java}/settings/Settings.java | 31 +- .../java}/transform/PaymentTransformer.java | 0 .../transform/TransformationException.java | 0 .../java}/transform/Transformer.java | 0 .../transform/block/BlockTransformer.java | 0 .../transaction/ATTransactionTransformer.java | 0 .../ArbitraryTransactionTransformer.java | 0 .../BuyNameTransactionTransformer.java | 0 .../CancelOrderTransactionTransformer.java | 0 .../CancelSellNameTransactionTransformer.java | 0 .../CreateOrderTransactionTransformer.java | 0 .../CreatePollTransactionTransformer.java | 0 .../DeployATTransactionTransformer.java | 0 .../GenesisTransactionTransformer.java | 0 .../IssueAssetTransactionTransformer.java | 0 .../MessageTransactionTransformer.java | 0 .../MultiPaymentTransactionTransformer.java | 0 .../PaymentTransactionTransformer.java | 0 .../RegisterNameTransactionTransformer.java | 0 .../SellNameTransactionTransformer.java | 0 .../transaction/TransactionTransformer.java | 0 .../TransferAssetTransactionTransformer.java | 0 .../UpdateNameTransactionTransformer.java | 0 .../VoteOnPollTransactionTransformer.java | 0 src/{ => main/java}/txhex.java | 0 src/{ => main/java}/utils/BIP39.java | 4 +- src/{ => main/java}/utils/Base58.java | 0 src/{ => main/java}/utils/NTP.java | 0 src/{ => main/java}/utils/Pair.java | 0 src/{ => main/java}/utils/Serialization.java | 0 src/{ => main/java}/utils/Triple.java | 0 src/{ => main/java}/v1feeder.java | 0 .../main/resources/BIP39/wordlist_en.txt | 0 .../main/resources/block-explorer.html | 0 .../globalization}/BlocksResource.de.xml | 0 .../globalization}/BlocksResource.en.xml | 0 .../resources/i18n/ApiError_de.properties | 72 +++ .../resources/i18n/ApiError_en.properties | 95 ++++ .../i18n/TransactionValidity_en.properties | 42 ++ {tests => src/test/java}/test/ATTests.java | 0 .../test/java}/test/BTCACCTTests.java | 1 - {tests => src/test/java}/test/BTCTests.java | 0 {tests => src/test/java}/test/BlockTests.java | 0 .../test/java}/test/BlockchainTests.java | 0 {tests => src/test/java}/test/Common.java | 0 .../test/java}/test/CompatibilityTests.java | 0 .../test/java}/test/CryptoTests.java | 0 .../test/java}/test/ExceptionTests.java | 0 .../test/java}/test/GenesisTests.java | 0 {tests => src/test/java}/test/LoadTests.java | 0 .../test/java}/test/NavigationTests.java | 0 .../test/java}/test/RepositoryTests.java | 0 {tests => src/test/java}/test/SaveTests.java | 0 .../test/java}/test/SerializationTests.java | 0 .../test/java}/test/SignatureTests.java | 0 .../test/java}/test/TransactionTests.java | 0 .../java/test/utils/AssertExtensions.java | 18 + tests/test/GlobalizationTests.java | 171 ------- tests/test/utils/AssertExtensions.java | 42 -- tests/test/utils/EqualityComparer.java | 6 - tests/test/utils/EquatableWrapper.java | 34 -- 284 files changed, 835 insertions(+), 2781 deletions(-) delete mode 100644 NOTES.md delete mode 100644 globalization/Api.de.xml delete mode 100644 globalization/Api.en.xml delete mode 100644 src/api/AnnotationPostProcessor.java delete mode 100644 src/api/ApiClient.java delete mode 100644 src/api/ApiErrorFactory.java delete mode 100644 src/api/BlockExplorerResource.java delete mode 100644 src/globalization/BIP39WordList.java delete mode 100644 src/globalization/ContextPaths.java delete mode 100644 src/globalization/TranslationEntry.java delete mode 100644 src/globalization/TranslationXmlStreamReader.java delete mode 100644 src/globalization/Translations.xsd delete mode 100644 src/globalization/Translator.java rename src/{ => main/java}/api/ApiError.java (83%) rename src/{ => main/java}/api/ApiErrorMessage.java (68%) create mode 100644 src/main/java/api/ApiErrors.java rename src/{ => main/java}/api/ApiException.java (84%) create mode 100644 src/main/java/api/ApiExceptionFactory.java rename src/{ => main/java}/api/ApiService.java (76%) rename src/{ => main/java}/api/Base58TypeAdapter.java (100%) rename src/{ => main/java}/api/BigDecimalTypeAdapter.java (100%) rename src/{ => main/java}/api/Constants.java (100%) rename src/{ => main/java}/api/Security.java (72%) rename src/{ => main/java}/api/TransactionClassExtractor.java (100%) rename src/{ => main/java}/api/TranslatableProperty.java (100%) rename src/{ => main/java}/api/models/AssetWithHolders.java (100%) rename src/{ => main/java}/api/models/BlockWithTransactions.java (100%) rename src/{ => main/java}/api/models/OrderWithTrades.java (100%) rename src/{ => main/java}/api/models/SimpleTransactionSignRequest.java (100%) rename src/{ => main/java}/api/models/TradeWithOrderInfo.java (100%) rename src/{api => main/java/api/resource}/AddressesResource.java (53%) rename src/{api => main/java/api/resource}/AdminResource.java (71%) create mode 100644 src/main/java/api/resource/AnnotationPostProcessor.java rename src/{api => main/java/api/resource}/ApiDefinition.java (97%) rename src/{api => main/java/api/resource}/AssetsResource.java (80%) create mode 100644 src/main/java/api/resource/BlockExplorerResource.java rename src/{api => main/java/api/resource}/BlocksResource.java (52%) rename src/{api => main/java/api/resource}/NamesResource.java (79%) rename src/{api => main/java/api/resource}/PaymentsResource.java (79%) rename src/{api => main/java/api/resource}/TransactionsResource.java (74%) rename src/{api => main/java/api/resource}/UtilsResource.java (89%) rename src/{ => main/java}/blockgenerator.java (100%) rename src/{ => main/java}/brokenmd160.java (100%) rename src/{ => main/java}/controller/Controller.java (100%) rename src/{ => main/java}/crosschain/BTC.java (99%) rename src/{ => main/java}/data/PaymentData.java (100%) rename src/{ => main/java}/data/account/AccountBalanceData.java (100%) rename src/{ => main/java}/data/account/AccountData.java (100%) rename src/{ => main/java}/data/assets/AssetData.java (100%) rename src/{ => main/java}/data/assets/OrderData.java (100%) rename src/{ => main/java}/data/assets/TradeData.java (100%) rename src/{ => main/java}/data/at/ATData.java (100%) rename src/{ => main/java}/data/at/ATStateData.java (100%) rename src/{ => main/java}/data/block/BlockData.java (100%) rename src/{ => main/java}/data/block/BlockTransactionData.java (100%) rename src/{ => main/java}/data/naming/NameData.java (100%) rename src/{ => main/java}/data/package-info.java (100%) rename src/{ => main/java}/data/transaction/ATTransactionData.java (100%) rename src/{ => main/java}/data/transaction/ArbitraryTransactionData.java (100%) rename src/{ => main/java}/data/transaction/BuyNameTransactionData.java (100%) rename src/{ => main/java}/data/transaction/CancelOrderTransactionData.java (100%) rename src/{ => main/java}/data/transaction/CancelSellNameTransactionData.java (100%) rename src/{ => main/java}/data/transaction/CreateOrderTransactionData.java (100%) rename src/{ => main/java}/data/transaction/CreatePollTransactionData.java (100%) rename src/{ => main/java}/data/transaction/DeployATTransactionData.java (100%) rename src/{ => main/java}/data/transaction/GenesisTransactionData.java (100%) rename src/{ => main/java}/data/transaction/IssueAssetTransactionData.java (100%) rename src/{ => main/java}/data/transaction/MessageTransactionData.java (100%) rename src/{ => main/java}/data/transaction/MultiPaymentTransactionData.java (100%) rename src/{ => main/java}/data/transaction/PaymentTransactionData.java (100%) rename src/{ => main/java}/data/transaction/RegisterNameTransactionData.java (100%) rename src/{ => main/java}/data/transaction/SellNameTransactionData.java (100%) rename src/{ => main/java}/data/transaction/TransactionData.java (100%) rename src/{ => main/java}/data/transaction/TransferAssetTransactionData.java (100%) rename src/{ => main/java}/data/transaction/UpdateNameTransactionData.java (100%) rename src/{ => main/java}/data/transaction/VoteOnPollTransactionData.java (100%) rename src/{ => main/java}/data/voting/PollData.java (100%) rename src/{ => main/java}/data/voting/PollOptionData.java (100%) rename src/{ => main/java}/data/voting/VoteOnPollData.java (100%) rename src/{ => main/java}/database/NoDataFoundException.java (100%) create mode 100644 src/main/java/globalization/BIP39WordList.java create mode 100644 src/main/java/globalization/Translator.java rename src/{ => main/java}/org/whispersystems/curve25519/java/Arrays.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/Sha512.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/crypto_verify_32.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/curve_sigs.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_0.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_1.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_add.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_cmov.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_copy.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_cswap.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_frombytes.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_invert.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_isnegative.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_isnonzero.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_mul.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_mul121666.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_neg.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_pow22523.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_sq.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_sq2.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_sub.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/fe_tobytes.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_add.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_cached.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_double_scalarmult.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_frombytes.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_madd.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_msub.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p1p1.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p1p1_to_p2.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p1p1_to_p3.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p2.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p2_0.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p2_dbl.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p3.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p3_0.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p3_dbl.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p3_to_cached.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p3_to_p2.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_p3_tobytes.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_precomp.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_precomp_0.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_precomp_base_0_7.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_precomp_base_16_23.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_precomp_base_24_31.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_precomp_base_8_15.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_scalarmult_base.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_sub.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/ge_tobytes.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/open.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/sc_muladd.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/sc_reduce.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/scalarmult.java (100%) rename src/{ => main/java}/org/whispersystems/curve25519/java/sign_modified.java (100%) rename src/{ => main/java}/orphan.java (100%) rename src/{ => main/java}/qora/account/Account.java (100%) rename src/{ => main/java}/qora/account/GenesisAccount.java (100%) rename src/{ => main/java}/qora/account/PrivateKeyAccount.java (100%) rename src/{ => main/java}/qora/account/PublicKeyAccount.java (100%) rename src/{ => main/java}/qora/assets/Asset.java (100%) rename src/{ => main/java}/qora/assets/Order.java (100%) rename src/{ => main/java}/qora/assets/Trade.java (100%) rename src/{ => main/java}/qora/at/AT.java (100%) rename src/{ => main/java}/qora/at/BlockchainAPI.java (100%) rename src/{ => main/java}/qora/at/QoraATAPI.java (100%) rename src/{ => main/java}/qora/at/QoraATLogger.java (100%) rename src/{ => main/java}/qora/at/QoraFunctionCode.java (100%) rename src/{ => main/java}/qora/block/Block.java (100%) rename src/{ => main/java}/qora/block/BlockChain.java (100%) rename src/{ => main/java}/qora/block/BlockGenerator.java (100%) rename src/{ => main/java}/qora/block/GenesisBlock.java (100%) rename src/{ => main/java}/qora/crypto/BrokenMD160.java (100%) rename src/{ => main/java}/qora/crypto/Crypto.java (100%) rename src/{ => main/java}/qora/crypto/CryptoBytes.java (100%) rename src/{ => main/java}/qora/crypto/Ed25519.java (100%) rename src/{ => main/java}/qora/naming/Name.java (100%) rename src/{ => main/java}/qora/payment/Payment.java (100%) rename src/{ => main/java}/qora/transaction/ATTransaction.java (100%) rename src/{ => main/java}/qora/transaction/ArbitraryTransaction.java (100%) rename src/{ => main/java}/qora/transaction/BuyNameTransaction.java (100%) rename src/{ => main/java}/qora/transaction/CancelOrderTransaction.java (100%) rename src/{ => main/java}/qora/transaction/CancelSellNameTransaction.java (100%) rename src/{ => main/java}/qora/transaction/CreateOrderTransaction.java (100%) rename src/{ => main/java}/qora/transaction/CreatePollTransaction.java (100%) rename src/{ => main/java}/qora/transaction/DeployATTransaction.java (100%) rename src/{ => main/java}/qora/transaction/GenesisTransaction.java (100%) rename src/{ => main/java}/qora/transaction/IssueAssetTransaction.java (100%) rename src/{ => main/java}/qora/transaction/MessageTransaction.java (100%) rename src/{ => main/java}/qora/transaction/MultiPaymentTransaction.java (100%) rename src/{ => main/java}/qora/transaction/PaymentTransaction.java (100%) rename src/{ => main/java}/qora/transaction/RegisterNameTransaction.java (100%) rename src/{ => main/java}/qora/transaction/SellNameTransaction.java (100%) rename src/{ => main/java}/qora/transaction/Transaction.java (100%) rename src/{ => main/java}/qora/transaction/TransferAssetTransaction.java (100%) rename src/{ => main/java}/qora/transaction/UpdateNameTransaction.java (100%) rename src/{ => main/java}/qora/transaction/VoteOnPollTransaction.java (100%) rename src/{ => main/java}/qora/voting/Poll.java (100%) rename src/{ => main/java}/repository/ATRepository.java (100%) rename src/{ => main/java}/repository/AccountRepository.java (100%) rename src/{ => main/java}/repository/AssetRepository.java (100%) rename src/{ => main/java}/repository/BlockRepository.java (100%) rename src/{ => main/java}/repository/DataException.java (100%) rename src/{ => main/java}/repository/NameRepository.java (100%) rename src/{ => main/java}/repository/Repository.java (100%) rename src/{ => main/java}/repository/RepositoryFactory.java (100%) rename src/{ => main/java}/repository/RepositoryManager.java (100%) rename src/{ => main/java}/repository/TransactionRepository.java (100%) rename src/{ => main/java}/repository/VotingRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/HSQLDBATRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/HSQLDBAccountRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/HSQLDBAssetRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/HSQLDBBlockRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/HSQLDBDatabaseUpdates.java (100%) rename src/{ => main/java}/repository/hsqldb/HSQLDBNameRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/HSQLDBRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/HSQLDBRepositoryFactory.java (100%) rename src/{ => main/java}/repository/hsqldb/HSQLDBSaver.java (100%) rename src/{ => main/java}/repository/hsqldb/HSQLDBVotingRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBArbitraryTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBBuyNameTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBCancelOrderTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBCancelSellNameTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBCreateOrderTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBCreatePollTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBDeployATTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBGenesisTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBIssueAssetTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBMessageTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBMultiPaymentTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBPaymentTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBRegisterNameTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBSellNameTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBTransferAssetTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBUpdateNameTransactionRepository.java (100%) rename src/{ => main/java}/repository/hsqldb/transaction/HSQLDBVoteOnPollTransactionRepository.java (100%) rename src/{ => main/java}/settings/Settings.java (89%) rename src/{ => main/java}/transform/PaymentTransformer.java (100%) rename src/{ => main/java}/transform/TransformationException.java (100%) rename src/{ => main/java}/transform/Transformer.java (100%) rename src/{ => main/java}/transform/block/BlockTransformer.java (100%) rename src/{ => main/java}/transform/transaction/ATTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/ArbitraryTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/BuyNameTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/CancelOrderTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/CancelSellNameTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/CreateOrderTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/CreatePollTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/DeployATTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/GenesisTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/IssueAssetTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/MessageTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/MultiPaymentTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/PaymentTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/RegisterNameTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/SellNameTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/TransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/TransferAssetTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/UpdateNameTransactionTransformer.java (100%) rename src/{ => main/java}/transform/transaction/VoteOnPollTransactionTransformer.java (100%) rename src/{ => main/java}/txhex.java (100%) rename src/{ => main/java}/utils/BIP39.java (93%) rename src/{ => main/java}/utils/Base58.java (100%) rename src/{ => main/java}/utils/NTP.java (100%) rename src/{ => main/java}/utils/Pair.java (100%) rename src/{ => main/java}/utils/Serialization.java (100%) rename src/{ => main/java}/utils/Triple.java (100%) rename src/{ => main/java}/v1feeder.java (100%) rename globalization/BIP39.en.txt => src/main/resources/BIP39/wordlist_en.txt (100%) rename block-explorer.html => src/main/resources/block-explorer.html (100%) rename {globalization => src/main/resources/globalization}/BlocksResource.de.xml (100%) rename {globalization => src/main/resources/globalization}/BlocksResource.en.xml (100%) create mode 100644 src/main/resources/i18n/ApiError_de.properties create mode 100644 src/main/resources/i18n/ApiError_en.properties create mode 100644 src/main/resources/i18n/TransactionValidity_en.properties rename {tests => src/test/java}/test/ATTests.java (100%) rename {tests => src/test/java}/test/BTCACCTTests.java (99%) rename {tests => src/test/java}/test/BTCTests.java (100%) rename {tests => src/test/java}/test/BlockTests.java (100%) rename {tests => src/test/java}/test/BlockchainTests.java (100%) rename {tests => src/test/java}/test/Common.java (100%) rename {tests => src/test/java}/test/CompatibilityTests.java (100%) rename {tests => src/test/java}/test/CryptoTests.java (100%) rename {tests => src/test/java}/test/ExceptionTests.java (100%) rename {tests => src/test/java}/test/GenesisTests.java (100%) rename {tests => src/test/java}/test/LoadTests.java (100%) rename {tests => src/test/java}/test/NavigationTests.java (100%) rename {tests => src/test/java}/test/RepositoryTests.java (100%) rename {tests => src/test/java}/test/SaveTests.java (100%) rename {tests => src/test/java}/test/SerializationTests.java (100%) rename {tests => src/test/java}/test/SignatureTests.java (100%) rename {tests => src/test/java}/test/TransactionTests.java (100%) create mode 100644 src/test/java/test/utils/AssertExtensions.java delete mode 100644 tests/test/GlobalizationTests.java delete mode 100644 tests/test/utils/AssertExtensions.java delete mode 100644 tests/test/utils/EqualityComparer.java delete mode 100644 tests/test/utils/EquatableWrapper.java diff --git a/.classpath b/.classpath index 470e5334..b9965edb 100644 --- a/.classpath +++ b/.classpath @@ -1,12 +1,18 @@ - + - + + + + + + + @@ -22,20 +28,11 @@ - + - - - - - - - - - @@ -44,5 +41,10 @@ + + + + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs index 165066bb..ed7df2b3 100644 --- a/.settings/org.eclipse.core.resources.prefs +++ b/.settings/org.eclipse.core.resources.prefs @@ -1,4 +1,6 @@ eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 encoding/=UTF-8 encoding/src=UTF-8 -encoding/tests=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 61cb7d11..cbbeed13 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.8 diff --git a/NOTES.md b/NOTES.md deleted file mode 100644 index ba619ca6..00000000 --- a/NOTES.md +++ /dev/null @@ -1,37 +0,0 @@ -### General - -- Reduce Qora2 down to core blockchain node with RESTful API access. -Other libraries can process name-storage data into websites, or provide web-based wallet UI, etc. - -- Trying to reduce number of external dependencies where possible, e.g. avoiding heavy-weight ORM like Hive, Hibernate, etc. - -- Trying to reduce duplicated code, especially across transactions with lots of serialisation and signature generation. - -- Transaction signatures should really be generated after creating the transaction, -compared to the old style of generating signature first (and throw-away transaction in the process) -then using signature when creating actual transaction! - -- Trying to keep most of the source structure, naming, code paths, etc. similar to old Qora to reduce brain load! - -- More comments/javadoc - -- More JUnit tests - -### Differences due to switching from MapDB to HSQLDB - -- We might need to maintain more mappings in the database, e.g. Qora address to/from public key, -as previously public key objects could be stored directly in MapDB. - -- The new database tried to store the data in "rawest" form, i.e. raw ```byte[]``` signatures, not base58-encoded. - -- The ```Transactions``` table contains ```creator``` column, which duplicates various child table columns, -e.g. ```PaymentTransactions.sender```, -so that all transactions by a specific Qora account can be quickly found without scanning all child tables. - -- SQL is contained within repository classes repository.* (interfaces) and repository.hsqldb.* (implementations). - -- We use transfer objects in data.* - -- "Business logic" is left in qora.* - -- Some MapDB-based objects had Java Map<> objects as their values. These will need to be unpacked into separate tables. diff --git a/globalization/Api.de.xml b/globalization/Api.de.xml deleted file mode 100644 index b188fa51..00000000 --- a/globalization/Api.de.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/globalization/Api.en.xml b/globalization/Api.en.xml deleted file mode 100644 index 3becbd6e..00000000 --- a/globalization/Api.en.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pom.xml b/pom.xml index 5a487019..6875cb95 100644 --- a/pom.xml +++ b/pom.xml @@ -17,8 +17,8 @@ 3.19.0 - src - tests + src/main/java + src/test/java maven-compiler-plugin @@ -119,14 +119,13 @@ data.** - + api.models** - + - ${project.basedir}/src ${project.build.directory}/generated-sources/package-info @@ -391,4 +390,4 @@ ${bouncycastle.version} - \ No newline at end of file + diff --git a/src/api/AnnotationPostProcessor.java b/src/api/AnnotationPostProcessor.java deleted file mode 100644 index 4149f41b..00000000 --- a/src/api/AnnotationPostProcessor.java +++ /dev/null @@ -1,239 +0,0 @@ -package api; - -import com.fasterxml.jackson.databind.node.ArrayNode; -import globalization.ContextPaths; -import globalization.Translator; -import io.swagger.v3.core.converter.ModelConverters; -import io.swagger.v3.jaxrs2.Reader; -import io.swagger.v3.jaxrs2.ReaderListener; -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.PathItem; -import io.swagger.v3.oas.models.examples.Example; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.media.Content; -import io.swagger.v3.oas.models.media.MediaType; -import io.swagger.v3.oas.models.media.Schema; -import io.swagger.v3.oas.models.parameters.Parameter; -import io.swagger.v3.oas.models.responses.ApiResponse; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - - -public class AnnotationPostProcessor implements ReaderListener { - - private static final Logger LOGGER = LogManager.getLogger(AnnotationPostProcessor.class); - - private class ContextInformation { - public String path; - public Map keys; - } - - private final Translator translator; - private final ApiErrorFactory apiErrorFactory; - - public AnnotationPostProcessor() { - this(Translator.getInstance(), ApiErrorFactory.getInstance()); - } - - public AnnotationPostProcessor(Translator translator, ApiErrorFactory apiErrorFactory) { - this.translator = translator; - this.apiErrorFactory = apiErrorFactory; - } - - @Override - public void beforeScan(Reader reader, OpenAPI openAPI) { - } - - @Override - public void afterScan(Reader reader, OpenAPI openAPI) { - // Populate Components section with reusable parameters, like "limit" and "offset" - // We take the reusable parameters from AdminResource.globalParameters path "/admin/unused" - Components components = openAPI.getComponents(); - PathItem globalParametersPathItem = openAPI.getPaths().get("/admin/unused"); - if (globalParametersPathItem != null) { - for (Parameter parameter : globalParametersPathItem.getGet().getParameters()) - components.addParameters(parameter.getName(), parameter); - openAPI.getPaths().remove("/admin/unused"); - } - - // use context path and keys from "x-translation" extension annotations - // to translate supported annotations and finally remove "x-translation" extensions - Info resourceInfo = openAPI.getInfo(); - ContextInformation resourceContext = getContextInformation(openAPI.getExtensions()); - removeTranslationAnnotations(openAPI.getExtensions()); - TranslateProperties(Constants.TRANSLATABLE_INFO_PROPERTIES, resourceContext, resourceInfo); - - for (Map.Entry pathEntry : openAPI.getPaths().entrySet()) - { - PathItem pathItem = pathEntry.getValue(); - ContextInformation pathContext = getContextInformation(pathItem.getExtensions(), resourceContext); - removeTranslationAnnotations(pathItem.getExtensions()); - TranslateProperties(Constants.TRANSLATABLE_PATH_ITEM_PROPERTIES, pathContext, pathItem); - - for (Operation operation : pathItem.readOperations()) { - ContextInformation operationContext = getContextInformation(operation.getExtensions(), pathContext); - removeTranslationAnnotations(operation.getExtensions()); - TranslateProperties(Constants.TRANSLATABLE_OPERATION_PROPERTIES, operationContext, operation); - - addApiErrorResponses(operation); - removeApiErrorsAnnotations(operation.getExtensions()); - - for (Map.Entry responseEntry : operation.getResponses().entrySet()) { - ApiResponse response = responseEntry.getValue(); - ContextInformation responseContext = getContextInformation(response.getExtensions(), operationContext); - removeTranslationAnnotations(response.getExtensions()); - TranslateProperties(Constants.TRANSLATABLE_API_RESPONSE_PROPERTIES, responseContext, response); - } - } - } - } - - private void addApiErrorResponses(Operation operation) { - List apiErrors = getApiErrors(operation.getExtensions()); - if(apiErrors != null) { - for(ApiError apiError : apiErrors) { - String statusCode = Integer.toString(apiError.getStatus()); - ApiResponse apiResponse = operation.getResponses().get(statusCode); - if(apiResponse == null) { - Schema errorMessageSchema = ModelConverters.getInstance().readAllAsResolvedSchema(ApiErrorMessage.class).schema; - MediaType mediaType = new MediaType().schema(errorMessageSchema); - Content content = new Content().addMediaType(javax.ws.rs.core.MediaType.APPLICATION_JSON, mediaType); - apiResponse = new ApiResponse().content(content); - operation.getResponses().addApiResponse(statusCode, apiResponse); - } - - int apiErrorCode = apiError.getCode(); - ApiErrorMessage apiErrorMessage = new ApiErrorMessage(apiErrorCode, this.apiErrorFactory.getErrorMessage(apiError)); - Example example = new Example().value(apiErrorMessage); - - // XXX: addExamples(..) is not working in Swagger 2.0.4. This bug is referenced in https://github.com/swagger-api/swagger-ui/issues/2651 - // Replace the call to .setExample(..) by .addExamples(..) when the bug is fixed. - apiResponse.getContent().get(javax.ws.rs.core.MediaType.APPLICATION_JSON).setExample(example); - //apiResponse.getContent().get(javax.ws.rs.core.MediaType.APPLICATION_JSON).addExamples(Integer.toString(apiErrorCode), example); - } - } - } - - private void TranslateProperties(List> translatableProperties, ContextInformation context, T item) { - if(context.keys != null) { - Map keys = context.keys; - for(TranslatableProperty prop : translatableProperties) { - String key = keys.get(prop.keyName()); - if(key != null) { - String originalValue = prop.getValue(item); - // XXX: use browser locale instead default? - String translation = translator.translate(context.path, key, originalValue); - prop.setValue(item, translation); - } - } - } - } - - private List getApiErrors(Map extensions) { - if(extensions == null) - return null; - - List apiErrorStrings = new ArrayList(); - try { - ArrayNode apiErrorsNode = (ArrayNode)extensions.get("x-" + Constants.API_ERRORS_EXTENSION_NAME); - if(apiErrorsNode == null) - return null; - - for(int i = 0; i < apiErrorsNode.size(); i++) { - String errorString = apiErrorsNode.get(i).asText(); - apiErrorStrings.add(errorString); - } - } catch(Exception e) { - // TODO: error logging - return null; - } - - List result = new ArrayList<>(); - for(String apiErrorString : apiErrorStrings) { - ApiError apiError = null; - try { - apiError = ApiError.valueOf(apiErrorString); - } catch(IllegalArgumentException e) { - try { - int errorCodeInt = Integer.parseInt(apiErrorString); - apiError = ApiError.fromCode(errorCodeInt); - } catch (NumberFormatException ex) { - return null; - } - } - - if(apiError == null) - return null; - - result.add(apiError); - } - - return result; - } - - private ContextInformation getContextInformation(Map extensions) { - return getContextInformation(extensions, null); - } - - private ContextInformation getContextInformation(Map extensions, ContextInformation base) { - if(extensions != null) { - Map translationDefinitions = (Map)extensions.get("x-" + Constants.TRANSLATION_EXTENSION_NAME); - if(translationDefinitions != null) { - ContextInformation result = new ContextInformation(); - result.path = combinePaths(base, (String)translationDefinitions.get(Constants.TRANSLATION_PATH_EXTENSION_NAME)); - result.keys = getTranslationKeys(translationDefinitions); - return result; - } - } - - if(base != null) { - ContextInformation result = new ContextInformation(); - result.path = base.path; - return result; - } - - return null; - } - - private void removeApiErrorsAnnotations(Map extensions) { - String extensionName = Constants.API_ERRORS_EXTENSION_NAME; - removeExtension(extensions, extensionName); - } - - private void removeTranslationAnnotations(Map extensions) { - String extensionName = Constants.TRANSLATION_EXTENSION_NAME; - removeExtension(extensions, extensionName); - } - - private void removeExtension(Map extensions, String extensionName) { - if(extensions == null) - return; - - extensions.remove("x-" + extensionName); - } - - private Map getTranslationKeys(Map translationDefinitions) { - Map result = new HashMap<>(); - - for(TranslatableProperty prop : Constants.TRANSLATABLE_INFO_PROPERTIES) { - String key = (String)translationDefinitions.get(prop.keyName()); - if(key != null) - result.put(prop.keyName(), key); - } - - return result; - } - - private String combinePaths(ContextInformation base, String path) { - String basePath = (base != null) ? base.path : null; - return ContextPaths.combinePaths(basePath, path); - } -} diff --git a/src/api/ApiClient.java b/src/api/ApiClient.java deleted file mode 100644 index 9421a23b..00000000 --- a/src/api/ApiClient.java +++ /dev/null @@ -1,340 +0,0 @@ -package api; - -import globalization.ContextPaths; -import globalization.Translator; -import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource; -import io.swagger.v3.oas.annotations.OpenAPIDefinition; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.extensions.Extension; -import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.ws.rs.Path; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.PATCH; -import javax.ws.rs.DELETE; -import javax.ws.rs.HttpMethod; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Invocation; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import org.apache.commons.lang3.StringUtils; -import org.glassfish.jersey.client.HttpUrlConnectorProvider; -import settings.Settings; - -public class ApiClient { - - private class HelpInfo { - - public final Pattern pattern; - public final String fullPath; - public final String description; - public final List success; - public final List errors; - - public HelpInfo(Pattern pattern, String fullPath, String description, List success, List errors) { - this.pattern = pattern; - this.fullPath = fullPath; - this.description = description; - this.success = success; - this.errors = errors; - } - } - - private static final String TRANSLATION_CONTEXT_PATH = "/Api/ApiClient"; - - private static final Pattern COMMAND_PATTERN = Pattern.compile("^ *(?GET|POST|PUT|PATCH|DELETE) *(?.*)$"); - private static final Pattern HELP_COMMAND_PATTERN = Pattern.compile("^ *help *(?.*)$", Pattern.CASE_INSENSITIVE); - private static final List> HTTP_METHOD_ANNOTATIONS = Arrays.asList( - GET.class, - POST.class, - PUT.class, - PATCH.class, - DELETE.class - ); - - private final Translator translator; - ApiService apiService; - List helpInfos; - - public ApiClient(ApiService apiService, Translator translator) { - this.apiService = apiService; - this.translator = translator; - this.helpInfos = getHelpInfos(apiService.getResources()); - } - - //XXX: replace singleton pattern by dependency injection? - private static ApiClient instance; - - public static ApiClient getInstance() { - if (instance == null) { - instance = new ApiClient(ApiService.getInstance(), Translator.getInstance()); - } - - return instance; - } - - private List getHelpInfos(Iterable> resources) { - List result = new ArrayList<>(); - - // scan each resource class - for (Class resource : resources) { - if (OpenApiResource.class.isAssignableFrom(resource)) { - continue; // ignore swagger resources - } - Path resourcePath = resource.getDeclaredAnnotation(Path.class); - if (resourcePath == null) { - continue; - } - String resourcePathString = resourcePath.value(); - - // get translation context path for resource - String resourceContextPath = "/"; - OpenAPIDefinition openAPIDefinition = resource.getDeclaredAnnotation(OpenAPIDefinition.class); - if(openAPIDefinition != null) - resourceContextPath = getContextPath(openAPIDefinition.extensions()); - - // scan each method - for (Method method : resource.getDeclaredMethods()) { - Operation operationAnnotation = method.getAnnotation(Operation.class); - if (operationAnnotation == null) - continue; - - String description = operationAnnotation.description(); - - // translate - String operationContextPath = ContextPaths.combinePaths(resourceContextPath, getContextPath(operationAnnotation.extensions())); - String operationDescriptionKey = getDescriptionTranslationKey(operationAnnotation.extensions()); - if(operationDescriptionKey != null) - description = translator.translate(operationContextPath, operationDescriptionKey, description); - - // extract responses - ArrayList success = new ArrayList(); - ArrayList errors = new ArrayList(); - for(ApiResponse response : operationAnnotation.responses()) { - String responseDescription = response.description(); - if(StringUtils.isBlank(responseDescription)) - continue; // ignore responses without description - - // translate - String responseContextPath = ContextPaths.combinePaths(operationContextPath, getContextPath(response.extensions())); - String responseDescriptionKey = getDescriptionTranslationKey(response.extensions()); - if(responseDescriptionKey != null) - responseDescription = translator.translate(responseContextPath, responseDescriptionKey, responseDescription); - - String apiErrorCode = getApiErrorCode(response.extensions()); - if(apiErrorCode != null) { - responseDescription = translator.translate(TRANSLATION_CONTEXT_PATH, "API error response", "(API error: ${ERROR_CODE}) ${DESCRIPTION}", - new AbstractMap.SimpleEntry<>("ERROR_CODE", apiErrorCode), - new AbstractMap.SimpleEntry<>("DESCRIPTION", responseDescription) - ); - } - - try { - // try to identify response type by status code - int responseCode = Integer.parseInt(response.responseCode()); - if(responseCode >= 400) { - errors.add(responseDescription); - } else { - success.add(responseDescription); - } - } catch (NumberFormatException e) { - // try to identify response type by content - if(response.content().length > 0) { - Content content = response.content()[0]; - Class implementation = content.schema().implementation(); - if(implementation != null && ApiErrorMessage.class.isAssignableFrom(implementation)) { - errors.add(responseDescription); - } else { - success.add(responseDescription); - } - } else { - success.add(responseDescription); - } - } - } - - Path methodPath = method.getDeclaredAnnotation(Path.class); - String methodPathString = (methodPath != null) ? methodPath.value() : ""; - - // scan for each potential http method - for (Class restMethodAnnotation : HTTP_METHOD_ANNOTATIONS) { - Annotation annotation = method.getDeclaredAnnotation(restMethodAnnotation); - if (annotation == null) { - continue; - } - - HttpMethod httpMethod = annotation.annotationType().getDeclaredAnnotation(HttpMethod.class); - String httpMethodString = httpMethod.value(); - - String fullPath = httpMethodString + " " + resourcePathString + methodPathString; - - Pattern pattern = Pattern.compile("^ *(" + httpMethodString + " *)?" + getHelpPatternForPath(resourcePathString + methodPathString)); - result.add(new HelpInfo(pattern, fullPath, description, success, errors)); - } - } - } - - // sort by path - result.sort((h1, h2) -> h1.fullPath.compareTo(h2.fullPath)); - - return result; - } - - private String getApiErrorCode(Extension[] extensions) { - if(extensions == null) - return null; - - for(Extension extension : extensions) { - if(extension.name() != null && !extension.name().isEmpty()) - continue; - - for(ExtensionProperty prop : extension.properties()) { - if(Constants.API_ERROR_CODE_EXTENSION_NAME.equals(prop.name())) { - return prop.value(); - } - } - } - - return null; - } - - private String getContextPath(Extension[] extensions) { - return getTranslationExtensionValue(extensions, Constants.TRANSLATION_PATH_EXTENSION_NAME); - } - - private String getDescriptionTranslationKey(Extension[] extensions) { - return getTranslationExtensionValue(extensions, Constants.TRANSLATION_ANNOTATION_DESCRIPTION_KEY); - } - - private String getTranslationExtensionValue(Extension[] extensions, String key) { - if(extensions == null) - return null; - - for(Extension extension : extensions) { - if(!Constants.TRANSLATION_EXTENSION_NAME.equals(extension.name())) - continue; - - for(ExtensionProperty prop : extension.properties()) { - if(key.equals(prop.name())) { - return prop.value(); - } - } - } - - return null; - } - - private String getHelpPatternForPath(String path) { - path = path - .replaceAll("\\.", "\\.") // escapes "." as "\." - .replaceAll("\\{.*?\\}", ".*?"); // replace placeholders "{...}" by the "ungreedy match anything" pattern ".*?" - - // arrange the regex pattern so that it also matches partial - StringBuilder result = new StringBuilder(); - String[] parts = path.split("/"); - for (int i = 0; i < parts.length; i++) { - if (i != 0) { - result.append("(/"); // opening bracket - } - result.append(parts[i]); - } - for (int i = 0; i < parts.length - 1; i++) { - result.append(")?"); // closing bracket - } - return result.toString(); - } - - public String executeCommand(String command) { - // check if this is a help command - Matcher match = HELP_COMMAND_PATTERN.matcher(command); - if (match.matches()) { - command = match.group("command"); - StringBuilder result = new StringBuilder(); - - boolean showAll = command.trim().equalsIgnoreCase("all"); - for (HelpInfo helpString : helpInfos) { - if (showAll || helpString.pattern.matcher(command).matches()) { - appendHelp(result, helpString); - } - } - - return result.toString(); - } - - - match = COMMAND_PATTERN.matcher(command); - if(!match.matches()) - return this.translator.translate(TRANSLATION_CONTEXT_PATH, "invalid command", "Invalid command! \nType 'help all' to get a list of commands."); - - // send the command to the API service - String method = match.group("method"); - String path = match.group("path"); - String url = String.format("http://127.0.0.1:%d/%s", Settings.getInstance().getRpcPort(), path); - - Client client = ClientBuilder.newClient(); - client.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true); // workaround for non-standard HTTP methods like PATCH - WebTarget wt = client.target(url); - Invocation.Builder builder = wt.request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN); - Response response = builder.method(method); - - // send back result - final String body = response.readEntity(String.class); - final int status = response.getStatus(); - StringBuilder result = new StringBuilder(); - if(status >= 400) { - if(StringUtils.isBlank(body)) { - result.append( - this.translator.translate(TRANSLATION_CONTEXT_PATH, "error without body", "HTTP Status ${STATUS}", - new AbstractMap.SimpleEntry<>("STATUS", status) - ) - ); - }else{ - result.append( - this.translator.translate(TRANSLATION_CONTEXT_PATH, "error with body", "HTTP Status ${STATUS}: ${BODY}", - new AbstractMap.SimpleEntry<>("STATUS", status), - new AbstractMap.SimpleEntry<>("BODY", body) - ) - ); - } - result.append("\n"); - result.append(this.translator.translate(TRANSLATION_CONTEXT_PATH, "error footer", "Type 'help all' to get a list of commands.")); - } else { - result.append(body); - } - return result.toString(); - } - - private void appendHelp(StringBuilder builder, HelpInfo help) { - builder.append(help.fullPath + "\n"); - builder.append(" " + help.description + "\n"); - if(help.success != null && help.success.size() > 0) { - builder.append(" "); - builder.append(this.translator.translate(TRANSLATION_CONTEXT_PATH, "help: success responses", "On success returns:")); - builder.append("\n"); - for(String content : help.success) { - builder.append(" " + content + "\n"); - } - } - if(help.errors != null && help.errors.size() > 0) { - builder.append(" "); - builder.append(this.translator.translate(TRANSLATION_CONTEXT_PATH, "help: failure responses", "On failure returns:")); - builder.append("\n"); - for(String content : help.errors) { - builder.append(" " + content + "\n"); - } - } - } -} diff --git a/src/api/ApiErrorFactory.java b/src/api/ApiErrorFactory.java deleted file mode 100644 index 8a41d6ed..00000000 --- a/src/api/ApiErrorFactory.java +++ /dev/null @@ -1,200 +0,0 @@ -package api; - -import globalization.Translator; -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -public class ApiErrorFactory { - - private class ErrorMessageEntry { - - String templateKey; - String defaultTemplate; - AbstractMap.Entry[] templateValues; - - public ErrorMessageEntry(String templateKey, String defaultTemplate, AbstractMap.Entry... templateValues) { - this.templateKey = templateKey; - this.defaultTemplate = defaultTemplate; - this.templateValues = templateValues; - } - } - - private Translator translator; - private Map errorMessages; - - public ApiErrorFactory(Translator translator) { - this.translator = translator; - - this.errorMessages = new HashMap(); - - //COMMON - this.errorMessages.put(ApiError.UNKNOWN, createErrorMessageEntry(ApiError.UNKNOWN, "unknown error")); - this.errorMessages.put(ApiError.JSON, createErrorMessageEntry(ApiError.JSON, "failed to parse json message")); - this.errorMessages.put(ApiError.NO_BALANCE, createErrorMessageEntry(ApiError.NO_BALANCE, "not enough balance")); - this.errorMessages.put(ApiError.NOT_YET_RELEASED, createErrorMessageEntry(ApiError.NOT_YET_RELEASED, "that feature is not yet released")); - this.errorMessages.put(ApiError.UNAUTHORIZED, createErrorMessageEntry(ApiError.UNAUTHORIZED, "api call unauthorized")); - this.errorMessages.put(ApiError.REPOSITORY_ISSUE, createErrorMessageEntry(ApiError.REPOSITORY_ISSUE, "repository error")); - - //VALIDATION - this.errorMessages.put(ApiError.INVALID_SIGNATURE, createErrorMessageEntry(ApiError.INVALID_SIGNATURE, "invalid signature")); - this.errorMessages.put(ApiError.INVALID_ADDRESS, createErrorMessageEntry(ApiError.INVALID_ADDRESS, "invalid address")); - this.errorMessages.put(ApiError.INVALID_SEED, createErrorMessageEntry(ApiError.INVALID_SEED, "invalid seed")); - this.errorMessages.put(ApiError.INVALID_AMOUNT, createErrorMessageEntry(ApiError.INVALID_AMOUNT, "invalid amount")); - this.errorMessages.put(ApiError.INVALID_FEE, createErrorMessageEntry(ApiError.INVALID_FEE, "invalid fee")); - this.errorMessages.put(ApiError.INVALID_SENDER, createErrorMessageEntry(ApiError.INVALID_SENDER, "invalid sender")); - this.errorMessages.put(ApiError.INVALID_RECIPIENT, createErrorMessageEntry(ApiError.INVALID_RECIPIENT, "invalid recipient")); - this.errorMessages.put(ApiError.INVALID_NAME_LENGTH, createErrorMessageEntry(ApiError.INVALID_NAME_LENGTH, "invalid name length")); - this.errorMessages.put(ApiError.INVALID_VALUE_LENGTH, createErrorMessageEntry(ApiError.INVALID_VALUE_LENGTH, "invalid value length")); - this.errorMessages.put(ApiError.INVALID_NAME_OWNER, createErrorMessageEntry(ApiError.INVALID_NAME_OWNER, "invalid name owner")); - this.errorMessages.put(ApiError.INVALID_BUYER, createErrorMessageEntry(ApiError.INVALID_BUYER, "invalid buyer")); - this.errorMessages.put(ApiError.INVALID_PUBLIC_KEY, createErrorMessageEntry(ApiError.INVALID_PUBLIC_KEY, "invalid public key")); - this.errorMessages.put(ApiError.INVALID_OPTIONS_LENGTH, createErrorMessageEntry(ApiError.INVALID_OPTIONS_LENGTH, "invalid options length")); - this.errorMessages.put(ApiError.INVALID_OPTION_LENGTH, createErrorMessageEntry(ApiError.INVALID_OPTION_LENGTH, "invalid option length")); - this.errorMessages.put(ApiError.INVALID_DATA, createErrorMessageEntry(ApiError.INVALID_DATA, "invalid data")); - this.errorMessages.put(ApiError.INVALID_DATA_LENGTH, createErrorMessageEntry(ApiError.INVALID_DATA_LENGTH, "invalid data length")); - this.errorMessages.put(ApiError.INVALID_UPDATE_VALUE, createErrorMessageEntry(ApiError.INVALID_UPDATE_VALUE, "invalid update value")); - this.errorMessages.put(ApiError.KEY_ALREADY_EXISTS, createErrorMessageEntry(ApiError.KEY_ALREADY_EXISTS, "key already exists, edit is false")); - this.errorMessages.put(ApiError.KEY_NOT_EXISTS, createErrorMessageEntry(ApiError.KEY_NOT_EXISTS, "the key does not exist")); -// TODO -// this.errorMessages.put(ApiError.LAST_KEY_IS_DEFAULT_KEY_ERROR, createErrorMessageEntry(ApiError.LAST_KEY_IS_DEFAULT_KEY_ERROR, -// "you can't delete the key \"${key}\" if it is the only key", -// new AbstractMap.SimpleEntry("key", Qorakeys.DEFAULT.toString()))); - this.errorMessages.put(ApiError.FEE_LESS_REQUIRED, createErrorMessageEntry(ApiError.FEE_LESS_REQUIRED, "fee less required")); - this.errorMessages.put(ApiError.WALLET_NOT_IN_SYNC, createErrorMessageEntry(ApiError.WALLET_NOT_IN_SYNC, "wallet needs to be synchronized")); - this.errorMessages.put(ApiError.INVALID_NETWORK_ADDRESS, createErrorMessageEntry(ApiError.INVALID_NETWORK_ADDRESS, "invalid network address")); - this.errorMessages.put(ApiError.ADDRESS_NO_EXISTS, createErrorMessageEntry(ApiError.ADDRESS_NO_EXISTS, "account address does not exist")); - this.errorMessages.put(ApiError.INVALID_CRITERIA, createErrorMessageEntry(ApiError.INVALID_CRITERIA, "invalid search criteria")); - - //WALLET - this.errorMessages.put(ApiError.WALLET_NO_EXISTS, createErrorMessageEntry(ApiError.WALLET_NO_EXISTS, "wallet does not exist")); - this.errorMessages.put(ApiError.WALLET_ADDRESS_NO_EXISTS, createErrorMessageEntry(ApiError.WALLET_ADDRESS_NO_EXISTS, "address does not exist in wallet")); - this.errorMessages.put(ApiError.WALLET_LOCKED, createErrorMessageEntry(ApiError.WALLET_LOCKED, "wallet is locked")); - this.errorMessages.put(ApiError.WALLET_ALREADY_EXISTS, createErrorMessageEntry(ApiError.WALLET_ALREADY_EXISTS, "wallet already exists")); - this.errorMessages.put(ApiError.WALLET_API_CALL_FORBIDDEN_BY_USER, createErrorMessageEntry(ApiError.WALLET_API_CALL_FORBIDDEN_BY_USER, "wallet denied api call")); - - //BLOCK - this.errorMessages.put(ApiError.BLOCK_NO_EXISTS, createErrorMessageEntry(ApiError.BLOCK_NO_EXISTS, "block does not exist")); - - //TRANSACTIONS - this.errorMessages.put(ApiError.TRANSACTION_NO_EXISTS, createErrorMessageEntry(ApiError.TRANSACTION_NO_EXISTS, "transaction does not exist")); - this.errorMessages.put(ApiError.PUBLIC_KEY_NOT_FOUND, createErrorMessageEntry(ApiError.PUBLIC_KEY_NOT_FOUND, "public key not found")); - - //NAMING - this.errorMessages.put(ApiError.NAME_NO_EXISTS, createErrorMessageEntry(ApiError.NAME_NO_EXISTS, "name does not exist")); - this.errorMessages.put(ApiError.NAME_ALREADY_EXISTS, createErrorMessageEntry(ApiError.NAME_ALREADY_EXISTS, "name already exists")); - this.errorMessages.put(ApiError.NAME_ALREADY_FOR_SALE, createErrorMessageEntry(ApiError.NAME_ALREADY_FOR_SALE, "name already for sale")); - this.errorMessages.put(ApiError.NAME_NOT_LOWER_CASE, createErrorMessageEntry(ApiError.NAME_NOT_LOWER_CASE, "name must be lower case")); - this.errorMessages.put(ApiError.NAME_SALE_NO_EXISTS, createErrorMessageEntry(ApiError.NAME_SALE_NO_EXISTS, "namesale does not exist")); - this.errorMessages.put(ApiError.BUYER_ALREADY_OWNER, createErrorMessageEntry(ApiError.BUYER_ALREADY_OWNER, "buyer is already owner")); - - //POLLS - this.errorMessages.put(ApiError.POLL_NO_EXISTS, createErrorMessageEntry(ApiError.POLL_NO_EXISTS, "poll does not exist")); - this.errorMessages.put(ApiError.POLL_ALREADY_EXISTS, createErrorMessageEntry(ApiError.POLL_ALREADY_EXISTS, "poll already exists")); - this.errorMessages.put(ApiError.DUPLICATE_OPTION, createErrorMessageEntry(ApiError.DUPLICATE_OPTION, "not all options are unique")); - this.errorMessages.put(ApiError.POLL_OPTION_NO_EXISTS, createErrorMessageEntry(ApiError.POLL_OPTION_NO_EXISTS, "option does not exist")); - this.errorMessages.put(ApiError.ALREADY_VOTED_FOR_THAT_OPTION, createErrorMessageEntry(ApiError.ALREADY_VOTED_FOR_THAT_OPTION, "already voted for that option")); - - //ASSETS - this.errorMessages.put(ApiError.INVALID_ASSET_ID, createErrorMessageEntry(ApiError.INVALID_ASSET_ID, "invalid asset id")); - - //NAME PAYMENTS -// TODO -// this.errorMessages.put(ApiError.NAME_NOT_REGISTERED, createErrorMessageEntry(ApiError.NAME_NOT_REGISTERED, NameResult.NAME_NOT_REGISTERED.getStatusMessage())); -// this.errorMessages.put(ApiError.NAME_FOR_SALE, createErrorMessageEntry(ApiError.NAME_FOR_SALE, NameResult.NAME_FOR_SALE.getStatusMessage())); -// this.errorMessages.put(ApiError.NAME_WITH_SPACE, createErrorMessageEntry(ApiError.NAME_WITH_SPACE, NameResult.NAME_WITH_SPACE.getStatusMessage())); - //AT -// TODO -// this.errorMessages.put(ApiError.INVALID_DESC_LENGTH, createErrorMessageEntry(ApiError.INVALID_DESC_LENGTH, -// "invalid description length. max length ${MAX_LENGTH}", -// new AbstractMap.SimpleEntry("MAX_LENGTH", AT_Constants.DESC_MAX_LENGTH)); - this.errorMessages.put(ApiError.EMPTY_CODE, createErrorMessageEntry(ApiError.EMPTY_CODE, "code is empty")); - this.errorMessages.put(ApiError.DATA_SIZE, createErrorMessageEntry(ApiError.DATA_SIZE, "invalid data length")); - this.errorMessages.put(ApiError.NULL_PAGES, createErrorMessageEntry(ApiError.NULL_PAGES, "invalid pages")); - this.errorMessages.put(ApiError.INVALID_TYPE_LENGTH, createErrorMessageEntry(ApiError.INVALID_TYPE_LENGTH, "invalid type length")); - this.errorMessages.put(ApiError.INVALID_TAGS_LENGTH, createErrorMessageEntry(ApiError.INVALID_TAGS_LENGTH, "invalid tags length")); - this.errorMessages.put(ApiError.INVALID_CREATION_BYTES, createErrorMessageEntry(ApiError.INVALID_CREATION_BYTES, "error in creation bytes")); - - //BLOG - this.errorMessages.put(ApiError.BODY_EMPTY, createErrorMessageEntry(ApiError.BODY_EMPTY, "invalid body it must not be empty")); - this.errorMessages.put(ApiError.BLOG_DISABLED, createErrorMessageEntry(ApiError.BLOG_DISABLED, "this blog is disabled")); - this.errorMessages.put(ApiError.NAME_NOT_OWNER, createErrorMessageEntry(ApiError.NAME_NOT_OWNER, "the creator address does not own the author name")); -// this.errorMessages.put(ApiError.TX_AMOUNT, createErrorMessageEntry(ApiError.TX_AMOUNT, -// "the data size is too large - currently only ${BATCH_TX_AMOUNT} arbitrary transactions are allowed at once!", -// new AbstractMap.SimpleEntry("BATCH_TX_AMOUNT", BATCH_TX_AMOUNT))); - this.errorMessages.put(ApiError.BLOG_ENTRY_NO_EXISTS, createErrorMessageEntry(ApiError.BLOG_ENTRY_NO_EXISTS, "transaction with this signature contains no entries!")); - this.errorMessages.put(ApiError.BLOG_EMPTY, createErrorMessageEntry(ApiError.BLOG_EMPTY, "this blog is empty")); - this.errorMessages.put(ApiError.POSTID_EMPTY, createErrorMessageEntry(ApiError.POSTID_EMPTY, "the attribute postid is empty! this is the signature of the post you want to comment")); - this.errorMessages.put(ApiError.POST_NOT_EXISTING, createErrorMessageEntry(ApiError.POST_NOT_EXISTING, "for the given postid no blogpost to comment was found")); - this.errorMessages.put(ApiError.COMMENTING_DISABLED, createErrorMessageEntry(ApiError.COMMENTING_DISABLED, "commenting is for this blog disabled")); - this.errorMessages.put(ApiError.COMMENT_NOT_EXISTING, createErrorMessageEntry(ApiError.COMMENT_NOT_EXISTING, "for the given signature no comment was found")); - this.errorMessages.put(ApiError.INVALID_COMMENT_OWNER, createErrorMessageEntry(ApiError.INVALID_COMMENT_OWNER, "invalid comment owner")); - - //MESSAGES - this.errorMessages.put(ApiError.MESSAGE_FORMAT_NOT_HEX, createErrorMessageEntry(ApiError.MESSAGE_FORMAT_NOT_HEX, "the Message format is not hex - correct the text or use isTextMessage = true")); - this.errorMessages.put(ApiError.MESSAGE_BLANK, createErrorMessageEntry(ApiError.MESSAGE_BLANK, "The message attribute is missing or content is blank")); - this.errorMessages.put(ApiError.NO_PUBLIC_KEY, createErrorMessageEntry(ApiError.NO_PUBLIC_KEY, "The recipient has not yet performed any action in the blockchain.\nYou can't send an encrypted message to them.")); - this.errorMessages.put(ApiError.MESSAGESIZE_EXCEEDED, createErrorMessageEntry(ApiError.MESSAGESIZE_EXCEEDED, "Message size exceeded!")); - - } - - //XXX: replace singleton pattern by dependency injection? - private static ApiErrorFactory instance; - - public static ApiErrorFactory getInstance() { - if (instance == null) { - instance = new ApiErrorFactory(Translator.getInstance()); - } - - return instance; - } - - private ErrorMessageEntry createErrorMessageEntry(ApiError errorCode, String defaultTemplate, AbstractMap.SimpleEntry... templateValues) { - String templateKey = String.format(Constants.APIERROR_KEY, errorCode.name()); - return new ErrorMessageEntry(templateKey, defaultTemplate, templateValues); - } - - public String getErrorMessage(ApiError error) { - return getErrorMessage(null, error); - } - - public String getErrorMessage(Locale locale, ApiError error) { - ErrorMessageEntry errorMessage = this.errorMessages.get(error); - String message = this.translator.translate(locale, Constants.APIERROR_CONTEXT_PATH, errorMessage.templateKey, errorMessage.defaultTemplate, errorMessage.templateValues); - return message; - } - - public ApiException createError(ApiError error) { - return createError(error, null); - } - - public ApiException createError(Locale locale, ApiError error) { - return createError(locale, error, null); - } - - public ApiException createError(ApiError error, Throwable throwable) { - return createError(null, error, throwable); - } - - public ApiException createError(Locale locale, ApiError error, Throwable throwable) { - // TODO: handle AT errors -// old AT error handling -// JSONObject jsonObject = new JSONObject(); -// jsonObject.put("error", error); -// if ( error > Transaction.AT_ERROR ) -// { -// jsonObject.put("message", AT_Error.getATError(error - Transaction.AT_ERROR) ); -// } -// else -// { -// jsonObject.put("message", this.errorMessages.get(error)); -// } -// -// -// return new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(jsonObject.toJSONString()).build()); - - String message = getErrorMessage(locale, error); - return new ApiException(error.getStatus(), error.getCode(), message, throwable); - } -} diff --git a/src/api/BlockExplorerResource.java b/src/api/BlockExplorerResource.java deleted file mode 100644 index 6944ced0..00000000 --- a/src/api/BlockExplorerResource.java +++ /dev/null @@ -1,35 +0,0 @@ -package api; - -import java.io.IOException; -import java.nio.file.FileSystems; -import java.nio.file.Files; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.core.Context; - -import io.swagger.v3.oas.annotations.Operation; - -@Path("/") -public class BlockExplorerResource { - - @Context - HttpServletRequest request; - - public BlockExplorerResource() { - } - - @GET - @Path("/block-explorer.html") - @Operation(hidden = true) - public String getBlockExplorer() { - try { - byte[] htmlBytes = Files.readAllBytes(FileSystems.getDefault().getPath("block-explorer.html")); - return new String(htmlBytes, "UTF-8"); - } catch (IOException e) { - return "block-explorer.html not found"; - } - } - -} diff --git a/src/globalization/BIP39WordList.java b/src/globalization/BIP39WordList.java deleted file mode 100644 index 1779dbd4..00000000 --- a/src/globalization/BIP39WordList.java +++ /dev/null @@ -1,55 +0,0 @@ -package globalization; - -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.nio.file.Files; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import settings.Settings; - -/** Providing multi-language BIP39 word lists, downloaded from https://github.com/bitcoin/bips/tree/master/bip-0039 */ -public class BIP39WordList { - - private static BIP39WordList instance; - - private static Map> wordListsByLang; - - private BIP39WordList() { - wordListsByLang = new HashMap<>(); - - String path = Settings.getInstance().translationsPath(); - File dir = new File(path); - File[] files = dir.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.startsWith("BIP39."); - } - }); - - try { - for (File file : files) { - String lang = file.getName().substring(6, 8); - List words = Files.readAllLines(file.toPath()); - wordListsByLang.put(lang, words); - } - } catch (IOException e) { - throw new RuntimeException("Unable to read BIP39 word list", e); - } - } - - public static synchronized BIP39WordList getInstance() { - if (instance == null) - instance = new BIP39WordList(); - - return instance; - } - - public List getByLang(String lang) { - return Collections.unmodifiableList(wordListsByLang.get(lang)); - } - -} diff --git a/src/globalization/ContextPaths.java b/src/globalization/ContextPaths.java deleted file mode 100644 index 8743d438..00000000 --- a/src/globalization/ContextPaths.java +++ /dev/null @@ -1,33 +0,0 @@ -package globalization; - -import java.nio.file.Paths; - -public class ContextPaths { - - public static boolean isValidKey(String value) { - return !value.contains("/") && !ContextPaths.containsParentReference(value); - } - - public static boolean containsParentReference(String value) { - for(String part : value.split("/")) { - if(part.equalsIgnoreCase("..")) - return true; - } - return false; - } - - public static String combinePaths(String left, String right) { - left = (left != null) ? left : ""; - right = (right != null) ? right : ""; - return Paths.get("/", left, right).normalize().toString(); - } - - public static String getParent(String path) { - return combinePaths(path, ".."); - } - - public static boolean isRoot(String path) { - return path.equals("/"); - } - -} diff --git a/src/globalization/TranslationEntry.java b/src/globalization/TranslationEntry.java deleted file mode 100644 index 91a5114d..00000000 --- a/src/globalization/TranslationEntry.java +++ /dev/null @@ -1,32 +0,0 @@ -package globalization; - -import java.util.Locale; - -public class TranslationEntry { - private Locale locale; - private String path; - private String template; - - public TranslationEntry(Locale locale, String path, String template) { - this.locale = locale; - this.path = path; - this.template = template; - } - - public Locale locale() { - return this.locale; - } - - public String path() { - return this.path; - } - - public String template() { - return this.template; - } - - @Override - public String toString() { - return String.format("{locale: '%s', path: '%s', template: '%s'}", this.locale, this.path, this.template); - } -} diff --git a/src/globalization/TranslationXmlStreamReader.java b/src/globalization/TranslationXmlStreamReader.java deleted file mode 100644 index 1712a9f6..00000000 --- a/src/globalization/TranslationXmlStreamReader.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package globalization; - -import java.io.InputStream; -import java.nio.file.Paths; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import javax.xml.namespace.QName; - -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.*; -import org.apache.commons.text.StringEscapeUtils; - -public class TranslationXmlStreamReader { - - private class State { - - public final Locale locale; - public final String path; - - public State(Locale locale, String path) { - this.locale = locale; - this.path = path; - } - } - - private static final String LOCALIZATION_TAG_NAME = "localization"; - - private static final String CONTEXT_TAG_NAME = "context"; - private static final String CONTEXT_LOCALE_ATTRIBUTE_NAME = "locale"; - private static final String CONTEXT_PATH_ATTRIBUTE_NAME = "path"; - - private static final String TRANSLATION_TAG_NAME = "translation"; - private static final String TRANSLATION_KEY_ATTRIBUTE_NAME = "key"; - private static final String TRANSLATION_TEMPLATE_ATTRIBUTE_NAME = "template"; - - public Iterable ReadFrom(InputStream stream) throws XMLStreamException { - XMLInputFactory inputFactory = XMLInputFactory.newInstance(); - XMLEventReader eventReader = inputFactory.createXMLEventReader(stream); - - XMLEvent element = eventReader.nextEvent(); - if(!element.isStartDocument()) - throw new javax.xml.stream.XMLStreamException("XML declaration must be first in the document"); - - State state = new State(Locale.forLanguageTag("default"), "/"); - - List result = new ArrayList<>(); - if (eventReader.hasNext()) - { - XMLEvent event = eventReader.nextTag(); - if (isStartElement(event, LOCALIZATION_TAG_NAME)) - { - processLocalization(eventReader, (StartElement)event, state, result); - } else { - throw new javax.xml.stream.XMLStreamException("Unexpected element: " + event.toString()); - } - } - - while (eventReader.hasNext()) - { - XMLEvent event = eventReader.nextEvent(); - switch(event.getEventType()) { - case XMLEvent.COMMENT: - break; - case XMLEvent.CHARACTERS: - if(!event.asCharacters().isIgnorableWhiteSpace()) - throw new javax.xml.stream.XMLStreamException("Unexpected content after end of root element: " + event.toString()); - break; - case XMLEvent.END_DOCUMENT: - return result; - default: - throw new javax.xml.stream.XMLStreamException("Unexpected content after end of root element: " + event.toString()); - } - } - - throw new javax.xml.stream.XMLStreamException("End of document not found"); - } - - private void processLocalization(XMLEventReader eventReader, StartElement element, State state, List result) throws XMLStreamException { - assureStartElement(element, LOCALIZATION_TAG_NAME); - - Iterator attributes = element.getAttributes(); - while (attributes.hasNext()) - { - Attribute attribute = attributes.next(); - QName name = attribute.getName(); - throw new javax.xml.stream.XMLStreamException("Unexpected attribute: " + name); - } - - XMLEvent event; - while(!(event = eventReader.nextTag()).isEndElement()) { - if(event.isStartElement()) { - StartElement childElement = (StartElement)event; - switch(childElement.getName().toString()) { - case CONTEXT_TAG_NAME: - processContext(eventReader, childElement, state, result); - break; - case TRANSLATION_TAG_NAME: - processTranslation(eventReader, childElement, state, result); - break; - default: - throw new javax.xml.stream.XMLStreamException("Unexpected element: " + event.toString()); - } - } else { - throw new javax.xml.stream.XMLStreamException("Unexpected content: " + event.toString()); - } - } - assureEndElement(event, LOCALIZATION_TAG_NAME); - } - - private void processContext(XMLEventReader eventReader, StartElement element, State state, List result) throws XMLStreamException { - assureStartElement(element, CONTEXT_TAG_NAME); - - Locale locale = state.locale; - String contextPath = state.path; - - Iterator attributes = element.getAttributes(); - while (attributes.hasNext()) - { - Attribute attribute = attributes.next(); - QName name = attribute.getName(); - String value = attribute.getValue(); - switch(name.toString()) { - case CONTEXT_LOCALE_ATTRIBUTE_NAME: - locale = Locale.forLanguageTag(value); - break; - case CONTEXT_PATH_ATTRIBUTE_NAME: - assureIsValidPathExtension(value); - contextPath = ContextPaths.combinePaths(contextPath, value); - break; - default: - throw new javax.xml.stream.XMLStreamException("Unexpected attribute: " + name); - } - } - - state = new State(locale, contextPath); - - XMLEvent event; - while(!(event = eventReader.nextTag()).isEndElement()) { - if(event.isStartElement()) { - StartElement childElement = (StartElement)event; - switch(childElement.getName().toString()) { - case CONTEXT_TAG_NAME: - processContext(eventReader, childElement, state, result); - break; - case TRANSLATION_TAG_NAME: - processTranslation(eventReader, childElement, state, result); - break; - default: - throw new javax.xml.stream.XMLStreamException("Unexpected element: " + event.toString()); - } - } else { - throw new javax.xml.stream.XMLStreamException("Unexpected content: " + event.toString()); - } - } - assureEndElement(event, CONTEXT_TAG_NAME); - } - - - private void processTranslation(XMLEventReader eventReader, StartElement element, State state, List result) throws XMLStreamException { - assureStartElement(element, TRANSLATION_TAG_NAME); - - String path = null; - String template = null; - - Iterator attributes = element.getAttributes(); - while (attributes.hasNext()) - { - Attribute attribute = attributes.next(); - QName name = attribute.getName(); - String value = attribute.getValue(); - switch(name.toString()) { - case TRANSLATION_KEY_ATTRIBUTE_NAME: - assureIsValidKey(value); - path = ContextPaths.combinePaths(state.path, value); - break; - case TRANSLATION_TEMPLATE_ATTRIBUTE_NAME: - template = unescape(value); - break; - default: - throw new javax.xml.stream.XMLStreamException("Unexpected attribute: " + name); - } - } - - XMLEvent event; - while(!(event = eventReader.nextTag()).isEndElement()) { - if(event.isStartElement()) { - throw new javax.xml.stream.XMLStreamException("Unexpected element: " + event.toString()); - } else if(event.isCharacters()) { - if(template != null) - throw new javax.xml.stream.XMLStreamException("Content must be empty if 'template' attribute is used"); - template = event.asCharacters().getData(); - } - } - assureEndElement(event, TRANSLATION_TAG_NAME); - - if(path == null) - throw new javax.xml.stream.XMLStreamException("Missing attribute: " + TRANSLATION_KEY_ATTRIBUTE_NAME); - - if(template == null) - throw new javax.xml.stream.XMLStreamException("Missing attribute: " + TRANSLATION_TEMPLATE_ATTRIBUTE_NAME); - - result.add(new TranslationEntry(state.locale, path, template)); - } - - private String unescape(String value) { - return StringEscapeUtils.unescapeJava(value); - } - - private void assureIsValidPathExtension(String value) throws XMLStreamException { - if(ContextPaths.containsParentReference(value)) - throw new javax.xml.stream.XMLStreamException("Parent reference .. is not allowed"); - } - - private void assureIsValidKey(String value) throws XMLStreamException { - if(!ContextPaths.isValidKey(value)) - throw new javax.xml.stream.XMLStreamException("Key is not valid"); - } - - private void assureStartElement(XMLEvent event, String name) throws XMLStreamException { - if(!isStartElement(event, name)) - throw new javax.xml.stream.XMLStreamException("Unexpected start element: " + event.toString() + ", <" + name + "> expected"); - } - - private void assureEndElement(XMLEvent event, String name) throws XMLStreamException { - if(!isEndElement(event, name)) - throw new javax.xml.stream.XMLStreamException("Unexpected end element: " + event.toString() + ", expected"); - } - - private boolean isStartElement(XMLEvent event, String name) { - if(!event.isStartElement()) - return false; - StartElement element = ((StartElement)event); - return element.getName().toString().equals(name); - } - - private boolean isEndElement(XMLEvent event, String name) { - if(!event.isEndElement()) - return false; - EndElement element = ((EndElement)event); - return element.getName().toString().equals(name); - } -} diff --git a/src/globalization/Translations.xsd b/src/globalization/Translations.xsd deleted file mode 100644 index aff8ab76..00000000 --- a/src/globalization/Translations.xsd +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/globalization/Translator.java b/src/globalization/Translator.java deleted file mode 100644 index c6c4569d..00000000 --- a/src/globalization/Translator.java +++ /dev/null @@ -1,176 +0,0 @@ -package globalization; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FilenameFilter; -import java.io.InputStream; -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.xml.stream.XMLStreamException; -import org.apache.commons.text.StringSubstitutor; - -import settings.Settings; - -public class Translator { - - Map> translations = new HashMap>(); - - //XXX: replace singleton pattern by dependency injection? - private static Translator instance; - - private Translator() { - InitializeTranslations(); - } - - public static Translator getInstance() { - if (instance == null) { - instance = new Translator(); - } - - return instance; - } - - private Settings settings() { - return Settings.getInstance(); - } - - private void InitializeTranslations() { - String path = this.settings().translationsPath(); - File dir = new File(path); - File [] files = dir.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".xml"); - } - }); - - Map> translations = new HashMap<>(); - TranslationXmlStreamReader translationReader = new TranslationXmlStreamReader(); - for (File file : files) { - Iterable entries = null; - try { - InputStream stream = new FileInputStream(file); - entries = translationReader.ReadFrom(stream); - } catch (FileNotFoundException ex) { - Logger.getLogger(Translator.class.getName()).log(Level.SEVERE, String.format("Translation file not found: %s", file), ex); - } catch (XMLStreamException ex) { - Logger.getLogger(Translator.class.getName()).log(Level.SEVERE, String.format("Error in translation file: %s", file), ex); - } - - for(TranslationEntry entry : entries) { - Map localTranslations = translations.get(entry.locale()); - if(localTranslations == null) { - localTranslations = new HashMap<>(); - translations.put(entry.locale(), localTranslations); - } - - if(localTranslations.containsKey(entry.path())) { - Logger.getLogger(Translator.class.getName()).log(Level.SEVERE, String.format("Duplicate entry for locale '%s' and path '%s' in translation file '%s'. Falling back to default translations.", entry.locale(), entry.path(), file)); - return; - } - localTranslations.put(entry.path(), entry.template()); - } - } - - // everything is fine, so we store all read translations - this.translations = translations; - } - - private Map createMap(Map.Entry[] entries) { - HashMap map = new HashMap<>(); - for (AbstractMap.Entry entry : entries) { - map.put(entry.getKey(), entry.getValue()); - } - return map; - } - - public String translate(Locale locale, String contextPath, String keyPath, AbstractMap.Entry... templateValues) { - Map map = createMap(templateValues); - return translate(locale, contextPath, keyPath, map); - } - - public String translate(String contextPath, String keyPath, AbstractMap.Entry... templateValues) { - Map map = createMap(templateValues); - return translate(contextPath, keyPath, map); - } - - public String translate(Locale locale, String contextPath, String keyPath, Map templateValues) { - return translate(locale, contextPath, keyPath, null, templateValues); - } - - public String translate(String contextPath, String keyPath, Map templateValues) { - return translate(contextPath, keyPath, null, templateValues); - } - - public String translate(Locale locale, String contextPath, String keyPath, String defaultTemplate, AbstractMap.Entry... templateValues) { - Map map = createMap(templateValues); - return translate(locale, contextPath, keyPath, defaultTemplate, map); - } - - public String translate(String contextPath, String keyPath, String defaultTemplate, AbstractMap.Entry... templateValues) { - Map map = createMap(templateValues); - return translate(contextPath, keyPath, defaultTemplate, map); - } - - public String translate(Locale locale, String contextPath, String keyPath, String defaultTemplate, Map templateValues) { - // look for requested language - String template = null; - if(locale != null) - template = getTemplateFromNearestPath(locale, contextPath, keyPath); - - if(template != null) - return substitute(template, templateValues); - - return translate(contextPath, keyPath, defaultTemplate, templateValues); - } - - public String translate(String contextPath, String keyPath, String defaultTemplate, Map templateValues) { - // scan default languages - String template = null; - for(String language : this.settings().translationsDefaultLocales()) { - Locale defaultLocale = Locale.forLanguageTag(language); - template = getTemplateFromNearestPath(defaultLocale, contextPath, keyPath); - if(template != null) - break; - } - - if(template == null) - template = defaultTemplate; // fallback template - - return substitute(template, templateValues); - } - - private String substitute(String template, Map templateValues) { - if(templateValues == null) - return template; - - StringSubstitutor sub = new StringSubstitutor(templateValues); - String result = sub.replace(template); - - return result; - } - - private String getTemplateFromNearestPath(Locale locale, String contextPath, String keyPath) { - Map localTranslations = this.translations.get(locale); - if(localTranslations == null) - return null; - - String template = null; - while(true) { - String path = ContextPaths.combinePaths(contextPath, keyPath); - template = localTranslations.get(path); - if(template != null) - break; // found template - if(ContextPaths.isRoot(contextPath)) - break; // nothing found - contextPath = ContextPaths.getParent(contextPath); - } - - return template; - } -} diff --git a/src/api/ApiError.java b/src/main/java/api/ApiError.java similarity index 83% rename from src/api/ApiError.java rename to src/main/java/api/ApiError.java index 93c087c3..73b19c2a 100644 --- a/src/api/ApiError.java +++ b/src/main/java/api/ApiError.java @@ -1,7 +1,12 @@ package api; +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.toMap; + +import java.util.Map; + public enum ApiError { - //COMMON + // COMMON UNKNOWN(0, 500), JSON(1, 400), NO_BALANCE(2, 422), @@ -9,7 +14,7 @@ public enum ApiError { UNAUTHORIZED(4, 403), REPOSITORY_ISSUE(5, 500), - //VALIDATION + // VALIDATION INVALID_SIGNATURE(101, 400), INVALID_ADDRESS(102, 400), INVALID_SEED(103, 400), @@ -36,22 +41,24 @@ public enum ApiError { ADDRESS_NO_EXISTS(124, 404), INVALID_CRITERIA(125, 400), INVALID_REFERENCE(126, 400), + TRANSFORMATION_ERROR(127, 400), - //WALLET + // WALLET WALLET_NO_EXISTS(201, 404), WALLET_ADDRESS_NO_EXISTS(202, 404), WALLET_LOCKED(203, 422), WALLET_ALREADY_EXISTS(204, 422), WALLET_API_CALL_FORBIDDEN_BY_USER(205, 403), - //BLOCKS + // BLOCKS BLOCK_NO_EXISTS(301, 404), - //TRANSACTIONS + // TRANSACTIONS TRANSACTION_NO_EXISTS(311, 404), PUBLIC_KEY_NOT_FOUND(304, 404), + TRANSACTION_INVALID(312, 400), - //NAMING + // NAMING NAME_NO_EXISTS(401, 404), NAME_ALREADY_EXISTS(402, 422), NAME_ALREADY_FOR_SALE(403, 422), @@ -59,24 +66,24 @@ public enum ApiError { NAME_SALE_NO_EXISTS(410, 404), BUYER_ALREADY_OWNER(411, 422), - //POLLS + // POLLS POLL_NO_EXISTS(501, 404), POLL_ALREADY_EXISTS(502, 422), DUPLICATE_OPTION(503, 422), POLL_OPTION_NO_EXISTS(504, 404), ALREADY_VOTED_FOR_THAT_OPTION(505, 422), - //ASSET + // ASSET INVALID_ASSET_ID(601, 400), INVALID_ORDER_ID(602, 400), ORDER_NO_EXISTS(603, 404), - //NAME PAYMENTS + // NAME PAYMENTS NAME_NOT_REGISTERED(701, 422), NAME_FOR_SALE(702, 422), NAME_WITH_SPACE(703, 422), - //ATs + // ATs INVALID_DESC_LENGTH(801, 400), EMPTY_CODE(802, 400), DATA_SIZE(803, 400), @@ -85,7 +92,7 @@ public enum ApiError { INVALID_TAGS_LENGTH(806, 400), INVALID_CREATION_BYTES(809, 400), - //BLOG/Namestorage + // BLOG/Namestorage BODY_EMPTY(901, 400), BLOG_DISABLED(902, 403), NAME_NOT_OWNER(903, 422), @@ -98,12 +105,14 @@ public enum ApiError { COMMENT_NOT_EXISTING(910, 404), INVALID_COMMENT_OWNER(911, 422), - //Messages + // Messages MESSAGE_FORMAT_NOT_HEX(1001, 400), MESSAGE_BLANK(1002, 400), NO_PUBLIC_KEY(1003, 422), MESSAGESIZE_EXCEEDED(1004, 400); + private final static Map map = stream(ApiError.values()).collect(toMap(apiError -> apiError.code, apiError -> apiError)); + private final int code; // API error code private final int status; // HTTP status code @@ -117,20 +126,15 @@ public enum ApiError { } public static ApiError fromCode(int code) { - for(ApiError apiError : ApiError.values()) { - if(apiError.code == code) - return apiError; - } - - return null; + return map.get(code); } - - int getCode() { + + public int getCode() { return this.code; } - int getStatus() { + public int getStatus() { return this.status; } - + } \ No newline at end of file diff --git a/src/api/ApiErrorMessage.java b/src/main/java/api/ApiErrorMessage.java similarity index 68% rename from src/api/ApiErrorMessage.java rename to src/main/java/api/ApiErrorMessage.java index 161e1836..580bb9fa 100644 --- a/src/api/ApiErrorMessage.java +++ b/src/main/java/api/ApiErrorMessage.java @@ -7,15 +7,16 @@ import javax.xml.bind.annotation.XmlAccessorType; @XmlAccessorType(XmlAccessType.FIELD) public class ApiErrorMessage { - public int error; + protected int error; - public String message; + protected String message; - ApiErrorMessage() { + protected ApiErrorMessage() { } - ApiErrorMessage(int errorCode, String message) { + public ApiErrorMessage(int errorCode, String message) { this.error = errorCode; this.message = message; } + } diff --git a/src/main/java/api/ApiErrors.java b/src/main/java/api/ApiErrors.java new file mode 100644 index 00000000..53728601 --- /dev/null +++ b/src/main/java/api/ApiErrors.java @@ -0,0 +1,18 @@ +package api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation lists potential ApiErrors that may be returned, or thrown, during the execution of this method. + *

+ * Value is expected to be an array of ApiError enum instances. + * + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ApiErrors { + ApiError[] value() default {}; +} diff --git a/src/api/ApiException.java b/src/main/java/api/ApiException.java similarity index 84% rename from src/api/ApiException.java rename to src/main/java/api/ApiException.java index b8419cc7..99e38a61 100644 --- a/src/api/ApiException.java +++ b/src/main/java/api/ApiException.java @@ -6,14 +6,16 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; public class ApiException extends WebApplicationException { - // HTTP status code - int status; + private static final long serialVersionUID = 4619299036312089050L; + + // HTTP status code + public int status; // API error code - int error; + public int error; - String message; + public String message; public ApiException(int status, int error, String message) { this(status, error, message, null); diff --git a/src/main/java/api/ApiExceptionFactory.java b/src/main/java/api/ApiExceptionFactory.java new file mode 100644 index 00000000..d5156148 --- /dev/null +++ b/src/main/java/api/ApiExceptionFactory.java @@ -0,0 +1,20 @@ +package api; + +import javax.servlet.http.HttpServletRequest; + +import globalization.Translator; + +public enum ApiExceptionFactory { + INSTANCE; + + public ApiException createException(HttpServletRequest request, ApiError apiError, Throwable throwable, Object... args) { + String template = Translator.INSTANCE.translate("ApiError", request.getLocale().getLanguage(), apiError.name()); + String message = String.format(template, args); + return new ApiException(apiError.getStatus(), apiError.getCode(), message, throwable); + } + + public ApiException createException(HttpServletRequest request, ApiError apiError) { + return createException(request, apiError, null); + } + +} diff --git a/src/api/ApiService.java b/src/main/java/api/ApiService.java similarity index 76% rename from src/api/ApiService.java rename to src/main/java/api/ApiService.java index 05c9788d..b2aed2d4 100644 --- a/src/api/ApiService.java +++ b/src/main/java/api/ApiService.java @@ -2,8 +2,6 @@ package api; import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource; -import java.util.HashSet; -import java.util.Set; import org.eclipse.jetty.rewrite.handler.RedirectPatternRule; import org.eclipse.jetty.rewrite.handler.RewriteHandler; @@ -17,30 +15,21 @@ import org.eclipse.jetty.servlets.CrossOriginFilter; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; +import api.resource.AnnotationPostProcessor; +import api.resource.ApiDefinition; import settings.Settings; public class ApiService { private final Server server; - private final Set> resources; + private final ResourceConfig config; public ApiService() { - // Resources to register - this.resources = new HashSet>(); - this.resources.add(AddressesResource.class); - this.resources.add(AdminResource.class); - this.resources.add(AssetsResource.class); - this.resources.add(BlocksResource.class); - this.resources.add(NamesResource.class); - this.resources.add(PaymentsResource.class); - this.resources.add(TransactionsResource.class); - this.resources.add(UtilsResource.class); - - this.resources.add(BlockExplorerResource.class); // block-explorer.html - this.resources.add(OpenApiResource.class); // Swagger/OpenAPI - this.resources.add(ApiDefinition.class); // API info - this.resources.add(AnnotationPostProcessor.class); // For API resource annotations - ResourceConfig config = new ResourceConfig(this.resources); + config = new ResourceConfig(); + config.packages("api.resource"); + config.register(OpenApiResource.class); + config.register(ApiDefinition.class); + config.register(AnnotationPostProcessor.class); // Create RPC server this.server = new Server(Settings.getInstance().getRpcPort()); @@ -94,8 +83,9 @@ public class ApiService { return instance; } - Iterable> getResources() { - return resources; + public Iterable> getResources() { + // return resources; + return config.getClasses(); } public void start() { diff --git a/src/api/Base58TypeAdapter.java b/src/main/java/api/Base58TypeAdapter.java similarity index 100% rename from src/api/Base58TypeAdapter.java rename to src/main/java/api/Base58TypeAdapter.java diff --git a/src/api/BigDecimalTypeAdapter.java b/src/main/java/api/BigDecimalTypeAdapter.java similarity index 100% rename from src/api/BigDecimalTypeAdapter.java rename to src/main/java/api/BigDecimalTypeAdapter.java diff --git a/src/api/Constants.java b/src/main/java/api/Constants.java similarity index 100% rename from src/api/Constants.java rename to src/main/java/api/Constants.java diff --git a/src/api/Security.java b/src/main/java/api/Security.java similarity index 72% rename from src/api/Security.java rename to src/main/java/api/Security.java index 2d981b2c..43463428 100644 --- a/src/api/Security.java +++ b/src/main/java/api/Security.java @@ -13,10 +13,10 @@ public class Security { try { remoteAddr = InetAddress.getByName(request.getRemoteAddr()); } catch (UnknownHostException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.UNAUTHORIZED); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.UNAUTHORIZED); } if (!remoteAddr.isLoopbackAddress()) - throw ApiErrorFactory.getInstance().createError(ApiError.UNAUTHORIZED); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.UNAUTHORIZED); } } diff --git a/src/api/TransactionClassExtractor.java b/src/main/java/api/TransactionClassExtractor.java similarity index 100% rename from src/api/TransactionClassExtractor.java rename to src/main/java/api/TransactionClassExtractor.java diff --git a/src/api/TranslatableProperty.java b/src/main/java/api/TranslatableProperty.java similarity index 100% rename from src/api/TranslatableProperty.java rename to src/main/java/api/TranslatableProperty.java diff --git a/src/api/models/AssetWithHolders.java b/src/main/java/api/models/AssetWithHolders.java similarity index 100% rename from src/api/models/AssetWithHolders.java rename to src/main/java/api/models/AssetWithHolders.java diff --git a/src/api/models/BlockWithTransactions.java b/src/main/java/api/models/BlockWithTransactions.java similarity index 100% rename from src/api/models/BlockWithTransactions.java rename to src/main/java/api/models/BlockWithTransactions.java diff --git a/src/api/models/OrderWithTrades.java b/src/main/java/api/models/OrderWithTrades.java similarity index 100% rename from src/api/models/OrderWithTrades.java rename to src/main/java/api/models/OrderWithTrades.java diff --git a/src/api/models/SimpleTransactionSignRequest.java b/src/main/java/api/models/SimpleTransactionSignRequest.java similarity index 100% rename from src/api/models/SimpleTransactionSignRequest.java rename to src/main/java/api/models/SimpleTransactionSignRequest.java diff --git a/src/api/models/TradeWithOrderInfo.java b/src/main/java/api/models/TradeWithOrderInfo.java similarity index 100% rename from src/api/models/TradeWithOrderInfo.java rename to src/main/java/api/models/TradeWithOrderInfo.java diff --git a/src/api/AddressesResource.java b/src/main/java/api/resource/AddressesResource.java similarity index 53% rename from src/api/AddressesResource.java rename to src/main/java/api/resource/AddressesResource.java index f3dd6454..cfc0a4d1 100644 --- a/src/api/AddressesResource.java +++ b/src/main/java/api/resource/AddressesResource.java @@ -1,9 +1,7 @@ -package api; +package api.resource; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.extensions.Extension; -import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; @@ -21,6 +19,10 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import api.ApiError; +import api.ApiErrors; +import api.ApiException; +import api.ApiExceptionFactory; import data.account.AccountBalanceData; import data.account.AccountData; import qora.account.Account; @@ -32,12 +34,8 @@ import repository.RepositoryManager; import transform.Transformer; import utils.Base58; -@Path("addresses") +@Path("/addresses") @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) -@Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="/Api/AddressesResource") - } -) @Tag(name = "Addresses") public class AddressesResource { @@ -49,30 +47,17 @@ public class AddressesResource { @Operation( summary = "Fetch reference for next transaction to be created by address", description = "Returns the base58-encoded signature of the last confirmed transaction created by address, failing that: the first incoming transaction to address. Returns \"false\" if there is no transactions.", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="GET lastreference:address"), - @ExtensionProperty(name="description.key", value="operation:description") - }), - @Extension(properties = { - @ExtensionProperty(name="apiErrors", value="[\"INVALID_ADDRESS\"]", parseValue = true), - }) - }, responses = { @ApiResponse( description = "the base58-encoded transaction signature or \"false\"", - content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string")), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string")) ) } ) + @ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) public String getLastReference(@Parameter(ref = "address") @PathParam("address") String address) { if (!Crypto.isValidAddress(address)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ADDRESS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); byte[] lastReference = null; try (final Repository repository = RepositoryManager.getRepository()) { @@ -81,7 +66,7 @@ public class AddressesResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } if(lastReference == null || lastReference.length == 0) { @@ -95,31 +80,18 @@ public class AddressesResource { @Path("/lastreference/{address}/unconfirmed") @Operation( summary = "Fetch reference for next transaction to be created by address, considering unconfirmed transactions", - description = "Returns the base58-encoded signature of the last confirmed/unconfirmed transaction created by address, failing that: the first incoming transaction. Returns \\\"false\\\" if there is no transactions.", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="GET lastreference:address:unconfirmed"), - @ExtensionProperty(name="description.key", value="operation:description") - }), - @Extension(properties = { - @ExtensionProperty(name="apiErrors", value="[\"INVALID_ADDRESS\"]", parseValue = true), - }) - }, + description = "Returns the base58-encoded signature of the last confirmed/unconfirmed transaction created by address, failing that: the first incoming transaction. Returns \"false\" if there is no transactions.", responses = { @ApiResponse( description = "the base58-encoded transaction signature", - content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string")), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string")) ) } ) + @ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) public String getLastReferenceUnconfirmed(@PathParam("address") String address) { if (!Crypto.isValidAddress(address)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ADDRESS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); byte[] lastReference = null; try (final Repository repository = RepositoryManager.getRepository()) { @@ -128,7 +100,7 @@ public class AddressesResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } if(lastReference == null || lastReference.length == 0) { @@ -143,21 +115,9 @@ public class AddressesResource { @Operation( summary = "Validates the given address", description = "Returns true/false.", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="GET validate:address"), - @ExtensionProperty(name="summary.key", value="operation:summary"), - @ExtensionProperty(name="description.key", value="operation:description"), - }) - }, responses = { @ApiResponse( - content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "boolean")), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "boolean")) ) } ) @@ -170,30 +130,17 @@ public class AddressesResource { @Operation( summary = "Return the generating balance of the given address", description = "Returns the effective balance of the given address, used in Proof-of-Stake calculationgs when generating a new block.", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="GET generatingbalance:address"), - @ExtensionProperty(name="description.key", value="operation:description") - }), - @Extension(properties = { - @ExtensionProperty(name="apiErrors", value="[\"INVALID_ADDRESS\"]", parseValue = true), - }) - }, responses = { @ApiResponse( description = "the generating balance", - content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string", format = "number")), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string", format = "number")) ) } ) + @ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) public BigDecimal getGeneratingBalanceOfAddress(@PathParam("address") String address) { if (!Crypto.isValidAddress(address)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ADDRESS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); try (final Repository repository = RepositoryManager.getRepository()) { Account account = new Account(repository, address); @@ -201,7 +148,7 @@ public class AddressesResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -209,30 +156,17 @@ public class AddressesResource { @Path("/balance/{address}") @Operation( summary = "Returns the confirmed balance of the given address", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="GET balance:address"), - @ExtensionProperty(name="description.key", value="operation:description") - }), - @Extension(properties = { - @ExtensionProperty(name="apiErrors", value="[\"INVALID_ADDRESS\"]", parseValue = true), - }) - }, responses = { @ApiResponse( description = "the balance", - content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string", format = "number")), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string", format = "number")) ) } ) + @ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) public BigDecimal getGeneratingBalance(@PathParam("address") String address) { if (!Crypto.isValidAddress(address)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ADDRESS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); try (final Repository repository = RepositoryManager.getRepository()) { Account account = new Account(repository, address); @@ -240,7 +174,7 @@ public class AddressesResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -249,30 +183,17 @@ public class AddressesResource { @Operation( summary = "Asset-specific balance request", description = "Returns the confirmed balance of the given address for the given asset key.", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="GET assetbalance:assetid:address"), - @ExtensionProperty(name="description.key", value="operation:description") - }), - @Extension(properties = { - @ExtensionProperty(name="apiErrors", value="[\"INVALID_ADDRESS\", \"INVALID_ASSET_ID\"]", parseValue = true), - }) - }, responses = { @ApiResponse( description = "the balance", - content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string", format = "number")), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string", format = "number")) ) } ) + @ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) public BigDecimal getAssetBalance(@PathParam("assetid") long assetid, @PathParam("address") String address) { if (!Crypto.isValidAddress(address)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ADDRESS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); try (final Repository repository = RepositoryManager.getRepository()) { Account account = new Account(repository, address); @@ -280,7 +201,7 @@ public class AddressesResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -289,37 +210,24 @@ public class AddressesResource { @Operation( summary = "All assets owned by this address", description = "Returns the list of assets for this address, with balances.", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="GET assets:address"), - @ExtensionProperty(name="description.key", value="operation:description") - }), - @Extension(properties = { - @ExtensionProperty(name="apiErrors", value="[\"INVALID_ADDRESS\"]", parseValue = true), - }) - }, responses = { @ApiResponse( description = "the list of assets", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = AccountBalanceData.class))), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(array = @ArraySchema(schema = @Schema(implementation = AccountBalanceData.class))) ) } ) + @ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) public List getAssets(@PathParam("address") String address) { if (!Crypto.isValidAddress(address)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ADDRESS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); try (final Repository repository = RepositoryManager.getRepository()) { return repository.getAccountRepository().getAllBalances(address); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -327,24 +235,10 @@ public class AddressesResource { @Path("/balance/{address}/{confirmations}") @Operation( summary = "Calculates the balance of the given address for the given confirmations", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="GET balance:address:confirmations"), - @ExtensionProperty(name="description.key", value="operation:description") - }), - @Extension(properties = { - @ExtensionProperty(name="apiErrors", value="[\"INVALID_ADDRESS\"]", parseValue = true), - }) - }, responses = { @ApiResponse( description = "the balance", - content = @Content(schema = @Schema(implementation = String.class)), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(schema = @Schema(type = "string", format = "number")) ) } ) @@ -357,30 +251,17 @@ public class AddressesResource { @Operation( summary = "Get public key of address", description = "Returns the base58-encoded account public key of the given address, or \"false\" if address not known or has no public key.", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="GET publickey:address"), - @ExtensionProperty(name="description.key", value="operation:description") - }), - @Extension(properties = { - @ExtensionProperty(name="apiErrors", value="[\"INVALID_ADDRESS\"]", parseValue = true), - }) - }, responses = { @ApiResponse( description = "the public key", - content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string")), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string")) ) } ) + @ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) public String getPublicKey(@PathParam("address") String address) { if (!Crypto.isValidAddress(address)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ADDRESS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); try (final Repository repository = RepositoryManager.getRepository()) { AccountData accountData = repository.getAccountRepository().getAccount(address); @@ -396,7 +277,7 @@ public class AddressesResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -405,46 +286,33 @@ public class AddressesResource { @Operation( summary = "Convert public key into address", description = "Returns account address based on supplied public key. Expects base58-encoded, 32-byte public key.", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="GET publickey:address"), - @ExtensionProperty(name="description.key", value="operation:description") - }), - @Extension(properties = { - @ExtensionProperty(name="apiErrors", value="[\"INVALID_ADDRESS\"]", parseValue = true), - }) - }, responses = { @ApiResponse( description = "the address", - content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string")), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string")) ) } ) + @ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.REPOSITORY_ISSUE}) public String fromPublicKey(@PathParam("publickey") String publicKey58) { // Decode public key byte[] publicKey; try { publicKey = Base58.decode(publicKey58); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_PUBLIC_KEY, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PUBLIC_KEY, e); } // Correct size for public key? if (publicKey.length != Transformer.PUBLIC_KEY_LENGTH) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_PUBLIC_KEY); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PUBLIC_KEY); try (final Repository repository = RepositoryManager.getRepository()) { return Crypto.toAddress(publicKey); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } diff --git a/src/api/AdminResource.java b/src/main/java/api/resource/AdminResource.java similarity index 71% rename from src/api/AdminResource.java rename to src/main/java/api/resource/AdminResource.java index e701b3fb..cc4894ea 100644 --- a/src/api/AdminResource.java +++ b/src/main/java/api/resource/AdminResource.java @@ -1,10 +1,8 @@ -package api; +package api.resource; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; -import io.swagger.v3.oas.annotations.extensions.Extension; -import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -17,14 +15,11 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import api.Security; import controller.Controller; -@Path("admin") +@Path("/admin") @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) -@Extension(name = "translation", properties = { - @ExtensionProperty(name="path", value="/Api/AdminResource") - } -) @Tag(name = "Admin") public class AdminResource { @@ -52,25 +47,15 @@ public class AdminResource { @Operation( summary = "Fetch running time of server", description = "Returns uptime in milliseconds", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="operation:description") - }) - }, responses = { @ApiResponse( description = "uptime in milliseconds", - content = @Content(schema = @Schema(implementation = String.class)), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(schema = @Schema(type = "number")) ) } ) - public String uptime() { - return Long.toString(System.currentTimeMillis() - Controller.startTime); + public long uptime() { + return System.currentTimeMillis() - Controller.startTime; } @GET @@ -78,20 +63,10 @@ public class AdminResource { @Operation( summary = "Shutdown", description = "Shutdown", - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="operation:description") - }) - }, responses = { @ApiResponse( description = "\"true\"", - content = @Content(schema = @Schema(implementation = String.class)), - extensions = { - @Extension(name = "translation", properties = { - @ExtensionProperty(name="description.key", value="success_response:description") - }) - } + content = @Content(schema = @Schema(type = "string")) ) } ) diff --git a/src/main/java/api/resource/AnnotationPostProcessor.java b/src/main/java/api/resource/AnnotationPostProcessor.java new file mode 100644 index 00000000..5f7e8fdd --- /dev/null +++ b/src/main/java/api/resource/AnnotationPostProcessor.java @@ -0,0 +1,114 @@ +package api.resource; + +import globalization.Translator; +import io.swagger.v3.core.converter.ModelConverters; +import io.swagger.v3.jaxrs2.Reader; +import io.swagger.v3.jaxrs2.ReaderListener; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.examples.Example; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.responses.ApiResponse; + +import java.lang.reflect.Method; +import java.util.Locale; + +import javax.ws.rs.Path; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import api.ApiError; +import api.ApiErrorMessage; +import api.ApiErrors; +import api.ApiService; + +public class AnnotationPostProcessor implements ReaderListener { + + private static final Logger LOGGER = LogManager.getLogger(AnnotationPostProcessor.class); + + @Override + public void beforeScan(Reader reader, OpenAPI openAPI) { + } + + @Override + public void afterScan(Reader reader, OpenAPI openAPI) { + // Populate Components section with reusable parameters, like "limit" and "offset" + // We take the reusable parameters from AdminResource.globalParameters path "/admin/unused" + Components components = openAPI.getComponents(); + + PathItem globalParametersPathItem = openAPI.getPaths().get("/admin/unused"); + + if (globalParametersPathItem != null) { + for (Parameter parameter : globalParametersPathItem.getGet().getParameters()) + components.addParameters(parameter.getName(), parameter); + + openAPI.getPaths().remove("/admin/unused"); + } + + // Search all ApiService resources (classes) for @ApiErrors annotations + // to generate corresponding openAPI operation responses. + for (Class clazz : ApiService.getInstance().getResources()) { + Path classPath = clazz.getAnnotation(Path.class); + if (classPath == null) + continue; + + String classPathString = classPath.value(); + if (classPathString.charAt(0) != '/') + classPathString = "/" + classPathString; + + for (Method method : clazz.getDeclaredMethods()) { + ApiErrors apiErrors = method.getAnnotation(ApiErrors.class); + if (apiErrors == null) + continue; + + LOGGER.info("Found @ApiErrors annotation on " + clazz.getSimpleName() + "." + method.getName()); + PathItem pathItem = getPathItemFromMethod(openAPI, classPathString, method); + + for (Operation operation : pathItem.readOperations()) + for (ApiError apiError : apiErrors.value()) + addApiErrorResponse(operation, apiError); + } + } + } + + private PathItem getPathItemFromMethod(OpenAPI openAPI, String classPathString, Method method) { + Path path = method.getAnnotation(Path.class); + if (path == null) + throw new RuntimeException("API method has no @Path annotation?"); + + String pathString = path.value(); + return openAPI.getPaths().get(classPathString + pathString); + } + + private void addApiErrorResponse(Operation operation, ApiError apiError) { + String statusCode = Integer.toString(apiError.getStatus()) + " " + apiError.name(); + + // Create response for this HTTP response code if it doesn't already exist + ApiResponse apiResponse = operation.getResponses().get(statusCode); + if (apiResponse == null) { + Schema errorMessageSchema = ModelConverters.getInstance().readAllAsResolvedSchema(ApiErrorMessage.class).schema; + MediaType mediaType = new MediaType().schema(errorMessageSchema); + Content content = new Content().addMediaType(javax.ws.rs.core.MediaType.APPLICATION_JSON, mediaType); + apiResponse = new ApiResponse().content(content); + operation.getResponses().addApiResponse(statusCode, apiResponse); + } + + // Add this specific ApiError code as an example + int apiErrorCode = apiError.getCode(); + String lang = Locale.getDefault().getLanguage(); + ApiErrorMessage apiErrorMessage = new ApiErrorMessage(apiErrorCode, Translator.INSTANCE.translate("ApiError", lang, apiError.name())); + Example example = new Example().value(apiErrorMessage); + + // XXX: addExamples(..) is not working in Swagger 2.0.4. This bug is referenced in https://github.com/swagger-api/swagger-ui/issues/2651 + // Replace the call to .setExample(..) by .addExamples(..) when the bug is fixed. + apiResponse.getContent().get(javax.ws.rs.core.MediaType.APPLICATION_JSON).setExample(example); + //apiResponse.getContent().get(javax.ws.rs.core.MediaType.APPLICATION_JSON).addExamples(Integer.toString(apiErrorCode), example); + } + +} diff --git a/src/api/ApiDefinition.java b/src/main/java/api/resource/ApiDefinition.java similarity index 97% rename from src/api/ApiDefinition.java rename to src/main/java/api/resource/ApiDefinition.java index 31239faf..0da2ad31 100644 --- a/src/api/ApiDefinition.java +++ b/src/main/java/api/resource/ApiDefinition.java @@ -1,4 +1,4 @@ -package api; +package api.resource; import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.extensions.Extension; @@ -25,5 +25,4 @@ import io.swagger.v3.oas.annotations.tags.Tag; } ) public class ApiDefinition { - -} +} \ No newline at end of file diff --git a/src/api/AssetsResource.java b/src/main/java/api/resource/AssetsResource.java similarity index 80% rename from src/api/AssetsResource.java rename to src/main/java/api/resource/AssetsResource.java index 81e51ca2..97defed1 100644 --- a/src/api/AssetsResource.java +++ b/src/main/java/api/resource/AssetsResource.java @@ -1,4 +1,4 @@ -package api; +package api.resource; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -30,6 +30,9 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import api.ApiError; +import api.ApiErrors; +import api.ApiExceptionFactory; import api.models.AssetWithHolders; import api.models.OrderWithTrades; import api.models.TradeWithOrderInfo; @@ -58,6 +61,7 @@ public class AssetsResource { ) } ) + @ApiErrors({ApiError.REPOSITORY_ISSUE}) public List getAllAssets(@Parameter(ref = "limit") @QueryParam("limit") int limit, @Parameter(ref = "offset") @QueryParam("offset") int offset) { try (final Repository repository = RepositoryManager.getRepository()) { List assets = repository.getAssetRepository().getAllAssets(); @@ -69,7 +73,7 @@ public class AssetsResource { return assets; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -85,9 +89,10 @@ public class AssetsResource { ) } ) + @ApiErrors({ApiError.INVALID_CRITERIA, ApiError.INVALID_ASSET_ID, ApiError.REPOSITORY_ISSUE}) public AssetWithHolders getAssetInfo(@QueryParam("assetId") Integer assetId, @QueryParam("assetName") String assetName, @Parameter(ref = "includeHolders") @QueryParam("includeHolders") boolean includeHolders) { if (assetId == null && (assetName == null || assetName.isEmpty())) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_CRITERIA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA); try (final Repository repository = RepositoryManager.getRepository()) { AssetData assetData = null; @@ -98,7 +103,7 @@ public class AssetsResource { assetData = repository.getAssetRepository().fromAssetName(assetName); if (assetData == null) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ASSET_ID); List holders = null; if (includeHolders) @@ -106,7 +111,7 @@ public class AssetsResource { return new AssetWithHolders(assetData, holders); } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -122,14 +127,15 @@ public class AssetsResource { ) } ) + @ApiErrors({ApiError.INVALID_ASSET_ID, ApiError.REPOSITORY_ISSUE}) public List getAssetOrders(@Parameter(ref = "assetId") @PathParam("assetId") int assetId, @Parameter(ref = "otherAssetId") @PathParam("otherAssetId") int otherAssetId, @Parameter(ref = "limit") @QueryParam("limit") int limit, @Parameter(ref = "offset") @QueryParam("offset") int offset) { try (final Repository repository = RepositoryManager.getRepository()) { if (!repository.getAssetRepository().assetExists(assetId)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ASSET_ID); if (!repository.getAssetRepository().assetExists(otherAssetId)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ASSET_ID); List orders = repository.getAssetRepository().getOpenOrders(assetId, otherAssetId); @@ -140,7 +146,7 @@ public class AssetsResource { return orders; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -158,14 +164,15 @@ public class AssetsResource { ) } ) + @ApiErrors({ApiError.INVALID_ASSET_ID, ApiError.REPOSITORY_ISSUE}) public List getAssetTrades(@Parameter(ref = "assetId") @PathParam("assetId") int assetId, @Parameter(ref = "otherAssetId") @PathParam("otherAssetId") int otherAssetId, @Parameter(ref = "limit") @QueryParam("limit") int limit, @Parameter(ref = "offset") @QueryParam("offset") int offset) { try (final Repository repository = RepositoryManager.getRepository()) { if (!repository.getAssetRepository().assetExists(assetId)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ASSET_ID); if (!repository.getAssetRepository().assetExists(otherAssetId)) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ASSET_ID); List trades = repository.getAssetRepository().getTrades(assetId, otherAssetId); @@ -184,7 +191,7 @@ public class AssetsResource { return fullTrades; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -200,25 +207,26 @@ public class AssetsResource { ) } ) + @ApiErrors({ApiError.INVALID_ORDER_ID, ApiError.ORDER_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) public OrderWithTrades getAssetOrder(@PathParam("orderId") String orderId58) { // Decode orderID byte[] orderId; try { orderId = Base58.decode(orderId58); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ORDER_ID, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ORDER_ID, e); } try (final Repository repository = RepositoryManager.getRepository()) { OrderData orderData = repository.getAssetRepository().fromOrderId(orderId); if (orderData == null) - throw ApiErrorFactory.getInstance().createError(ApiError.ORDER_NO_EXISTS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.ORDER_NO_EXISTS); List trades = repository.getAssetRepository().getOrdersTrades(orderId); return new OrderWithTrades(orderData, trades); } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -245,20 +253,21 @@ public class AssetsResource { ) } ) + @ApiErrors({ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE, ApiError.TRANSACTION_INVALID}) public String issueAsset(IssueAssetTransactionData transactionData) { try (final Repository repository = RepositoryManager.getRepository()) { Transaction transaction = Transaction.fromData(repository, transactionData); ValidationResult result = transaction.isValid(); if (result != ValidationResult.OK) - throw new ApiException(400, ApiError.INVALID_DATA.getCode(), "Transaction invalid: " + result.name()); + throw TransactionsResource.createTransactionInvalidException(request, result); byte[] bytes = IssueAssetTransactionTransformer.toBytes(transactionData); return Base58.encode(bytes); } catch (TransformationException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.UNKNOWN, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e); } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } diff --git a/src/main/java/api/resource/BlockExplorerResource.java b/src/main/java/api/resource/BlockExplorerResource.java new file mode 100644 index 00000000..1cf236c7 --- /dev/null +++ b/src/main/java/api/resource/BlockExplorerResource.java @@ -0,0 +1,37 @@ +package api.resource; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; + +import io.swagger.v3.oas.annotations.Operation; + +@Path("/") +public class BlockExplorerResource { + + @Context + HttpServletRequest request; + + @GET + @Path("/block-explorer.html") + @Operation(hidden = true) + public String getBlockExplorer() { + ClassLoader loader = this.getClass().getClassLoader(); + try (InputStream inputStream = loader.getResourceAsStream("block-explorer.html")) { + if (inputStream == null) + return "block-explorer.html resource not found"; + + return new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining("\n")); + } catch (IOException e) { + return "Error reading block-explorer.html resource"; + } + } + +} diff --git a/src/api/BlocksResource.java b/src/main/java/api/resource/BlocksResource.java similarity index 52% rename from src/api/BlocksResource.java rename to src/main/java/api/resource/BlocksResource.java index cae882e5..ae53c0ac 100644 --- a/src/api/BlocksResource.java +++ b/src/main/java/api/resource/BlocksResource.java @@ -1,11 +1,9 @@ -package api; +package api.resource; import data.block.BlockData; import data.transaction.TransactionData; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.extensions.Extension; -import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -26,6 +24,10 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import api.ApiError; +import api.ApiErrors; +import api.ApiException; +import api.ApiExceptionFactory; import api.models.BlockWithTransactions; import qora.block.Block; import repository.DataException; @@ -33,22 +35,9 @@ import repository.Repository; import repository.RepositoryManager; import utils.Base58; -@Path("blocks") -@Produces({ - MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN -}) -@Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "/Api/BlocksResource" - ) - } -) -@Tag( - name = "Blocks" -) +@Path("/blocks") +@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) +@Tag(name = "Blocks") public class BlocksResource { @Context @@ -59,28 +48,6 @@ public class BlocksResource { @Operation( summary = "Fetch block using base58 signature", description = "Returns the block that matches the given signature", - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET signature" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), @Extension( - properties = { - @ExtensionProperty( - name = "apiErrors", - value = "[\"INVALID_SIGNATURE\", \"BLOCK_NO_EXISTS\"]", - parseValue = true - ), - } - ) - }, responses = { @ApiResponse( description = "the block", @@ -88,30 +55,18 @@ public class BlocksResource { schema = @Schema( implementation = BlockWithTransactions.class ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) - public BlockWithTransactions getBlock(@PathParam("signature") String signature58, @Parameter( - ref = "includeTransactions" - ) @QueryParam("includeTransactions") boolean includeTransactions) { + @ApiErrors({ApiError.INVALID_SIGNATURE, ApiError.BLOCK_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) + public BlockWithTransactions getBlock(@PathParam("signature") String signature58, @Parameter(ref = "includeTransactions") @QueryParam("includeTransactions") boolean includeTransactions) { // Decode signature byte[] signature; try { signature = Base58.decode(signature58); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_SIGNATURE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_SIGNATURE, e); } try (final Repository repository = RepositoryManager.getRepository()) { @@ -120,7 +75,7 @@ public class BlocksResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -129,18 +84,6 @@ public class BlocksResource { @Operation( summary = "Fetch genesis block", description = "Returns the genesis block", - extensions = @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET first" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), responses = { @ApiResponse( description = "the block", @@ -148,31 +91,19 @@ public class BlocksResource { schema = @Schema( implementation = BlockWithTransactions.class ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) - public BlockWithTransactions getFirstBlock(@Parameter( - ref = "includeTransactions" - ) @QueryParam("includeTransactions") boolean includeTransactions) { + @ApiErrors({ApiError.BLOCK_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) + public BlockWithTransactions getFirstBlock(@Parameter(ref = "includeTransactions") @QueryParam("includeTransactions") boolean includeTransactions) { try (final Repository repository = RepositoryManager.getRepository()) { BlockData blockData = repository.getBlockRepository().fromHeight(1); return packageBlockData(repository, blockData, includeTransactions); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -181,18 +112,6 @@ public class BlocksResource { @Operation( summary = "Fetch last/newest block in blockchain", description = "Returns the last valid block", - extensions = @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET last" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), responses = { @ApiResponse( description = "the block", @@ -200,31 +119,19 @@ public class BlocksResource { schema = @Schema( implementation = BlockWithTransactions.class ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) - public BlockWithTransactions getLastBlock(@Parameter( - ref = "includeTransactions" - ) @QueryParam("includeTransactions") boolean includeTransactions) { + @ApiErrors({ApiError.BLOCK_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) + public BlockWithTransactions getLastBlock(@Parameter(ref = "includeTransactions") @QueryParam("includeTransactions") boolean includeTransactions) { try (final Repository repository = RepositoryManager.getRepository()) { BlockData blockData = repository.getBlockRepository().getLastBlock(); return packageBlockData(repository, blockData, includeTransactions); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -233,28 +140,6 @@ public class BlocksResource { @Operation( summary = "Fetch child block using base58 signature of parent block", description = "Returns the child block of the block that matches the given signature", - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET child:signature" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), @Extension( - properties = { - @ExtensionProperty( - name = "apiErrors", - value = "[\"INVALID_SIGNATURE\", \"BLOCK_NO_EXISTS\"]", - parseValue = true - ), - } - ) - }, responses = { @ApiResponse( description = "the block", @@ -262,30 +147,18 @@ public class BlocksResource { schema = @Schema( implementation = BlockWithTransactions.class ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) - public BlockWithTransactions getChild(@PathParam("signature") String signature58, @Parameter( - ref = "includeTransactions" - ) @QueryParam("includeTransactions") boolean includeTransactions) { + @ApiErrors({ApiError.INVALID_SIGNATURE, ApiError.BLOCK_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) + public BlockWithTransactions getChild(@PathParam("signature") String signature58, @Parameter(ref = "includeTransactions") @QueryParam("includeTransactions") boolean includeTransactions) { // Decode signature byte[] signature; try { signature = Base58.decode(signature58); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_SIGNATURE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_SIGNATURE, e); } try (final Repository repository = RepositoryManager.getRepository()) { @@ -293,7 +166,7 @@ public class BlocksResource { // Check block exists if (blockData == null) - throw ApiErrorFactory.getInstance().createError(ApiError.BLOCK_NO_EXISTS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BLOCK_NO_EXISTS); BlockData childBlockData = repository.getBlockRepository().fromReference(signature); @@ -302,7 +175,7 @@ public class BlocksResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -311,18 +184,6 @@ public class BlocksResource { @Operation( summary = "Generating balance of next block", description = "Calculates the generating balance of the block that will follow the last block", - extensions = @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET generatingbalance" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), responses = { @ApiResponse( description = "the generating balance", @@ -331,21 +192,11 @@ public class BlocksResource { schema = @Schema( implementation = BigDecimal.class ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) + @ApiErrors({ApiError.REPOSITORY_ISSUE}) public BigDecimal getGeneratingBalance() { try (final Repository repository = RepositoryManager.getRepository()) { BlockData blockData = repository.getBlockRepository().getLastBlock(); @@ -354,7 +205,7 @@ public class BlocksResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -363,28 +214,6 @@ public class BlocksResource { @Operation( summary = "Generating balance of block after specific block", description = "Calculates the generating balance of the block that will follow the block that matches the signature", - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET generatingbalance:signature" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), @Extension( - properties = { - @ExtensionProperty( - name = "apiErrors", - value = "[\"INVALID_SIGNATURE\", \"BLOCK_NO_EXISTS\"]", - parseValue = true - ), - } - ) - }, responses = { @ApiResponse( description = "the block", @@ -393,28 +222,18 @@ public class BlocksResource { schema = @Schema( implementation = BigDecimal.class ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) + @ApiErrors({ApiError.INVALID_SIGNATURE, ApiError.BLOCK_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) public BigDecimal getGeneratingBalance(@PathParam("signature") String signature58) { // Decode signature byte[] signature; try { signature = Base58.decode(signature58); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_SIGNATURE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_SIGNATURE, e); } try (final Repository repository = RepositoryManager.getRepository()) { @@ -422,14 +241,14 @@ public class BlocksResource { // Check block exists if (blockData == null) - throw ApiErrorFactory.getInstance().createError(ApiError.BLOCK_NO_EXISTS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BLOCK_NO_EXISTS); Block block = new Block(repository, blockData); return block.calcNextBlockGeneratingBalance(); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -438,42 +257,19 @@ public class BlocksResource { @Operation( summary = "Estimated time to forge next block", description = "Calculates the time it should take for the network to generate the next block", - extensions = @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET time" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), responses = { @ApiResponse( - description = "the time in seconds", // in - // seconds? + description = "the time in seconds", content = @Content( mediaType = MediaType.TEXT_PLAIN, schema = @Schema( type = "number" ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) + @ApiErrors({ApiError.REPOSITORY_ISSUE}) public long getTimePerBlock() { try (final Repository repository = RepositoryManager.getRepository()) { BlockData blockData = repository.getBlockRepository().getLastBlock(); @@ -481,7 +277,7 @@ public class BlocksResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -490,18 +286,6 @@ public class BlocksResource { @Operation( summary = "Estimated time to forge block given generating balance", description = "Calculates the time it should take for the network to generate blocks based on specified generating balance", - extensions = @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET time:generatingbalance" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), responses = { @ApiResponse( description = "the time", // in seconds? @@ -510,18 +294,7 @@ public class BlocksResource { schema = @Schema( type = "number" ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) @@ -534,18 +307,6 @@ public class BlocksResource { @Operation( summary = "Current blockchain height", description = "Returns the block height of the last block.", - extensions = @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET height" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), responses = { @ApiResponse( description = "the height", @@ -554,28 +315,18 @@ public class BlocksResource { schema = @Schema( type = "number" ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) + @ApiErrors({ApiError.REPOSITORY_ISSUE}) public int getHeight() { try (final Repository repository = RepositoryManager.getRepository()) { return repository.getBlockRepository().getBlockchainHeight(); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -584,28 +335,6 @@ public class BlocksResource { @Operation( summary = "Height of specific block", description = "Returns the block height of the block that matches the given signature", - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET height:signature" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), @Extension( - properties = { - @ExtensionProperty( - name = "apiErrors", - value = "[\"INVALID_SIGNATURE\", \"BLOCK_NO_EXISTS\"]", - parseValue = true - ), - } - ) - }, responses = { @ApiResponse( description = "the height", @@ -614,28 +343,18 @@ public class BlocksResource { schema = @Schema( type = "number" ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) + @ApiErrors({ApiError.INVALID_SIGNATURE, ApiError.BLOCK_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) public int getHeight(@PathParam("signature") String signature58) { // Decode signature byte[] signature; try { signature = Base58.decode(signature58); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_SIGNATURE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_SIGNATURE, e); } try (final Repository repository = RepositoryManager.getRepository()) { @@ -643,13 +362,13 @@ public class BlocksResource { // Check block exists if (blockData == null) - throw ApiErrorFactory.getInstance().createError(ApiError.BLOCK_NO_EXISTS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BLOCK_NO_EXISTS); return blockData.getHeight(); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -658,28 +377,6 @@ public class BlocksResource { @Operation( summary = "Fetch block using block height", description = "Returns the block with given height", - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET byheight:height" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), @Extension( - properties = { - @ExtensionProperty( - name = "apiErrors", - value = "[\"BLOCK_NO_EXISTS\"]", - parseValue = true - ), - } - ) - }, responses = { @ApiResponse( description = "the block", @@ -687,31 +384,19 @@ public class BlocksResource { schema = @Schema( implementation = BlockWithTransactions.class ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) - public BlockWithTransactions getByHeight(@PathParam("height") int height, @Parameter( - ref = "includeTransactions" - ) @QueryParam("includeTransactions") boolean includeTransactions) { + @ApiErrors({ApiError.BLOCK_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) + public BlockWithTransactions getByHeight(@PathParam("height") int height, @Parameter(ref = "includeTransactions") @QueryParam("includeTransactions") boolean includeTransactions) { try (final Repository repository = RepositoryManager.getRepository()) { BlockData blockData = repository.getBlockRepository().fromHeight(height); return packageBlockData(repository, blockData, includeTransactions); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -720,28 +405,6 @@ public class BlocksResource { @Operation( summary = "Fetch blocks starting with given height", description = "Returns blocks starting with given height.", - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET byheight:height" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), @Extension( - properties = { - @ExtensionProperty( - name = "apiErrors", - value = "[\"BLOCK_NO_EXISTS\"]", - parseValue = true - ), - } - ) - }, responses = { @ApiResponse( description = "blocks", @@ -749,24 +412,12 @@ public class BlocksResource { schema = @Schema( implementation = BlockWithTransactions.class ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) - public List getBlockRange(@PathParam("height") int height, @Parameter( - ref = "count" - ) @QueryParam("count") int count) { + @ApiErrors({ApiError.BLOCK_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) + public List getBlockRange(@PathParam("height") int height, @Parameter(ref = "count") @QueryParam("count") int count) { boolean includeTransactions = false; try (final Repository repository = RepositoryManager.getRepository()) { @@ -785,13 +436,25 @@ public class BlocksResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } + /** + * Returns block, optionally including transactions. + *

+ * Throws ApiException using ApiError.BLOCK_NO_EXISTS if blockData is null. + * + * @param repository + * @param blockData + * @param includeTransactions + * @return packaged block, with optional transactions + * @throws DataException + * @throws ApiException ApiError.BLOCK_NO_EXISTS + */ private BlockWithTransactions packageBlockData(Repository repository, BlockData blockData, boolean includeTransactions) throws DataException { if (blockData == null) - throw ApiErrorFactory.getInstance().createError(ApiError.BLOCK_NO_EXISTS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BLOCK_NO_EXISTS); List transactions = null; if (includeTransactions) { diff --git a/src/api/NamesResource.java b/src/main/java/api/resource/NamesResource.java similarity index 79% rename from src/api/NamesResource.java rename to src/main/java/api/resource/NamesResource.java index 4631400d..2b6ebf37 100644 --- a/src/api/NamesResource.java +++ b/src/main/java/api/resource/NamesResource.java @@ -1,4 +1,4 @@ -package api; +package api.resource; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -22,15 +22,14 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import api.ApiError; +import api.ApiErrors; +import api.ApiExceptionFactory; import data.transaction.RegisterNameTransactionData; @Path("/names") -@Produces({ - MediaType.TEXT_PLAIN -}) -@Tag( - name = "Names" -) +@Produces({ MediaType.TEXT_PLAIN}) +@Tag(name = "Names") public class NamesResource { @Context @@ -61,20 +60,21 @@ public class NamesResource { ) } ) + @ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE}) public String buildTransaction(RegisterNameTransactionData transactionData) { try (final Repository repository = RepositoryManager.getRepository()) { Transaction transaction = Transaction.fromData(repository, transactionData); ValidationResult result = transaction.isValid(); if (result != ValidationResult.OK) - throw new ApiException(400, ApiError.INVALID_DATA.getCode(), "Transaction invalid: " + result.name()); + throw TransactionsResource.createTransactionInvalidException(request, result); byte[] bytes = RegisterNameTransactionTransformer.toBytes(transactionData); return Base58.encode(bytes); } catch (TransformationException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.UNKNOWN, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e); } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } diff --git a/src/api/PaymentsResource.java b/src/main/java/api/resource/PaymentsResource.java similarity index 79% rename from src/api/PaymentsResource.java rename to src/main/java/api/resource/PaymentsResource.java index 5a8106e3..5f2f26f0 100644 --- a/src/api/PaymentsResource.java +++ b/src/main/java/api/resource/PaymentsResource.java @@ -1,4 +1,4 @@ -package api; +package api.resource; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -22,15 +22,14 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import api.ApiError; +import api.ApiErrors; +import api.ApiExceptionFactory; import data.transaction.PaymentTransactionData; @Path("/payments") -@Produces({ - MediaType.TEXT_PLAIN -}) -@Tag( - name = "Payments" -) +@Produces({MediaType.TEXT_PLAIN}) +@Tag(name = "Payments") public class PaymentsResource { @Context @@ -61,20 +60,21 @@ public class PaymentsResource { ) } ) + @ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE}) public String buildTransaction(PaymentTransactionData transactionData) { try (final Repository repository = RepositoryManager.getRepository()) { Transaction transaction = Transaction.fromData(repository, transactionData); ValidationResult result = transaction.isValid(); if (result != ValidationResult.OK) - throw new ApiException(400, ApiError.INVALID_DATA.getCode(), "Transaction invalid: " + result.name()); + throw TransactionsResource.createTransactionInvalidException(request, result); byte[] bytes = PaymentTransactionTransformer.toBytes(transactionData); return Base58.encode(bytes); } catch (TransformationException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.UNKNOWN, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e); } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } diff --git a/src/api/TransactionsResource.java b/src/main/java/api/resource/TransactionsResource.java similarity index 74% rename from src/api/TransactionsResource.java rename to src/main/java/api/resource/TransactionsResource.java index 0d68f088..d20083ad 100644 --- a/src/api/TransactionsResource.java +++ b/src/main/java/api/resource/TransactionsResource.java @@ -1,9 +1,7 @@ -package api; +package api.resource; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.extensions.Extension; -import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; @@ -30,10 +28,15 @@ import javax.ws.rs.core.MediaType; import com.google.common.primitives.Bytes; +import api.ApiError; +import api.ApiErrors; +import api.ApiException; +import api.ApiExceptionFactory; import api.models.SimpleTransactionSignRequest; import data.transaction.GenesisTransactionData; import data.transaction.PaymentTransactionData; import data.transaction.TransactionData; +import globalization.Translator; import repository.DataException; import repository.Repository; import repository.RepositoryManager; @@ -41,22 +44,9 @@ import transform.TransformationException; import transform.transaction.TransactionTransformer; import utils.Base58; -@Path("transactions") -@Produces({ - MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN -}) -@Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "/Api/TransactionsResource" - ) - } -) -@Tag( - name = "Transactions" -) +@Path("/transactions") +@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) +@Tag(name = "Transactions") public class TransactionsResource { @Context @@ -67,17 +57,6 @@ public class TransactionsResource { @Operation( summary = "Fetch transaction using transaction signature", description = "Returns transaction", - extensions = { - @Extension( - properties = { - @ExtensionProperty( - name = "apiErrors", - value = "[\"INVALID_SIGNATURE\", \"TRANSACTION_NO_EXISTS\"]", - parseValue = true - ), - } - ) - }, responses = { @ApiResponse( description = "a transaction", @@ -85,39 +64,29 @@ public class TransactionsResource { schema = @Schema( implementation = TransactionData.class ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) + @ApiErrors({ApiError.INVALID_SIGNATURE, ApiError.TRANSACTION_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) public TransactionData getTransactions(@PathParam("signature") String signature58) { byte[] signature; try { signature = Base58.decode(signature58); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_SIGNATURE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_SIGNATURE, e); } try (final Repository repository = RepositoryManager.getRepository()) { TransactionData transactionData = repository.getTransactionRepository().fromSignature(signature); if (transactionData == null) - throw ApiErrorFactory.getInstance().createError(ApiError.TRANSACTION_NO_EXISTS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSACTION_NO_EXISTS); return transactionData; } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -126,28 +95,6 @@ public class TransactionsResource { @Operation( summary = "Fetch transactions using block signature", description = "Returns list of transactions", - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "path", - value = "GET block:signature" - ), @ExtensionProperty( - name = "description.key", - value = "operation:description" - ) - } - ), @Extension( - properties = { - @ExtensionProperty( - name = "apiErrors", - value = "[\"INVALID_SIGNATURE\", \"BLOCK_NO_EXISTS\"]", - parseValue = true - ), - } - ) - }, responses = { @ApiResponse( description = "list of transactions", @@ -159,31 +106,17 @@ public class TransactionsResource { } ) ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) - public List getBlockTransactions(@PathParam("signature") String signature58, @Parameter( - ref = "limit" - ) @QueryParam("limit") int limit, @Parameter( - ref = "offset" - ) @QueryParam("offset") int offset) { + @ApiErrors({ApiError.INVALID_SIGNATURE, ApiError.BLOCK_NO_EXISTS, ApiError.REPOSITORY_ISSUE}) + public List getBlockTransactions(@PathParam("signature") String signature58, @Parameter(ref = "limit") @QueryParam("limit") int limit, @Parameter(ref = "offset") @QueryParam("offset") int offset) { byte[] signature; try { signature = Base58.decode(signature58); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_SIGNATURE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_SIGNATURE, e); } try (final Repository repository = RepositoryManager.getRepository()) { @@ -191,7 +124,7 @@ public class TransactionsResource { // check if block exists if (transactions == null) - throw ApiErrorFactory.getInstance().createError(ApiError.BLOCK_NO_EXISTS); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BLOCK_NO_EXISTS); // Pagination would take effect here (or as part of the repository access) int fromIndex = Integer.min(offset, transactions.size()); @@ -202,7 +135,7 @@ public class TransactionsResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -220,28 +153,18 @@ public class TransactionsResource { implementation = TransactionData.class ) ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) + @ApiErrors({ApiError.REPOSITORY_ISSUE}) public List getUnconfirmedTransactions() { try (final Repository repository = RepositoryManager.getRepository()) { return repository.getTransactionRepository().getAllUnconfirmedTransactions(); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -271,35 +194,25 @@ public class TransactionsResource { implementation = TransactionData.class ) ) - ), - extensions = { - @Extension( - name = "translation", - properties = { - @ExtensionProperty( - name = "description.key", - value = "success_response:description" - ) - } - ) - } + ) ) } ) - public List searchTransactions(@QueryParam("startBlock") Integer startBlock, @QueryParam("blockLimit") Integer blockLimit, + @ApiErrors({ApiError.INVALID_CRITERIA, ApiError.REPOSITORY_ISSUE}) + public List searchTransactions(@QueryParam("startBlock") Integer startBlock, @QueryParam("blockLimit") Integer blockLimit, @QueryParam("txType") Integer txTypeNum, @QueryParam("address") String address, @Parameter( ref = "limit" ) @QueryParam("limit") int limit, @Parameter( ref = "offset" ) @QueryParam("offset") int offset) { if ((txTypeNum == null || txTypeNum == 0) && (address == null || address.isEmpty())) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_CRITERIA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA); TransactionType txType = null; if (txTypeNum != null) { txType = TransactionType.valueOf(txTypeNum); if (txType == null) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_CRITERIA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA); } try (final Repository repository = RepositoryManager.getRepository()) { @@ -319,7 +232,7 @@ public class TransactionsResource { } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -348,6 +261,7 @@ public class TransactionsResource { ) } ) + @ApiErrors({ApiError.TRANSFORMATION_ERROR}) public String signTransaction(SimpleTransactionSignRequest signRequest) { try { // Append null signature on the end before transformation @@ -364,7 +278,7 @@ public class TransactionsResource { return Base58.encode(signedBytes); } catch (TransformationException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.UNKNOWN, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e); } } @@ -395,6 +309,7 @@ public class TransactionsResource { ) } ) + @ApiErrors({ApiError.INVALID_SIGNATURE, ApiError.INVALID_DATA, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE}) public String processTransaction(String rawBytes58) { try (final Repository repository = RepositoryManager.getRepository()) { byte[] rawBytes = Base58.decode(rawBytes58); @@ -402,11 +317,11 @@ public class TransactionsResource { Transaction transaction = Transaction.fromData(repository, transactionData); if (!transaction.isSignatureValid()) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_SIGNATURE); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_SIGNATURE); ValidationResult result = transaction.isValid(); if (result != ValidationResult.OK) - throw new ApiException(400, ApiError.INVALID_DATA.getCode(), "Transaction invalid: " + result.name()); + throw createTransactionInvalidException(request, result); repository.getTransactionRepository().save(transactionData); repository.getTransactionRepository().unconfirmTransaction(transactionData); @@ -414,11 +329,11 @@ public class TransactionsResource { return "true"; } catch (TransformationException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.UNKNOWN, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @@ -448,6 +363,7 @@ public class TransactionsResource { ) } ) + @ApiErrors({ApiError.INVALID_SIGNATURE, ApiError.INVALID_DATA, ApiError.TRANSACTION_INVALID, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE}) public TransactionData decodeTransaction(String rawBytes58) { try (final Repository repository = RepositoryManager.getRepository()) { byte[] rawBytes = Base58.decode(rawBytes58); @@ -465,23 +381,28 @@ public class TransactionsResource { Transaction transaction = Transaction.fromData(repository, transactionData); if (hasSignature && !transaction.isSignatureValid()) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_SIGNATURE); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_SIGNATURE); ValidationResult result = transaction.isValid(); if (result != ValidationResult.OK) - throw new ApiException(400, ApiError.INVALID_DATA.getCode(), "Transaction invalid: " + result.name()); + throw createTransactionInvalidException(request, result); if (!hasSignature) transactionData.setSignature(null); return transactionData; } catch (TransformationException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.UNKNOWN, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e); } catch (ApiException e) { throw e; } catch (DataException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } + public static ApiException createTransactionInvalidException(HttpServletRequest request, ValidationResult result) { + String translatedResult = Translator.INSTANCE.translate("TransactionValidity", request.getLocale().getLanguage(), result.name()); + return ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSACTION_INVALID, null, translatedResult); + } + } diff --git a/src/api/UtilsResource.java b/src/main/java/api/resource/UtilsResource.java similarity index 89% rename from src/api/UtilsResource.java rename to src/main/java/api/resource/UtilsResource.java index 224b0b0e..5c48f5aa 100644 --- a/src/api/UtilsResource.java +++ b/src/main/java/api/resource/UtilsResource.java @@ -1,4 +1,4 @@ -package api; +package api.resource; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -31,6 +31,10 @@ import com.google.common.hash.HashCode; import com.google.common.primitives.Bytes; import com.google.common.primitives.Longs; +import api.ApiError; +import api.ApiErrors; +import api.ApiExceptionFactory; + @Path("/utils") @Produces({ MediaType.TEXT_PLAIN @@ -67,11 +71,12 @@ public class UtilsResource { ) } ) + @ApiErrors({ApiError.INVALID_DATA}) public String fromBase64(String base64) { try { return HashCode.fromBytes(Base64.getDecoder().decode(base64.trim())).toString(); } catch (IllegalArgumentException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_DATA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); } } @@ -99,11 +104,12 @@ public class UtilsResource { ) } ) + @ApiErrors({ApiError.INVALID_DATA}) public String base64from58(String base58) { try { return HashCode.fromBytes(Base58.decode(base58.trim())).toString(); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_DATA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); } } @@ -189,6 +195,7 @@ public class UtilsResource { ) } ) + @ApiErrors({ApiError.INVALID_DATA}) public String getMnemonic(@QueryParam("entropy") String suppliedEntropy) { /* * BIP39 word lists have 2048 entries so can be represented by 11 bits. @@ -201,12 +208,12 @@ public class UtilsResource { try { entropy = Base58.decode(suppliedEntropy); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_DATA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); } // Must be 16-bytes if (entropy.length != 16) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_DATA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); } else { // Generate entropy internally UUID uuid = UUID.randomUUID(); @@ -296,16 +303,17 @@ public class UtilsResource { ) } ) + @ApiErrors({ApiError.INVALID_DATA}) public String privateKey(@PathParam("entropy") String entropy58) { byte[] entropy; try { entropy = Base58.decode(entropy58); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_DATA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); } if (entropy.length != 16) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_DATA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); byte[] privateKey = Crypto.digest(entropy); @@ -328,16 +336,17 @@ public class UtilsResource { ) } ) + @ApiErrors({ApiError.INVALID_DATA}) public String publicKey(@PathParam("privateKey") String privateKey58) { byte[] privateKey; try { privateKey = Base58.decode(privateKey58); } catch (NumberFormatException e) { - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_DATA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); } if (privateKey.length != 32) - throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_DATA); + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); byte[] publicKey = new PrivateKeyAccount(null, privateKey).getPublicKey(); diff --git a/src/blockgenerator.java b/src/main/java/blockgenerator.java similarity index 100% rename from src/blockgenerator.java rename to src/main/java/blockgenerator.java diff --git a/src/brokenmd160.java b/src/main/java/brokenmd160.java similarity index 100% rename from src/brokenmd160.java rename to src/main/java/brokenmd160.java diff --git a/src/controller/Controller.java b/src/main/java/controller/Controller.java similarity index 100% rename from src/controller/Controller.java rename to src/main/java/controller/Controller.java diff --git a/src/crosschain/BTC.java b/src/main/java/crosschain/BTC.java similarity index 99% rename from src/crosschain/BTC.java rename to src/main/java/crosschain/BTC.java index ce7a9e17..feb29dc5 100644 --- a/src/crosschain/BTC.java +++ b/src/main/java/crosschain/BTC.java @@ -30,7 +30,6 @@ import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.StoredBlock; import org.bitcoinj.core.Transaction; import org.bitcoinj.core.TransactionOutput; -import org.bitcoinj.core.Utils; import org.bitcoinj.core.VerificationException; import org.bitcoinj.core.listeners.NewBestBlockListener; import org.bitcoinj.net.discovery.DnsDiscovery; @@ -109,6 +108,7 @@ public class BTC { } } + @SuppressWarnings("unused") public void saveAsBinary(File file) throws IOException { try (final FileOutputStream fileOutputStream = new FileOutputStream(file, false)) { MessageDigest digest = Sha256Hash.newDigest(); diff --git a/src/data/PaymentData.java b/src/main/java/data/PaymentData.java similarity index 100% rename from src/data/PaymentData.java rename to src/main/java/data/PaymentData.java diff --git a/src/data/account/AccountBalanceData.java b/src/main/java/data/account/AccountBalanceData.java similarity index 100% rename from src/data/account/AccountBalanceData.java rename to src/main/java/data/account/AccountBalanceData.java diff --git a/src/data/account/AccountData.java b/src/main/java/data/account/AccountData.java similarity index 100% rename from src/data/account/AccountData.java rename to src/main/java/data/account/AccountData.java diff --git a/src/data/assets/AssetData.java b/src/main/java/data/assets/AssetData.java similarity index 100% rename from src/data/assets/AssetData.java rename to src/main/java/data/assets/AssetData.java diff --git a/src/data/assets/OrderData.java b/src/main/java/data/assets/OrderData.java similarity index 100% rename from src/data/assets/OrderData.java rename to src/main/java/data/assets/OrderData.java diff --git a/src/data/assets/TradeData.java b/src/main/java/data/assets/TradeData.java similarity index 100% rename from src/data/assets/TradeData.java rename to src/main/java/data/assets/TradeData.java diff --git a/src/data/at/ATData.java b/src/main/java/data/at/ATData.java similarity index 100% rename from src/data/at/ATData.java rename to src/main/java/data/at/ATData.java diff --git a/src/data/at/ATStateData.java b/src/main/java/data/at/ATStateData.java similarity index 100% rename from src/data/at/ATStateData.java rename to src/main/java/data/at/ATStateData.java diff --git a/src/data/block/BlockData.java b/src/main/java/data/block/BlockData.java similarity index 100% rename from src/data/block/BlockData.java rename to src/main/java/data/block/BlockData.java diff --git a/src/data/block/BlockTransactionData.java b/src/main/java/data/block/BlockTransactionData.java similarity index 100% rename from src/data/block/BlockTransactionData.java rename to src/main/java/data/block/BlockTransactionData.java diff --git a/src/data/naming/NameData.java b/src/main/java/data/naming/NameData.java similarity index 100% rename from src/data/naming/NameData.java rename to src/main/java/data/naming/NameData.java diff --git a/src/data/package-info.java b/src/main/java/data/package-info.java similarity index 100% rename from src/data/package-info.java rename to src/main/java/data/package-info.java diff --git a/src/data/transaction/ATTransactionData.java b/src/main/java/data/transaction/ATTransactionData.java similarity index 100% rename from src/data/transaction/ATTransactionData.java rename to src/main/java/data/transaction/ATTransactionData.java diff --git a/src/data/transaction/ArbitraryTransactionData.java b/src/main/java/data/transaction/ArbitraryTransactionData.java similarity index 100% rename from src/data/transaction/ArbitraryTransactionData.java rename to src/main/java/data/transaction/ArbitraryTransactionData.java diff --git a/src/data/transaction/BuyNameTransactionData.java b/src/main/java/data/transaction/BuyNameTransactionData.java similarity index 100% rename from src/data/transaction/BuyNameTransactionData.java rename to src/main/java/data/transaction/BuyNameTransactionData.java diff --git a/src/data/transaction/CancelOrderTransactionData.java b/src/main/java/data/transaction/CancelOrderTransactionData.java similarity index 100% rename from src/data/transaction/CancelOrderTransactionData.java rename to src/main/java/data/transaction/CancelOrderTransactionData.java diff --git a/src/data/transaction/CancelSellNameTransactionData.java b/src/main/java/data/transaction/CancelSellNameTransactionData.java similarity index 100% rename from src/data/transaction/CancelSellNameTransactionData.java rename to src/main/java/data/transaction/CancelSellNameTransactionData.java diff --git a/src/data/transaction/CreateOrderTransactionData.java b/src/main/java/data/transaction/CreateOrderTransactionData.java similarity index 100% rename from src/data/transaction/CreateOrderTransactionData.java rename to src/main/java/data/transaction/CreateOrderTransactionData.java diff --git a/src/data/transaction/CreatePollTransactionData.java b/src/main/java/data/transaction/CreatePollTransactionData.java similarity index 100% rename from src/data/transaction/CreatePollTransactionData.java rename to src/main/java/data/transaction/CreatePollTransactionData.java diff --git a/src/data/transaction/DeployATTransactionData.java b/src/main/java/data/transaction/DeployATTransactionData.java similarity index 100% rename from src/data/transaction/DeployATTransactionData.java rename to src/main/java/data/transaction/DeployATTransactionData.java diff --git a/src/data/transaction/GenesisTransactionData.java b/src/main/java/data/transaction/GenesisTransactionData.java similarity index 100% rename from src/data/transaction/GenesisTransactionData.java rename to src/main/java/data/transaction/GenesisTransactionData.java diff --git a/src/data/transaction/IssueAssetTransactionData.java b/src/main/java/data/transaction/IssueAssetTransactionData.java similarity index 100% rename from src/data/transaction/IssueAssetTransactionData.java rename to src/main/java/data/transaction/IssueAssetTransactionData.java diff --git a/src/data/transaction/MessageTransactionData.java b/src/main/java/data/transaction/MessageTransactionData.java similarity index 100% rename from src/data/transaction/MessageTransactionData.java rename to src/main/java/data/transaction/MessageTransactionData.java diff --git a/src/data/transaction/MultiPaymentTransactionData.java b/src/main/java/data/transaction/MultiPaymentTransactionData.java similarity index 100% rename from src/data/transaction/MultiPaymentTransactionData.java rename to src/main/java/data/transaction/MultiPaymentTransactionData.java diff --git a/src/data/transaction/PaymentTransactionData.java b/src/main/java/data/transaction/PaymentTransactionData.java similarity index 100% rename from src/data/transaction/PaymentTransactionData.java rename to src/main/java/data/transaction/PaymentTransactionData.java diff --git a/src/data/transaction/RegisterNameTransactionData.java b/src/main/java/data/transaction/RegisterNameTransactionData.java similarity index 100% rename from src/data/transaction/RegisterNameTransactionData.java rename to src/main/java/data/transaction/RegisterNameTransactionData.java diff --git a/src/data/transaction/SellNameTransactionData.java b/src/main/java/data/transaction/SellNameTransactionData.java similarity index 100% rename from src/data/transaction/SellNameTransactionData.java rename to src/main/java/data/transaction/SellNameTransactionData.java diff --git a/src/data/transaction/TransactionData.java b/src/main/java/data/transaction/TransactionData.java similarity index 100% rename from src/data/transaction/TransactionData.java rename to src/main/java/data/transaction/TransactionData.java diff --git a/src/data/transaction/TransferAssetTransactionData.java b/src/main/java/data/transaction/TransferAssetTransactionData.java similarity index 100% rename from src/data/transaction/TransferAssetTransactionData.java rename to src/main/java/data/transaction/TransferAssetTransactionData.java diff --git a/src/data/transaction/UpdateNameTransactionData.java b/src/main/java/data/transaction/UpdateNameTransactionData.java similarity index 100% rename from src/data/transaction/UpdateNameTransactionData.java rename to src/main/java/data/transaction/UpdateNameTransactionData.java diff --git a/src/data/transaction/VoteOnPollTransactionData.java b/src/main/java/data/transaction/VoteOnPollTransactionData.java similarity index 100% rename from src/data/transaction/VoteOnPollTransactionData.java rename to src/main/java/data/transaction/VoteOnPollTransactionData.java diff --git a/src/data/voting/PollData.java b/src/main/java/data/voting/PollData.java similarity index 100% rename from src/data/voting/PollData.java rename to src/main/java/data/voting/PollData.java diff --git a/src/data/voting/PollOptionData.java b/src/main/java/data/voting/PollOptionData.java similarity index 100% rename from src/data/voting/PollOptionData.java rename to src/main/java/data/voting/PollOptionData.java diff --git a/src/data/voting/VoteOnPollData.java b/src/main/java/data/voting/VoteOnPollData.java similarity index 100% rename from src/data/voting/VoteOnPollData.java rename to src/main/java/data/voting/VoteOnPollData.java diff --git a/src/database/NoDataFoundException.java b/src/main/java/database/NoDataFoundException.java similarity index 100% rename from src/database/NoDataFoundException.java rename to src/main/java/database/NoDataFoundException.java diff --git a/src/main/java/globalization/BIP39WordList.java b/src/main/java/globalization/BIP39WordList.java new file mode 100644 index 00000000..3e5a8d32 --- /dev/null +++ b/src/main/java/globalization/BIP39WordList.java @@ -0,0 +1,52 @@ +package globalization; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** Providing multi-language BIP39 word lists, downloaded from https://github.com/bitcoin/bips/tree/master/bip-0039 */ +public enum BIP39WordList { + INSTANCE; + + private Logger LOGGER = LogManager.getLogger(BIP39WordList.class); + + private Map> wordListsByLang; + + private BIP39WordList() { + wordListsByLang = new HashMap<>(); + } + + public synchronized List getByLang(String lang) { + List wordList = wordListsByLang.get(lang); + + if (wordList == null) { + ClassLoader loader = this.getClass().getClassLoader(); + + try (InputStream inputStream = loader.getResourceAsStream("BIP39/wordlist_" + lang + ".txt")) { + if (inputStream == null) { + LOGGER.warn("Can't locate '" + lang + "' BIP39 wordlist"); + return null; + } + + wordList = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.toList()); + } catch (IOException e) { + LOGGER.warn("Error reading '" + lang + "' BIP39 wordlist", e); + return null; + } + + wordListsByLang.put(lang, wordList); + } + + return Collections.unmodifiableList(wordList); + } + +} diff --git a/src/main/java/globalization/Translator.java b/src/main/java/globalization/Translator.java new file mode 100644 index 00000000..15291f91 --- /dev/null +++ b/src/main/java/globalization/Translator.java @@ -0,0 +1,52 @@ +package globalization; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public enum Translator { + INSTANCE; + + private final Logger LOGGER = LogManager.getLogger(Translator.class); + private final String DEFAULT_LANG = Locale.getDefault().getLanguage(); + + private final Map resourceBundles = new HashMap<>(); + + private synchronized ResourceBundle getOrLoadResourceBundle(String className, String lang) { + final String bundleKey = className + ":" + lang; + + ResourceBundle resourceBundle = resourceBundles.get(bundleKey); + if (resourceBundle != null) + return resourceBundle; + + try { + resourceBundle = ResourceBundle.getBundle("i18n." + className, Locale.forLanguageTag(lang)); + } catch (MissingResourceException e) { + LOGGER.warn("Can't locate '" + lang + "' translation resource bundle for " + className, e); + return null; + } + + resourceBundles.put(bundleKey, resourceBundle); + + return resourceBundle; + } + + public String translate(final String className, final String key) { + return this.translate(className, DEFAULT_LANG, key); + } + + public String translate(final String className, final String lang, final String key, final Object... args) { + ResourceBundle resourceBundle = getOrLoadResourceBundle(className, lang); + + if (resourceBundle == null || !resourceBundle.containsKey(key)) + return "!!" + lang + ":" + className + "." + key + "!!"; + + return String.format(resourceBundle.getString(key), args); + } + +} diff --git a/src/org/whispersystems/curve25519/java/Arrays.java b/src/main/java/org/whispersystems/curve25519/java/Arrays.java similarity index 100% rename from src/org/whispersystems/curve25519/java/Arrays.java rename to src/main/java/org/whispersystems/curve25519/java/Arrays.java diff --git a/src/org/whispersystems/curve25519/java/Sha512.java b/src/main/java/org/whispersystems/curve25519/java/Sha512.java similarity index 100% rename from src/org/whispersystems/curve25519/java/Sha512.java rename to src/main/java/org/whispersystems/curve25519/java/Sha512.java diff --git a/src/org/whispersystems/curve25519/java/crypto_verify_32.java b/src/main/java/org/whispersystems/curve25519/java/crypto_verify_32.java similarity index 100% rename from src/org/whispersystems/curve25519/java/crypto_verify_32.java rename to src/main/java/org/whispersystems/curve25519/java/crypto_verify_32.java diff --git a/src/org/whispersystems/curve25519/java/curve_sigs.java b/src/main/java/org/whispersystems/curve25519/java/curve_sigs.java similarity index 100% rename from src/org/whispersystems/curve25519/java/curve_sigs.java rename to src/main/java/org/whispersystems/curve25519/java/curve_sigs.java diff --git a/src/org/whispersystems/curve25519/java/fe_0.java b/src/main/java/org/whispersystems/curve25519/java/fe_0.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_0.java rename to src/main/java/org/whispersystems/curve25519/java/fe_0.java diff --git a/src/org/whispersystems/curve25519/java/fe_1.java b/src/main/java/org/whispersystems/curve25519/java/fe_1.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_1.java rename to src/main/java/org/whispersystems/curve25519/java/fe_1.java diff --git a/src/org/whispersystems/curve25519/java/fe_add.java b/src/main/java/org/whispersystems/curve25519/java/fe_add.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_add.java rename to src/main/java/org/whispersystems/curve25519/java/fe_add.java diff --git a/src/org/whispersystems/curve25519/java/fe_cmov.java b/src/main/java/org/whispersystems/curve25519/java/fe_cmov.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_cmov.java rename to src/main/java/org/whispersystems/curve25519/java/fe_cmov.java diff --git a/src/org/whispersystems/curve25519/java/fe_copy.java b/src/main/java/org/whispersystems/curve25519/java/fe_copy.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_copy.java rename to src/main/java/org/whispersystems/curve25519/java/fe_copy.java diff --git a/src/org/whispersystems/curve25519/java/fe_cswap.java b/src/main/java/org/whispersystems/curve25519/java/fe_cswap.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_cswap.java rename to src/main/java/org/whispersystems/curve25519/java/fe_cswap.java diff --git a/src/org/whispersystems/curve25519/java/fe_frombytes.java b/src/main/java/org/whispersystems/curve25519/java/fe_frombytes.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_frombytes.java rename to src/main/java/org/whispersystems/curve25519/java/fe_frombytes.java diff --git a/src/org/whispersystems/curve25519/java/fe_invert.java b/src/main/java/org/whispersystems/curve25519/java/fe_invert.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_invert.java rename to src/main/java/org/whispersystems/curve25519/java/fe_invert.java diff --git a/src/org/whispersystems/curve25519/java/fe_isnegative.java b/src/main/java/org/whispersystems/curve25519/java/fe_isnegative.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_isnegative.java rename to src/main/java/org/whispersystems/curve25519/java/fe_isnegative.java diff --git a/src/org/whispersystems/curve25519/java/fe_isnonzero.java b/src/main/java/org/whispersystems/curve25519/java/fe_isnonzero.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_isnonzero.java rename to src/main/java/org/whispersystems/curve25519/java/fe_isnonzero.java diff --git a/src/org/whispersystems/curve25519/java/fe_mul.java b/src/main/java/org/whispersystems/curve25519/java/fe_mul.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_mul.java rename to src/main/java/org/whispersystems/curve25519/java/fe_mul.java diff --git a/src/org/whispersystems/curve25519/java/fe_mul121666.java b/src/main/java/org/whispersystems/curve25519/java/fe_mul121666.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_mul121666.java rename to src/main/java/org/whispersystems/curve25519/java/fe_mul121666.java diff --git a/src/org/whispersystems/curve25519/java/fe_neg.java b/src/main/java/org/whispersystems/curve25519/java/fe_neg.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_neg.java rename to src/main/java/org/whispersystems/curve25519/java/fe_neg.java diff --git a/src/org/whispersystems/curve25519/java/fe_pow22523.java b/src/main/java/org/whispersystems/curve25519/java/fe_pow22523.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_pow22523.java rename to src/main/java/org/whispersystems/curve25519/java/fe_pow22523.java diff --git a/src/org/whispersystems/curve25519/java/fe_sq.java b/src/main/java/org/whispersystems/curve25519/java/fe_sq.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_sq.java rename to src/main/java/org/whispersystems/curve25519/java/fe_sq.java diff --git a/src/org/whispersystems/curve25519/java/fe_sq2.java b/src/main/java/org/whispersystems/curve25519/java/fe_sq2.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_sq2.java rename to src/main/java/org/whispersystems/curve25519/java/fe_sq2.java diff --git a/src/org/whispersystems/curve25519/java/fe_sub.java b/src/main/java/org/whispersystems/curve25519/java/fe_sub.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_sub.java rename to src/main/java/org/whispersystems/curve25519/java/fe_sub.java diff --git a/src/org/whispersystems/curve25519/java/fe_tobytes.java b/src/main/java/org/whispersystems/curve25519/java/fe_tobytes.java similarity index 100% rename from src/org/whispersystems/curve25519/java/fe_tobytes.java rename to src/main/java/org/whispersystems/curve25519/java/fe_tobytes.java diff --git a/src/org/whispersystems/curve25519/java/ge_add.java b/src/main/java/org/whispersystems/curve25519/java/ge_add.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_add.java rename to src/main/java/org/whispersystems/curve25519/java/ge_add.java diff --git a/src/org/whispersystems/curve25519/java/ge_cached.java b/src/main/java/org/whispersystems/curve25519/java/ge_cached.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_cached.java rename to src/main/java/org/whispersystems/curve25519/java/ge_cached.java diff --git a/src/org/whispersystems/curve25519/java/ge_double_scalarmult.java b/src/main/java/org/whispersystems/curve25519/java/ge_double_scalarmult.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_double_scalarmult.java rename to src/main/java/org/whispersystems/curve25519/java/ge_double_scalarmult.java diff --git a/src/org/whispersystems/curve25519/java/ge_frombytes.java b/src/main/java/org/whispersystems/curve25519/java/ge_frombytes.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_frombytes.java rename to src/main/java/org/whispersystems/curve25519/java/ge_frombytes.java diff --git a/src/org/whispersystems/curve25519/java/ge_madd.java b/src/main/java/org/whispersystems/curve25519/java/ge_madd.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_madd.java rename to src/main/java/org/whispersystems/curve25519/java/ge_madd.java diff --git a/src/org/whispersystems/curve25519/java/ge_msub.java b/src/main/java/org/whispersystems/curve25519/java/ge_msub.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_msub.java rename to src/main/java/org/whispersystems/curve25519/java/ge_msub.java diff --git a/src/org/whispersystems/curve25519/java/ge_p1p1.java b/src/main/java/org/whispersystems/curve25519/java/ge_p1p1.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p1p1.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p1p1.java diff --git a/src/org/whispersystems/curve25519/java/ge_p1p1_to_p2.java b/src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p2.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p1p1_to_p2.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p2.java diff --git a/src/org/whispersystems/curve25519/java/ge_p1p1_to_p3.java b/src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p3.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p1p1_to_p3.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p3.java diff --git a/src/org/whispersystems/curve25519/java/ge_p2.java b/src/main/java/org/whispersystems/curve25519/java/ge_p2.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p2.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p2.java diff --git a/src/org/whispersystems/curve25519/java/ge_p2_0.java b/src/main/java/org/whispersystems/curve25519/java/ge_p2_0.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p2_0.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p2_0.java diff --git a/src/org/whispersystems/curve25519/java/ge_p2_dbl.java b/src/main/java/org/whispersystems/curve25519/java/ge_p2_dbl.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p2_dbl.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p2_dbl.java diff --git a/src/org/whispersystems/curve25519/java/ge_p3.java b/src/main/java/org/whispersystems/curve25519/java/ge_p3.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p3.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p3.java diff --git a/src/org/whispersystems/curve25519/java/ge_p3_0.java b/src/main/java/org/whispersystems/curve25519/java/ge_p3_0.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p3_0.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p3_0.java diff --git a/src/org/whispersystems/curve25519/java/ge_p3_dbl.java b/src/main/java/org/whispersystems/curve25519/java/ge_p3_dbl.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p3_dbl.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p3_dbl.java diff --git a/src/org/whispersystems/curve25519/java/ge_p3_to_cached.java b/src/main/java/org/whispersystems/curve25519/java/ge_p3_to_cached.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p3_to_cached.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p3_to_cached.java diff --git a/src/org/whispersystems/curve25519/java/ge_p3_to_p2.java b/src/main/java/org/whispersystems/curve25519/java/ge_p3_to_p2.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p3_to_p2.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p3_to_p2.java diff --git a/src/org/whispersystems/curve25519/java/ge_p3_tobytes.java b/src/main/java/org/whispersystems/curve25519/java/ge_p3_tobytes.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_p3_tobytes.java rename to src/main/java/org/whispersystems/curve25519/java/ge_p3_tobytes.java diff --git a/src/org/whispersystems/curve25519/java/ge_precomp.java b/src/main/java/org/whispersystems/curve25519/java/ge_precomp.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_precomp.java rename to src/main/java/org/whispersystems/curve25519/java/ge_precomp.java diff --git a/src/org/whispersystems/curve25519/java/ge_precomp_0.java b/src/main/java/org/whispersystems/curve25519/java/ge_precomp_0.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_precomp_0.java rename to src/main/java/org/whispersystems/curve25519/java/ge_precomp_0.java diff --git a/src/org/whispersystems/curve25519/java/ge_precomp_base_0_7.java b/src/main/java/org/whispersystems/curve25519/java/ge_precomp_base_0_7.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_precomp_base_0_7.java rename to src/main/java/org/whispersystems/curve25519/java/ge_precomp_base_0_7.java diff --git a/src/org/whispersystems/curve25519/java/ge_precomp_base_16_23.java b/src/main/java/org/whispersystems/curve25519/java/ge_precomp_base_16_23.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_precomp_base_16_23.java rename to src/main/java/org/whispersystems/curve25519/java/ge_precomp_base_16_23.java diff --git a/src/org/whispersystems/curve25519/java/ge_precomp_base_24_31.java b/src/main/java/org/whispersystems/curve25519/java/ge_precomp_base_24_31.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_precomp_base_24_31.java rename to src/main/java/org/whispersystems/curve25519/java/ge_precomp_base_24_31.java diff --git a/src/org/whispersystems/curve25519/java/ge_precomp_base_8_15.java b/src/main/java/org/whispersystems/curve25519/java/ge_precomp_base_8_15.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_precomp_base_8_15.java rename to src/main/java/org/whispersystems/curve25519/java/ge_precomp_base_8_15.java diff --git a/src/org/whispersystems/curve25519/java/ge_scalarmult_base.java b/src/main/java/org/whispersystems/curve25519/java/ge_scalarmult_base.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_scalarmult_base.java rename to src/main/java/org/whispersystems/curve25519/java/ge_scalarmult_base.java diff --git a/src/org/whispersystems/curve25519/java/ge_sub.java b/src/main/java/org/whispersystems/curve25519/java/ge_sub.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_sub.java rename to src/main/java/org/whispersystems/curve25519/java/ge_sub.java diff --git a/src/org/whispersystems/curve25519/java/ge_tobytes.java b/src/main/java/org/whispersystems/curve25519/java/ge_tobytes.java similarity index 100% rename from src/org/whispersystems/curve25519/java/ge_tobytes.java rename to src/main/java/org/whispersystems/curve25519/java/ge_tobytes.java diff --git a/src/org/whispersystems/curve25519/java/open.java b/src/main/java/org/whispersystems/curve25519/java/open.java similarity index 100% rename from src/org/whispersystems/curve25519/java/open.java rename to src/main/java/org/whispersystems/curve25519/java/open.java diff --git a/src/org/whispersystems/curve25519/java/sc_muladd.java b/src/main/java/org/whispersystems/curve25519/java/sc_muladd.java similarity index 100% rename from src/org/whispersystems/curve25519/java/sc_muladd.java rename to src/main/java/org/whispersystems/curve25519/java/sc_muladd.java diff --git a/src/org/whispersystems/curve25519/java/sc_reduce.java b/src/main/java/org/whispersystems/curve25519/java/sc_reduce.java similarity index 100% rename from src/org/whispersystems/curve25519/java/sc_reduce.java rename to src/main/java/org/whispersystems/curve25519/java/sc_reduce.java diff --git a/src/org/whispersystems/curve25519/java/scalarmult.java b/src/main/java/org/whispersystems/curve25519/java/scalarmult.java similarity index 100% rename from src/org/whispersystems/curve25519/java/scalarmult.java rename to src/main/java/org/whispersystems/curve25519/java/scalarmult.java diff --git a/src/org/whispersystems/curve25519/java/sign_modified.java b/src/main/java/org/whispersystems/curve25519/java/sign_modified.java similarity index 100% rename from src/org/whispersystems/curve25519/java/sign_modified.java rename to src/main/java/org/whispersystems/curve25519/java/sign_modified.java diff --git a/src/orphan.java b/src/main/java/orphan.java similarity index 100% rename from src/orphan.java rename to src/main/java/orphan.java diff --git a/src/qora/account/Account.java b/src/main/java/qora/account/Account.java similarity index 100% rename from src/qora/account/Account.java rename to src/main/java/qora/account/Account.java diff --git a/src/qora/account/GenesisAccount.java b/src/main/java/qora/account/GenesisAccount.java similarity index 100% rename from src/qora/account/GenesisAccount.java rename to src/main/java/qora/account/GenesisAccount.java diff --git a/src/qora/account/PrivateKeyAccount.java b/src/main/java/qora/account/PrivateKeyAccount.java similarity index 100% rename from src/qora/account/PrivateKeyAccount.java rename to src/main/java/qora/account/PrivateKeyAccount.java diff --git a/src/qora/account/PublicKeyAccount.java b/src/main/java/qora/account/PublicKeyAccount.java similarity index 100% rename from src/qora/account/PublicKeyAccount.java rename to src/main/java/qora/account/PublicKeyAccount.java diff --git a/src/qora/assets/Asset.java b/src/main/java/qora/assets/Asset.java similarity index 100% rename from src/qora/assets/Asset.java rename to src/main/java/qora/assets/Asset.java diff --git a/src/qora/assets/Order.java b/src/main/java/qora/assets/Order.java similarity index 100% rename from src/qora/assets/Order.java rename to src/main/java/qora/assets/Order.java diff --git a/src/qora/assets/Trade.java b/src/main/java/qora/assets/Trade.java similarity index 100% rename from src/qora/assets/Trade.java rename to src/main/java/qora/assets/Trade.java diff --git a/src/qora/at/AT.java b/src/main/java/qora/at/AT.java similarity index 100% rename from src/qora/at/AT.java rename to src/main/java/qora/at/AT.java diff --git a/src/qora/at/BlockchainAPI.java b/src/main/java/qora/at/BlockchainAPI.java similarity index 100% rename from src/qora/at/BlockchainAPI.java rename to src/main/java/qora/at/BlockchainAPI.java diff --git a/src/qora/at/QoraATAPI.java b/src/main/java/qora/at/QoraATAPI.java similarity index 100% rename from src/qora/at/QoraATAPI.java rename to src/main/java/qora/at/QoraATAPI.java diff --git a/src/qora/at/QoraATLogger.java b/src/main/java/qora/at/QoraATLogger.java similarity index 100% rename from src/qora/at/QoraATLogger.java rename to src/main/java/qora/at/QoraATLogger.java diff --git a/src/qora/at/QoraFunctionCode.java b/src/main/java/qora/at/QoraFunctionCode.java similarity index 100% rename from src/qora/at/QoraFunctionCode.java rename to src/main/java/qora/at/QoraFunctionCode.java diff --git a/src/qora/block/Block.java b/src/main/java/qora/block/Block.java similarity index 100% rename from src/qora/block/Block.java rename to src/main/java/qora/block/Block.java diff --git a/src/qora/block/BlockChain.java b/src/main/java/qora/block/BlockChain.java similarity index 100% rename from src/qora/block/BlockChain.java rename to src/main/java/qora/block/BlockChain.java diff --git a/src/qora/block/BlockGenerator.java b/src/main/java/qora/block/BlockGenerator.java similarity index 100% rename from src/qora/block/BlockGenerator.java rename to src/main/java/qora/block/BlockGenerator.java diff --git a/src/qora/block/GenesisBlock.java b/src/main/java/qora/block/GenesisBlock.java similarity index 100% rename from src/qora/block/GenesisBlock.java rename to src/main/java/qora/block/GenesisBlock.java diff --git a/src/qora/crypto/BrokenMD160.java b/src/main/java/qora/crypto/BrokenMD160.java similarity index 100% rename from src/qora/crypto/BrokenMD160.java rename to src/main/java/qora/crypto/BrokenMD160.java diff --git a/src/qora/crypto/Crypto.java b/src/main/java/qora/crypto/Crypto.java similarity index 100% rename from src/qora/crypto/Crypto.java rename to src/main/java/qora/crypto/Crypto.java diff --git a/src/qora/crypto/CryptoBytes.java b/src/main/java/qora/crypto/CryptoBytes.java similarity index 100% rename from src/qora/crypto/CryptoBytes.java rename to src/main/java/qora/crypto/CryptoBytes.java diff --git a/src/qora/crypto/Ed25519.java b/src/main/java/qora/crypto/Ed25519.java similarity index 100% rename from src/qora/crypto/Ed25519.java rename to src/main/java/qora/crypto/Ed25519.java diff --git a/src/qora/naming/Name.java b/src/main/java/qora/naming/Name.java similarity index 100% rename from src/qora/naming/Name.java rename to src/main/java/qora/naming/Name.java diff --git a/src/qora/payment/Payment.java b/src/main/java/qora/payment/Payment.java similarity index 100% rename from src/qora/payment/Payment.java rename to src/main/java/qora/payment/Payment.java diff --git a/src/qora/transaction/ATTransaction.java b/src/main/java/qora/transaction/ATTransaction.java similarity index 100% rename from src/qora/transaction/ATTransaction.java rename to src/main/java/qora/transaction/ATTransaction.java diff --git a/src/qora/transaction/ArbitraryTransaction.java b/src/main/java/qora/transaction/ArbitraryTransaction.java similarity index 100% rename from src/qora/transaction/ArbitraryTransaction.java rename to src/main/java/qora/transaction/ArbitraryTransaction.java diff --git a/src/qora/transaction/BuyNameTransaction.java b/src/main/java/qora/transaction/BuyNameTransaction.java similarity index 100% rename from src/qora/transaction/BuyNameTransaction.java rename to src/main/java/qora/transaction/BuyNameTransaction.java diff --git a/src/qora/transaction/CancelOrderTransaction.java b/src/main/java/qora/transaction/CancelOrderTransaction.java similarity index 100% rename from src/qora/transaction/CancelOrderTransaction.java rename to src/main/java/qora/transaction/CancelOrderTransaction.java diff --git a/src/qora/transaction/CancelSellNameTransaction.java b/src/main/java/qora/transaction/CancelSellNameTransaction.java similarity index 100% rename from src/qora/transaction/CancelSellNameTransaction.java rename to src/main/java/qora/transaction/CancelSellNameTransaction.java diff --git a/src/qora/transaction/CreateOrderTransaction.java b/src/main/java/qora/transaction/CreateOrderTransaction.java similarity index 100% rename from src/qora/transaction/CreateOrderTransaction.java rename to src/main/java/qora/transaction/CreateOrderTransaction.java diff --git a/src/qora/transaction/CreatePollTransaction.java b/src/main/java/qora/transaction/CreatePollTransaction.java similarity index 100% rename from src/qora/transaction/CreatePollTransaction.java rename to src/main/java/qora/transaction/CreatePollTransaction.java diff --git a/src/qora/transaction/DeployATTransaction.java b/src/main/java/qora/transaction/DeployATTransaction.java similarity index 100% rename from src/qora/transaction/DeployATTransaction.java rename to src/main/java/qora/transaction/DeployATTransaction.java diff --git a/src/qora/transaction/GenesisTransaction.java b/src/main/java/qora/transaction/GenesisTransaction.java similarity index 100% rename from src/qora/transaction/GenesisTransaction.java rename to src/main/java/qora/transaction/GenesisTransaction.java diff --git a/src/qora/transaction/IssueAssetTransaction.java b/src/main/java/qora/transaction/IssueAssetTransaction.java similarity index 100% rename from src/qora/transaction/IssueAssetTransaction.java rename to src/main/java/qora/transaction/IssueAssetTransaction.java diff --git a/src/qora/transaction/MessageTransaction.java b/src/main/java/qora/transaction/MessageTransaction.java similarity index 100% rename from src/qora/transaction/MessageTransaction.java rename to src/main/java/qora/transaction/MessageTransaction.java diff --git a/src/qora/transaction/MultiPaymentTransaction.java b/src/main/java/qora/transaction/MultiPaymentTransaction.java similarity index 100% rename from src/qora/transaction/MultiPaymentTransaction.java rename to src/main/java/qora/transaction/MultiPaymentTransaction.java diff --git a/src/qora/transaction/PaymentTransaction.java b/src/main/java/qora/transaction/PaymentTransaction.java similarity index 100% rename from src/qora/transaction/PaymentTransaction.java rename to src/main/java/qora/transaction/PaymentTransaction.java diff --git a/src/qora/transaction/RegisterNameTransaction.java b/src/main/java/qora/transaction/RegisterNameTransaction.java similarity index 100% rename from src/qora/transaction/RegisterNameTransaction.java rename to src/main/java/qora/transaction/RegisterNameTransaction.java diff --git a/src/qora/transaction/SellNameTransaction.java b/src/main/java/qora/transaction/SellNameTransaction.java similarity index 100% rename from src/qora/transaction/SellNameTransaction.java rename to src/main/java/qora/transaction/SellNameTransaction.java diff --git a/src/qora/transaction/Transaction.java b/src/main/java/qora/transaction/Transaction.java similarity index 100% rename from src/qora/transaction/Transaction.java rename to src/main/java/qora/transaction/Transaction.java diff --git a/src/qora/transaction/TransferAssetTransaction.java b/src/main/java/qora/transaction/TransferAssetTransaction.java similarity index 100% rename from src/qora/transaction/TransferAssetTransaction.java rename to src/main/java/qora/transaction/TransferAssetTransaction.java diff --git a/src/qora/transaction/UpdateNameTransaction.java b/src/main/java/qora/transaction/UpdateNameTransaction.java similarity index 100% rename from src/qora/transaction/UpdateNameTransaction.java rename to src/main/java/qora/transaction/UpdateNameTransaction.java diff --git a/src/qora/transaction/VoteOnPollTransaction.java b/src/main/java/qora/transaction/VoteOnPollTransaction.java similarity index 100% rename from src/qora/transaction/VoteOnPollTransaction.java rename to src/main/java/qora/transaction/VoteOnPollTransaction.java diff --git a/src/qora/voting/Poll.java b/src/main/java/qora/voting/Poll.java similarity index 100% rename from src/qora/voting/Poll.java rename to src/main/java/qora/voting/Poll.java diff --git a/src/repository/ATRepository.java b/src/main/java/repository/ATRepository.java similarity index 100% rename from src/repository/ATRepository.java rename to src/main/java/repository/ATRepository.java diff --git a/src/repository/AccountRepository.java b/src/main/java/repository/AccountRepository.java similarity index 100% rename from src/repository/AccountRepository.java rename to src/main/java/repository/AccountRepository.java diff --git a/src/repository/AssetRepository.java b/src/main/java/repository/AssetRepository.java similarity index 100% rename from src/repository/AssetRepository.java rename to src/main/java/repository/AssetRepository.java diff --git a/src/repository/BlockRepository.java b/src/main/java/repository/BlockRepository.java similarity index 100% rename from src/repository/BlockRepository.java rename to src/main/java/repository/BlockRepository.java diff --git a/src/repository/DataException.java b/src/main/java/repository/DataException.java similarity index 100% rename from src/repository/DataException.java rename to src/main/java/repository/DataException.java diff --git a/src/repository/NameRepository.java b/src/main/java/repository/NameRepository.java similarity index 100% rename from src/repository/NameRepository.java rename to src/main/java/repository/NameRepository.java diff --git a/src/repository/Repository.java b/src/main/java/repository/Repository.java similarity index 100% rename from src/repository/Repository.java rename to src/main/java/repository/Repository.java diff --git a/src/repository/RepositoryFactory.java b/src/main/java/repository/RepositoryFactory.java similarity index 100% rename from src/repository/RepositoryFactory.java rename to src/main/java/repository/RepositoryFactory.java diff --git a/src/repository/RepositoryManager.java b/src/main/java/repository/RepositoryManager.java similarity index 100% rename from src/repository/RepositoryManager.java rename to src/main/java/repository/RepositoryManager.java diff --git a/src/repository/TransactionRepository.java b/src/main/java/repository/TransactionRepository.java similarity index 100% rename from src/repository/TransactionRepository.java rename to src/main/java/repository/TransactionRepository.java diff --git a/src/repository/VotingRepository.java b/src/main/java/repository/VotingRepository.java similarity index 100% rename from src/repository/VotingRepository.java rename to src/main/java/repository/VotingRepository.java diff --git a/src/repository/hsqldb/HSQLDBATRepository.java b/src/main/java/repository/hsqldb/HSQLDBATRepository.java similarity index 100% rename from src/repository/hsqldb/HSQLDBATRepository.java rename to src/main/java/repository/hsqldb/HSQLDBATRepository.java diff --git a/src/repository/hsqldb/HSQLDBAccountRepository.java b/src/main/java/repository/hsqldb/HSQLDBAccountRepository.java similarity index 100% rename from src/repository/hsqldb/HSQLDBAccountRepository.java rename to src/main/java/repository/hsqldb/HSQLDBAccountRepository.java diff --git a/src/repository/hsqldb/HSQLDBAssetRepository.java b/src/main/java/repository/hsqldb/HSQLDBAssetRepository.java similarity index 100% rename from src/repository/hsqldb/HSQLDBAssetRepository.java rename to src/main/java/repository/hsqldb/HSQLDBAssetRepository.java diff --git a/src/repository/hsqldb/HSQLDBBlockRepository.java b/src/main/java/repository/hsqldb/HSQLDBBlockRepository.java similarity index 100% rename from src/repository/hsqldb/HSQLDBBlockRepository.java rename to src/main/java/repository/hsqldb/HSQLDBBlockRepository.java diff --git a/src/repository/hsqldb/HSQLDBDatabaseUpdates.java b/src/main/java/repository/hsqldb/HSQLDBDatabaseUpdates.java similarity index 100% rename from src/repository/hsqldb/HSQLDBDatabaseUpdates.java rename to src/main/java/repository/hsqldb/HSQLDBDatabaseUpdates.java diff --git a/src/repository/hsqldb/HSQLDBNameRepository.java b/src/main/java/repository/hsqldb/HSQLDBNameRepository.java similarity index 100% rename from src/repository/hsqldb/HSQLDBNameRepository.java rename to src/main/java/repository/hsqldb/HSQLDBNameRepository.java diff --git a/src/repository/hsqldb/HSQLDBRepository.java b/src/main/java/repository/hsqldb/HSQLDBRepository.java similarity index 100% rename from src/repository/hsqldb/HSQLDBRepository.java rename to src/main/java/repository/hsqldb/HSQLDBRepository.java diff --git a/src/repository/hsqldb/HSQLDBRepositoryFactory.java b/src/main/java/repository/hsqldb/HSQLDBRepositoryFactory.java similarity index 100% rename from src/repository/hsqldb/HSQLDBRepositoryFactory.java rename to src/main/java/repository/hsqldb/HSQLDBRepositoryFactory.java diff --git a/src/repository/hsqldb/HSQLDBSaver.java b/src/main/java/repository/hsqldb/HSQLDBSaver.java similarity index 100% rename from src/repository/hsqldb/HSQLDBSaver.java rename to src/main/java/repository/hsqldb/HSQLDBSaver.java diff --git a/src/repository/hsqldb/HSQLDBVotingRepository.java b/src/main/java/repository/hsqldb/HSQLDBVotingRepository.java similarity index 100% rename from src/repository/hsqldb/HSQLDBVotingRepository.java rename to src/main/java/repository/hsqldb/HSQLDBVotingRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBArbitraryTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBArbitraryTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBArbitraryTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBArbitraryTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBBuyNameTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBBuyNameTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBBuyNameTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBBuyNameTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBCancelOrderTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBCancelOrderTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBCancelOrderTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBCancelOrderTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBCancelSellNameTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBCancelSellNameTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBCancelSellNameTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBCancelSellNameTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBCreateOrderTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBCreateOrderTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBCreateOrderTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBCreateOrderTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBCreatePollTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBCreatePollTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBCreatePollTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBCreatePollTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBDeployATTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBDeployATTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBDeployATTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBDeployATTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBGenesisTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBGenesisTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBGenesisTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBGenesisTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBIssueAssetTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBIssueAssetTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBIssueAssetTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBIssueAssetTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBMessageTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBMessageTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBMessageTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBMessageTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBMultiPaymentTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBMultiPaymentTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBMultiPaymentTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBMultiPaymentTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBPaymentTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBPaymentTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBPaymentTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBPaymentTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBRegisterNameTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBRegisterNameTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBRegisterNameTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBRegisterNameTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBSellNameTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBSellNameTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBSellNameTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBSellNameTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBTransferAssetTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBTransferAssetTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBTransferAssetTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBTransferAssetTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBUpdateNameTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBUpdateNameTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBUpdateNameTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBUpdateNameTransactionRepository.java diff --git a/src/repository/hsqldb/transaction/HSQLDBVoteOnPollTransactionRepository.java b/src/main/java/repository/hsqldb/transaction/HSQLDBVoteOnPollTransactionRepository.java similarity index 100% rename from src/repository/hsqldb/transaction/HSQLDBVoteOnPollTransactionRepository.java rename to src/main/java/repository/hsqldb/transaction/HSQLDBVoteOnPollTransactionRepository.java diff --git a/src/settings/Settings.java b/src/main/java/settings/Settings.java similarity index 89% rename from src/settings/Settings.java rename to src/main/java/settings/Settings.java index 63cb4f14..e9d75541 100644 --- a/src/settings/Settings.java +++ b/src/main/java/settings/Settings.java @@ -33,12 +33,6 @@ public class Settings { private List rpcAllowed = new ArrayList(Arrays.asList("127.0.0.1", "::1")); // ipv4, ipv6 private boolean rpcEnabled = true; - // Globalization - private String translationsPath = "globalization/"; - private String[] translationsDefaultLocales = { - "en" - }; - // Constants private static final String SETTINGS_FILENAME = "settings.json"; @@ -122,19 +116,20 @@ public class Settings { if (json.containsKey("rpcallowed")) { JSONArray allowedArray = (JSONArray) json.get("rpcallowed"); - this.rpcAllowed = new ArrayList(allowedArray); + + this.rpcAllowed = new ArrayList(); + + for (Object entry : allowedArray) { + if (!(entry instanceof String)) + throw new RuntimeException("Entry inside 'rpcallowed' is not string"); + + this.rpcAllowed.add((String) entry); + } } if (json.containsKey("rpcenabled")) this.rpcEnabled = ((Boolean) json.get("rpcenabled")).booleanValue(); - // Globalization - if (json.containsKey("translationspath")) - this.translationsPath = ((String) json.get("translationspath")); - - if (json.containsKey("translationsdefaultlocales")) - this.translationsDefaultLocales = ((String[]) json.get("translationsdefaultlocales")); - if (json.containsKey("blockchainConfig")) { String filename = (String) json.get("blockchainConfig"); File file = new File(this.userpath + filename); @@ -173,14 +168,6 @@ public class Settings { return this.rpcEnabled; } - public String translationsPath() { - return this.translationsPath; - } - - public String[] translationsDefaultLocales() { - return this.translationsDefaultLocales; - } - public boolean useBitcoinTestNet() { return this.useBitcoinTestNet; } diff --git a/src/transform/PaymentTransformer.java b/src/main/java/transform/PaymentTransformer.java similarity index 100% rename from src/transform/PaymentTransformer.java rename to src/main/java/transform/PaymentTransformer.java diff --git a/src/transform/TransformationException.java b/src/main/java/transform/TransformationException.java similarity index 100% rename from src/transform/TransformationException.java rename to src/main/java/transform/TransformationException.java diff --git a/src/transform/Transformer.java b/src/main/java/transform/Transformer.java similarity index 100% rename from src/transform/Transformer.java rename to src/main/java/transform/Transformer.java diff --git a/src/transform/block/BlockTransformer.java b/src/main/java/transform/block/BlockTransformer.java similarity index 100% rename from src/transform/block/BlockTransformer.java rename to src/main/java/transform/block/BlockTransformer.java diff --git a/src/transform/transaction/ATTransactionTransformer.java b/src/main/java/transform/transaction/ATTransactionTransformer.java similarity index 100% rename from src/transform/transaction/ATTransactionTransformer.java rename to src/main/java/transform/transaction/ATTransactionTransformer.java diff --git a/src/transform/transaction/ArbitraryTransactionTransformer.java b/src/main/java/transform/transaction/ArbitraryTransactionTransformer.java similarity index 100% rename from src/transform/transaction/ArbitraryTransactionTransformer.java rename to src/main/java/transform/transaction/ArbitraryTransactionTransformer.java diff --git a/src/transform/transaction/BuyNameTransactionTransformer.java b/src/main/java/transform/transaction/BuyNameTransactionTransformer.java similarity index 100% rename from src/transform/transaction/BuyNameTransactionTransformer.java rename to src/main/java/transform/transaction/BuyNameTransactionTransformer.java diff --git a/src/transform/transaction/CancelOrderTransactionTransformer.java b/src/main/java/transform/transaction/CancelOrderTransactionTransformer.java similarity index 100% rename from src/transform/transaction/CancelOrderTransactionTransformer.java rename to src/main/java/transform/transaction/CancelOrderTransactionTransformer.java diff --git a/src/transform/transaction/CancelSellNameTransactionTransformer.java b/src/main/java/transform/transaction/CancelSellNameTransactionTransformer.java similarity index 100% rename from src/transform/transaction/CancelSellNameTransactionTransformer.java rename to src/main/java/transform/transaction/CancelSellNameTransactionTransformer.java diff --git a/src/transform/transaction/CreateOrderTransactionTransformer.java b/src/main/java/transform/transaction/CreateOrderTransactionTransformer.java similarity index 100% rename from src/transform/transaction/CreateOrderTransactionTransformer.java rename to src/main/java/transform/transaction/CreateOrderTransactionTransformer.java diff --git a/src/transform/transaction/CreatePollTransactionTransformer.java b/src/main/java/transform/transaction/CreatePollTransactionTransformer.java similarity index 100% rename from src/transform/transaction/CreatePollTransactionTransformer.java rename to src/main/java/transform/transaction/CreatePollTransactionTransformer.java diff --git a/src/transform/transaction/DeployATTransactionTransformer.java b/src/main/java/transform/transaction/DeployATTransactionTransformer.java similarity index 100% rename from src/transform/transaction/DeployATTransactionTransformer.java rename to src/main/java/transform/transaction/DeployATTransactionTransformer.java diff --git a/src/transform/transaction/GenesisTransactionTransformer.java b/src/main/java/transform/transaction/GenesisTransactionTransformer.java similarity index 100% rename from src/transform/transaction/GenesisTransactionTransformer.java rename to src/main/java/transform/transaction/GenesisTransactionTransformer.java diff --git a/src/transform/transaction/IssueAssetTransactionTransformer.java b/src/main/java/transform/transaction/IssueAssetTransactionTransformer.java similarity index 100% rename from src/transform/transaction/IssueAssetTransactionTransformer.java rename to src/main/java/transform/transaction/IssueAssetTransactionTransformer.java diff --git a/src/transform/transaction/MessageTransactionTransformer.java b/src/main/java/transform/transaction/MessageTransactionTransformer.java similarity index 100% rename from src/transform/transaction/MessageTransactionTransformer.java rename to src/main/java/transform/transaction/MessageTransactionTransformer.java diff --git a/src/transform/transaction/MultiPaymentTransactionTransformer.java b/src/main/java/transform/transaction/MultiPaymentTransactionTransformer.java similarity index 100% rename from src/transform/transaction/MultiPaymentTransactionTransformer.java rename to src/main/java/transform/transaction/MultiPaymentTransactionTransformer.java diff --git a/src/transform/transaction/PaymentTransactionTransformer.java b/src/main/java/transform/transaction/PaymentTransactionTransformer.java similarity index 100% rename from src/transform/transaction/PaymentTransactionTransformer.java rename to src/main/java/transform/transaction/PaymentTransactionTransformer.java diff --git a/src/transform/transaction/RegisterNameTransactionTransformer.java b/src/main/java/transform/transaction/RegisterNameTransactionTransformer.java similarity index 100% rename from src/transform/transaction/RegisterNameTransactionTransformer.java rename to src/main/java/transform/transaction/RegisterNameTransactionTransformer.java diff --git a/src/transform/transaction/SellNameTransactionTransformer.java b/src/main/java/transform/transaction/SellNameTransactionTransformer.java similarity index 100% rename from src/transform/transaction/SellNameTransactionTransformer.java rename to src/main/java/transform/transaction/SellNameTransactionTransformer.java diff --git a/src/transform/transaction/TransactionTransformer.java b/src/main/java/transform/transaction/TransactionTransformer.java similarity index 100% rename from src/transform/transaction/TransactionTransformer.java rename to src/main/java/transform/transaction/TransactionTransformer.java diff --git a/src/transform/transaction/TransferAssetTransactionTransformer.java b/src/main/java/transform/transaction/TransferAssetTransactionTransformer.java similarity index 100% rename from src/transform/transaction/TransferAssetTransactionTransformer.java rename to src/main/java/transform/transaction/TransferAssetTransactionTransformer.java diff --git a/src/transform/transaction/UpdateNameTransactionTransformer.java b/src/main/java/transform/transaction/UpdateNameTransactionTransformer.java similarity index 100% rename from src/transform/transaction/UpdateNameTransactionTransformer.java rename to src/main/java/transform/transaction/UpdateNameTransactionTransformer.java diff --git a/src/transform/transaction/VoteOnPollTransactionTransformer.java b/src/main/java/transform/transaction/VoteOnPollTransactionTransformer.java similarity index 100% rename from src/transform/transaction/VoteOnPollTransactionTransformer.java rename to src/main/java/transform/transaction/VoteOnPollTransactionTransformer.java diff --git a/src/txhex.java b/src/main/java/txhex.java similarity index 100% rename from src/txhex.java rename to src/main/java/txhex.java diff --git a/src/utils/BIP39.java b/src/main/java/utils/BIP39.java similarity index 93% rename from src/utils/BIP39.java rename to src/main/java/utils/BIP39.java index 6fbb8dfc..622f913c 100644 --- a/src/utils/BIP39.java +++ b/src/main/java/utils/BIP39.java @@ -14,7 +14,7 @@ public class BIP39 { if (lang == null) lang = "en"; - List wordList = BIP39WordList.getInstance().getByLang(lang); + List wordList = BIP39WordList.INSTANCE.getByLang(lang); if (wordList == null) throw new IllegalStateException("BIP39 word list for lang '" + lang + "' unavailable"); @@ -53,7 +53,7 @@ public class BIP39 { if (lang == null) lang = "en"; - List wordList = BIP39WordList.getInstance().getByLang(lang); + List wordList = BIP39WordList.INSTANCE.getByLang(lang); if (wordList == null) throw new IllegalStateException("BIP39 word list for lang '" + lang + "' unavailable"); diff --git a/src/utils/Base58.java b/src/main/java/utils/Base58.java similarity index 100% rename from src/utils/Base58.java rename to src/main/java/utils/Base58.java diff --git a/src/utils/NTP.java b/src/main/java/utils/NTP.java similarity index 100% rename from src/utils/NTP.java rename to src/main/java/utils/NTP.java diff --git a/src/utils/Pair.java b/src/main/java/utils/Pair.java similarity index 100% rename from src/utils/Pair.java rename to src/main/java/utils/Pair.java diff --git a/src/utils/Serialization.java b/src/main/java/utils/Serialization.java similarity index 100% rename from src/utils/Serialization.java rename to src/main/java/utils/Serialization.java diff --git a/src/utils/Triple.java b/src/main/java/utils/Triple.java similarity index 100% rename from src/utils/Triple.java rename to src/main/java/utils/Triple.java diff --git a/src/v1feeder.java b/src/main/java/v1feeder.java similarity index 100% rename from src/v1feeder.java rename to src/main/java/v1feeder.java diff --git a/globalization/BIP39.en.txt b/src/main/resources/BIP39/wordlist_en.txt similarity index 100% rename from globalization/BIP39.en.txt rename to src/main/resources/BIP39/wordlist_en.txt diff --git a/block-explorer.html b/src/main/resources/block-explorer.html similarity index 100% rename from block-explorer.html rename to src/main/resources/block-explorer.html diff --git a/globalization/BlocksResource.de.xml b/src/main/resources/globalization/BlocksResource.de.xml similarity index 100% rename from globalization/BlocksResource.de.xml rename to src/main/resources/globalization/BlocksResource.de.xml diff --git a/globalization/BlocksResource.en.xml b/src/main/resources/globalization/BlocksResource.en.xml similarity index 100% rename from globalization/BlocksResource.en.xml rename to src/main/resources/globalization/BlocksResource.en.xml diff --git a/src/main/resources/i18n/ApiError_de.properties b/src/main/resources/i18n/ApiError_de.properties new file mode 100644 index 00000000..84b9f00d --- /dev/null +++ b/src/main/resources/i18n/ApiError_de.properties @@ -0,0 +1,72 @@ +UNKNOWN=Unbekannter Fehler +JSON=JSON Nachricht konnte nicht geparsed werden +NO_BALANCE=Guthaben ungenügend +NOT_YET_RELEASED=Feature wurde noch nicht veröffentlicht +INVALID_SIGNATURE=Ungültige Signatur +INVALID_ADDRESS=Ungültige Adresse +INVALID_SEED=Ungültiger Seed +INVALID_AMOUNT=Ungültiger Betrag +INVALID_FEE=Ungültige Gebühr +INVALID_SENDER=Ungültiger Sender +INVALID_RECIPIENT=Ungültiger Empfänger +INVALID_NAME_LENGTH=Ungültige Namenslänge +INVALID_VALUE_LENGTH=Ungültige Wertlänge +INVALID_NAME_OWNER=Ungültiger Namensbesitzer +INVALID_BUYER=Ungültiger Käufer +INVALID_PUBLIC_KEY=Ungültiger Public Key +INVALID_OPTIONS_LENGTH=Ungültige Optionen-Länge +INVALID_OPTION_LENGTH=Ungültige Optionslänge +INVALID_DATA=Ungültige Daten +INVALID_DATA_LENGTH=Ungültige Datenlänge +INVALID_UPDATE_VALUE=Ungültiger Update-Wert +KEY_ALREADY_EXISTS=Der Schlüssel existiert bereits, Editieren ist deaktiviert +KEY_NOT_EXISTS=Der Schlüssel existiert nicht +LAST_KEY_IS_DEFAULT_KEY_ERROR=Du kannst den Schlüssel '${key}' nicht löschen, wenn er der einzige ist +FEE_LESS_REQUIRED=fee less required +WALLET_NOT_IN_SYNC=Das Wallet muss synchronisiert werden +INVALID_NETWORK_ADDRESS=Ungültige Netzwerkadresse +WALLET_NO_EXISTS=Das Wallet existiert nicht +WALLET_ADDRESS_NO_EXISTS=Die Adresse existiert nicht im Wallet +WALLET_LOCKED=Das Wallet ist abgeschlossen +WALLET_ALREADY_EXISTS=Das Wallet existiert bereits +WALLET_API_CALL_FORBIDDEN_BY_USER=Der Benutzer hat den API-Aufruf abgelehnt +BLOCK_NO_EXISTS=Der Block existiert nicht +TRANSACTION_NO_EXISTS=Die Transaktion existiert nicht +PUBLIC_KEY_NOT_FOUND=Public Key wurde nicht gefunden +NAME_NO_EXISTS=Der Name existiert nicht +NAME_ALREADY_EXISTS=Der Name existiert bereits +NAME_ALREADY_FOR_SALE=Der Name steht bereits zum Verkauf +NAME_NOT_LOWER_CASE=Der Name muss aus Kleinbuchstaben bestehen +NAME_SALE_NO_EXISTS=Namensverkauf existiert nicht +BUYER_ALREADY_OWNER=Der Käufer ist bereits Besitzer +POLL_NO_EXISTS=Die Abstimmung existiert nicht +POLL_ALREADY_EXISTS=Die Abstimmung existiert bereits +DUPLICATE_OPTION=Nicht alle Optionen sind eindeutig +POLL_OPTION_NO_EXISTS=Die option existiert nicht +ALREADY_VOTED_FOR_THAT_OPTION=Bereits für diese Option abgestimmt +INVALID_ASSET_ID=Ungültige Asset ID +NAME_NOT_REGISTERED=?NAME_NOT_REGISTERED? +NAME_FOR_SALE=?NAME_FOR_SALE? +NAME_WITH_SPACE=?NAME_WITH_SPACE? +INVALID_DESC_LENGTH=Ungültige Beschreibungslänge. Max. Länge ${MAX_LENGTH} +EMPTY_CODE=Der Code ist leer +DATA_SIZE=Ungültige Datenlänge +NULL_PAGES=Ungültige Seiten +INVALID_TYPE_LENGTH=Ungültige Typlänge +INVALID_TAGS_LENGTH=Ungültige Tag-Länge +INVALID_CREATION_BYTES=Fehler in Creation Bytes +BODY_EMPTY=invalid body it must not be empty +BLOG_DISABLED=Dieser Blog ist deaktiviert +NAME_NOT_OWNER=the creator address does not own the author name +TX_AMOUNT=the data size is too large - currently only ${BATCH_TX_AMOUNT} arbitrary transactions are allowed at once! +BLOG_ENTRY_NO_EXISTS=transaction with this signature contains no entries! +BLOG_EMPTY=this blog is empty +POSTID_EMPTY=the attribute postid is empty! this is the signature of the post you want to comment +POST_NOT_EXISTING=for the given postid no blogpost to comment was found +COMMENTING_DISABLED=commenting is for this blog disabled +COMMENT_NOT_EXISTING=for the given signature no comment was found +INVALID_COMMENT_OWNER=invalid comment owner +MESSAGE_FORMAT_NOT_HEX=the Message format is not hex - correct the text or use isTextMessage = true +MESSAGE_BLANK=The message attribute is missing or content is blank +NO_PUBLIC_KEY=The recipient has not yet performed any action in the blockchain.\nYou can't send an encrypted message to him. +MESSAGESIZE_EXCEEDED=Message size exceeded! diff --git a/src/main/resources/i18n/ApiError_en.properties b/src/main/resources/i18n/ApiError_en.properties new file mode 100644 index 00000000..5a8c0c3c --- /dev/null +++ b/src/main/resources/i18n/ApiError_en.properties @@ -0,0 +1,95 @@ +# Keys are from api.ApiError enum + +# Common +UNKNOWN=unknown error +JSON=failed to parse json message +NO_BALANCE=not enough balance +NOT_YET_RELEASED=that feature is not yet released +UNAUTHORIZED=api call unauthorized +REPOSITORY_ISSUE=repository error + +# Validation +INVALID_SIGNATURE=invalid signature +INVALID_ADDRESS=invalid address +INVALID_SEED=invalid seed +INVALID_AMOUNT=invalid amount +INVALID_FEE=invalid fee +INVALID_SENDER=invalid sender +INVALID_RECIPIENT=invalid recipient +INVALID_NAME_LENGTH=invalid name length +INVALID_VALUE_LENGTH=invalid value length +INVALID_NAME_OWNER=invalid name owner +INVALID_BUYER=invalid buyer +INVALID_PUBLIC_KEY=invalid public key +INVALID_OPTIONS_LENGTH=invalid options length +INVALID_OPTION_LENGTH=invalid option length +INVALID_DATA=invalid data +INVALID_DATA_LENGTH=invalid data length +INVALID_UPDATE_VALUE=invalid update value +KEY_ALREADY_EXISTS=key already exists, edit is false +KEY_NOT_EXISTS=the key does not exist +FEE_LESS_REQUIRED=fee less required +WALLET_NOT_IN_SYNC=wallet needs to be synchronized +INVALID_NETWORK_ADDRESS=invalid network address +ADDRESS_NO_EXISTS=account address does not exist +INVALID_CRITERIA=invalid search criteria + +# Wallet +WALLET_NO_EXISTS=wallet does not exist +WALLET_ADDRESS_NO_EXISTS=address does not exist in wallet +WALLET_LOCKED=wallet is locked +WALLET_ALREADY_EXISTS=wallet already exists +WALLET_API_CALL_FORBIDDEN_BY_USER=wallet denied api call + +# Blocks +BLOCK_NO_EXISTS=block does not exist + +# Transactions +TRANSACTION_NO_EXISTS=transaction does not exist +PUBLIC_KEY_NOT_FOUND=public key not found + +# Names +NAME_NO_EXISTS=name does not exist +NAME_ALREADY_EXISTS=name already exists +NAME_ALREADY_FOR_SALE=name already for sale +NAME_NOT_LOWER_CASE=name must be lower case +NAME_SALE_NO_EXISTS=namesale does not exist +BUYER_ALREADY_OWNER=buyer is already owner + +# Voting +POLL_NO_EXISTS=poll does not exist +POLL_ALREADY_EXISTS=poll already exists +DUPLICATE_OPTION=not all options are unique +POLL_OPTION_NO_EXISTS=option does not exist +ALREADY_VOTED_FOR_THAT_OPTION=already voted for that option + +# Assets +INVALID_ASSET_ID=invalid asset id +INVALID_ORDER_ID=invalid asset order id +ORDER_NO_EXISTS=unknown asset order id + +# ATs +EMPTY_CODE=code is empty +DATA_SIZE=invalid data length +NULL_PAGES=invalid pages +INVALID_TYPE_LENGTH=invalid type length +INVALID_TAGS_LENGTH=invalid tags length +INVALID_CREATION_BYTES=error in creation bytes + +# Blogs/Name-storage +BODY_EMPTY=invalid body it must not be empty +BLOG_DISABLED=this blog is disabled +NAME_NOT_OWNER=the creator address does not own the author name +BLOG_ENTRY_NO_EXISTS=transaction with this signature contains no entries! +BLOG_EMPTY=this blog is empty +POSTID_EMPTY=the attribute postid is empty! this is the signature of the post you want to comment +POST_NOT_EXISTING=for the given postid no blogpost to comment was found +COMMENTING_DISABLED=commenting is for this blog disabled +COMMENT_NOT_EXISTING=for the given signature no comment was found +INVALID_COMMENT_OWNER=invalid comment owner + +# Messages +MESSAGE_FORMAT_NOT_HEX=the Message format is not hex - correct the text or use isTextMessage = true +MESSAGE_BLANK=The message attribute is missing or content is blank +NO_PUBLIC_KEY=The recipient has not yet performed any action in the blockchain.\nYou can't send an encrypted message to them. +MESSAGESIZE_EXCEEDED=Message size exceeded! diff --git a/src/main/resources/i18n/TransactionValidity_en.properties b/src/main/resources/i18n/TransactionValidity_en.properties new file mode 100644 index 00000000..8f16b499 --- /dev/null +++ b/src/main/resources/i18n/TransactionValidity_en.properties @@ -0,0 +1,42 @@ +OK=OK +INVALID_ADDRESS=INVALID_ADDRESS +NEGATIVE_AMOUNT=NEGATIVE_AMOUNT +NEGATIVE_FEE=NEGATIVE_FEE +NO_BALANCE=NO_BALANCE +INVALID_REFERENCE=INVALID_REFERENCE +INVALID_NAME_LENGTH=INVALID_NAME_LENGTH +INVALID_VALUE_LENGTH=INVALID_VALUE_LENGTH +NAME_ALREADY_REGISTERED=NAME_ALREADY_REGISTERED +NAME_DOES_NOT_EXIST=NAME_DOES_NOT_EXIST +INVALID_NAME_OWNER=INVALID_NAME_OWNER +NAME_ALREADY_FOR_SALE=NAME_ALREADY_FOR_SALE +NAME_NOT_FOR_SALE=NAME_NOT_FOR_SALE +BUYER_ALREADY_OWNER=BUYER_ALREADY_OWNER +INVALID_AMOUNT=INVALID_AMOUNT +INVALID_SELLER=INVALID_SELLER +NAME_NOT_LOWER_CASE=NAME_NOT_LOWER_CASE +INVALID_DESCRIPTION_LENGTH=INVALID_DESCRIPTION_LENGTH +INVALID_OPTIONS_COUNT=INVALID_OPTIONS_COUNT +INVALID_OPTION_LENGTH=INVALID_OPTION_LENGTH +DUPLICATE_OPTION=DUPLICATE_OPTION +POLL_ALREADY_EXISTS=POLL_ALREADY_EXISTS +POLL_DOES_NOT_EXIST=POLL_DOES_NOT_EXIST +POLL_OPTION_DOES_NOT_EXIST=POLL_OPTION_DOES_NOT_EXIST +ALREADY_VOTED_FOR_THAT_OPTION=ALREADY_VOTED_FOR_THAT_OPTION +INVALID_DATA_LENGTH=INVALID_DATA_LENGTH +INVALID_QUANTITY=INVALID_QUANTITY +ASSET_DOES_NOT_EXIST=ASSET_DOES_NOT_EXIST +INVALID_RETURN=INVALID_RETURN +HAVE_EQUALS_WANT=HAVE_EQUALS_WANT +ORDER_DOES_NOT_EXIST=ORDER_DOES_NOT_EXIST +INVALID_ORDER_CREATOR=INVALID_ORDER_CREATOR +INVALID_PAYMENTS_COUNT=INVALID_PAYMENTS_COUNT +NEGATIVE_PRICE=NEGATIVE_PRICE +INVALID_CREATION_BYTES=INVALID_CREATION_BYTES +INVALID_TAGS_LENGTH=INVALID_TAGS_LENGTH +INVALID_AT_TYPE_LENGTH=INVALID_AT_TYPE_LENGTH +INVALID_AT_TRANSACTION=INVALID_AT_TRANSACTION +AT_IS_FINISHED=AT_IS_FINISHED +ASSET_DOES_NOT_MATCH_AT=ASSET_DOES_NOT_MATCH_AT +ASSET_ALREADY_EXISTS=ASSET_ALREADY_EXISTS +NOT_YET_RELEASED=NOT_YET_RELEASED diff --git a/tests/test/ATTests.java b/src/test/java/test/ATTests.java similarity index 100% rename from tests/test/ATTests.java rename to src/test/java/test/ATTests.java diff --git a/tests/test/BTCACCTTests.java b/src/test/java/test/BTCACCTTests.java similarity index 99% rename from tests/test/BTCACCTTests.java rename to src/test/java/test/BTCACCTTests.java index 881bcc26..ac1a6a96 100644 --- a/tests/test/BTCACCTTests.java +++ b/src/test/java/test/BTCACCTTests.java @@ -22,7 +22,6 @@ import org.bitcoinj.core.TransactionInput; import org.bitcoinj.core.TransactionOutPoint; import org.bitcoinj.crypto.TransactionSignature; import org.bitcoinj.kits.WalletAppKit; -import org.bitcoinj.params.RegTestParams; import org.bitcoinj.params.TestNet3Params; import org.bitcoinj.script.Script; import org.bitcoinj.script.ScriptBuilder; diff --git a/tests/test/BTCTests.java b/src/test/java/test/BTCTests.java similarity index 100% rename from tests/test/BTCTests.java rename to src/test/java/test/BTCTests.java diff --git a/tests/test/BlockTests.java b/src/test/java/test/BlockTests.java similarity index 100% rename from tests/test/BlockTests.java rename to src/test/java/test/BlockTests.java diff --git a/tests/test/BlockchainTests.java b/src/test/java/test/BlockchainTests.java similarity index 100% rename from tests/test/BlockchainTests.java rename to src/test/java/test/BlockchainTests.java diff --git a/tests/test/Common.java b/src/test/java/test/Common.java similarity index 100% rename from tests/test/Common.java rename to src/test/java/test/Common.java diff --git a/tests/test/CompatibilityTests.java b/src/test/java/test/CompatibilityTests.java similarity index 100% rename from tests/test/CompatibilityTests.java rename to src/test/java/test/CompatibilityTests.java diff --git a/tests/test/CryptoTests.java b/src/test/java/test/CryptoTests.java similarity index 100% rename from tests/test/CryptoTests.java rename to src/test/java/test/CryptoTests.java diff --git a/tests/test/ExceptionTests.java b/src/test/java/test/ExceptionTests.java similarity index 100% rename from tests/test/ExceptionTests.java rename to src/test/java/test/ExceptionTests.java diff --git a/tests/test/GenesisTests.java b/src/test/java/test/GenesisTests.java similarity index 100% rename from tests/test/GenesisTests.java rename to src/test/java/test/GenesisTests.java diff --git a/tests/test/LoadTests.java b/src/test/java/test/LoadTests.java similarity index 100% rename from tests/test/LoadTests.java rename to src/test/java/test/LoadTests.java diff --git a/tests/test/NavigationTests.java b/src/test/java/test/NavigationTests.java similarity index 100% rename from tests/test/NavigationTests.java rename to src/test/java/test/NavigationTests.java diff --git a/tests/test/RepositoryTests.java b/src/test/java/test/RepositoryTests.java similarity index 100% rename from tests/test/RepositoryTests.java rename to src/test/java/test/RepositoryTests.java diff --git a/tests/test/SaveTests.java b/src/test/java/test/SaveTests.java similarity index 100% rename from tests/test/SaveTests.java rename to src/test/java/test/SaveTests.java diff --git a/tests/test/SerializationTests.java b/src/test/java/test/SerializationTests.java similarity index 100% rename from tests/test/SerializationTests.java rename to src/test/java/test/SerializationTests.java diff --git a/tests/test/SignatureTests.java b/src/test/java/test/SignatureTests.java similarity index 100% rename from tests/test/SignatureTests.java rename to src/test/java/test/SignatureTests.java diff --git a/tests/test/TransactionTests.java b/src/test/java/test/TransactionTests.java similarity index 100% rename from tests/test/TransactionTests.java rename to src/test/java/test/TransactionTests.java diff --git a/src/test/java/test/utils/AssertExtensions.java b/src/test/java/test/utils/AssertExtensions.java new file mode 100644 index 00000000..f0d9b4c9 --- /dev/null +++ b/src/test/java/test/utils/AssertExtensions.java @@ -0,0 +1,18 @@ +package test.utils; + +import java.util.Collection; + +import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; +import static org.hamcrest.MatcherAssert.assertThat; + +public class AssertExtensions { + + public static void assertItemsEqual(Collection expected, Iterable actual) { + assertItemsEqual(expected, actual, (String) null); + } + + public static void assertItemsEqual(Collection expected, Iterable actual, String message) { + assertThat(message, actual, containsInAnyOrder(expected.toArray())); + } + +} diff --git a/tests/test/GlobalizationTests.java b/tests/test/GlobalizationTests.java deleted file mode 100644 index 967cba08..00000000 --- a/tests/test/GlobalizationTests.java +++ /dev/null @@ -1,171 +0,0 @@ -package test; - -import globalization.TranslationEntry; -import globalization.TranslationXmlStreamReader; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import javax.xml.stream.XMLStreamException; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -import static test.utils.AssertExtensions.*; -import test.utils.EqualityComparer; - -public class GlobalizationTests { - - private class TranslationEntryEqualityComparer implements EqualityComparer { - - @Override - public boolean equals(TranslationEntry first, TranslationEntry second) { - if(first == null && second == null) - return true; - if(first == null && second != null || first != null && second == null) - return false; - - if(!first.locale().equals(second.locale())) - return false; - if(!first.path().equals(second.path())) - return false; - if(!first.template().equals(second.template())) - return false; - - return true; - } - - @Override - public int hashCode(TranslationEntry item) { - int hash = 17; - final int multiplier = 59; - - hash = hash * multiplier + item.locale().hashCode(); - hash = hash * multiplier + item.path().hashCode(); - hash = hash * multiplier + item.template().hashCode(); - - return hash; - } - - } - - @Test - public void TestTranslationXmlReaderContextPaths() throws XMLStreamException { - String xml = - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "\n"; - - List expected = new ArrayList<>(); - expected.add(new TranslationEntry(Locale.forLanguageTag("en-GB"), "/path1/key1", "1")); - expected.add(new TranslationEntry(Locale.forLanguageTag("en-GB"), "/path1/path2/path3/key2", "2")); - expected.add(new TranslationEntry(Locale.forLanguageTag("en-GB"), "/path1/path4/key3", "3")); - - InputStream is = new ByteArrayInputStream(xml.getBytes(Charset.forName("UTF-8"))); - TranslationXmlStreamReader reader = new TranslationXmlStreamReader(); - Iterable actual = reader.ReadFrom(is); - - for(TranslationEntry i:expected)System.out.println(i);for(TranslationEntry i:actual)System.out.println(i); - assertItemsEqual(expected, actual, new TranslationEntryEqualityComparer()); - } - - @Test - public void TestTranslationXmlReaderLocales() throws XMLStreamException { - String xml = - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "\n"; - - List expected = new ArrayList(); - expected.add(new TranslationEntry(Locale.forLanguageTag("default"), "/key1", "1")); - expected.add(new TranslationEntry(Locale.forLanguageTag("en-GB"), "/path1/key2", "2")); - expected.add(new TranslationEntry(Locale.forLanguageTag("de-DE"), "/path1/path2/key3", "3")); - - InputStream is = new ByteArrayInputStream(xml.getBytes(Charset.forName("UTF-8"))); - TranslationXmlStreamReader reader = new TranslationXmlStreamReader(); - Iterable actual = reader.ReadFrom(is); - - assertItemsEqual(expected, actual, new TranslationEntryEqualityComparer()); - } - - @Test - public void TestTranslationXmlReader_BadPath() { - String xml = - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "\n"; - - InputStream is = new ByteArrayInputStream(xml.getBytes(Charset.forName("UTF-8"))); - TranslationXmlStreamReader reader = new TranslationXmlStreamReader(); - - assertThrows(XMLStreamException.class, () -> reader.ReadFrom(is)); - } - - @Test - public void TestTranslationXmlReader_BadKey1() { - String xml = - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "\n"; - - InputStream is = new ByteArrayInputStream(xml.getBytes(Charset.forName("UTF-8"))); - TranslationXmlStreamReader reader = new TranslationXmlStreamReader(); - - assertThrows(XMLStreamException.class, () -> reader.ReadFrom(is)); - } - - @Test - public void TestTranslationXmlReader_BadKey2() { - String xml = - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "\n"; - - InputStream is = new ByteArrayInputStream(xml.getBytes(Charset.forName("UTF-8"))); - TranslationXmlStreamReader reader = new TranslationXmlStreamReader(); - - assertThrows(XMLStreamException.class, () -> reader.ReadFrom(is)); - } -} diff --git a/tests/test/utils/AssertExtensions.java b/tests/test/utils/AssertExtensions.java deleted file mode 100644 index fabce6a0..00000000 --- a/tests/test/utils/AssertExtensions.java +++ /dev/null @@ -1,42 +0,0 @@ -package test.utils; - -import com.google.common.collect.Iterables; -import java.lang.reflect.Array; -import java.lang.Class; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; -import static org.hamcrest.MatcherAssert.assertThat; - -public class AssertExtensions { - - public static void assertItemsEqual(Collection expected, Iterable actual, EqualityComparer comparer) { - assertItemsEqual(expected, actual, comparer, (String)null); - } - - public static void assertItemsEqual(Collection expected, Iterable actual, EqualityComparer comparer, String message) { - List> expectedSet = new ArrayList>(); - for(T item: expected) - expectedSet.add(new EquatableWrapper(item, comparer)); - - List> actualSet = new ArrayList>(); - for(T item: actual) - actualSet.add(new EquatableWrapper(item, comparer)); - - assertItemsEqual(expectedSet, actualSet, message); - } - - public static void assertItemsEqual(Collection expected, Iterable actual) { - assertItemsEqual(expected, actual, (String)null); - } - - public static void assertItemsEqual(Collection expected, Iterable actual, String message) { - List list = new ArrayList(); - T[] expectedArray = (T[])expected.toArray(); - assertThat(message, actual, containsInAnyOrder(expectedArray)); - } -} diff --git a/tests/test/utils/EqualityComparer.java b/tests/test/utils/EqualityComparer.java deleted file mode 100644 index c560c9ce..00000000 --- a/tests/test/utils/EqualityComparer.java +++ /dev/null @@ -1,6 +0,0 @@ -package test.utils; - -public interface EqualityComparer { - boolean equals(T first, T second); - int hashCode(T item); -} diff --git a/tests/test/utils/EquatableWrapper.java b/tests/test/utils/EquatableWrapper.java deleted file mode 100644 index b719cf32..00000000 --- a/tests/test/utils/EquatableWrapper.java +++ /dev/null @@ -1,34 +0,0 @@ -package test.utils; - -class EquatableWrapper { - - private final T item; - private final EqualityComparer comparer; - - public EquatableWrapper(T item, EqualityComparer comparer) { - this.item = item; - this.comparer = comparer; - } - - @Override - public boolean equals(Object obj) { - if(obj == null) - return false; - if (!(this.getClass().isInstance(obj))) - return false; - EquatableWrapper otherWrapper = (EquatableWrapper)obj; - if (otherWrapper.item == this.item) - return true; - return this.comparer.equals(this.item, otherWrapper.item); - } - - @Override - public int hashCode() { - return this.comparer.hashCode(this.item); - } - - @Override - public String toString() { - return this.item.toString(); - } -} \ No newline at end of file