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.ui;
22  
23  import java.lang.reflect.Constructor;
24  import java.lang.reflect.InvocationTargetException;
25  import java.sql.ResultSet;
26  import java.sql.SQLException;
27  import java.sql.Statement;
28  import java.util.HashSet;
29  import java.util.List;
30  import java.util.Set;
31  import java.util.UUID;
32  import java.util.concurrent.TimeUnit;
33  
34  import org.efaps.admin.AbstractAdminObject;
35  import org.efaps.admin.datamodel.Type;
36  import org.efaps.admin.event.EventDefinition;
37  import org.efaps.admin.event.EventType;
38  import org.efaps.admin.event.Parameter;
39  import org.efaps.admin.event.Parameter.ParameterValues;
40  import org.efaps.admin.event.Return;
41  import org.efaps.admin.event.Return.ReturnValues;
42  import org.efaps.admin.program.bundle.BundleMaker;
43  import org.efaps.admin.ui.field.Field;
44  import org.efaps.admin.user.AbstractUserObject;
45  import org.efaps.admin.user.Company;
46  import org.efaps.ci.CIAdmin;
47  import org.efaps.ci.CIAttribute;
48  import org.efaps.db.Context;
49  import org.efaps.db.Instance;
50  import org.efaps.db.InstanceQuery;
51  import org.efaps.db.MultiPrintQuery;
52  import org.efaps.db.QueryBuilder;
53  import org.efaps.jaas.AppAccessHandler;
54  import org.efaps.util.EFapsException;
55  import org.efaps.util.cache.CacheLogListener;
56  import org.efaps.util.cache.CacheReloadException;
57  import org.efaps.util.cache.InfinispanCache;
58  import org.infinispan.Cache;
59  
60  /**
61   * This Class is the Abstract Class for all UserInterfaces in eFaps.<br/>
62   * In this Class only a few Methods are defined which are common to all Class
63   * inside the UserInterface Package. With this Class all
64   * <code>UserInterfaceObjects</code> can be initialized, the Access is checked
65   * and the Triggers for the <code>UserInterfaceObjects</code> are handled.
66   *
67   * @author The eFaps Team
68   * @version $Id: AbstractUserInterfaceObject.java 4820 2011-06-19 01:37:58Z
69   *          jan.moxter $
70   */
71  public abstract class AbstractUserInterfaceObject
72      extends AbstractAdminObject
73  {
74      /**
75       * This enum id used to define the different Modes a Target of a Command can
76       * have, like create, edit etc.
77       */
78      public static enum TargetMode
79      {
80          /** TargetMode for connect. */
81          CONNECT,
82          /** TargetMode for connect. */
83          CREATE,
84          /** TargetMode for create. */
85          EDIT,
86          /** TargetMode for print. */
87          PRINT,
88          /** TargetMode for edit. */
89          SEARCH,
90          /** TargetMode for unkown. */
91          UNKNOWN,
92          /** TargetMode for view. */
93          VIEW;
94      }
95  
96      /**
97       * Needed for serialization.
98       */
99      private static final long serialVersionUID = 1L;
100 
101     /**
102      * Used as <code>null</code> replacement for the cache.
103      */
104     private static AbstractUserInterfaceObject NULL = new AbstractUserInterfaceObject(Long.valueOf(0), null, null) {
105         private static final long serialVersionUID = 1L;
106     };
107 
108     /**
109      * The instance variable is an Access HashSet to store all userIds (person,
110      * group or role) who have access to this user interface object.
111      *
112      * @see #getAccess
113      */
114     private final Set<Long> access = new HashSet<Long>();
115 
116     /**
117      * Constructor to set the id, the uuid and the name of the user interface
118      * object.
119      *
120      * @param _id id to set
121      * @param _uuid uuid to set (as String)
122      * @param _name name to set
123      */
124     protected AbstractUserInterfaceObject(final long _id,
125                                           final String _uuid,
126                                           final String _name)
127     {
128         super(_id, _uuid, _name);
129     }
130 
131     /**
132      * The instance method reads all needed information for this user interface
133      * object. Here, only the properties are read from the database
134      *
135      * @see #readFromDB4Properties
136      * @see #readFromDB4Links
137      * @see #readFromDB4Access
138      * @throws CacheReloadException on error during reload
139      */
140     protected void readFromDB()
141         throws CacheReloadException
142     {
143         readFromDB4Properties();
144         readFromDB4Links();
145         readFromDB4Access();
146     }
147 
148     /**
149      * The instance method reads the access for this user interface object.
150      *
151      * @throws CacheReloadException on error during reload
152      */
153     private void readFromDB4Access()
154         throws CacheReloadException
155     {
156         Statement stmt = null;
157         try {
158             stmt = Context.getThreadContext().getConnection().createStatement();
159             final ResultSet resultset = stmt.executeQuery("select "
160                             + "T_UIACCESS.USERABSTRACT "
161                             + "from T_UIACCESS "
162                             + "where T_UIACCESS.UIABSTRACT=" + getId());
163             while (resultset.next()) {
164                 final long userId = resultset.getLong(1);
165                 final AbstractUserObject userObject = AbstractUserObject.getUserObject(userId);
166                 if (userObject == null) {
167                     throw new CacheReloadException("user " + userId + " does not exists!");
168                 } else {
169                     getAccess().add(userId);
170                 }
171             }
172             resultset.close();
173         } catch (final SQLException e) {
174             throw new CacheReloadException("could not read access for " + "'" + getName() + "'", e);
175         } catch (final EFapsException e) {
176             throw new CacheReloadException("could not read access for " + "'" + getName() + "'", e);
177         } finally {
178             if (stmt != null) {
179                 try {
180                     stmt.close();
181                 } catch (final SQLException e) {
182                     throw new CacheReloadException("could not read access for " + "'" + getName() + "'", e);
183                 }
184             }
185         }
186     }
187 
188     /**
189      * Check, if the user of the context has access to this user interface
190      * object. <br>
191      * The Check is made in the following order: <br>
192      * <ol>
193      * <li>If no access User or role is assigned to this user interface object,
194      * all user have access and the return is <i>true</i> => go on with Step 3</li>
195      * <li>else check if the context person is assigned to one of the user
196      * objects.</li>
197      * <li>if Step 1 or Step 2 have <i>true</i> and the context an Event of the
198      * Type <code>TriggerEvent.ACCESSCHECK</code>, the return of the trigger
199      * initiated program is returned</li>
200      * </ol>
201      *
202      * @param _targetMode targetmode of the access
203      * @param _instance the field will represent, e.g. on edit mode
204      * @return <i>true</i> if context user has access, otherwise <i>false</i> is
205      *         returned
206      * @throws EFapsException on error
207      */
208     public boolean hasAccess(final TargetMode _targetMode,
209                              final Instance _instance)
210         throws EFapsException
211     {
212         return hasAccess(_targetMode, _instance, null, null);
213     }
214 
215     /**
216      * Check, if the user of the context has access to this user interface
217      * object. <br>
218      * The Check is made in the following order: <br>
219      * <ol>
220      * <li>If no access User or role is assigned to this user interface object,
221      * all user have access and the return is <i>true</i> => go on with Step 3</li>
222      * <li>else check if the context person is assigned to one of the user
223      * objects.</li>
224      * <li>if Step 1 or Step 2 have <i>true</i> and the context an Event of the
225      * Type <code>TriggerEvent.ACCESSCHECK</code>, the return of the trigger
226      * initiated program is returned</li>
227      * </ol>
228      *
229      * @param _targetMode targetmode of the access
230      * @param _instance the field will represent, e.g. on edit mode
231      * @param _callCmd the cmd that called this UI-Object
232      * @param _callInstance the instance the object is called in
233      * @return <i>true</i> if context user has access, otherwise <i>false</i> is
234      *         returned
235      * @throws EFapsException on error
236      */
237     public boolean hasAccess(final TargetMode _targetMode,
238                              final Instance _instance,
239                              final AbstractCommand _callCmd,
240                              final Instance _callInstance)
241         throws EFapsException
242     {
243         boolean ret = false;
244         if (getAccess().isEmpty() && !AppAccessHandler.excludeMode()) {
245             ret = true;
246         } else {
247             // first must be checked for the company
248             boolean company = false;
249             boolean checked = false;
250             for (final Long userId : getAccess()) {
251                 final Company companyObj = Company.get(userId);
252                 if (companyObj != null) {
253                     checked = true;
254                     if (companyObj.isAssigned()) {
255                         company = true;
256                         break;
257                     }
258                 }
259             }
260             // second it must be checked for the others, if no companies had to
261             // be checked or
262             // if the check on companies was positiv
263             if (!company && !checked || company && checked) {
264                 for (final Long userId : getAccess()) {
265                     final AbstractUserObject userObject = AbstractUserObject.getUserObject(userId);
266                     if (!(userObject instanceof Company)) {
267                         if (userObject.isAssigned()) {
268                             ret = true;
269                             break;
270                         }
271                     }
272                 }
273             }
274         }
275         if ((ret || AppAccessHandler.excludeMode()) && super.hasEvents(EventType.UI_ACCESSCHECK)) {
276             ret = false;
277             final List<EventDefinition> events = super.getEvents(EventType.UI_ACCESSCHECK);
278             final Parameter parameter = new Parameter();
279             parameter.put(ParameterValues.UIOBJECT, this);
280             parameter.put(ParameterValues.ACCESSMODE, _targetMode);
281             parameter.put(ParameterValues.INSTANCE, _instance);
282             parameter.put(ParameterValues.CALL_CMD, _callCmd);
283             parameter.put(ParameterValues.CALL_INSTANCE, _callInstance);
284             for (final EventDefinition event : events) {
285                 final Return retIn = event.execute(parameter);
286                 if (retIn.get(ReturnValues.TRUE) == null) {
287                     ret = false;
288                     break;
289                 } else {
290                     ret = true;
291                 }
292             }
293         }
294         return ret;
295     }
296 
297     /**
298      * Getter method for the HashSet instance variable {@link #access}.
299      *
300      * @return value of the HashSet instance variable {@link #access}
301      * @see #access
302      */
303     protected Set<Long> getAccess()
304     {
305         return this.access;
306     }
307 
308     /**
309      * @param _uuid             UUUI of the UIObject wanted
310      * @param _componentType    type of the UIObject
311      * @param _type             datamodel type of the object
312      * @param <V> Object type
313      * @return UIObject
314      * @throws CacheReloadException on error
315      */
316     @SuppressWarnings("unchecked")
317     protected static <V> V get(final UUID _uuid,
318                                final Class<V> _componentType,
319                                final Type _type)
320         throws CacheReloadException
321     {
322         final Cache<UUID, V> cache = InfinispanCache.get().<UUID, V>getCache(
323                         AbstractUserInterfaceObject.getUUIDCacheName(_componentType));
324         if (!cache.containsKey(_uuid)
325                         && !AbstractUserInterfaceObject
326                                         .readObjectFromDB(_componentType, _type, CIAdmin.Abstract.UUID, _uuid)) {
327             cache.put(_uuid, (V) AbstractUserInterfaceObject.NULL, 100, TimeUnit.SECONDS);
328         }
329         final V ret = cache.get(_uuid);
330         return ret.equals(AbstractUserInterfaceObject.NULL) ? null : ret;
331     }
332 
333     /**
334      * @param _id ID of the UIObject wanted
335      * @param _componentType type of the UIObject
336      * @param _type datamodel type of the object
337      * @param <V> Object type
338      * @return UIObject
339      * @throws CacheReloadException on error
340      */
341     @SuppressWarnings("unchecked")
342     protected static <V> V get(final Long _id,
343                                final Class<V> _componentType,
344                                final Type _type)
345         throws CacheReloadException
346     {
347         final Cache<Long, V> cache = InfinispanCache.get().<Long, V>getCache(
348                         AbstractUserInterfaceObject.getIDCacheName(_componentType));
349         if (!cache.containsKey(_id) && !
350                         AbstractUserInterfaceObject.readObjectFromDB(_componentType, _type, CIAdmin.Abstract.ID, _id)) {
351             cache.put(_id, (V) AbstractUserInterfaceObject.NULL, 100, TimeUnit.SECONDS);
352         }
353         final V ret = cache.get(_id);
354         return ret.equals(AbstractUserInterfaceObject.NULL) ? null : ret;
355     }
356 
357     /**
358      * @param _name Name of the UIObject wanted
359      * @param _componentType type of the UIObject
360      * @param _type datamodel type of the object
361      * @param <V> Object type
362      * @return UIObject
363      * @throws CacheReloadException on error
364      */
365     @SuppressWarnings("unchecked")
366     protected static <V> V get(final String _name,
367                                final Class<V> _componentType,
368                                final Type _type)
369         throws CacheReloadException
370     {
371         final Cache<String, V> cache = InfinispanCache.get().<String, V>getCache(
372                         AbstractUserInterfaceObject.getNameCacheName(_componentType));
373         if (!cache.containsKey(_name)
374                         && !AbstractUserInterfaceObject.readObjectFromDB(_componentType, _type, CIAdmin.Abstract.Name,
375                                         _name)) {
376             cache.put(_name, (V) AbstractUserInterfaceObject.NULL, 100, TimeUnit.SECONDS);
377         }
378         final V ret = cache.get(_name);
379         return ret.equals(AbstractUserInterfaceObject.NULL) ? null : ret;
380     }
381 
382     /**
383      * @param _componentType class of the UIObject
384      * @return name for the UUID Cache
385      */
386     protected static String getUUIDCacheName(final Class<?> _componentType)
387     {
388         return _componentType.getName() + ".UUID";
389     }
390     /**
391      * @param _componentType class of the UIObject
392      * @return name for the ID Cache
393      */
394 
395     protected static String getIDCacheName(final Class<?> _componentType)
396     {
397         return _componentType.getName() + ".ID";
398     }
399 
400     /**
401      * @param _componentType class of the UIObject
402      * @return name for the Name Cache
403      */
404     protected static String getNameCacheName(final Class<?> _componentType)
405     {
406         return _componentType.getName() + ".Name";
407     }
408 
409     /**
410      * @param _object UIObject to be cache
411      */
412     protected static void cacheUIObject(final AbstractUserInterfaceObject _object)
413     {
414         final Cache<UUID, AbstractUserInterfaceObject> cache4UUID = InfinispanCache.get()
415                         .<UUID, AbstractUserInterfaceObject>getIgnReCache(
416                                         AbstractUserInterfaceObject.getUUIDCacheName(_object.getClass()));
417         cache4UUID.putIfAbsent(_object.getUUID(), _object);
418 
419         final Cache<String, AbstractUserInterfaceObject> nameCache = InfinispanCache.get()
420                         .<String, AbstractUserInterfaceObject>getIgnReCache(
421                                         AbstractUserInterfaceObject.getNameCacheName(_object.getClass()));
422         nameCache.putIfAbsent(_object.getName(), _object);
423 
424         final Cache<Long, AbstractUserInterfaceObject> idCache = InfinispanCache.get()
425                         .<Long, AbstractUserInterfaceObject>getIgnReCache(
426                                         AbstractUserInterfaceObject.getIDCacheName(_object.getClass()));
427         idCache.putIfAbsent(_object.getId(), _object);
428     }
429 
430     /**
431      * @param _componentType  c lass of UIObject to be retrieved
432      * @param _type             DataModel TYpe of UIObject to be retrieved
433      * @param _ciAttr           Attribute used for filtered
434      * @param _value            value to filtered
435      * @return true if successful
436      * @throws CacheReloadException on error
437      */
438     private static boolean readObjectFromDB(final Class<?> _componentType,
439                                             final Type _type,
440                                             final CIAttribute _ciAttr,
441                                             final Object _value)
442         throws CacheReloadException
443     {
444         boolean ret = false;
445         try {
446             final QueryBuilder queryBldr = new QueryBuilder(_type);
447             queryBldr.addWhereAttrEqValue(_ciAttr, _value.toString());
448             final InstanceQuery query = queryBldr.getQuery();
449             query.setIncludeChildTypes(false);
450 
451             final List<Instance> instances = query.execute();
452             final MultiPrintQuery multi = new MultiPrintQuery(instances);
453             multi.addAttribute(CIAdmin.Abstract.Name,
454                             CIAdmin.Abstract.UUID);
455             multi.executeWithoutAccessCheck();
456             if (multi.next()) {
457                 final long id = multi.getCurrentInstance().getId();
458                 final String name = multi.<String>getAttribute(CIAdmin.Abstract.Name);
459                 final String uuid = multi.<String>getAttribute(CIAdmin.Abstract.UUID);
460                 final Constructor<?> uiObjConst = _componentType.getConstructor(Long.class, String.class,
461                                 String.class);
462                 final AbstractUserInterfaceObject uiObje = (AbstractUserInterfaceObject) uiObjConst.newInstance(id,
463                                 uuid, name);
464                 AbstractUserInterfaceObject.cacheUIObject(uiObje);
465                 uiObje.readFromDB();
466                 ret = true;
467             }
468         } catch (final NoSuchMethodException e) {
469             throw new CacheReloadException("NoSuchMethodException", e);
470         } catch (final EFapsException e) {
471             throw new CacheReloadException("EFapsException", e);
472         } catch (final IllegalArgumentException e) {
473             throw new CacheReloadException("IllegalArgumentException", e);
474         } catch (final InstantiationException e) {
475             throw new CacheReloadException("InstantiationException", e);
476         } catch (final IllegalAccessException e) {
477             throw new CacheReloadException("IllegalAccessException", e);
478         } catch (final InvocationTargetException e) {
479             throw new CacheReloadException("InvocationTargetException", e);
480         }
481         return ret;
482     }
483 
484     /**
485      * Method to initialize the Cache of this CacheObjectInterface.
486      *
487      * @throws CacheReloadException on error
488      */
489     public static void initialize()
490         throws CacheReloadException
491     {
492         Field.initialize();
493 
494         if (InfinispanCache.get().exists(AbstractUserInterfaceObject.getUUIDCacheName(Command.class))) {
495             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Command.class))
496                             .clear();
497             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Command.class))
498                             .clear();
499             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Command.class))
500                             .clear();
501             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Menu.class))
502                             .clear();
503             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Menu.class)).clear();
504             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Menu.class))
505                             .clear();
506             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Image.class))
507                             .clear();
508             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Image.class)).clear();
509             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Image.class))
510                             .clear();
511 
512             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Search.class))
513                             .clear();
514             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Search.class))
515                             .clear();
516             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Search.class))
517                             .clear();
518 
519             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Form.class))
520                             .clear();
521             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Form.class)).clear();
522             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Form.class))
523                             .clear();
524 
525             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Table.class))
526                             .clear();
527             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Table.class)).clear();
528             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Table.class))
529                             .clear();
530         } else {
531             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Command.class))
532                             .addListener(new CacheLogListener(Command.LOG));
533             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Command.class))
534                             .addListener(new CacheLogListener(Command.LOG));
535             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Command.class))
536                             .addListener(new CacheLogListener(Command.LOG));
537 
538             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Menu.class))
539                             .addListener(new CacheLogListener(Menu.LOG));
540             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Menu.class))
541                             .addListener(new CacheLogListener(Menu.LOG));
542             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Menu.class))
543                             .addListener(new CacheLogListener(Menu.LOG));
544 
545             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Image.class))
546                             .addListener(new CacheLogListener(Image.LOG));
547             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Image.class))
548                             .addListener(new CacheLogListener(Image.LOG));
549             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Image.class))
550                             .addListener(new CacheLogListener(Image.LOG));
551 
552             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Search.class))
553                             .addListener(new CacheLogListener(Search.LOG));
554             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Search.class))
555                             .addListener(new CacheLogListener(Search.LOG));
556             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Search.class))
557                             .addListener(new CacheLogListener(Search.LOG));
558 
559             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Form.class))
560                             .addListener(new CacheLogListener(Form.LOG));
561             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Form.class))
562                             .addListener(new CacheLogListener(Form.LOG));
563             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Form.class))
564                             .addListener(new CacheLogListener(Form.LOG));
565 
566             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getUUIDCacheName(Table.class))
567                             .addListener(new CacheLogListener(Table.LOG));
568             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getIDCacheName(Table.class))
569                             .addListener(new CacheLogListener(Table.LOG));
570             InfinispanCache.get().<UUID, Type>getCache(AbstractUserInterfaceObject.getNameCacheName(Table.class))
571                             .addListener(new CacheLogListener(Table.LOG));
572         }
573         BundleMaker.initialize();
574     }
575 }