    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.Enumeration;
    027    import java.util.List;
    028    import java.util.Vector;
    029
    030    import org.apache.commons.configuration.Configuration;
    031
    032    import org.apache.commons.logging.Log;
    033    import org.apache.commons.logging.LogFactory;
    034
    035    import org.apache.turbine.om.security.Permission;
    036    import org.apache.turbine.om.security.Role;
    037    import org.apache.turbine.services.InitializationException;
    038    import org.apache.turbine.services.security.TurbineSecurity;
    039    import org.apache.turbine.services.security.torque.om.TurbineRolePermissionPeer;
    040    import org.apache.turbine.util.security.DataBackendException;
    041    import org.apache.turbine.util.security.PermissionSet;
    042
    043    import org.apache.torque.TorqueException;
    044    import org.apache.torque.om.Persistent;
    045    import org.apache.torque.util.BasePeer;
    046    import org.apache.torque.util.Criteria;
    047
    048    /**
    049     * This class capsulates all direct Peer access for the Permission entities.
    050     * It allows the exchange of the default Turbine supplied TurbinePermissionPeer
    051     * class against a custom class.
    052     *
    053     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    054     * @version $Id: PermissionPeerManager.java 1096130 2011-04-23 10:37:19Z ludwig $
    055     *
    056     */
    057
    058    public class PermissionPeerManager
    059        implements PermissionPeerManagerConstants
    060    {
    061        /** The class of the Peer the TorqueSecurityService uses */
    062        private static Class persistentPeerClass = null;
    063
    064        /** The class name of the objects returned by the configured peer. */
    065        private static Class permissionObject = null;
    066
    067        /** The name of the Table used for Permission Object queries  */
    068        private static String tableName = null;
    069
    070        /** The name of the column used as "Name" Column */
    071        private static String nameColumn = null;
    072
    073        /** The name of the column used as "Id" Column */
    074        private static String idColumn = null;
    075
    076        /** The "Name" property descriptor */
    077        private static PropertyDescriptor namePropDesc = null;
    078
    079        /** The "Id" property descriptor */
    080        private static PropertyDescriptor idPropDesc = null;
    081
    082        /** Logging */
    083        static Log log = LogFactory.getLog(PermissionPeerManager.class);
    084
    085        /**
    086         * Initializes the PermissionPeerManager, loading the class object for the
    087         * Peer used to retrieve Permission objects
    088         *
    089         * @param conf The configuration object used to configure the Manager
    090         *
    091         * @exception InitializationException A problem occured during initialization
    092         */
    093
    094        public static void init(Configuration conf)
    095            throws InitializationException
    096        {
    097            String persistentPeerClassName =
    098                conf.getString(PERMISSION_PEER_CLASS_KEY,
    099                               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