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.datamodel;
22  
23  import java.sql.PreparedStatement;
24  import java.sql.ResultSet;
25  import java.sql.SQLException;
26  
27  import org.apache.commons.lang3.builder.ToStringBuilder;
28  import org.efaps.admin.datamodel.ui.IUIProvider;
29  import org.efaps.admin.datamodel.ui.UIInterface;
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   * @author The eFaps Team
44   * @version $Id$
45   *          TODO: description
46   */
47  public class AttributeType
48      extends AbstractDataModelObject
49  {
50      /**
51       * Needed for serialization.
52       */
53      private static final long serialVersionUID = 1L;
54  
55      /**
56       * Logging instance used in this class.
57       */
58      private static final Logger LOG = LoggerFactory.getLogger(AttributeType.class);
59  
60      /**
61       * This is the SQL select statement to select a role from the database by
62       * ID.
63       */
64      private static final String SQL_ID = new SQLSelect()
65                      .column("ID")
66                      .column("NAME")
67                      .column("UUID")
68                      .column("CLASSNAME")
69                      .column("CLASSNAMEUI")
70                      .column("ALWAYSUPDATE")
71                      .column("CREATEUPDATE")
72                      .from("V_DMATTRIBUTETYPE", 0)
73                      .addPart(SQLPart.WHERE).addColumnPart(0, "ID").addPart(SQLPart.EQUAL).addValuePart("?").toString();
74  
75      /**
76       * This is the SQL select statement to select a role from the database by
77       * Name.
78       */
79      private static final String SQL_NAME = new SQLSelect()
80                      .column("ID")
81                      .column("NAME")
82                      .column("UUID")
83                      .column("CLASSNAME")
84                      .column("CLASSNAMEUI")
85                      .column("ALWAYSUPDATE")
86                      .column("CREATEUPDATE")
87                      .from("V_DMATTRIBUTETYPE", 0)
88                      .addPart(SQLPart.WHERE).addColumnPart(0, "NAME").addPart(SQLPart.EQUAL).addValuePart("?")
89                      .toString();
90  
91      /**
92       * Name of the Cache by ID.
93       */
94      private static final String IDCACHE = AttributeType.class.getName() + ".ID";
95  
96      /**
97       * Name of the Cache by Name.
98       */
99      private static final String NAMECACHE = AttributeType.class.getName() + ".Name";
100 
101     /**
102      * The instance variable store the class representation for the attribute
103      * type. With the class representation, a new instance of the value can be
104      * created.
105      *
106      * @see #getClassRepr()
107      * @see #setClassRepr(String)
108      */
109     private IAttributeType dbAttrType;
110 
111     /**
112      * The instance variable stores the instance for the user interface.
113      */
114     private IUIProvider uiAttrType;
115 
116     /**
117      * The instance variable store the behavior, if an update is made. If the
118      * value is set to <i>true</i>, the attribute must be always updated.
119      *
120      * @see #isAlwaysUpdate()
121      */
122     private boolean alwaysUpdate = false;
123 
124     /**
125      * The instance variable store the behavior, if an insert is made. If the
126      * value is set to <i>true</i>, the attribute must be updated for an insert.
127      *
128      * @see #isCreateUpdate()
129      */
130     private boolean createUpdate = false;
131 
132     /**
133      * The instance for the user interface provider.
134      */
135     private IUIProvider uiProvider;
136 
137     /**
138      * This is the constructor for class {@link Attribute}. Every instance of
139      * class {@link Attribute} must have a name (parameter <i>_name</i>) and an
140      * identifier (parameter <i>_id</i>).
141      *
142      * @param _id id of the attribute
143      * @param _uuid universal unique identifier
144      * @param _name name of the instance
145      * @param _dbAttrTypeName name of the database attribute type
146      * @param _uiAttrTypeName name of the user interface attribute type
147      * @throws EFapsException if attribute type for the data model or user
148      *             interface could not be initialized
149      */
150     protected AttributeType(final long _id,
151                             final String _uuid,
152                             final String _name,
153                             final String _dbAttrTypeName,
154                             final String _uiAttrTypeName)
155         throws EFapsException
156     {
157         super(_id, _uuid, _name);
158 
159         try {
160             this.dbAttrType = (IAttributeType) Class.forName(_dbAttrTypeName).newInstance();
161         } catch (final ClassNotFoundException e) {
162             throw new EFapsException(getClass(), "setUIClass.ClassNotFoundException", e, _uiAttrTypeName);
163         } catch (final InstantiationException e) {
164             throw new EFapsException(getClass(), "newInstance.InstantiationException", e);
165         } catch (final IllegalAccessException e) {
166             throw new EFapsException(getClass(), "newInstance.IllegalAccessException", e);
167         }
168 
169         try {
170             this.uiAttrType = (IUIProvider) Class.forName(_uiAttrTypeName).newInstance();
171             this.uiProvider = (IUIProvider) Class.forName(_uiAttrTypeName).newInstance();
172         } catch (final ClassNotFoundException e) {
173             throw new EFapsException(getClass(), "setUIClass.ClassNotFoundException", e, _uiAttrTypeName);
174         } catch (final InstantiationException e) {
175             throw new EFapsException(getClass(), "setUIClass.InstantiationException", e, _uiAttrTypeName);
176         } catch (final IllegalAccessException e) {
177             throw new EFapsException(getClass(), "setUIClass.IllegalAccessException", e, _uiAttrTypeName);
178         } catch (final ClassCastException e) {
179             throw new EFapsException(getClass(), "setUIClass.ClassCastException", e, _uiAttrTypeName);
180         }
181     }
182 
183     /**
184      *
185      *
186      * @return new instance of the class representation
187      * @see #dbAttrType
188      */
189     public IAttributeType getDbAttrType()
190     {
191         return this.dbAttrType;
192     }
193 
194     /**
195      * This is the getter method for instance variable {@link #classRepr}.
196      *
197      * @return value of instance variable {@link #classRepr}
198      * @see #classRepr
199      * @see #setClassRepr(Class)
200      */
201     public Class<?> getClassRepr()
202     {
203         return this.dbAttrType.getClass();
204     }
205 
206     /**
207      * This is the getter method for instance variable {@link #uiAttrType}.
208      *
209      * @return value of instance variable {@link #uiAttrType}
210      * @see #uiAttrType
211      * @see #setUI(Class)
212      */
213     public UIInterface getUI()
214     {
215         UIInterface ret;
216         if (this.uiAttrType instanceof UIInterface) {
217             ret = (UIInterface) this.uiAttrType;
218         } else {
219             ret = null;
220         }
221         return ret;
222     }
223 
224     /**
225      * This is the getter method for instance variable {@link #uiProvider}.
226      *
227      * @return value of instance variable {@link #uiProvider}
228      */
229     public IUIProvider getUIProvider()
230     {
231         return this.uiProvider;
232     }
233 
234     /**
235      * This is the getter method for instance variable {@link #alwaysUpdate}.
236      *
237      * @return value of instance variable {@link #alwaysUpdate}
238      * @see #alwaysUpdate
239      * @see #setAlwaysUpdate
240      */
241     public boolean isAlwaysUpdate()
242     {
243         return this.alwaysUpdate;
244     }
245 
246     /**
247      * This is the getter method for instance variable {@link #createUpdate}.
248      *
249      * @return value of instance variable {@link #createUpdate}
250      * @see #createUpdate
251      * @see #setCreateUpdate
252      */
253     public boolean isCreateUpdate()
254     {
255         return this.createUpdate;
256     }
257 
258     /**
259      * @return string representation of this attribute type
260      */
261     @Override
262     public String toString()
263     {
264         return new ToStringBuilder(this)
265                         .appendSuper(super.toString())
266                         .append("dbAttrType", this.dbAttrType)
267                         .append("uiAttrType", this.uiAttrType)
268                         .append("alwaysUpdate", this.alwaysUpdate)
269                         .append("createUpdate", this.createUpdate)
270                         .toString();
271     }
272 
273     @Override
274     public boolean equals(final Object _obj)
275     {
276         boolean ret;
277         if (_obj instanceof AttributeType) {
278             ret = ((AttributeType) _obj).getId() == getId();
279         } else {
280             ret = super.equals(_obj);
281         }
282         return ret;
283     }
284 
285     @Override
286     public int hashCode()
287     {
288         return  Long.valueOf(getId()).intValue();
289     }
290 
291     /**
292      *
293      * @param _class attribute type class
294      */
295     public static void initialize(final Class<?> _class)
296     {
297         if (InfinispanCache.get().exists(AttributeType.IDCACHE)) {
298             InfinispanCache.get().<Long, AttributeType>getCache(AttributeType.IDCACHE).clear();
299         } else {
300             InfinispanCache.get().<Long, AttributeType>getCache(AttributeType.IDCACHE)
301                             .addListener(new CacheLogListener(AttributeType.LOG));
302         }
303         if (InfinispanCache.get().exists(AttributeType.NAMECACHE)) {
304             InfinispanCache.get().<String, AttributeType>getCache(AttributeType.NAMECACHE).clear();
305         } else {
306             InfinispanCache.get().<String, AttributeType>getCache(AttributeType.NAMECACHE)
307                             .addListener(new CacheLogListener(AttributeType.LOG));
308         }
309     }
310 
311     /**
312      * Method to initialize the Cache of this CacheObjectInterface.
313      */
314     public static void initialize()
315     {
316         AttributeType.initialize(AttributeType.class);
317     }
318 
319     /**
320      * Returns for given parameter <i>_id</i> the instance of class
321      * {@link AttributeType}.
322      *
323      * @param _id id to search in the cache
324      * @return instance of class {@link AttributeType}
325      * @see #CACHE
326      * @throws CacheReloadException on error
327      */
328     public static AttributeType get(final long _id)
329         throws CacheReloadException
330     {
331         final Cache<Long, AttributeType> cache = InfinispanCache.get().<Long, AttributeType>getCache(
332                         AttributeType.IDCACHE);
333         if (!cache.containsKey(_id)) {
334             AttributeType.getAttributeTypeFromDB(AttributeType.SQL_ID, _id);
335         }
336         return cache.get(_id);
337     }
338 
339     /**
340      * Returns for given parameter <i>_name</i> the instance of class
341      * {@link AttributeType}.
342      *
343      * @param _name name to search in the cache
344      * @return instance of class {@link AttributeType}
345      * @see #CACHE
346      * @throws CacheReloadException on error
347      */
348     public static AttributeType get(final String _name)
349         throws CacheReloadException
350     {
351         final Cache<String, AttributeType> cache = InfinispanCache.get().<String, AttributeType>getCache(
352                         AttributeType.NAMECACHE);
353         if (!cache.containsKey(_name)) {
354             AttributeType.getAttributeTypeFromDB(AttributeType.SQL_NAME, _name);
355         }
356         return cache.get(_name);
357     }
358 
359     /**
360      * @param _role AttributeType to be cached
361      */
362     private static void cacheAttributeType(final AttributeType _role)
363     {
364         final Cache<String, AttributeType> nameCache = InfinispanCache.get()
365                         .<String, AttributeType>getIgnReCache(AttributeType.NAMECACHE);
366         nameCache.putIfAbsent(_role.getName(), _role);
367 
368         final Cache<Long, AttributeType> idCache = InfinispanCache.get().<Long, AttributeType>getIgnReCache(
369                         AttributeType.IDCACHE);
370         idCache.putIfAbsent(_role.getId(), _role);
371     }
372 
373     /**
374      * @param _sql      SQL Statement to be executed
375      * @param _criteria filter criteria
376      * @return true if successful
377      * @throws CacheReloadException on error
378      */
379     private static boolean getAttributeTypeFromDB(final String _sql,
380                                                   final Object _criteria)
381         throws CacheReloadException
382     {
383         boolean ret = false;
384         ConnectionResource con = null;
385         try {
386             con = Context.getThreadContext().getConnectionResource();
387             PreparedStatement stmt = null;
388             try {
389                 stmt = con.getConnection().prepareStatement(_sql);
390                 stmt.setObject(1, _criteria);
391                 final ResultSet rs = stmt.executeQuery();
392 
393                 if (rs.next()) {
394                     final long id = rs.getLong(1);
395                     final String name = rs.getString(2).trim();
396                     String uuid = rs.getString(3);
397                     uuid = (uuid == null) ? null : uuid.trim();
398 
399                     if (AttributeType.LOG.isDebugEnabled()) {
400                         AttributeType.LOG.debug("read attribute type '" + name + "' " + "(id = " + id + ", uuid = '"
401                                         + uuid + "')");
402                     }
403 
404                     final AttributeType attrType = new AttributeType(id,
405                                     uuid,
406                                     name,
407                                     rs.getString(4).trim(),
408                                     rs.getString(5).trim());
409                     if (rs.getInt(6) != 0) {
410                         attrType.alwaysUpdate = true;
411                     }
412                     if (rs.getInt(7) != 0) {
413                         attrType.createUpdate = true;
414                     }
415                     AttributeType.cacheAttributeType(attrType);
416                 }
417                 ret = true;
418                 rs.close();
419             } finally {
420                 if (stmt != null) {
421                     stmt.close();
422                 }
423             }
424             con.commit();
425         } catch (final SQLException e) {
426             throw new CacheReloadException("could not read roles", e);
427         } catch (final EFapsException e) {
428             throw new CacheReloadException("could not read roles", e);
429         } finally {
430             if ((con != null) && con.isOpened()) {
431                 try {
432                     con.abort();
433                 } catch (final EFapsException e) {
434                     throw new CacheReloadException("could not read roles", e);
435                 }
436             }
437         }
438         return ret;
439     }
440 }