View Javadoc

1   package org.apache.turbine.services.security.torque;
2   
3   /*
4    * Copyright 2001-2005 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License")
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.beans.PropertyDescriptor;
20  
21  import java.util.ArrayList;
22  import java.util.Iterator;
23  import java.util.Enumeration;
24  import java.util.List;
25  import java.util.Vector;
26  
27  import org.apache.commons.configuration.Configuration;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  
32  import org.apache.turbine.om.security.Permission;
33  import org.apache.turbine.om.security.Role;
34  import org.apache.turbine.services.InitializationException;
35  import org.apache.turbine.services.security.TurbineSecurity;
36  import org.apache.turbine.services.security.torque.om.TurbineRolePermissionPeer;
37  import org.apache.turbine.util.security.DataBackendException;
38  import org.apache.turbine.util.security.PermissionSet;
39  
40  import org.apache.torque.TorqueException;
41  import org.apache.torque.om.Persistent;
42  import org.apache.torque.util.BasePeer;
43  import org.apache.torque.util.Criteria;
44  
45  /***
46   * This class capsulates all direct Peer access for the Permission entities.
47   * It allows the exchange of the default Turbine supplied TurbinePermissionPeer
48   * class against a custom class.
49   *
50   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
51   * @version $Id: PermissionPeerManager.java 264148 2005-08-29 14:21:04Z henning $
52   *
53   */
54  
55  public class PermissionPeerManager
56      implements PermissionPeerManagerConstants
57  {
58      /*** The class of the Peer the TorqueSecurityService uses */
59      private static Class persistentPeerClass = null;
60  
61      /*** The class name of the objects returned by the configured peer. */
62      private static Class permissionObject = null;
63  
64      /*** The name of the Table used for Permission Object queries  */
65      private static String tableName = null;
66  
67      /*** The name of the column used as "Name" Column */
68      private static String nameColumn = null;
69  
70      /*** The name of the column used as "Id" Column */
71      private static String idColumn = null;
72  
73      /*** The "Name" property descriptor */
74      private static PropertyDescriptor namePropDesc = null;
75  
76      /*** The "Id" property descriptor */
77      private static PropertyDescriptor idPropDesc = null;
78  
79      /*** Logging */
80      static Log log = LogFactory.getLog(PermissionPeerManager.class);
81  
82      /***
83       * Initializes the PermissionPeerManager, loading the class object for the
84       * Peer used to retrieve Permission objects
85       *
86       * @param conf The configuration object used to configure the Manager
87       *
88       * @exception InitializationException A problem occured during initialization
89       */
90  
91      public static void init(Configuration conf)
92          throws InitializationException
93      {
94          String persistentPeerClassName =
95              conf.getString(PERMISSION_PEER_CLASS_KEY,
96                             PERMISSION_PEER_CLASS_DEFAULT);
97  
98          String permissionObjectName = null;
99  
100         try
101         {
102             persistentPeerClass = Class.forName(persistentPeerClassName);
103 
104             tableName  =
105                 (String) persistentPeerClass.getField("TABLE_NAME").get(null);
106 
107             //
108             // We have either an user configured Object class or we use the
109             // default as supplied by the Peer class
110             //
111             // Default from Peer, can be overridden
112 
113             permissionObject = getPersistenceClass();
114 
115             permissionObjectName = conf.getString(PERMISSION_CLASS_KEY,
116                                         permissionObject.getName());
117 
118             // Maybe the user set a new value...
119             permissionObject = Class.forName(permissionObjectName);
120 
121             /* If any of the following Field queries fails, the permission
122              * subsystem is unusable. So check this right here at init time,
123              * which saves us much time and hassle if it fails...
124              */
125 
126             nameColumn = (String) persistentPeerClass.getField(
127                     conf.getString(PERMISSION_NAME_COLUMN_KEY,
128                                    PERMISSION_NAME_COLUMN_DEFAULT)
129                     ).get(null);
130 
131             idColumn = (String) persistentPeerClass.getField(
132                     conf.getString(PERMISSION_ID_COLUMN_KEY,
133                                    PERMISSION_ID_COLUMN_DEFAULT)
134                     ).get(null);
135 
136             namePropDesc = new PropertyDescriptor(
137                     conf.getString(PERMISSION_NAME_PROPERTY_KEY,
138                                    PERMISSION_NAME_PROPERTY_DEFAULT),
139                     permissionObject);
140 
141             idPropDesc = new PropertyDescriptor(
142                     conf.getString(PERMISSION_ID_PROPERTY_KEY,
143                                    PERMISSION_ID_PROPERTY_DEFAULT),
144                     permissionObject);
145         }
146         catch (Exception e)
147         {
148             if (persistentPeerClassName == null || persistentPeerClass == null)
149             {
150                 throw new InitializationException(
151                     "Could not find PermissionPeer class ("
152                     + persistentPeerClassName + ")", e);
153             }
154             if (tableName == null)
155             {
156                 throw new InitializationException(
157                     "Failed to get the table name from the Peer object", e);
158             }
159 
160             if (permissionObject == null || permissionObjectName == null)
161             {
162                 throw new InitializationException(
163                     "Failed to get the object type from the Peer object", e);
164             }
165 
166 
167             if (nameColumn == null || namePropDesc == null)
168             {
169                 throw new InitializationException(
170                     "PermissionPeer " + persistentPeerClassName +
171                     " has no name column information!", e);
172             }
173             if (idColumn == null || idPropDesc == null)
174             {
175                 throw new InitializationException(
176                     "PermissionPeer " + persistentPeerClassName +
177                     " has no id column information!", e);
178             }
179         }
180     }
181 
182     /***
183      * Get the name of this table.
184      *
185      * @return A String with the name of the table.
186      */
187     public static String getTableName()
188     {
189         return tableName;
190     }
191 
192     /***
193      * Returns the fully qualified name of the Column to
194      * use as the Name Column for a permission
195      *
196      * @return A String containing the column name
197      */
198     public static String getNameColumn()
199     {
200         return nameColumn;
201     }
202 
203     /***
204      * Returns the fully qualified name of the Column to
205      * use as the Id Column for a permission
206      *
207      * @return A String containing the column id
208      *
209      */
210     public static String getIdColumn()
211     {
212         return idColumn;
213     }
214 
215     /***
216      * Returns the full name of a column.
217      *
218      * @param name The column to fully qualify
219      *
220      * @return A String with the full name of the column.
221      */
222     public static String getColumnName(String name)
223     {
224         StringBuffer sb = new StringBuffer();
225         sb.append(getTableName());
226         sb.append(".");
227         sb.append(name);
228         return sb.toString();
229     }
230 
231     /***
232      * Returns a new, empty object for the underlying peer.
233      * Used to create a new underlying object
234      *
235      * @return A new object which is compatible to the Peer
236      *         and can be used as a User object
237      *
238      */
239 
240     public static Persistent newPersistentInstance()
241     {
242         Persistent obj = null;
243 
244         if(permissionObject == null)
245         {
246             // This can happen if the Turbine wants to determine the
247             // name of the anonymous user before the security service
248             // has been initialized. In this case, the Peer Manager
249             // has not yet been inited and the permissionObject is still
250             // null. Return null in this case.
251             //
252             return obj;
253         }
254 
255         try
256         {
257             obj = (Persistent) permissionObject.newInstance();
258         }
259         catch (Exception e)
260         {
261             log.error("Could not instantiate a permission object", e);
262             obj = null;
263         }
264         return obj;
265     }
266 
267     /***
268      * Checks if a Permission is defined in the system. The name
269      * is used as query criteria.
270      *
271      * @param permission The Permission to be checked.
272      * @return <code>true</code> if given Permission exists in the system.
273      * @throws DataBackendException when more than one Permission with
274      *         the same name exists.
275      * @throws Exception A generic exception.
276      */
277     public static boolean checkExists(Permission permission)
278         throws DataBackendException, Exception
279     {
280         Criteria criteria = new Criteria();
281 
282         criteria.addSelectColumn(getIdColumn());
283 
284         criteria.add(getNameColumn(), permission.getName());
285 
286         List results = BasePeer.doSelect(criteria);
287 
288         if (results.size() > 1)
289         {
290             throw new DataBackendException("Multiple permissions named '" +
291                                            permission.getName() + "' exist!");
292         }
293         return (results.size() == 1);
294     }
295 
296     /***
297      * Retrieves/assembles a PermissionSet
298      *
299      * @param criteria The criteria to use.
300      * @return A PermissionSet.
301      * @exception Exception A generic Exception.
302      */
303     public static PermissionSet retrieveSet(Criteria criteria)
304         throws Exception
305     {
306         List results = doSelect(criteria);
307         PermissionSet ps = new PermissionSet();
308 
309         for(Iterator it = results.iterator(); it.hasNext(); )
310         {
311             ps.add((Permission) it.next());
312         }
313         return ps;
314     }
315 
316     /***
317      * Retrieves a set of Permissions associated with a particular Role.
318      *
319      * @param role The role to query permissions of.
320      * @return A set of permissions associated with the Role.
321      * @exception Exception A generic Exception.
322      */
323     public static PermissionSet retrieveSet(Role role)
324         throws Exception
325     {
326         Criteria criteria = new Criteria();
327         criteria.add(TurbineRolePermissionPeer.ROLE_ID,
328                      ((Persistent) role).getPrimaryKey());
329 
330         criteria.addJoin(TurbineRolePermissionPeer.PERMISSION_ID,
331                          getIdColumn());
332 
333         return retrieveSet(criteria);
334     }
335 
336     /***
337      * Pass in two Vector's of Permission Objects.  It will return a
338      * new Vector with the difference of the two Vectors: C = (A - B).
339      *
340      * @param some Vector B in C = (A - B).
341      * @param all Vector A in C = (A - B).
342      * @return Vector C in C = (A - B).
343      */
344     public static final Vector getDifference(Vector some, Vector all)
345     {
346         Vector clone = (Vector) all.clone();
347         for (Enumeration e = some.elements() ; e.hasMoreElements() ;)
348         {
349             Permission tmp = (Permission) e.nextElement();
350             for (Enumeration f = clone.elements() ; f.hasMoreElements() ;)
351             {
352                 Permission tmp2 = (Permission) f.nextElement();
353                 if (((Persistent) tmp).getPrimaryKey() ==
354                     ((Persistent) tmp2).getPrimaryKey())
355                 {
356                     clone.removeElement(tmp2);
357                     break;
358                 }
359             }
360         }
361         return clone;
362     }
363 
364     /*
365      * ========================================================================
366      *
367      * WARNING! Do not read on if you have a weak stomach. What follows here
368      * are some abominations thanks to the braindead static peers of Torque
369      * and the rigidity of Java....
370      *
371      * ========================================================================
372      *
373      */
374 
375     /***
376      * Calls buildCriteria(Permission permission) in
377      * the configured PermissionPeer. If you get a
378      * ClassCastException in this routine, you put a
379      * Permission object into this method which
380      * can't be cast into an object for the
381      * TorqueSecurityService. This is a configuration error most of
382      * the time.
383      *
384      * @param permission An object which implements
385      *                 the Permission interface
386      *
387      * @return A criteria for the supplied permission object
388      */
389 
390     public static Criteria buildCriteria(Permission permission)
391     {
392         Criteria crit;
393 
394         try
395         {
396             Class[] clazz = new Class[] { permissionObject };
397             Object[] params =
398               new Object[] { ((TorquePermission) permission).getPersistentObj() };
399 
400             crit =  (Criteria) persistentPeerClass
401                 .getMethod("buildCriteria", clazz)
402                 .invoke(null, params);
403         }
404         catch (Exception e)
405         {
406             crit = null;
407         }
408 
409         return crit;
410     }
411 
412     /***
413      * Invokes doUpdate(Criteria c) on the configured Peer Object
414      *
415      * @param criteria  A Criteria Object
416      *
417      * @exception TorqueException A problem occured.
418      */
419 
420     public static void doUpdate(Criteria criteria)
421         throws TorqueException
422     {
423         try
424         {
425             Class[] clazz = new Class[] { Criteria.class };
426             Object[] params = new Object[] { criteria };
427 
428             persistentPeerClass
429                 .getMethod("doUpdate", clazz)
430                 .invoke(null, params);
431         }
432         catch (Exception e)
433         {
434             throw new TorqueException("doUpdate failed", e);
435         }
436     }
437 
438     /***
439      * Invokes doInsert(Criteria c) on the configured Peer Object
440      *
441      * @param criteria  A Criteria Object
442      *
443      * @exception TorqueException A problem occured.
444      */
445 
446     public static void doInsert(Criteria criteria)
447         throws TorqueException
448     {
449         try
450         {
451             Class[] clazz = new Class[] { Criteria.class };
452             Object[] params = new Object[] { criteria };
453 
454             persistentPeerClass
455                 .getMethod("doInsert", clazz)
456                 .invoke(null, params);
457         }
458         catch (Exception e)
459         {
460             throw new TorqueException("doInsert failed", e);
461         }
462     }
463 
464     /***
465      * Invokes doSelect(Criteria c) on the configured Peer Object
466      *
467      * @param criteria  A Criteria Object
468      *
469      * @return A List of Permission Objects selected by the Criteria
470      *
471      * @exception TorqueException A problem occured.
472      */
473     public static List doSelect(Criteria criteria)
474         throws TorqueException
475     {
476         List list;
477 
478         try
479         {
480             Class[] clazz =
481               new Class[] { Criteria.class };
482             Object[] params = new Object[] { criteria };
483 
484             list = (List) persistentPeerClass
485                 .getMethod("doSelect", clazz)
486                 .invoke(null, params);
487         }
488         catch (Exception e)
489         {
490             throw new TorqueException("doSelect failed", e);
491         }
492 
493         List newList = new ArrayList(list.size());
494 
495         //
496         // Wrap the returned Objects into TorquePermissions.
497         //
498         for (Iterator it = list.iterator(); it.hasNext(); )
499         {
500             Permission p = getNewPermission((Persistent) it.next());
501             newList.add(p);
502         }
503 
504         return newList;
505     }
506 
507     /***
508      * Invokes doDelete(Criteria c) on the configured Peer Object
509      *
510      * @param criteria  A Criteria Object
511      *
512      * @exception TorqueException A problem occured.
513      */
514     public static void doDelete(Criteria criteria)
515         throws TorqueException
516     {
517         try
518         {
519             Class[] clazz = new Class[] { Criteria.class };
520             Object[] params = new Object[] { criteria };
521 
522             persistentPeerClass
523                 .getMethod("doDelete", clazz)
524                 .invoke(null, params);
525         }
526         catch (Exception e)
527         {
528             throw new TorqueException("doDelete failed", e);
529         }
530     }
531 
532     /***
533      * Invokes setName(String s) on the supplied base object
534      *
535      * @param obj The object to use for setting the name
536      * @param name The Name to set
537      */
538     public static void setPermissionName(Persistent obj, String name)
539     {
540         if(obj == null)
541         {
542             return;
543         }
544 
545         try
546         {
547             Object[] params = new Object[] { name };
548             namePropDesc.getWriteMethod().invoke(obj, params);
549         }
550         catch (ClassCastException cce)
551         {
552             String msg = obj.getClass().getName() + " does not seem to be a Permission Object!";
553             log.error(msg);
554             throw new RuntimeException(msg);
555         }
556         catch (Exception e)
557         {
558             log.error(e, e);
559         }
560     }
561 
562     /***
563      * Invokes getName() on the supplied base object
564      *
565      * @param obj The object to use for getting the name
566      *
567      * @return A string containing the name
568      */
569     public static String getPermissionName(Persistent obj)
570     {
571         String name = null;
572 
573         if(obj == null)
574         {
575             return null;
576         }
577 
578         try
579         {
580             name = (String) namePropDesc
581                 .getReadMethod()
582                 .invoke(obj, new Object[] {});
583         }
584         catch (ClassCastException cce)
585         {
586             String msg = obj.getClass().getName() + " does not seem to be a Permission Object!";
587             log.error(msg);
588             throw new RuntimeException(msg);
589         }
590         catch (Exception e)
591         {
592             log.error(e, e);
593         }
594         return name;
595     }
596 
597     /***
598      * Invokes setId(int n) on the supplied base object
599      *
600      * @param obj The object to use for setting the name
601      * @param id The new Id
602      */
603     public static void setId(Persistent obj, int id)
604     {
605         if(obj == null)
606         {
607             return;
608         }
609 
610         try
611         {
612             Object[] params = new Object[] { Integer.TYPE };
613             idPropDesc.getWriteMethod().invoke(obj, params);
614         }
615         catch (ClassCastException cce)
616         {
617             String msg = obj.getClass().getName() + " does not seem to be a Permission Object!";
618             log.error(msg);
619             throw new RuntimeException(msg);
620         }
621         catch (Exception e)
622         {
623             log.error(e, e);
624         }
625     }
626 
627     /***
628      * Invokes getId() on the supplied base object
629      *
630      * @param obj The object to use for getting the id
631      *
632      * @return The Id of this object
633      */
634     public static Integer getIdAsObj(Persistent obj)
635     {
636         Integer id = null;
637 
638         if(obj == null)
639         {
640             return new Integer(0);
641         }
642 
643         try
644         {
645             id = (Integer) idPropDesc
646                 .getReadMethod()
647                 .invoke(obj, new Object[] {});
648         }
649         catch (ClassCastException cce)
650         {
651             String msg = obj.getClass().getName() + " does not seem to be a Permission Object!";
652             log.error(msg);
653             throw new RuntimeException(msg);
654         }
655         catch (Exception e)
656         {
657             log.error(e, e);
658         }
659         return id;
660     }
661 
662     /***
663      * Returns the Class of the configured Object class
664      * from the peer
665      *
666      * @return The class of the objects returned by the configured peer
667      *
668      */
669 
670     private static Class getPersistenceClass()
671     {
672         Class persistenceClass = null;
673 
674         try
675         {
676             Object[] params = new Object[0];
677 
678             persistenceClass =  (Class) persistentPeerClass
679                 .getMethod("getOMClass", null)
680                 .invoke(null, params);
681         }
682         catch (Exception e)
683         {
684             persistenceClass = null;
685         }
686 
687         return persistenceClass;
688     }
689 
690     /***
691      * Returns a new, configured Permission Object with
692      * a supplied Persistent object at its core
693      *
694      * @param p The persistent object
695      *
696      * @return a new, configured Permission Object
697      *
698      * @exception Exception Could not create a new Object
699      *
700      */
701 
702     public static Permission getNewPermission(Persistent p)
703     {
704         Permission perm = null;
705         try
706         {
707             Class permissionWrapperClass = TurbineSecurity.getPermissionClass();
708 
709             Class [] clazz = new Class [] { Persistent.class };
710             Object [] params = new Object [] { p };
711 
712             perm = (Permission) permissionWrapperClass
713               .getConstructor(clazz)
714               .newInstance(params);
715         }
716         catch (Exception e)
717         {
718             log.error("Could not instantiate a new permission from supplied persistent: ", e);
719         }
720 
721         return perm;
722     }
723 }
724