All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.efaps.admin.user.Person Maven / Gradle / Ivy

/*
 * Copyright 2003 - 2013 The eFaps Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Revision:        $Rev: 9042 $
 * Last Changed:    $Date: 2013-03-13 12:03:41 -0500 (Wed, 13 Mar 2013) $
 * Last Changed By: $Author: [email protected] $
 */

package org.efaps.admin.user;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.efaps.admin.EFapsSystemConfiguration;
import org.efaps.admin.common.SystemConfiguration;
import org.efaps.admin.datamodel.Type;
import org.efaps.admin.datamodel.attributevalue.PasswordStore;
import org.efaps.ci.CIAdminUser;
import org.efaps.db.Context;
import org.efaps.db.PrintQuery;
import org.efaps.db.Update;
import org.efaps.db.Update.Status;
import org.efaps.db.transaction.ConnectionResource;
import org.efaps.db.wrapper.SQLPart;
import org.efaps.db.wrapper.SQLSelect;
import org.efaps.jaas.AppAccessHandler;
import org.efaps.util.ChronologyType;
import org.efaps.util.DateTimeUtil;
import org.efaps.util.EFapsException;
import org.efaps.util.cache.CacheLogListener;
import org.efaps.util.cache.InfinispanCache;
import org.infinispan.Cache;
import org.joda.time.Chronology;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Class represents the instance of a person/user in eFaps.
 *
 * @author The eFasp Team
 * @version $Id: Person.java 9042 2013-03-13 17:03:41Z [email protected] $
 */
public final class Person
    extends AbstractUserObject
{
    /**
     * Needed for serialization.
     */
    private static final long serialVersionUID = 1L;

    /**
     * Enum for all known and updated attributes from a person. Only this could
     * be defined which are in the SQL table T_USERPERSON.
     */
    public enum AttrName {
        /** Attribute Name for the First Name of the person. */
        FIRSTNAME("FIRSTNAME"),
        /** Attribute Name for the Last Name of the person. */
        LASTNAME("LASTNAME"),
        /** Attribute Name for the Chronology of the person. */
        CHRONOLOGY("CHRONOLOGY"),
        /** Attribute Name for the Timezone of the person. */
        TIMZONE("TIMZONE"),
        /** Attribute Name for the Locale of the person. */
        LOCALE("LOCALE"),
         /** Attribute Name for the language of the person. */
         LANGUAGE("LANG", true);

        /**
         * The name of the depending SQL column for an attribute in the table.
         */
        private final String sqlColumn;

        /**
         * The name of the depending SQL column for an attribute in the table.
         */
        private final boolean integer;

        /**
         * Constructor setting the instance variables.
         *
         * @param _sqlColumn name of the column in the table
         */
        private AttrName(final String _sqlColumn)
        {
            this(_sqlColumn, false);
        }

        /**
         * Constructor setting the instance variables.
         *
         * @param _sqlColumn name of the column in the table
         * @param _integer is the column a integer column
         */
        private AttrName(final String _sqlColumn,
                         final boolean _integer)
        {
            this.sqlColumn = _sqlColumn;
            this.integer = _integer;
        }
    }

    /**
     * This is the SQL select statement to select a Person from the database by ID.
     */
    private static final String SQL_ID = new SQLSelect()
                    .column("ID")
                    .column("NAME")
                    .column("STATUS")
                    .from("V_USERPERSON", 0)
                    .addPart(SQLPart.WHERE).addColumnPart(0, "ID").addPart(SQLPart.EQUAL).addValuePart("?").toString();

    /**
     * This is the SQL select statement to select a Person from the database by Name.
     */
    private static final String SQL_NAME = new SQLSelect()
                    .column("ID")
                    .column("NAME")
                    .column("STATUS")
                    .from("V_USERPERSON", 0)
                    .addPart(SQLPart.WHERE).addColumnPart(0, "NAME").addPart(SQLPart.EQUAL).addValuePart("?")
                    .toString();

    /**
     * Name of the Cache by ID.
     */
    private static String IDCACHE = "Person4ID";

    /**
     * Name of the Cache by Name.
     */
    private static String NAMECACHE = "Person4Name";

    /**
     * Logging instance used to give logging information of this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(Person.class);

    /**
     * HashSet instance variable to hold all id of roles for this person.
     *
     * @see #getRoles
     * @see #add(Role)
     */
    private final Set roles = new HashSet();

    /**
     * HashSet instance variable to hold all id of groups for this person.
     *
     * @see #getGroups
     * @see #add(Group)
     */
    private final Set groups = new HashSet();

    /**
     * HashSet instance variable to hold all id of groups for this person.
     *
     * @see #getCompanies
     * @see #add(Company)
     */
    private final Set companies = new HashSet();

    /**
     * The map is used to store all attribute values depending on attribute
     * names defined in {@link #AttrName}.
     *
     * @see #setAttrValue
     * @see #updateAttrValue
     * @see #AttrName
     */
    private final Map attrValues = new HashMap();

    /**
     * The map is used to store information about updates on attribute values.
     * This information is needed if the database must be updated.
     *
     * @see #updateAttrValue
     * @see #commitAttrValuesInDB
     * @see #AttrName
     */
    private final Map attrUpdated = new HashMap();

    /**
     * The constructor creates a new instance of class {@link Person} and sets
     * the {@link #key} and {@link #id}.
     *
     * @param _id id of the person to set
     * @param _name name of the person to set
     * @param _status status of the person to set
     */
    private Person(final long _id,
                   final String _name,
                   final boolean _status)
    {
        super(_id, null, _name, _status);
    }

    /**
     * Checks, if the given person is assigned to this user object. Here it is
     * only tested if the person is the same as the user of the parameter.
     *
     * @param _person person to test
     * @return true if the person is the same person as this person,
     *         otherwise false
     */
    @Override
    public boolean hasChildPerson(final Person _person)
    {
        return _person.getId() == getId();
    }

    /**
     * Add a role to this person.
     *
     * @param _role role to add to this person
     * @see #roles
     */
    private void add(final Role _role)
    {
        this.roles.add(_role.getId());
    }

    /**
     * Tests, if the given role is assigned to this person.
     *
     * @param _role role to test
     * @return true if role is assigned to this person, otherwise
     *         false
     */
    public boolean isAssigned(final Role _role)
    {
        return this.roles.contains(_role.getId());
    }

    /**
     * Add a role to this person.
     *
     * @param _group group to add to this person
     * @see #groups
     */
    private void add(final Group _group)
    {
        this.groups.add(_group.getId());
    }

    /**
     * Tests, if the given group is assigned to this person.
     *
     * @param _group group to test
     * @return true if group is assigned to this person, otherwise
     *         false
     */
    public boolean isAssigned(final Group _group)
    {
        return this.groups.contains(_group.getId());
    }

    /**
     * Add a role to this person.
     *
     * @param _group group to add to this person
     * @see #groups
     */
    private void add(final Company _group)
    {
        this.companies.add(_group.getId());
    }

    /**
     * Tests, if the given group is assigned to this person.
     *
     * @param _company Company to test
     * @return true if group is assigned to this person, otherwise
     *         false
     */
    public boolean isAssigned(final Company _company)
    {
        return this.companies.contains(_company.getId());
    }

    /**
     * All assigned roles in {@link #roles} and groups in {@link #groups} are
     * removed in the cache from this person instance. This is needed if the
     * person assignments are rebuild (e.g. from a login servlet).
     */
    public void cleanUp()
    {
        this.roles.clear();
        this.groups.clear();
        this.companies.clear();
    }

    /**
     * The method sets the attribute values in the cache for given attribute
     * name to given new attribute value.
     *
     * @param _attrName name of attribute to set
     * @param _value new value to set
     * @see #attrValues
     */
    private void setAttrValue(final AttrName _attrName,
                              final String _value)
    {
        synchronized (this.attrValues) {
            this.attrValues.put(_attrName, _value);
        }
    }

    /**
     * Returns for given attribute name the value in the cache.
     *
     * @param _attrName name of attribute for which the value must returned
     * @return attribute value of given attribute name
     */
    public String getAttrValue(final AttrName _attrName)
    {
        return this.attrValues.get(_attrName);
    }

    /**
     * @return attribute value of first name
     */
    public String getFirstName()
    {
        return this.attrValues.get(Person.AttrName.FIRSTNAME);
    }

    /**
     * @return attribute value of last name
     */
    public String getLastName()
    {
        return this.attrValues.get(Person.AttrName.LASTNAME);
    }

    /**
     * Method to get the Locale of this Person. Default is the "English" Locale.
     *
     * @return Locale of this Person
     */
    public Locale getLocale()
    {
        final Locale ret;
        if (this.attrValues.get(Person.AttrName.LOCALE) != null) {
            final String localeStr = this.attrValues.get(Person.AttrName.LOCALE);
            final String[] countries = localeStr.split("_");
            if (countries.length == 2) {
                ret = new Locale(countries[0], countries[1]);
            } else if (countries.length == 3) {
                ret = new Locale(countries[0], countries[1], countries[2]);
            } else {
                ret = new Locale(localeStr);
            }
        } else {
            ret = Locale.ENGLISH;
        }
        return ret;
    }

    /**
     * Method to get the Language of the UserInterface for this Person. Default
     * is english.
     *
     * @return iso code of a language
     */
    public String getLanguage()
    {
        return this.attrValues.get(Person.AttrName.LANGUAGE) != null
                        ? this.attrValues.get(Person.AttrName.LANGUAGE)
                        : Locale.ENGLISH.getISO3Language();
    }

    /**
     * Method to get the Timezone of this Person. Default is the "UTC" Timezone.
     *
     * @return Timezone of this Person
     */
    public DateTimeZone getTimeZone()
    {
        return this.attrValues.get(Person.AttrName.TIMZONE) != null
                        ? DateTimeZone.forID(this.attrValues.get(Person.AttrName.TIMZONE))
                        : DateTimeZone.UTC;
    }

    /**
     * Method to get the Chronology of this Person. Default is the "ISO8601"
     * Chronology.
     *
     * @return Chronology of this Person
     */
    public Chronology getChronology()
    {
        return getChronologyType().getInstance(getTimeZone());
    }

    /**
     * Method to get the ChronologyType of this Person. Default is the "ISO8601"
     * ChronologyType.
     *
     * @return ChronologyType of this Person
     */
    public ChronologyType getChronologyType()
    {
        final String chronoKey = this.attrValues.get(Person.AttrName.CHRONOLOGY);
        final ChronologyType chronoType;
        if (chronoKey != null) {
            chronoType = ChronologyType.getByKey(chronoKey);
        } else {
            chronoType = ChronologyType.ISO8601;
        }
        return chronoType;
    }

    /**
     * Updates a value for an attribute in the cache and marks then as modified.
     * Only after calling method {@link #commitAttrValuesInDB} the updated
     * attribute value is stored in the database!
     *
     * @param _attrName name of attribute to update
     * @param _value new value to set directly
     */
    public void updateAttrValue(final AttrName _attrName,
                                final String _value)
    {
        this.updateAttrValue(_attrName, _value, _value);
    }

    /**
     * Updates a value for an attribute in the cache and marks then as modified.
     * Only after calling method {@link #commitAttrValuesInDB} the updated
     * attribute value is stored in the database!
     *
     * @param _attrName name of attribute to update
     * @param _value new value to set directly
     * @param _updateValue new value to be set in the database
     * @see #attrUpdated
     * @see #attrValues
     */
    public void updateAttrValue(final AttrName _attrName,
                                final String _value,
                                final String _updateValue)
    {
        synchronized (this.attrUpdated) {
            synchronized (this.attrValues) {
                this.attrValues.put(_attrName, _value);
            }
            this.attrUpdated.put(_attrName, _updateValue);
        }
    }

    /**
     * Commits update attribute defined in {@link #attrUpdated} with method
     * {@link #updateAttrValue} to the database. After database update,
     * {@link #attrUpdated} is cleared.
     *
     * @throws EFapsException on error
     * @see #attrUpdated
     * @see #attrValues
     * @see #updateAttrValue
     *
     */
    public void commitAttrValuesInDB()
        throws EFapsException
    {
        synchronized (this.attrUpdated) {
            if (this.attrUpdated.size() > 0) {
                ConnectionResource rsrc = null;
                try {
                    final Context context = Context.getThreadContext();
                    rsrc = context.getConnectionResource();

                    final StringBuilder cmd = new StringBuilder();
                    PreparedStatement stmt = null;
                    try {
                        cmd.append("update T_USERPERSON set ");
                        boolean first = true;
                        for (final AttrName attrName : this.attrUpdated.keySet()) {
                            if (first) {
                                first = false;
                            } else {
                                cmd.append(",");
                            }
                            cmd.append(attrName.sqlColumn).append("=?");
                        }
                        cmd.append(" where ID=").append(getId());
                        stmt = rsrc.getConnection().prepareStatement(cmd.toString());

                        int col = 1;
                        for (final AttrName attrName : this.attrUpdated.keySet()) {
                            final String tmp = this.attrUpdated.get(attrName);
                            if (attrName.integer) {
                                stmt.setInt(col, tmp == null ? 0 : Integer.parseInt(tmp.trim()));
                            } else {
                                stmt.setString(col, tmp == null ? null : tmp.trim());
                            }
                            col++;
                        }

                        final int rows = stmt.executeUpdate();
                        if (rows == 0) {
                            Person.LOG.error("could not update '" + cmd.toString() + "' person with user name '"
                                            + getName() + "' (id = " + getId() + ")");
                            throw new EFapsException(Person.class, "commitAttrValuesInDB.NotUpdated", cmd.toString(),
                                            getName(), getId());
                        }
                        // TODO: update modified date
                    } catch (final SQLException e) {
                        Person.LOG.error("could not update '" + cmd.toString() + "' person with user name '" + getName()
                                        + "' (id = " + getId() + ")", e);
                        throw new EFapsException(Person.class, "commitAttrValuesInDB.SQLException", e, cmd.toString(),
                                        getName(), getId());
                    } finally {
                        try {
                            if (stmt != null) {
                                stmt.close();
                            }
                        } catch (final SQLException e) {
                            throw new EFapsException(Person.class, "commitAttrValuesInDB.SQLException", e, cmd
                                            .toString(), getName(), getId());
                        }
                    }
                    rsrc.commit();
                } finally {
                    if ((rsrc != null) && rsrc.isOpened()) {
                        rsrc.abort();
                    }
                }
                this.attrUpdated.clear();
            }
        }
    }

    /**
     * The instance method checks if the given password is the same password as
     * the password in the database.
     *
     * @param _passwd password to check for this person
     * @return true if password is correct, otherwise false
     * @throws EFapsException if query for the password check failed
     */
    public boolean checkPassword(final String _passwd)
        throws EFapsException
    {
        boolean ret = false;
        final PrintQuery query = new PrintQuery(CIAdminUser.Person.getType(), getId());
        query.addAttribute(CIAdminUser.Person.Password,
                           CIAdminUser.Person.LastLogin,
                           CIAdminUser.Person.LoginTry,
                           CIAdminUser.Person.LoginTriesCounter,
                           CIAdminUser.Person.Status);
        if (query.executeWithoutAccessCheck()) {
            final PasswordStore pwd = query.getAttribute(CIAdminUser.Person.Password);
            if (pwd.checkCurrent(_passwd)) {
                ret = query.getAttribute(CIAdminUser.Person.Status);
            } else {
                setFalseLogin(query.getAttribute(CIAdminUser.Person.LoginTry),
                                query.getAttribute(CIAdminUser.Person.LoginTriesCounter));
            }
        }
        return ret;
    }

    /**
     * Method that sets the time and the number of failed logins.
     *
     * @param _logintry time of the false Login
     * @param _count number of tries
     * @throws EFapsException on error
     */
    private void setFalseLogin(final DateTime _logintry,
                               final int _count)
        throws EFapsException
    {
        if (_count > 0) {
            final Timestamp now = DateTimeUtil.getCurrentTimeFromDB();
            final SystemConfiguration kernelConfig = EFapsSystemConfiguration.KERNEL.get();

            // Admin_User_LoginTimeBeforeRetry
            final int dif = kernelConfig.getAttributeValueAsInteger("LoginTimeBeforeRetry");

            // Admin_User_LoginTries
            final int maxtries = kernelConfig.getAttributeValueAsInteger("LoginTries");

            final int count = _count + 1;
            if (dif > 0 && (now.getTime() - _logintry.getMillis()) > dif * 60 * 1000) {
                updateFalseLoginDB(1);
            } else {
                updateFalseLoginDB(count);
            }
            if (maxtries > 0 && count > maxtries && getStatus()) {
                setStatusInDB(false);
            }
        } else {
            updateFalseLoginDB(1);
        }
    }

    /**
     * Method to set the number of false Login tries in the eFaps-DataBase.
     *
     * @param _tries number or tries
     * @throws EFapsException on error
     */
    private void updateFalseLoginDB(final int _tries)
        throws EFapsException
    {
        ConnectionResource rsrc = null;
        try {
            final Context context = Context.getThreadContext();
            rsrc = context.getConnectionResource();

            Statement stmt = null;
            final StringBuilder cmd = new StringBuilder();
            try {

                cmd.append("update T_USERPERSON ").append("set LOGINTRY=").append(
                                Context.getDbType().getCurrentTimeStamp()).append(", LOGINTRIES=").append(_tries)
                                .append(" where ID=").append(getId());
                stmt = rsrc.getConnection().createStatement();
                final int rows = stmt.executeUpdate(cmd.toString());
                if (rows == 0) {
                    Person.LOG.error("could not execute '" + cmd.toString()
                                    + "' to update last login information for person '" + toString() + "'");
                    throw new EFapsException(getClass(), "updateLastLogin.NotUpdated", cmd.toString(), getName());
                }
            } catch (final SQLException e) {
                Person.LOG.error("could not execute '" + cmd.toString()
                                + "' to update last login information for person '" + toString() + "'", e);
                throw new EFapsException(getClass(), "updateLastLogin.SQLException", e, cmd.toString(), getName());
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                } catch (final SQLException e) {
                    throw new EFapsException(getClass(), "updateLastLogin.SQLException", e, cmd.toString(), getName());
                }
            }
            rsrc.commit();
        } finally {
            if ((rsrc != null) && rsrc.isOpened()) {
                rsrc.abort();
            }
        }
    }

    /**
     * The instance method sets the new password for the current context user.
     * Before the new password is set, some checks are made.
     *
     * @param _newPasswd new Password to set
     * @throws EFapsException on error
     * @return true if password set, else false
     */
    public Status setPassword(final String _newPasswd)
        throws EFapsException
    {
        final Type type = CIAdminUser.Person.getType();
        if (_newPasswd.length() == 0) {
            throw new EFapsException(getClass(), "PassWordLength", 1, _newPasswd.length());
        }
        final Update update = new Update(type, "" + getId());
        final Status status = update.add(CIAdminUser.Person.Password, _newPasswd);
        if (status.isOk()) {
            update.execute();
            update.close();
        } else {
            Person.LOG.error("Password could not be set by the Update, due to restrictions " + "e.g. length???");
            throw new EFapsException(getClass(), "TODO");
        }
        return status;
    }

    /**
     * The instance method reads all information from the database.
     *
     * @throws EFapsException on error
     * @see #readFromDBAttributes()
     */
    protected void readFromDB()
        throws EFapsException
    {
        readFromDBAttributes();
        this.roles.clear();
        for (final Role role : getRolesFromDB()) {
            add(role);
        }
        this.groups.clear();
        for (final Group group : getGroupsFromDB(null)) {
            add(group);
        }
        this.companies.clear();
        for (final Company company : getCompaniesFromDB(null)) {
            add(company);
        }
    }

    /**
     * All attributes from this person are read from the database.
     *
     * @throws EFapsException if the attributes for this person could not be
     *             read
     */
    private void readFromDBAttributes()
        throws EFapsException
    {
        ConnectionResource rsrc = null;
        try {
            rsrc = Context.getThreadContext().getConnectionResource();
            Statement stmt = null;
            try {
                stmt = rsrc.getConnection().createStatement();

                final StringBuilder cmd = new StringBuilder("select ");
                for (final AttrName attrName : Person.AttrName.values()) {
                    cmd.append(attrName.sqlColumn).append(",");
                }
                cmd.append("0 as DUMMY ").append("from V_USERPERSON ").append("where V_USERPERSON.ID=").append(getId());

                final ResultSet resultset = stmt.executeQuery(cmd.toString());
                if (resultset.next()) {
                    for (final AttrName attrName : Person.AttrName.values()) {
                        final String tmp = resultset.getString(attrName.sqlColumn);
                        setAttrValue(attrName, tmp == null ? null : tmp.trim());
                    }
                }
                resultset.close();
            } catch (final SQLException e) {
                Person.LOG.error("read attributes for person with SQL statement is not " + "possible", e);
                throw new EFapsException(Person.class, "readFromDBAttributes.SQLException", e, getName(), getId());
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                } catch (final SQLException e) {
                    Person.LOG.error("close of SQL statement is not possible", e);
                }
            }
            rsrc.commit();
        } finally {
            if ((rsrc != null) && rsrc.isOpened()) {
                rsrc.abort();
            }
        }
    }

    /**
     * The method reads directly from the database all stored companies for this
     * person. The found roles are returned as instance of {@link Set}.
     *
     * @param _jaasSystem JAAS system for which the roles must get from eFaps
     *            (if value is null, all companies independent from
     *            the related JAAS system are returned)
     * @return set of all found companies for given JAAS system
     * @throws EFapsException on error
     */
    public Set getCompaniesFromDB(final JAASSystem _jaasSystem)
        throws EFapsException
    {
        final Set ret = new HashSet();
        ConnectionResource rsrc = null;
        try {
            final List companyIds = new ArrayList();
            rsrc = Context.getThreadContext().getConnectionResource();

            Statement stmt = null;

            try {
                final StringBuilder cmd = new StringBuilder();
                cmd.append("select ").append("USERABSTRACTTO ").append("from V_USERPERSON2COMPANY ")
                                .append("where USERABSTRACTFROM=").append(getId());

                if (_jaasSystem != null) {
                    cmd.append(" and JAASSYSID=").append(_jaasSystem.getId());
                }

                stmt = rsrc.getConnection().createStatement();
                final ResultSet resultset = stmt.executeQuery(cmd.toString());
                while (resultset.next()) {
                    companyIds.add(resultset.getLong(1));
                }
                resultset.close();

            } catch (final SQLException e) {
                throw new EFapsException(getClass(), "getCompaniesFromDB.SQLException", e, getName());
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                } catch (final SQLException e) {
                    throw new EFapsException(getClass(), "getCompaniesFromDB.SQLException", e, getName());
                }
            }
            rsrc.commit();
            for (final Long companyId : companyIds) {
                final Company company = Company.get(companyId);
                ret.add(company);
            }
        } finally {
            if ((rsrc != null) && rsrc.isOpened()) {
                rsrc.abort();
            }
        }
        return ret;
    }

    /**
     * The depending roles for the user are set for the given JAAS system. All
     * roles are added to the loaded roles in the cache of this person.
     *
     * @param _jaasSystem JAAS system for which the roles are set
     * @param _companies set of company to set for the JAAS system
     * @throws EFapsException from calling methods
     */
    public void setCompanies(final JAASSystem _jaasSystem,
                             final Set _companies)
        throws EFapsException
    {

        if (_jaasSystem == null) {
            throw new EFapsException(getClass(), "setRoles.nojaasSystem", getName());
        }
        if (_companies == null) {
            throw new EFapsException(getClass(), "setRoles.noRoles", getName());
        }
        for (final Company role : _companies) {
            add(role);
        }
    }

    /**
     * The method reads directly from the database all stores roles for the this
     * person. The found roles are returned as instance of {@link java.util.Set}
     * .
     *
     * @return set of all found roles for all JAAS systems
     * @see #getRolesFromDB(JAASSystem);
     * @throws EFapsException on error
     */
    public Set getRolesFromDB()
        throws EFapsException
    {
        return getRolesFromDB((JAASSystem) null);
    }

    /**
     * The method reads directly from the database all stores roles for the this
     * person. The found roles are returned as instance of {@link java.util.Set}
     * .
     *
     * @param _jaasSystem JAAS system for which the roles are searched in eFaps
     *            (if value is null, all roles independent from the
     *            related JAAS system are returned)
     * @return set of all found roles for given JAAS system
     * @throws EFapsException on error
     */
    public Set getRolesFromDB(final JAASSystem _jaasSystem)
        throws EFapsException
    {

        final Set ret = new HashSet();
        ConnectionResource rsrc = null;
        try {
            final List roleIds = new ArrayList();
            rsrc = Context.getThreadContext().getConnectionResource();
            Statement stmt = null;
            try {
                final StringBuilder cmd = new StringBuilder();
                cmd.append("select ").append("USERABSTRACTTO ").append("from V_USERPERSON2ROLE ").append(
                                "where USERABSTRACTFROM=").append(getId());

                if (_jaasSystem != null) {
                    cmd.append(" and JAASSYSID=").append(_jaasSystem.getId());
                }

                stmt = rsrc.getConnection().createStatement();
                final ResultSet resultset = stmt.executeQuery(cmd.toString());
                while (resultset.next()) {
                    roleIds.add(resultset.getLong(1));
                }
                resultset.close();

            } catch (final SQLException e) {
                throw new EFapsException(getClass(), "getRolesFromDB.SQLException", e, getName());
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                } catch (final SQLException e) {
                    throw new EFapsException(getClass(), "getRolesFromDB.SQLException", e, getName());
                }
            }
            rsrc.commit();

            final Set roleNames = AppAccessHandler.getLoginRoles();
            for (final Long roleId : roleIds) {
                final Role role = Role.get(roleId);
                if (!AppAccessHandler.excludeMode()
                                || (AppAccessHandler.excludeMode() && roleNames.contains(role.getName()))) {
                    ret.add(role);
                }
            }
        } finally {
            if ((rsrc != null) && rsrc.isOpened()) {
                rsrc.abort();
            }
        }
        return ret;
    }

    /**
     * The depending roles for the user are set for the given JAAS system. All
     * roles are added to the loaded roles in the cache of this person.
     *
     * @param _jaasSystem JAAS system for which the roles are set
     * @param _roles set of roles to set for the JAAS system
     * @see #assignRoleInDb
     * @see #unassignRoleInDb
     * @throws EFapsException from calling methods
     */
    public void setRoles(final JAASSystem _jaasSystem,
                         final Set _roles)
        throws EFapsException
    {

        if (_jaasSystem == null) {
            throw new EFapsException(getClass(), "setRoles.nojaasSystem", getName());
        }
        if (_roles == null) {
            throw new EFapsException(getClass(), "setRoles.noRoles", getName());
        }

        for (final Role role : _roles) {
            add(role);
        }

        // current roles
        final Set rolesInDb = getRolesFromDB(_jaasSystem);

        // compare new roles with current roles (add missing roles)
        for (final Role role : _roles) {
            if (!rolesInDb.contains(role)) {
                assignRoleInDb(_jaasSystem, role);
            }
        }

        // compare current roles with new roles (remove roles which are to much)
        for (final Role role : rolesInDb) {
            if (!_roles.contains(role)) {
                unassignRoleInDb(_jaasSystem, role);
            }
        }
    }

    /**
     * For this person, a role is assigned for the given JAAS system.
     *
     * @param _jaasSystem JAAS system for which the role is assigned
     * @param _role role to assign
     * @see AbstractUserObject#assignToUserObjectInDb(Type, JAASSystem,
     *      AbstractUserObject)
     * @throws EFapsException on error
     */
    public void assignRoleInDb(final JAASSystem _jaasSystem,
                               final Role _role)
        throws EFapsException
    {
        assignToUserObjectInDb(CIAdminUser.Person2Role.getType(), _jaasSystem, _role);
    }

    /**
     * The given role is unassigned for the given JAAS system from this person.
     *
     * @param _jaasSystem JAAS system for which the role is assigned
     * @param _role role to unassign
     * @see AbstractUserObject#unassignFromUserObjectInDb(Type, JAASSystem,
     *      AbstractUserObject)
     * @throws EFapsException on error
     */
    public void unassignRoleInDb(final JAASSystem _jaasSystem,
                                 final Role _role)
        throws EFapsException
    {
        unassignFromUserObjectInDb(CIAdminUser.Person2Role.getType(), _jaasSystem, _role);
    }

    /**
     * The method reads directly from eFaps all stored groups for the this
     * person. The found groups are returned as instance of {@link Set}.
     *
     * @param _jaasSystem JAAS system for which the groups must fetched from
     *            eFaps (if value is null, all groups independent
     *            from the related JAAS system are returned)
     * @throws EFapsException on error
     * @return set of all found groups for given JAAS system
     */
    public Set getGroupsFromDB(final JAASSystem _jaasSystem)
        throws EFapsException
    {
        final Set ret = new HashSet();
        ConnectionResource rsrc = null;
        try {
            final List groupIds = new ArrayList();
            rsrc = Context.getThreadContext().getConnectionResource();

            Statement stmt = null;

            try {
                final StringBuilder cmd = new StringBuilder();
                cmd.append("select ").append("USERABSTRACTTO ").append("from V_USERPERSON2GROUP ").append(
                                "where USERABSTRACTFROM=").append(getId());

                if (_jaasSystem != null) {
                    cmd.append(" and JAASSYSID=").append(_jaasSystem.getId());
                }

                stmt = rsrc.getConnection().createStatement();
                final ResultSet resultset = stmt.executeQuery(cmd.toString());
                while (resultset.next()) {
                    groupIds.add(resultset.getLong(1));
                }
                resultset.close();
            } catch (final SQLException e) {
                throw new EFapsException(getClass(), "getGroupsFromDB.SQLException", e, getName());
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                } catch (final SQLException e) {
                    throw new EFapsException(getClass(), "getGroupsFromDB.SQLException", e, getName());
                }
            }
            rsrc.commit();
            for (final Long groupId : groupIds) {
                ret.add(Group.get(groupId));
            }
        } finally {
            if ((rsrc != null) && rsrc.isOpened()) {
                rsrc.abort();
            }
        }
        return ret;
    }

    /**
     * The depending groups for the user are set for the given JAAS system. All
     * groups are added to the loaded groups in the cache of this person.
     *
     * @param _jaasSystem JAAS system for which the roles are set
     * @param _groups set of groups to set for the JAAS system
     * @see #assignGroupInDb(JAASSystem, Group)
     * @see #unassignGroupInDb(JAASSystem, Group)
     * @throws EFapsException from calling methods
     */
    public void setGroups(final JAASSystem _jaasSystem,
                          final Set _groups)
        throws EFapsException
    {
        if (_jaasSystem == null) {
            throw new EFapsException(getClass(), "setGroups.nojaasSystem", getName());
        }
        if (_groups == null) {
            throw new EFapsException(getClass(), "setGroups.noGroups", getName());
        }

        for (final Group group : _groups) {
            add(group);
        }

        // current groups
        final Set groupsInDb = getGroupsFromDB(_jaasSystem);

        // compare new roles with current groups (add missing groups)
        for (final Group group : _groups) {
            if (!groupsInDb.contains(group)) {
                assignGroupInDb(_jaasSystem, group);
            }
        }

        // compare current roles with new groups (remove groups which are to
        // much)
        for (final Group group : groupsInDb) {
            if (!_groups.contains(group)) {
                unassignGroupInDb(_jaasSystem, group);
            }
        }
    }

    /**
     * For this person, a group is assigned for the given JAAS system.
     *
     * @param _jaasSystem JAAS system for which the group is assigned
     * @param _group group to assign
     * @throws EFapsException on error
     * @see AbstractUserObject#assignToUserObjectInDb
     */
    public void assignGroupInDb(final JAASSystem _jaasSystem,
                                final Group _group)
        throws EFapsException
    {
        assignToUserObjectInDb(CIAdminUser.Person2Group.getType(), _jaasSystem, _group);
    }

    /**
     * The given group is unassigned for the given JAAS system from this person.
     *
     * @param _jaasSystem JAAS system for which the role is assigned
     * @param _group group to unassign
     * @throws EFapsException on error
     * @see AbstractUserObject#unassignFromUserObjectInDb
     */
    public void unassignGroupInDb(final JAASSystem _jaasSystem,
                                  final Group _group)
        throws EFapsException
    {
        unassignFromUserObjectInDb(CIAdminUser.Person2Group.getType(), _jaasSystem, _group);
    }

    /**
     * Update the last login date of this person to current time stamp.
     *
     * @throws EFapsException if the last login information could not be updated
     */
    public void updateLastLogin()
        throws EFapsException
    {
        ConnectionResource rsrc = null;
        try {
            final Context context = Context.getThreadContext();
            rsrc = context.getConnectionResource();

            Statement stmt = null;
            final StringBuilder cmd = new StringBuilder();
            try {

                cmd.append("update T_USERPERSON ").append("set LASTLOGIN=").append(
                                Context.getDbType().getCurrentTimeStamp()).append(", LOGINTRIES=0 ")
                                .append("where ID=").append(getId());
                stmt = rsrc.getConnection().createStatement();
                final int rows = stmt.executeUpdate(cmd.toString());
                if (rows == 0) {
                    Person.LOG.error("could not execute '" + cmd.toString()
                                    + "' to update last login information for person '" + toString() + "'");
                    throw new EFapsException(getClass(), "updateLastLogin.NotUpdated", cmd.toString(), getName());
                }
            } catch (final SQLException e) {
                Person.LOG.error("could not execute '" + cmd.toString()
                                + "' to update last login information for person '" + toString() + "'", e);
                throw new EFapsException(getClass(), "updateLastLogin.SQLException", e, cmd.toString(), getName());
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                } catch (final SQLException e) {
                    throw new EFapsException(getClass(), "updateLastLogin.SQLException", e, cmd.toString(), getName());
                }
            }
            rsrc.commit();
        } finally {
            if ((rsrc != null) && rsrc.isOpened()) {
                rsrc.abort();
            }
        }
    }

    /**
     * This is the getter method for instance variable {@link #roles}.
     *
     * @return the value of the instance variable {@link #roles}.
     * @see #roles
     */
    public Set getRoles()
    {
        return this.roles;
    }

    /**
     * This is the getter method for instance variable {@link #groups}.
     *
     * @return the value of the instance variable {@link #groups}.
     * @see #groups
     */
    public Set getGroups()
    {
        return this.groups;
    }

    /**
     * Getter method for instance variable {@link #companies}.
     *
     * @return value of instance variable {@link #companies}
     */
    public Set getCompanies()
    {
        return this.companies;
    }

    /**
     * Returns a string representation of this person.
     *
     * @return string representation of this person
     */
    @Override
    public String toString()
    {
        return new ToStringBuilder(this)
                        .appendSuper(super.toString())
                        .append("attrValues", this.attrValues)
                        .append("roles", this.roles)
                        .append("groups", this.groups)
                        .append("companies", this.companies)
                        .toString();
    }

    /**
     * Method to initialize the Cache of this CacheObjectInterface.
     */
    public static void initialize()
    {
        if (InfinispanCache.get().exists(Person.IDCACHE)) {
            InfinispanCache.get().getCache(Person.IDCACHE).clear();
        } else {
            InfinispanCache.get().getCache(Person.IDCACHE).addListener(new CacheLogListener(Person.LOG));
        }
        if (InfinispanCache.get().exists(Person.NAMECACHE)) {
            InfinispanCache.get().getCache(Person.NAMECACHE).clear();
        } else {
            InfinispanCache.get().getCache(Person.NAMECACHE)
                            .addListener(new CacheLogListener(Person.LOG));
        }
    }

    /**
     * Returns for given parameter _id the instance of class
     * {@link Person}.
     *
     * @param _id id to search in the cache
     * @throws EFapsException on error
     * @return instance of class {@link Person}
     * @see #CACHE
     * @see #getFromDB
     */
    public static Person get(final long _id)
        throws EFapsException
    {
        final Cache cache = InfinispanCache.get().getCache(Person.IDCACHE);
        if (!cache.containsKey(_id)) {
            Person.getPersonFromDB(Person.SQL_ID, _id);
        }
        return cache.get(_id);
    }

    /**
     * Returns for given parameter _name the instance of class
     * {@link Person}.
     *
     * @param _name name to search in the cache
     * @throws EFapsException on error
     * @return instance of class {@link Person}
     * @see #CACHE
     * @see #getFromDB
     */
    public static Person get(final String _name)
        throws EFapsException
    {
        final Cache cache = InfinispanCache.get().getCache(Person.NAMECACHE);
        if (!cache.containsKey(_name)) {
            Person.getPersonFromDB(Person.SQL_NAME, _name);
        }
        return cache.get(_name);
    }

    /**
     * @param _person Person to be cached
     */
    private static void cachePerson(final Person _person)
    {
        final Cache nameCache = InfinispanCache.get().getCache(Person.NAMECACHE);
        if (!nameCache.containsKey(_person.getName())) {
            nameCache.put(_person.getName(), _person);
        }
        final Cache idCache = InfinispanCache.get().getCache(Person.IDCACHE);
        if (!idCache.containsKey(_person.getId())) {
            idCache.put(_person.getId(), _person);
        }
    }


    /**
     * @param _sql      SQL Statment to be execuetd
     * @param _criteria filter criteria
     * @return true if successful
     * @throws EFapsException on error
     */
    private static Person getPersonFromDB(final String _sql,
                                          final Object _criteria)
        throws EFapsException
    {
        Person ret = null;
        ConnectionResource con = null;
        try {
            con = Context.getThreadContext().getConnectionResource();
            PreparedStatement stmt = null;
            try {
                stmt = con.getConnection().prepareStatement(_sql);
                stmt.setObject(1, _criteria);
                final ResultSet rs = stmt.executeQuery();

                if (rs.next()) {
                    final long id = rs.getLong(1);
                    final String name = rs.getString(2);
                    final boolean status = rs.getBoolean(3);
                    ret = new Person(id, name.trim(), status);
                    Person.cachePerson(ret);
                }
                rs.close();
            } catch (final SQLException e) {
                Person.LOG.error("search for person with SQL statement '" + _sql + "' is not possible", e);
                throw new EFapsException(Person.class, "getFromDB.SQLException", e, _sql);
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                } catch (final SQLException e) {
                    Person.LOG.error("Catched error on closing statement", e);
                }
                if (con != null) {
                    con.commit();
                }
            }
        } finally {
            if ((con != null) && con.isOpened()) {
                con.abort();
            }
        }
        if (ret != null) {
            ret.readFromDB();
        }
        return ret;
    }

    /**
     * Returns for given parameter _jaasKey the instance of class
     * {@link Person}. The parameter _jaasKey is the name of the person
     * used in the given JAAS system for the person.
     *
     * @param _jaasSystem JAAS system for which the JAAS key is named
     * @param _jaasKey key in the foreign JAAS system for which the person is
     *            searched
     * @throws EFapsException on error
     * @return instance of class {@link Person}, or null if person
     *         is not found
     * @see #get(long)
     */
    public static Person getWithJAASKey(final JAASSystem _jaasSystem,
                                        final String _jaasKey)
        throws EFapsException
    {
        long personId = 0;
        ConnectionResource rsrc = null;
        try {
            rsrc = Context.getThreadContext().getConnectionResource();

            Statement stmt = null;

            try {
                final StringBuilder cmd = new StringBuilder();
                cmd.append("select ").append("ID ").append("from V_USERPERSONJASSKEY ").append("where JAASKEY='")
                                .append(_jaasKey).append("' ").append("and JAASSYSID=").append(_jaasSystem.getId());

                stmt = rsrc.getConnection().createStatement();
                final ResultSet resultset = stmt.executeQuery(cmd.toString());
                if (resultset.next()) {
                    personId = resultset.getLong(1);
                }
                resultset.close();

            } catch (final SQLException e) {
                Person.LOG.error("search for person for JAAS system '" + _jaasSystem.getName() + "' with key '"
                                + _jaasKey + "' is not possible", e);
                throw new EFapsException(Person.class, "getWithJAASKey.SQLException", e, _jaasSystem.getName(),
                                _jaasKey);
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                } catch (final SQLException e) {
                    throw new EFapsException(Person.class, "getWithJAASKey.SQLException", e, _jaasSystem.getName(),
                                    _jaasKey);
                }
            }
            rsrc.commit();
        } finally {
            if ((rsrc != null) && rsrc.isOpened()) {
                rsrc.abort();
            }
        }
        return Person.get(personId);
    }

    /**
     * @param _jaasSystem JAAS system which want to create a new person in eFaps
     * @param _jaasKey key of the person in the JAAS system
     * @param _userName name in the eFaps system (used as proposal, it's tested
     *            for uniqueness and changed if needed!)
     * @return new created person
     * @throws EFapsException if person could not be created in eFaps
     * @see #assignToJAASSystem
     */
    public static Person createPerson(final JAASSystem _jaasSystem,
                                      final String _jaasKey,
                                      final String _userName)
        throws EFapsException
    {
        long persId = 0;
        final Type persType = CIAdminUser.Person.getType();
        ConnectionResource rsrc = null;
        try {
            final Context context = Context.getThreadContext();

            rsrc = context.getConnectionResource();

            PreparedStatement stmt = null;
            try {
                StringBuilder cmd = new StringBuilder();

                // TODO: check for uniqueness!
                // TODO: hard coded mofifier and creator
                if (Context.getDbType().supportsGetGeneratedKeys()) {
                    cmd.append("insert into ").append(persType.getMainTable().getSqlTable()).append(
                                    "(TYPEID,NAME,CREATOR,CREATED,MODIFIER,MODIFIED) ").append("values (");
                } else {
                    persId = Context.getDbType().getNewId(rsrc.getConnection(), persType.getMainTable().getSqlTable(),
                                    "ID");
                    cmd.append("insert into ").append(persType.getMainTable().getSqlTable()).append(
                                    "(ID,TYPEID,NAME,CREATOR,CREATED,MODIFIER,MODIFIED) ").append("values (").append(
                                    persId).append(",");
                }
                cmd.append(persType.getId()).append(",").append("'").append(_userName).append("',").append(
                                context.getPersonId()).append(",").append(Context.getDbType().getCurrentTimeStamp())
                                .append(",").append(context.getPersonId()).append(",").append(
                                                Context.getDbType().getCurrentTimeStamp()).append(")");

                if (persId == 0) {
                    stmt = rsrc.getConnection().prepareStatement(cmd.toString(), new String[] { "ID" });
                } else {
                    stmt = rsrc.getConnection().prepareStatement(cmd.toString());
                }

                int rows = stmt.executeUpdate();
                if (rows == 0) {
                    Person.LOG.error("could not execute '" + cmd.toString() + "' for JAAS system '"
                                    + _jaasSystem.getName() + "' person with key '" + _jaasKey
                                    + "' and user name '" + _userName + "'");
                    throw new EFapsException(Person.class, "createPerson.NotInserted", cmd.toString(), _jaasSystem
                                    .getName(), _jaasKey, _userName);
                }
                if (persId == 0) {
                    final ResultSet resultset = stmt.getGeneratedKeys();
                    if (resultset.next()) {
                        persId = resultset.getLong(1);
                    }
                }

                stmt.close();

                cmd = new StringBuilder();
                cmd.append("insert into T_USERPERSON").append("(ID,FIRSTNAME,LASTNAME,EMAIL) ").append("values (")
                                .append(persId).append(",'-','-','-')");
                stmt = rsrc.getConnection().prepareStatement(cmd.toString());
                rows = stmt.executeUpdate();
                if (rows == 0) {
                    Person.LOG.error("could not execute '" + cmd.toString() + "' for JAAS system '"
                                    + _jaasSystem.getName()
                                    + "' person with key '" + _jaasKey + "' and user name '" + _userName + "'");
                    throw new EFapsException(Person.class, "createPerson.NotInserted", cmd.toString(), _jaasSystem
                                    .getName(), _jaasKey, _userName);
                }

            } catch (final SQLException e) {
                Person.LOG.error("could not create for JAAS system '" + _jaasSystem.getName() + "' person with key '"
                                + _jaasKey + "' and user name '" + _userName + "'", e);
                throw new EFapsException(Person.class, "createPerson.SQLException", e, _jaasSystem.getName(), _jaasKey,
                                _userName);
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                } catch (final SQLException e) {
                    throw new EFapsException(Person.class, "createPerson.SQLException", e, _jaasSystem.getName(),
                                    _jaasKey);
                }
            }
            rsrc.commit();
        } finally {
            if ((rsrc != null) && rsrc.isOpened()) {
                rsrc.abort();
            }
        }

        final Person ret = Person.get(persId);
        ret.assignToJAASSystem(_jaasSystem, _jaasKey);
        return ret;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy