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.torque.TorqueException;
034    import org.apache.torque.om.Persistent;
035    import org.apache.torque.util.BasePeer;
036    import org.apache.torque.util.Criteria;
037    
038    import org.apache.turbine.om.security.Group;
039    import org.apache.turbine.services.InitializationException;
040    import org.apache.turbine.services.security.TurbineSecurity;
041    import org.apache.turbine.util.security.DataBackendException;
042    import org.apache.turbine.util.security.GroupSet;
043    
044    /**
045     * This class capsulates all direct Peer access for the Group entities.
046     * It allows the exchange of the default Turbine supplied TurbineGroupPeer
047     * class against a custom class.
048     *
049     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
050     * @version $Id: GroupPeerManager.java 1096130 2011-04-23 10:37:19Z ludwig $
051     *
052     */
053    public class GroupPeerManager
054        implements GroupPeerManagerConstants
055    {
056        /** The class of the Peer the TorqueSecurityService uses */
057        private static Class groupPeerClass = null;
058    
059        /** The class name of the objects returned by the configured peer. */
060        private static Class groupObject = null;
061    
062        /** The name of the Table used for Group Object queries  */
063        private static String tableName = null;
064    
065        /** The name of the column used as "Name" Column */
066        private static String nameColumn = null;
067    
068        /** The name of the column used as "Id" Column */
069        private static String idColumn = null;
070    
071        /** The "Name" property descriptor */
072        private static PropertyDescriptor namePropDesc = null;
073    
074        /** The "Id" property descriptor */
075        private static PropertyDescriptor idPropDesc = null;
076    
077        /** Logging */
078        static Log log = LogFactory.getLog(GroupPeerManager.class);
079    
080        /**
081         * Initializes the GroupPeerManager, loading the class object for the
082         * Peer used to retrieve Group objects
083         *
084         * @param conf The configuration object used to configure the Manager
085         *
086         * @exception InitializationException A problem occured during initialization
087         */
088    
089        public static void init(Configuration conf)
090            throws InitializationException
091        {
092            String groupPeerClassName = conf.getString(GROUP_PEER_CLASS_KEY,
093                                                       GROUP_PEER_CLASS_DEFAULT);
094            String groupObjectName = null;
095    
096            try
097            {
098                groupPeerClass = Class.forName(groupPeerClassName);
099    
100                tableName  = (String) groupPeerClass.getField("TABLE_NAME").get(null);
101    
102                //
103                // We have either an user configured Object class or we use the default
104                // as supplied by the Peer class
105                //
106                groupObject = getPersistenceClass(); // Default from Peer, can be overridden
107    
108                groupObjectName = conf.getString(GROUP_CLASS_KEY,
109                        groupObject.getName());
110    
111                groupObject = Class.forName(groupObjectName); // Maybe the user set a new value...
112    
113                // If any of the following Field queries fails, the group subsystem
114                // is unusable. So check this right here at init time, which saves
115                // us much time and hassle if it fails...
116                nameColumn = (String) groupPeerClass.getField(conf
117                        .getString(GROUP_NAME_COLUMN_KEY, GROUP_NAME_COLUMN_DEFAULT)
118                        ).get(null);
119    
120                idColumn = (String) groupPeerClass.getField(conf
121                        .getString(GROUP_ID_COLUMN_KEY, GROUP_ID_COLUMN_DEFAULT)
122                        ).get(null);
123    
124                namePropDesc = new PropertyDescriptor(conf
125                        .getString(GROUP_NAME_PROPERTY_KEY,
126                        GROUP_NAME_PROPERTY_DEFAULT), groupObject);
127    
128                idPropDesc = new PropertyDescriptor(conf
129                        .getString(GROUP_ID_PROPERTY_KEY,
130                        GROUP_ID_PROPERTY_DEFAULT), groupObject);
131            }
132            catch (Exception e)
133            {
134                if (groupPeerClassName == null || groupPeerClass == null)
135                {
136                    throw new InitializationException(
137                        "Could not find GroupPeer class ("
138                        + groupPeerClassName + ")", e);
139                }
140                if (tableName == null)
141                {
142                    throw new InitializationException(
143                        "Failed to get the table name from the Peer object", e);
144                }
145    
146                if (groupObject == null || groupObjectName == null)
147                {
148                    throw new InitializationException(
149                        "Failed to get the object type from the Peer object", e);
150                }
151    
152                if (nameColumn == null || namePropDesc == null)
153                {
154                    throw new InitializationException(
155                        "GroupPeer " + groupPeerClassName + " has no name column information!", e);
156                }
157                if (idColumn == null || idPropDesc == null)
158                {
159                    throw new InitializationException(
160                        "GroupPeer " + groupPeerClassName + " has no id column information!", e);
161                }
162            }
163        }
164    
165        /**
166         * Get the name of this table.
167         *
168         * @return A String with the name of the table.
169         */
170        public static String getTableName()
171        {
172            return tableName;
173        }
174    
175        /**
176         * Returns the fully qualified name of the Column to
177         * use as the Name Column for a group
178         *
179         * @return A String containing the column name
180         */
181        public static String getNameColumn()
182        {
183            return nameColumn;
184        }
185    
186        /**
187         * Returns the fully qualified name of the Column to
188         * use as the Id Column for a group
189         *
190         * @return A String containing the column id
191         */
192        public static String getIdColumn()
193        {
194            return idColumn;
195        }
196    
197        /**
198         * Returns the full name of a column.
199         *
200         * @param name The column to fully qualify
201         *
202         * @return A String with the full name of the column.
203         */
204        public static String getColumnName(String name)
205        {
206            StringBuffer sb = new StringBuffer();
207            sb.append(getTableName());
208            sb.append(".");
209            sb.append(name);
210            return sb.toString();
211        }
212    
213        /**
214         * Returns a new, empty object for the underlying peer.
215         * Used to create a new underlying object
216         *
217         * @return A new object which is compatible to the Peer
218         *         and can be used as a Group object
219         *
220         */
221    
222        public static Persistent newPersistentInstance()
223        {
224            Persistent obj = null;
225    
226            if(groupObject == null)
227            {
228                // This can happen if the Turbine wants to determine the
229                // name of the anonymous user before the security service
230                // has been initialized. In this case, the Peer Manager
231                // has not yet been inited and the groupObject is still
232                // null. Return null in this case.
233                //
234                return obj;
235            }
236    
237            try
238            {
239                obj = (Persistent) groupObject.newInstance();
240            }
241            catch (Exception e)
242            {
243                log.error("Could not instantiate a group object", e);
244                obj = null;
245            }
246            return obj;
247        }
248    
249        /**
250         * Retrieves/assembles a GroupSet of all of the Groups.
251         *
252         * @return A set of all the Groups in the system
253         * @exception Exception A generic exception.
254         */
255        public static GroupSet retrieveSet()
256            throws Exception
257        {
258            return retrieveSet(new Criteria());
259        }
260    
261        /**
262         * Retrieves/assembles a GroupSet based on the Criteria passed in
263         *
264         * @param criteria A criteria containing a pre-assembled set of criterias
265         *                 for the GroupSet
266         *
267         * @return A Set of groups which fulfil the required criterias
268         *
269         * @exception Exception A generic exception
270         *
271         */
272        public static GroupSet retrieveSet(Criteria criteria)
273            throws Exception
274        {
275            List results = doSelect(criteria);
276            GroupSet gs = new GroupSet();
277    
278            for(Iterator it = results.iterator(); it.hasNext(); )
279            {
280                gs.add((Group) it.next());
281            }
282            return gs;
283        }
284    
285        /**
286         * Checks if a Group is defined in the system. The name
287         * is used as query criteria.
288         *
289         * @param group The Group to be checked.
290         * @return <code>true</code> if given Group exists in the system.
291         * @throws DataBackendException when more than one Group with
292         *         the same name exists.
293         * @throws Exception A generic exception.
294         */
295        public static boolean checkExists(Group group)
296            throws DataBackendException, Exception
297        {
298            Criteria criteria = new Criteria();
299    
300            criteria.addSelectColumn(getIdColumn());
301    
302            criteria.add(getNameColumn(), group.getName());
303    
304            List results = BasePeer.doSelect(criteria);
305    
306            if (results.size() > 1)
307            {
308                throw new DataBackendException("Multiple groups named '" +
309                                               group.getName() + "' exist!");
310            }
311    
312            return (results.size() == 1);
313        }
314    
315        /*
316         * ========================================================================
317         *
318         * WARNING! Do not read on if you have a weak stomach. What follows here
319         * are some abominations thanks to the braindead static peers of Torque
320         * and the rigidity of Java....
321         *
322         * ========================================================================
323         *
324         */
325    
326        /**
327         * Calls buildCriteria(Group group) in the configured GroupPeer. If you get
328         * a ClassCastException in this routine, you put a Group object into this
329         * method which can't be cast into an object for the TorqueSecurityService. This is a
330         * configuration error most of the time.
331         *
332         * @param group An object which implements the Group interface
333         *
334         * @return A criteria for the supplied group object
335         */
336    
337        public static Criteria buildCriteria(Group group)
338        {
339            Criteria crit;
340    
341            try
342            {
343                Class[] clazz = new Class[] { groupObject };
344                Object[] params =
345                  new Object[] { ((TorqueGroup) group).getPersistentObj() };
346    
347                crit =  (Criteria) groupPeerClass
348                    .getMethod("buildCriteria", clazz)
349                    .invoke(null, params);
350            }
351            catch (Exception e)
352            {
353                crit = null;
354            }
355    
356            return crit;
357        }
358    
359        /**
360         * Invokes doUpdate(Criteria c) on the configured Peer Object
361         *
362         * @param criteria  A Criteria Object
363         *
364         * @exception TorqueException A problem occured.
365         */
366    
367        public static void doUpdate(Criteria criteria)
368            throws TorqueException
369        {
370            try
371            {
372                Class[] clazz = new Class[] { Criteria.class };
373                Object[] params = new Object[] { criteria };
374    
375                groupPeerClass
376                    .getMethod("doUpdate", clazz)
377                    .invoke(null, params);
378            }
379            catch (Exception e)
380            {
381                throw new TorqueException("doUpdate failed", e);
382            }
383        }
384    
385        /**
386         * Invokes doInsert(Criteria c) on the configured Peer Object
387         *
388         * @param criteria  A Criteria Object
389         *
390         * @exception TorqueException A problem occured.
391         */
392    
393        public static void doInsert(Criteria criteria)
394            throws TorqueException
395        {
396            try
397            {
398                Class[] clazz = new Class[] { Criteria.class };
399                Object[] params = new Object[] { criteria };
400    
401                groupPeerClass
402                    .getMethod("doInsert", clazz)
403                    .invoke(null, params);
404            }
405            catch (Exception e)
406            {
407                throw new TorqueException("doInsert failed", e);
408            }
409        }
410    
411        /**
412         * Invokes doSelect(Criteria c) on the configured Peer Object
413         *
414         * @param criteria  A Criteria Object
415         *
416         * @return A List of Group Objects selected by the Criteria
417         *
418         * @exception TorqueException A problem occured.
419         */
420        public static List doSelect(Criteria criteria)
421            throws TorqueException
422        {
423            List list;
424    
425            try
426            {
427                Class[] clazz = new Class[] { Criteria.class };
428                Object[] params = new Object[] { criteria };
429    
430                list = (List) groupPeerClass
431                    .getMethod("doSelect", clazz)
432                    .invoke(null, params);
433            }
434            catch (Exception e)
435            {
436                throw new TorqueException("doSelect failed", e);
437            }
438            List newList = new ArrayList(list.size());
439    
440            //
441            // Wrap the returned Objects into the configured Peer Objects.
442            //
443            for (Iterator it = list.iterator(); it.hasNext(); )
444            {
445                Group dr = getNewGroup((Persistent) it.next());
446                newList.add(dr);
447            }
448    
449            return newList;
450        }
451    
452        /**
453         * Invokes doDelete(Criteria c) on the configured Peer Object
454         *
455         * @param criteria  A Criteria Object
456         *
457         * @exception TorqueException A problem occured.
458         */
459        public static void doDelete(Criteria criteria)
460            throws TorqueException
461        {
462            try
463            {
464                Class[] clazz =
465                  new Class[] { Criteria.class };
466                Object[] params = new Object[] { criteria };
467    
468                groupPeerClass
469                    .getMethod("doDelete", clazz)
470                    .invoke(null, params);
471            }
472            catch (Exception e)
473            {
474                throw new TorqueException("doDelete failed", e);
475            }
476        }
477    
478        /**
479         * Invokes setName(String s) on the supplied base object
480         *
481         * @param obj The object to use for setting the name
482         *
483         * @param name The Name to set
484         */
485        public static void setGroupName(Persistent obj, String name)
486        {
487            if(obj == null)
488            {
489                return;
490            }
491    
492            try
493            {
494                Object[] params = new Object[] { name };
495                namePropDesc.getWriteMethod().invoke(obj, params);
496            }
497            catch (ClassCastException cce)
498            {
499                String msg = obj.getClass().getName() + " does not seem to be a Group Object!";
500                log.error(msg);
501                throw new RuntimeException(msg);
502            }
503            catch (Exception e)
504            {
505                log.error(e, e);
506            }
507        }
508    
509        /**
510         * Invokes getName() on the supplied base object
511         *
512         * @param obj The object to use for getting the name
513         *
514         * @return A string containing the name
515         */
516        public static String getGroupName(Persistent obj)
517        {
518            String name = null;
519    
520            if(obj == null)
521            {
522                return null;
523            }
524    
525            try
526            {
527                name = (String) namePropDesc
528                    .getReadMethod()
529                    .invoke(obj, new Object[] {});
530            }
531            catch (ClassCastException cce)
532            {
533                String msg = obj.getClass().getName() + " does not seem to be a Group Object!";
534                log.error(msg);
535                throw new RuntimeException(msg);
536            }
537            catch (Exception e)
538            {
539                log.error(e, e);
540            }
541            return name;
542        }
543    
544        /**
545         * Invokes setId(int n) on the supplied base object
546         *
547         * @param obj The object to use for setting the name
548         * @param id The new Id
549         */
550        public static void setId(Persistent obj, int id)
551        {
552            if(obj == null)
553            {
554                return;
555            }
556    
557            try
558            {
559                Object[] params = new Object[] { Integer.TYPE };
560                idPropDesc.getWriteMethod().invoke(obj, params);
561            }
562            catch (ClassCastException cce)
563            {
564                String msg = obj.getClass().getName() + " does not seem to be a Group Object!";
565                log.error(msg);
566                throw new RuntimeException(msg);
567            }
568            catch (Exception e)
569            {
570                log.error(e, e);
571            }
572        }
573    
574        /**
575         * Invokes getId() on the supplied base object
576         *
577         * @param obj The object to use for getting the id
578         *
579         * @return The Id of this object
580         */
581        public static Integer getIdAsObj(Persistent obj)
582        {
583            Integer id = null;
584    
585            if(obj == null)
586            {
587                return new Integer(0);
588            }
589    
590            try
591            {
592                id = (Integer) idPropDesc
593                    .getReadMethod()
594                    .invoke(obj, new Object[] {});
595            }
596            catch (ClassCastException cce)
597            {
598                String msg = obj.getClass().getName() + " does not seem to be a Group Object!";
599                log.error(msg);
600                throw new RuntimeException(msg);
601            }
602            catch (Exception e)
603            {
604                log.error(e, e);
605            }
606            return id;
607        }
608    
609        /**
610         * Returns the Class of the configured Object class
611         * from the peer
612         *
613         * @return The class of the objects returned by the configured peer
614         *
615         */
616    
617        private static Class getPersistenceClass()
618        {
619            Class persistenceClass = null;
620    
621            try
622            {
623                Object[] params = new Object[0];
624    
625                persistenceClass =  (Class) groupPeerClass
626                    .getMethod("getOMClass", (Class[])null)
627                    .invoke(null, params);
628            }
629            catch (Exception e)
630            {
631                persistenceClass = null;
632            }
633    
634            return persistenceClass;
635        }
636    
637        /**
638         * Returns a new, configured Group Object with
639         * a supplied Persistent object at its core
640         *
641         * @param p The persistent object
642         *
643         * @return a new, configured Group Object
644         *
645         * @exception Exception Could not create a new Object
646         *
647         */
648    
649        public static Group getNewGroup(Persistent p)
650        {
651            Group g = null;
652            try
653            {
654                Class groupWrapperClass = TurbineSecurity.getGroupClass();
655    
656                Class [] clazz = new Class [] { Persistent.class };
657                Object [] params = new Object [] { p };
658    
659                g = (Group) groupWrapperClass
660                    .getConstructor(clazz)
661                    .newInstance(params);
662            }
663            catch (Exception e)
664            {
665                log.error("Could not instantiate a new group from supplied persistent: ", e);
666            }
667    
668            return g;
669        }
670    }
671