X-Git-Url: https://git.ktnx.net/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fnet%2Fktnx%2Fmobileledger%2Fasync%2FRetrieveTransactionsTask.java;h=b004ec9a0f1a11e6077f3327c0425365a3b4e443;hb=b30e9bd1cb3347a5db4b53729e491f4adcbb12ba;hp=aa47d73d403cc456bf6fca05a7046e8dbd421241;hpb=8098a8b37a4331b9faf6cf50a51a0d7aa9677421;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 aa47d73d..b004ec9a 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -18,15 +18,26 @@ package net.ktnx.mobileledger.async; import android.annotation.SuppressLint; -import android.database.sqlite.SQLiteDatabase; import android.os.AsyncTask; import android.os.OperationCanceledException; import androidx.annotation.NonNull; +import androidx.room.Transaction; +import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.RuntimeJsonMappingException; -import net.ktnx.mobileledger.App; +import net.ktnx.mobileledger.dao.AccountDAO; +import net.ktnx.mobileledger.dao.AccountValueDAO; +import net.ktnx.mobileledger.dao.TransactionAccountDAO; +import net.ktnx.mobileledger.dao.TransactionDAO; +import net.ktnx.mobileledger.db.Account; +import net.ktnx.mobileledger.db.AccountWithAmounts; +import net.ktnx.mobileledger.db.DB; +import net.ktnx.mobileledger.db.Option; +import net.ktnx.mobileledger.db.Profile; +import net.ktnx.mobileledger.db.TransactionAccount; +import net.ktnx.mobileledger.db.TransactionWithAccounts; import net.ktnx.mobileledger.err.HTTPException; import net.ktnx.mobileledger.json.API; import net.ktnx.mobileledger.json.AccountListParser; @@ -36,10 +47,10 @@ 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 net.ktnx.mobileledger.utils.Profiler; import java.io.BufferedReader; import java.io.IOException; @@ -52,6 +63,7 @@ import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -75,21 +87,18 @@ public class RetrieveTransactionsTask extends private static final Pattern reEnd = Pattern.compile("\\bid=\"addmodal\""); private static final Pattern reDecimalPoint = Pattern.compile("\\.\\d\\d?$"); private static final Pattern reDecimalComma = Pattern.compile(",\\d\\d?$"); + private static final String TAG = "RTT"; // %3A is '=' private final Pattern reAccountName = Pattern.compile("/register\\?q=inacct%3A([a-zA-Z0-9%]+)\""); private final Pattern reAccountValue = Pattern.compile( "\\s*([-+]?[\\d.,]+)(?:\\s+(\\S+))?"); private final MainModel mainModel; - private final MobileLedgerProfile profile; - private final List prevAccounts; + private final Profile profile; private int expectedPostingsCount = -1; - public RetrieveTransactionsTask(@NonNull MainModel mainModel, - @NonNull MobileLedgerProfile profile, - List accounts) { + public RetrieveTransactionsTask(@NonNull MainModel mainModel, @NonNull Profile profile) { this.mainModel = mainModel; this.profile = profile; - this.prevAccounts = accounts; } private static void L(String msg) { //debug("transaction-parser", msg); @@ -325,7 +334,7 @@ public class RetrieveTransactionsTask extends state = ParserState.EXPECTING_TRANSACTION; L(String.format("transaction %s parsed → expecting transaction", - transaction.getId())); + transaction.getLedgerId())); // sounds like a good idea, but transaction-1 may not be the first one chronologically // for example, when you add the initial seeding transaction after entering some others @@ -340,8 +349,9 @@ public class RetrieveTransactionsTask extends LedgerTransactionAccount lta = parseTransactionAccountLine(line); if (lta != null) { transaction.addAccount(lta); - L(String.format(Locale.ENGLISH, "%d: %s = %s", transaction.getId(), - lta.getAccountName(), lta.getAmount())); + L(String.format(Locale.ENGLISH, "%d: %s = %s", + transaction.getLedgerId(), lta.getAccountName(), + lta.getAmount())); } else throw new IllegalStateException( @@ -384,7 +394,7 @@ public class RetrieveTransactionsTask extends } private List retrieveAccountList() throws IOException, HTTPException, ApiNotSupportedException { - final API apiVersion = profile.getApiVersion(); + final API apiVersion = API.valueOf(profile.getApiVersion()); if (apiVersion.equals(API.auto)) { return retrieveAccountListAnyVersion(); } @@ -398,21 +408,20 @@ public class RetrieveTransactionsTask extends } } private List retrieveAccountListAnyVersion() - throws HTTPException, ApiNotSupportedException { + throws ApiNotSupportedException, IOException, HTTPException { for (API ver : API.allVersions) { try { return retrieveAccountListForVersion(ver); } - catch (Exception e) { + catch (JsonParseException | RuntimeJsonMappingException e) { Logger.debug("json", String.format(Locale.US, "Error during account list retrieval using API %s", - ver.getDescription())); + ver.getDescription()), e); } - throw new ApiNotSupportedException(); } - throw new RuntimeException("This should never be reached"); + throw new ApiNotSupportedException(); } private List retrieveAccountListForVersion(API version) throws IOException, HTTPException { @@ -427,12 +436,8 @@ public class RetrieveTransactionsTask extends throw new HTTPException(http.getResponseCode(), http.getResponseMessage()); } publishProgress(Progress.indeterminate()); - SQLiteDatabase db = App.getDatabase(); ArrayList list = new ArrayList<>(); HashMap map = new HashMap<>(); - HashMap currentMap = new HashMap<>(); - for (LedgerAccount acc : prevAccounts) - currentMap.put(acc.getName(), acc); throwIfCancelled(); try (InputStream resp = http.getInputStream()) { throwIfCancelled(); @@ -452,20 +457,11 @@ public class RetrieveTransactionsTask extends throwIfCancelled(); } - // the current account tree may have changed, update the new-to be tree to match - for (LedgerAccount acc : list) { - LedgerAccount prevData = currentMap.get(acc.getName()); - if (prevData != null) { - acc.setExpanded(prevData.isExpanded()); - acc.setAmountsExpanded(prevData.amountsExpanded()); - } - } - return list; } private List retrieveTransactionList() throws ParseException, HTTPException, IOException, ApiNotSupportedException { - final API apiVersion = profile.getApiVersion(); + final API apiVersion = API.valueOf(profile.getApiVersion()); if (apiVersion.equals(API.auto)) { return retrieveTransactionListAnyVersion(); } @@ -485,16 +481,15 @@ public class RetrieveTransactionsTask extends try { return retrieveTransactionListForVersion(ver); } - catch (Exception | HTTPException e) { + 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"); + throw new ApiNotSupportedException(); } private List retrieveTransactionListForVersion(API apiVersion) throws IOException, ParseException, HTTPException { @@ -552,7 +547,7 @@ public class RetrieveTransactionsTask extends .compareTo(o1.getDate()); if (res != 0) return res; - return Long.compare(o2.getId(), o1.getId()); + return Long.compare(o2.getLedgerId(), o1.getLedgerId()); }); return trList; } @@ -579,7 +574,10 @@ public class RetrieveTransactionsTask extends transactions = new ArrayList<>(); retrieveTransactionListLegacy(accounts, transactions); } - mainModel.setAndStoreAccountAndTransactionListFromWeb(accounts, transactions); + + storeAccountsAndTransactions(accounts, transactions); + + mainModel.updateDisplayedTransactionsFromWeb(transactions); return new Result(accounts, transactions); } @@ -589,8 +587,8 @@ public class RetrieveTransactionsTask extends } catch (HTTPException e) { e.printStackTrace(); - return new Result(String.format("HTTP error %d: %s", e.getResponseCode(), - e.getResponseMessage())); + return new Result( + String.format("HTTP error %d: %s", e.getResponseCode(), e.getMessage())); } catch (IOException e) { e.printStackTrace(); @@ -616,6 +614,71 @@ public class RetrieveTransactionsTask extends Data.backgroundTaskFinished(); } } + @Transaction + private void storeAccountsAndTransactions(List accounts, + List transactions) { + AccountDAO accDao = DB.get() + .getAccountDAO(); + TransactionDAO trDao = DB.get() + .getTransactionDAO(); + TransactionAccountDAO trAccDao = DB.get() + .getTransactionAccountDAO(); + AccountValueDAO valDao = DB.get() + .getAccountValueDAO(); + + Logger.debug(TAG, "Preparing account list"); + final List list = new ArrayList<>(); + for (LedgerAccount acc : accounts) { + final AccountWithAmounts a = acc.toDBOWithAmounts(); + Account existing = accDao.getByNameSync(profile.getId(), acc.getName()); + if (existing != null) { + a.account.setExpanded(existing.isExpanded()); + a.account.setAmountsExpanded(existing.isAmountsExpanded()); + a.account.setId( + existing.getId()); // not strictly needed, but since we have it anyway... + } + + list.add(a); + } + Logger.debug(TAG, "Account list prepared. Storing"); + accDao.storeAccountsSync(list, profile.getId()); + Logger.debug(TAG, "Account list stored"); + + Profiler tranProfiler = new Profiler("transactions"); + Profiler tranAccProfiler = new Profiler("transaction accounts"); + + Logger.debug(TAG, "Storing transactions"); + long trGen = trDao.getGenerationSync(profile.getId()); + for (LedgerTransaction tr : transactions) { + TransactionWithAccounts tran = tr.toDBO(); + tran.transaction.setGeneration(trGen); + tran.transaction.setProfileId(profile.getId()); + + tranProfiler.opStart(); + tran.transaction.setId(trDao.insertSync(tran.transaction)); + tranProfiler.opEnd(); + + for (TransactionAccount trAcc : tran.accounts) { + trAcc.setGeneration(trGen); + trAcc.setTransactionId(tran.transaction.getId()); + tranAccProfiler.opStart(); + trAcc.setId(trAccDao.insertSync(trAcc)); + tranAccProfiler.opEnd(); + } + } + + tranProfiler.dumpStats(); + tranAccProfiler.dumpStats(); + + Logger.debug(TAG, "Transactions stored. Purging old"); + trDao.purgeOldTransactionsSync(profile.getId(), trGen); + Logger.debug(TAG, "Old transactions purged"); + + DB.get() + .getOptionDAO() + .insertSync(new Option(profile.getId(), Option.OPT_LAST_SCRAPE, + String.valueOf((new Date()).getTime()))); + } public void throwIfCancelled() { if (isCancelled()) throw new OperationCanceledException(null);