diff --git a/catacomb-bukkit-api/src/main/java/org/minecraftoss/catacomb/bukkit/BukkitRequestContext.java b/catacomb-bukkit-api/src/main/java/org/minecraftoss/catacomb/bukkit/BukkitRequestContext.java new file mode 100644 index 0000000..0ab9084 --- /dev/null +++ b/catacomb-bukkit-api/src/main/java/org/minecraftoss/catacomb/bukkit/BukkitRequestContext.java @@ -0,0 +1,20 @@ +package org.minecraftoss.catacomb.bukkit; + +import org.bukkit.plugin.Plugin; +import org.minecraftoss.catacomb.account.request.RequestContext; + +import java.util.UUID; + +public interface BukkitRequestContext extends RequestContext { + + static BukkitRequestContext pluginRequest(UUID accountId, Plugin requestId) { + return new BukkitRequestContextImpl(accountId, requestId); + } + + Plugin getRequestIdentifier(); + + @Override + default String getRequesterIdentifier() { + return getRequestIdentifier().getName(); + } +} diff --git a/catacomb-bukkit-api/src/main/java/org/minecraftoss/catacomb/bukkit/BukkitRequestContextFactory.java b/catacomb-bukkit-api/src/main/java/org/minecraftoss/catacomb/bukkit/BukkitRequestContextFactory.java new file mode 100644 index 0000000..e7bcdd9 --- /dev/null +++ b/catacomb-bukkit-api/src/main/java/org/minecraftoss/catacomb/bukkit/BukkitRequestContextFactory.java @@ -0,0 +1,25 @@ +package org.minecraftoss.catacomb.bukkit; + +import org.bukkit.plugin.Plugin; +import org.minecraftoss.catacomb.account.request.RequestContext; +import org.minecraftoss.catacomb.account.request.RequestContextFactory; + +import java.util.UUID; + +public class BukkitRequestContextFactory implements RequestContextFactory { + + private final Plugin plugin; + + private BukkitRequestContextFactory(Plugin plugin) { + this.plugin = plugin; + } + + public static BukkitRequestContextFactory forPlugin(Plugin plugin) { + return new BukkitRequestContextFactory(plugin); + } + + @Override + public RequestContext fromAccountIdentifier(UUID accountIdentifier) { + return BukkitRequestContext.pluginRequest(accountIdentifier, this.plugin); + } +} diff --git a/catacomb-bukkit-api/src/main/java/org/minecraftoss/catacomb/bukkit/BukkitRequestContextImpl.java b/catacomb-bukkit-api/src/main/java/org/minecraftoss/catacomb/bukkit/BukkitRequestContextImpl.java new file mode 100644 index 0000000..c84714a --- /dev/null +++ b/catacomb-bukkit-api/src/main/java/org/minecraftoss/catacomb/bukkit/BukkitRequestContextImpl.java @@ -0,0 +1,39 @@ +package org.minecraftoss.catacomb.bukkit; + +import org.bukkit.plugin.Plugin; +import org.minecraftoss.catacomb.account.request.RequestContextImpl; + +import java.util.UUID; + +class BukkitRequestContextImpl extends RequestContextImpl implements BukkitRequestContext { + + private final Plugin requestIdentifier; + + BukkitRequestContextImpl(UUID accountIdentifier, Plugin requestIdentifier) { + super(accountIdentifier, requestIdentifier.getName()); + this.requestIdentifier = requestIdentifier; + } + + @Override + public Plugin getRequestIdentifier() { + return this.requestIdentifier; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BukkitRequestContextImpl)) return false; + if (!super.equals(o)) return false; + + BukkitRequestContextImpl that = (BukkitRequestContextImpl) o; + + return requestIdentifier.equals(that.requestIdentifier); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + requestIdentifier.hashCode(); + return result; + } +} diff --git a/catacomb-bukkit/src/main/resources/plugin.yml b/catacomb-bukkit/src/main/resources/plugin.yml index 136f9e1..18460cb 100644 --- a/catacomb-bukkit/src/main/resources/plugin.yml +++ b/catacomb-bukkit/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: Catacomb version: @version@ -main: org.mincraftoss.catacomb.CatacombBukkit +main: org.minecraftoss.catacomb.CatacombBukkit api-version: 1.13 authors: [mbaxter, md678685] description: Totally not a replacement for Vault diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/Capability.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/Capability.java new file mode 100644 index 0000000..62c1e2a --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/Capability.java @@ -0,0 +1,33 @@ +package org.minecraftoss.catacomb; + +@SuppressWarnings("unused") +public enum Capability { + + /** + * Accounts that are provided by a third-party plugin. + * + *

If this capability isn't provided, third-party plugins + * can't use the implementation to have e.g. shared accounts. + */ + PLUGIN_ACCOUNTS, + + /** + * Different contexts for accounts. + * + *

If this capability isn't provided, third-party plugins + * can't use the implementation to have e.g. a bank account + * and a wallet for one player. Alternatively, {@link #PLUGIN_ACCOUNTS} + * could be used to achieve the same functionality in some cases. + */ + CONTEXTS, + + /** + * More than one currency. + * + *

If this capability isn't provided, third-party plugins + * can't use the implementation to have different currencies. + * Depending on the use case, {@link #PLUGIN_ACCOUNTS} could be + * used if provided. + */ + MULTIPLE_CURRENCIES +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/CatacombService.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/CatacombService.java new file mode 100644 index 0000000..997a758 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/CatacombService.java @@ -0,0 +1,25 @@ +package org.minecraftoss.catacomb; + +import org.minecraftoss.catacomb.account.AccountManager; + +import java.util.Set; + +public interface CatacombService { + + default boolean queryCapabilities(Capability capability) { + return false; + } + + default boolean queryCapabilities(Set capabilities) { + for (Capability capability : capabilities) { + if (!queryCapabilities(capability)) { + return false; + } + } + return true; + } + + EconomyManager getEconomyManager(); + + AccountManager getAccountManager(); +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/EconomyManager.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/EconomyManager.java new file mode 100644 index 0000000..0292073 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/EconomyManager.java @@ -0,0 +1,18 @@ +package org.minecraftoss.catacomb; + +import org.minecraftoss.catacomb.currency.Currency; +import org.minecraftoss.catacomb.transaction.Transaction; +import org.minecraftoss.catacomb.transaction.TransactionCondition; +import org.minecraftoss.catacomb.transaction.TransactionContext; +import org.minecraftoss.catacomb.transaction.result.TransactionResult; + +import java.math.BigDecimal; +import java.util.Set; +import java.util.UUID; + +public interface EconomyManager { + + TransactionResult handle(Transaction transaction, TransactionCondition condition); + + BigDecimal getBalance(UUID identifier, Currency currency, Set contexts); +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/SimpleCatacombService.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/SimpleCatacombService.java new file mode 100644 index 0000000..879229d --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/SimpleCatacombService.java @@ -0,0 +1,39 @@ +package org.minecraftoss.catacomb; + +import org.minecraftoss.catacomb.account.AccountManager; + +import java.util.EnumSet; +import java.util.Set; + +public class SimpleCatacombService implements CatacombService { + private final EconomyManager economyManager; + private final AccountManager accountManager; + private final Set capabilities; + + public SimpleCatacombService(EconomyManager economyManager, + AccountManager accountManager, Set capabilities) { + this.economyManager = economyManager; + this.accountManager = accountManager; + this.capabilities = EnumSet.copyOf(capabilities); + } + + @Override + public boolean queryCapabilities(Capability capability) { + return this.capabilities.contains(capability); + } + + @Override + public boolean queryCapabilities(Set capabilities) { + return this.capabilities.containsAll(capabilities); + } + + @Override + public EconomyManager getEconomyManager() { + return this.economyManager; + } + + @Override + public AccountManager getAccountManager() { + return this.accountManager; + } +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/Account.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/Account.java new file mode 100644 index 0000000..a66afda --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/Account.java @@ -0,0 +1,164 @@ +package org.minecraftoss.catacomb.account; + +import org.minecraftoss.catacomb.CatacombService; +import org.minecraftoss.catacomb.currency.Currency; +import org.minecraftoss.catacomb.transaction.Transaction; +import org.minecraftoss.catacomb.transaction.TransactionContext; +import org.minecraftoss.catacomb.transaction.TransactionCondition; +import org.minecraftoss.catacomb.transaction.result.TransactionResult; + +import java.math.BigDecimal; +import java.util.Set; +import java.util.UUID; + +public interface Account { + + UUID getIdentifier(); + + default BigDecimal getBalance(Currency currency, Set contexts) { + return getCatacombService().getEconomyManager().getBalance(getIdentifier(), currency, contexts); + } + + default BigDecimal getBalance(Currency currency) { + return getBalance(currency, getAccountContext().getDefaultContexts()); + } + + default BigDecimal getBalance() { + return getBalance(getAccountContext().getDefaultCurrency()); + } + + BigDecimal getInitialBalance(Currency currency); + + default BigDecimal getInitialBalance() { + return getInitialBalance(getAccountContext().getDefaultCurrency()); + } + + // account reset + + TransactionResult resetBalance(Currency currency, Set contexts); + + default TransactionResult resetBalance(Currency currency) { + return resetBalance(currency, getAccountContext().getDefaultContexts()); + } + + default TransactionResult resetBalance() { + return resetBalance(getAccountContext().getDefaultCurrency()); + } + + // transfer + + default TransactionResult transfer(Account to, Currency currency, BigDecimal amount, TransactionCondition condition, Set contexts) { + Transaction transaction = Transaction.of(this, to, currency, amount, contexts); + TransactionCondition andDefault = condition.and(getAccountContext().getDefaultTransactionCondition()); + return getCatacombService().getEconomyManager().handle(transaction, andDefault); + } + + default TransactionResult transfer(Account to, BigDecimal amount, TransactionCondition condition, Set contexts) { + return transfer(to, getAccountContext().getDefaultCurrency(), amount, condition, contexts); + } + + default TransactionResult transfer(Account to, Currency currency, BigDecimal amount, Set contexts) { + return transfer(to, currency, amount, getAccountContext().getDefaultTransactionCondition(), contexts); + } + + default TransactionResult transfer(Account to, BigDecimal amount, Set contexts) { + return transfer(to, getAccountContext().getDefaultCurrency(), amount, contexts); + } + + default TransactionResult transfer(Account to, Currency currency, BigDecimal amount, TransactionCondition condition) { + return transfer(to, currency, amount, condition, getAccountContext().getDefaultContexts()); + } + + default TransactionResult transfer(Account to, BigDecimal amount, TransactionCondition condition) { + return transfer(to, getAccountContext().getDefaultCurrency(), amount, condition); + } + + default TransactionResult transfer(Account to, Currency currency, BigDecimal amount) { + return transfer(to, currency, amount, getAccountContext().getDefaultTransactionCondition()); + } + + default TransactionResult transfer(Account to, BigDecimal amount) { + return transfer(to, getAccountContext().getDefaultCurrency(), amount); + } + + // withdraw + + default TransactionResult withdraw(Currency currency, BigDecimal amount, TransactionCondition condition, Set contexts) { + return transfer(getAccountContext().getInfiniteAccount(), currency, amount, condition, contexts); + } + + default TransactionResult withdraw(BigDecimal amount, TransactionCondition condition, Set contexts) { + return withdraw(getAccountContext().getDefaultCurrency(), amount, condition, contexts); + } + + default TransactionResult withdraw(Currency currency, BigDecimal amount, Set contexts) { + return withdraw(currency, amount, getAccountContext().getDefaultTransactionCondition(), contexts); + } + + default TransactionResult withdraw(BigDecimal amount, Set contexts) { + return withdraw(getAccountContext().getDefaultCurrency(), amount, contexts); + } + + default TransactionResult withdraw(Currency currency, BigDecimal amount, TransactionCondition condition) { + return withdraw(currency, amount, condition, getAccountContext().getDefaultContexts()); + } + + default TransactionResult withdraw(BigDecimal amount, TransactionCondition condition) { + return withdraw(getAccountContext().getDefaultCurrency(), amount, condition); + } + + default TransactionResult withdraw(Currency currency, BigDecimal amount) { + return withdraw(currency, amount, getAccountContext().getDefaultTransactionCondition()); + } + + default TransactionResult withdraw(BigDecimal amount) { + return withdraw(getAccountContext().getDefaultCurrency(), amount); + } + + // deposit + + default TransactionResult deposit(Currency currency, BigDecimal amount, TransactionCondition condition, Set contexts) { + return getAccountContext().getInfiniteAccount().transfer(this, currency, amount, condition, contexts); + } + + default TransactionResult deposit(BigDecimal amount, TransactionCondition condition, Set contexts) { + return deposit(getAccountContext().getDefaultCurrency(), amount, condition, contexts); + } + + default TransactionResult deposit(Currency currency, BigDecimal amount, Set contexts) { + return deposit(currency, amount, getAccountContext().getDefaultTransactionCondition(), contexts); + } + + default TransactionResult deposit(BigDecimal amount, Set contexts) { + return deposit(getAccountContext().getDefaultCurrency(), amount, contexts); + } + + default TransactionResult deposit(Currency currency, BigDecimal amount, TransactionCondition condition) { + return deposit(currency, amount, condition, getAccountContext().getDefaultContexts()); + } + + default TransactionResult deposit(BigDecimal amount, TransactionCondition condition) { + return deposit(getAccountContext().getDefaultCurrency(), amount, condition); + } + + default TransactionResult deposit(Currency currency, BigDecimal amount) { + return deposit(currency, amount, getAccountContext().getDefaultTransactionCondition()); + } + + default TransactionResult deposit(BigDecimal amount) { + return deposit(getAccountContext().getDefaultCurrency(), amount); + } + + CatacombService getCatacombService(); + + /** + * The context of this account. While an account is uniquely identified + * by {@link #getIdentifier()}, this allows to provide different context + * to different users (e.g. third-party plugins). + * + *

Implementations of Catacomb might allow settings so different plugins + * use different {@link Currency}, different default {@link TransactionCondition}. + * @return the context of this account. + */ + AccountContext getAccountContext(); +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/AccountContext.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/AccountContext.java new file mode 100644 index 0000000..da91495 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/AccountContext.java @@ -0,0 +1,24 @@ +package org.minecraftoss.catacomb.account; + +import org.minecraftoss.catacomb.currency.Currency; +import org.minecraftoss.catacomb.transaction.TransactionCondition; +import org.minecraftoss.catacomb.transaction.TransactionContext; + +import java.util.Set; + +public interface AccountContext { + + TransactionCondition getDefaultTransactionCondition(); + + Currency getDefaultCurrency(); + + Set getDefaultContexts(); + + // TODO better name? + /** + * The account that is used for withdraw/deposit transactions as target/source. + * + * @return an infinite account. + */ + Account getInfiniteAccount(); +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/AccountManager.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/AccountManager.java new file mode 100644 index 0000000..1842671 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/AccountManager.java @@ -0,0 +1,8 @@ +package org.minecraftoss.catacomb.account; + +import org.minecraftoss.catacomb.account.request.RequestContext; + +public interface AccountManager { + + Account getAccount(RequestContext context); +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/InfiniteAccount.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/InfiniteAccount.java new file mode 100644 index 0000000..8b17f65 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/InfiniteAccount.java @@ -0,0 +1,56 @@ +package org.minecraftoss.catacomb.account; + +import org.minecraftoss.catacomb.CatacombService; +import org.minecraftoss.catacomb.currency.Currency; +import org.minecraftoss.catacomb.transaction.Transaction; +import org.minecraftoss.catacomb.transaction.TransactionCondition; +import org.minecraftoss.catacomb.transaction.TransactionContext; +import org.minecraftoss.catacomb.transaction.result.TransactionResult; + +import java.math.BigDecimal; +import java.util.Set; +import java.util.UUID; + +public enum InfiniteAccount implements Account { + INSTANCE; + + // TODO + private final UUID id = UUID.nameUUIDFromBytes(new byte[0]); + + @Override + public UUID getIdentifier() { + return this.id; + } + + @Override + public BigDecimal getBalance(Currency currency) { + return getInitialBalance(currency); + } + + @Override + public BigDecimal getInitialBalance(Currency currency) { + return BigDecimal.valueOf(Double.MAX_VALUE); + } + + @Override + public TransactionResult resetBalance(Currency currency, Set contexts) { + throw new UnsupportedOperationException("Cannot reset infinite account"); + } + + @Override + public TransactionResult transfer(Account to, Currency currency, BigDecimal amount, + TransactionCondition condition, Set contexts) { + Transaction transaction = Transaction.of(this, to, currency, amount, contexts); + return to.getCatacombService().getEconomyManager().handle(transaction, condition); + } + + @Override + public CatacombService getCatacombService() { + throw new UnsupportedOperationException("No associated catacomb service for infinite account"); + } + + @Override + public AccountContext getAccountContext() { + throw new UnsupportedOperationException("No associated account context"); + } +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/request/RequestContext.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/request/RequestContext.java new file mode 100644 index 0000000..bcfbdfa --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/request/RequestContext.java @@ -0,0 +1,34 @@ +package org.minecraftoss.catacomb.account.request; + +import org.minecraftoss.catacomb.account.Account; +import org.minecraftoss.catacomb.account.AccountContext; +import org.minecraftoss.catacomb.account.AccountManager; + +import java.util.UUID; + +/** + * The context of an {@link Account} request. + * + *

When requesting an account, a {@link UUID} and a {@link RequestContext} + * is required. Depending on the context, the {@link AccountContext} associated with + * the returned account might vary. + * + * @see AccountManager#getAccount(RequestContext) + * @see Account#getAccountContext() + */ +public interface RequestContext { + + static RequestContext rawRequest(UUID accountId, String requestId) { + return new RequestContextImpl(accountId, requestId); + } + + /** + * The identifier used to identify the request. For example, this + * could be a plugin's name. + * + * @return the identifier of this context. + */ + String getRequesterIdentifier(); // TODO maybe use something like a "hierarchical key" (similar to permissions) or namespaced + + UUID getAccountIdentifier(); +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/request/RequestContextFactory.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/request/RequestContextFactory.java new file mode 100644 index 0000000..e53a193 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/request/RequestContextFactory.java @@ -0,0 +1,8 @@ +package org.minecraftoss.catacomb.account.request; + +import java.util.UUID; + +public interface RequestContextFactory { + + RequestContext fromAccountIdentifier(UUID accountIdentifier); +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/request/RequestContextImpl.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/request/RequestContextImpl.java new file mode 100644 index 0000000..3155193 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/account/request/RequestContextImpl.java @@ -0,0 +1,42 @@ +package org.minecraftoss.catacomb.account.request; + +import java.util.UUID; + +public class RequestContextImpl implements RequestContext { + + private final UUID accountIdentifier; + private final String requestIdentifier; + + protected RequestContextImpl(UUID accountIdentifier, String requestIdentifier) { + this.accountIdentifier = accountIdentifier; + this.requestIdentifier = requestIdentifier; + } + + @Override + public UUID getAccountIdentifier() { + return this.accountIdentifier; + } + + @Override + public String getRequesterIdentifier() { + return this.requestIdentifier; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof RequestContextImpl)) return false; + + RequestContextImpl that = (RequestContextImpl) o; + + if (!accountIdentifier.equals(that.accountIdentifier)) return false; + return requestIdentifier.equals(that.requestIdentifier); + } + + @Override + public int hashCode() { + int result = accountIdentifier.hashCode(); + result = 31 * result + requestIdentifier.hashCode(); + return result; + } +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/currency/Currency.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/currency/Currency.java new file mode 100644 index 0000000..994a497 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/currency/Currency.java @@ -0,0 +1,5 @@ +package org.minecraftoss.catacomb.currency; + +public interface Currency { + // TODO +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/Transaction.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/Transaction.java new file mode 100644 index 0000000..5f86964 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/Transaction.java @@ -0,0 +1,25 @@ +package org.minecraftoss.catacomb.transaction; + +import org.minecraftoss.catacomb.currency.Currency; +import org.minecraftoss.catacomb.account.Account; + +import java.math.BigDecimal; +import java.util.HashSet; +import java.util.Set; + +public interface Transaction { + + static Transaction of(Account accountFrom, Account accountTo, Currency currency, BigDecimal amount, Set contexts) { + return new TransactionImpl(accountFrom, accountTo, currency, amount, new HashSet<>(contexts)); + } + + Account getAccountFrom(); + + Account getAccountTo(); + + Currency getCurrency(); + + BigDecimal getAmount(); + + Set getContexts(); +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionCondition.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionCondition.java new file mode 100644 index 0000000..94728a5 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionCondition.java @@ -0,0 +1,67 @@ +package org.minecraftoss.catacomb.transaction; + +import java.util.function.Predicate; + +/** + * A TransactionCondition checks if a {@link Transaction} is valid or not. + * + *

As an example, if the balance of an account might not be below 0, + * a TransactionCondition can be used to check if the {@link Transaction} + * fulfills that requirement. + */ +@FunctionalInterface +public interface TransactionCondition extends Predicate { + + static TransactionCondition allOf(Iterable conditions) { + return transaction -> { + for (TransactionCondition condition : conditions) { + if (!condition.isFulfilled(transaction)) { + return false; + } + } + return true; + }; + } + + static TransactionCondition anyOf(Iterable conditions) { + return transaction -> { + for (TransactionCondition condition : conditions) { + if (condition.isFulfilled(transaction)) { + return true; + } + } + return false; + }; + } + + static TransactionCondition always() { + return transaction -> true; + } + + static TransactionCondition never() { + return transaction -> false; + } + + boolean isFulfilled(Transaction transaction); + + @Override + default boolean test(Transaction transaction) { + return isFulfilled(transaction); + } + + default TransactionCondition negate() { + return transaction -> !isFulfilled(transaction); + } + + default TransactionCondition and(TransactionCondition other) { + return transaction -> isFulfilled(transaction) && other.isFulfilled(transaction); + } + + default TransactionCondition or(TransactionCondition other) { + return transaction -> isFulfilled(transaction) || other.isFulfilled(transaction); + } + + default TransactionCondition xor(TransactionCondition other) { + return transaction -> isFulfilled(transaction) ^ other.isFulfilled(transaction); + } +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionContext.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionContext.java new file mode 100644 index 0000000..5998460 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionContext.java @@ -0,0 +1,12 @@ +package org.minecraftoss.catacomb.transaction; + +public interface TransactionContext { + + static TransactionContext of(String key, String value) { + return new TransactionContextImpl(key, value); + } + + String getKey(); + + String getValue(); +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionContextImpl.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionContextImpl.java new file mode 100644 index 0000000..64cdb1d --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionContextImpl.java @@ -0,0 +1,39 @@ +package org.minecraftoss.catacomb.transaction; + +class TransactionContextImpl implements TransactionContext { + private final String key; + private final String value; + + TransactionContextImpl(String key, String value) { + this.key = key; + this.value = value; + } + + @Override + public String getKey() { + return this.key; + } + + @Override + public String getValue() { + return this.value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof TransactionContextImpl)) return false; + + TransactionContextImpl that = (TransactionContextImpl) o; + + if (!key.equals(that.key)) return false; + return value.equals(that.value); + } + + @Override + public int hashCode() { + int result = key.hashCode(); + result = 31 * result + value.hashCode(); + return result; + } +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionImpl.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionImpl.java new file mode 100644 index 0000000..5fbd502 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/TransactionImpl.java @@ -0,0 +1,73 @@ +package org.minecraftoss.catacomb.transaction; + +import org.minecraftoss.catacomb.currency.Currency; +import org.minecraftoss.catacomb.account.Account; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.Set; + +class TransactionImpl implements Transaction { + private final Account accountFrom; + private final Account accountTo; + private final Currency currency; + private final BigDecimal amount; + private final Set contexts; + + TransactionImpl(Account accountFrom, Account accountTo, Currency currency, BigDecimal amount, Set contexts) { + this.accountFrom = accountFrom; + this.accountTo = accountTo; + this.currency = currency; + this.amount = amount; + this.contexts = Collections.unmodifiableSet(contexts); + } + + @Override + public Account getAccountFrom() { + return this.accountFrom; + } + + @Override + public Account getAccountTo() { + return this.accountTo; + } + + @Override + public Currency getCurrency() { + return this.currency; + } + + @Override + public BigDecimal getAmount() { + return this.amount; + } + + @Override + public Set getContexts() { + return this.contexts; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof TransactionImpl)) return false; + + TransactionImpl that = (TransactionImpl) o; + + if (!accountFrom.equals(that.accountFrom)) return false; + if (!accountTo.equals(that.accountTo)) return false; + if (!currency.equals(that.currency)) return false; + if (!amount.equals(that.amount)) return false; + return contexts.equals(that.contexts); + } + + @Override + public int hashCode() { + int result = accountFrom.hashCode(); + result = 31 * result + accountTo.hashCode(); + result = 31 * result + currency.hashCode(); + result = 31 * result + amount.hashCode(); + result = 31 * result + contexts.hashCode(); + return result; + } +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/result/BuiltinTransactionResultState.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/result/BuiltinTransactionResultState.java new file mode 100644 index 0000000..b329711 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/result/BuiltinTransactionResultState.java @@ -0,0 +1,12 @@ +package org.minecraftoss.catacomb.transaction.result; + +public enum BuiltinTransactionResultState implements TransactionResultState { + ACCEPTED, + DECLINED, + FAILED; + + @Override + public BuiltinTransactionResultState getParent() { + return this; + } +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/result/TransactionResult.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/result/TransactionResult.java new file mode 100644 index 0000000..26a20b0 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/result/TransactionResult.java @@ -0,0 +1,46 @@ +package org.minecraftoss.catacomb.transaction.result; + +import org.minecraftoss.catacomb.transaction.Transaction; + +public class TransactionResult { + private final TransactionResultState transactionResultState; + private final Transaction transaction; + + private TransactionResult(TransactionResultState transactionResultState, Transaction transaction) { + this.transactionResultState = transactionResultState; + this.transaction = transaction; + } + + public static TransactionResult of(TransactionResultState transactionResultState, Transaction transaction) { + return new TransactionResult(transactionResultState, transaction); + } + + public TransactionResultState getTransactionResultState() { + return this.transactionResultState; + } + + public Transaction getTransaction() { + return this.transaction; + } + + // TODO track changes? + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof TransactionResult)) return false; + + TransactionResult that = (TransactionResult) o; + + if (!transactionResultState.equals(that.transactionResultState)) return false; + return transaction.equals(that.transaction); + } + + @Override + public int hashCode() { + int result = transactionResultState.hashCode(); + result = 31 * result + transaction.hashCode(); + return result; + } +} diff --git a/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/result/TransactionResultState.java b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/result/TransactionResultState.java new file mode 100644 index 0000000..d21cea1 --- /dev/null +++ b/catacomb-common-api/src/main/java/org/minecraftoss/catacomb/transaction/result/TransactionResultState.java @@ -0,0 +1,6 @@ +package org.minecraftoss.catacomb.transaction.result; + +public interface TransactionResultState & TransactionResultState> { + + BuiltinTransactionResultState getParent(); +} diff --git a/catacomb-sponge-api/src/main/java/org/minecraftoss/catacomb/sponge/SpongeRequestContext.java b/catacomb-sponge-api/src/main/java/org/minecraftoss/catacomb/sponge/SpongeRequestContext.java new file mode 100644 index 0000000..09a9441 --- /dev/null +++ b/catacomb-sponge-api/src/main/java/org/minecraftoss/catacomb/sponge/SpongeRequestContext.java @@ -0,0 +1,20 @@ +package org.minecraftoss.catacomb.sponge; + +import org.minecraftoss.catacomb.account.request.RequestContext; +import org.spongepowered.api.plugin.PluginContainer; + +import java.util.UUID; + +public interface SpongeRequestContext extends RequestContext { + + static SpongeRequestContext pluginRequest(UUID accountId, PluginContainer plugin) { + return new SpongeRequestContextImpl(accountId, plugin); + } + + PluginContainer getPlugin(); + + @Override + default String getRequesterIdentifier() { + return getPlugin().getId(); + } +} diff --git a/catacomb-sponge-api/src/main/java/org/minecraftoss/catacomb/sponge/SpongeRequestContextFactory.java b/catacomb-sponge-api/src/main/java/org/minecraftoss/catacomb/sponge/SpongeRequestContextFactory.java new file mode 100644 index 0000000..49831c1 --- /dev/null +++ b/catacomb-sponge-api/src/main/java/org/minecraftoss/catacomb/sponge/SpongeRequestContextFactory.java @@ -0,0 +1,24 @@ +package org.minecraftoss.catacomb.sponge; + +import org.minecraftoss.catacomb.account.request.RequestContext; +import org.minecraftoss.catacomb.account.request.RequestContextFactory; +import org.spongepowered.api.plugin.PluginContainer; + +import java.util.UUID; + +public class SpongeRequestContextFactory implements RequestContextFactory { + private final PluginContainer plugin; + + SpongeRequestContextFactory(PluginContainer plugin) { + this.plugin = plugin; + } + + static SpongeRequestContextFactory forPlugin(PluginContainer plugin) { + return new SpongeRequestContextFactory(plugin); + } + + @Override + public RequestContext fromAccountIdentifier(UUID accountIdentifier) { + return SpongeRequestContext.pluginRequest(accountIdentifier, plugin); + } +} diff --git a/catacomb-sponge-api/src/main/java/org/minecraftoss/catacomb/sponge/SpongeRequestContextImpl.java b/catacomb-sponge-api/src/main/java/org/minecraftoss/catacomb/sponge/SpongeRequestContextImpl.java new file mode 100644 index 0000000..915399c --- /dev/null +++ b/catacomb-sponge-api/src/main/java/org/minecraftoss/catacomb/sponge/SpongeRequestContextImpl.java @@ -0,0 +1,38 @@ +package org.minecraftoss.catacomb.sponge; + +import org.minecraftoss.catacomb.account.request.RequestContextImpl; +import org.spongepowered.api.plugin.PluginContainer; + +import java.util.UUID; + +class SpongeRequestContextImpl extends RequestContextImpl implements SpongeRequestContext { + private final PluginContainer plugin; + + SpongeRequestContextImpl(UUID accountIdentifier, PluginContainer requestIdentifier) { + super(accountIdentifier, requestIdentifier.getId()); + this.plugin = requestIdentifier; + } + + @Override + public PluginContainer getPlugin() { + return this.plugin; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof SpongeRequestContextImpl)) return false; + if (!super.equals(o)) return false; + + SpongeRequestContextImpl that = (SpongeRequestContextImpl) o; + + return plugin.equals(that.plugin); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + plugin.hashCode(); + return result; + } +}