data.User.java Source code

Java tutorial

Introduction

Here is the source code for data.User.java

Source

/*
 * Copyright (C) 2017 stephan
 *
 * This program 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.
 *
 * This program 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 data;

import com.mongodb.client.AggregateIterable;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import db.common.DBManagerMongo;
import db.common.DBManagerPostgres;
import db.interfaces.DBEntity;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.Binary;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.eq;

/**
 * @author stephan
 */

public class User implements DBEntity {

    private int remoteHash;
    private String loginName;
    private String firstName;
    private String lastName;
    private ROLE role;
    private String email;
    private byte[] password;
    private byte[] salt;
    private char[] newPassword;
    private char[] newPasswordAgain;
    private char[] oldPassword;

    private User(int remoteHash, String loginName, String firstName, String lastName, ROLE role, String email,
            byte[] password, byte[] salt) {
        this.remoteHash = remoteHash;
        this.loginName = loginName;
        this.firstName = firstName;
        this.lastName = lastName;
        this.role = role;
        this.email = email;
        this.password = password;
        this.salt = salt;
    }

    public User(String loginName, String firstName, String lastName, ROLE role, String email, byte[] password,
            byte[] salt) {
        this.loginName = loginName;
        this.firstName = firstName;
        this.lastName = lastName;
        this.role = role;
        this.email = email;
        this.password = password;
        this.salt = salt;
    }

    public User(String loginName, String firstName, String lastName, ROLE role, String email, char[] password,
            char[] passwordAgain) {
        this.loginName = loginName;
        this.firstName = firstName;
        this.lastName = lastName;
        this.role = role;
        this.email = email;
        this.newPassword = password;
        this.newPasswordAgain = passwordAgain;
    }

    public static User getByPrimaryKey(String loginName, DBManagerPostgres db) throws Exception {
        try (Connection con = db.getConnection()) {
            String sql = "SELECT HASH, FIRST_NAME, LAST_NAME, ROLE, " + "SALT, PASSWORD, LOGIN_NAME, EMAIL "
                    + "FROM USERS " + "WHERE LOGIN_NAME = ?";

            int index = 1;
            PreparedStatement ps = con.prepareStatement(sql);
            ps.setString(index++, loginName);

            ResultSet rs = ps.executeQuery();
            if (!rs.next())
                throw new Exception("No such record");

            return extractUser(rs, db);
        }
    }

    public static ArrayList<User> getAvailableUsersFor(int projectId, DBManagerPostgres db) throws Exception {
        ArrayList<User> l = new ArrayList<>();

        try (Connection con = db.getConnection()) {
            String sql = "SELECT USERS.HASH, USERS.FIRST_NAME, USERS.LAST_NAME, USERS.ROLE, "
                    + "USERS.SALT, USERS.PASSWORD, USERS.LOGIN_NAME, USERS.EMAIL " + "FROM USERS "
                    + "RIGHT JOIN PROJECT_MEMBERS " + "ON PROJECT_MEMBERS.USER_LOGIN_NAME = USERS.LOGIN_NAME "
                    + "WHERE PROJECT_MEMBERS.PROJECT_ID IS NULL OR PROJECT_MEMBERS.PROJECT_ID != ?";
            PreparedStatement ps = con.prepareStatement(sql);
            int index = 1;
            ps.setInt(index++, projectId);

            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                User u = extractUser(rs, db);
                l.add(u);
            }
        }
        return l;
    }

    public static List<User> getAll(DBManagerPostgres db) throws Exception {
        ArrayList<User> l = new ArrayList<>();

        try (Connection con = db.getConnection()) {
            String sql = "SELECT HASH, FIRST_NAME, LAST_NAME, ROLE, " + "SALT, PASSWORD, LOGIN_NAME, EMAIL "
                    + "FROM USERS ";
            PreparedStatement ps = con.prepareStatement(sql);

            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                User u = extractUser(rs, db);
                l.add(u);
            }
        }
        return l;
    }

    private static User extractUser(ResultSet rs, DBManagerPostgres db) throws Exception {
        int hash = rs.getInt("HASH");
        String firstName = rs.getString("FIRST_NAME");
        String lastName = rs.getString("LAST_NAME");
        String role = rs.getString("ROLE");
        byte[] salt = rs.getBytes("SALT");
        byte[] password = rs.getBytes("PASSWORD");
        String loginName = rs.getString("LOGIN_NAME");
        String email = rs.getString("EMAIL");

        return new User(hash, loginName, firstName, lastName, User.ROLE.valueOf(role), email, password, salt);
    }

    public char[] getOldPassword() {
        return oldPassword;
    }

    public void setOldPassword(char[] oldPassword) {
        this.oldPassword = oldPassword;
    }

    public char[] getNewPasswordAgain() {
        return newPasswordAgain;
    }

    public byte[] getPassword() {
        return password;
    }

    public void setPassword(byte[] password) {
        this.password = password;
    }

    public byte[] getSalt() {
        return salt;
    }

    public void setSalt(byte[] salt) {
        this.salt = salt;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String userName) {
        this.loginName = userName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public ROLE getRole() {
        return role;
    }

    public void setRole(ROLE role) {
        this.role = role;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public boolean isChanged() {
        return getLocalHash() != getRemoteHash();
    }

    public int getLocalHash() {
        return new HashCodeBuilder().append(firstName).append(lastName).append(role).append(loginName).append(email)
                .hashCode();
    }

    public int getRemoteHash() {
        return remoteHash;
    }

    public void setRemoteHash(int hash) {
        this.remoteHash = hash;
    }

    public char[] getNewPassword() {
        return newPassword;
    }

    public void setNewPassword(char[] newPassword) {
        this.newPassword = newPassword;
    }

    public void insertIntoDb(DBManagerPostgres db) throws Exception {
        try (Connection con = db.getConnection()) {
            String sql = "INSERT INTO USERS(HASH, FIRST_NAME, LAST_NAME, ROLE, "
                    + "SALT, PASSWORD, LOGIN_NAME, EMAIL) " + "VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?)";
            PreparedStatement ps = con.prepareStatement(sql);

            int index = 1;
            ps.setInt(index++, getLocalHash());
            ps.setString(index++, getFirstName());
            ps.setString(index++, getLastName());
            ps.setString(index++, getRole().name());
            ps.setBytes(index++, getSalt());
            ps.setBytes(index++, getPassword());
            ps.setString(index++, getLoginName());
            ps.setString(index++, getEmail());

            ps.executeUpdate();
            setRemoteHash(getLocalHash());
        }
    }

    public void updateInDb(DBManagerPostgres db) throws Exception {
        try (Connection con = db.getConnection()) {
            String sql = "UPDATE USERS SET HASH = ?, FIRST_NAME = ?, LAST_NAME = ?, ROLE = ?, "
                    + "SALT = ?, PASSWORD = ?, LOGIN_NAME = ?, EMAIL = ? " + "WHERE LOGIN_NAME = ? AND HASH = ?";

            PreparedStatement ps = con.prepareStatement(sql);

            int index = 1;
            ps.setInt(index++, getLocalHash());
            ps.setString(index++, getFirstName());
            ps.setString(index++, getLastName());
            ps.setString(index++, getRole().name());
            ps.setBytes(index++, getSalt());
            ps.setBytes(index++, getPassword());
            ps.setString(index++, getLoginName());
            ps.setString(index++, getEmail());

            ps.setString(index++, getLoginName());
            ps.setInt(index++, getRemoteHash());

            int numRowsAffected = ps.executeUpdate();
            if (numRowsAffected == 0)
                throw new Exception("Record has changed or was not found!");
        }
    }

    public void deleteFromDb(DBManagerPostgres db) throws Exception {
        try (Connection con = db.getConnection()) {
            String sql = "DELETE FROM USERS " + "WHERE LOGIN_NAME = ? AND HASH = ?";

            PreparedStatement ps = con.prepareStatement(sql);
            int index = 1;
            ps.setString(index++, getLoginName());
            ps.setInt(index++, getRemoteHash());

            int numRowsAffected = ps.executeUpdate();
            if (numRowsAffected == 0)
                throw new Exception("Record has changed or was not found!");
        }
    }

    public static User getByPrimaryKey(String loginName, DBManagerMongo manager) throws Exception {
        MongoCollection<Document> coll = manager.getDb().getCollection("user");
        FindIterable<Document> doc = coll.find(eq("login_name", loginName));
        MongoCursor<Document> cursor = doc.iterator();
        if (!cursor.hasNext())
            throw new Exception("no such record");

        return extractUser(cursor.next());
    }

    public void deleteFromDb(DBManagerMongo manager) throws Exception {
        ArrayList<Project> ownedProjects = Project.getProjectsByUserName(getLoginName(), manager);
        for (Project p : ownedProjects)
            p.deleteFromDb(manager);

        MongoCollection<Document> coll = manager.getDb().getCollection("user");
        DeleteResult result = coll.deleteOne(and(eq("login_name", getLoginName()), eq("hash", getRemoteHash())));
        if (result.getDeletedCount() != 1)
            throw new Exception("Record was modyfied or not found");

        MongoCollection members = manager.getDb().getCollection("project_member");
        members.deleteMany(eq("user_login_name", getLoginName()));

        MongoCollection activities = manager.getDb().getCollection("activity");
        activities.deleteMany(eq("user_login_name", getLoginName()));

        MongoCollection project = manager.getDb().getCollection("project");
        project.deleteMany(eq("user_login_name", getLoginName()));
    }

    public static List<User> getAll(DBManagerMongo manager) throws Exception {
        ArrayList<User> list = new ArrayList<>();
        MongoCollection<Document> coll = manager.getDb().getCollection("user");
        FindIterable<Document> doc = coll.find();
        MongoCursor<Document> cursor = doc.iterator();
        while (cursor.hasNext())
            list.add(extractUser(cursor.next()));

        return list;
    }

    private static User extractUser(Document current) {
        String loginName = (String) current.get("login_name");
        int hash = (Integer) current.get("hash");
        String firstName = (String) current.get("first_name");
        String lastName = (String) current.get("last_name");
        String role = (String) current.get("role");
        String email = (String) current.get("email");
        Binary saltBinary = (Binary) current.get("salt");
        byte[] salt = saltBinary.getData();
        Binary passwordBinary = (Binary) current.get("password");
        byte[] password = passwordBinary.getData();
        return new User(hash, loginName, firstName, lastName, User.ROLE.valueOf(role), email, password, salt);
    }

    public static ArrayList<User> getAvailableUsersFor(int projectId, DBManagerMongo manager) throws Exception {
        ArrayList<User> list = new ArrayList<>();
        MongoCollection<Document> coll = manager.getDb().getCollection("user");
        Bson lookup = new Document("$lookup",
                new Document("from", "project_member").append("localField", "login_name")
                        .append("foreignField", "user_login_name") //local field, remote field
                        .append("as", "project_member"));

        List<Bson> filters = new ArrayList<>();
        filters.add(lookup);

        AggregateIterable<Document> it = coll.aggregate(filters);

        for (Document row : it) {
            boolean add = true;
            ArrayList<Document> members = (ArrayList<Document>) row.get("project_member");
            for (Document doc : members) {
                if (doc.getInteger("project_id") == projectId) {
                    add = false;
                    break;
                }
            }

            if (add)
                list.add(extractUser(row));

        }

        return list;
    }

    public void insertIntoDb(DBManagerMongo manager) throws Exception {
        MongoCollection<Document> coll = manager.getDb().getCollection("user");
        Document toAdd = new Document("hash", getLocalHash()).append("login_name", getLoginName())
                .append("first_name", getFirstName()).append("last_name", getLastName()).append("email", getEmail())
                .append("salt", getSalt()).append("password", getPassword()).append("role", getRole().name());
        coll.insertOne(toAdd);
    }

    public void updateInDb(DBManagerMongo manager) throws Exception {
        MongoCollection<Document> coll = manager.getDb().getCollection("user");
        Document toUpdate = new Document("hash", getLocalHash()).append("login_name", getLoginName())
                .append("first_name", getFirstName()).append("last_name", getLastName()).append("email", getEmail())
                .append("salt", getSalt()).append("password", getPassword()).append("role", getRole().name());

        UpdateResult result = coll.replaceOne(and(eq("login_name", getLoginName()), eq("hash", getRemoteHash())),
                toUpdate);
        if (result.getModifiedCount() != 1)
            throw new Exception("Record was modyfied or not found");
        setRemoteHash(getLocalHash());

    }

    public void deleteFromDB(DBManagerMongo manager) throws Exception {
        ArrayList<Project> ownedProjects = Project.getProjectsByUserName(getLoginName(), manager);
        for (Project p : ownedProjects)
            p.deleteFromDb(manager);

        MongoCollection<Document> coll = manager.getDb().getCollection("user");
        DeleteResult result = coll.deleteOne(and(eq("login_name", getLoginName()), eq("hash", getRemoteHash())));
        if (result.getDeletedCount() != 1)
            throw new Exception("Record was modyfied or not found");

        MongoCollection members = manager.getDb().getCollection("project_member");
        members.deleteMany(eq("user_login_name", getLoginName()));

        MongoCollection activities = manager.getDb().getCollection("activity");
        activities.deleteMany(eq("user_login_name", getLoginName()));

        MongoCollection project = manager.getDb().getCollection("project");
        project.deleteMany(eq("user_login_name", getLoginName()));
    }

    public enum ROLE {
        ADMIN, USER
    }
}