com.axway.academy.addressbook.core.AccountManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.axway.academy.addressbook.core.AccountManagerImpl.java

Source

/*
 * Copyright (c) Axway Academy, 2016. All Rights Reserved.
 */
package com.axway.academy.addressbook.core;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.ReplicationMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.exception.ConstraintViolationException;

import com.axway.academy.addressbook.api.Account;
import com.axway.academy.addressbook.api.Account.Id;
import com.axway.academy.addressbook.api.AccountCriterion;
import com.axway.academy.addressbook.api.AccountManager;
import com.axway.academy.addressbook.api.AddressBookEntry;
import com.axway.academy.addressbook.api.AddressBookEntryCriterion;
import com.axway.academy.addressbook.api.exceptions.AccountConstraintException;
import com.axway.academy.addressbook.api.exceptions.DuplicateAccountException;
import com.axway.academy.addressbook.api.exceptions.DuplicateAddressBookEntryException;
import com.axway.academy.addressbook.api.exceptions.NoSuchAccountException;
import com.axway.academy.addressbook.api.exceptions.NoSuchAddressBookEntryException;
import com.axway.academy.addressbook.api.exceptions.PasswordPolicyException;
import com.axway.academy.addressbook.beans.AccountBean;
import com.axway.academy.addressbook.beans.AddressBookEntryBean;
import com.axway.academy.addressbook.sql.SessionFactoryManager;
import com.axway.academy.addressbook.sql.SessionManagerFactory;

public class AccountManagerImpl implements AccountManager {

    /** The logger. */
    private static final Logger sLogger = Logger.getLogger(AccountManager.class);

    /** The single instance of the account manager. */
    private static final AccountManagerImpl sAccountManager = new AccountManagerImpl();

    private SessionFactoryManager mSessionFactoryManager;

    public AccountManagerImpl() {
        super();
        mSessionFactoryManager = SessionManagerFactory.getInstance().getSessionFactoryManager();
    }

    @Override
    public Account getAccount(Id accountId) throws NoSuchAccountException {
        Session session = mSessionFactoryManager.getSessionFactory().openSession();

        try {
            return getAccount(session, accountId);
        } finally {
            SessionManagerFactory.closeSession(session);
        }
    }

    @Override
    public Account getAccount(String name) throws NoSuchAccountException {
        Session session = mSessionFactoryManager.getSessionFactory().openSession();

        try {
            AccountCriterionImpl criterion = (AccountCriterionImpl) getAccountCriterion().named(name);
            Criteria criteria = criterion.getCriteria(session);
            Account account = (Account) criteria.uniqueResult();
            if (account == null) {
                throw new NoSuchAccountException(name);
            }
            return account;

        } finally {
            SessionManagerFactory.closeSession(session);
        }
    }

    @Override
    public Id newAccountId(String uuid) {
        return new AccountBean.Id(uuid);
    }

    @Override
    public Account createAccount(Account account)
            throws DuplicateAccountException, PasswordPolicyException, AccountConstraintException {
        return persistAccount(account);
    }

    /**
     * Persist a new account and a user associated with the account.
     *
     * @param account the new {@code Account} object that holds the account's attributes.
     * @param user the new {@code User} object that holds the user's attributes to be created along with the account.
     *            May be set to {@code null} to create an account without a user.
     * @return An array of the newly persisted {@code Account} and {@code User} objects.
     * @throws DuplicateAccountException if the specified account already exists.
     * @throws DuplicateUserException if the specified user already exists.
     * @throws PasswordPolicyException if the passphrase set for the user does not fulfill the password policy
     *             requirements.
     * @throws AccountConstraintException if the account home folder is not valid.
     */
    private Account persistAccount(Account account)
            throws DuplicateAccountException, PasswordPolicyException, AccountConstraintException {

        if (account.getId() != null) {
            throw new IllegalArgumentException("Instantiated from Template");
        }

        Session session = mSessionFactoryManager.getSessionFactory().openSession();

        try {

            ConstraintValidationUtil.validateNewAccount(session, (AccountBean) account);

            Transaction tx = session.beginTransaction();

            Account persistedAccount = account;
            try {
                if (account.getId() == null) {
                    // If object does not have an id, persist a copy so if exception is thrown original object is
                    // unchanged.
                    persistedAccount = ((AccountBean) account).copy();
                    session.save(persistedAccount);
                } else {
                    session.replicate(persistedAccount, ReplicationMode.OVERWRITE);
                }
            } catch (ConstraintViolationException ex) {
                // Assume this is a uniqueness violation on the name since that is the only constraint in this bean.
                throw new DuplicateAccountExceptionImpl(account, "Duplicate account: " + account.getLoginname(),
                        ex);
            } catch (HibernateException e) {
                final String message = "Database error creating account";
                throw new RuntimeException(message, e);
            }
            session.flush();

            tx.commit();

            if (sLogger.isDebugEnabled()) {
                sLogger.debug("76568:createAccount : " + account);
            }

            return persistedAccount;
        } finally {
            SessionManagerFactory.closeSession(session);
        }
    }

    @Override
    public void updateAccount(Account account) throws NoSuchAccountException, DuplicateAccountException,
            PasswordPolicyException, AccountConstraintException {

        Session session = mSessionFactoryManager.getSessionFactory().openSession();

        try {

            ConstraintValidationUtil.validateUpdateAccount(session, (AccountBean) account);

            Transaction tx = session.beginTransaction();

            try {
                session.replicate(account, ReplicationMode.OVERWRITE);
                session.flush();

            } catch (UnresolvableObjectException ex) {
                throw new NoSuchAccountException(account.getLoginname(), ex);
            } catch (ConstraintViolationException ex) {
                throw new DuplicateAccountExceptionImpl(account, "Duplicate account: " + account.getLoginname(),
                        ex);
            }

            tx.commit();

            if (sLogger.isDebugEnabled()) {
                sLogger.debug("76568: updateAccount updated: " + account, new Throwable("trace caller"));
            }

        } finally {
            SessionManagerFactory.closeSession(session);
        }

    }

    @Override
    public void deleteAccount(Id accountId) throws NoSuchAccountException {
        // TODO Auto-generated method stub

    }

    @Override
    public AccountCriterion getAccountCriterion() {
        return new AccountCriterionImpl();
    }

    @Override
    public List<Account> getAccounts(AccountCriterion criterion, int first, int count) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public List<Account> getAccounts(AccountCriterion criterion) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int getAccountCount(AccountCriterion criterion) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void disableAccount(Id accountId) throws NoSuchAccountException {
        // TODO Auto-generated method stub

    }

    @Override
    public void enableAccount(Id accountId) throws NoSuchAccountException {
        // TODO Auto-generated method stub

    }

    @Override
    public AddressBookEntry createAddressBookEntry(String accountName, AddressBookEntry addressBookEntry)
            throws NoSuchAccountException, DuplicateAddressBookEntryException {
        Account.Id accountId = getAccount(accountName).getId();
        Serializable[] result = persistAddressBookEntry(accountId, addressBookEntry);
        return (AddressBookEntry) result[1];
    }

    static void exists(Session session, Account.Id accountId) throws NoSuchAccountException {
        exists(session, accountId, null);
    }

    static void exists(Session session, Account.Id accountId, Boolean unlicensed) throws NoSuchAccountException {

        final AccountCriterion accountCriterion = sAccountManager.getAccountCriterion();
        if (!((CriterionBase) accountCriterion.id(accountId, true)).exists(session)) {
            throw new NoSuchAccountException(accountId.toString());
        }
    }

    private Serializable[] persistAddressBookEntry(Account.Id accountId, AddressBookEntry entry)
            throws NoSuchAccountException, DuplicateAddressBookEntryException {

        Session session = mSessionFactoryManager.getSessionFactory().openSession();

        try {
            Transaction tx = session.beginTransaction();
            exists(session, accountId);
            entry = addAddressBookEntry(session, accountId, entry);
            tx.commit();

            if (sLogger.isDebugEnabled()) {
                sLogger.debug("76568:createAddressBookEntry created: " + entry, new Throwable("trace caller"));
            }

            return new Serializable[] { accountId, entry };
        } finally {
            SessionManagerFactory.closeSession(session);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Account getAccountByAccountName(String loginname) throws NoSuchAccountException {

        Session session = mSessionFactoryManager.getSessionFactory().openSession();
        try {
            AccountCriterionImpl criterion = (AccountCriterionImpl) getAccountCriterion().named(loginname);

            Criteria criteria = criterion.getCriteria(session);
            Account account = (Account) criteria.uniqueResult();
            if (account == null) {
                throw new NoSuchAccountException(loginname);
            }
            return account;

        } finally {
            SessionManagerFactory.closeSession(session);
        }
    }

    @Override
    public AddressBookEntryCriterion getAddressBookContactCriterion(String accountName)
            throws NoSuchAccountException {
        Account.Id accountId = getAccountByAccountName(accountName).getId();
        return new AddressBookEntryCriterionImpl(accountId);
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<AddressBookEntry> getAddressBookContacts(AddressBookEntryCriterion criterion, Integer first,
            Integer count) throws NoSuchAccountException {
        Session session = mSessionFactoryManager.getSessionFactory().openSession();

        try {
            if (criterion == null) {
                throw new NoSuchAccountException("AddressBookEntryCriterion not valid");
            }

            Criteria criteria = ((AddressBookEntryCriterionImpl) criterion).getCriteria(session);

            if (first != null) {
                criteria.setFirstResult(first);
            }

            if (count != null) {
                criteria.setMaxResults(count);
            }

            return criteria.list();

        } finally {
            SessionManagerFactory.closeSession(session);
        }
    }

    @Override
    public AddressBookEntry getAddressBookEntryById(String accountId, String addressBookContactId)
            throws NoSuchAccountException, NoSuchAddressBookEntryException {
        Session session = mSessionFactoryManager.getSessionFactory().openSession();

        try {

            AddressBookEntryCriterionImpl criterion = (AddressBookEntryCriterionImpl) (new AddressBookEntryCriterionImpl(
                    newAccountId(accountId))).uniqueId(addressBookContactId);
            Criteria criteria = criterion.getCriteria(session);
            AddressBookEntry contact = (AddressBookEntry) criteria.uniqueResult();
            if (contact == null) {
                throw new NoSuchAddressBookEntryException(
                        (MessageFormat.format("Address book with Id - {0} does not exist", addressBookContactId)));
            }

            return contact;

        } finally {
            SessionManagerFactory.closeSession(session);
        }

    }

    @Override
    public void updateAddressBookEntry(AddressBookEntryBean entry)
            throws NoSuchAddressBookEntryException, DuplicateAddressBookEntryException {
        Session session = mSessionFactoryManager.getSessionFactory().openSession();

        try {
            Transaction tx = session.beginTransaction();
            updategetAddressBookEntry(session, entry);
            tx.commit();
        } finally {
            SessionManagerFactory.closeSession(session);
        }
    }

    private void updategetAddressBookEntry(Session session, AddressBookEntryBean entry)
            throws NoSuchAddressBookEntryException, DuplicateAddressBookEntryException {

        try {
            AddressBookEntryBean addressBookEntryBean = (AddressBookEntryBean) entry;
            AccountBean account = (AccountBean) getAccount(session, addressBookEntryBean.getAccountId());

            if (addressBookEntryBean.getId() == null) {
                throw new NoSuchAddressBookEntryException("AddressBookContact does not exist yet");
            }

            for (AddressBookEntryBean existingContact : account.getAddressBookEntries()) {
                if (((AddressBookEntryBean) entry).getId().equals(existingContact.getId())) {
                    account.removeAddressBookContact(existingContact);
                    session.delete(existingContact);
                    session.flush();
                    break;
                }
            }
            addAddressBookEntry(session, addressBookEntryBean.getAccountId(), addressBookEntryBean);

        } catch (ConstraintViolationException ex) {
            throw new DuplicateAddressBookEntryException("Duplicate address book contact: " + entry.getEmail(), ex);
        } catch (UnresolvableObjectException ex) {
            throw new NoSuchAddressBookEntryException("Id: " + entry.getId().toString());
        } catch (NoSuchAccountException e) {
            throw new NoSuchAddressBookEntryException("Assigned account does not exist", e);
        }

        if (sLogger.isDebugEnabled()) {
            sLogger.debug("76568: updateAddressBookContact updated: " + entry, new Throwable("trace caller"));
        }
    }

    private AddressBookEntry addAddressBookEntry(Session session, Account.Id accountId, AddressBookEntry entry)
            throws DuplicateAddressBookEntryException, NoSuchAccountException {

        // Create the association between the contact and account.
        AccountBean account = (AccountBean) getAccount(session, accountId);
        ((AddressBookEntryBean) entry).setAccountId(accountId);

        // If object does not have an id, persist a clone so if exception is thrown original object is unchanged.
        AddressBookEntry persistedContact = (entry.getId() == null) ? ((AddressBookEntryBean) entry).clone()
                : entry;
        account.addAddressBookContact((AddressBookEntryBean) persistedContact);

        try {
            session.save(persistedContact);
            session.flush();
        } catch (ConstraintViolationException ex) {
            throw new DuplicateAddressBookEntryException("Duplicate address book entry: " + entry.getEmail(), ex);
        }

        return persistedContact;
    }

    @Override
    public void deleteAddressBookEntry(String addressBookEntryId) throws NoSuchAddressBookEntryException {

        Session session = mSessionFactoryManager.getSessionFactory().openSession();

        try {
            Transaction tx = session.beginTransaction();
            AddressBookEntryBean addressBookEntry = (AddressBookEntryBean) session.get(AddressBookEntryBean.class,
                    addressBookEntryId);
            if (addressBookEntry == null) {
                throw new NoSuchAddressBookEntryException("Id: " + addressBookEntryId.toString());
            }

            AccountBean account = null;
            try {
                account = (AccountBean) getAccount(session, addressBookEntry.getAccountId());
            } catch (NoSuchAccountException e) {
                // ignore, no account associated to this address book contact.
            }
            if (account != null) {
                account.removeAddressBookContact(addressBookEntry);
            }

            session.delete(addressBookEntry);
            session.flush();
            tx.commit();

            if (sLogger.isDebugEnabled()) {
                sLogger.debug("76568: deleteAddressBookContact deleted: " + addressBookEntry,
                        new Throwable("trace caller"));
            }

        } finally {
            SessionManagerFactory.closeSession(session);
        }

    }

    @Override
    public List<Account> getAccountsByEmail(String email) {
        return getAccountsByEmails(Arrays.asList(email));
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Account> getAccountsByEmails(List<String> emails) {
        if (emails.isEmpty()) {
            return Collections.emptyList();
        }

        Session session = mSessionFactoryManager.getSessionFactory().openSession();

        try {
            final AccountCriterion accountCriterion = getAccountCriterion();
            for (final String email : emails) {
                if (email == null) {
                    throw new IllegalArgumentException("E-mail address cannot be null.");
                }
                accountCriterion.email(email);
            }
            return ((AccountCriterionImpl) accountCriterion).getCriteria(session).list();
        } finally {
            SessionManagerFactory.closeSession(session);
        }
    }

    private Account getAccount(Session session, Account.Id accountId) throws NoSuchAccountException {

        Account account = (Account) session.get(AccountBean.class, accountId.toString());
        if (account == null) {
            throw new NoSuchAccountException(accountId.toString());
        }
        return account;
    }

    /**
     * Subclass of the DuplicateAccountException implementing getDuplicate method.
     */
    private class DuplicateAccountExceptionImpl extends DuplicateAccountException {

        /** The serial version UID */
        private static final long serialVersionUID = 1L;

        private Account mAccount;

        private Account mDupAccount;

        private DuplicateAccountExceptionImpl(Account a, String message, Throwable cause) {
            super(message, cause);
            mAccount = a;
        }

        /**
         * Get an existing Account object which may have caused this duplicate exception to be thrown.
         *
         * @return the Account object already persisted or null if a duplicate was not found.
         */
        @Override
        public Account getDuplicate() {
            if (mDupAccount != null) {
                return mDupAccount;
            }
            Session session = mSessionFactoryManager.getSessionFactory().openSession();
            try {
                AccountCriterionImpl criterion = (AccountCriterionImpl) getAccountCriterion();
                if (mAccount.getId() != null) {
                    criterion.id(mAccount.getId(), false);
                }
                mDupAccount = (Account) criterion.getCriteria(session).setMaxResults(1).uniqueResult();
                session.flush();
                return mDupAccount;
            } catch (HibernateException ex) {
                return null;
            } finally {
                SessionManagerFactory.closeSession(session);
            }
        }

        /**
         * Get the new Account object which failed to be persisted because this exception was thrown.
         *
         * @return an Account object.
         */
        @Override
        public Account getObject() {
            return mAccount;
        }
    }

}