View Javadoc

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