001/*
002 * The Kuali Financial System, a comprehensive financial management system for higher education.
003 * 
004 * Copyright 2005-2014 The Kuali Foundation
005 * 
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU Affero General Public License as
008 * published by the Free Software Foundation, either version 3 of the
009 * License, or (at your option) any later version.
010 * 
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU Affero General Public License for more details.
015 * 
016 * You should have received a copy of the GNU Affero General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.kuali.kfs.sys.dataaccess.impl;
020
021import java.sql.DatabaseMetaData;
022import java.sql.ResultSet;
023import java.sql.SQLException;
024
025import org.apache.commons.beanutils.PropertyUtils;
026import org.apache.log4j.Logger;
027import org.apache.ojb.broker.metadata.ClassDescriptor;
028import org.kuali.kfs.sys.dataaccess.FieldMetaData;
029import org.kuali.rice.core.framework.persistence.ojb.conversion.OjbKualiEncryptDecryptFieldConversion;
030import org.kuali.rice.krad.bo.BusinessObject;
031import org.kuali.rice.krad.bo.PersistableBusinessObject;
032import org.springframework.jdbc.support.DatabaseMetaDataCallback;
033import org.springframework.jdbc.support.MetaDataAccessException;
034
035public class FieldMetaDataImpl implements DatabaseMetaDataCallback, FieldMetaData {
036    private static final Logger LOG = Logger.getLogger(FieldMetaDataImpl.class);
037    
038    private Class businessObjectClass;
039    private String propertyName;
040    
041    private String tableName;
042    private String columnName;
043    private String dataType;
044    private int length;
045    private int decimalPlaces;
046    private boolean encrypted;
047
048    public FieldMetaDataImpl(Class businessObjectClass, String propertyName) {
049        this.businessObjectClass = businessObjectClass;
050        this.propertyName = propertyName;
051    }
052
053    public Object processMetaData(DatabaseMetaData databaseMetaData) throws SQLException, MetaDataAccessException {
054        Class workingBusinessObjectClass = businessObjectClass;
055        String workingPropertyName = propertyName;
056        while (workingPropertyName.contains(".")) {
057            try {
058                workingBusinessObjectClass = org.apache.ojb.broker.metadata.MetadataManager.getInstance().getGlobalRepository().getDescriptorFor(workingBusinessObjectClass).getObjectReferenceDescriptorByName(workingPropertyName.substring(0, workingPropertyName.indexOf("."))).getItemClass();
059            }
060            catch (Exception e1) {
061                LOG.debug(new StringBuffer("Unable to get property type via reference descriptor for property ").append(workingPropertyName.substring(0, workingPropertyName.indexOf("."))).append(" of BusinessObject class ").append(workingBusinessObjectClass).toString(), e1);
062                try {
063                    workingBusinessObjectClass = org.apache.ojb.broker.metadata.MetadataManager.getInstance().getGlobalRepository().getDescriptorFor(workingBusinessObjectClass).getCollectionDescriptorByName(workingPropertyName.substring(0, workingPropertyName.indexOf("."))).getItemClass();                        
064                }
065                catch (Exception e2) {
066                    LOG.debug(new StringBuffer("Unable to get property type via collection descriptor of property ").append(workingPropertyName.substring(0, workingPropertyName.indexOf("."))).append(" of BusinessObject class ").append(workingBusinessObjectClass).toString(), e2);
067                    BusinessObject businessObject = null;
068                    try {
069                        businessObject = (BusinessObject)workingBusinessObjectClass.newInstance();
070                    }
071                    catch (Exception e3) {
072                        if (LOG.isDebugEnabled()) {
073                            LOG.debug("Unable to instantiate BusinessObject class " + workingBusinessObjectClass, e3);
074                        }
075                        return populateAndReturnNonPersistableInstance();
076                    }
077                    try {
078                        workingBusinessObjectClass = PropertyUtils.getPropertyType(businessObject, workingPropertyName.substring(0, workingPropertyName.indexOf(".")));
079                    }
080                    catch (Exception e4) {
081                        LOG.debug(new StringBuffer("Unable to get type of property ").append(workingPropertyName.substring(0, workingPropertyName.indexOf("."))).append(" for BusinessObject class ").append(workingBusinessObjectClass).toString(), e4);
082                        return populateAndReturnNonPersistableInstance();
083                    }
084                }
085            }
086            if (workingBusinessObjectClass == null) {
087                return populateAndReturnNonPersistableInstance();
088            }
089            else {
090                workingPropertyName = workingPropertyName.substring(workingPropertyName.indexOf(".") + 1);
091            }
092        }
093        if (!PersistableBusinessObject.class.isAssignableFrom(workingBusinessObjectClass)) {
094            return populateAndReturnNonPersistableInstance();
095        }
096        ClassDescriptor classDescriptor = org.apache.ojb.broker.metadata.MetadataManager.getInstance().getGlobalRepository().getDescriptorFor(workingBusinessObjectClass);
097        if (classDescriptor == null) {
098            return populateAndReturnNonPersistableInstance();
099        }
100        tableName = classDescriptor.getFullTableName();
101        if (classDescriptor.getFieldDescriptorByName(workingPropertyName) == null) {
102            return populateAndReturnNonPersistableInstance();
103        }
104        columnName = classDescriptor.getFieldDescriptorByName(workingPropertyName).getColumnName();
105        ResultSet resultSet = databaseMetaData.getColumns(null, null, tableName, columnName);
106        if (resultSet.next()) {
107            dataType = resultSet.getString("TYPE_NAME");
108            length = resultSet.getInt("COLUMN_SIZE");
109            decimalPlaces = resultSet.getInt("DECIMAL_DIGITS");
110            encrypted = classDescriptor.getFieldDescriptorByName(workingPropertyName).getFieldConversion() instanceof OjbKualiEncryptDecryptFieldConversion;
111        }
112        resultSet.close();
113        return this;
114    }
115    
116    protected FieldMetaData populateAndReturnNonPersistableInstance() {
117        tableName = "N/A";
118        columnName = tableName;
119        dataType = tableName;
120        length = 0;
121        decimalPlaces = 0;
122        encrypted = false;
123        return this;
124    }
125
126    public String getTableName() {
127        return tableName;
128    }
129
130    public String getColumnName() {
131        return columnName;
132    }
133
134    public String getDataType() {
135        return dataType;
136    }
137
138    public int getLength() {
139        return length;
140    }
141
142    public int getDecimalPlaces() {
143        return decimalPlaces;
144    }
145
146    public boolean isEncrypted() {
147        return encrypted;
148    }
149}