001/**
002 * Copyright 2005-2016 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 */
016package org.kuali.rice.krad.service.impl;
017
018import org.apache.ojb.broker.metadata.ClassDescriptor;
019import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
020import org.apache.ojb.broker.metadata.DescriptorRepository;
021import org.apache.ojb.broker.metadata.FieldDescriptor;
022import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
023import org.kuali.rice.core.api.config.property.ConfigContext;
024import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
025import org.kuali.rice.core.framework.persistence.jpa.metadata.EntityDescriptor;
026import org.kuali.rice.core.framework.persistence.jpa.metadata.MetadataManager;
027import org.kuali.rice.core.framework.persistence.jpa.metadata.ObjectDescriptor;
028import org.kuali.rice.core.framework.persistence.ojb.BaseOjbConfigurer;
029import org.kuali.rice.krad.bo.PersistableBusinessObject;
030import org.kuali.rice.krad.bo.PersistableBusinessObjectExtension;
031import org.kuali.rice.krad.exception.ClassNotPersistableException;
032
033import java.util.ArrayList;
034import java.util.List;
035
036public class PersistenceServiceStructureImplBase {
037    protected static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PersistenceServiceStructureImplBase.class);
038        private DescriptorRepository descriptorRepository;
039
040        /**
041         * Constructs a PersistenceServiceImpl instance.
042         */
043        public PersistenceServiceStructureImplBase() {
044                String ojbPropertyFileLocation = ConfigContext.getCurrentContextConfig().getProperty(BaseOjbConfigurer.RICE_OJB_PROPERTIES_PARAM);
045        String currentValue = System.getProperty(BaseOjbConfigurer.OJB_PROPERTIES_PROP);
046                try {
047                        System.setProperty(BaseOjbConfigurer.OJB_PROPERTIES_PROP, ojbPropertyFileLocation);
048                        org.apache.ojb.broker.metadata.MetadataManager metadataManager = org.apache.ojb.broker.metadata.MetadataManager.getInstance();
049                        descriptorRepository = metadataManager.getGlobalRepository();
050            } finally {
051                if (currentValue == null) {
052                    System.getProperties().remove(BaseOjbConfigurer.OJB_PROPERTIES_PROP);
053                } else {
054                    System.setProperty(BaseOjbConfigurer.OJB_PROPERTIES_PROP, currentValue);
055                }
056            }
057        }
058
059        /**
060         * @return DescriptorRepository containing everything OJB knows about persistable classes
061         */
062        protected DescriptorRepository getDescriptorRepository() {
063                return descriptorRepository;
064        }
065
066        /**
067         *
068         * This method returns a list of primary key field names.  This method uses the CacheNoCopy caching method.
069         * "NoCopy" is the faster of the caching annotations, but because it does not make a copy the list that is
070         * returned must not be modified.  To enforce this the returned list is wrapped in a Collections.unmodifiableList
071         * method.  This will cause an exception to be thrown if the list is altered.
072         *
073         * @param clazz
074         * @return unmodifiableList of field names.  Any attempt to alter list will result in an UnsupportedOperationException
075         */
076        public List listPrimaryKeyFieldNames(Class clazz) {
077        // Rice JPA MetadataManager
078                if (isJpaEnabledForKradClass(clazz)) {
079                        List fieldNames = new ArrayList();
080                EntityDescriptor descriptor = MetadataManager.getEntityDescriptor(clazz);
081                for (org.kuali.rice.core.framework.persistence.jpa.metadata.FieldDescriptor field : descriptor.getPrimaryKeys()) {
082                        fieldNames.add(field.getName());
083                }
084                return fieldNames;
085                } else {
086                // Legacy OJB
087                        List fieldNamesLegacy = new ArrayList();
088                        ClassDescriptor classDescriptor = getClassDescriptor(clazz);
089                        FieldDescriptor keyDescriptors[] = classDescriptor.getPkFields();
090
091                        for (int i = 0; i < keyDescriptors.length; ++i) {
092                                FieldDescriptor keyDescriptor = keyDescriptors[i];
093                                fieldNamesLegacy.add(keyDescriptor.getAttributeName());
094                        }
095                        return fieldNamesLegacy;
096                }
097        }
098
099        /* Not used anywhere... need to check KFS and batch stuff */
100        /**
101         * @param classDescriptor
102         * @return name of the database table associated with given classDescriptor,
103         *         stripped of its leading schemaName
104         */
105        /*
106        @CacheNoCopy
107        protected String getTableName(ClassDescriptor classDescriptor) {
108                String schemaName = classDescriptor.getSchema();
109                String fullTableName = classDescriptor.getFullTableName();
110
111                String tableName = null;
112                if (StringUtils.isNotBlank(schemaName)) {
113                        tableName = StringUtils.substringAfter(fullTableName, schemaName + ".");
114                }
115                if (StringUtils.isBlank(tableName)) {
116                        tableName = fullTableName;
117                }
118
119                return tableName;
120        }
121        */
122
123        /**
124         * @param persistableClass
125         * @return ClassDescriptor for the given Class
126         * @throws IllegalArgumentException
127         *             if the given Class is null
128         * @throws ClassNotPersistableException
129         *             if the given Class is unknown to OJB
130         */
131        // Legacy OJB - no need for JPA equivalent
132        protected ClassDescriptor getClassDescriptor(Class persistableClass) {
133                if (persistableClass == null) {
134                        throw new IllegalArgumentException("invalid (null) object");
135                }
136
137                ClassDescriptor classDescriptor = null;
138                DescriptorRepository globalRepository = getDescriptorRepository();
139                try {
140                        classDescriptor = globalRepository.getDescriptorFor(persistableClass);
141                } catch (ClassNotPersistenceCapableException e) {
142                        throw new ClassNotPersistableException("class '" + persistableClass.getName() + "' is not persistable", e);
143                }
144
145                return classDescriptor;
146        }
147        
148        /**
149         * Determines if JPA is enabled for the KNS and for the given class
150         * 
151         * @param clazz the class to check for JPA enabling of
152         * @return true if JPA is enabled for the class, false otherwise
153         */
154        public boolean isJpaEnabledForKradClass(Class clazz) {
155                final boolean jpaAnnotated = OrmUtils.isJpaAnnotated(clazz);
156                final boolean jpaEnabled = OrmUtils.isJpaEnabled();
157                final boolean prefixJpaEnabled = OrmUtils.isJpaEnabled("rice.krad");
158                return jpaAnnotated && (jpaEnabled || prefixJpaEnabled);
159        }
160
161        /**
162         * @see org.kuali.rice.krad.service.PersistenceStructureService#getBusinessObjectAttributeClass(java.lang.Class,
163         *      java.lang.String)
164         */
165        public Class<? extends PersistableBusinessObjectExtension> getBusinessObjectAttributeClass(Class<? extends PersistableBusinessObject> clazz, String attributeName) {
166                String baseAttributeName = attributeName;
167                String subAttributeString = null;
168                if (attributeName.contains(".")) {
169                        baseAttributeName = attributeName.substring(0, attributeName.indexOf('.'));
170                        subAttributeString = attributeName.substring(attributeName.indexOf('.') + 1);
171                }
172
173        // Rice JPA MetadataManager
174                if (isJpaEnabledForKradClass(clazz)) {
175                        Class attributeClass = null;
176                EntityDescriptor descriptor = MetadataManager.getEntityDescriptor(clazz);
177                ObjectDescriptor objectDescriptor = descriptor.getObjectDescriptorByName(baseAttributeName);
178                        if (objectDescriptor != null) {
179                                attributeClass = objectDescriptor.getTargetEntity();
180                        }
181
182                        // recurse if necessary
183                        if (subAttributeString != null) {
184                                attributeClass = getBusinessObjectAttributeClass(attributeClass, subAttributeString);
185                        }
186
187                        return attributeClass;
188                } else {
189                // Legacy OJB
190                        Class attributeClassLegacy = null;
191            ClassDescriptor classDescriptor = null;
192            try{
193                            classDescriptor = this.getClassDescriptor(clazz);
194            }catch (ClassNotPersistableException e){
195                LOG.warn("Class descriptor for "+ clazz.getName() +"was not found");
196            }
197
198                        ObjectReferenceDescriptor refDescriptor = null;
199            if(classDescriptor != null){
200                refDescriptor = classDescriptor.getObjectReferenceDescriptorByName(baseAttributeName);
201            }
202
203                        if (refDescriptor != null) {
204                                attributeClassLegacy = refDescriptor.getItemClass();
205                        }
206
207                        // recurse if necessary
208                        if (subAttributeString != null) {
209                                attributeClassLegacy = getBusinessObjectAttributeClass(attributeClassLegacy, subAttributeString);
210                        }
211
212                        return attributeClassLegacy;
213                }
214        }
215
216}