Java tutorial
/* * Copyright 2003 - 2016 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. * */ package org.efaps.admin.user; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; 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 java.util.UUID; import org.apache.commons.lang3.builder.ToStringBuilder; import org.efaps.admin.EFapsSystemConfiguration; import org.efaps.admin.KernelSettings; 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.Instance; 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; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** * Class represents the instance of a person/user in eFaps. * * @author The eFasp Team * */ 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 */ 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 */ 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("UUID").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("UUID").column("NAME") .column("STATUS").from("V_USERPERSON", 0).addPart(SQLPart.WHERE).addColumnPart(0, "NAME") .addPart(SQLPart.EQUAL).addValuePart("?").toString(); /** * This is the SQL select statement to select a Person from the database by UUID. */ private static final String SQL_UUID = new SQLSelect().column("ID").column("UUID").column("NAME") .column("STATUS").from("V_USERPERSON", 0).addPart(SQLPart.WHERE).addColumnPart(0, "UUID") .addPart(SQLPart.EQUAL).addValuePart("?").toString(); /** * This is the SQL select statement to select a Role from the database using the JAAS key.. */ private static final String SQL_JAASKEY = new SQLSelect().column("ID").from("V_USERPERSONJASSKEY", 0) .addPart(SQLPart.WHERE).addColumnPart(0, "JAASKEY").addPart(SQLPart.EQUAL).addValuePart("?") .addPart(SQLPart.AND).addColumnPart(0, "JAASSYSID").addPart(SQLPart.EQUAL).addValuePart("?").toString(); /** * SQL select statement to select the relation to active companies. */ private static final String SQL_COMPANY = new SQLSelect().column("USERABSTRACTTO") .from("V_USERPERSON2COMPANY", 0).innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO") .addPart(SQLPart.WHERE).addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true) .addPart(SQLPart.AND).addColumnPart(0, "USERABSTRACTFROM").addPart(SQLPart.EQUAL).addValuePart("?") .toString(); /** * SQL select statement to select the relation to active companies including the JAASYSTEM as filter. */ private static final String SQL_COMPANYJAASKEY = new SQLSelect().column("USERABSTRACTTO") .from("V_USERPERSON2COMPANY", 0).innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO") .addPart(SQLPart.WHERE).addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true) .addPart(SQLPart.AND).addColumnPart(0, "USERABSTRACTFROM").addPart(SQLPart.EQUAL).addValuePart("?") .addPart(SQLPart.AND).addColumnPart(0, "JAASSYSID").addPart(SQLPart.EQUAL).addValuePart("?").toString(); /** * SQL select statement to select the relation to active roles. */ private static final String SQL_ROLE = new SQLSelect().column("USERABSTRACTTO").from("V_USERPERSON2ROLE", 0) .innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO").addPart(SQLPart.WHERE) .addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true).addPart(SQLPart.AND) .addColumnPart(0, "USERABSTRACTFROM").addPart(SQLPart.EQUAL).addValuePart("?").toString(); /** * SQL select statement to select the relation to active roles including the JAASYSTEM as filter. */ private static final String SQL_ROLEJAASKEY = new SQLSelect().column("USERABSTRACTTO") .from("V_USERPERSON2ROLE", 0).innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO") .addPart(SQLPart.WHERE).addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true) .addPart(SQLPart.AND).addColumnPart(0, "USERABSTRACTFROM").addPart(SQLPart.EQUAL).addValuePart("?") .addPart(SQLPart.AND).addColumnPart(0, "JAASSYSID").addPart(SQLPart.EQUAL).addValuePart("?").toString(); /** * SQL select statement to select the relation to active groups. */ private static final String SQL_GROUP = new SQLSelect().column("USERABSTRACTTO").from("V_USERPERSON2GROUP", 0) .innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO").addPart(SQLPart.WHERE) .addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true).addPart(SQLPart.AND) .addColumnPart(0, "USERABSTRACTFROM").addPart(SQLPart.EQUAL).addValuePart("?").toString(); /** * SQL select statement to select the relation to active groups including the JAASYSTEM as filter. */ private static final String SQL_GROUPJAASKEY = new SQLSelect().column("USERABSTRACTTO") .from("V_USERPERSON2GROUP", 0).innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO") .addPart(SQLPart.WHERE).addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true) .addPart(SQLPart.AND).addColumnPart(0, "USERABSTRACTFROM").addPart(SQLPart.EQUAL).addValuePart("?") .addPart(SQLPart.AND).addColumnPart(0, "JAASSYSID").addPart(SQLPart.EQUAL).addValuePart("?").toString(); /** * Name of the Cache by ID. */ private static String IDCACHE = Person.class.getName() + ".ID"; /** * Name of the Cache by Name. */ private static String NAMECACHE = Person.class.getName() + ".Name"; /** * Name of the Cache by UUID. */ private static String UUIDCACHE = Person.class.getName() + ".UUID"; /** * 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<Long> roles = new HashSet<Long>(); /** * HashSet instance variable to hold all id of groups for this person. * * @see #getGroups * @see #add(Group) */ private final Set<Long> groups = new HashSet<Long>(); /** * HashSet instance variable to hold all id of groups for this person. * * @see #getCompanies * @see #add(Company) */ private final Set<Long> companies = new HashSet<Long>(); /** * HashSet instance variable to hold all id of associations for this person. * * @see #getAssociations * @see #add(Associations) */ private final Set<Long> associations = new HashSet<Long>(); /** * 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<Person.AttrName, String> attrValues = new HashMap<Person.AttrName, String>(); /** * 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<Person.AttrName, String> attrUpdated = new HashMap<Person.AttrName, String>(); /** * 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 _uuid UUID 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 _uuid, final String _name, final boolean _status) { super(_id, _uuid, _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 <i>true</i> if the person is the same person as this person, * otherwise <i>false</i> */ @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 <code>true</code> if role is assigned to this person, otherwise * <code>false</code> */ 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 <code>true</code> if group is assigned to this person, otherwise * <code>false</code> */ public boolean isAssigned(final Group _group) { return this.groups.contains(_group.getId()); } /** * Add a Company to this person. * * @param _company Company to add to this person */ private void add(final Company _company) { this.companies.add(_company.getId()); } /** * Tests, if the given Association is assigned to this person. * * @param _association Association to test * @return <code>true</code> if Association is assigned to this person, * otherwise <code>false</code> */ public boolean isAssigned(final Association _association) { return this.associations.contains(_association.getId()); } /** * Add a Association to this person. * * @param _associations Association to add to this person * @see #groups */ private void add(final Association _associations) { this.associations.add(_associations.getId()); } /** * Tests, if the given group is assigned to this person. * * @param _company Company to test * @return <code>true</code> if group is assigned to this person, otherwise * <code>false</code> */ 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 <i>true</i> if password is correct, otherwise <i>false</i> * @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.<PasswordStore>getAttribute(CIAdminUser.Person.Password); if (pwd.checkCurrent(_passwd)) { ret = query.<Boolean>getAttribute(CIAdminUser.Person.Status); } else { setFalseLogin(query.<DateTime>getAttribute(CIAdminUser.Person.LoginTry), query.<Integer>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 DateTime now = new DateTime(DateTimeUtil.getCurrentTimeFromDB().getTime()); final SystemConfiguration kernelConfig = EFapsSystemConfiguration.get(); final int minutes = kernelConfig.getAttributeValueAsInteger(KernelSettings.LOGIN_TIME_RETRY); final int maxtries = kernelConfig.getAttributeValueAsInteger(KernelSettings.LOGIN_MAX_TRIES); final int count = _count + 1; if (minutes > 0 && _logintry.minusMinutes(minutes).isBefore(now)) { 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); } this.associations.clear(); for (final Association association : getAssociationsFromDB(null)) { add(association); } } /** * 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 Association for this * person. The found Association are returned as instance of {@link Set}. * * @param _jaasSystem JAAS system for which the roles must get from eFaps * (if value is <code>null</code>, all companies independent from * the related JAAS system are returned) * @return set of all found Association for given JAAS system * @throws EFapsException on error */ public Set<Association> getAssociationsFromDB(final JAASSystem _jaasSystem) throws EFapsException { final Set<Association> ret = new HashSet<Association>(); ConnectionResource rsrc = null; try { final List<Long> associationIds = new ArrayList<Long>(); rsrc = Context.getThreadContext().getConnectionResource(); Statement stmt = null; try { final StringBuilder cmd = new StringBuilder(); cmd.append("select ").append("ID ").append("from T_USERASSOC ").append("where GROUPID in (") .append("select ").append("USERABSTRACTTO ").append("from V_USERPERSON2GROUP ") .append("where USERABSTRACTFROM =").append(getId()).append(") and ROLEID in (") .append("select ").append("USERABSTRACTTO ").append("from V_USERPERSON2ROLE ") .append("where USERABSTRACTFROM =").append(getId()).append(")"); stmt = rsrc.getConnection().createStatement(); final ResultSet resultset = stmt.executeQuery(cmd.toString()); while (resultset.next()) { associationIds.add(resultset.getLong(1)); } resultset.close(); } catch (final SQLException e) { throw new EFapsException(getClass(), "getAssociationsFromDB.SQLException", e, getName()); } finally { try { if (stmt != null) { stmt.close(); } } catch (final SQLException e) { throw new EFapsException(getClass(), "getAssociationsFromDB.SQLException", e, getName()); } } rsrc.commit(); for (final Long associationId : associationIds) { final Association association = Association.get(associationId); ret.add(association); } } finally { if (rsrc != null && rsrc.isOpened()) { rsrc.abort(); } } return ret; } /** * 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 <code>null</code>, 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<Company> getCompaniesFromDB(final JAASSystem _jaasSystem) throws EFapsException { final Set<Company> ret = new HashSet<Company>(); ConnectionResource rsrc = null; try { final List<Long> companyIds = new ArrayList<Long>(); rsrc = Context.getThreadContext().getConnectionResource(); PreparedStatement stmt = null; try { if (_jaasSystem == null) { stmt = rsrc.getConnection().prepareStatement(SQL_COMPANY); } else { stmt = rsrc.getConnection().prepareStatement(SQL_COMPANYJAASKEY); stmt.setObject(2, _jaasSystem.getId()); } stmt.setObject(1, getId()); final ResultSet resultset = stmt.executeQuery(); 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<Company> _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 company : _companies) { add(company); } } /** * 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<Role> 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 <code>null</code>, 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<Role> getRolesFromDB(final JAASSystem _jaasSystem) throws EFapsException { final Set<Role> ret = new HashSet<Role>(); ConnectionResource rsrc = null; try { final List<Long> roleIds = new ArrayList<Long>(); rsrc = Context.getThreadContext().getConnectionResource(); PreparedStatement stmt = null; try { if (_jaasSystem == null) { stmt = rsrc.getConnection().prepareStatement(SQL_ROLE); } else { stmt = rsrc.getConnection().prepareStatement(SQL_ROLEJAASKEY); stmt.setObject(2, _jaasSystem.getId()); } stmt.setObject(1, getId()); final ResultSet resultset = stmt.executeQuery(); 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<UUID> roleUUIDs = AppAccessHandler.getLoginRoles(); for (final Long roleId : roleIds) { final Role role = Role.get(roleId); if (!AppAccessHandler.excludeMode() || AppAccessHandler.excludeMode() && roleUUIDs.contains(role.getUUID())) { 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<Role> _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<Role> 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 <code>null</code>, 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<Group> getGroupsFromDB(final JAASSystem _jaasSystem) throws EFapsException { final Set<Group> ret = new HashSet<Group>(); ConnectionResource rsrc = null; try { final List<Long> groupIds = new ArrayList<Long>(); rsrc = Context.getThreadContext().getConnectionResource(); PreparedStatement stmt = null; try { if (_jaasSystem == null) { stmt = rsrc.getConnection().prepareStatement(SQL_GROUP); } else { stmt = rsrc.getConnection().prepareStatement(SQL_GROUPJAASKEY); stmt.setObject(2, _jaasSystem.getId()); } stmt.setObject(1, getId()); final ResultSet resultset = stmt.executeQuery(); 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<Group> _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<Group> 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<Long> 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<Long> getGroups() { return this.groups; } /** * Getter method for instance variable {@link #companies}. * * @return value of instance variable {@link #companies} */ public Set<Long> getCompanies() { return this.companies; } /** * Getter method for instance variable {@link #associations}. * * @return value of instance variable {@link #associations} */ public Set<Long> getAssociations() { return this.associations; } @Override public Instance getInstance() { return Instance.get(CIAdminUser.Person.getType(), getId()); } /** * 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) .append("associations", this.associations).toString(); } @Override public boolean equals(final Object _obj) { final boolean ret; if (_obj instanceof Person) { ret = ((Person) _obj).getId() == getId(); } else { ret = super.equals(_obj); } return ret; } @Override public int hashCode() { return Long.valueOf(getId()).intValue(); } /** * Method to initialize the Cache of this CacheObjectInterface. */ public static void initialize() { if (InfinispanCache.get().exists(Person.IDCACHE)) { InfinispanCache.get().<Long, Person>getCache(Person.IDCACHE).clear(); } else { InfinispanCache.get().<Long, Person>getCache(Person.IDCACHE) .addListener(new CacheLogListener(Person.LOG)); } if (InfinispanCache.get().exists(Person.NAMECACHE)) { InfinispanCache.get().<String, Person>getCache(Person.NAMECACHE).clear(); } else { InfinispanCache.get().<String, Person>getCache(Person.NAMECACHE) .addListener(new CacheLogListener(Person.LOG)); } if (InfinispanCache.get().exists(Person.UUIDCACHE)) { InfinispanCache.get().<UUID, Person>getCache(Person.UUIDCACHE).clear(); } else { InfinispanCache.get().<UUID, Person>getCache(Person.UUIDCACHE) .addListener(new CacheLogListener(Person.LOG)); } } /** * Returns for given parameter <i>_id</i> 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<Long, Person> cache = InfinispanCache.get().<Long, Person>getCache(Person.IDCACHE); if (!cache.containsKey(_id)) { Person.getPersonFromDB(Person.SQL_ID, _id); } return cache.get(_id); } /** * Returns for given parameter <i>_uuid</i> the instance of class * {@link Person}. * * @param _uuid UUID to search in the cache * @throws EFapsException on error * @return instance of class {@link Person} * @see #getFromDB */ public static Person get(final UUID _uuid) throws EFapsException { final Cache<UUID, Person> cache = InfinispanCache.get().<UUID, Person>getCache(Person.UUIDCACHE); if (!cache.containsKey(_uuid)) { Person.getPersonFromDB(Person.SQL_UUID, _uuid.toString()); } return cache.get(_uuid); } /** * Returns for given parameter <i>_name</i> 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<String, Person> cache = InfinispanCache.get().<String, Person>getCache(Person.NAMECACHE); if (!cache.containsKey(_name)) { Person.getPersonFromDB(Person.SQL_NAME, _name); } return cache.get(_name); } /** * @param _person Person to be cached * @throws EFapsException on error */ @SuppressFBWarnings("RV_RETURN_VALUE_OF_PUTIFABSENT_IGNORED") private static void cachePerson(final Person _person) throws EFapsException { final Cache<String, Person> nameCache = InfinispanCache.get() .<String, Person>getIgnReCache(Person.NAMECACHE); nameCache.putIfAbsent(_person.getName(), _person); final Cache<Long, Person> idCache = InfinispanCache.get().<Long, Person>getIgnReCache(Person.IDCACHE); idCache.putIfAbsent(_person.getId(), _person); if (_person.getUUID() != null) { final Cache<UUID, Person> uuidCache = InfinispanCache.get() .<UUID, Person>getIgnReCache(Person.UUIDCACHE); uuidCache.putIfAbsent(_person.getUUID(), _person); } } /** * @param _sql SQL Statment to be execuetd * @param _criteria filter criteria * @return true if successful * @throws EFapsException on error */ @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") 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 uuid = rs.getString(2); final String name = rs.getString(3); final boolean status = rs.getBoolean(4); ret = new Person(id, uuid, name.trim(), status); Person.cachePerson(ret); Person.LOG.debug("read from DB Person:{} ", 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 <i>_jaasKey</i> the instance of class * {@link Person}. The parameter <i>_jaasKey</i> 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 <code>null</code> 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(); PreparedStatement stmt = null; try { stmt = rsrc.getConnection().prepareStatement(Person.SQL_JAASKEY); stmt.setObject(1, _jaasKey); stmt.setObject(2, _jaasSystem.getId()); final ResultSet rs = stmt.executeQuery(); if (rs.next()) { personId = rs.getLong(1); } rs.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; } }