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.lang.reflect.Method;
24  import java.security.Principal;
25  import java.sql.PreparedStatement;
26  import java.sql.ResultSet;
27  import java.sql.SQLException;
28  import java.util.HashMap;
29  import java.util.HashSet;
30  import java.util.Map;
31  import java.util.Set;
32  
33  import org.efaps.admin.AbstractAdminObject;
34  import org.efaps.db.Context;
35  import org.efaps.db.transaction.ConnectionResource;
36  import org.efaps.db.wrapper.SQLPart;
37  import org.efaps.db.wrapper.SQLSelect;
38  import org.efaps.util.EFapsException;
39  import org.efaps.util.cache.CacheLogListener;
40  import org.efaps.util.cache.CacheReloadException;
41  import org.efaps.util.cache.InfinispanCache;
42  import org.infinispan.Cache;
43  import org.slf4j.Logger;
44  import org.slf4j.LoggerFactory;
45  
46  /**
47   * The class handles the caching for JAAS systems.
48   *
49   * @author The eFaps Team
50   * @version $Id$
51   */
52  public final class JAASSystem
53      extends AbstractAdminObject
54  {
55      /**
56       * Needed for serialization.
57       */
58      private static final long serialVersionUID = 1L;
59  
60      /**
61       * Logging instance used in this class.
62       */
63      private static final Logger LOG = LoggerFactory.getLogger(JAASSystem.class);
64  
65      /**
66       * This is the SQL select statement to select all JAAS systems from the
67       * database.
68       */
69      private static final String SQL_SELECT = new SQLSelect()
70                      .column("ID")
71                      .column("NAME")
72                      .column("CLASSNAMEPERSON")
73                      .column("METHODPERSONKEY")
74                      .column("METHODPERSONNAME")
75                      .column("METHODPERSONFIRSTNAME")
76                      .column("METHODPERSONLASTNAME")
77                      .column("METHODPERSONEMAIL")
78                      .column("CLASSNAMEROLE")
79                      .column("METHODROLEKEY")
80                      .column("CLASSNAMEGROUP")
81                      .column("METHODGROUPKEY")
82                      .from("V_USERJAASSYSTEM").toString();
83  
84      /**
85       * This is the SQL select statement to select a JAASSystem from the database
86       * by ID.
87       */
88      private static final String SQL_ID = new SQLSelect()
89                      .column("ID")
90                      .column("NAME")
91                      .column("CLASSNAMEPERSON")
92                      .column("METHODPERSONKEY")
93                      .column("METHODPERSONNAME")
94                      .column("METHODPERSONFIRSTNAME")
95                      .column("METHODPERSONLASTNAME")
96                      .column("METHODPERSONEMAIL")
97                      .column("CLASSNAMEROLE")
98                      .column("METHODROLEKEY")
99                      .column("CLASSNAMEGROUP")
100                     .column("METHODGROUPKEY")
101                     .from("V_USERJAASSYSTEM", 0)
102                     .addPart(SQLPart.WHERE).addColumnPart(0, "ID").addPart(SQLPart.EQUAL).addValuePart("?").toString();
103 
104   /**
105      * This is the SQL select statement to select a JAASSystem from the database
106      * by Name.
107      */
108     private static final String SQL_NAME = new SQLSelect()
109                     .column("ID")
110                     .column("NAME")
111                     .column("CLASSNAMEPERSON")
112                     .column("METHODPERSONKEY")
113                     .column("METHODPERSONNAME")
114                     .column("METHODPERSONFIRSTNAME")
115                     .column("METHODPERSONLASTNAME")
116                     .column("METHODPERSONEMAIL")
117                     .column("CLASSNAMEROLE")
118                     .column("METHODROLEKEY")
119                     .column("CLASSNAMEGROUP")
120                     .column("METHODGROUPKEY")
121                     .from("V_USERJAASSYSTEM", 0)
122                     .addPart(SQLPart.WHERE).addColumnPart(0, "NAME").addPart(SQLPart.EQUAL).addValuePart("?")
123                     .toString();
124 
125     /**
126      * Name of the Cache by ID.
127      */
128     private static String IDCACHE = JAASSystem.class.getName() + ".ID";
129 
130     /**
131      * Name of the Cache by Name.
132      */
133     private static String NAMECACHE = JAASSystem.class.getName() + ".Name";
134 
135     /**
136      * The class used as principle for persons for this JAAS system is stored
137      * in this instance variable.
138      *
139      * @see #getPersonJAASPrincipleClass
140      */
141     private Class<Principal> personJAASPrincipleClass;
142 
143     /**
144      * @see #getPersonMethodKey()
145      */
146     private Method personMethodKey;
147 
148     /**
149      * @see #getPersonMethodName()
150      */
151     private Method personMethodName;
152 
153     /**
154      * Map between person attributes the the method of the JAAS.
155      */
156     private final Map<Person.AttrName, Method> personMethodAttributes
157         = new HashMap<Person.AttrName, Method>();
158 
159     /**
160      * The class used as principle for roles for this JAAS system is stored in
161      * this instance variable.
162      *
163      * @see #getRoleJAASPrincipleClass()
164      */
165     private Class<Principal> roleJAASPrincipleClass;
166 
167     /**
168      * @see #getRoleMethodKey()
169      */
170     private Method roleMethodKey;
171 
172     /**
173      * The class used as principle for groups for this JAAS system is stored in
174      * this instance variable.
175      *
176      * @see #getGroupJAASPrincipleClass
177      */
178     private Class<Principal> groupJAASPrincipleClass;
179 
180     /**
181      * @see #getGroupMethodKey()
182      */
183     private Method groupMethodKey;
184 
185     /**
186      * Constructor to set the id and name of the user object.
187      *
188      * @param _id       id to set
189      * @param _name     name to set
190      */
191     private JAASSystem(final long _id,
192                        final String _name)
193     {
194         super(_id, null, _name);
195     }
196 
197     /**
198      * This is the getter method for instance variable
199      * {@link #personJAASPrincipleClass}.
200      *
201      * @return the value of the instance variable
202      *         {@link #personJAASPrincipleClass}.
203      * @see #personJAASPrincipleClass
204      */
205     public Class<Principal> getPersonJAASPrincipleClass()
206     {
207         return this.personJAASPrincipleClass;
208     }
209 
210     /**
211      * This is the getter method for instance variable {@link #personMethodKey}.
212      *
213      * @return the value of the instance variable {@link #personMethodKey}.
214      * @see #personMethodKey
215      */
216     public Method getPersonMethodKey()
217     {
218         return this.personMethodKey;
219     }
220 
221     /**
222      * This is the getter method for instance variable
223      * {@link #personMethodName}.
224      *
225      * @return the value of the instance variable {@link #personMethodName}
226      * @see #personMethodName
227      */
228     public Method getPersonMethodName()
229     {
230         return this.personMethodName;
231     }
232 
233     /**
234      * This is the getter method for instance variable
235      * {@link #personMethodAttributes}.
236      *
237      * @return the value of the instance variable
238      *         {@link #personMethodAttributes}
239      * @see #personMethodAttributes
240      */
241     public Map<Person.AttrName, Method> getPersonMethodAttributes()
242     {
243         return this.personMethodAttributes;
244     }
245 
246     /**
247      * This is the getter method for instance variable
248      * {@link #roleJAASPrincipleClass}.
249      *
250      * @return the value of the instance variable {@link #roleJAASPrincipleClass}.
251      * @see #roleJAASPrincipleClass
252      */
253     public Class<Principal> getRoleJAASPrincipleClass()
254     {
255         return this.roleJAASPrincipleClass;
256     }
257 
258     /**
259      * This is the getter method for instance variable {@link #roleMethodKey}.
260      *
261      * @return the value of the instance variable {@link #roleMethodKey}
262      * @see #roleMethodKey
263      */
264     public Method getRoleMethodKey()
265     {
266         return this.roleMethodKey;
267     }
268 
269     /**
270      * This is the getter method for instance variable
271      * {@link #groupJAASPrincipleClass}.
272      *
273      * @return the value of the instance variable
274      *         {@link #groupJAASPrincipleClass}
275      * @see #groupJAASPrincipleClass
276      */
277     public Class<Principal> getGroupJAASPrincipleClass()
278     {
279         return this.groupJAASPrincipleClass;
280     }
281 
282     /**
283      * This is the getter method for instance variable {@link #groupMethodKey}.
284      *
285      * @return the value of the instance variable {@link #groupMethodKey}
286      * @see #groupMethodKey
287      */
288     public Method getGroupMethodKey()
289     {
290         return this.groupMethodKey;
291     }
292 
293     /**
294      * Method to initialize the cache of JAAS systems.
295      * @throws CacheReloadException on error
296      */
297     public static void initialize()
298         throws CacheReloadException
299     {
300         if (InfinispanCache.get().exists(JAASSystem.IDCACHE)) {
301             InfinispanCache.get().<Long, JAASSystem>getCache(JAASSystem.IDCACHE).clear();
302         } else {
303             InfinispanCache.get().<Long, JAASSystem>getCache(JAASSystem.IDCACHE)
304                             .addListener(new CacheLogListener(JAASSystem.LOG));
305         }
306         if (InfinispanCache.get().exists(JAASSystem.NAMECACHE)) {
307             InfinispanCache.get().<String, JAASSystem>getCache(JAASSystem.NAMECACHE).clear();
308         } else {
309             InfinispanCache.get().<String, JAASSystem>getCache(JAASSystem.NAMECACHE)
310                             .addListener(new CacheLogListener(JAASSystem.LOG));
311         }
312         JAASSystem.getJAASSystemFromDB(JAASSystem.SQL_SELECT, null);
313     }
314 
315     /**
316      * Returns for given parameter <i>_id</i> the instance of class
317      * {@link JAASSystem}.
318      *
319      * @param _id       id to search in the cache
320      * @return instance of class {@link JAASSystem}
321      * @throws CacheReloadException on error
322      */
323     public static JAASSystem getJAASSystem(final long _id)
324         throws CacheReloadException
325     {
326         final Cache<Long, JAASSystem> cache = InfinispanCache.get().<Long, JAASSystem>getCache(JAASSystem.IDCACHE);
327         if (!cache.containsKey(_id)) {
328             JAASSystem.getJAASSystemFromDB(JAASSystem.SQL_ID, _id);
329         }
330         return cache.get(_id);
331     }
332 
333     /**
334      * Returns for given parameter <i>_name</i> the instance of class
335      * {@link JAASSystem}.
336      *
337      * @param _name name to search in the cache
338      * @return instance of class {@link JAASSystem}
339      * @throws CacheReloadException on error
340      */
341     public static JAASSystem getJAASSystem(final String _name)
342         throws CacheReloadException
343     {
344         final Cache<String, JAASSystem> cache = InfinispanCache.get()
345                         .<String, JAASSystem>getCache(JAASSystem.NAMECACHE);
346         if (!cache.containsKey(_name)) {
347             JAASSystem.getJAASSystemFromDB(JAASSystem.SQL_NAME, _name);
348         }
349         return cache.get(_name);
350     }
351 
352     /**
353      * Returns all cached JAAS system in a set.
354      *
355      * @return set of all loaded and cached JAAS systems
356      */
357     public static Set<JAASSystem> getAllJAASSystems()
358     {
359         final Set<JAASSystem> ret = new HashSet<JAASSystem>();
360         final Cache<Long, JAASSystem> cache = InfinispanCache.get().<Long, JAASSystem>getCache(JAASSystem.IDCACHE);
361         for (final Map.Entry<Long, JAASSystem> entry : cache.entrySet()) {
362             ret.add(entry.getValue());
363         }
364         return ret;
365     }
366 
367     /**
368      * Returns for the given method name the method found in the given class.
369      * The found method is tested, if the method is returning string and has no
370      * parameters.<br/>
371      * If the checks fails or the method is not found, an error log is written
372      * and <code>null</code> is returned.
373      *
374      * @param _class        class on which the method is searched
375      * @param _method       method name
376      * @param _type         text string for which the method is searched
377      * @param _jaasName     name of the JAAS system
378      * @param _jaasId       id of the JAAS system
379      * @return found method, or <code>null</code> if no method found
380      * @see #initialize()
381      */
382     private static Method getMethod(final Class<?> _class,
383                                     final String _method,
384                                     final String _type,
385                                     final String _jaasName,
386                                     final long _jaasId)
387     {
388         Method ret = null;
389 
390         if ((_method != null) && (_method.trim().length() > 0)) {
391             try {
392                 ret = _class.getMethod(_method.trim(), new Class[] {});
393             } catch (final NoSuchMethodException e) {
394                 JAASSystem.LOG.error("could not get a " + _type
395                     + " method for JAAS System '" + _jaasName + "' (id = " + _jaasId + ")", e);
396             } catch (final SecurityException e) {
397                 JAASSystem.LOG.error("could not get a " + _type
398                     + " method for JAAS System '" + _jaasName + "' (id = " + _jaasId + ")", e);
399             }
400             if (!ret.getReturnType().equals(String.class)) {
401                 JAASSystem.LOG.error("could not get a " + _type
402                     + " method returning java.lang.String for JAAS System '" + _jaasName + "' (id = " + _jaasId + ")");
403                 ret = null;
404             } else if ((ret.getParameterTypes() != null) && (ret.getParameterTypes().length > 0)) {
405                 JAASSystem.LOG.error("could not get a " + _type
406                     + " method returning java.lang.String for JAAS System '" + _jaasName + "' (id = " + _jaasId + ")");
407                 ret = null;
408             }
409         }
410         return ret;
411     }
412 
413     /**
414      * @param _group Group to be cached
415      */
416     private static void cacheJAASSystem(final JAASSystem _group)
417     {
418         final Cache<String, JAASSystem> nameCache = InfinispanCache.get().<String, JAASSystem>getIgnReCache(
419                         JAASSystem.NAMECACHE);
420         nameCache.putIfAbsent(_group.getName(), _group);
421 
422         final Cache<Long, JAASSystem> idCache = InfinispanCache.get().<Long, JAASSystem>getIgnReCache(
423                         JAASSystem.IDCACHE);
424         idCache.putIfAbsent(_group.getId(), _group);
425     }
426 
427     /**
428      * @param _sql      SQL Statment to be execuetd
429      * @param _criteria filter criteria
430      * @throws CacheReloadException on error
431      */
432     private static void getJAASSystemFromDB(final String _sql,
433                                             final Object _criteria)
434         throws CacheReloadException
435     {
436         ConnectionResource con = null;
437         try {
438             con = Context.getThreadContext().getConnectionResource();
439 
440             PreparedStatement stmt = null;
441             try {
442                 stmt = con.getConnection().prepareStatement(_sql);
443                 if (!_sql.equals(JAASSystem.SQL_SELECT)) {
444                     stmt.setObject(1, _criteria);
445                 }
446                 final ResultSet rs = stmt.executeQuery();
447 
448                 while (rs.next()) {
449                     final long id = rs.getLong(1);
450                     final String name = rs.getString(2).trim();
451                     final String personClassName = rs.getString(3);
452                     final String personMethodKey = rs.getString(4);
453                     final String personMethodName = rs.getString(5);
454                     final String personMethodFirstName = rs.getString(6);
455                     final String personMethodLastName = rs.getString(7);
456                     final String personMethodEmail = rs.getString(8);
457                     final String roleClassName = rs.getString(9);
458                     final String roleMethodKey = rs.getString(10);
459                     final String groupClassName = rs.getString(11);
460                     final String groupMethodKey = rs.getString(12);
461 
462                     JAASSystem.LOG.debug("read JAAS System '{}' (id = {})", name, id);
463 
464                     try {
465                         final JAASSystem system = new JAASSystem(id, name);
466                         @SuppressWarnings("unchecked")
467                         final Class<Principal> forName = (Class<Principal>) Class.forName(personClassName.trim());
468                         system.personJAASPrincipleClass = forName;
469                         system.personMethodKey = JAASSystem.getMethod(system.personJAASPrincipleClass,
470                                         personMethodKey,
471                                         "person key", name, id);
472                         system.personMethodName = JAASSystem.getMethod(system.personJAASPrincipleClass,
473                                         personMethodName,
474                                         "person name", name, id);
475                         Method method = JAASSystem.getMethod(system.personJAASPrincipleClass,
476                                         personMethodFirstName,
477                                         "person first name", name, id);
478                         if (method != null) {
479                             system.personMethodAttributes.put(Person.AttrName.FIRSTNAME,
480                                             method);
481                         }
482                         method = JAASSystem.getMethod(system.personJAASPrincipleClass,
483                                         personMethodLastName,
484                                         "person last name", name, id);
485                         if (method != null) {
486                             system.personMethodAttributes.put(Person.AttrName.LASTNAME,
487                                             method);
488                         }
489                         method = JAASSystem.getMethod(system.personJAASPrincipleClass,
490                                         personMethodEmail,
491                                         "person email", name, id);
492                         if (method != null) {
493                             JAASSystem.LOG.debug("method '{}' not implemented yet.", method);
494                             // TODO: person email method
495                         }
496                         if ((roleClassName != null) && (roleClassName.trim().length() > 0)) {
497                             @SuppressWarnings("unchecked")
498                             final Class<Principal> fn = (Class<Principal>) Class.forName(roleClassName.trim());
499                             system.roleJAASPrincipleClass = fn;
500                             system.roleMethodKey = JAASSystem.getMethod(system.roleJAASPrincipleClass,
501                                             roleMethodKey,
502                                             "role key", name, id);
503                         }
504                         if ((groupClassName != null) && (groupClassName.trim().length() > 0)) {
505                             @SuppressWarnings("unchecked")
506                             final Class<Principal> fn = (Class<Principal>) Class.forName(groupClassName.trim());
507                             system.groupJAASPrincipleClass = fn;
508                             system.groupMethodKey = JAASSystem.getMethod(system.groupJAASPrincipleClass,
509                                             groupMethodKey,
510                                             "group key", name, id);
511                         }
512                         JAASSystem.cacheJAASSystem(system);
513                     } catch (final ClassNotFoundException e) {
514                         JAASSystem.LOG.error("read JAAS System '{}' (id = {})", name, id, e);
515                     }
516                 }
517                 rs.close();
518             } finally {
519                 if (stmt != null) {
520                     stmt.close();
521                 }
522             }
523             con.commit();
524         } catch (final SQLException e) {
525             throw new CacheReloadException("could not read roles", e);
526         } catch (final EFapsException e) {
527             throw new CacheReloadException("could not read roles", e);
528         } finally {
529             if ((con != null) && con.isOpened()) {
530                 try {
531                     con.abort();
532                 } catch (final EFapsException e) {
533                     throw new CacheReloadException("could not read roles", e);
534                 }
535             }
536         }
537     }
538 
539     @Override
540     public boolean equals(final Object _obj)
541     {
542         boolean ret;
543         if (_obj instanceof JAASSystem) {
544             ret = ((JAASSystem) _obj).getId() == getId();
545         } else {
546             ret = super.equals(_obj);
547         }
548         return ret;
549     }
550 
551     @Override
552     public int hashCode()
553     {
554         return  Long.valueOf(getId()).intValue();
555     }
556 }