1   /*
2    * Copyright 2003 - 2013 The eFaps Team
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Revision:        $Rev$
17   * Last Changed:    $Date$
18   * Last Changed By: $Author$
19   */
20  
21  package org.efaps.admin.user;
22  
23  import java.sql.PreparedStatement;
24  import java.sql.ResultSet;
25  import java.sql.SQLException;
26  import java.sql.Statement;
27  import java.util.ArrayList;
28  import java.util.HashMap;
29  import java.util.HashSet;
30  import java.util.List;
31  import java.util.Locale;
32  import java.util.Map;
33  import java.util.Set;
34  import java.util.UUID;
35  
36  import org.apache.commons.lang3.builder.ToStringBuilder;
37  import org.efaps.admin.EFapsSystemConfiguration;
38  import org.efaps.admin.KernelSettings;
39  import org.efaps.admin.common.SystemConfiguration;
40  import org.efaps.admin.datamodel.Type;
41  import org.efaps.admin.datamodel.attributevalue.PasswordStore;
42  import org.efaps.ci.CIAdminUser;
43  import org.efaps.db.Context;
44  import org.efaps.db.PrintQuery;
45  import org.efaps.db.Update;
46  import org.efaps.db.Update.Status;
47  import org.efaps.db.transaction.ConnectionResource;
48  import org.efaps.db.wrapper.SQLPart;
49  import org.efaps.db.wrapper.SQLSelect;
50  import org.efaps.jaas.AppAccessHandler;
51  import org.efaps.util.ChronologyType;
52  import org.efaps.util.DateTimeUtil;
53  import org.efaps.util.EFapsException;
54  import org.efaps.util.cache.CacheLogListener;
55  import org.efaps.util.cache.InfinispanCache;
56  import org.infinispan.Cache;
57  import org.joda.time.Chronology;
58  import org.joda.time.DateTime;
59  import org.joda.time.DateTimeZone;
60  import org.slf4j.Logger;
61  import org.slf4j.LoggerFactory;
62  
63  /**
64   * Class represents the instance of a person/user in eFaps.
65   *
66   * @author The eFasp Team
67   * @version $Id$
68   */
69  public final class Person
70      extends AbstractUserObject
71  {
72      /**
73       * Needed for serialization.
74       */
75      private static final long serialVersionUID = 1L;
76  
77      /**
78       * Enum for all known and updated attributes from a person. Only this could
79       * be defined which are in the SQL table T_USERPERSON.
80       */
81      public enum AttrName {
82          /** Attribute Name for the First Name of the person. */
83          FIRSTNAME("FIRSTNAME"),
84          /** Attribute Name for the Last Name of the person. */
85          LASTNAME("LASTNAME"),
86          /** Attribute Name for the Chronology of the person. */
87          CHRONOLOGY("CHRONOLOGY"),
88          /** Attribute Name for the Timezone of the person. */
89          TIMZONE("TIMZONE"),
90          /** Attribute Name for the Locale of the person. */
91          LOCALE("LOCALE"),
92           /** Attribute Name for the language of the person. */
93           LANGUAGE("LANG", true);
94  
95          /**
96           * The name of the depending SQL column for an attribute in the table.
97           */
98          private final String sqlColumn;
99  
100         /**
101          * The name of the depending SQL column for an attribute in the table.
102          */
103         private final boolean integer;
104 
105         /**
106          * Constructor setting the instance variables.
107          *
108          * @param _sqlColumn name of the column in the table
109          */
110         private AttrName(final String _sqlColumn)
111         {
112             this(_sqlColumn, false);
113         }
114 
115         /**
116          * Constructor setting the instance variables.
117          *
118          * @param _sqlColumn name of the column in the table
119          * @param _integer is the column a integer column
120          */
121         private AttrName(final String _sqlColumn,
122                          final boolean _integer)
123         {
124             this.sqlColumn = _sqlColumn;
125             this.integer = _integer;
126         }
127     }
128 
129     /**
130      * This is the SQL select statement to select a Person from the database by ID.
131      */
132     private static final String SQL_ID = new SQLSelect()
133                     .column("ID")
134                     .column("UUID")
135                     .column("NAME")
136                     .column("STATUS")
137                     .from("V_USERPERSON", 0)
138                     .addPart(SQLPart.WHERE).addColumnPart(0, "ID").addPart(SQLPart.EQUAL).addValuePart("?").toString();
139 
140     /**
141      * This is the SQL select statement to select a Person from the database by Name.
142      */
143     private static final String SQL_NAME = new SQLSelect()
144                     .column("ID")
145                     .column("UUID")
146                     .column("NAME")
147                     .column("STATUS")
148                     .from("V_USERPERSON", 0)
149                     .addPart(SQLPart.WHERE).addColumnPart(0, "NAME").addPart(SQLPart.EQUAL).addValuePart("?")
150                     .toString();
151 
152     /**
153      * This is the SQL select statement to select a Person from the database by UUID.
154      */
155     private static final String SQL_UUID = new SQLSelect()
156                     .column("ID")
157                     .column("UUID")
158                     .column("NAME")
159                     .column("STATUS")
160                     .from("V_USERPERSON", 0)
161                     .addPart(SQLPart.WHERE).addColumnPart(0, "UUID").addPart(SQLPart.EQUAL).addValuePart("?")
162                     .toString();
163 
164     /**
165      * This is the SQL select statement to select a Role from the database using the JAAS key..
166      */
167     private static final String SQL_JAASKEY = new SQLSelect().column("ID")
168                     .from("V_USERPERSONJASSKEY", 0)
169                     .addPart(SQLPart.WHERE).addColumnPart(0, "JAASKEY").addPart(SQLPart.EQUAL).addValuePart("?")
170                     .addPart(SQLPart.AND).addColumnPart(0, "JAASSYSID").addPart(SQLPart.EQUAL).addValuePart("?")
171                     .toString();
172 
173     /**
174      * SQL select statement to select the relation to active companies.
175      */
176     private static final String SQL_COMPANY = new SQLSelect()
177                     .column("USERABSTRACTTO")
178                     .from("V_USERPERSON2COMPANY", 0)
179                     .innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO")
180                     .addPart(SQLPart.WHERE).addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true)
181                     .addPart(SQLPart.AND).addColumnPart(0, "USERABSTRACTFROM")
182                         .addPart(SQLPart.EQUAL).addValuePart("?")
183                     .toString();
184     /**
185      * SQL select statement to select the relation to active companies including the JAASYSTEM as filter.
186      */
187     private static final String SQL_COMPANYJAASKEY = new SQLSelect()
188                     .column("USERABSTRACTTO")
189                     .from("V_USERPERSON2COMPANY", 0)
190                     .innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO")
191                     .addPart(SQLPart.WHERE).addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true)
192                     .addPart(SQLPart.AND).addColumnPart(0, "USERABSTRACTFROM")
193                         .addPart(SQLPart.EQUAL).addValuePart("?")
194                     .addPart(SQLPart.AND).addColumnPart(0, "JAASSYSID").addPart(SQLPart.EQUAL).addValuePart("?")
195                     .toString();
196 
197     /**
198      * SQL select statement to select the relation to active roles.
199      */
200     private static final String SQL_ROLE = new SQLSelect()
201                     .column("USERABSTRACTTO")
202                     .from("V_USERPERSON2ROLE", 0)
203                     .innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO")
204                     .addPart(SQLPart.WHERE).addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true)
205                     .addPart(SQLPart.AND).addColumnPart(0, "USERABSTRACTFROM")
206                         .addPart(SQLPart.EQUAL).addValuePart("?")
207                     .toString();
208     /**
209      * SQL select statement to select the relation to active roles including the JAASYSTEM as filter.
210      */
211     private static final String SQL_ROLEJAASKEY = new SQLSelect()
212                     .column("USERABSTRACTTO")
213                     .from("V_USERPERSON2ROLE", 0)
214                     .innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO")
215                     .addPart(SQLPart.WHERE).addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true)
216                     .addPart(SQLPart.AND).addColumnPart(0, "USERABSTRACTFROM")
217                         .addPart(SQLPart.EQUAL).addValuePart("?")
218                     .addPart(SQLPart.AND).addColumnPart(0, "JAASSYSID").addPart(SQLPart.EQUAL).addValuePart("?")
219                     .toString();
220 
221     /**
222      * SQL select statement to select the relation to active groups.
223      */
224     private static final String SQL_GROUP = new SQLSelect()
225                     .column("USERABSTRACTTO")
226                     .from("V_USERPERSON2GROUP", 0)
227                     .innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO")
228                     .addPart(SQLPart.WHERE).addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true)
229                     .addPart(SQLPart.AND).addColumnPart(0, "USERABSTRACTFROM")
230                         .addPart(SQLPart.EQUAL).addValuePart("?")
231                     .toString();
232     /**
233      * SQL select statement to select the relation to active groups including the JAASYSTEM as filter.
234      */
235     private static final String SQL_GROUPJAASKEY = new SQLSelect()
236                     .column("USERABSTRACTTO")
237                     .from("V_USERPERSON2GROUP", 0)
238                     .innerJoin("T_USERABSTRACT", 1, "ID", 0, "USERABSTRACTTO")
239                     .addPart(SQLPart.WHERE).addColumnPart(1, "STATUS").addPart(SQLPart.EQUAL).addBooleanValue(true)
240                     .addPart(SQLPart.AND).addColumnPart(0, "USERABSTRACTFROM")
241                         .addPart(SQLPart.EQUAL).addValuePart("?")
242                     .addPart(SQLPart.AND).addColumnPart(0, "JAASSYSID").addPart(SQLPart.EQUAL).addValuePart("?")
243                     .toString();
244 
245 
246     /**
247      * Name of the Cache by ID.
248      */
249     private static String IDCACHE = Person.class.getName() + ".ID";
250 
251     /**
252      * Name of the Cache by Name.
253      */
254     private static String NAMECACHE = Person.class.getName() + ".Name";
255 
256     /**
257      * Name of the Cache by UUID.
258      */
259     private static String UUIDCACHE = Person.class.getName() + ".UUID";
260 
261     /**
262      * Logging instance used to give logging information of this class.
263      */
264     private static final Logger LOG = LoggerFactory.getLogger(Person.class);
265 
266     /**
267      * HashSet instance variable to hold all id of roles for this person.
268      *
269      * @see #getRoles
270      * @see #add(Role)
271      */
272     private final Set<Long> roles = new HashSet<Long>();
273 
274     /**
275      * HashSet instance variable to hold all id of groups for this person.
276      *
277      * @see #getGroups
278      * @see #add(Group)
279      */
280     private final Set<Long> groups = new HashSet<Long>();
281 
282     /**
283      * HashSet instance variable to hold all id of groups for this person.
284      *
285      * @see #getCompanies
286      * @see #add(Company)
287      */
288     private final Set<Long> companies = new HashSet<Long>();
289 
290     /**
291      * HashSet instance variable to hold all id of associations for this person.
292      *
293      * @see #getAssociations
294      * @see #add(Associations)
295      */
296     private final Set<Long> associations = new HashSet<Long>();
297 
298     /**
299      * The map is used to store all attribute values depending on attribute
300      * names defined in {@link #AttrName}.
301      *
302      * @see #setAttrValue
303      * @see #updateAttrValue
304      * @see #AttrName
305      */
306     private final Map<Person.AttrName, String> attrValues = new HashMap<Person.AttrName, String>();
307 
308     /**
309      * The map is used to store information about updates on attribute values.
310      * This information is needed if the database must be updated.
311      *
312      * @see #updateAttrValue
313      * @see #commitAttrValuesInDB
314      * @see #AttrName
315      */
316     private final Map<Person.AttrName, String> attrUpdated = new HashMap<Person.AttrName, String>();
317 
318     /**
319      * The constructor creates a new instance of class {@link Person} and sets
320      * the {@link #key} and {@link #id}.
321      *
322      * @param _id id of the person to set
323      * @param _uuid UUID of the person to set
324      * @param _name name of the person to set
325      * @param _status status of the person to set
326      */
327     private Person(final long _id,
328                    final String _uuid,
329                    final String _name,
330                    final boolean _status)
331     {
332         super(_id, _uuid, _name, _status);
333     }
334 
335     /**
336      * Checks, if the given person is assigned to this user object. Here it is
337      * only tested if the person is the same as the user of the parameter.
338      *
339      * @param _person person to test
340      * @return <i>true</i> if the person is the same person as this person,
341      *         otherwise <i>false</i>
342      */
343     @Override
344     public boolean hasChildPerson(final Person _person)
345     {
346         return _person.getId() == getId();
347     }
348 
349     /**
350      * Add a role to this person.
351      *
352      * @param _role role to add to this person
353      * @see #roles
354      */
355     private void add(final Role _role)
356     {
357         this.roles.add(_role.getId());
358     }
359 
360     /**
361      * Tests, if the given role is assigned to this person.
362      *
363      * @param _role role to test
364      * @return <code>true</code> if role is assigned to this person, otherwise
365      *         <code>false</code>
366      */
367     public boolean isAssigned(final Role _role)
368     {
369         return this.roles.contains(_role.getId());
370     }
371 
372     /**
373      * Add a role to this person.
374      *
375      * @param _group group to add to this person
376      * @see #groups
377      */
378     private void add(final Group _group)
379     {
380         this.groups.add(_group.getId());
381     }
382 
383     /**
384      * Tests, if the given group is assigned to this person.
385      *
386      * @param _group group to test
387      * @return <code>true</code> if group is assigned to this person, otherwise
388      *         <code>false</code>
389      */
390     public boolean isAssigned(final Group _group)
391     {
392         return this.groups.contains(_group.getId());
393     }
394 
395     /**
396      * Add a Company to this person.
397      *
398      * @param _company Company to add to this person
399      */
400     private void add(final Company _company)
401     {
402         this.companies.add(_company.getId());
403     }
404 
405     /**
406      * Tests, if the given Association is assigned to this person.
407      *
408      * @param _association Association to test
409      * @return <code>true</code> if Association is assigned to this person,
410      *          otherwise <code>false</code>
411      */
412     public boolean isAssigned(final Association _association)
413     {
414         return this.associations.contains(_association.getId());
415     }
416 
417     /**
418      * Add a Association to this person.
419      *
420      * @param _associations Association to add to this person
421      * @see #groups
422      */
423     private void add(final Association _associations)
424     {
425         this.associations.add(_associations.getId());
426     }
427 
428     /**
429      * Tests, if the given group is assigned to this person.
430      *
431      * @param _company Company to test
432      * @return <code>true</code> if group is assigned to this person, otherwise
433      *         <code>false</code>
434      */
435     public boolean isAssigned(final Company _company)
436     {
437         return this.companies.contains(_company.getId());
438     }
439 
440     /**
441      * All assigned roles in {@link #roles} and groups in {@link #groups} are
442      * removed in the cache from this person instance. This is needed if the
443      * person assignments are rebuild (e.g. from a login servlet).
444      */
445     public void cleanUp()
446     {
447         this.roles.clear();
448         this.groups.clear();
449         this.companies.clear();
450     }
451 
452     /**
453      * The method sets the attribute values in the cache for given attribute
454      * name to given new attribute value.
455      *
456      * @param _attrName name of attribute to set
457      * @param _value new value to set
458      * @see #attrValues
459      */
460     private void setAttrValue(final AttrName _attrName,
461                               final String _value)
462     {
463         synchronized (this.attrValues) {
464             this.attrValues.put(_attrName, _value);
465         }
466     }
467 
468     /**
469      * Returns for given attribute name the value in the cache.
470      *
471      * @param _attrName name of attribute for which the value must returned
472      * @return attribute value of given attribute name
473      */
474     public String getAttrValue(final AttrName _attrName)
475     {
476         return this.attrValues.get(_attrName);
477     }
478 
479     /**
480      * @return attribute value of first name
481      */
482     public String getFirstName()
483     {
484         return this.attrValues.get(Person.AttrName.FIRSTNAME);
485     }
486 
487     /**
488      * @return attribute value of last name
489      */
490     public String getLastName()
491     {
492         return this.attrValues.get(Person.AttrName.LASTNAME);
493     }
494 
495     /**
496      * Method to get the Locale of this Person. Default is the "English" Locale.
497      *
498      * @return Locale of this Person
499      */
500     public Locale getLocale()
501     {
502         final Locale ret;
503         if (this.attrValues.get(Person.AttrName.LOCALE) != null) {
504             final String localeStr = this.attrValues.get(Person.AttrName.LOCALE);
505             final String[] countries = localeStr.split("_");
506             if (countries.length == 2) {
507                 ret = new Locale(countries[0], countries[1]);
508             } else if (countries.length == 3) {
509                 ret = new Locale(countries[0], countries[1], countries[2]);
510             } else {
511                 ret = new Locale(localeStr);
512             }
513         } else {
514             ret = Locale.ENGLISH;
515         }
516         return ret;
517     }
518 
519     /**
520      * Method to get the Language of the UserInterface for this Person. Default
521      * is english.
522      *
523      * @return iso code of a language
524      */
525     public String getLanguage()
526     {
527         return this.attrValues.get(Person.AttrName.LANGUAGE) != null
528                         ? this.attrValues.get(Person.AttrName.LANGUAGE)
529                         : Locale.ENGLISH.getISO3Language();
530     }
531 
532     /**
533      * Method to get the Timezone of this Person. Default is the "UTC" Timezone.
534      *
535      * @return Timezone of this Person
536      */
537     public DateTimeZone getTimeZone()
538     {
539         return this.attrValues.get(Person.AttrName.TIMZONE) != null
540                         ? DateTimeZone.forID(this.attrValues.get(Person.AttrName.TIMZONE))
541                         : DateTimeZone.UTC;
542     }
543 
544     /**
545      * Method to get the Chronology of this Person. Default is the "ISO8601"
546      * Chronology.
547      *
548      * @return Chronology of this Person
549      */
550     public Chronology getChronology()
551     {
552         return getChronologyType().getInstance(getTimeZone());
553     }
554 
555     /**
556      * Method to get the ChronologyType of this Person. Default is the "ISO8601"
557      * ChronologyType.
558      *
559      * @return ChronologyType of this Person
560      */
561     public ChronologyType getChronologyType()
562     {
563         final String chronoKey = this.attrValues.get(Person.AttrName.CHRONOLOGY);
564         final ChronologyType chronoType;
565         if (chronoKey != null) {
566             chronoType = ChronologyType.getByKey(chronoKey);
567         } else {
568             chronoType = ChronologyType.ISO8601;
569         }
570         return chronoType;
571     }
572 
573     /**
574      * Updates a value for an attribute in the cache and marks then as modified.
575      * Only after calling method {@link #commitAttrValuesInDB} the updated
576      * attribute value is stored in the database!
577      *
578      * @param _attrName name of attribute to update
579      * @param _value new value to set directly
580      */
581     public void updateAttrValue(final AttrName _attrName,
582                                 final String _value)
583     {
584         this.updateAttrValue(_attrName, _value, _value);
585     }
586 
587     /**
588      * Updates a value for an attribute in the cache and marks then as modified.
589      * Only after calling method {@link #commitAttrValuesInDB} the updated
590      * attribute value is stored in the database!
591      *
592      * @param _attrName name of attribute to update
593      * @param _value new value to set directly
594      * @param _updateValue new value to be set in the database
595      * @see #attrUpdated
596      * @see #attrValues
597      */
598     public void updateAttrValue(final AttrName _attrName,
599                                 final String _value,
600                                 final String _updateValue)
601     {
602         synchronized (this.attrUpdated) {
603             synchronized (this.attrValues) {
604                 this.attrValues.put(_attrName, _value);
605             }
606             this.attrUpdated.put(_attrName, _updateValue);
607         }
608     }
609 
610     /**
611      * Commits update attribute defined in {@link #attrUpdated} with method
612      * {@link #updateAttrValue} to the database. After database update,
613      * {@link #attrUpdated} is cleared.
614      *
615      * @throws EFapsException on error
616      * @see #attrUpdated
617      * @see #attrValues
618      * @see #updateAttrValue
619      *
620      */
621     public void commitAttrValuesInDB()
622         throws EFapsException
623     {
624         synchronized (this.attrUpdated) {
625             if (this.attrUpdated.size() > 0) {
626                 ConnectionResource rsrc = null;
627                 try {
628                     final Context context = Context.getThreadContext();
629                     rsrc = context.getConnectionResource();
630 
631                     final StringBuilder cmd = new StringBuilder();
632                     PreparedStatement stmt = null;
633                     try {
634                         cmd.append("update T_USERPERSON set ");
635                         boolean first = true;
636                         for (final AttrName attrName : this.attrUpdated.keySet()) {
637                             if (first) {
638                                 first = false;
639                             } else {
640                                 cmd.append(",");
641                             }
642                             cmd.append(attrName.sqlColumn).append("=?");
643                         }
644                         cmd.append(" where ID=").append(getId());
645                         stmt = rsrc.getConnection().prepareStatement(cmd.toString());
646 
647                         int col = 1;
648                         for (final AttrName attrName : this.attrUpdated.keySet()) {
649                             final String tmp = this.attrUpdated.get(attrName);
650                             if (attrName.integer) {
651                                 stmt.setInt(col, tmp == null ? 0 : Integer.parseInt(tmp.trim()));
652                             } else {
653                                 stmt.setString(col, tmp == null ? null : tmp.trim());
654                             }
655                             col++;
656                         }
657 
658                         final int rows = stmt.executeUpdate();
659                         if (rows == 0) {
660                             Person.LOG.error("could not update '" + cmd.toString() + "' person with user name '"
661                                             + getName() + "' (id = " + getId() + ")");
662                             throw new EFapsException(Person.class, "commitAttrValuesInDB.NotUpdated", cmd.toString(),
663                                             getName(), getId());
664                         }
665                         // TODO: update modified date
666                     } catch (final SQLException e) {
667                         Person.LOG.error("could not update '" + cmd.toString() + "' person with user name '" + getName()
668                                         + "' (id = " + getId() + ")", e);
669                         throw new EFapsException(Person.class, "commitAttrValuesInDB.SQLException", e, cmd.toString(),
670                                         getName(), getId());
671                     } finally {
672                         try {
673                             if (stmt != null) {
674                                 stmt.close();
675                             }
676                         } catch (final SQLException e) {
677                             throw new EFapsException(Person.class, "commitAttrValuesInDB.SQLException", e, cmd
678                                             .toString(), getName(), getId());
679                         }
680                     }
681                     rsrc.commit();
682                 } finally {
683                     if (rsrc != null && rsrc.isOpened()) {
684                         rsrc.abort();
685                     }
686                 }
687                 this.attrUpdated.clear();
688             }
689         }
690     }
691 
692     /**
693      * The instance method checks if the given password is the same password as
694      * the password in the database.
695      *
696      * @param _passwd password to check for this person
697      * @return <i>true</i> if password is correct, otherwise <i>false</i>
698      * @throws EFapsException if query for the password check failed
699      */
700     public boolean checkPassword(final String _passwd)
701         throws EFapsException
702     {
703         boolean ret = false;
704         final PrintQuery query = new PrintQuery(CIAdminUser.Person.getType(), getId());
705         query.addAttribute(CIAdminUser.Person.Password,
706                            CIAdminUser.Person.LastLogin,
707                            CIAdminUser.Person.LoginTry,
708                            CIAdminUser.Person.LoginTriesCounter,
709                            CIAdminUser.Person.Status);
710         if (query.executeWithoutAccessCheck()) {
711             final PasswordStore pwd = query.<PasswordStore>getAttribute(CIAdminUser.Person.Password);
712             if (pwd.checkCurrent(_passwd)) {
713                 ret = query.<Boolean>getAttribute(CIAdminUser.Person.Status);
714             } else {
715                 setFalseLogin(query.<DateTime>getAttribute(CIAdminUser.Person.LoginTry),
716                                 query.<Integer>getAttribute(CIAdminUser.Person.LoginTriesCounter));
717             }
718         }
719         return ret;
720     }
721 
722     /**
723      * Method that sets the time and the number of failed logins.
724      *
725      * @param _logintry time of the false Login
726      * @param _count number of tries
727      * @throws EFapsException on error
728      */
729     private void setFalseLogin(final DateTime _logintry,
730                                final int _count)
731         throws EFapsException
732     {
733         if (_count > 0) {
734             final DateTime now = new DateTime(DateTimeUtil.getCurrentTimeFromDB().getTime());
735             final SystemConfiguration kernelConfig = EFapsSystemConfiguration.get();
736 
737             final int minutes = kernelConfig.getAttributeValueAsInteger(KernelSettings.LOGIN_TIME_RETRY);
738 
739             final int maxtries = kernelConfig.getAttributeValueAsInteger(KernelSettings.LOGIN_MAX_TRIES);
740 
741             final int count = _count + 1;
742             if (minutes > 0 && _logintry.minusMinutes(minutes).isBefore(now)) {
743                 updateFalseLoginDB(1);
744             } else {
745                 updateFalseLoginDB(count);
746             }
747             if (maxtries > 0 && count > maxtries && getStatus()) {
748                 setStatusInDB(false);
749             }
750         } else {
751             updateFalseLoginDB(1);
752         }
753     }
754 
755     /**
756      * Method to set the number of false Login tries in the eFaps-DataBase.
757      *
758      * @param _tries number or tries
759      * @throws EFapsException on error
760      */
761     private void updateFalseLoginDB(final int _tries)
762         throws EFapsException
763     {
764         ConnectionResource rsrc = null;
765         try {
766             final Context context = Context.getThreadContext();
767             rsrc = context.getConnectionResource();
768 
769             Statement stmt = null;
770             final StringBuilder cmd = new StringBuilder();
771             try {
772 
773                 cmd.append("update T_USERPERSON ").append("set LOGINTRY=").append(
774                                 Context.getDbType().getCurrentTimeStamp()).append(", LOGINTRIES=").append(_tries)
775                                 .append(" where ID=").append(getId());
776                 stmt = rsrc.getConnection().createStatement();
777                 final int rows = stmt.executeUpdate(cmd.toString());
778                 if (rows == 0) {
779                     Person.LOG.error("could not execute '" + cmd.toString()
780                                     + "' to update last login information for person '" + toString() + "'");
781                     throw new EFapsException(getClass(), "updateLastLogin.NotUpdated", cmd.toString(), getName());
782                 }
783             } catch (final SQLException e) {
784                 Person.LOG.error("could not execute '" + cmd.toString()
785                                 + "' to update last login information for person '" + toString() + "'", e);
786                 throw new EFapsException(getClass(), "updateLastLogin.SQLException", e, cmd.toString(), getName());
787             } finally {
788                 try {
789                     if (stmt != null) {
790                         stmt.close();
791                     }
792                 } catch (final SQLException e) {
793                     throw new EFapsException(getClass(), "updateLastLogin.SQLException", e, cmd.toString(), getName());
794                 }
795             }
796             rsrc.commit();
797         } finally {
798             if (rsrc != null && rsrc.isOpened()) {
799                 rsrc.abort();
800             }
801         }
802     }
803 
804     /**
805      * The instance method sets the new password for the current context user.
806      * Before the new password is set, some checks are made.
807      *
808      * @param _newPasswd new Password to set
809      * @throws EFapsException on error
810      * @return true if password set, else false
811      */
812     public Status setPassword(final String _newPasswd)
813         throws EFapsException
814     {
815         final Type type = CIAdminUser.Person.getType();
816         if (_newPasswd.length() == 0) {
817             throw new EFapsException(getClass(), "PassWordLength", 1, _newPasswd.length());
818         }
819         final Update update = new Update(type, "" + getId());
820         final Status status = update.add(CIAdminUser.Person.Password, _newPasswd);
821         if (status.isOk()) {
822             update.execute();
823             update.close();
824         } else {
825             Person.LOG.error("Password could not be set by the Update, due to restrictions " + "e.g. length???");
826             throw new EFapsException(getClass(), "TODO");
827         }
828         return status;
829     }
830 
831     /**
832      * The instance method reads all information from the database.
833      *
834      * @throws EFapsException on error
835      * @see #readFromDBAttributes()
836      */
837     protected void readFromDB()
838         throws EFapsException
839     {
840         readFromDBAttributes();
841         this.roles.clear();
842         for (final Role role : getRolesFromDB()) {
843             add(role);
844         }
845         this.groups.clear();
846         for (final Group group : getGroupsFromDB(null)) {
847             add(group);
848         }
849         this.companies.clear();
850         for (final Company company : getCompaniesFromDB(null)) {
851             add(company);
852         }
853         this.associations.clear();
854         for (final Association association : getAssociationsFromDB(null)) {
855             add(association);
856         }
857     }
858 
859     /**
860      * All attributes from this person are read from the database.
861      *
862      * @throws EFapsException if the attributes for this person could not be
863      *             read
864      */
865     private void readFromDBAttributes()
866         throws EFapsException
867     {
868         ConnectionResource rsrc = null;
869         try {
870             rsrc = Context.getThreadContext().getConnectionResource();
871             Statement stmt = null;
872             try {
873                 stmt = rsrc.getConnection().createStatement();
874 
875                 final StringBuilder cmd = new StringBuilder("select ");
876                 for (final AttrName attrName : Person.AttrName.values()) {
877                     cmd.append(attrName.sqlColumn).append(",");
878                 }
879                 cmd.append("0 as DUMMY ").append("from V_USERPERSON ").append("where V_USERPERSON.ID=").append(getId());
880 
881                 final ResultSet resultset = stmt.executeQuery(cmd.toString());
882                 if (resultset.next()) {
883                     for (final AttrName attrName : Person.AttrName.values()) {
884                         final String tmp = resultset.getString(attrName.sqlColumn);
885                         setAttrValue(attrName, tmp == null ? null : tmp.trim());
886                     }
887                 }
888                 resultset.close();
889             } catch (final SQLException e) {
890                 Person.LOG.error("read attributes for person with SQL statement is not " + "possible", e);
891                 throw new EFapsException(Person.class, "readFromDBAttributes.SQLException", e, getName(), getId());
892             } finally {
893                 try {
894                     if (stmt != null) {
895                         stmt.close();
896                     }
897                 } catch (final SQLException e) {
898                     Person.LOG.error("close of SQL statement is not possible", e);
899                 }
900             }
901             rsrc.commit();
902         } finally {
903             if (rsrc != null && rsrc.isOpened()) {
904                 rsrc.abort();
905             }
906         }
907     }
908 
909     /**
910      * The method reads directly from the database all stored Association for this
911      * person. The found Association are returned as instance of {@link Set}.
912      *
913      * @param _jaasSystem JAAS system for which the roles must get from eFaps
914      *            (if value is <code>null</code>, all companies independent from
915      *            the related JAAS system are returned)
916      * @return set of all found Association for given JAAS system
917      * @throws EFapsException on error
918      */
919     public Set<Association> getAssociationsFromDB(final JAASSystem _jaasSystem)
920         throws EFapsException
921     {
922         final Set<Association> ret = new HashSet<Association>();
923         ConnectionResource rsrc = null;
924         try {
925             final List<Long> associationIds = new ArrayList<Long>();
926             rsrc = Context.getThreadContext().getConnectionResource();
927 
928             Statement stmt = null;
929 
930             try {
931                 final StringBuilder cmd = new StringBuilder();
932                 cmd.append("select ").append("ID ")
933                     .append("from T_USERASSOC ")
934                     .append("where GROUPID in (")
935                         .append("select ").append("USERABSTRACTTO ")
936                         .append("from V_USERPERSON2GROUP ")
937                         .append("where USERABSTRACTFROM =").append(getId())
938                     .append(") and ROLEID in (")
939                         .append("select ").append("USERABSTRACTTO ")
940                         .append("from V_USERPERSON2ROLE ")
941                         .append("where USERABSTRACTFROM =").append(getId())
942                     .append(")");
943 
944                 stmt = rsrc.getConnection().createStatement();
945                 final ResultSet resultset = stmt.executeQuery(cmd.toString());
946                 while (resultset.next()) {
947                     associationIds.add(resultset.getLong(1));
948                 }
949                 resultset.close();
950 
951             } catch (final SQLException e) {
952                 throw new EFapsException(getClass(), "getAssociationsFromDB.SQLException", e, getName());
953             } finally {
954                 try {
955                     if (stmt != null) {
956                         stmt.close();
957                     }
958                 } catch (final SQLException e) {
959                     throw new EFapsException(getClass(), "getAssociationsFromDB.SQLException", e, getName());
960                 }
961             }
962             rsrc.commit();
963             for (final Long associationId : associationIds) {
964                 final Association association = Association.get(associationId);
965                 ret.add(association);
966             }
967         } finally {
968             if (rsrc != null && rsrc.isOpened()) {
969                 rsrc.abort();
970             }
971         }
972         return ret;
973     }
974 
975     /**
976      * The method reads directly from the database all stored companies for this
977      * person. The found roles are returned as instance of {@link Set}.
978      *
979      * @param _jaasSystem JAAS system for which the roles must get from eFaps
980      *            (if value is <code>null</code>, all companies independent from
981      *            the related JAAS system are returned)
982      * @return set of all found companies for given JAAS system
983      * @throws EFapsException on error
984      */
985     public Set<Company> getCompaniesFromDB(final JAASSystem _jaasSystem)
986         throws EFapsException
987     {
988         final Set<Company> ret = new HashSet<Company>();
989         ConnectionResource rsrc = null;
990         try {
991             final List<Long> companyIds = new ArrayList<Long>();
992             rsrc = Context.getThreadContext().getConnectionResource();
993 
994             PreparedStatement stmt = null;
995             try {
996                 if (_jaasSystem == null) {
997                     stmt = rsrc.getConnection().prepareStatement(SQL_COMPANY);
998                 } else {
999                     stmt = rsrc.getConnection().prepareStatement(SQL_COMPANYJAASKEY);
1000                     stmt.setObject(2, _jaasSystem.getId());
1001                 }
1002                 stmt.setObject(1, getId());
1003                 final ResultSet resultset = stmt.executeQuery();
1004                 while (resultset.next()) {
1005                     companyIds.add(resultset.getLong(1));
1006                 }
1007                 resultset.close();
1008 
1009             } catch (final SQLException e) {
1010                 throw new EFapsException(getClass(), "getCompaniesFromDB.SQLException", e, getName());
1011             } finally {
1012                 try {
1013                     if (stmt != null) {
1014                         stmt.close();
1015                     }
1016                 } catch (final SQLException e) {
1017                     throw new EFapsException(getClass(), "getCompaniesFromDB.SQLException", e, getName());
1018                 }
1019             }
1020             rsrc.commit();
1021             for (final Long companyId : companyIds) {
1022                 final Company company = Company.get(companyId);
1023                 ret.add(company);
1024             }
1025         } finally {
1026             if (rsrc != null && rsrc.isOpened()) {
1027                 rsrc.abort();
1028             }
1029         }
1030         return ret;
1031     }
1032 
1033     /**
1034      * The depending roles for the user are set for the given JAAS system. All
1035      * roles are added to the loaded roles in the cache of this person.
1036      *
1037      * @param _jaasSystem JAAS system for which the roles are set
1038      * @param _companies set of company to set for the JAAS system
1039      * @throws EFapsException from calling methods
1040      */
1041     public void setCompanies(final JAASSystem _jaasSystem,
1042                              final Set<Company> _companies)
1043         throws EFapsException
1044     {
1045 
1046         if (_jaasSystem == null) {
1047             throw new EFapsException(getClass(), "setRoles.nojaasSystem", getName());
1048         }
1049         if (_companies == null) {
1050             throw new EFapsException(getClass(), "setRoles.noRoles", getName());
1051         }
1052         for (final Company company : _companies) {
1053             add(company);
1054         }
1055     }
1056 
1057     /**
1058      * The method reads directly from the database all stores roles for the this
1059      * person. The found roles are returned as instance of {@link java.util.Set}
1060      * .
1061      *
1062      * @return set of all found roles for all JAAS systems
1063      * @see #getRolesFromDB(JAASSystem);
1064      * @throws EFapsException on error
1065      */
1066     public Set<Role> getRolesFromDB()
1067         throws EFapsException
1068     {
1069         return getRolesFromDB((JAASSystem) null);
1070     }
1071 
1072     /**
1073      * The method reads directly from the database all stores roles for the this
1074      * person. The found roles are returned as instance of {@link java.util.Set}
1075      * .
1076      *
1077      * @param _jaasSystem JAAS system for which the roles are searched in eFaps
1078      *            (if value is <code>null</code>, all roles independent from the
1079      *            related JAAS system are returned)
1080      * @return set of all found roles for given JAAS system
1081      * @throws EFapsException on error
1082      */
1083     public Set<Role> getRolesFromDB(final JAASSystem _jaasSystem)
1084         throws EFapsException
1085     {
1086 
1087         final Set<Role> ret = new HashSet<Role>();
1088         ConnectionResource rsrc = null;
1089         try {
1090             final List<Long> roleIds = new ArrayList<Long>();
1091             rsrc = Context.getThreadContext().getConnectionResource();
1092             PreparedStatement stmt = null;
1093             try {
1094                 if (_jaasSystem == null) {
1095                     stmt = rsrc.getConnection().prepareStatement(SQL_ROLE);
1096                 } else {
1097                     stmt = rsrc.getConnection().prepareStatement(SQL_ROLEJAASKEY);
1098                     stmt.setObject(2, _jaasSystem.getId());
1099                 }
1100                 stmt.setObject(1, getId());
1101                 final ResultSet resultset = stmt.executeQuery();
1102                 while (resultset.next()) {
1103                     roleIds.add(resultset.getLong(1));
1104                 }
1105                 resultset.close();
1106 
1107             } catch (final SQLException e) {
1108                 throw new EFapsException(getClass(), "getRolesFromDB.SQLException", e, getName());
1109             } finally {
1110                 try {
1111                     if (stmt != null) {
1112                         stmt.close();
1113                     }
1114                 } catch (final SQLException e) {
1115                     throw new EFapsException(getClass(), "getRolesFromDB.SQLException", e, getName());
1116                 }
1117             }
1118             rsrc.commit();
1119 
1120             final Set<UUID> roleUUIDs = AppAccessHandler.getLoginRoles();
1121             for (final Long roleId : roleIds) {
1122                 final Role role = Role.get(roleId);
1123                 if (!AppAccessHandler.excludeMode()
1124                                 || AppAccessHandler.excludeMode() && roleUUIDs.contains(role.getUUID())) {
1125                     ret.add(role);
1126                 }
1127             }
1128         } finally {
1129             if (rsrc != null && rsrc.isOpened()) {
1130                 rsrc.abort();
1131             }
1132         }
1133         return ret;
1134     }
1135 
1136     /**
1137      * The depending roles for the user are set for the given JAAS system. All
1138      * roles are added to the loaded roles in the cache of this person.
1139      *
1140      * @param _jaasSystem JAAS system for which the roles are set
1141      * @param _roles set of roles to set for the JAAS system
1142      * @see #assignRoleInDb
1143      * @see #unassignRoleInDb
1144      * @throws EFapsException from calling methods
1145      */
1146     public void setRoles(final JAASSystem _jaasSystem,
1147                          final Set<Role> _roles)
1148         throws EFapsException
1149     {
1150 
1151         if (_jaasSystem == null) {
1152             throw new EFapsException(getClass(), "setRoles.nojaasSystem", getName());
1153         }
1154         if (_roles == null) {
1155             throw new EFapsException(getClass(), "setRoles.noRoles", getName());
1156         }
1157 
1158         for (final Role role : _roles) {
1159             add(role);
1160         }
1161 
1162         // current roles
1163         final Set<Role> rolesInDb = getRolesFromDB(_jaasSystem);
1164 
1165         // compare new roles with current roles (add missing roles)
1166         for (final Role role : _roles) {
1167             if (!rolesInDb.contains(role)) {
1168                 assignRoleInDb(_jaasSystem, role);
1169             }
1170         }
1171 
1172         // compare current roles with new roles (remove roles which are to much)
1173         for (final Role role : rolesInDb) {
1174             if (!_roles.contains(role)) {
1175                 unassignRoleInDb(_jaasSystem, role);
1176             }
1177         }
1178     }
1179 
1180     /**
1181      * For this person, a role is assigned for the given JAAS system.
1182      *
1183      * @param _jaasSystem JAAS system for which the role is assigned
1184      * @param _role role to assign
1185      * @see AbstractUserObject#assignToUserObjectInDb(Type, JAASSystem,
1186      *      AbstractUserObject)
1187      * @throws EFapsException on error
1188      */
1189     public void assignRoleInDb(final JAASSystem _jaasSystem,
1190                                final Role _role)
1191         throws EFapsException
1192     {
1193         assignToUserObjectInDb(CIAdminUser.Person2Role.getType(), _jaasSystem, _role);
1194     }
1195 
1196     /**
1197      * The given role is unassigned for the given JAAS system from this person.
1198      *
1199      * @param _jaasSystem JAAS system for which the role is assigned
1200      * @param _role role to unassign
1201      * @see AbstractUserObject#unassignFromUserObjectInDb(Type, JAASSystem,
1202      *      AbstractUserObject)
1203      * @throws EFapsException on error
1204      */
1205     public void unassignRoleInDb(final JAASSystem _jaasSystem,
1206                                  final Role _role)
1207         throws EFapsException
1208     {
1209         unassignFromUserObjectInDb(CIAdminUser.Person2Role.getType(), _jaasSystem, _role);
1210     }
1211 
1212     /**
1213      * The method reads directly from eFaps all stored groups for the this
1214      * person. The found groups are returned as instance of {@link Set}.
1215      *
1216      * @param _jaasSystem JAAS system for which the groups must fetched from
1217      *            eFaps (if value is <code>null</code>, all groups independent
1218      *            from the related JAAS system are returned)
1219      * @throws EFapsException on error
1220      * @return set of all found groups for given JAAS system
1221      */
1222     public Set<Group> getGroupsFromDB(final JAASSystem _jaasSystem)
1223         throws EFapsException
1224     {
1225         final Set<Group> ret = new HashSet<Group>();
1226         ConnectionResource rsrc = null;
1227         try {
1228             final List<Long> groupIds = new ArrayList<Long>();
1229             rsrc = Context.getThreadContext().getConnectionResource();
1230 
1231             PreparedStatement stmt = null;
1232             try {
1233                 if (_jaasSystem == null) {
1234                     stmt = rsrc.getConnection().prepareStatement(SQL_GROUP);
1235                 } else {
1236                     stmt = rsrc.getConnection().prepareStatement(SQL_GROUPJAASKEY);
1237                     stmt.setObject(2, _jaasSystem.getId());
1238                 }
1239                 stmt.setObject(1, getId());
1240                 final ResultSet resultset = stmt.executeQuery();
1241                 while (resultset.next()) {
1242                     groupIds.add(resultset.getLong(1));
1243                 }
1244                 resultset.close();
1245             } catch (final SQLException e) {
1246                 throw new EFapsException(getClass(), "getGroupsFromDB.SQLException", e, getName());
1247             } finally {
1248                 try {
1249                     if (stmt != null) {
1250                         stmt.close();
1251                     }
1252                 } catch (final SQLException e) {
1253                     throw new EFapsException(getClass(), "getGroupsFromDB.SQLException", e, getName());
1254                 }
1255             }
1256             rsrc.commit();
1257             for (final Long groupId : groupIds) {
1258                 ret.add(Group.get(groupId));
1259             }
1260         } finally {
1261             if (rsrc != null && rsrc.isOpened()) {
1262                 rsrc.abort();
1263             }
1264         }
1265         return ret;
1266     }
1267 
1268     /**
1269      * The depending groups for the user are set for the given JAAS system. All
1270      * groups are added to the loaded groups in the cache of this person.
1271      *
1272      * @param _jaasSystem JAAS system for which the roles are set
1273      * @param _groups set of groups to set for the JAAS system
1274      * @see #assignGroupInDb(JAASSystem, Group)
1275      * @see #unassignGroupInDb(JAASSystem, Group)
1276      * @throws EFapsException from calling methods
1277      */
1278     public void setGroups(final JAASSystem _jaasSystem,
1279                           final Set<Group> _groups)
1280         throws EFapsException
1281     {
1282         if (_jaasSystem == null) {
1283             throw new EFapsException(getClass(), "setGroups.nojaasSystem", getName());
1284         }
1285         if (_groups == null) {
1286             throw new EFapsException(getClass(), "setGroups.noGroups", getName());
1287         }
1288 
1289         for (final Group group : _groups) {
1290             add(group);
1291         }
1292 
1293         // current groups
1294         final Set<Group> groupsInDb = getGroupsFromDB(_jaasSystem);
1295 
1296         // compare new roles with current groups (add missing groups)
1297         for (final Group group : _groups) {
1298             if (!groupsInDb.contains(group)) {
1299                 assignGroupInDb(_jaasSystem, group);
1300             }
1301         }
1302 
1303         // compare current roles with new groups (remove groups which are to
1304         // much)
1305         for (final Group group : groupsInDb) {
1306             if (!_groups.contains(group)) {
1307                 unassignGroupInDb(_jaasSystem, group);
1308             }
1309         }
1310     }
1311 
1312     /**
1313      * For this person, a group is assigned for the given JAAS system.
1314      *
1315      * @param _jaasSystem JAAS system for which the group is assigned
1316      * @param _group group to assign
1317      * @throws EFapsException on error
1318      * @see AbstractUserObject#assignToUserObjectInDb
1319      */
1320     public void assignGroupInDb(final JAASSystem _jaasSystem,
1321                                 final Group _group)
1322         throws EFapsException
1323     {
1324         assignToUserObjectInDb(CIAdminUser.Person2Group.getType(), _jaasSystem, _group);
1325     }
1326 
1327     /**
1328      * The given group is unassigned for the given JAAS system from this person.
1329      *
1330      * @param _jaasSystem JAAS system for which the role is assigned
1331      * @param _group group to unassign
1332      * @throws EFapsException on error
1333      * @see AbstractUserObject#unassignFromUserObjectInDb
1334      */
1335     public void unassignGroupInDb(final JAASSystem _jaasSystem,
1336                                   final Group _group)
1337         throws EFapsException
1338     {
1339         unassignFromUserObjectInDb(CIAdminUser.Person2Group.getType(), _jaasSystem, _group);
1340     }
1341 
1342     /**
1343      * Update the last login date of this person to current time stamp.
1344      *
1345      * @throws EFapsException if the last login information could not be updated
1346      */
1347     public void updateLastLogin()
1348         throws EFapsException
1349     {
1350         ConnectionResource rsrc = null;
1351         try {
1352             final Context context = Context.getThreadContext();
1353             rsrc = context.getConnectionResource();
1354 
1355             Statement stmt = null;
1356             final StringBuilder cmd = new StringBuilder();
1357             try {
1358 
1359                 cmd.append("update T_USERPERSON ").append("set LASTLOGIN=").append(
1360                                 Context.getDbType().getCurrentTimeStamp()).append(", LOGINTRIES=0 ")
1361                                 .append("where ID=").append(getId());
1362                 stmt = rsrc.getConnection().createStatement();
1363                 final int rows = stmt.executeUpdate(cmd.toString());
1364                 if (rows == 0) {
1365                     Person.LOG.error("could not execute '" + cmd.toString()
1366                                     + "' to update last login information for person '" + toString() + "'");
1367                     throw new EFapsException(getClass(), "updateLastLogin.NotUpdated", cmd.toString(), getName());
1368                 }
1369             } catch (final SQLException e) {
1370                 Person.LOG.error("could not execute '" + cmd.toString()
1371                                 + "' to update last login information for person '" + toString() + "'", e);
1372                 throw new EFapsException(getClass(), "updateLastLogin.SQLException", e, cmd.toString(), getName());
1373             } finally {
1374                 try {
1375                     if (stmt != null) {
1376                         stmt.close();
1377                     }
1378                 } catch (final SQLException e) {
1379                     throw new EFapsException(getClass(), "updateLastLogin.SQLException", e, cmd.toString(), getName());
1380                 }
1381             }
1382             rsrc.commit();
1383         } finally {
1384             if (rsrc != null && rsrc.isOpened()) {
1385                 rsrc.abort();
1386             }
1387         }
1388     }
1389 
1390     /**
1391      * This is the getter method for instance variable {@link #roles}.
1392      *
1393      * @return the value of the instance variable {@link #roles}.
1394      * @see #roles
1395      */
1396     public Set<Long> getRoles()
1397     {
1398         return this.roles;
1399     }
1400 
1401     /**
1402      * This is the getter method for instance variable {@link #groups}.
1403      *
1404      * @return the value of the instance variable {@link #groups}.
1405      * @see #groups
1406      */
1407     public Set<Long> getGroups()
1408     {
1409         return this.groups;
1410     }
1411 
1412     /**
1413      * Getter method for instance variable {@link #companies}.
1414      *
1415      * @return value of instance variable {@link #companies}
1416      */
1417     public Set<Long> getCompanies()
1418     {
1419         return this.companies;
1420     }
1421 
1422     /**
1423      * Getter method for instance variable {@link #associations}.
1424      *
1425      * @return value of instance variable {@link #associations}
1426      */
1427     public Set<Long> getAssociations()
1428     {
1429         return this.associations;
1430     }
1431 
1432     /**
1433      * Returns a string representation of this person.
1434      *
1435      * @return string representation of this person
1436      */
1437     @Override
1438     public String toString()
1439     {
1440         return new ToStringBuilder(this)
1441                         .appendSuper(super.toString())
1442                         .append("attrValues", this.attrValues)
1443                         .append("roles", this.roles)
1444                         .append("groups", this.groups)
1445                         .append("companies", this.companies)
1446                         .append("associations", this.associations)
1447                         .toString();
1448     }
1449 
1450     @Override
1451     public boolean equals(final Object _obj)
1452     {
1453         boolean ret;
1454         if (_obj instanceof Person) {
1455             ret = ((Person) _obj).getId() == getId();
1456         } else {
1457             ret = super.equals(_obj);
1458         }
1459         return ret;
1460     }
1461 
1462     @Override
1463     public int hashCode()
1464     {
1465         return  Long.valueOf(getId()).intValue();
1466     }
1467 
1468     /**
1469      * Method to initialize the Cache of this CacheObjectInterface.
1470      */
1471     public static void initialize()
1472     {
1473         if (InfinispanCache.get().exists(Person.IDCACHE)) {
1474             InfinispanCache.get().<Long, Person>getCache(Person.IDCACHE).clear();
1475         } else {
1476             InfinispanCache.get().<Long, Person>getCache(Person.IDCACHE).addListener(new CacheLogListener(Person.LOG));
1477         }
1478         if (InfinispanCache.get().exists(Person.NAMECACHE)) {
1479             InfinispanCache.get().<String, Person>getCache(Person.NAMECACHE).clear();
1480         } else {
1481             InfinispanCache.get().<String, Person>getCache(Person.NAMECACHE)
1482                             .addListener(new CacheLogListener(Person.LOG));
1483         }
1484         if (InfinispanCache.get().exists(Person.UUIDCACHE)) {
1485             InfinispanCache.get().<UUID, Person>getCache(Person.UUIDCACHE).clear();
1486         } else {
1487             InfinispanCache.get().<UUID, Person>getCache(Person.UUIDCACHE)
1488                             .addListener(new CacheLogListener(Person.LOG));
1489         }
1490     }
1491 
1492     /**
1493      * Returns for given parameter <i>_id</i> the instance of class
1494      * {@link Person}.
1495      *
1496      * @param _id id to search in the cache
1497      * @throws EFapsException on error
1498      * @return instance of class {@link Person}
1499      * @see #CACHE
1500      * @see #getFromDB
1501      */
1502     public static Person get(final long _id)
1503         throws EFapsException
1504     {
1505         final Cache<Long, Person> cache = InfinispanCache.get().<Long, Person>getCache(Person.IDCACHE);
1506         if (!cache.containsKey(_id)) {
1507             Person.getPersonFromDB(Person.SQL_ID, _id);
1508         }
1509         return cache.get(_id);
1510     }
1511 
1512     /**
1513      * Returns for given parameter <i>_uuid</i> the instance of class
1514      * {@link Person}.
1515      *
1516      * @param _uuid UUID to search in the cache
1517      * @throws EFapsException on error
1518      * @return instance of class {@link Person}
1519      * @see #getFromDB
1520      */
1521     public static Person get(final UUID _uuid)
1522         throws EFapsException
1523     {
1524         final Cache<UUID, Person> cache = InfinispanCache.get().<UUID, Person>getCache(Person.UUIDCACHE);
1525         if (!cache.containsKey(_uuid)) {
1526             Person.getPersonFromDB(Person.SQL_UUID, _uuid.toString());
1527         }
1528         return cache.get(_uuid);
1529     }
1530 
1531     /**
1532      * Returns for given parameter <i>_name</i> the instance of class
1533      * {@link Person}.
1534      *
1535      * @param _name name to search in the cache
1536      * @throws EFapsException on error
1537      * @return instance of class {@link Person}
1538      * @see #CACHE
1539      * @see #getFromDB
1540      */
1541     public static Person get(final String _name)
1542         throws EFapsException
1543     {
1544         final Cache<String, Person> cache = InfinispanCache.get().<String, Person>getCache(Person.NAMECACHE);
1545         if (!cache.containsKey(_name)) {
1546             Person.getPersonFromDB(Person.SQL_NAME, _name);
1547         }
1548         return cache.get(_name);
1549     }
1550 
1551     /**
1552      * @param _person Person to be cached
1553      * @throws EFapsException on error
1554      */
1555     private static void cachePerson(final Person _person)
1556         throws EFapsException
1557     {
1558         final Cache<String, Person> nameCache = InfinispanCache.get().<String, Person>getIgnReCache(Person.NAMECACHE);
1559         nameCache.putIfAbsent(_person.getName(), _person);
1560 
1561         final Cache<Long, Person> idCache = InfinispanCache.get().<Long, Person>getIgnReCache(Person.IDCACHE);
1562         idCache.putIfAbsent(_person.getId(), _person);
1563 
1564         if (_person.getUUID() != null) {
1565             final Cache<UUID, Person> uuidCache = InfinispanCache.get().<UUID, Person>getIgnReCache(Person.UUIDCACHE);
1566             uuidCache.putIfAbsent(_person.getUUID(), _person);
1567         }
1568     }
1569 
1570 
1571     /**
1572      * @param _sql      SQL Statment to be execuetd
1573      * @param _criteria filter criteria
1574      * @return true if successful
1575      * @throws EFapsException on error
1576      */
1577     private static Person getPersonFromDB(final String _sql,
1578                                           final Object _criteria)
1579         throws EFapsException
1580     {
1581         Person ret = null;
1582         ConnectionResource con = null;
1583         try {
1584             con = Context.getThreadContext().getConnectionResource();
1585             PreparedStatement stmt = null;
1586             try {
1587                 stmt = con.getConnection().prepareStatement(_sql);
1588                 stmt.setObject(1, _criteria);
1589                 final ResultSet rs = stmt.executeQuery();
1590 
1591                 if (rs.next()) {
1592                     final long id = rs.getLong(1);
1593                     final String uuid = rs.getString(2);
1594                     final String name = rs.getString(3);
1595                     final boolean status = rs.getBoolean(4);
1596                     ret = new Person(id, uuid, name.trim(), status);
1597                     Person.cachePerson(ret);
1598                     Person.LOG.debug("read from DB Person:{} ", ret);
1599                 }
1600                 rs.close();
1601             } catch (final SQLException e) {
1602                 Person.LOG.error("search for person with SQL statement '" + _sql + "' is not possible", e);
1603                 throw new EFapsException(Person.class, "getFromDB.SQLException", e, _sql);
1604             } finally {
1605                 try {
1606                     if (stmt != null) {
1607                         stmt.close();
1608                     }
1609                 } catch (final SQLException e) {
1610                     Person.LOG.error("Catched error on closing statement", e);
1611                 }
1612                 if (con != null) {
1613                     con.commit();
1614                 }
1615             }
1616         } finally {
1617             if (con != null && con.isOpened()) {
1618                 con.abort();
1619             }
1620         }
1621         if (ret != null) {
1622             ret.readFromDB();
1623         }
1624         return ret;
1625     }
1626 
1627     /**
1628      * Returns for given parameter <i>_jaasKey</i> the instance of class
1629      * {@link Person}. The parameter <i>_jaasKey</i> is the name of the person
1630      * used in the given JAAS system for the person.
1631      *
1632      * @param _jaasSystem JAAS system for which the JAAS key is named
1633      * @param _jaasKey key in the foreign JAAS system for which the person is
1634      *            searched
1635      * @throws EFapsException on error
1636      * @return instance of class {@link Person}, or <code>null</code> if person
1637      *         is not found
1638      * @see #get(long)
1639      */
1640     public static Person getWithJAASKey(final JAASSystem _jaasSystem,
1641                                         final String _jaasKey)
1642         throws EFapsException
1643     {
1644         long personId = 0;
1645         ConnectionResource rsrc = null;
1646         try {
1647             rsrc = Context.getThreadContext().getConnectionResource();
1648             PreparedStatement stmt = null;
1649             try {
1650                 stmt = rsrc.getConnection().prepareStatement(Person.SQL_JAASKEY);
1651                 stmt.setObject(1, _jaasKey);
1652                 stmt.setObject(2, _jaasSystem.getId());
1653                 final ResultSet rs = stmt.executeQuery();
1654                 if (rs.next()) {
1655                     personId = rs.getLong(1);
1656                 }
1657                 rs.close();
1658             } catch (final SQLException e) {
1659                 Person.LOG.error("search for person for JAAS system '" + _jaasSystem.getName() + "' with key '"
1660                                 + _jaasKey + "' is not possible", e);
1661                 throw new EFapsException(Person.class, "getWithJAASKey.SQLException", e, _jaasSystem.getName(),
1662                                 _jaasKey);
1663             } finally {
1664                 try {
1665                     if (stmt != null) {
1666                         stmt.close();
1667                     }
1668                 } catch (final SQLException e) {
1669                     throw new EFapsException(Person.class, "getWithJAASKey.SQLException", e, _jaasSystem.getName(),
1670                                     _jaasKey);
1671                 }
1672             }
1673             rsrc.commit();
1674         } finally {
1675             if (rsrc != null && rsrc.isOpened()) {
1676                 rsrc.abort();
1677             }
1678         }
1679         return Person.get(personId);
1680     }
1681 
1682     /**
1683      * @param _jaasSystem JAAS system which want to create a new person in eFaps
1684      * @param _jaasKey key of the person in the JAAS system
1685      * @param _userName name in the eFaps system (used as proposal, it's tested
1686      *            for uniqueness and changed if needed!)
1687      * @return new created person
1688      * @throws EFapsException if person could not be created in eFaps
1689      * @see #assignToJAASSystem
1690      */
1691     public static Person createPerson(final JAASSystem _jaasSystem,
1692                                       final String _jaasKey,
1693                                       final String _userName)
1694         throws EFapsException
1695     {
1696         long persId = 0;
1697         final Type persType = CIAdminUser.Person.getType();
1698         ConnectionResource rsrc = null;
1699         try {
1700             final Context context = Context.getThreadContext();
1701 
1702             rsrc = context.getConnectionResource();
1703 
1704             PreparedStatement stmt = null;
1705             try {
1706                 StringBuilder cmd = new StringBuilder();
1707 
1708                 // TODO: check for uniqueness!
1709                 // TODO: hard coded mofifier and creator
1710                 if (Context.getDbType().supportsGetGeneratedKeys()) {
1711                     cmd.append("insert into ").append(persType.getMainTable().getSqlTable()).append(
1712                                     "(TYPEID,NAME,CREATOR,CREATED,MODIFIER,MODIFIED) ").append("values (");
1713                 } else {
1714                     persId = Context.getDbType().getNewId(rsrc.getConnection(), persType.getMainTable().getSqlTable(),
1715                                     "ID");
1716                     cmd.append("insert into ").append(persType.getMainTable().getSqlTable()).append(
1717                                     "(ID,TYPEID,NAME,CREATOR,CREATED,MODIFIER,MODIFIED) ").append("values (").append(
1718                                     persId).append(",");
1719                 }
1720                 cmd.append(persType.getId()).append(",").append("'").append(_userName).append("',").append(
1721                                 context.getPersonId()).append(",").append(Context.getDbType().getCurrentTimeStamp())
1722                                 .append(",").append(context.getPersonId()).append(",").append(
1723                                                 Context.getDbType().getCurrentTimeStamp()).append(")");
1724 
1725                 if (persId == 0) {
1726                     stmt = rsrc.getConnection().prepareStatement(cmd.toString(), new String[] { "ID" });
1727                 } else {
1728                     stmt = rsrc.getConnection().prepareStatement(cmd.toString());
1729                 }
1730 
1731                 int rows = stmt.executeUpdate();
1732                 if (rows == 0) {
1733                     Person.LOG.error("could not execute '" + cmd.toString() + "' for JAAS system '"
1734                                     + _jaasSystem.getName() + "' person with key '" + _jaasKey
1735                                     + "' and user name '" + _userName + "'");
1736                     throw new EFapsException(Person.class, "createPerson.NotInserted", cmd.toString(), _jaasSystem
1737                                     .getName(), _jaasKey, _userName);
1738                 }
1739                 if (persId == 0) {
1740                     final ResultSet resultset = stmt.getGeneratedKeys();
1741                     if (resultset.next()) {
1742                         persId = resultset.getLong(1);
1743                     }
1744                 }
1745 
1746                 stmt.close();
1747 
1748                 cmd = new StringBuilder();
1749                 cmd.append("insert into T_USERPERSON").append("(ID,FIRSTNAME,LASTNAME,EMAIL) ").append("values (")
1750                                 .append(persId).append(",'-','-','-')");
1751                 stmt = rsrc.getConnection().prepareStatement(cmd.toString());
1752                 rows = stmt.executeUpdate();
1753                 if (rows == 0) {
1754                     Person.LOG.error("could not execute '" + cmd.toString() + "' for JAAS system '"
1755                                     + _jaasSystem.getName()
1756                                     + "' person with key '" + _jaasKey + "' and user name '" + _userName + "'");
1757                     throw new EFapsException(Person.class, "createPerson.NotInserted", cmd.toString(), _jaasSystem
1758                                     .getName(), _jaasKey, _userName);
1759                 }
1760 
1761             } catch (final SQLException e) {
1762                 Person.LOG.error("could not create for JAAS system '" + _jaasSystem.getName() + "' person with key '"
1763                                 + _jaasKey + "' and user name '" + _userName + "'", e);
1764                 throw new EFapsException(Person.class, "createPerson.SQLException", e, _jaasSystem.getName(), _jaasKey,
1765                                 _userName);
1766             } finally {
1767                 try {
1768                     if (stmt != null) {
1769                         stmt.close();
1770                     }
1771                 } catch (final SQLException e) {
1772                     throw new EFapsException(Person.class, "createPerson.SQLException", e, _jaasSystem.getName(),
1773                                     _jaasKey);
1774                 }
1775             }
1776             rsrc.commit();
1777         } finally {
1778             if (rsrc != null && rsrc.isOpened()) {
1779                 rsrc.abort();
1780             }
1781         }
1782 
1783         final Person ret = Person.get(persId);
1784         ret.assignToJAASSystem(_jaasSystem, _jaasKey);
1785         return ret;
1786     }
1787 }