X-Git-Url: https://git.ktnx.net/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fnet%2Fktnx%2Fmobileledger%2Fasync%2FRetrieveTransactionsTask.java;h=d092a1cbfc55f1f0294cef1f6fc583248e14efa6;hb=a87079ed41bdc3ad89fe8bd15dfba10e37b29b76;hp=1d69fa2941a1f0963f5857c560f15bf244e2d751;hpb=20c03b7a5eb152d42fbbe9ecbaae27530563b398;p=mobile-ledger.git diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index 1d69fa29..d092a1cb 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -24,19 +24,20 @@ import android.os.OperationCanceledException; import androidx.annotation.NonNull; +import com.fasterxml.jackson.databind.RuntimeJsonMappingException; + import net.ktnx.mobileledger.App; import net.ktnx.mobileledger.err.HTTPException; -import net.ktnx.mobileledger.json.v1_15.AccountListParser; -import net.ktnx.mobileledger.json.v1_15.ParsedBalance; -import net.ktnx.mobileledger.json.v1_15.ParsedLedgerAccount; -import net.ktnx.mobileledger.json.v1_15.ParsedLedgerTransaction; -import net.ktnx.mobileledger.json.v1_15.TransactionListParser; +import net.ktnx.mobileledger.json.AccountListParser; +import net.ktnx.mobileledger.json.ApiNotSupportedException; +import net.ktnx.mobileledger.json.TransactionListParser; import net.ktnx.mobileledger.model.Data; import net.ktnx.mobileledger.model.LedgerAccount; import net.ktnx.mobileledger.model.LedgerTransaction; import net.ktnx.mobileledger.model.LedgerTransactionAccount; import net.ktnx.mobileledger.model.MobileLedgerProfile; import net.ktnx.mobileledger.ui.MainModel; +import net.ktnx.mobileledger.utils.Logger; import net.ktnx.mobileledger.utils.NetworkUtil; import java.io.BufferedReader; @@ -119,6 +120,9 @@ public class RetrieveTransactionsTask extends return null; } } + public MobileLedgerProfile getProfile() { + return profile; + } @Override protected void onProgressUpdate(Progress... values) { super.onProgressUpdate(values); @@ -356,9 +360,9 @@ public class RetrieveTransactionsTask extends throwIfCancelled(); } } - private @NonNull - LedgerAccount ensureAccountExists(String accountName, HashMap map, - ArrayList createdAccounts) { + @NonNull + public LedgerAccount ensureAccountExists(String accountName, HashMap map, + ArrayList createdAccounts) { LedgerAccount acc = map.get(accountName); if (acc != null) @@ -377,7 +381,43 @@ public class RetrieveTransactionsTask extends createdAccounts.add(acc); return acc; } - private List retrieveAccountList() throws IOException, HTTPException { + public void addNumberOfPostings(int number) { + expectedPostingsCount += number; + } + private List retrieveAccountList() + throws IOException, HTTPException, ApiNotSupportedException { + final SendTransactionTask.API apiVersion = profile.getApiVersion(); + if (apiVersion.equals(SendTransactionTask.API.auto)) { + return retrieveAccountListAnyVersion(); + } + else if (apiVersion.equals(SendTransactionTask.API.html)) { + Logger.debug("json", + "Declining using JSON API for /accounts with configured legacy API version"); + return null; + } + else { + return retrieveAccountListForVersion(apiVersion); + } + } + private List retrieveAccountListAnyVersion() + throws HTTPException, ApiNotSupportedException { + for (SendTransactionTask.API ver : SendTransactionTask.API.allVersions) { + try { + return retrieveAccountListForVersion(ver); + } + catch (Exception e) { + Logger.debug("json", + String.format(Locale.US, "Error during account list retrieval using API %s", + ver.getDescription())); + } + + throw new ApiNotSupportedException(); + } + + throw new RuntimeException("This should never be reached"); + } + private List retrieveAccountListForVersion(SendTransactionTask.API version) + throws IOException, HTTPException { HttpURLConnection http = NetworkUtil.prepareConnection(profile, "accounts"); http.setAllowUserInteraction(false); switch (http.getResponseCode()) { @@ -401,58 +441,15 @@ public class RetrieveTransactionsTask extends if (http.getResponseCode() != 200) throw new IOException(String.format("HTTP error %d", http.getResponseCode())); - AccountListParser parser = new AccountListParser(resp); + AccountListParser parser = AccountListParser.forApiVersion(version, resp); expectedPostingsCount = 0; while (true) { throwIfCancelled(); - ParsedLedgerAccount parsedAccount = parser.nextAccount(); - if (parsedAccount == null) { + LedgerAccount acc = parser.nextAccount(this, map); + if (acc == null) break; - } - expectedPostingsCount += parsedAccount.getAnumpostings(); - final String accName = parsedAccount.getAname(); - LedgerAccount acc = map.get(accName); - if (acc != null) - throw new RuntimeException( - String.format("Account '%s' already present", acc.getName())); - String parentName = LedgerAccount.extractParentName(accName); - ArrayList createdParents = new ArrayList<>(); - LedgerAccount parent; - if (parentName == null) { - parent = null; - } - else { - parent = ensureAccountExists(parentName, map, createdParents); - parent.setHasSubAccounts(true); - } - acc = new LedgerAccount(profile, accName, parent); list.add(acc); - map.put(accName, acc); - - String lastCurrency = null; - float lastCurrencyAmount = 0; - for (ParsedBalance b : parsedAccount.getAibalance()) { - throwIfCancelled(); - final String currency = b.getAcommodity(); - final float amount = b.getAquantity() - .asFloat(); - if (currency.equals(lastCurrency)) { - lastCurrencyAmount += amount; - } - else { - if (lastCurrency != null) { - acc.addAmount(lastCurrencyAmount, lastCurrency); - } - lastCurrency = currency; - lastCurrencyAmount = amount; - } - } - if (lastCurrency != null) { - acc.addAmount(lastCurrencyAmount, lastCurrency); - } - for (LedgerAccount p : createdParents) - acc.propagateAmountsTo(p); } throwIfCancelled(); } @@ -469,7 +466,40 @@ public class RetrieveTransactionsTask extends return list; } private List retrieveTransactionList() - throws IOException, ParseException, HTTPException { + throws ParseException, HTTPException, IOException, ApiNotSupportedException { + final SendTransactionTask.API apiVersion = profile.getApiVersion(); + if (apiVersion.equals(SendTransactionTask.API.auto)) { + return retrieveTransactionListAnyVersion(); + } + else if (apiVersion.equals(SendTransactionTask.API.html)) { + Logger.debug("json", + "Declining using JSON API for /accounts with configured legacy API version"); + return null; + } + else { + return retrieveTransactionListForVersion(apiVersion); + } + + } + private List retrieveTransactionListAnyVersion() + throws ApiNotSupportedException { + for (SendTransactionTask.API ver : SendTransactionTask.API.allVersions) { + try { + return retrieveTransactionListForVersion(ver); + } + catch (Exception | HTTPException e) { + Logger.debug("json", + String.format(Locale.US, "Error during account list retrieval using API %s", + ver.getDescription())); + } + + throw new ApiNotSupportedException(); + } + + throw new RuntimeException("This should never be reached"); + } + private List retrieveTransactionListForVersion( + SendTransactionTask.API apiVersion) throws IOException, ParseException, HTTPException { Progress progress = new Progress(); progress.setTotal(expectedPostingsCount); @@ -488,18 +518,17 @@ public class RetrieveTransactionsTask extends try (InputStream resp = http.getInputStream()) { throwIfCancelled(); - TransactionListParser parser = new TransactionListParser(resp); + TransactionListParser parser = TransactionListParser.forApiVersion(apiVersion, resp); int processedPostings = 0; while (true) { throwIfCancelled(); - ParsedLedgerTransaction parsedTransaction = parser.nextTransaction(); + LedgerTransaction transaction = parser.nextTransaction(); throwIfCancelled(); - if (parsedTransaction == null) + if (transaction == null) break; - LedgerTransaction transaction = parsedTransaction.asLedgerTransaction(); trList.add(transaction); progress.setProgress(processedPostings += transaction.getAccounts() @@ -538,10 +567,15 @@ public class RetrieveTransactionsTask extends List transactions; try { accounts = retrieveAccountList(); + // accounts is null in API-version auto-detection and means + // requesting 'html' API version via the JSON classes + // this can't work, and the null results in the legacy code below + // being called if (accounts == null) transactions = null; else transactions = retrieveTransactionList(); + if (accounts == null || transactions == null) { accounts = new ArrayList<>(); transactions = new ArrayList<>(); @@ -564,6 +598,10 @@ public class RetrieveTransactionsTask extends e.printStackTrace(); return new Result(e.getLocalizedMessage()); } + catch (RuntimeJsonMappingException e) { + e.printStackTrace(); + return new Result(Result.ERR_JSON_PARSER_ERROR); + } catch (ParseException e) { e.printStackTrace(); return new Result("Network error"); @@ -572,11 +610,15 @@ public class RetrieveTransactionsTask extends e.printStackTrace(); return new Result("Operation cancelled"); } + catch (ApiNotSupportedException e) { + e.printStackTrace(); + return new Result("Server version not supported"); + } finally { Data.backgroundTaskFinished(); } } - private void throwIfCancelled() { + public void throwIfCancelled() { if (isCancelled()) throw new OperationCanceledException(null); } @@ -661,6 +703,7 @@ public class RetrieveTransactionsTask extends } public static class Result { + public static String ERR_JSON_PARSER_ERROR = "err_json_parser"; public String error; public List accounts; public List transactions;