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  
22  package org.efaps.admin.user;
23  
24  import java.sql.PreparedStatement;
25  import java.sql.ResultSet;
26  import java.sql.SQLException;
27  import java.util.concurrent.TimeUnit;
28  
29  import org.efaps.db.Context;
30  import org.efaps.db.transaction.ConnectionResource;
31  import org.efaps.db.wrapper.SQLPart;
32  import org.efaps.db.wrapper.SQLSelect;
33  import org.efaps.util.EFapsException;
34  import org.efaps.util.cache.CacheLogListener;
35  import org.efaps.util.cache.CacheReloadException;
36  import org.efaps.util.cache.InfinispanCache;
37  import org.infinispan.Cache;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  
42  /**
43   * A relation mapping between a Group and a Role providing a 2 dimensional
44   * access and right definition. e.g.<br/>
45   * A Person has the right of Sales_Admin (Role) in a Department (Group)
46   *
47   * @author The eFaps Team
48   * @version $Id$
49   */
50  public class Association
51  {
52      /**
53       * Logging instance used in this class.
54       */
55      private static final Logger LOG = LoggerFactory.getLogger(Association.class);
56  
57      /**
58       * This is the SQL select statement to select a role from the database by ID.
59       */
60      private static final String SQL_ID = new SQLSelect().column("ID")
61                      .column("ROLEID")
62                      .column("GROUPID")
63                      .from("T_USERASSOC", 0)
64                      .addPart(SQLPart.WHERE).addColumnPart(0, "ID").addPart(SQLPart.EQUAL).addValuePart("?").toString();
65  
66      /**
67       * Name of the Cache by ID.
68       */
69      private static final String IDCACHE = Association.class.getName() + ".ID";
70  
71      /**
72       * Use to mark not found and return <code>null</code>.
73       */
74      private static final Association NULL = new Association(0, 0, 0);
75  
76      /**
77       * Id of this Association.
78       */
79      private final long id;
80  
81      /**
82       * The id of the Role.
83       */
84      private final long roleId;
85  
86      /**
87       * The id of the group.
88       */
89      private final long groupId;
90  
91      /**
92       * @param _id       id of this Association
93       * @param _roleId   related role
94       * @param _groupId  related group
95       */
96      public Association(final long _id,
97                         final long _roleId,
98                         final long _groupId)
99      {
100         this.id = _id;
101         this.roleId = _roleId;
102         this.groupId = _groupId;
103     }
104 
105     /**
106      * Getter method for the instance variable {@link #id}.
107      *
108      * @return value of instance variable {@link #id}
109      */
110     protected long getId()
111     {
112         return this.id;
113     }
114 
115     /**
116      * Get the Role.
117      * @return Role for this Association.
118      * @throws CacheReloadException on error
119      */
120     public Role getRole()
121         throws CacheReloadException
122     {
123         return Role.get(this.roleId);
124     }
125 
126     /**
127      * Get the Group.
128      * @return Group for this Association.
129      * @throws CacheReloadException on error
130      */
131     public Group getGroup()
132         throws CacheReloadException
133     {
134         return Group.get(this.groupId);
135     }
136 
137     /**
138      * Method to initialize the Cache of this CacheObjectInterface.
139      */
140     public static void initialize()
141     {
142         if (InfinispanCache.get().exists(Association.IDCACHE)) {
143             InfinispanCache.get().<Long, Association>getCache(Association.IDCACHE).clear();
144         } else {
145             InfinispanCache.get().<Long, Association>getCache(Association.IDCACHE)
146                             .addListener(new CacheLogListener(Association.LOG));
147         }
148     }
149 
150     /**
151      * Returns for given parameter <i>_id</i> the instance of class
152      * {@link Association}.
153      *
154      * @param _id  id to search in the cache
155      * @return instance of class {@link Association}
156      * @throws CacheReloadException on error
157      */
158     public static Association get(final long _id)
159         throws CacheReloadException
160     {
161         final Cache<Long, Association> cache = InfinispanCache.get().<Long, Association>getCache(Association.IDCACHE);
162         if (!cache.containsKey(_id) && !Association.getAssociationFromDB(Association.SQL_ID, _id)) {
163             cache.put(_id, Association.NULL, 100, TimeUnit.SECONDS);
164         }
165         final Association ret = cache.get(_id);
166         return ret.equals(Association.NULL) ? null : ret;
167     }
168 
169     /**
170      * @param _association Association to be cached
171      */
172     private static void cacheAssociation(final Association _association)
173     {
174         final Cache<Long, Association> idCache = InfinispanCache.get().<Long, Association>getIgnReCache(
175                         Association.IDCACHE);
176         idCache.putIfAbsent(_association.getId(), _association);
177 
178     }
179 
180     /**
181      * @param _sql      SQL Statment to be execuetd
182      * @param _criteria filter criteria
183      * @return true if successful
184      * @throws CacheReloadException on error
185      */
186     private static boolean getAssociationFromDB(final String _sql,
187                                                 final Object _criteria) throws CacheReloadException
188     {
189         boolean ret = false;
190         ConnectionResource con = null;
191         try {
192             con = Context.getThreadContext().getConnectionResource();
193             PreparedStatement stmt = null;
194             try {
195                 stmt = con.getConnection().prepareStatement(_sql);
196                 stmt.setObject(1, _criteria);
197                 final ResultSet rs = stmt.executeQuery();
198 
199                 if (rs.next()) {
200                     final long id = rs.getLong(1);
201                     final long roleId = rs.getLong(2);
202                     final long groupId = rs.getLong(3);
203 
204                     Association.LOG.debug("read association id: {}, roleId: {}, groupId: {}", id, roleId, groupId);
205                     final Association association = new Association(id, roleId, groupId);
206                     Association.cacheAssociation(association);
207                     ret = true;
208                 }
209                 rs.close();
210             } finally {
211                 if (stmt != null) {
212                     stmt.close();
213                 }
214             }
215             con.commit();
216         } catch (final SQLException e) {
217             throw new CacheReloadException("could not read Association", e);
218         } catch (final EFapsException e) {
219             throw new CacheReloadException("could not read Association", e);
220         } finally {
221             if ((con != null) && con.isOpened()) {
222                 try {
223                     con.abort();
224                 } catch (final EFapsException e) {
225                     throw new CacheReloadException("could not read Association", e);
226                 }
227             }
228         }
229         return ret;
230     }
231 
232     /* (non-Javadoc)
233      * @see java.lang.Object#equals(java.lang.Object)
234      */
235     @Override
236     public boolean equals(final Object _obj)
237     {
238         boolean ret;
239         if (_obj instanceof Association) {
240             ret = ((Association) _obj).id == this.id;
241         } else {
242             ret = super.equals(_obj);
243         }
244         return ret;
245     }
246 
247     /* (non-Javadoc)
248      * @see java.lang.Object#hashCode()
249      */
250     @Override
251     public int hashCode()
252     {
253         return Long.valueOf(this.id).intValue();
254     }
255 }