diff --git a/build.gradle b/build.gradle index 1b53e6e..9afb985 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,10 @@ buildscript { dependencies { + // Material Design classpath group: 'de.dynamicfiles.projects.gradle.plugins', name: 'javafx-gradle-plugin', version: '8.8.2' + + // Database + } repositories { mavenLocal() diff --git a/fasel-jfx/build.gradle b/fasel-jfx/build.gradle index 1e15f7f..47874fd 100644 --- a/fasel-jfx/build.gradle +++ b/fasel-jfx/build.gradle @@ -6,21 +6,38 @@ repositories { mavenCentral() } -// Note that the test dependencies (junit, …) are inferred from the -// sourceSet.test of the core subproject -dependencies { - implementation 'com.jfoenix:jfoenix:8.0.7' +ext { + smackVersion="4.4.0-alpha2-SNAPSHOT" } -repositories { - mavenLocal() - mavenCentral() +dependencies { + + // Smack + compile "org.igniterealtime.smack:smack-java7:$smackVersion" + compile "org.igniterealtime.smack:smack-resolver-dnsjava:$smackVersion" + compile "org.igniterealtime.smack:smack-tcp:$smackVersion" + compile "org.igniterealtime.smack:smack-openpgp:$smackVersion" + compile "org.igniterealtime.smack:smack-experimental:$smackVersion" + + // JFX + implementation 'com.jfoenix:jfoenix:8.0.7' + implementation 'de.jensd:fontawesomefx:8.9' + + // Database + implementation 'javax.persistence:javax.persistence-api:2.2' + implementation 'com.j256.ormlite:ormlite-core:5.1' + implementation 'com.j256.ormlite:ormlite-jdbc:5.1' + implementation 'com.h2database:h2:1.4.197' + + // Lombok + compile 'org.projectlombok:lombok:1.18.6' + annotationProcessor 'org.projectlombok:lombok:1.18.6' + + testCompile 'junit:junit:4.12' } jfx { - // minimal requirement for jfxJar-task mainClass = 'de.vanitasvitae.fasel.sample.Main' - // minimal requirement for jfxNative-task vendor = 'vanitasvitae' } \ No newline at end of file diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/Configs.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/Configs.java new file mode 100644 index 0000000..21606e2 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/Configs.java @@ -0,0 +1,22 @@ +package de.vanitasvitae.fasel; + +public class Configs { + + /** + * Application wide configurations. + */ + public interface ApplicationConfig { + + boolean isDebug(); + void setIsDebug(boolean debug); + + boolean isUIDummy(); + } + + /** + * Account specific configurations. + */ + public interface AccountConfig { + + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/FaselApplication.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/FaselApplication.java index bb9042e..1137780 100644 --- a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/FaselApplication.java +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/FaselApplication.java @@ -1,5 +1,8 @@ package de.vanitasvitae.fasel; +import java.sql.SQLException; + + import de.vanitasvitae.fasel.ui.container.LoginController; import javafx.application.Application; import javafx.fxml.FXMLLoader; @@ -10,9 +13,21 @@ import javafx.stage.Stage; public class FaselApplication extends Application { private Stage primaryStage; + private static FaselApplication INSTANCE; + + private FaselApplication() throws SQLException { + } + + public static FaselApplication getInstance() throws SQLException { + if (INSTANCE == null) { + INSTANCE = new FaselApplication(); + } + return INSTANCE; + } @Override - public void start(Stage primaryStage) throws Exception{ + public void start(Stage primaryStage) throws Exception { + INSTANCE = this; this.primaryStage = primaryStage; FXMLLoader loader = new FXMLLoader(); loader.setLocation(getClass().getResource("/fxml/container/login_container.fxml")); @@ -20,7 +35,7 @@ public class FaselApplication extends Application { LoginController controller = loader.getController(); controller.setApplication(this); Scene scene = new Scene(root, 1200, 741); - primaryStage.setTitle("Hello World"); + primaryStage.setTitle("Fasel - Login"); primaryStage.setScene(scene); primaryStage.show(); } diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/AbstractDatabase.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/AbstractDatabase.java new file mode 100644 index 0000000..08def97 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/AbstractDatabase.java @@ -0,0 +1,40 @@ +package de.vanitasvitae.fasel.db; + +import java.sql.SQLException; +import java.util.List; + +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.TableUtils; + +public abstract class AbstractDatabase { + + private final ConnectionSource connectionSource; + + protected AbstractDatabase() throws SQLException { + connectionSource = DatabaseService.getConnectionSource(getDatabaseName()); + setupTables(); + } + + public ConnectionSource getConnectionSource() { + return connectionSource; + } + + protected abstract List> getTables(); + + protected abstract String getDatabaseName(); + + private void setupTables() throws SQLException { + List> tableClasses = getTables(); + if (tableClasses == null) { + throw new IllegalStateException("getTables cannot return null!"); + } + + for (Class clazz : tableClasses) { + createTableIfNotExists(clazz); + } + } + + private void createTableIfNotExists(Class clazz) throws SQLException { + TableUtils.createTableIfNotExists(connectionSource, clazz); + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/DatabaseService.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/DatabaseService.java new file mode 100644 index 0000000..1a861e4 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/DatabaseService.java @@ -0,0 +1,26 @@ +package de.vanitasvitae.fasel.db; + +import java.sql.SQLException; + +import com.j256.ormlite.support.ConnectionSource; + +public class DatabaseService { + + private static DatabaseCreator CREATOR; + + public interface DatabaseCreator { + ConnectionSource getConnectionSource(String databaseName) throws SQLException; + } + + public static ConnectionSource getConnectionSource(String databaseName) throws SQLException { + if (CREATOR == null) { + throw new IllegalStateException("No DatabaseCreator set in DatabaseService."); + } + + return CREATOR.getConnectionSource(databaseName); + } + + public static void setDatabaseCreator(DatabaseCreator creator) { + CREATOR = creator; + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/H2DatabaseCreator.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/H2DatabaseCreator.java new file mode 100644 index 0000000..e6da5c6 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/H2DatabaseCreator.java @@ -0,0 +1,28 @@ +package de.vanitasvitae.fasel.db; + +import java.io.File; +import java.sql.SQLException; + +import com.j256.ormlite.jdbc.JdbcConnectionSource; +import com.j256.ormlite.support.ConnectionSource; + +public class H2DatabaseCreator implements DatabaseService.DatabaseCreator { + + private final File directory; + + public H2DatabaseCreator(File directory) { + if (directory == null) { + throw new IllegalArgumentException("Directory cannot be null!"); + } + this.directory = directory; + } + + @Override + public ConnectionSource getConnectionSource(String databaseName) throws SQLException { + return new JdbcConnectionSource(getH2DatabaseURL(directory, databaseName)); + } + + private static String getH2DatabaseURL(File directory, String databaseName) { + return "jdbc:h2:" + new File(directory, databaseName).getAbsolutePath(); + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/AccountDao.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/AccountDao.java new file mode 100644 index 0000000..9b5759a --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/AccountDao.java @@ -0,0 +1,8 @@ +package de.vanitasvitae.fasel.db.dao; + +import com.j256.ormlite.dao.Dao; +import de.vanitasvitae.fasel.db.entity.Account; + +public interface AccountDao extends Dao { + +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/AvatarDao.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/AvatarDao.java new file mode 100644 index 0000000..7a912a2 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/AvatarDao.java @@ -0,0 +1,8 @@ +package de.vanitasvitae.fasel.db.dao; + +import com.j256.ormlite.dao.Dao; +import de.vanitasvitae.fasel.db.entity.Avatar; + +public interface AvatarDao extends Dao { + +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/ContactDao.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/ContactDao.java new file mode 100644 index 0000000..7a4d6e0 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/ContactDao.java @@ -0,0 +1,8 @@ +package de.vanitasvitae.fasel.db.dao; + +import com.j256.ormlite.dao.Dao; +import de.vanitasvitae.fasel.db.entity.Contact; + +public interface ContactDao extends Dao { + +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/XmppEntityDao.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/XmppEntityDao.java new file mode 100644 index 0000000..67ad258 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/XmppEntityDao.java @@ -0,0 +1,8 @@ +package de.vanitasvitae.fasel.db.dao; + +import com.j256.ormlite.dao.Dao; +import de.vanitasvitae.fasel.db.entity.XmppEntity; + +public interface XmppEntityDao extends Dao { + +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/AccountDaoImpl.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/AccountDaoImpl.java new file mode 100644 index 0000000..770c972 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/AccountDaoImpl.java @@ -0,0 +1,21 @@ +package de.vanitasvitae.fasel.db.dao.impl; + +import java.sql.SQLException; +import java.util.List; + +import com.j256.ormlite.dao.BaseDaoImpl; +import com.j256.ormlite.support.ConnectionSource; +import de.vanitasvitae.fasel.db.dao.AccountDao; +import de.vanitasvitae.fasel.db.entity.Account; + +public class AccountDaoImpl extends BaseDaoImpl implements AccountDao { + + public AccountDaoImpl(ConnectionSource connectionSource) + throws SQLException { + super(connectionSource, Account.class); + } + + public List getAccounts() throws SQLException { + return queryForAll(); + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/AvatarDaoImpl.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/AvatarDaoImpl.java new file mode 100644 index 0000000..80ae597 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/AvatarDaoImpl.java @@ -0,0 +1,39 @@ +package de.vanitasvitae.fasel.db.dao.impl; + +import java.sql.SQLException; +import java.util.List; + +import com.j256.ormlite.dao.BaseDaoImpl; +import com.j256.ormlite.support.ConnectionSource; +import de.vanitasvitae.fasel.db.dao.AvatarDao; +import de.vanitasvitae.fasel.db.entity.Avatar; +import de.vanitasvitae.fasel.db.entity.XmppEntity; + +public class AvatarDaoImpl extends BaseDaoImpl implements AvatarDao { + + public AvatarDaoImpl(ConnectionSource connectionSource) + throws SQLException { + super(connectionSource, Avatar.class); + } + + /** + * TODO: Test + * @param entity + * @return + * @throws SQLException + */ + public Avatar getAvatarForEntity(XmppEntity entity) throws SQLException { + if (entity == null) { + throw new IllegalArgumentException("XmppEntity cannot be null!"); + } + + List avatars = queryForEq("entity", entity.getEntityID()); + if (avatars.isEmpty()) { + return null; + } else if (avatars.size() == 1) { + return avatars.get(0); + } else { + throw new SQLException("There are more than one Avatar for entity " + entity.toString()); + } + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/ContactDaoImpl.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/ContactDaoImpl.java new file mode 100644 index 0000000..47d2036 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/ContactDaoImpl.java @@ -0,0 +1,37 @@ +package de.vanitasvitae.fasel.db.dao.impl; + +import java.sql.SQLException; +import java.util.List; + +import com.j256.ormlite.dao.BaseDaoImpl; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import de.vanitasvitae.fasel.db.dao.ContactDao; +import de.vanitasvitae.fasel.db.entity.Account; +import de.vanitasvitae.fasel.db.entity.Contact; +import de.vanitasvitae.fasel.db.entity.XmppEntity; + +public class ContactDaoImpl extends BaseDaoImpl implements ContactDao { + + public ContactDaoImpl(ConnectionSource connectionSource) + throws SQLException { + super(connectionSource, Contact.class); + } + + // TODO: Test + public List getContactsOf(Account account) throws SQLException { + return queryForEq(Contact.ACCOUNT, account.getAccountId()); + } + + public List getContactsByJid(String jid) throws SQLException { + XmppEntityDaoImpl entityDao = DaoManager.createDao(getConnectionSource(), XmppEntity.class); + List contacts = queryBuilder() + .join(Contact.ENTITY, XmppEntity.ENTITY_ID, entityDao.queryBuilder()) + .where().eq(XmppEntity.JID, jid).query(); + return contacts; + } + + public List getAllContacts() throws SQLException { + return queryForAll(); + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/XmppEntityDaoImpl.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/XmppEntityDaoImpl.java new file mode 100644 index 0000000..614858c --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/dao/impl/XmppEntityDaoImpl.java @@ -0,0 +1,21 @@ +package de.vanitasvitae.fasel.db.dao.impl; + +import java.sql.SQLException; +import java.util.List; + +import com.j256.ormlite.dao.BaseDaoImpl; +import com.j256.ormlite.support.ConnectionSource; +import de.vanitasvitae.fasel.db.dao.XmppEntityDao; +import de.vanitasvitae.fasel.db.entity.XmppEntity; + +public class XmppEntityDaoImpl extends BaseDaoImpl implements XmppEntityDao { + + public XmppEntityDaoImpl(ConnectionSource connectionSource) + throws SQLException { + super(connectionSource, XmppEntity.class); + } + + public List getXmppEntityByJid(String jid) throws SQLException { + return queryForEq(XmppEntity.JID, jid); + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/databases/AccountDatabase.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/databases/AccountDatabase.java new file mode 100644 index 0000000..6300740 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/databases/AccountDatabase.java @@ -0,0 +1,47 @@ +package de.vanitasvitae.fasel.db.databases; + +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; + +import com.j256.ormlite.dao.DaoManager; +import de.vanitasvitae.fasel.db.AbstractDatabase; +import de.vanitasvitae.fasel.db.dao.impl.AccountDaoImpl; +import de.vanitasvitae.fasel.db.dao.impl.ContactDaoImpl; +import de.vanitasvitae.fasel.db.dao.impl.XmppEntityDaoImpl; +import de.vanitasvitae.fasel.db.entity.Account; +import de.vanitasvitae.fasel.db.entity.Contact; +import de.vanitasvitae.fasel.db.entity.XmppEntity; + +public class AccountDatabase extends AbstractDatabase { + + public AccountDatabase() throws SQLException { + super(); + } + + @Override + protected List> getTables() { + return Arrays.asList( + Account.class, + XmppEntity.class, + Contact.class + ); + } + + @Override + protected String getDatabaseName() { + return "accounts"; + } + + public AccountDaoImpl getAccountDao() throws SQLException { + return DaoManager.createDao(getConnectionSource(), Account.class); + } + + public XmppEntityDaoImpl getXmppEntityDao() throws SQLException { + return DaoManager.createDao(getConnectionSource(), XmppEntity.class); + } + + public ContactDaoImpl getContactDao() throws SQLException { + return DaoManager.createDao(getConnectionSource(), Contact.class); + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/databases/AvatarDatabase.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/databases/AvatarDatabase.java new file mode 100644 index 0000000..56ba310 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/databases/AvatarDatabase.java @@ -0,0 +1,31 @@ +package de.vanitasvitae.fasel.db.databases; + +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; + +import com.j256.ormlite.dao.DaoManager; +import de.vanitasvitae.fasel.db.AbstractDatabase; +import de.vanitasvitae.fasel.db.dao.impl.AvatarDaoImpl; +import de.vanitasvitae.fasel.db.entity.Avatar; + +public class AvatarDatabase extends AbstractDatabase { + + public AvatarDatabase() throws SQLException { + super(); + } + + @Override + protected List> getTables() { + return Arrays.asList(Avatar.class); + } + + @Override + protected String getDatabaseName() { + return "avatars"; + } + + public AvatarDaoImpl getAvatarDao() throws SQLException { + return DaoManager.createDao(getConnectionSource(), Avatar.class); + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/databases/OmemoDatabase.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/databases/OmemoDatabase.java new file mode 100644 index 0000000..fdf4154 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/databases/OmemoDatabase.java @@ -0,0 +1,24 @@ +package de.vanitasvitae.fasel.db.databases; + +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; + +import de.vanitasvitae.fasel.db.AbstractDatabase; + +public class OmemoDatabase extends AbstractDatabase { + + public OmemoDatabase() throws SQLException { + super(); + } + + @Override + protected List> getTables() { + return Arrays.asList(); + } + + @Override + protected String getDatabaseName() { + return "omemo"; + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Account.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Account.java new file mode 100644 index 0000000..8b4caf7 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Account.java @@ -0,0 +1,69 @@ +package de.vanitasvitae.fasel.db.entity; + +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import de.vanitasvitae.fasel.db.dao.impl.AccountDaoImpl; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@EqualsAndHashCode +@DatabaseTable(tableName = "accounts", daoClass = AccountDaoImpl.class) +public class Account { + + public static final String ACCOUNT_ID = "accountID"; + public static final String SERVICE_ADDRESS = "serviceAddress"; + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; + public static final String ENTITY = "entity"; + public static final String ENABLED = "enabled"; + + @Getter + @DatabaseField(generatedId = true, columnName = ACCOUNT_ID, dataType = DataType.LONG) + private long accountId; + + @Getter + @Setter + @DatabaseField(canBeNull = false, columnName = SERVICE_ADDRESS, uniqueCombo = true, dataType = DataType.STRING) + private String serviceAddress; + + @Getter + @Setter + @DatabaseField(canBeNull = false, columnName = USERNAME, uniqueCombo = true, dataType = DataType.STRING) + private String username; + + @Getter + @Setter + @DatabaseField(columnName = PASSWORD, dataType = DataType.STRING) + private String password; + + @Getter + @Setter + @DatabaseField(foreign = true, columnName = ENTITY, canBeNull = false, foreignAutoCreate = true, foreignAutoRefresh = true) + private XmppEntity baseEntity; + + @Getter + @Setter + @DatabaseField(canBeNull = false, columnName = ENABLED, defaultValue = "false", dataType = DataType.BOOLEAN) + private boolean enabled; + + /** + * Empty account for ORMLite. + */ + public Account() { + + } + + public Account(String username, String service, String password) { + this.username = username; + this.serviceAddress = service; + this.password = password; + this.baseEntity = new XmppEntity(username + "@" + service); + } + + @Override + public String toString() { + return "Account[" + accountId + ", " + serviceAddress + ", " + username + ", " + password + ", " + baseEntity + ", " + enabled + "]"; + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Avatar.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Avatar.java new file mode 100644 index 0000000..667425b --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Avatar.java @@ -0,0 +1,40 @@ +package de.vanitasvitae.fasel.db.entity; + +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import lombok.Getter; +import lombok.Setter; + +@DatabaseTable(tableName = "Avatars") +public class Avatar { + + public static final String AVATAR_ID = "avatarID"; + public static final String ENTITY = "entity"; + public static final String IMAGE = "image"; + public static final String HASH = "hash"; + + @Getter + @Setter + @DatabaseField(generatedId = true, columnName = AVATAR_ID, dataType = DataType.LONG) + private Long avatarID; + + @Getter + @Setter + @DatabaseField(foreign = true, columnName = ENTITY, unique = true) + private XmppEntity entity; + + @Getter + @Setter + @DatabaseField(columnName = IMAGE, dataType = DataType.BYTE_ARRAY) + private byte[] image; + + @Getter + @Setter + @DatabaseField(columnName = HASH, dataType = DataType.STRING) + private String hash; + + public Avatar() { + + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Chat.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Chat.java new file mode 100644 index 0000000..caaef29 --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Chat.java @@ -0,0 +1,23 @@ +package de.vanitasvitae.fasel.db.entity; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import lombok.Getter; +import lombok.Setter; + +@DatabaseTable(tableName = "chats") +public class Chat { + + public static final String CHAT_ID = "chatID"; + public static final String CONTACT = "contact"; + + @Getter + @Setter + @DatabaseField(generatedId = true, columnName = CHAT_ID) + private long chatID; + + @Getter + @Setter + @DatabaseField(foreign = true, columnName = CONTACT, unique = true) + private Contact contact; +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Contact.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Contact.java new file mode 100644 index 0000000..9a04ade --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/Contact.java @@ -0,0 +1,51 @@ +package de.vanitasvitae.fasel.db.entity; + +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import de.vanitasvitae.fasel.db.dao.impl.ContactDaoImpl; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@EqualsAndHashCode +@DatabaseTable(tableName = "contacts", daoClass = ContactDaoImpl.class) +public class Contact { + + public static final String CONTACT_ID = "contactID"; + public static final String ACCOUNT = "account"; + public static final String ENTITY = "entity"; + public static final String NICKNAME = "nickname"; + + @Getter + @DatabaseField(generatedId = true, columnName = CONTACT_ID, dataType = DataType.LONG) + private long contactID; + + @Getter + @Setter + @DatabaseField(foreign = true, columnName = ACCOUNT) + private Account account; + + @Getter + @Setter + @DatabaseField(foreign = true, columnName = ENTITY, foreignAutoRefresh = true, foreignAutoCreate = true) + private XmppEntity entity; + + @Getter + @Setter + @DatabaseField(dataType = DataType.STRING, columnName = NICKNAME) + private String nickname; + + public Contact() { + + } + + public Contact(String jid, String nickname) { + this.entity = new XmppEntity(jid); + this.nickname = nickname; + } + + public String toString() { + return "Contact[" + contactID + ", " + account + ", " + entity + ", " + nickname + "]"; + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/XmppEntity.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/XmppEntity.java new file mode 100644 index 0000000..a1e6dfe --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/db/entity/XmppEntity.java @@ -0,0 +1,39 @@ +package de.vanitasvitae.fasel.db.entity; + +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import de.vanitasvitae.fasel.db.dao.impl.XmppEntityDaoImpl; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@EqualsAndHashCode +@DatabaseTable(tableName = "entities", daoClass = XmppEntityDaoImpl.class) +public class XmppEntity { + + public static final String ENTITY_ID = "entityID"; + public static final String JID = "jid"; + + public XmppEntity() { + + } + + public XmppEntity(String jid) { + this.jid = jid; + } + + @Getter + @DatabaseField(generatedId = true, columnName = ENTITY_ID, dataType = DataType.LONG) + private long entityID; + + @Getter + @Setter + @DatabaseField(columnName = JID, dataType = DataType.STRING) + private String jid; + + @Override + public String toString() { + return "XmppEntity[" + entityID + ", " + jid + "]"; + } +} diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/ui/fragment/LoginFragmentController.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/ui/fragment/LoginFragmentController.java index 79a202a..b50d794 100644 --- a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/ui/fragment/LoginFragmentController.java +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/ui/fragment/LoginFragmentController.java @@ -6,6 +6,9 @@ import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXPasswordField; import com.jfoenix.controls.JFXTextField; import de.vanitasvitae.fasel.FaselApplication; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; @@ -43,13 +46,30 @@ public class LoginFragmentController { }); } + private static void setUsernameValidator(JFXTextField text_username) { + text_username.textProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observableValue, String oldValue, String newValue) { + ObservableList styleClass = text_username.getStyleClass(); + if (newValue.length() < 5) { + if (styleClass.contains("error")) { + return; + } + styleClass.add("error"); + } else { + styleClass.removeAll("error"); + } + } + }); + } + private void switchToMainScene() throws IOException { FXMLLoader loader = new FXMLLoader(); loader.setLocation(getClass().getResource("/fxml/container/main_container.fxml")); Parent root = loader.load(); Scene scene = new Scene(root, 1200, 741); - main.getPrimaryStage().setTitle("Hello World"); + main.getPrimaryStage().setTitle("Fasel"); main.getPrimaryStage().setScene(scene); // primaryStage.show(); } diff --git a/fasel-jfx/src/main/java/de/vanitasvitae/fasel/xmpp/XmppConnectionService.java b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/xmpp/XmppConnectionService.java new file mode 100644 index 0000000..169598a --- /dev/null +++ b/fasel-jfx/src/main/java/de/vanitasvitae/fasel/xmpp/XmppConnectionService.java @@ -0,0 +1,47 @@ +package de.vanitasvitae.fasel.xmpp; + +import java.io.IOException; +import java.util.Map; +import java.util.WeakHashMap; + +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.tcp.XMPPTCPConnection; + +import de.vanitasvitae.fasel.db.entity.Account; +import org.jxmpp.stringprep.XmppStringprepException; + +public final class XmppConnectionService { + + private final XMPPTCPConnection connection; + + private static final Map CONNECTIONS = new WeakHashMap<>(); + + public static XmppConnectionService connectionForAccount(Account account) throws XmppStringprepException { + XmppConnectionService connection = CONNECTIONS.get(account); + if (connection == null) { + connection = new XmppConnectionService(account.getUsername(), account.getServiceAddress(), account.getPassword()); + CONNECTIONS.put(account, connection); + } + return connection; + } + + private XmppConnectionService(String username, String serverAddress, String password) + throws XmppStringprepException { + connection = new XMPPTCPConnection(username, password, serverAddress); + } + + public XMPPConnection getConnection() { + return connection; + } + + public void login() throws InterruptedException, IOException, SmackException, XMPPException { + connection.connect(); + connection.login(); + } + + public void attachDatabase() { + + } +} diff --git a/fasel-jfx/src/main/resources/fxml/container/login_container.fxml b/fasel-jfx/src/main/resources/fxml/container/login_container.fxml index 7a343dc..8b6ed34 100644 --- a/fasel-jfx/src/main/resources/fxml/container/login_container.fxml +++ b/fasel-jfx/src/main/resources/fxml/container/login_container.fxml @@ -3,11 +3,7 @@ - + diff --git a/fasel-jfx/src/test/java/de/vanitasvitae/fasel/ContactsTest.java b/fasel-jfx/src/test/java/de/vanitasvitae/fasel/ContactsTest.java new file mode 100644 index 0000000..667ac42 --- /dev/null +++ b/fasel-jfx/src/test/java/de/vanitasvitae/fasel/ContactsTest.java @@ -0,0 +1,6 @@ +package de.vanitasvitae.fasel; + +public class ContactsTest { + + +} diff --git a/fasel-jfx/src/test/java/de/vanitasvitae/fasel/TestUtils.java b/fasel-jfx/src/test/java/de/vanitasvitae/fasel/TestUtils.java new file mode 100644 index 0000000..420dc4a --- /dev/null +++ b/fasel-jfx/src/test/java/de/vanitasvitae/fasel/TestUtils.java @@ -0,0 +1,21 @@ +package de.vanitasvitae.fasel; + +import java.io.File; +import java.util.Random; + +public class TestUtils { + + private static final Random RAND = new Random(); + + public static File getTempDir(String dirPrefix) { + return new File(System.getProperty("java.io.tmpdir"), randomFilename(dirPrefix, "")); + } + + public static File getTempFile(String prefix, String suffix) { + return new File(System.getProperty("java.io.tmpdir"), randomFilename(prefix, suffix)); + } + + public static String randomFilename(String prefix, String suffix) { + return prefix + RAND.nextInt() + suffix; + } +} diff --git a/fasel-jfx/src/test/java/de/vanitasvitae/fasel/database/AccountDatabaseTest.java b/fasel-jfx/src/test/java/de/vanitasvitae/fasel/database/AccountDatabaseTest.java new file mode 100644 index 0000000..e53a3cc --- /dev/null +++ b/fasel-jfx/src/test/java/de/vanitasvitae/fasel/database/AccountDatabaseTest.java @@ -0,0 +1,69 @@ +package de.vanitasvitae.fasel.database; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; + +import java.io.File; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + +import de.vanitasvitae.fasel.TestUtils; +import de.vanitasvitae.fasel.db.DatabaseService; +import de.vanitasvitae.fasel.db.H2DatabaseCreator; +import de.vanitasvitae.fasel.db.databases.AccountDatabase; +import de.vanitasvitae.fasel.db.entity.Account; +import de.vanitasvitae.fasel.db.entity.Contact; +import de.vanitasvitae.fasel.db.entity.XmppEntity; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AccountDatabaseTest { + + private final AccountDatabase database; + + public AccountDatabaseTest() throws SQLException { + File file = TestUtils.getTempDir("accounttest_"); + DatabaseService.setDatabaseCreator(new H2DatabaseCreator(file)); + database = new AccountDatabase(); + } + + @Before + public void populate() throws SQLException { + Account account = new Account("alice", "wonderland.lit","secret"); + database.getAccountDao().createIfNotExists(account); + + assertEquals(account, database.getAccountDao().getAccounts().get(0)); + + Contact contact = new Contact("bob@builder.tv", "Bob the Builder"); + contact.setAccount(account); + database.getContactDao().createIfNotExists(contact); + + contact = new Contact("buggy@builder.tv", "Buggy"); + contact.setAccount(account); + database.getContactDao().createIfNotExists(contact); + + contact = new Contact("buggy@builder.tv", "Buggy"); + contact.setAccount(account); + database.getContactDao().createIfNotExists(contact); + + database.getXmppEntityDao().queryForAll().forEach(System.out::println); + assertEquals(2, database.getContactDao().getContactsOf(account).size()); + } + + @Test + public void queryContactTest() throws SQLException { + Account account = database.getAccountDao().getAccounts().get(0); + List contacts = database.getContactDao().getAllContacts(); + contacts.forEach(contact -> System.out.println(contact.toString())); + assertEquals(2, database.getContactDao().getAllContacts().size()); + assertEquals(2, database.getContactDao().getContactsOf(account).size()); + assertEquals(1, database.getContactDao().getContactsByJid("bob@builder.tv").size()); + } + + @After + public void closeConnection() throws IOException { + database.getConnectionSource().close(); + } +} diff --git a/fasel.mv.db b/fasel.mv.db new file mode 100644 index 0000000..cc8a798 Binary files /dev/null and b/fasel.mv.db differ