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.util.UUID;
27  import java.util.concurrent.TimeUnit;
28  
29  import org.efaps.ci.CIAdminUser;
30  import org.efaps.db.Context;
31  import org.efaps.db.transaction.ConnectionResource;
32  import org.efaps.db.wrapper.SQLPart;
33  import org.efaps.db.wrapper.SQLSelect;
34  import org.efaps.util.EFapsException;
35  import org.efaps.util.cache.CacheLogListener;
36  import org.efaps.util.cache.CacheReloadException;
37  import org.efaps.util.cache.InfinispanCache;
38  import org.infinispan.Cache;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  /**
43   * Class represents the instance of a role in eFaps.
44   *
45   * @author The eFaps Team
46   * @version $Id$
47   */
48  public final class Role
49      extends AbstractUserObject
50  {
51      /**
52       * Needed for serialization.
53       */
54      private static final long serialVersionUID = 1L;
55  
56      /**
57       * Logging instance used in this class.
58       */
59      private static final Logger LOG = LoggerFactory.getLogger(Role.class);
60  
61      /**
62       * This is the SQL select statement to select a role from the database by ID.
63       */
64      private static final String SQL_ID = new SQLSelect().column("ID")
65                      .column("UUID")
66                      .column("NAME")
67                      .column("STATUS")
68                      .column("TYPEID")
69                      .from("V_USERROLE", 0)
70                      .addPart(SQLPart.WHERE).addColumnPart(0, "ID").addPart(SQLPart.EQUAL).addValuePart("?").toString();
71  
72      /**
73       * This is the SQL select statement to select a role from the database by Name.
74       */
75      private static final String SQL_NAME = new SQLSelect().column("ID")
76                      .column("UUID")
77                      .column("NAME")
78                      .column("STATUS")
79                      .column("TYPEID")
80                      .from("V_USERROLE", 0)
81                      .addPart(SQLPart.WHERE).addColumnPart(0, "NAME").addPart(SQLPart.EQUAL).addValuePart("?")
82                      .toString();
83  
84      /**
85       * This is the SQL select statement to select a role from the database by UUID.
86       */
87      private static final String SQL_UUID = new SQLSelect().column("ID")
88                      .column("UUID")
89                      .column("NAME")
90                      .column("STATUS")
91                      .column("TYPEID")
92                      .from("V_USERROLE", 0)
93                      .addPart(SQLPart.WHERE).addColumnPart(0, "UUID").addPart(SQLPart.EQUAL).addValuePart("?")
94                      .toString();
95  
96      /**
97       * This is the SQL select statement to select a Role from the database using the JAAS key..
98       */
99      private static final String SQL_JAASKEY = new SQLSelect().column("ID")
100                     .from("V_USERROLEJASSKEY", 0)
101                     .addPart(SQLPart.WHERE).addColumnPart(0, "JAASKEY").addPart(SQLPart.EQUAL).addValuePart("?")
102                     .addPart(SQLPart.AND).addColumnPart(0, "JAASSYSID").addPart(SQLPart.EQUAL).addValuePart("?")
103                     .toString();
104 
105     /**
106      * Name of the Cache by UUID.
107      */
108     private static final String UUIDCACHE = Role.class.getName() + ".UUID";
109 
110     /**
111      * Name of the Cache by ID.
112      */
113     private static final String IDCACHE = Role.class.getName() + ".ID";
114 
115     /**
116      * Name of the Cache by Name.
117      */
118     private static final String NAMECACHE = Role.class.getName() + ".Name";
119 
120     /**
121      * Use to mark not found and return <code>null</code>.
122      */
123     private static final Role NULL = new Role(0, null, null, false, 0);
124 
125     /**
126      * Id of the DataModel type for this Role.
127      */
128     private final long typeId;
129 
130     /**
131      * Create a new role instance. The method is used from the static method
132      * {@link #initialize()} to read all roles from the database.
133      *
134      * @param _id       id of the role
135      * @param _uuid     uuid of the role
136      * @param _name     name of the role
137      * @param _status   status of the role
138      * @param _typeId   id of the type
139      */
140     private Role(final long _id,
141                  final String _uuid,
142                  final String _name,
143                  final boolean _status,
144                  final long _typeId)
145     {
146         super(_id, _uuid, _name, _status);
147         this.typeId = _typeId;
148     }
149 
150     /**
151      * Is this a Global Role.
152      *
153      * @return <code>true</code> if global role type, else <code>false</code>
154      */
155     public boolean isGlobal()
156     {
157         return CIAdminUser.RoleGlobal.getType() == null ? false
158                         : CIAdminUser.RoleGlobal.getType().getId() == this.typeId;
159     }
160 
161     /**
162      * Is this a Global Role.
163      *
164      * @return <code>true</code> if global role type, else <code>false</code>
165      */
166     public boolean isLocal()
167     {
168         return CIAdminUser.RoleLocal.getType() == null ? false
169                         : CIAdminUser.RoleLocal.getType().getId() == this.typeId;
170     }
171 
172     /**
173      * Checks, if the given person is assigned to this role.
174      *
175      * @param _person   person to test
176      * @return <i>true</i> if the person is assigned to this role, otherwise
177      *         <i>false</i>
178      * @see Person#isAssigned(Role)
179      */
180     @Override
181     public boolean hasChildPerson(final Person _person)
182     {
183         return _person.isAssigned(this);
184     }
185 
186     /**
187      * Method to initialize the Cache of this CacheObjectInterface.
188      */
189     public static void initialize()
190     {
191         if (InfinispanCache.get().exists(Role.UUIDCACHE)) {
192             InfinispanCache.get().<UUID, Role>getCache(Role.UUIDCACHE).clear();
193         } else {
194             InfinispanCache.get().<UUID, Role>getCache(Role.UUIDCACHE).addListener(new CacheLogListener(Role.LOG));
195         }
196         if (InfinispanCache.get().exists(Role.IDCACHE)) {
197             InfinispanCache.get().<Long, Role>getCache(Role.IDCACHE).clear();
198         } else {
199             InfinispanCache.get().<Long, Role>getCache(Role.IDCACHE).addListener(new CacheLogListener(Role.LOG));
200         }
201         if (InfinispanCache.get().exists(Role.NAMECACHE)) {
202             InfinispanCache.get().<String, Role>getCache(Role.NAMECACHE).clear();
203         } else {
204             InfinispanCache.get().<String, Role>getCache(Role.NAMECACHE).addListener(new CacheLogListener(Role.LOG));
205         }
206     }
207 
208     /**
209      * Returns for given parameter <i>_id</i> the instance of class
210      * {@link Role}.
211      *
212      * @param _id  id to search in the cache
213      * @return instance of class {@link Role}
214      * @throws CacheReloadException on error
215      * @see #CACHE
216      */
217     public static Role get(final long _id)
218         throws CacheReloadException
219     {
220         final Cache<Long, Role> cache = InfinispanCache.get().<Long, Role>getCache(Role.IDCACHE);
221         if (!cache.containsKey(_id) && !Role.getRoleFromDB(Role.SQL_ID, _id)) {
222             cache.put(_id, Role.NULL, 100, TimeUnit.SECONDS);
223         }
224         final Role ret = cache.get(_id);
225         return ret.equals(Role.NULL) ? null : ret;
226     }
227 
228     /**
229      * Returns for given parameter <i>_name</i> the instance of class
230      * {@link Role}.
231      *
232      * @param _name name to search in the cache
233      * @return instance of class {@link Role}
234      * @throws CacheReloadException on error
235      * @see #CACHE
236      */
237     public static Role get(final String _name)
238         throws CacheReloadException
239     {
240         final Cache<String, Role> cache = InfinispanCache.get().<String, Role>getCache(Role.NAMECACHE);
241         if (!cache.containsKey(_name) && !Role.getRoleFromDB(Role.SQL_NAME, _name)) {
242             cache.put(_name, Role.NULL, 100, TimeUnit.SECONDS);
243         }
244         final Role ret = cache.get(_name);
245         return ret.equals(Role.NULL) ? null : ret;
246     }
247 
248     /**
249      * Returns for given parameter <i>_uuid</i> the instance of class
250      * {@link Role}.
251      *
252      * @param _uuid UUI to search for
253      * @return instance of class {@link Role}
254      * @throws CacheReloadException on error
255      * @see #CACHE
256      */
257     public static Role get(final UUID _uuid)
258         throws CacheReloadException
259     {
260         final Cache<UUID, Role> cache = InfinispanCache.get().<UUID, Role>getCache(Role.UUIDCACHE);
261         if (!cache.containsKey(_uuid)) {
262             Role.getRoleFromDB(Role.SQL_UUID, String.valueOf(_uuid));
263         }
264         return cache.get(_uuid);
265     }
266 
267     /**
268      * @param _role Role to be cached
269      */
270     private static void cacheRole(final Role _role)
271     {
272         final Cache<UUID, Role> cache4UUID = InfinispanCache.get().<UUID, Role>getIgnReCache(Role.UUIDCACHE);
273         cache4UUID.putIfAbsent(_role.getUUID(), _role);
274 
275         final Cache<String, Role> nameCache = InfinispanCache.get().<String, Role>getIgnReCache(Role.NAMECACHE);
276         nameCache.putIfAbsent(_role.getName(), _role);
277 
278         final Cache<Long, Role> idCache = InfinispanCache.get().<Long, Role>getIgnReCache(Role.IDCACHE);
279         idCache.putIfAbsent(_role.getId(), _role);
280     }
281 
282     /**
283      * @param _sql      SQL Statment to be execuetd
284      * @param _criteria filter criteria
285      * @return true if successful
286      * @throws CacheReloadException on error
287      */
288     private static boolean getRoleFromDB(final String _sql,
289                                          final Object _criteria)
290         throws CacheReloadException
291     {
292         boolean ret = false;
293         ConnectionResource con = null;
294         try {
295             con = Context.getThreadContext().getConnectionResource();
296             PreparedStatement stmt = null;
297             try {
298                 stmt = con.getConnection().prepareStatement(_sql);
299                 stmt.setObject(1, _criteria);
300                 final ResultSet rs = stmt.executeQuery();
301 
302                 if (rs.next()) {
303                     final long id = rs.getLong(1);
304                     final String uuid = rs.getString(2);
305                     final String name = rs.getString(3).trim();
306                     final boolean status = rs.getBoolean(4);
307                     final long typeId = rs.getLong(5);
308 
309                     Role.LOG.debug("read role '{}' (id = {}, type = {})", name, id, typeId);
310                     final Role role = new Role(id, uuid, name, status, typeId);
311                     Role.cacheRole(role);
312                     ret = true;
313                 }
314                 rs.close();
315             } finally {
316                 if (stmt != null) {
317                     stmt.close();
318                 }
319             }
320             con.commit();
321         } catch (final SQLException e) {
322             throw new CacheReloadException("could not read roles", e);
323         } catch (final EFapsException e) {
324             throw new CacheReloadException("could not read roles", e);
325         } finally {
326             if ((con != null) && con.isOpened()) {
327                 try {
328                     con.abort();
329                 } catch (final EFapsException e) {
330                     throw new CacheReloadException("could not read roles", e);
331                 }
332             }
333         }
334         return ret;
335     }
336 
337     /**
338      * Returns for given parameter <code>_jaasKey</code> the instance of class
339      * {@link Role}. The parameter <code>_jaasKey</code> is the name of the
340      * role used in the given JAAS system for the role.
341      *
342      * @param _jaasSystem   JAAS system for which the JAAS key is named
343      * @param _jaasKey      key in the foreign JAAS system for which the role is
344      *                      searched
345      * @throws EFapsException on error
346      * @return instance of class {@link Role}, or <code>null</code> if role is
347      *         not found
348      * @see #get(long)
349      */
350     public static Role getWithJAASKey(final JAASSystem _jaasSystem,
351                                       final String _jaasKey)
352         throws EFapsException
353     {
354         long roleId = 0;
355         ConnectionResource rsrc = null;
356         try {
357             rsrc = Context.getThreadContext().getConnectionResource();
358 
359             PreparedStatement stmt = null;
360             try {
361                 stmt = rsrc.getConnection().prepareStatement(Role.SQL_JAASKEY);
362                 stmt.setObject(1, _jaasKey);
363                 stmt.setObject(2, _jaasSystem.getId());
364                 final ResultSet rs = stmt.executeQuery();
365                 if (rs.next()) {
366                     roleId = rs.getLong(1);
367                 }
368                 rs.close();
369             } catch (final SQLException e) {
370                 Role.LOG.warn("search for role for JAAS system '" + _jaasSystem.getName()
371                         + "' with key '" + _jaasKey + "' is not possible", e);
372                 throw new EFapsException(Role.class, "getWithJAASKey.SQLException", e,
373                         _jaasSystem.getName(), _jaasKey);
374             } finally {
375                 try {
376                     stmt.close();
377                 } catch (final SQLException e) {
378                     Role.LOG.warn("Catched SQLException in class " + Role.class);
379                 }
380             }
381             rsrc.commit();
382         } finally {
383             if ((rsrc != null) && rsrc.isOpened()) {
384                 rsrc.abort();
385             }
386         }
387         return Role.get(roleId);
388     }
389 
390     @Override
391     public boolean equals(final Object _obj)
392     {
393         boolean ret;
394         if (_obj instanceof Role) {
395             ret = ((Role) _obj).getId() == getId();
396         } else {
397             ret = super.equals(_obj);
398         }
399         return ret;
400     }
401 
402     @Override
403     public int hashCode()
404     {
405         return  Long.valueOf(getId()).intValue();
406     }
407 }