001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.fp.dataaccess;
017    
018    import java.util.Map;
019    
020    import org.apache.ojb.broker.PersistenceBroker;
021    import org.apache.ojb.broker.PersistenceBrokerException;
022    import org.apache.ojb.broker.PersistenceBrokerFactory;
023    import org.apache.ojb.broker.accesslayer.RowReaderDefaultImpl;
024    import org.apache.ojb.broker.metadata.ClassDescriptor;
025    
026    /**
027     * (Inspired by example posted at http://nagoya.apache.org/eyebrowse/ReadMsg?listName=ojb-user@db.apache.org&msgId=749837) This
028     * class enables mapping multiple (presumably similar) classes to a single database table. Subclasses must implement the
029     * getDiscriminatorColumns method, returning a String array of columns to consider when determining which class to return, as well
030     * as implement the corresponding chooseClass method that acts on received values for those columns. Sample OBJ config:
031     * <class-descriptor class="org.kuali.bo.ClassA" table="some_common_table" row-reader="org.kuali.dao.ojb.ClassADiscriminator"> ...
032     * </class-descriptor> <class-descriptor class="org.kuali.bo.ClassB" table="some_common_table"
033     * row-reader="org.kuali.dao.ojb.ClassBDiscriminator"> ... </class-descriptor> (where ClassADiscriminator and ClassBDiscriminator
034     * extend PolymorphicMultiColumnDiscriminator)
035     */
036    public abstract class PolymorphicMultiColumnDiscriminator extends RowReaderDefaultImpl {
037    
038        /** Column(s) that distinguish the parent class */
039        private String[] column = null;
040    
041        public PolymorphicMultiColumnDiscriminator(ClassDescriptor cld) {
042            super(cld);
043            column = getDiscriminatorColumns();
044        }
045    
046        /**
047         * This method should return the column(s) necessary to determine which class to cast to.
048         * 
049         * @return one or more column names
050         */
051        public abstract String[] getDiscriminatorColumns();
052    
053        /**
054         * Based on the received key values, this method determines the appropriate class.
055         * 
056         * @param values
057         * @return an appropriately chosen class
058         */
059        public abstract Class chooseClass(String[] values);
060    
061        protected ClassDescriptor selectClassDescriptor(Map row) throws PersistenceBrokerException {
062            String[] key = new String[column.length];
063    
064            for (int i = 0; i < column.length; i++) {
065                key[i] = (String) row.get(column[i]);
066            }
067    
068            Class clazz = null;
069    
070            if (key != null) {
071                clazz = chooseClass(key);
072            }
073            if (clazz == null) {
074                return getClassDescriptor();
075            }
076    
077            PersistenceBroker broker = null;
078            try {
079                broker = PersistenceBrokerFactory.defaultPersistenceBroker();
080                ClassDescriptor result = broker.getClassDescriptor(clazz);
081                broker.close();
082                if (result == null) {
083                    return getClassDescriptor();
084                }
085                else {
086                    return result;
087                }
088            }
089            catch (PersistenceBrokerException e) {
090                broker.close();
091                throw e;
092            }
093        }
094    
095    }