001    package org.apache.turbine.services.security.torque;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.beans.PropertyDescriptor;
023    
024    import java.util.ArrayList;
025    import java.util.Iterator;
026    import java.util.List;
027    
028    import org.apache.commons.configuration.Configuration;
029    
030    import org.apache.commons.logging.Log;
031    import org.apache.commons.logging.LogFactory;
032    
033    import org.apache.turbine.om.security.Group;
034    import org.apache.turbine.om.security.Role;
035    import org.apache.turbine.om.security.User;
036    import org.apache.turbine.services.InitializationException;
037    import org.apache.turbine.services.security.TurbineSecurity;
038    import org.apache.turbine.services.security.torque.om.TurbineUserGroupRolePeer;
039    import org.apache.turbine.util.security.DataBackendException;
040    import org.apache.turbine.util.security.RoleSet;
041    
042    import org.apache.torque.TorqueException;
043    import org.apache.torque.om.Persistent;
044    import org.apache.torque.util.BasePeer;
045    import org.apache.torque.util.Criteria;
046    
047    /**
048     * This class capsulates all direct Peer access for the Role entities.
049     * It allows the exchange of the default Turbine supplied TurbineRolePeer
050     * class against a custom class
051     *
052     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
053     * @version $Id: RolePeerManager.java 1096130 2011-04-23 10:37:19Z ludwig $
054     */
055    
056    public class RolePeerManager
057        implements RolePeerManagerConstants
058    {
059        /** The class of the Peer the TorqueSecurityService uses */
060        private static Class rolePeerClass = null;
061    
062        /** The class name of the objects returned by the configured peer. */
063        private static Class roleObject = null;
064    
065        /** The name of the Table used for Role Object queries  */
066        private static String tableName = null;
067    
068        /** The name of the column used as "Name" Column */
069        private static String nameColumn = null;
070    
071        /** The name of the column used as "Id" Column */
072        private static String idColumn = null;
073    
074        /** The "Name" property descriptor */
075        private static PropertyDescriptor namePropDesc = null;
076    
077        /** The "Id" property descriptor */
078        private static PropertyDescriptor idPropDesc = null;
079    
080        /** Logging */
081        static Log log = LogFactory.getLog(RolePeerManager.class);
082    
083        /**
084         * Initializes the RolePeerManager, loading the class object for the
085         * Peer used to retrieve Role objects
086         *
087         * @param conf The configuration object used to configure the Manager
088         *
089         * @exception InitializationException A problem occured during
090         *            initialization
091         */
092    
093        public static void init(Configuration conf)
094            throws InitializationException
095        {
096            String rolePeerClassName = conf.getString(ROLE_PEER_CLASS_KEY,
097                                                      ROLE_PEER_CLASS_DEFAULT);
098    
099            String roleObjectName = null;
100    
101            try
102            {
103                rolePeerClass = Class.forName(rolePeerClassName);
104    
105                tableName  =
106                  (String) rolePeerClass.getField("TABLE_NAME").get(null);
107    
108                //
109                // We have either an user configured Object class or we use the
110                // default as supplied by the Peer class
111                //
112    
113                // Default from Peer, can be overridden
114    
115                roleObject = getPersistenceClass();
116    
117                roleObjectName = conf.getString(ROLE_CLASS_KEY,
118                        roleObject.getName());
119    
120                // Maybe the user set a new value...
121                roleObject = Class.forName(roleObjectName);
122    
123                /* If any of the following Field queries fails, the role
124                 * subsystem is unusable. So check this right here at init time,
125                 * which saves us much time and hassle if it fails...
126                 */
127    
128                nameColumn = (String) rolePeerClass.getField(
129                        conf.getString(ROLE_NAME_COLUMN_KEY,
130                                       ROLE_NAME_COLUMN_DEFAULT)
131                        ).get(null);
132    
133                idColumn = (String) rolePeerClass.getField(
134                        conf.getString(ROLE_ID_COLUMN_KEY,
135                                       ROLE_ID_COLUMN_DEFAULT)
136                        ).get(null);
137    
138                namePropDesc = new PropertyDescriptor(
139                        conf.getString(ROLE_NAME_PROPERTY_KEY,
140                                       ROLE_NAME_PROPERTY_DEFAULT),
141                        roleObject);
142    
143                idPropDesc = new PropertyDescriptor(
144                        conf.getString(ROLE_ID_PROPERTY_KEY,
145                                       ROLE_ID_PROPERTY_DEFAULT),
146                        roleObject);
147    
148            }
149            catch (Exception e)
150            {
151                if (rolePeerClassName == null || rolePeerClass == null)
152                {
153                    throw new InitializationException(
154                        "Could not find RolePeer class ("
155                        + rolePeerClassName + ")", 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 (roleObject == null || roleObjectName == 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                        "RolePeer " + rolePeerClassName
174                        + " has no name column information!", e);
175                }
176                if (idColumn == null || idPropDesc == null)
177                {
178                    throw new InitializationException(
179                        "RolePeer " + rolePeerClassName
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 role
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 role
209         *
210         * @return A String containing the column id
211         */
212        public static String getIdColumn()
213        {
214            return idColumn;
215        }
216    
217        /**
218         * Returns the full name of a column.
219         *
220         * @param name The column to fully qualify
221         *
222         * @return A String with the full name of the column.
223         */
224        public static String getColumnName(String name)
225        {
226            StringBuffer sb = new StringBuffer();
227            sb.append(getTableName());
228            sb.append(".");
229            sb.append(name);
230            return sb.toString();
231        }
232    
233        /**
234         * Returns a new, empty object for the underlying peer.
235         * Used to create a new underlying object
236         *
237         * @return A new object which is compatible to the Peer
238         *         and can be used as a User object
239         *
240         */
241    
242        public static Persistent newPersistentInstance()
243        {
244            Persistent obj = null;
245    
246            if (roleObject == null)
247            {
248                // This can happen if the Turbine wants to determine the
249                // name of the anonymous user before the security service
250                // has been initialized. In this case, the Peer Manager
251                // has not yet been inited and the roleObject is still
252                // null. Return null in this case.
253                //
254                return obj;
255            }
256    
257            try
258            {
259                obj = (Persistent) roleObject.newInstance();
260            }
261            catch (Exception e)
262            {
263                log.error("Could not instantiate a role object", e);
264                obj = null;
265            }
266            return obj;
267        }
268    
269        /**
270         * Retrieves/assembles a RoleSet based on the Criteria passed in
271         *
272         * @param criteria A criteria containing a pre-assembled set of criterias
273         *         for the RoleSet
274         *
275         * @return A Set of roles which fulfil the required criterias
276         *
277         * @exception Exception A generic exception.
278         *
279         */
280        public static RoleSet retrieveSet(Criteria criteria)
281            throws Exception
282        {
283            List results = doSelect(criteria);
284            RoleSet rs = new RoleSet();
285    
286            for (Iterator it = results.iterator(); it.hasNext(); )
287            {
288                rs.add((Role) it.next());
289            }
290            return rs;
291        }
292    
293        /**
294         * Retrieves a set of Roles that an User was assigned in a Group
295         *
296         * @param user An user object
297         * @param group A group object
298         *
299         * @return A Set of Roles of this User in the Group
300         *
301         * @exception Exception A generic exception.
302         */
303        public static RoleSet retrieveSet(User user, Group group)
304            throws Exception
305        {
306            Criteria criteria = new Criteria();
307    
308            criteria.add(UserPeerManager.getNameColumn(),
309                         user.getName());
310    
311            criteria.add(TurbineUserGroupRolePeer.GROUP_ID,
312                         ((Persistent) group).getPrimaryKey());
313    
314            criteria.addJoin(UserPeerManager.getIdColumn(),
315                             TurbineUserGroupRolePeer.USER_ID);
316    
317            criteria.addJoin(TurbineUserGroupRolePeer.ROLE_ID, getIdColumn());
318    
319            return retrieveSet(criteria);
320        }
321    
322        /**
323         * Checks if a Role is defined in the system. The name
324         * is used as query criteria.
325         *
326         * @param role The Role to be checked.
327         * @return <code>true</code> if given Role exists in the system.
328         * @throws DataBackendException when more than one Role with
329         *         the same name exists.
330         * @throws Exception A generic exception.
331         */
332        public static boolean checkExists(Role role)
333            throws DataBackendException, Exception
334        {
335            Criteria criteria = new Criteria();
336    
337            criteria.addSelectColumn(getIdColumn());
338    
339            criteria.add(getNameColumn(), role.getName());
340    
341            List results = BasePeer.doSelect(criteria);
342    
343            if (results.size() > 1)
344            {
345                throw new DataBackendException("Multiple roles named '" +
346                                               role.getName() + "' exist!");
347            }
348            return (results.size() == 1);
349        }
350    
351        /*
352         * ========================================================================
353         *
354         * WARNING! Do not read on if you have a weak stomach. What follows here
355         * are some abominations thanks to the braindead static peers of Torque
356         * and the rigidity of Java....
357         *
358         * ========================================================================
359         *
360         */
361    
362        /**
363         * Calls buildCriteria(Role role) in the configured RolePeer. If you get
364         * a ClassCastException in this routine, you put a Role object into this
365         * method which can't be cast into an object for the TorqueSecurityService. This is a
366         * configuration error most of the time.
367         *
368         * @param role An object which implements the Role interface
369         *
370         * @return A criteria for the supplied role object
371         */
372    
373        public static Criteria buildCriteria(Role role)
374        {
375            Criteria crit;
376    
377            try
378            {
379                Class[] clazz = new Class[] { roleObject };
380                Object[] params =
381                    new Object[] { ((TorqueRole) role).getPersistentObj() };
382    
383                crit =  (Criteria) rolePeerClass
384                    .getMethod("buildCriteria", clazz)
385                    .invoke(null, params);
386            }
387            catch (Exception e)
388            {
389                crit = null;
390            }
391    
392            return crit;
393        }
394    
395        /**
396         * Invokes doUpdate(Criteria c) on the configured Peer Object
397         *
398         * @param criteria  A Criteria Object
399         *
400         * @exception TorqueException A problem occured.
401         */
402    
403        public static void doUpdate(Criteria criteria)
404            throws TorqueException
405        {
406            try
407            {
408                Class[] clazz = new Class[] { Criteria.class };
409                Object[] params = new Object[] { criteria };
410    
411                rolePeerClass
412                    .getMethod("doUpdate", clazz)
413                    .invoke(null, params);
414            }
415            catch (Exception e)
416            {
417                throw new TorqueException("doUpdate failed", e);
418            }
419        }
420    
421        /**
422         * Invokes doInsert(Criteria c) on the configured Peer Object
423         *
424         * @param criteria  A Criteria Object
425         *
426         * @exception TorqueException A problem occured.
427         */
428    
429        public static void doInsert(Criteria criteria)
430            throws TorqueException
431        {
432            try
433            {
434                Class[] clazz = new Class[] { Criteria.class };
435                Object[] params = new Object[] { criteria };
436    
437                rolePeerClass
438                    .getMethod("doInsert", clazz)
439                    .invoke(null, params);
440            }
441            catch (Exception e)
442            {
443                throw new TorqueException("doInsert failed", e);
444            }
445        }
446    
447        /**
448         * Invokes doSelect(Criteria c) on the configured Peer Object
449         *
450         * @param criteria  A Criteria Object
451         *
452         * @return A List of Role Objects selected by the Criteria
453         *
454         * @exception TorqueException A problem occured.
455         */
456        public static List doSelect(Criteria criteria)
457            throws TorqueException
458        {
459            List list;
460    
461            try
462            {
463                Class[] clazz =
464                    new Class[] { Criteria.class };
465                Object[] params = new Object[] { criteria };
466    
467                list = (List) rolePeerClass
468                    .getMethod("doSelect", clazz)
469                    .invoke(null, params);
470            }
471            catch (Exception e)
472            {
473                throw new TorqueException("doSelect failed", e);
474            }
475            List newList = new ArrayList(list.size());
476    
477            //
478            // Wrap the returned Objects into TorqueRoles.
479            //
480            for (Iterator it = list.iterator(); it.hasNext(); )
481            {
482                Role r = getNewRole((Persistent) it.next());
483                newList.add(r);
484            }
485    
486            return newList;
487        }
488    
489        /**
490         * Invokes doDelete(Criteria c) on the configured Peer Object
491         *
492         * @param criteria  A Criteria Object
493         *
494         * @exception TorqueException A problem occured.
495         */
496        public static void doDelete(Criteria criteria)
497            throws TorqueException
498        {
499            try
500            {
501                Class[] clazz = new Class[] { Criteria.class };
502                Object[] params = new Object[] { criteria };
503    
504                rolePeerClass
505                    .getMethod("doDelete", clazz)
506                    .invoke(null, params);
507            }
508            catch (Exception e)
509            {
510                throw new TorqueException("doDelete failed", e);
511            }
512        }
513    
514        /**
515         * Invokes setName(String s) on the supplied base object
516         *
517         * @param obj The object to use for setting the name
518         * @param name The Name to set
519         *
520         */
521        public static void setRoleName(Persistent obj, String name)
522        {
523            if (obj == null)
524            {
525                return;
526            }
527    
528            try
529            {
530                Object[] params = new Object[] { name };
531                namePropDesc.getWriteMethod().invoke(obj, params);
532            }
533            catch (ClassCastException cce)
534            {
535                String msg = obj.getClass().getName() + " does not seem to be a Role Object!";
536                log.error(msg);
537                throw new RuntimeException(msg);
538            }
539            catch (Exception e)
540            {
541                log.error(e, e);
542            }
543        }
544    
545        /**
546         * Invokes getName() on the supplied base object
547         *
548         * @param obj The object to use for getting the name
549         *
550         * @return A string containing the name
551         */
552        public static String getRoleName(Persistent obj)
553        {
554            String name = null;
555    
556            if (obj == null)
557            {
558                return null;
559            }
560    
561            try
562            {
563                name = (String) namePropDesc
564                    .getReadMethod()
565                    .invoke(obj, new Object[] {});
566            }
567            catch (ClassCastException cce)
568            {
569                String msg = obj.getClass().getName() + " does not seem to be a Role Object!";
570                log.error(msg);
571                throw new RuntimeException(msg);
572            }
573            catch (Exception e)
574            {
575                log.error(e, e);
576            }
577            return name;
578        }
579    
580        /**
581         * Invokes setId(int n) on the supplied base object
582         *
583         * @param obj The object to use for setting the name
584         * @param id The new Id
585         */
586        public static void setId(Persistent obj, int id)
587        {
588            if (obj == null)
589            {
590                return;
591            }
592    
593            try
594            {
595                Object[] params = new Object[] { Integer.TYPE };
596                idPropDesc.getWriteMethod().invoke(obj, params);
597            }
598            catch (ClassCastException cce)
599            {
600                String msg = obj.getClass().getName() + " does not seem to be a Role Object!";
601                log.error(msg);
602                throw new RuntimeException(msg);
603            }
604            catch (Exception e)
605            {
606                log.error(e, e);
607            }
608        }
609    
610        /**
611         * Invokes getId() on the supplied base object
612         *
613         * @param obj The object to use for getting the id
614         *
615         * @return The Id of this object
616         */
617        public static Integer getIdAsObj(Persistent obj)
618        {
619            Integer id = null;
620    
621            if (obj == null)
622            {
623                return new Integer(0);
624            }
625    
626            try
627            {
628                id = (Integer) idPropDesc
629                    .getReadMethod()
630                    .invoke(obj, new Object[] {});
631            }
632            catch (ClassCastException cce)
633            {
634                String msg = obj.getClass().getName() + " does not seem to be a Role Object!";
635                log.error(msg);
636                throw new RuntimeException(msg);
637            }
638            catch (Exception e)
639            {
640                log.error(e, e);
641            }
642            return id;
643        }
644    
645        /**
646         * Returns the Class of the configured Object class
647         * from the peer
648         *
649         * @return The class of the objects returned by the configured peer
650         */
651    
652        private static Class getPersistenceClass()
653        {
654            Class persistenceClass = null;
655    
656            try
657            {
658                Object[] params = new Object[0];
659    
660                persistenceClass =  (Class) rolePeerClass
661                    .getMethod("getOMClass", (Class[])null)
662                    .invoke(null, params);
663            }
664            catch (Exception e)
665            {
666                persistenceClass = null;
667            }
668    
669            return persistenceClass;
670        }
671    
672    
673        /**
674         * Returns a new, configured Role Object with
675         * a supplied Persistent object at its core
676         *
677         * @param p The persistent object
678         *
679         * @return a new, configured Role Object
680         *
681         * @exception Exception Could not create a new Object
682         *
683         */
684    
685        public static Role getNewRole(Persistent p)
686        {
687            Role r = null;
688            try
689            {
690                Class roleWrapperClass = TurbineSecurity.getRoleClass();
691    
692                Class [] clazz = new Class [] { Persistent.class };
693                Object [] params = new Object [] { p };
694    
695                r = (Role) roleWrapperClass
696                    .getConstructor(clazz)
697                    .newInstance(params);
698            }
699            catch (Exception e)
700            {
701                log.error("Could not instantiate a new role from supplied persistent: ", e);
702            }
703    
704            return r;
705        }
706    }
707