    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