Convert some core.io classes to Kotlin

pull/699/head
Alinson S. Xavier 5 years ago
parent a02c7bdc44
commit 298bb01762

@ -1,69 +0,0 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.core.io;
import androidx.annotation.*;
import org.isoron.uhabits.core.models.*;
import java.io.*;
import java.util.*;
import javax.inject.*;
/**
* A GenericImporter decides which implementation of AbstractImporter is able to
* handle a given file and delegates to it the task of importing the data.
*/
public class GenericImporter extends AbstractImporter
{
List<AbstractImporter> importers;
@Inject
public GenericImporter(@NonNull HabitList habits,
@NonNull LoopDBImporter loopDBImporter,
@NonNull RewireDBImporter rewireDBImporter,
@NonNull TickmateDBImporter tickmateDBImporter,
@NonNull HabitBullCSVImporter habitBullCSVImporter)
{
super(habits);
importers = new LinkedList<>();
importers.add(loopDBImporter);
importers.add(rewireDBImporter);
importers.add(tickmateDBImporter);
importers.add(habitBullCSVImporter);
}
@Override
public boolean canHandle(@NonNull File file) throws IOException
{
for (AbstractImporter importer : importers)
if (importer.canHandle(file)) return true;
return false;
}
@Override
public void importHabitsFromFile(@NonNull File file) throws IOException
{
for (AbstractImporter importer : importers)
if (importer.canHandle(file)) importer.importHabitsFromFile(file);
}
}

@ -0,0 +1,61 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.core.io
import org.isoron.uhabits.core.models.*
import java.io.*
import javax.inject.*
/**
* A GenericImporter decides which implementation of AbstractImporter is able to
* handle a given file and delegates to it the task of importing the data.
*/
class GenericImporter
@Inject constructor(
habits: HabitList,
loopDBImporter: LoopDBImporter,
rewireDBImporter: RewireDBImporter,
tickmateDBImporter: TickmateDBImporter,
habitBullCSVImporter: HabitBullCSVImporter,
) : AbstractImporter(habits) {
var importers: List<AbstractImporter> = listOf(
loopDBImporter,
rewireDBImporter,
tickmateDBImporter,
habitBullCSVImporter,
)
override fun canHandle(file: File): Boolean {
for (importer in importers) {
if (importer.canHandle(file)) {
return true
}
}
return false
}
override fun importHabitsFromFile(file: File) {
for (importer in importers) {
if (importer.canHandle(file)) {
importer.importHabitsFromFile(file)
}
}
}
}

@ -1,101 +0,0 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.core.io;
import androidx.annotation.*;
import com.opencsv.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.utils.*;
import java.io.*;
import java.util.*;
import javax.inject.*;
import static org.isoron.uhabits.core.models.Entry.*;
/**
* Class that imports data from HabitBull CSV files.
*/
public class HabitBullCSVImporter extends AbstractImporter
{
private ModelFactory modelFactory;
@Inject
public HabitBullCSVImporter(@NonNull HabitList habits,
@NonNull ModelFactory modelFactory)
{
super(habits);
this.modelFactory = modelFactory;
}
@Override
public boolean canHandle(@NonNull File file) throws IOException
{
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = reader.readLine();
return line.startsWith("HabitName,HabitDescription,HabitCategory");
}
@Override
public void importHabitsFromFile(@NonNull final File file)
throws IOException
{
CSVReader reader = new CSVReader(new FileReader(file));
HashMap<String, Habit> map = new HashMap<>();
for (String line[] : reader)
{
String name = line[0];
if (name.equals("HabitName")) continue;
String description = line[1];
String dateString[] = line[3].split("-");
int year = Integer.parseInt(dateString[0]);
int month = Integer.parseInt(dateString[1]);
int day = Integer.parseInt(dateString[2]);
Calendar date = DateUtils.getStartOfTodayCalendar();
date.set(year, month - 1, day);
Timestamp timestamp = new Timestamp(date.getTimeInMillis());
int value = Integer.parseInt(line[4]);
if (value != 1) continue;
Habit h = map.get(name);
if (h == null)
{
h = modelFactory.buildHabit();
h.setName(name);
h.setDescription(description == null ? "" : description);
h.setFrequency(Frequency.DAILY);
habitList.add(h);
map.put(name, h);
}
h.getOriginalEntries().add(new Entry(timestamp, YES_MANUAL));
}
}
}

@ -0,0 +1,71 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.core.io
import com.opencsv.*
import org.isoron.uhabits.core.models.*
import org.isoron.uhabits.core.utils.*
import java.io.*
import java.util.*
import javax.inject.*
/**
* Class that imports data from HabitBull CSV files.
*/
class HabitBullCSVImporter
@Inject constructor(
habits: HabitList,
private val modelFactory: ModelFactory,
) : AbstractImporter(habits) {
override fun canHandle(file: File): Boolean {
val reader = BufferedReader(FileReader(file))
val line = reader.readLine()
return line.startsWith("HabitName,HabitDescription,HabitCategory")
}
override fun importHabitsFromFile(file: File) {
val reader = CSVReader(FileReader(file))
val map = HashMap<String, Habit>()
for (line in reader) {
val name = line[0]
if (name == "HabitName") continue
val description = line[1]
val dateString = line[3].split("-").toTypedArray()
val year = dateString[0].toInt()
val month = dateString[1].toInt()
val day = dateString[2].toInt()
val date = DateUtils.getStartOfTodayCalendar()
date[year, month - 1] = day
val timestamp = Timestamp(date.timeInMillis)
val value = line[4].toInt()
if (value != 1) continue
var h = map[name]
if (h == null) {
h = modelFactory.buildHabit()
h.name = name
h.description = description ?: ""
h.frequency = Frequency.DAILY
habitList.add(h)
map[name] = h
}
h.originalEntries.add(Entry(timestamp, Entry.YES_MANUAL))
}
}
}

@ -31,3 +31,28 @@ interface Logger {
fun error(msg: String) fun error(msg: String)
fun error(exception: Exception) fun error(exception: Exception)
} }
class StandardLogging : Logging {
override fun getLogger(name: String): Logger {
return StandardLogger(name)
}
}
class StandardLogger(val name: String): Logger {
override fun info(msg: String) {
println("[$name] $msg")
}
override fun debug(msg: String) {
println("[$name] $msg")
}
override fun error(msg: String) {
println("[$name] $msg")
}
override fun error(exception: Exception) {
exception.printStackTrace()
}
}

@ -1,145 +0,0 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.core.io;
import androidx.annotation.*;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.commands.*;
import org.isoron.uhabits.core.database.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.models.sqlite.records.*;
import java.io.*;
import java.util.*;
import javax.inject.*;
import static org.isoron.uhabits.core.ConstantsKt.*;
/**
* Class that imports data from database files exported by Loop Habit Tracker.
*/
public class LoopDBImporter extends AbstractImporter
{
@NonNull
private final ModelFactory modelFactory;
@NonNull
private final DatabaseOpener opener;
@NonNull
private final CommandRunner runner;
@Inject
public LoopDBImporter(@AppScope @NonNull HabitList habitList,
@AppScope @NonNull ModelFactory modelFactory,
@AppScope @NonNull DatabaseOpener opener,
@AppScope @NonNull CommandRunner runner)
{
super(habitList);
this.modelFactory = modelFactory;
this.opener = opener;
this.runner = runner;
}
@Override
public boolean canHandle(@NonNull File file) throws IOException
{
if (!isSQLite3File(file)) return false;
Database db = opener.open(file);
boolean canHandle = true;
Cursor c = db.query("select count(*) from SQLITE_MASTER " +
"where name='Habits' or name='Repetitions'");
if (!c.moveToNext() || c.getInt(0) != 2)
{
// Log.w("LoopDBImporter", "Cannot handle file: tables not found");
canHandle = false;
}
if (db.getVersion() > DATABASE_VERSION)
{
// Log.w("LoopDBImporter", String.format(
// "Cannot handle file: incompatible version: %d > %d",
// db.getVersion(), DATABASE_VERSION));
canHandle = false;
}
c.close();
db.close();
return canHandle;
}
@Override
public synchronized void importHabitsFromFile(@NonNull File file)
{
Database db = opener.open(file);
MigrationHelper helper = new MigrationHelper(db);
helper.migrateTo(DATABASE_VERSION);
Repository<HabitRecord> habitsRepository;
Repository<EntryRecord> entryRepository;
habitsRepository = new Repository<>(HabitRecord.class, db);
entryRepository = new Repository<>(EntryRecord.class, db);
List<HabitRecord> habitRecords = habitsRepository.findAll("order by position");
for (HabitRecord habitRecord : habitRecords)
{
List<EntryRecord> entryRecords =
entryRepository.findAll("where habit = ?",
habitRecord.id.toString());
Habit habit = habitList.getByUUID(habitRecord.uuid);
Command command;
if (habit == null)
{
habit = modelFactory.buildHabit();
habitRecord.id = null;
habitRecord.copyTo(habit);
command = new CreateHabitCommand(modelFactory, habitList, habit);
command.run();
}
else
{
Habit modified = modelFactory.buildHabit();
habitRecord.id = habit.getId();
habitRecord.copyTo(modified);
command = new EditHabitCommand(habitList, habit.getId(), modified);
command.run();
}
// Reload saved version of the habit
habit = habitList.getByUUID(habitRecord.uuid);
for (EntryRecord r : entryRecords)
{
Timestamp t = new Timestamp(r.timestamp);
Entry existingEntry = habit.getOriginalEntries().get(t);
if (existingEntry.getValue() != r.value)
new CreateRepetitionCommand(habitList, habit, t, r.value).run();
}
runner.notifyListeners(command);
}
db.close();
}
}

@ -0,0 +1,103 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.core.io
import org.isoron.uhabits.core.*
import org.isoron.uhabits.core.commands.*
import org.isoron.uhabits.core.database.*
import org.isoron.uhabits.core.models.*
import org.isoron.uhabits.core.models.sqlite.records.*
import java.io.*
import javax.inject.*
/**
* Class that imports data from database files exported by Loop Habit Tracker.
*/
class LoopDBImporter
@Inject constructor(
@AppScope val habitList: HabitList,
@AppScope val modelFactory: ModelFactory,
@AppScope val opener: DatabaseOpener,
@AppScope val runner: CommandRunner,
@AppScope logging: Logging,
) : AbstractImporter(habitList) {
private val logger = logging.getLogger("LoopDBImporter")
override fun canHandle(file: File): Boolean {
if (!isSQLite3File(file)) return false
val db = opener.open(file)!!
var canHandle = true
val c = db.query("select count(*) from SQLITE_MASTER where name='Habits' or name='Repetitions'")
if (!c.moveToNext() || c.getInt(0) != 2) {
logger.error("Cannot handle file: tables not found")
canHandle = false
}
if (db.version > DATABASE_VERSION) {
logger.error("Cannot handle file: incompatible version: ${db.version} > $DATABASE_VERSION")
canHandle = false
}
c.close()
db.close()
return canHandle
}
override fun importHabitsFromFile(file: File) {
val db = opener.open(file)!!
val helper = MigrationHelper(db)
helper.migrateTo(DATABASE_VERSION)
val habitsRepository = Repository(HabitRecord::class.java, db)
val entryRepository = Repository(EntryRecord::class.java, db)
for (habitRecord in habitsRepository.findAll("order by position")) {
var habit = habitList.getByUUID(habitRecord.uuid)
val entryRecords = entryRepository.findAll("where habit = ?", habitRecord.id.toString())
var command: Command
if (habit == null) {
habit = modelFactory.buildHabit()
habitRecord.id = null
habitRecord.copyTo(habit)
command = CreateHabitCommand(modelFactory, habitList, habit)
command.run()
} else {
val modified = modelFactory.buildHabit()
habitRecord.id = habit.id
habitRecord.copyTo(modified)
command = EditHabitCommand(habitList, habit.id!!, modified)
command.run()
}
// Reload saved version of the habit
habit = habitList.getByUUID(habitRecord.uuid)
for (r in entryRecords) {
val t = Timestamp(r.timestamp)
val (_, value) = habit!!.originalEntries.get(t)
if (value != r.value) CreateRepetitionCommand(habitList, habit, t, r.value).run()
}
runner.notifyListeners(command)
}
db.close()
}
}

@ -134,7 +134,7 @@ public class ImportTest extends BaseUnitTest
assertTrue(file.canRead()); assertTrue(file.canRead());
GenericImporter importer = new GenericImporter(habitList, GenericImporter importer = new GenericImporter(habitList,
new LoopDBImporter(habitList, modelFactory, databaseOpener, commandRunner), new LoopDBImporter(habitList, modelFactory, databaseOpener, commandRunner, new StandardLogging()),
new RewireDBImporter(habitList, modelFactory, databaseOpener), new RewireDBImporter(habitList, modelFactory, databaseOpener),
new TickmateDBImporter(habitList, modelFactory, databaseOpener), new TickmateDBImporter(habitList, modelFactory, databaseOpener),
new HabitBullCSVImporter(habitList, modelFactory)); new HabitBullCSVImporter(habitList, modelFactory));

Loading…
Cancel
Save